pre-readme

This commit is contained in:
Brett Weiland 2025-09-22 19:07:37 -05:00
parent 27c8d95173
commit ac63c1fb84
55 changed files with 75703 additions and 4767 deletions

BIN
datasheets/SMD291AX50T3.pdf Normal file

Binary file not shown.

BIN
imgs/twopaths.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

View File

@ -0,0 +1 @@
/home/indigo/projects/stm32_buisnesscard/kicad/stm32card/_autosave-stm32card.kicad_sch

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
"images": 1.0, "images": 1.0,
"pads": 1.0, "pads": 1.0,
"shapes": 1.0, "shapes": 1.0,
"tracks": 1.0, "tracks": 0.27000001072883606,
"vias": 1.0, "vias": 1.0,
"zones": 0.7099999785423279 "zones": 0.7099999785423279
}, },

View File

@ -459,6 +459,7 @@
"single_global_label": "ignore", "single_global_label": "ignore",
"unannotated": "error", "unannotated": "error",
"unconnected_wire_endpoint": "warning", "unconnected_wire_endpoint": "warning",
"undefined_netclass": "error",
"unit_value_mismatch": "error", "unit_value_mismatch": "error",
"unresolved_variable": "error", "unresolved_variable": "error",
"wire_dangling": "error" "wire_dangling": "error"
@ -528,10 +529,10 @@
"gencad": "", "gencad": "",
"idf": "", "idf": "",
"netlist": "", "netlist": "",
"plot": "../../v3_career_fair/", "plot": "../stm32card_stencil/",
"pos_files": "", "pos_files": "",
"specctra_dsn": "", "specctra_dsn": "",
"step": "", "step": "stm32card.step",
"svg": "", "svg": "",
"vrml": "" "vrml": ""
}, },

View File

@ -5259,6 +5259,16 @@
) )
(uuid "3002dedb-2703-489f-882f-bab25b7dda33") (uuid "3002dedb-2703-489f-882f-bab25b7dda33")
) )
(text "I finished this in a rush and I'm not sure why I did this.\nR21 should be a short and there needs to be a resistor instead of a diode."
(exclude_from_sim no)
(at 84.074 149.352 0)
(effects
(font
(size 1.27 1.27)
)
)
(uuid "5473d214-3849-47a5-8b2b-db0b7c7e51f5")
)
(text "double check voltage diviers, maybe push higher - LCSC!" (text "double check voltage diviers, maybe push higher - LCSC!"
(exclude_from_sim no) (exclude_from_sim no)
(at 43.434 -3.556 0) (at 43.434 -3.556 0)
@ -15482,13 +15492,12 @@
(dnp no) (dnp no)
(uuid "b24b357b-0b8d-43fe-933c-61bdb6083d63") (uuid "b24b357b-0b8d-43fe-933c-61bdb6083d63")
(property "Reference" "R21" (property "Reference" "R21"
(at 104.648 140.97 0) (at 104.902 142.24 0)
(effects (effects
(font (font
(size 1.27 1.27) (size 1.27 1.27)
) )
(justify right) (justify right)
(hide yes)
) )
) )
(property "Value" "10k" (property "Value" "10k"
@ -15498,6 +15507,7 @@
(size 1.27 1.27) (size 1.27 1.27)
) )
(justify right) (justify right)
(hide yes)
) )
) )
(property "Footprint" "Resistor_SMD:R_0603_1608Metric" (property "Footprint" "Resistor_SMD:R_0603_1608Metric"

View File

@ -0,0 +1 @@
{"hostname":"indigosDesktop","username":"indigo"}

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Based on https://github.com/KiCad/kicad-source-mirror/blob/master/demos/python_scripts_examples/gen_gerber_and_drill_files_board.py
import sys
import os
from pcbnew import *
def help():
print("Usage: kicadExportDxf.py <board file> [<output dir>]")
print(" Default output dir same as the board directory'")
if len(sys.argv) == 1 or len(sys.argv) > 3:
print("Invalid number of arguments.")
help()
sys.exit()
filename = sys.argv[1]
basename = os.path.dirname(filename)
if len(sys.argv) == 3:
plotDir = sys.argv[2]
else:
plotDir = basename
plotDir = os.path.abspath(plotDir)
board = LoadBoard(filename)
pctl = PLOT_CONTROLLER(board)
popt = pctl.GetPlotOptions()
popt.SetOutputDirectory(plotDir)
popt.SetAutoScale(False)
popt.SetScale(1)
popt.SetMirror(False)
popt.SetExcludeEdgeLayer(True)
popt.SetScale(1)
popt.SetDXFPlotUnits(DXF_PLOTTER.DXF_UNIT_MILLIMETERS)
popt.SetDXFPlotPolygonMode(False)
plot_plan = [
# name, id, comment
("PasteBottom", B_Paste, "Paste Bottom"),
("PasteTop", F_Paste, "Paste top"),
("EdgeCuts", Edge_Cuts, "Edges"),
]
for name, id, comment in plot_plan:
pctl.SetLayer(id)
pctl.OpenPlotfile(name, PLOT_FORMAT_DXF, comment)
print('plot {}'.format(pctl.GetPlotFileName()))
if pctl.PlotLayer() == False:
print("plot error")
pctl.ClosePlot()
sys.exit(0)

View File

@ -0,0 +1,48 @@
module stencilFrame(outlineDxf, height, width, clearance) {
linear_extrude(height = height)
difference() {
offset(r = width + clearance) import(file = outlineDxf);
offset(r = clearance) import(file = outlineDxf);
};
};
module stencilSubstrate(outlineDxf, thickness, frameHeight,
frameWidth, frameClearance)
{
difference() {
linear_extrude(height = thickness + frameHeight)
offset(r = frameWidth + frameClearance)
import(file = outlineDxf);
translate([0, 0, thickness])
linear_extrude(height = thickness + frameHeight)
offset(r = frameClearance)
import(file = outlineDxf);
}
}
module stencil(outlineDxf, holesDxf, thickness = 0.2, frameHeight = 1,
frameWidth = 1, frameClearance = 0.1, enlargeHoles = 0.05, front = true)
{
zScale = front ? -1 : 1;
xRotate = front ? 180 : 0;
rotate(a = xRotate, v = [1, 0, 0])
difference() {
scale([1, 1, zScale]) stencilSubstrate(outlineDxf, thickness,
frameHeight, frameWidth, frameClearance);
linear_extrude(height = 4 * thickness, center = true)
offset(delta = enlargeHoles) import(file = holesDxf);
};
}
$fa = 0.4;
$fs = 0.4;
thickness = 0.2;
frameHeight = 1;
frameWidth = 2;
enlargeHoles = 0.0;
frameClearance = 0;
front = true;
stencil("../stm32card-Edge_Cuts.dxf", "../stm32card-F_Paste.dxf", thickness = thickness, frameHeight = frameHeight,
frameWidth = frameWidth, frameClearance = frameClearance, front=front);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="297.0022mm" height="210.0072mm" viewBox="0.0000 0.0000 297.0022 210.0072">
<title>SVG Image created as stm32card-Edge_Cuts.svg date 2025/09/11 14:25:54 </title>
<desc>Image generated by PCBNEW </desc>
<g style="fill:#000000; fill-opacity:1.0000;stroke:#000000; stroke-opacity:1.0000;
stroke-linecap:round; stroke-linejoin:round;"
transform="translate(0 0) scale(1 1)">
</g>
<g style="fill:none;
stroke:#000000; stroke-width:0.0500; stroke-opacity:1;
stroke-linecap:round; stroke-linejoin:round;">
<path d="M137.5645 132.3355
L216.4645 132.3355
" />
<path d="M132.5645 127.3355 A5.0000 5.0000 0.0 0 0 137.5645 132.3355" />
<path d="M132.5645 86.5355
L132.5645 127.3355
" />
<path d="M221.4645 86.5355 A5.0000 5.0000 0.0 0 0 216.4645 81.5355" />
<path d="M221.4645 127.3355
L221.4645 86.5355
" />
<path d="M216.4645 81.5355
L137.5645 81.5355
" />
<path d="M137.5645 81.5355 A4.9999 4.9999 0.0 0 0 132.5645 86.5355" />
<path d="M216.4645 132.3356 A5.0001 5.0001 0.0 0 0 221.4645 127.3355" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 124 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -1,256 +1,256 @@
c
p unoptimized_times
quit
c
p unoptimized_times
print optimized_times
run
print optimized_times
p unoptimized_times
quit
c
quit
quit
c
print optimized_times
p unoptimized_times
quit
quit
c
quit
qut
quit
c
print unoptimized_times
print optimized_times
print unoptimized_times
load
c
print unoptimized_times
print optimized_times
dump mod8
disassemble
disassemble mod8
context
b mod8
b mandelbrot.c:67
load
c
quit
c
print optimized_times
quit
c
quit
c
print optimized_times
quit
quit
c
print optimized_times
b mandelbrot_bordertrace
load
c
print mod8
print mod8(1)
print mod(1)
print mod8(1)
quit
c
print optimized_times
quit
c
print optimized_times
quit
c
quit
c
quit
c
b get_neighbor_index
c
load load
c c
next next
n print from_pixel + neighbor_index_accl[direction]
print borders print direction
n print from_pixel - win.w
print nei_dir print from_pixel - (win.w + 1)
n print from_pixel + neighbor_index_accl[1]
n print from_pixel - win.w + 1
print nei_dir quit
quit
c
b get_neighbor_index
c
load
c
next
quit
c
quit
c
print optimized_times
quit
c
quit
c
print optimized_times
quit
c
quit
c
print pin_mult
print/x pin_mult
print pin
print/x pin
print/b pin
print/x pin
c
quyit
quit
c
c
print/x pin_mult
quit
c
print pin_mult
print/x pin_mult
print GPIO_EXTI_REG->IDR & BUTTON_MASK
print GPIO_EXTI_REG->IDR
c
print/x pin_mult
print/x pin_mult
c
print/x pin_mult
c
print/x pin_mult
c
print/x pin_mult
quit
make
quit
c
print/x pin_mult
quit
c
quit
c
print pin_mult
print/x pin_mult
print pin_mult
print/x pin_mult
quit
c
print/x pin_mult
c
print/x pin_mult
c
print/x pin_mult
c
print/x pin_mult
c
print/x pin_mult
c
print/x pin_mult
c
print/x pin_mult
p BUTTON_REG_1
print/x pin_mult
c
print/x pin_mult
print pin_mult & (pin_mult - 1)
print pin
print button_reg_1
print GPIO_B
print BUTTON_R1_MASK
quit
c
print fuck1
print fuck2
print pin_mult
next
c
c
c
quit
c
print pin_mult
print fuck1
print fuck1 & BUTTON_R1_MASK
c
print pin_mult
print/x pin_mult
quit
c
c
c
quit
c
quit
c
b mandelbrot.c:447
c
b 55
b 372-55
b 317
c
c
print GET_X(this_index, win)
print x
print this_index print this_index
print pixels[this_index]
print framebuffer[this_index]
print framebuffer[this_index] & G_MASK
print framebuffer[this_index+1] & G_MASK
next next
print gchan_info
next next
print i
print this_coord
print get_neighbor_coord(this_coord, nei_dir, scale)
print FIXED_TO_DOUBLE(this_coord.r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, nei_dir, scale))
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, nei_dir, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 0, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 0, scale).r) 1
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 0, scale).r), 1
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 0, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 1, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 2, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 3, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 4, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 5, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 6, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 7, scale).r)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 0, scale).i)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 1, scale).i)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 2, scale).i)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 3, scale).i)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 4, scale).i)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 5, scale).i)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 6, scale).i)
print FIXED_TO_DOUBLE(get_neighbor_coord(this_coord, 7, scale).i)
print FIXED_TO_DOUBLE(this_coord.i)
c c
c c
d
d
c
quit
quit quit
c
c c
quit quit
c c
quit quit
c c
quit
c c
quit quit
quit quit
c c
c
quit
next
qiot
quit quit
c c
quit quit
c
print unoptimized_times
cat optimized_times
print optimized_times
exit()
quit
quit
c
quit
c
context
quit
quit quit
c c
c c
f 2 f 2
context print cam
quit quit
c c
quit f 2
c print cam
quit c
'c f 2
c print cam
c c
quit f 2
c print cam
HAL_GPIO_TogglePin c
print HAL_GPIO_TogglePin() print cam
b idle f 2
c print cam
print HAL_GPIO_TogglePin()
quit
c
c
quit
quit
c
quit
c
b idle
c
next
print charging_bat
print charging_bat()
print charging_batt()
b charging_batt
c
print HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN)
print ~HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN)
print ~(HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN))
print !(HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN))
print (HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN))
print GPIO_PIN_SET
ptype GPIO_PIN_SET
quit
print HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN)
b charging_batt
c
step
quit
b idle
c
next
print charing_batt()
print charging_batt()
print event_peek()
next
next
c
next
next
next
b idle
d
c
b idle
c
next
print event_peek
print event_peek()
print ST7735_wake()
b ST7735_wake
c
c
next
next
next
c
next
quit
c
quit
c
b idle.c:23
c
c
quit
c
c
c
print ST7735_sleep()
c
print ST7735_wake()
quit
b main
c
next
print ST7735_sleep()
print ST7735_wake()
exit
c
quit
c
quit
c
quit
c
quit
c
quit
quit
c
quit
c
quit
c
quit
c
quit
c
quit
c
quit
c
quit
quit
c
quit
c
quit
c
next
quit
c
print on_pixel
next
quit
c
next
quit
quit
c
print y
print x
next
next
print framebuffer[on_pixel] & G_MASK
print framebuffer[on_pixel]
print framebuffer[on_pixel] & ~G_MASK
quit
c
c
quit
c
c
quit
c
next
next
quit
quit
c
c
step
print on_pixel
quit
c
next
print border
print borders
next
print iterate(this_coord)
quit
c
quit
c
print framebuffer[this_index]
print framebuffer[this_index] & GCHAN
print framebuffer[this_index] & G_MASK
print framebuffer[nei_i] & G_MASK
print nei_i
print framebuffer[nei_i] & G_MASK
next
print i
print colorscheme[i]
print ITERS
quit
c
c
c
c
quit
quit quit

View File

@ -2,6 +2,4 @@
#include <signal.h> #include <signal.h>
#include "main.h" #include "main.h"
void benchmark();
void benchmark_start();
void benchmark_stop();

View File

@ -7,15 +7,26 @@
TODO move to gpio.h or somethin TODO move to gpio.h or somethin
**/ **/
#define GPIO_EXTI_REG GPIOB #define EVENT_NONE 0
#define BUTTON_REG_1 GPIOA
#define BUTTON_REG_2 GPIOB
#define BUTTON_R1_MASK (BUTTON_UP | BUTTON_DOWN | BUTTON_RIGHT | BUTTON_LEFT)
#define BUTTON_R2_MASK (BUTTON_A | BUTTON_B)
#define BUTTON_UP GPIO_PIN_3 #define BUTTON_UP GPIO_PIN_3
#define BUTTON_RIGHT GPIO_PIN_2 #define BUTTON_RIGHT GPIO_PIN_2
#define BUTTON_DOWN GPIO_PIN_0 #define BUTTON_DOWN GPIO_PIN_0
#define BUTTON_LEFT GPIO_PIN_1 #define BUTTON_LEFT GPIO_PIN_1
#define BUTTON_A GPIO_PIN_13 #define BUTTON_A GPIO_PIN_13
#define BUTTON_B GPIO_PIN_14 #define BUTTON_B GPIO_PIN_14
#define CHARGING_PORT GPIOB
#define CHARGING_PIN GPIO_PIN_12 #define CHARGING_PIN GPIO_PIN_12
#define EVENT_NONE 0
#define DEMO_NEXTVIEW BUTTON_A | BUTTON_B | BUTTON_RIGHT
#define DEMO_LASTVIEW BUTTON_A | BUTTON_B | BUTTON_LEFT
#define DEMO_BORDER BUTTON_A | BUTTON_B | BUTTON_UP
extern int button; extern int button;
void HAL_GPIO_EXTI_Callback(uint16_t pin); void HAL_GPIO_EXTI_Callback(uint16_t pin);

View File

@ -1,3 +1,17 @@
#pragma once #pragma once
void draw_mandelbrot(); #define RES_X 160
#define RES_Y 80
struct camera {
double min_r, min_i, max_r, max_i;
};
struct window {
unsigned int x0, y0, w, h;
};
void render_loop();
void init_colorscheme(uint16_t *scheme);
unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, const uint16_t *colorscheme, const struct camera cam, const struct window win);
unsigned int mandelbrot_unoptimized(uint16_t *framebuffer, const uint16_t *colorscheme, const struct camera cam, const struct window win);

View File

@ -30,138 +30,7 @@ extern SPI_HandleTypeDef ST7735_SPI_PORT;
#define BACKLIGHT_PORT GPIOB #define BACKLIGHT_PORT GPIOB
#define BACKLIGHT_PIN GPIO_PIN_15 #define BACKLIGHT_PIN GPIO_PIN_15
// AliExpress/eBay 1.8" display, default orientation
/*
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 160
#define ST7735_XSTART 0
#define ST7735_YSTART 0
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MY)
*/
// AliExpress/eBay 1.8" display, rotate right
/*
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 160
#define ST7735_HEIGHT 128
#define ST7735_XSTART 0
#define ST7735_YSTART 0
#define ST7735_ROTATION (ST7735_MADCTL_MY | ST7735_MADCTL_MV)
*/
// AliExpress/eBay 1.8" display, rotate left
/*
shutdown command invoked
1 indigo@indigosDesktop ~/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1 main make && openocd -f i
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 160
#define ST7735_HEIGHT 128
#define ST7735_XSTART 0
#define ST7735_YSTART 0
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MV)
*/
// AliExpress/eBay 1.8" display, upside down
/*
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 160
#define ST7735_XSTART 0
#define ST7735_YSTART 0
#define ST7735_ROTATION (0)
*/
// WaveShare ST7735S-based 1.8" display, default orientation
/*
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 160
#define ST7735_XSTART 2
#define ST7735_YSTART 1
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_RGB)
*/
// WaveShare ST7735S-based 1.8" display, rotate right
/*
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 160
#define ST7735_HEIGHT 128
#define ST7735_XSTART 1
#define ST7735_YSTART 2
#define ST7735_ROTATION (ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_RGB)
*/
// WaveShare ST7735S-based 1.8" display, rotate left
/*
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 160
#define ST7735_HEIGHT 128
#define ST7735_XSTART 1
#define ST7735_YSTART 2
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_RGB)
*/
// WaveShare ST7735S-based 1.8" display, upside down
/*
#define ST7735_IS_160X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 160
#define ST7735_XSTART 2
#define ST7735_YSTART 1
#define ST7735_ROTATION (ST7735_MADCTL_RGB)
*/
// 1.44" display, default orientation
/**
#define ST7735_IS_128X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 128
#define ST7735_XSTART 2
#define ST7735_YSTART 3
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_BGR)
**/
// 1.44" display, rotate right
/*
#define ST7735_IS_128X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 128
#define ST7735_XSTART 3
#define ST7735_YSTART 2
#define ST7735_ROTATION (ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_BGR)
*/
// 1.44" display, rotate left
/*
#define ST7735_IS_128X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 128
#define ST7735_XSTART 1
#define ST7735_YSTART 2
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_BGR)
*/
// 1.44" display, upside down
/*
#define ST7735_IS_128X128 1
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 128
#define ST7735_XSTART 2
#define ST7735_YSTART 1
#define ST7735_ROTATION (ST7735_MADCTL_BGR)
*/
// mini 160x80 display (it's unlikely you want the default orientation)
/*
#define ST7735_IS_160X80 1
#define ST7735_XSTART 26
#define ST7735_YSTART 1
#define ST7735_WIDTH 80
#define ST7735_HEIGHT 160
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MY | ST7735_MADCTL_BGR)
*/
// mini 160x80, rotate left // mini 160x80, rotate left
#define ST7735_IS_160X80 1 #define ST7735_IS_160X80 1
@ -171,18 +40,6 @@ shutdown command invoked
#define ST7735_HEIGHT 80 #define ST7735_HEIGHT 80
#define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_BGR) #define ST7735_ROTATION (ST7735_MADCTL_MX | ST7735_MADCTL_MV | ST7735_MADCTL_BGR)
// mini 160x80, rotate right
/**
#define ST7735_IS_160X80 1
#define ST7735_XSTART 1
#define ST7735_YSTART 26
#define ST7735_WIDTH 160
#define ST7735_HEIGHT 80
#define ST7735_ROTATION (ST7735_MADCTL_MY | ST7735_MADCTL_MV | ST7735_MADCTL_BGR)
**/
/****************************/ /****************************/
#define ST7735_NOP 0x00 #define ST7735_NOP 0x00

View File

@ -1,20 +1,77 @@
#include <signal.h> #include <signal.h>
#include "mandelbrot.h"
#include "main.h" #include "main.h"
#include "st7735.h"
#include "gpio.h"
static float time __attribute__((used)); //static float time __attribute__((used));
//whatever I'm tired of using hal
void benchmark_start() { void benchmark_start() {
TIM4->CNT = 0; TIM4->CNT = 0;
TIM4->CR1 |= TIM_CR1_CEN; TIM4->CR1 |= TIM_CR1_CEN;
} }
void benchmark_stop() {
float benchmark_stop() {
TIM4->CR1 ^= TIM_CR1_CEN; TIM4->CR1 ^= TIM_CR1_CEN;
time = (float)(TIM4->CNT + 1) * (TIM4->PSC + 1) / HAL_RCC_GetSysClockFreq(); return (float)(TIM4->CNT + 1) * (TIM4->PSC + 1) / HAL_RCC_GetSysClockFreq();
BENCHMARK_CHECKTIME:
__NOP();
// __BKPT();
} }
void benchmark() { void benchmark() {
uint16_t scheme[256]; //yeah eyah yeah constant scope balalse';hjf v'wef
init_colorscheme(scheme);
const struct camera cases[] = {
//shows child mandelbrot at about 1/4th of the screen
(struct camera) {1.511138965827779623297, -0.000099833545397436595, 1.513299500557251375810, 0.000980433819429512915},
//main set taking up most of screen
(struct camera) {-1.006631762350983283483, 0.033264514201812478422, 0.159212948008334742589, 0.616186869452269969649},
//main set taking up a little bit of the screen
(struct camera) {-3.860919485929509509248, -1.895171233654595388529, 4.122278116347564136390, 2.096427567968737193382},
//zoomed in far, set taking up half of screen
(struct camera) {0.250175465354113391037, -0.000006169573538442441, 0.250185172171380920680, -0.000001316164904004028},
//zoomed in far, set taking up none of screen
(struct camera) {0.250177970233267155109, -0.000003445496138560340, 0.250181935207702044188, -0.000001463008920807711},
//half and half, complex border
(struct camera) {3.530034617447952438596, -0.011581384229626515842, 3.530490903206738639852, -0.011353241350196253967},
//complete blackness
(struct camera) {-1.097044987707582519576, 0.142802338676453366428, -1.000760853479837342306, 0.190944405713568132743}
};
const int case_cnt = sizeof(cases) / sizeof(*cases);
static float unoptimized_times[7] __attribute__((used));
static float optimized_times[7] __attribute__((used));
uint16_t framebuffer[(RES_X/2) * RES_Y] = {0};
const struct window left_half = {0, 0, 80, 80};
const struct window right_half = {80, 0, 80, 80};
for(int case_i = 0; case_i < case_cnt; case_i++) {
benchmark_start();
mandelbrot_bordertrace(framebuffer, scheme, cases[case_i], left_half);
ST7735_DrawImage(0, 0, 80, 80, framebuffer);
mandelbrot_bordertrace(framebuffer, scheme, cases[case_i], right_half);
ST7735_DrawImage(80, 0, 80, 80, framebuffer);
optimized_times[case_i] = benchmark_stop();
// while(!event_get());
benchmark_start();
mandelbrot_unoptimized(framebuffer, scheme, cases[case_i], left_half);
ST7735_DrawImage(0, 0, 80, 80, framebuffer);
mandelbrot_unoptimized(framebuffer, scheme, cases[case_i], right_half);
ST7735_DrawImage(80, 0, 80, 80, framebuffer);
unoptimized_times[case_i] = benchmark_stop();
// while(!event_get());
}
__BKPT();
} }

View File

@ -2,8 +2,20 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
int gpio_event = EVENT_NONE; int gpio_event = EVENT_NONE;
void HAL_GPIO_EXTI_Callback(uint16_t pin) { gpio_event = pin; }
void HAL_GPIO_EXTI_Callback(uint16_t pin) {
//implimented demo functionality last second; maybe consider moving to a different interrupt
uint32_t pin_mult = (((BUTTON_REG_1->IDR) & BUTTON_R1_MASK) | ((BUTTON_REG_2->IDR) & BUTTON_R2_MASK));
uint32_t fuck1 = BUTTON_REG_1 -> IDR;
uint32_t fuck2 = BUTTON_REG_2 -> IDR;
if((pin_mult & (pin_mult - 1))) {
gpio_event = pin_mult;
}
else gpio_event = pin;
}
int event_get() { int event_get() {
int event = gpio_event; int event = gpio_event;
gpio_event = EVENT_NONE; gpio_event = EVENT_NONE;
@ -12,5 +24,4 @@ int event_get() {
int event_peek() { return gpio_event; } int event_peek() { return gpio_event; }
bool charging_batt() { return !HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN); } bool charging_batt() { return HAL_GPIO_ReadPin(CHARGING_PORT, CHARGING_PIN); }
//bool charging_batt() { return ~HAL_GPIO_ReadPin(GPIO_EXTI_REG, CHARGING_PIN); }

View File

@ -125,9 +125,11 @@ int main(void)
/* Infinite loop */ /* Infinite loop */
/* USER CODE BEGIN WHILE */ /* USER CODE BEGIN WHILE */
// benchmark();
while (1) while (1)
{ {
draw_mandelbrot(); render_loop();
// benchmark();
/* USER CODE END WHILE */ /* USER CODE END WHILE */
/* USER CODE BEGIN 3 */ /* USER CODE BEGIN 3 */

View File

@ -5,6 +5,7 @@
#include "main.h" #include "main.h"
#include "gpio.h" #include "gpio.h"
#include "idle.h" #include "idle.h"
#include "stm32f1xx_hal_spi.h"
#define RES_X 160 #define RES_X 160
#define RES_Y 80 #define RES_Y 80
@ -24,12 +25,6 @@
#define ITERS 255 #define ITERS 255
#define INFTY_SQR_FIXED DOUBLE_TO_FIXED(INFTY_SQR) #define INFTY_SQR_FIXED DOUBLE_TO_FIXED(INFTY_SQR)
//TODO move to some hardware.h or somethin
//channel order: B, G, R
#define R_BITS 5
#define G_BITS 6
#define B_BITS 5
#define G_MASK 0xe007 #define G_MASK 0xe007
//imaginary axis set automatically //imaginary axis set automatically
@ -59,24 +54,24 @@ typedef struct {
int32_t r; int32_t i; int32_t r; int32_t i;
} FixedCord; } FixedCord;
struct camera {
double min_r, min_i, max_r, max_i;
};
struct window {
unsigned int x0, y0, w, h;
};
//C does remainder, not modulo. int mod8(int n) {
//TODO optimize for mod 8. Benchmark //I don't understand how, but somehow just anding the result is slower...?
inline int mod(int n, int d) { //I've got too many things on my plate to disassemble this, but feel free to look into it yourself
int r = n % d; int r = n % 8;
return (r < 0) ? r + d : r; return (r < 0) ? r + 8 : r;
} }
int mod(int n, int d); /**
inline __attribute__((forced_inline)) int mod8(int n) {
return (n + 8) & 0b111;
}
**/
int mod8(int n);
inline FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step) {
FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step) {
if((direction == NW) || (direction < E)) from_coord.i += step.i; //up if((direction == NW) || (direction < E)) from_coord.i += step.i; //up
if((direction > N) && (direction < S)) from_coord.r += step.r; //right if((direction > N) && (direction < S)) from_coord.r += step.r; //right
if((direction > E) && (direction < W)) from_coord.i -= step.i; //down if((direction > E) && (direction < W)) from_coord.i -= step.i; //down
@ -87,11 +82,17 @@ FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step
size_t get_neighbor_index(size_t from_pixel, int direction, struct window win) { size_t get_neighbor_index(size_t from_pixel, int direction, struct window win) {
//TODO gross since window is no longer constant switch(direction) {
int neighbor_index_accl[8] = case N: return from_pixel - win.w;
{-win.w, -win.w + 1, 1, win.w + 1, win.w, win.w - 1, -1, -win.w - 1}; case NE: return from_pixel - win.w + 1;
from_pixel += neighbor_index_accl[direction]; case E: return from_pixel + 1;
return from_pixel; case SE: return from_pixel + win.w + 1;
case S: return from_pixel + win.w;
case SW: return from_pixel + win.w - 1;
case W: return from_pixel - 1;
case NW: return from_pixel - win.w - 1;
}
return 0;
} }
void detect_borders(bool borders[8], size_t i, struct window win) { void detect_borders(bool borders[8], size_t i, struct window win) {
@ -117,8 +118,6 @@ void detect_borders(bool borders[8], size_t i, struct window win) {
} }
} }
enum VIEW_MODES { VIEW_UNINIT, VIEW_MANDREL, VIEW_SHIP };
void init_colorscheme(uint16_t *scheme) { void init_colorscheme(uint16_t *scheme) {
uint16_t *tc = scheme; uint16_t *tc = scheme;
for(unsigned int i = 0; i <= ITERS; i++) { for(unsigned int i = 0; i <= ITERS; i++) {
@ -132,15 +131,6 @@ void init_colorscheme(uint16_t *scheme) {
scheme[ITERS] = 0; scheme[ITERS] = 0;
} }
void init_colorscheme_ship(uint16_t *scheme) {
uint16_t *tc = scheme;
for(unsigned int i = 0; i < ITERS; i++) {
if((i == 0) || (i == ITERS)) *tc = 0;
else *tc = (((i - (128)) << 1)+0x1f) << (5+6);
tc++;
}
}
void cam_shift(struct camera *cam, double step_r, double step_i) { void cam_shift(struct camera *cam, double step_r, double step_i) {
double i_offset = (cam->max_i - cam->min_i) * step_i; double i_offset = (cam->max_i - cam->min_i) * step_i;
double r_offset = (cam->max_r - cam->min_r) * step_r; double r_offset = (cam->max_r - cam->min_r) * step_r;
@ -159,7 +149,7 @@ void cam_zoom(struct camera *cam, double zoom) {
cam->max_r -= r_scale; cam->max_r -= r_scale;
} }
inline int __attribute__((always_inline)) iterate(FixedCord c) { int iterate(FixedCord c) {
int32_t z_i = 0; int32_t z_i = 0;
int32_t z_r = 0; int32_t z_r = 0;
int32_t z_r_2, z_i_2, zn_r, zn_i; int32_t z_r_2, z_i_2, zn_r, zn_i;
@ -182,7 +172,12 @@ inline int __attribute__((always_inline)) iterate(FixedCord c) {
int iterate(FixedCord c); int iterate(FixedCord c);
unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme, struct camera cam, const struct window win) { #define GET_X(index, win) (((index) % win.w) + win.x0) //TODO organize
#define GET_Y(index, win) ((this_index / (double)win.w) + win.y0)
//no reason this needs to be global, this is just a last second addition and I'm in a hurry
static bool demo = false;
unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, const uint16_t *colorscheme, const struct camera cam, const struct window win) {
unsigned int total_iters = 0; unsigned int total_iters = 0;
size_t on_pixel = 0; size_t on_pixel = 0;
bool border_scanning = false; bool border_scanning = false;
@ -214,7 +209,8 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme
int i = iterate(c); int i = iterate(c);
total_iters += i; total_iters += i;
framebuffer[on_pixel] = colorscheme[i]; framebuffer[on_pixel] = colorscheme[i];
if(i == ITERS) { if(i != ITERS) { framebuffer[on_pixel] |= GCHAN_EXTERNAL; }
else {
FixedCord this_coord = c; FixedCord this_coord = c;
size_t this_index = on_pixel; size_t this_index = on_pixel;
bool seperated_from_start = false; bool seperated_from_start = false;
@ -237,11 +233,16 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme
if(nei_dir < 8) { if(nei_dir >= 8) border_scanning = true;
else {
while(true) { while(true) {
bzero(nei_presort, sizeof(nei_presort)); bzero(nei_presort, sizeof(nei_presort));
bzero(nei_canidate, sizeof(nei_canidate)); bzero(nei_canidate, sizeof(nei_canidate));
detect_borders(borders, this_index, win); detect_borders(borders, this_index, win);
if(demo) {
ST7735_DrawPixel(GET_X(this_index, win), GET_Y(this_index, win), ST7735_GREEN);
HAL_Delay(10);
}
//step 1: check pixels around us, fill in neighbors. //step 1: check pixels around us, fill in neighbors.
@ -288,7 +289,7 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme
} }
for(nei_edge_i = -2; nei_edge_i <= 2; nei_edge_i++) { for(nei_edge_i = -2; nei_edge_i <= 2; nei_edge_i++) {
int nei_edge_mod = mod((nei_dir + nei_edge_i), 8); int nei_edge_mod = mod8(nei_dir + nei_edge_i);
if((nei_presort[nei_edge_mod] == GCHAN_EXTERNAL) || borders[nei_edge_mod]) break; if((nei_presort[nei_edge_mod] == GCHAN_EXTERNAL) || borders[nei_edge_mod]) break;
} }
@ -296,7 +297,7 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme
if(nei_edge_i > 2) continue; if(nei_edge_i > 2) continue;
//narrow bridge scenario //narrow bridge scenario
if(nei_presort[mod((nei_dir + 1), 8)] & nei_presort[mod((nei_dir - 1), 8)] & GCHAN_EXTERNAL) if(nei_presort[mod8(nei_dir + 1)] & nei_presort[mod8(nei_dir - 1)] & GCHAN_EXTERNAL)
continue; continue;
edge_cnt++; edge_cnt++;
@ -321,9 +322,7 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme
} }
} }
} }
else border_scanning = true;
} }
else framebuffer[on_pixel] |= GCHAN_EXTERNAL;
} }
on_pixel++; on_pixel++;
c.r += scale.r; c.r += scale.r;
@ -334,20 +333,19 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme
return total_iters; return total_iters;
} }
//TODO rename unsigned int mandelbrot_unoptimized(uint16_t *framebuffer, const uint16_t *colorscheme, const struct camera cam, const struct window win) {
unsigned int render_mandelbrot(uint16_t *framebuffer, uint16_t *colorscheme, struct camera cam, int x0, int y0, int w, int h) {
int32_t scale_i = DOUBLE_TO_FIXED((cam.max_i - cam.min_i) / (double)RES_Y); int32_t scale_i = DOUBLE_TO_FIXED((cam.max_i - cam.min_i) / (double)RES_Y);
int32_t scale_r = DOUBLE_TO_FIXED((cam.max_r - cam.min_r) / (double)RES_X); int32_t scale_r = DOUBLE_TO_FIXED((cam.max_r - cam.min_r) / (double)RES_X);
int32_t c_i = DOUBLE_TO_FIXED((((cam.max_i - cam.min_i) * (RES_Y - y0)) / RES_Y) + cam.min_i); int32_t c_i = DOUBLE_TO_FIXED((((cam.max_i - cam.min_i) * (RES_Y - win.y0)) / RES_Y) + cam.min_i);
int32_t c_r0 = DOUBLE_TO_FIXED((((cam.max_r - cam.min_r) * x0) / RES_X) + cam.min_r); int32_t c_r0 = DOUBLE_TO_FIXED((((cam.max_r - cam.min_r) * win.x0) / RES_X) + cam.min_r);
int32_t c_r, z_i, z_r, zn_r, z_r_2, z_i_2; int32_t c_r, z_i, z_r, zn_r, z_r_2, z_i_2;
size_t fb_index = 0; size_t fb_index = 0;
int i; int i;
unsigned int total_iters = 0; unsigned int total_iters = 0;
for(int y = y0; y < y0 + h; y++) { for(int y = win.y0; y < win.y0 + win.h; y++) {
c_r = c_r0; c_r = c_r0;
for(int x = x0; x < x0 + w; x++) { for(int x = win.x0; x < win.x0 + win.w; x++) {
z_i = 0; z_i = 0;
z_r = 0; z_r = 0;
for(i = 0; i < ITERS; i++) { for(i = 0; i < ITERS; i++) {
@ -376,36 +374,39 @@ unsigned int render_mandelbrot(uint16_t *framebuffer, uint16_t *colorscheme, str
#define FB_SIZE_X RES_X/2 #define FB_SIZE_X RES_X/2
#define FB_SIZE_Y RES_Y #define FB_SIZE_Y RES_Y
//TODO rename
void draw_mandelbrot() { void render_loop() {
uint16_t framebuffer[FB_SIZE_X * FB_SIZE_Y]; uint16_t framebuffer[FB_SIZE_X * FB_SIZE_Y];
uint16_t columnbuffer[(size_t)(STEP_SIZE * RES_X * RES_Y)]; uint16_t columnbuffer[(size_t)(STEP_SIZE * RES_X * RES_Y)];
uint16_t left_line = 0; uint16_t left_line = 0;
//program flow is awful atm becuase I was planning something different; will be improved soon.
/**
static struct camera cam = {
.min_r = CAM_DEF_MIN_R,
.max_r = CAM_DEF_MAX_R,
.min_i = ((double)RES_Y / RES_X) * CAM_DEF_MIN_R,
.max_i = ((double)RES_Y / RES_X) * CAM_DEF_MAX_R,
};
**/
uint16_t on_slide = 0; //for demo locations
struct camera demo_cams[] = {
(struct camera) {-1.422917204962495851817, -0.000225276304707995275, -1.422016598199103754041, 0.000225027077043296207},
(struct camera) {-1.438263106924943857123, -0.000223747558519589895, -1.436086818463690795156, 0.000864396672238325900},
(struct camera) {-0.090225435380407282, -0.64998091931263191, -0.088768020367418904, -0.64925221180605341},
(struct camera) {-1.438799496517434883813, -0.001121122635241165663, -1.434096351603858066071, 0.001230449821984478309},
(struct camera) {0.281321953633743959688, 0.485607916741705558650, 0.282220985515896194418, 0.486057432682865053764},
(struct camera) {1.463643582778787255450, -0.000020491662036057693, 1.463725101406749828925, 0.000020267651948646491}
};
//TODO change before gifting any cards
struct camera cam = { struct camera cam = {
.min_r = 1.511138965827779623297, .min_i = -0.000099833545397436595, .max_r = 1.513299500557251375810, .max_i = 0.000980433819429512915 .min_r = -0.090225435380407282,
.min_i = -0.64998091931263191,
.max_r = -0.088768020367418904,
.max_i = -0.64925221180605341
}; };
uint16_t colorscheme[ITERS + 1]; uint16_t colorscheme[ITERS + 1];
/** yes, I know the following is disgusting. Before I clean it, I just wanna get the general idea out,
it's more efficient in that order
TODO once you get your idea ironed out, clean code **/
init_colorscheme(colorscheme); init_colorscheme(colorscheme);
bzero(framebuffer, sizeof(framebuffer)); bzero(framebuffer, sizeof(framebuffer));
bzero(columnbuffer, sizeof(columnbuffer)); bzero(columnbuffer, sizeof(columnbuffer));
//ggyaaaagh!!!
//I will clean this up later.
while(true) { while(true) {
const int y_offset = STEP_SIZE * FB_SIZE_Y; const int y_offset = STEP_SIZE * FB_SIZE_Y;
const int x_offset = STEP_SIZE * RES_X; const int x_offset = STEP_SIZE * RES_X;
@ -446,14 +447,27 @@ void draw_mandelbrot() {
cam_zoom(&cam, -ZOOM_SIZE); cam_zoom(&cam, -ZOOM_SIZE);
mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y}); mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y});
break; break;
case DEMO_NEXTVIEW:
cam = demo_cams[(++on_slide % (sizeof(demo_cams) / sizeof(*demo_cams)))];
mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y});
break;
case DEMO_LASTVIEW:
cam = demo_cams[(--on_slide % (sizeof(demo_cams) / sizeof(*demo_cams)))];
mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y});
break;
case DEMO_BORDER:
demo = true;
default: default:
mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y}); mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y});
} }
ST7735_DrawImage(left_line, 0, FB_SIZE_X, FB_SIZE_Y, framebuffer);
if(!demo) ST7735_DrawImage(left_line, 0, FB_SIZE_X, FB_SIZE_Y, framebuffer);
left_line = left_line ? 0 : FB_SIZE_X; left_line = left_line ? 0 : FB_SIZE_X;
mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y}); mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y});
ST7735_DrawImage(left_line, 0, FB_SIZE_X, FB_SIZE_Y, framebuffer); if(!demo) ST7735_DrawImage(left_line, 0, FB_SIZE_X, FB_SIZE_Y, framebuffer);
demo = false;
idle(); idle();
} }
} }

View File

@ -134,7 +134,7 @@ ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffuncti
CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
ifeq ($(DEBUG), 1) ifeq ($(DEBUG), 1)
CFLAGS += -ggdb -g3 CFLAGS += -ggdb -g3 -DNAME=DEBUG_BUILD
endif endif

View File

@ -1,3 +1,4 @@
# delete file
file build/stm32f1_buisnesscard_v1.elf file build/stm32f1_buisnesscard_v1.elf
target extended localhost:3333 target extended localhost:3333

View File

@ -1,531 +0,0 @@
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
Loading section .isr_vector, size 0x10c lma 0x8000000
Loading section .text, size 0x38c0 lma 0x8000110
Loading section .rodata, size 0x9c lma 0x80039d0
Loading section .init_array, size 0x4 lma 0x8003a6c
Loading section .fini_array, size 0x4 lma 0x8003a70
Loading section .data, size 0x30 lma 0x8003a74
Start address 0x080038e4, load size 15008
Transfer rate: 15 KB/sec, 2501 bytes/write.
Breakpoint 1, main () at Core/Src/main.c:130
130 HAL_SuspendTick();
$1 = {min_r = -1, min_i = -0.5, max_r = 1, max_i = 0.5}
$2 = {min_r = 3.1577176569116192, min_i = 0.22066305108751161, max_r = 3.1577882779434727, max_i = 0.22069836160343248}
$3 = {min_r = 3.1576023402469482, min_i = 0.22069267606110915, max_r = 3.1576029655564359, max_i = 0.22069298871585336}
$4 = {min_r = 1.5143340717923357, min_i = -1.4054856689592869e-05, max_r = 1.5143697529846534, max_i = 3.7857394692316253e-06}
A debugging session is active.
Inferior 1 [Remote target] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
[Inferior 1 (Remote target) detached]
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
Loading section .isr_vector, size 0x10c lma 0x8000000
Loading section .text, size 0x38c0 lma 0x8000110
Loading section .rodata, size 0x9c lma 0x80039d0
Loading section .init_array, size 0x4 lma 0x8003a6c
Loading section .fini_array, size 0x4 lma 0x8003a70
Loading section .data, size 0x30 lma 0x8003a74
Start address 0x080038e4, load size 15008
Transfer rate: 15 KB/sec, 2501 bytes/write.
Breakpoint 1, main () at Core/Src/main.c:130
130 HAL_SuspendTick();
$1 = {min_r = -1, min_i = -0.5, max_r = 1, max_i = 0.5}
$2 = 1.31749451
$3 = {min_r = 3.1577176569116192, min_i = 0.22066305108751161, max_r = 3.1577882779434727, max_i = 0.22069836160343248}
$4 = 0.183570281
$5 = {min_r = 3.1576023402469482, min_i = 0.22069267606110915, max_r = 3.1576029655564359, max_i = 0.22069298871585336}
$6 = 0.217522398
$7 = {min_r = 1.5143340717923357, min_i = -1.4054856689592869e-05, max_r = 1.5143697529846534, max_i = 3.7857394692316253e-06}
$8 = 0.761290252
A debugging session is active.
Inferior 1 [Remote target] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
[Inferior 1 (Remote target) detached]
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
Loading section .isr_vector, size 0x10c lma 0x8000000
Loading section .text, size 0x38c0 lma 0x8000110
Loading section .rodata, size 0x9c lma 0x80039d0
Loading section .init_array, size 0x4 lma 0x8003a6c
Loading section .fini_array, size 0x4 lma 0x8003a70
Loading section .data, size 0x30 lma 0x8003a74
Start address 0x080038e4, load size 15008
Transfer rate: 15 KB/sec, 2501 bytes/write.
Breakpoint 1, main () at Core/Src/main.c:130
130 HAL_SuspendTick();
$1 = {min_r = -1, min_i = -0.5, max_r = 1, max_i = 0.5}
$2 = 1.31749451
$3 = {min_r = 3.1577176569116192, min_i = 0.22066305108751161, max_r = 3.1577882779434727, max_i = 0.22069836160343248}
$4 = 0.183570281
$5 = {min_r = 3.1576023402469482, min_i = 0.22069267606110915, max_r = 3.1576029655564359, max_i = 0.22069298871585336}
$6 = 0.217522398
$7 = {min_r = 1.5143340717923357, min_i = -1.4054856689592869e-05, max_r = 1.5143697529846534, max_i = 3.7857394692316253e-06}
$8 = 0.761290252
A debugging session is active.
Inferior 1 [Remote target] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
[Inferior 1 (Remote target) detached]
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
Loading section .isr_vector, size 0x10c lma 0x8000000
Loading section .text, size 0x38c0 lma 0x8000110
Loading section .rodata, size 0x9c lma 0x80039d0
Loading section .init_array, size 0x4 lma 0x8003a6c
Loading section .fini_array, size 0x4 lma 0x8003a70
Loading section .data, size 0x30 lma 0x8003a74
Start address 0x080038e4, load size 15008
Transfer rate: 15 KB/sec, 2501 bytes/write.
Breakpoint 1, main () at Core/Src/main.c:130
130 HAL_SuspendTick();
$1 = {min_r = -1, min_i = -0.5, max_r = 1, max_i = 0.5}
$2 = 1.31749451
$3 = {min_r = 3.1577176569116192, min_i = 0.22066305108751161, max_r = 3.1577882779434727, max_i = 0.22069836160343248}
$4 = 0.183570281
$5 = {min_r = 3.1576023402469482, min_i = 0.22069267606110915, max_r = 3.1576029655564359, max_i = 0.22069298871585336}
$6 = 0.217522398
$7 = {min_r = 1.5143340717923357, min_i = -1.4054856689592869e-05, max_r = 1.5143697529846534, max_i = 3.7857394692316253e-06}
$8 = 0.761290252
A debugging session is active.
Inferior 1 [Remote target] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
[Inferior 1 (Remote target) detached]
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
Loading section .isr_vector, size 0x10c lma 0x8000000
Loading section .text, size 0x38c0 lma 0x8000110
Loading section .rodata, size 0x9c lma 0x80039d0
Loading section .init_array, size 0x4 lma 0x8003a6c
Loading section .fini_array, size 0x4 lma 0x8003a70
Loading section .data, size 0x30 lma 0x8003a74
Start address 0x080038e4, load size 15008
Transfer rate: 15 KB/sec, 2501 bytes/write.
Breakpoint 1, main () at Core/Src/main.c:130
130 HAL_SuspendTick();
$1 = {min_r = -1, min_i = -0.5, max_r = 1, max_i = 0.5}
$2 = 1.31749451
$3 = {min_r = 3.1577176569116192, min_i = 0.22066305108751161, max_r = 3.1577882779434727, max_i = 0.22069836160343248}
$4 = 0.183570281
$5 = {min_r = 3.1576023402469482, min_i = 0.22069267606110915, max_r = 3.1576029655564359, max_i = 0.22069298871585336}
$6 = 0.217522398
$7 = {min_r = 1.5143340717923357, min_i = -1.4054856689592869e-05, max_r = 1.5143697529846534, max_i = 3.7857394692316253e-06}
$8 = 0.761290252
A debugging session is active.
Inferior 1 [Remote target] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
[Inferior 1 (Remote target) detached]
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
benchmark.gdb:49: Error in sourced command file:
Error erasing flash with vFlashErase packet
------- tip of the day (disable with set show-tips off) -------
The set show-flags on setting will display CPU flags register in the regs context panel
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────
R0 0
R1 0x42420000
R2 0x12c0c0
R3 0x4b03
R4 0
R5 0x40021000
R6 0
R7 0x80000000
R8 0xffff
R9 0x1000
R10 0x20000054
R11 0x77bdd31d
R12 0xf8ff
SP 0x20005000
LR 0xffffffff
PC 0x80038e4
──────────────────[ DISASM / armcm / thumb mode / set emulate on ]──────────────────
► 0x80038e4 <Reset_Handler> movs r0, r0
0x80038e6 <Reset_Handler+2> movs r0, r0
0x80038e8 <Reset_Handler+4> movs r0, r0
0x80038ea <Reset_Handler+6> movs r0, r0
0x80038ec <Reset_Handler+8> movs r0, r0
0x80038ee <Reset_Handler+10> movs r0, r0
0x80038f0 <Reset_Handler+12> movs r0, r0
0x80038f2 <Reset_Handler+14> movs r0, r0
0x80038f4 <Reset_Handler+16> movs r0, r0
0x80038f6 <Reset_Handler+18> movs r0, r0
0x80038f8 <Reset_Handler+20> movs r0, r0
─────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────
In file: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/startup_stm32f103xb.s:64
59 .weak Reset_Handler
60 .type Reset_Handler, %function
61 Reset_Handler:
62
63 /* Call the clock system initialization function.*/
► 64 bl SystemInit
65
66 /* Copy the data segment initializers from flash to SRAM */
67 ldr r0, =_sdata
68 ldr r1, =_edata
69 ldr r2, =_sidata
─────────────────────────────────────[ STACK ]──────────────────────────────────────
00:0000│ sp 0x20005000
... ↓ 7 skipped
───────────────────────────────────[ BACKTRACE ]────────────────────────────────────
► 0 0x80038e4 Reset_Handler
────────────────────────────────────────────────────────────────────────────────────
Continuing.
target not halted
target stm32f1x.cpu was not halted when resume was requested
Halt timed out, wake up GDB.
Program received signal SIGINT, Interrupt.
Reset_Handler () at startup_stm32f103xb.s:64
64 bl SystemInit
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────
R0 0
R1 0x42420000
R2 0x12c0c0
R3 0x4b03
R4 0
R5 0x40021000
R6 0
R7 0x80000000
R8 0xffff
R9 0x1000
R10 0x20000054
R11 0x77bdd31d
R12 0xf8ff
SP 0x20005000
LR 0xffffffff
PC 0x80038e4
──────────────────[ DISASM / armcm / thumb mode / set emulate on ]──────────────────
► 0x80038e4 <Reset_Handler> movs r0, r0
0x80038e6 <Reset_Handler+2> movs r0, r0
0x80038e8 <Reset_Handler+4> movs r0, r0
0x80038ea <Reset_Handler+6> movs r0, r0
0x80038ec <Reset_Handler+8> movs r0, r0
0x80038ee <Reset_Handler+10> movs r0, r0
0x80038f0 <Reset_Handler+12> movs r0, r0
0x80038f2 <Reset_Handler+14> movs r0, r0
0x80038f4 <Reset_Handler+16> movs r0, r0
0x80038f6 <Reset_Handler+18> movs r0, r0
0x80038f8 <Reset_Handler+20> movs r0, r0
─────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────
In file: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/startup_stm32f103xb.s:64
59 .weak Reset_Handler
60 .type Reset_Handler, %function
61 Reset_Handler:
62
63 /* Call the clock system initialization function.*/
► 64 bl SystemInit
65
66 /* Copy the data segment initializers from flash to SRAM */
67 ldr r0, =_sdata
68 ldr r1, =_edata
69 ldr r2, =_sidata
─────────────────────────────────────[ STACK ]──────────────────────────────────────
00:0000│ sp 0x20005000
... ↓ 7 skipped
───────────────────────────────────[ BACKTRACE ]────────────────────────────────────
► 0 0x80038e4 Reset_Handler
────────────────────────────────────────────────────────────────────────────────────
Continuing.
target not halted
target stm32f1x.cpu was not halted when resume was requested
The target is not running when halt was requested, stopping GDB.
Program received signal SIGINT, Interrupt.
Reset_Handler () at startup_stm32f103xb.s:64
64 bl SystemInit
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────
R0 0
R1 0x42420000
R2 0x12c0c0
R3 0x4b03
R4 0
R5 0x40021000
R6 0
R7 0x80000000
R8 0xffff
R9 0x1000
R10 0x20000054
R11 0x77bdd31d
R12 0xf8ff
SP 0x20005000
LR 0xffffffff
PC 0x80038e4
──────────────────[ DISASM / armcm / thumb mode / set emulate on ]──────────────────
► 0x80038e4 <Reset_Handler> movs r0, r0
0x80038e6 <Reset_Handler+2> movs r0, r0
0x80038e8 <Reset_Handler+4> movs r0, r0
0x80038ea <Reset_Handler+6> movs r0, r0
0x80038ec <Reset_Handler+8> movs r0, r0
0x80038ee <Reset_Handler+10> movs r0, r0
0x80038f0 <Reset_Handler+12> movs r0, r0
0x80038f2 <Reset_Handler+14> movs r0, r0
0x80038f4 <Reset_Handler+16> movs r0, r0
0x80038f6 <Reset_Handler+18> movs r0, r0
0x80038f8 <Reset_Handler+20> movs r0, r0
─────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────
In file: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/startup_stm32f103xb.s:64
59 .weak Reset_Handler
60 .type Reset_Handler, %function
61 Reset_Handler:
62
63 /* Call the clock system initialization function.*/
► 64 bl SystemInit
65
66 /* Copy the data segment initializers from flash to SRAM */
67 ldr r0, =_sdata
68 ldr r1, =_edata
69 ldr r2, =_sidata
─────────────────────────────────────[ STACK ]──────────────────────────────────────
00:0000│ sp 0x20005000
... ↓ 7 skipped
───────────────────────────────────[ BACKTRACE ]────────────────────────────────────
► 0 0x80038e4 Reset_Handler
────────────────────────────────────────────────────────────────────────────────────
Error erasing flash with vFlashErase packet
Detaching from program: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/build/stm32f1_buisnesscard_v1.elf, Remote target
[Inferior 1 (Remote target) detached]
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
benchmark.gdb:49: Error in sourced command file:
Error erasing flash with vFlashErase packet
------- tip of the day (disable with set show-tips off) -------
Use the pipe <cmd> | <prog> command to pass output of a GDB/Pwndbg command to a shell program, e.g. pipe elfsections | grep bss. This can also be shortened to: | <cmd> | <prog>
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────
R0 0x40
R1 0x80
R2 1
R3 0x20003548
R4 0x97
R5 6
R6 0x8003a20
R7 0
R8 0xffff
R9 0x1000
R10 0x20000054
R11 0x77bdd31d
R12 0
SP 0x20005000
LR 0xffffffff
PC 0x80038e4
──────────────────[ DISASM / armcm / thumb mode / set emulate on ]──────────────────
► 0x80038e4 <Reset_Handler> bl #SystemInit <SystemInit>
0x80038e8 <Reset_Handler+4> ldr r0, [pc, #0x2c] R0, [LoopFillZerobss+14]
0x80038ea <Reset_Handler+6> ldr r1, [pc, #0x30] R1, [LoopFillZerobss+18]
0x80038ec <Reset_Handler+8> ldr r2, [pc, #0x30] R2, [LoopFillZerobss+22]
0x80038ee <Reset_Handler+10> movs r3, #0 R3 => 0
0x80038f0 <Reset_Handler+12> b #Reset_Handler+20 <Reset_Handler+20>
0x80038f8 <Reset_Handler+20> adds r4, r0, r3
0x80038fa <Reset_Handler+22> cmp r4, r1
0x80038fc <Reset_Handler+24> blo #Reset_Handler+14 <Reset_Handler+14>
0x80038fe <Reset_Handler+26> ldr r2, [pc, #0x24] R2, [LoopFillZerobss+26]
0x8003900 <Reset_Handler+28> ldr r4, [pc, #0x24] R4, [LoopFillZerobss+30]
─────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────
In file: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/startup_stm32f103xb.s:64
59 .weak Reset_Handler
60 .type Reset_Handler, %function
61 Reset_Handler:
62
63 /* Call the clock system initialization function.*/
► 64 bl SystemInit
65
66 /* Copy the data segment initializers from flash to SRAM */
67 ldr r0, =_sdata
68 ldr r1, =_edata
69 ldr r2, =_sidata
─────────────────────────────────────[ STACK ]──────────────────────────────────────
00:0000│ sp 0x20005000
... ↓ 7 skipped
───────────────────────────────────[ BACKTRACE ]────────────────────────────────────
► 0 0x80038e4 Reset_Handler
────────────────────────────────────────────────────────────────────────────────────
Continuing.
target not halted
target stm32f1x.cpu was not halted when resume was requested
Program received signal SIGINT, Interrupt.
0x08003428 in HAL_PWR_EnterSLEEPMode (Regulator=Regulator@entry=1, SLEEPEntry=SLEEPEntry@entry=1 '\001') at Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c:432
432 __WFI();
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────
*R0 1
*R1 1
*R2 0xe000ed00
*R3 0
*R4 0x2000009c
*R5 1
*R6 0
*R7 0x2000004c
R8 0xffff
R9 0x1000
R10 0x20000054
R11 0x77bdd31d
R12 0
*SP 0x20004fc0
LR 0x8000ea7
*PC 0x8003428
──────────────────[ DISASM / armcm / thumb mode / set emulate on ]──────────────────
► 0x8003428 <HAL_PWR_EnterSLEEPMode+24> bx lr <main+478>
0x8000ea6 <main+478> ldr r5, [pc, #0x7c] R5, [main+604]
0x8000ea8 <main+480> ldrb r3, [r5] R3, [button_event]
0x8000eaa <main+482> ✔ cbz r3, #main+534 <main+534>
0x8000ede <main+534> bl #HAL_SuspendTick <HAL_SuspendTick>
0x8000ee2 <main+538> movs r1, #1 R1 => 1
0x8000ee4 <main+540> mov r0, r1
0x8000ee6 <main+542> bl #HAL_PWR_EnterSTOPMode <HAL_PWR_EnterSTOPMode>
0x8000eea <main+546> bl #SystemClock_Config <SystemClock_Config>
0x8000eee <main+550> bl #HAL_ResumeTick <HAL_ResumeTick>
0x8000ef2 <main+554> bl #ST7735_wake <ST7735_wake>
─────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────
In file: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c:432
427
428 /* Select SLEEP mode entry -------------------------------------------------*/
429 if(SLEEPEntry == PWR_SLEEPENTRY_WFI)
430 {
431 /* Request Wait For Interrupt */
► 432 __WFI();
433 }
434 else
435 {
436 /* Request Wait For Event */
437 __SEV();
─────────────────────────────────────[ STACK ]──────────────────────────────────────
00:0000│ sp 0x20004fc0
01:0004│ 0x20004fc4
02:0008│ 0x20004fc8
... ↓ 3 skipped
06:0018│ 0x20004fd8
07:001c│ 0x20004fdc
───────────────────────────────────[ BACKTRACE ]────────────────────────────────────
► 0 0x8003428 HAL_PWR_EnterSLEEPMode+24
1 0x8000ea6 main+478
2 0x8003916 Reset_Handler+50
────────────────────────────────────────────────────────────────────────────────────
Error erasing flash with vFlashErase packet
Error erasing flash with vFlashErase packet
Detaching from program: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/build/stm32f1_buisnesscard_v1.elf, Remote target
[Inferior 1 (Remote target) detached]
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
benchmark.gdb:49: Error in sourced command file:
Error erasing flash with vFlashErase packet
------- tip of the day (disable with set show-tips off) -------
Use contextprev and contextnext to display a previous context output again without scrolling
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
───────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────
R0 1
R1 1
R2 0x40007000
R3 4
R4 0xe000ed00
R5 0x20000050
R6 0
R7 0x2000004c
R8 0xffff
R9 0x1000
R10 0x20000054
R11 0x77bdd31d
R12 0
SP 0x20005000
LR 0xffffffff
PC 0x80038e4
──────────────────[ DISASM / armcm / thumb mode / set emulate on ]──────────────────
► 0x80038e4 <Reset_Handler> movs r0, r0
0x80038e6 <Reset_Handler+2> movs r0, r0
0x80038e8 <Reset_Handler+4> movs r0, r0
0x80038ea <Reset_Handler+6> movs r0, r0
0x80038ec <Reset_Handler+8> movs r0, r0
0x80038ee <Reset_Handler+10> movs r0, r0
0x80038f0 <Reset_Handler+12> movs r0, r0
0x80038f2 <Reset_Handler+14> movs r0, r0
0x80038f4 <Reset_Handler+16> movs r0, r0
0x80038f6 <Reset_Handler+18> movs r0, r0
0x80038f8 <Reset_Handler+20> movs r0, r0
─────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────
In file: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/startup_stm32f103xb.s:64
59 .weak Reset_Handler
60 .type Reset_Handler, %function
61 Reset_Handler:
62
63 /* Call the clock system initialization function.*/
► 64 bl SystemInit
65
66 /* Copy the data segment initializers from flash to SRAM */
67 ldr r0, =_sdata
68 ldr r1, =_edata
69 ldr r2, =_sidata
─────────────────────────────────────[ STACK ]──────────────────────────────────────
00:0000│ sp 0x20005000
... ↓ 7 skipped
───────────────────────────────────[ BACKTRACE ]────────────────────────────────────
► 0 0x80038e4 Reset_Handler
────────────────────────────────────────────────────────────────────────────────────
Error erasing flash with vFlashErase packet
Continuing.
target not halted
target stm32f1x.cpu was not halted when resume was requested
shutdown command invoked
Remote connection closed
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
Loading section .isr_vector, size 0x10c lma 0x8000000
Loading section .text, size 0x38c0 lma 0x8000110
Loading section .rodata, size 0x9c lma 0x80039d0
Loading section .init_array, size 0x4 lma 0x8003a6c
Loading section .fini_array, size 0x4 lma 0x8003a70
Loading section .data, size 0x30 lma 0x8003a74
Start address 0x080038e4, load size 15008
Transfer rate: 14 KB/sec, 2501 bytes/write.
Breakpoint 1, main () at Core/Src/main.c:130
130 HAL_SuspendTick();
Breakpoint 1 at 0x8000e9a: file Core/Src/main.c, line 129.
Note: automatically using hardware breakpoints for read-only addresses.
Loading section .isr_vector, size 0x10c lma 0x8000000
Loading section .text, size 0x38c0 lma 0x8000110
Loading section .rodata, size 0x9c lma 0x80039d0
Loading section .init_array, size 0x4 lma 0x8003a6c
Loading section .fini_array, size 0x4 lma 0x8003a70
Loading section .data, size 0x30 lma 0x8003a74
Start address 0x080038e4, load size 15008
Transfer rate: 15 KB/sec, 2501 bytes/write.
Breakpoint 1, main () at Core/Src/main.c:130
130 HAL_SuspendTick();
$1 = {min_r = -1, min_i = -0.5, max_r = 1, max_i = 0.5}
$2 = 1.31749451
$3 = {min_r = 3.1577176569116192, min_i = 0.22066305108751161, max_r = 3.1577882779434727, max_i = 0.22069836160343248}
$4 = 0.183570281
$5 = {min_r = 3.1576023402469482, min_i = 0.22069267606110915, max_r = 3.1576029655564359, max_i = 0.22069298871585336}
$6 = 0.217522398
$7 = {min_r = 1.5143340717923357, min_i = -1.4054856689592869e-05, max_r = 1.5143697529846534, max_i = 3.7857394692316253e-06}
$8 = 0.761290252
Quit
Detaching from program: /home/indigo/projects/stm32_buisnesscard/program/stm32f1_buisnesscard_v1/build/stm32f1_buisnesscard_v1.elf, Remote target
Remote connection closed

View File

@ -1,201 +0,0 @@
##########################################################################################################################
# File automatically-generated by tool: [projectgenerator] version: [4.5.0-RC5] date: [Sun Apr 27 01:38:15 CDT 2025]
##########################################################################################################################
# ------------------------------------------------
# Generic Makefile (based on gcc)
#
# ChangeLog :
# 2017-02-10 - Several enhancements + project update mode
# 2015-07-22 - first version
# ------------------------------------------------
######################################
# target
######################################
TARGET = stm32f1_buisnesscard_v1
######################################
# building variables
######################################
# debug build?
DEBUG = 1
# optimization
OPT = -Og -Wall
#######################################
# paths
#######################################
# Build path
BUILD_DIR = build
######################################
# source
######################################
# C sources
C_SOURCES = \
Core/Src/main.c \
Core/Src/stm32f1xx_it.c \
Core/Src/stm32f1xx_hal_msp.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_spi.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c \
Core/Src/system_stm32f1xx.c \
Core/Src/sysmem.c \
Core/Src/syscalls.c \
Core/Src/st7735.c \
Core/Src/fonts.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c \
#Core/Src/mandelbrot.c
# ASM sources
# ASM sources# ASM sources# ASM sources# ASM sourcesASM_SOURCES = \
startup_stm32f103xb.s
# ASM sources
ASMM_SOURCES =
#######################################
# binaries
#######################################
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
#######################################
# CFLAGS
#######################################
# cpu
CPU = -mcpu=cortex-m3
# fpu
# NONE for Cortex-M0/M0+/M3
# float-abi
# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
# macros for gcc
# AS defines
AS_DEFS =
# C defines
C_DEFS = \
-DUSE_HAL_DRIVER \
-DSTM32F103xB
# AS includes
AS_INCLUDES =
# C includes
C_INCLUDES = \
-ICore/Inc \
-IDrivers/STM32F1xx_HAL_Driver/Inc \
-IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy \
-IDrivers/CMSIS/Device/ST/STM32F1xx/Include \
-IDrivers/CMSIS/Include
# compile gcc flags
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
ifeq ($(DEBUG), 1)
CFLAGS += -ggdb
endif
# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
#######################################
# LDFLAGS
#######################################
# link script
LDSCRIPT = stm32f103c8tx_flash.ld
# libraries
LIBS = -lc -lm -lnosys
LIBDIR =
#LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
LDFLAGS = $(MCU) -ggdb -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref
# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASMM_SOURCES:.S=.o)))
vpath %.S $(sort $(dir $(ASMM_SOURCES)))
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
$(CC) $(CFLAGS) $(OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(HEX) $< $@
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(BIN) $< $@
$(BUILD_DIR):
mkdir $@
#######################################
# clean up
#######################################
clean:
-rm -fR $(BUILD_DIR)
#######################################
# dependencies
#######################################
-include $(wildcard $(BUILD_DIR)/*.d)
# *** EOF ***

View File

@ -0,0 +1,7 @@
before mod change
$3 = {0.441072255, 0.427796572, 0.214012727, 1.09791195, 1.38234675, 0.860323548, 0.396820068}
$4 = {0.786849678, 1.75887191, 0.250482649, 2.17491865, 2.08977127, 1.37807417, 2.25014758}
{0.439698875, 0.42016688, 0.212486804, 1.10897517, 1.41301811, 0.844758987, 0.392089635}

View File

@ -1,4 +0,0 @@
border tracing - 255 iter only!
frame shift
change: side that has most iterations is the saved fb
benchamrking: make shift benchmark

View File

@ -0,0 +1,6 @@
up + down + 2 secs: enable debug mode
right: go to next slide
up: show border tracing
enable zoom/pan limits

View File

@ -1,793 +0,0 @@
/** READ BEFORE JUDING!
* Yes, I know this code is a mess. Debug code is added
* happhazardly, two cameras are used, etc.
* That's because it's a temporary program
* to create optimizations and debug rendering issues without hardware.
* None of this is going to be included in the project, and the code is thus
* not extensible or organized; it really doesn't save any effort to do so.
*
* This code is meant for my eyes only. You've been warned!
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <raylib.h>
#include <raymath.h>
#include <limits.h>
#include <complex.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#define WINDOW_SIZE_X 1600
#define WINDOW_SIZE_Y 800
#define RES_X 160
#define RES_Y 80
#define DEFAULT_CENTER_X 0
#define DEFAULT_CENTER_Y 0
#define MOUSE_BUTTON 0
#define STEP_SIZE .1
#define ZOOM_SIZE .1
#define DECIMAL_LOC 28
#define DOUBLE_SCALER (1 << DECIMAL_LOC)
#define DOUBLE_TO_FIXED(val) (int32_t)((val) * DOUBLE_SCALER)
#define FIXED_MULTIPLY(x,y) ((((uint64_t)(x))*(y)) >> DECIMAL_LOC)
#define FIXED_TO_DOUBLE(val) ((val) / (double)DOUBLE_SCALER)
#define INFTY 2
#define INFTY_SQR INFTY * INFTY
#define ITERS 255
#define INFTY_SQR_FIXED DOUBLE_TO_FIXED(INFTY_SQR)
//#define SHIP
//#undef SHIP
//#define COLOR_DEBUG
Color get_color_dbg(int i) {
if(i == ITERS) return (Color){0,0,255,255};
// if(i == 0) return (Color){255,255,255,255};
return (Color){255,0,255,255};
}
#ifdef COLOR_DEBUG
#elif SHIP
Color get_color(int i) {
if(i == ITERS) return (Color){0, 0, 0, 255};
if(i == 0) return (Color){0, 0, 0, 255};
return (Color) {
2*(i - 128)+255,
0,
0,
255
};
}
#else
Color get_color(int i) {
// if((i == ITERS) || (i == 0)) return (Color){0, 0, 0, 255};
if(i == ITERS) return (Color){0,0,0,255};
if(i == 0) return (Color){0,0,1,255};
if(i < 128) {
return (Color) {
(8*(i - 128)+255) & 0xff,
0,
(16*(i - 64)+255) & 0xff,
255
};
}
return (Color) {
0,
0,
((unsigned int)-2*(i - 128)+255) & 0xff,
255
};
}
#endif
//C does remainder, not modulo.
//TODO optimize for mod 8
inline int mod(int n, int d) {
int r = n % d;
return (r < 0) ? r + d : r;
}
int mod(int n, int d);
struct camera {
double min_r, min_i, max_r, max_i;
};
typedef struct {
int32_t r; int32_t i;
} FixedCord;
static inline int iterate(FixedCord c) {
int32_t z_i = 0;
int32_t z_r = 0;
int32_t z_r_2, z_i_2, zn_r, zn_i;
for(int it = 0; it < ITERS; it++) {
z_r_2 = FIXED_MULTIPLY(z_r, z_r);
z_i_2 = FIXED_MULTIPLY(z_i, z_i);
zn_r = z_r_2 - z_i_2 + c.r;
#ifdef SHIP
zn_i = abs(FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#else
zn_i = (FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#endif
z_i = zn_i;
z_r = zn_r;
if(z_i_2 + z_r_2 > INFTY_SQR_FIXED) return it;
}
return ITERS;
}
//blllluuuuurg, matracies and vectors in raylib are floats and we need doubles
void shift_cam(struct camera *cam, double step_r, double step_i) {
double i_offset = (cam->max_i - cam->min_i) * step_i;
double r_offset = (cam->max_r - cam->min_r) * step_r;
cam->min_i += i_offset;
cam->max_i += i_offset;
cam->min_r += r_offset;
cam->max_r += r_offset;
}
void zoom_cam(struct camera *cam, double zoom) {
double i_scale = (cam->max_i - cam->min_i) * zoom;
double r_scale = (cam->max_r - cam->min_r) * zoom;
cam->min_i += i_scale;
cam->max_i -= i_scale;
cam->min_r += r_scale;
cam->max_r -= r_scale;
}
enum DIRECTIONS {
N, NE, E, SE, S, SW, W, NW
};
//we can inline these if needed
inline bool bitarray_check(uint8_t *array, size_t i) {
return array[i/8] & (1 << (i%8));
}
inline void bitarray_set(uint8_t *array, size_t i) {
array[i/8] |= (1 << (i%8));
}
inline FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step) {
if((direction == NW) || (direction < E)) from_coord.i += step.i;
if((direction > N) && (direction < S)) from_coord.r += step.r;
if((direction > E) && (direction < W)) from_coord.i -= step.i;
if(direction > S) from_coord.r -= step.r;
return from_coord;
}
FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step);
size_t get_neighbor_index(size_t from_pixel, int direction) {
const int neighbor_index_accl[8] =
{-RES_X, -RES_X + 1, 1, RES_X + 1, RES_X, RES_X - 1, -1, -RES_X - 1};
from_pixel += neighbor_index_accl[direction];
//canidate for optimization; lots of branches. maybe inline
return from_pixel;
}
//we'll be storing info in the green channel to utalize available memory
//per pixel.
#define BACKSTACK_SIZE 32
#define GCHAN_UNRENDERED 0 //don't change; green channel zero'd on cam move
#define GCHAN_BLOCKED (1 << 7) //interior element or visiteed
#define GCHAN_INTERNAL (1 << 5) //part of set, 0x20
#define GCHAN_EXTERNAL (1 << 0) //not part of set, 0x10
#define GCHAN_INNER_VISITED (1 << 3)
#define GCHAN_INNER_CLOSED (1 << 2)
/**
void switch_pixel(coord &this_coord, const coord step, size_t this_index, int dir) {
}
**/
void debug_step(Color *pix, Texture *tex, size_t index, bool pause) {
return;
// SetTargetFPS(0);
static bool fuckin_manual_pause_iguess = false;
static Camera2D cam = {0};
if(!cam.zoom) cam.zoom = (float)GetRenderWidth()/RES_X;
static int debug_color = 0;
const float dbg_cam_step = 100;
const float dbg_cam_zoom = 1.5;
(pause || fuckin_manual_pause_iguess) ? SetTargetFPS(60) : SetTargetFPS(0);
for(;;) {
switch(GetKeyPressed()) {
case KEY_UP:
cam.offset.y += dbg_cam_step;
break;
case KEY_DOWN:
cam.offset.y -= dbg_cam_step;
break;
case KEY_RIGHT:
cam.offset.x += dbg_cam_step;
break;
case KEY_LEFT:
cam.offset.x -= dbg_cam_step;
break;
case KEY_W:
cam.zoom *= dbg_cam_zoom;
break;
case KEY_S:
cam.zoom /= dbg_cam_zoom;
break;
case KEY_SPACE:
Vector2 mouse_pos = Vector2Multiply(GetMousePosition(), (Vector2){(double)RES_X / WINDOW_SIZE_X, (double)RES_Y / WINDOW_SIZE_Y});
//mouse_pos = Vector2Divide(mouse_pos, (Vector2){cam.zoom, cam.zoom});
printf("%f, %f (%lu)\n", mouse_pos.x, mouse_pos.y, ((size_t)mouse_pos.y * RES_X) + (size_t)mouse_pos.x);
break;
case KEY_ENTER:
return;
default:
BeginDrawing();
pix[index] =
(Color) {debug_color, pix[index].g, 0, 255};
BeginDrawing();
UpdateTexture(*tex, pix);
DrawTextureEx(*tex, (Vector2)
{0 - cam.offset.x, cam.offset.y}, 0,
cam.zoom, WHITE);
EndDrawing();
if(!pause && !fuckin_manual_pause_iguess) return;
}
}
}
//only need four indecies, however we use 8 because it's more convinient.
void detect_borders(bool borders[8], size_t i) {
//if this is too slow, it's easy to do it without the modulos.
int index_mod = i % RES_X;
bzero(borders, sizeof(*borders) * 8);
if((i + RES_X) > (RES_X * RES_Y)) {
for(int nei_dir = SE; nei_dir <= SW; nei_dir++)
borders[nei_dir] = GCHAN_EXTERNAL;
}
else if(((int)i - RES_X) < 0) {
borders[NE] = GCHAN_EXTERNAL;
borders[N] = GCHAN_EXTERNAL;
borders[NW] = GCHAN_EXTERNAL;
}
if(index_mod == 0) {
for(int nei_dir = SW; nei_dir < NW; nei_dir++)
borders[nei_dir] = GCHAN_EXTERNAL;
}
else if(index_mod == (RES_X - 1)) {
for(int nei_dir = NE; nei_dir < SE; nei_dir++)
borders[nei_dir] = GCHAN_EXTERNAL;
}
/**
//runs into occational percision issues
if((this_coord.i - scale.i) <= cam_bord_fixed_s) {
for(int nei_dir = SE; nei_dir <= SW; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
else if((this_coord.i + scale.i) >= cam_bord_fixed_n) {
printf("bruh\n");
nei_presort[NE] = GCHAN_EXTERNAL;
nei_presort[N] = GCHAN_EXTERNAL;
nei_presort[NW] = GCHAN_EXTERNAL;
}
if((this_coord.r - scale.r) <= cam_bord_fixed_w) {
for(int nei_dir = SW; nei_dir < NW; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
else if((this_coord.r + scale.r) >= cam_bord_fixed_e) {
for(int nei_dir = NE; nei_dir < SE; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
**/
}
void debug_nei_arrays(int *priority, int *presort, size_t index) {
int debug_x = index % RES_X;
int debug_y = index / RES_X;
printf("(%i, %i) %lu: pre [", debug_x, debug_y, index);
for(int nd = 0; nd < 8; nd++) printf("%i, ", presort[nd]);
printf("], pri [");
for(int nd = 0; nd < 8; nd++) printf("%i, ", priority[nd]);
printf("]\n");
}
enum {
SCAN_MODE_NONE,
SCAN_MODE_SAFE,
SCAN_MODE_INTERIOR
} scan_mode;
unsigned int mandelbrot_bordertrace(struct camera *cam, Color *pixels) {
//these lookup tables r cheap cuz on the stm32f1, 1 memory read is 1 instruction
FixedCord scale = {
.r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X),
.i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y)};
FixedCord c = {.r = 0, .i = DOUBLE_TO_FIXED(cam->max_i)};
unsigned int total_iters = 0;
size_t on_pixel = 0;
int border_scanning = 0;
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture debug_tex = LoadTextureFromImage(img);
UnloadImage(img);
// bzero(pixels, RES_X * RES_Y * sizeof(Color));
// for(size_t c = 0; c < (RES_X * RES_Y); c++) pixels[c] = (Color){0,0,0,255};
for(int y = 0; y < RES_Y; y++) {
border_scanning = 0;
for(int x = 0; x < RES_X; x++) {
c.r = DOUBLE_TO_FIXED((((on_pixel % RES_X) / (double)RES_X) * (cam->max_r - cam->min_r)) + cam->min_r);
c.i = DOUBLE_TO_FIXED((((on_pixel / (double)RES_X) / (double)RES_Y) * (cam->min_i - cam->max_i)) + cam->max_i);
/**
SetTargetFPS(0);
BeginDrawing();
UpdateTexture(debug_tex, pixels);
DrawTextureEx(debug_tex, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
**/
switch(pixels[on_pixel].g) {
case GCHAN_INTERNAL:
// printf("starting interior trace...\n");
size_t inner_pix_i = on_pixel;
int next_pix;
bool pass = false;
bool start_detached = false;
bool touching_start;
bool borders[8];
int nei_dir;
size_t nei_i;
bool trusted_nei[8];
{
//TODO
detect_borders(borders, on_pixel);
for(nei_dir = 0; nei_dir < 8; nei_dir += 2) if(borders[nei_dir]) break;
int edge_state = 0;
bool first_unrendered = false;
for(nei_dir = 0; nei_dir < 8; nei_dir += 2) {
nei_i = get_neighbor_index(inner_pix_i, nei_dir);
if((nei_dir == 0) && (pixels[nei_i].g == GCHAN_UNRENDERED)) first_unrendered = true;
if((edge_state & 1) && (pixels[nei_i].g != GCHAN_UNRENDERED)) edge_state++;
else if(!(edge_state & 1) && (pixels[nei_i].g == GCHAN_UNRENDERED)) edge_state++;
}
//tired, easier to think of success states
if(!((edge_state == 1)
|| ((edge_state == 2) && (!first_unrendered && pixels[nei_i].g != GCHAN_UNRENDERED))
|| ((edge_state == 3) && (first_unrendered && pixels[nei_i].g == GCHAN_UNRENDERED)))) break;
}
for(nei_dir = 0; nei_dir < 8; nei_dir++) {
nei_i = get_neighbor_index(inner_pix_i, nei_dir);
if(pixels[nei_i].g == GCHAN_UNRENDERED) trusted_nei[nei_dir] = true;
else trusted_nei[nei_dir] = false;
}
while(true) {
detect_borders(borders, inner_pix_i);
next_pix = -1;
touching_start = false;
//debug_step(pixels, &debug_tex, inner_pix_i, true);
for(nei_dir = 0; nei_dir < 8; nei_dir += 2) {
size_t nei_i;
size_t localized_dirs[8];
if(borders[nei_dir]) continue;
nei_i = get_neighbor_index(inner_pix_i, nei_dir);
if(nei_i == on_pixel) {
touching_start = true;
if(start_detached) {
next_pix = on_pixel;
break;
}
continue;
}
if(pixels[nei_i].g != ((pass) ? GCHAN_INNER_VISITED : GCHAN_INTERNAL)) continue;
//if((pixels[nei_i].g == GCHAN_UNRENDERED) || (pixels[nei_i].g == ((pass) ? GCHAN_INNER_CLOSED : GCHAN_INNER_VISITED))) continue;
for(int i = 0; i < 8; i++) localized_dirs[i] = mod(nei_dir + i, 8);
if(!(trusted_nei[localized_dirs[2]] || trusted_nei[localized_dirs[1]] ||
trusted_nei[localized_dirs[6]] || trusted_nei[localized_dirs[7]])) {
continue;
}
/** TODO if we have time, we can only keep track of safe borders when we get in trouble by looking at
the past pixel. This has a lot of overhead, but I did it before thinking & I'm out of resources.
**/
trusted_nei[localized_dirs[4]] = false;
trusted_nei[localized_dirs[3]] = trusted_nei[localized_dirs[2]];
trusted_nei[localized_dirs[2]] = trusted_nei[localized_dirs[1]];
trusted_nei[localized_dirs[5]] = trusted_nei[localized_dirs[6]];
trusted_nei[localized_dirs[6]] = trusted_nei[localized_dirs[7]];
{
bool front_neighbors[5];
bool local_borders[8];
detect_borders(local_borders, nei_i);
for(int nei_edge_dir = -1; nei_edge_dir <= 1; nei_edge_dir++) {
size_t nei_edge_local = mod(nei_dir + nei_edge_dir, 8);
front_neighbors[nei_edge_dir + 1] =
!(local_borders[nei_edge_local] || (pixels[get_neighbor_index(nei_i, nei_edge_local)].g != GCHAN_UNRENDERED));
}
front_neighbors[3] = trusted_nei[localized_dirs[6]];
front_neighbors[4] = trusted_nei[localized_dirs[2]];
trusted_nei[localized_dirs[7]] = (front_neighbors[0] && (front_neighbors[3] ||
(front_neighbors[1] && front_neighbors[2] && front_neighbors[4])));
trusted_nei[localized_dirs[1]] = (front_neighbors[2] && (front_neighbors[4] ||
(front_neighbors[0] && front_neighbors[1] && front_neighbors[3])));
trusted_nei[localized_dirs[0]] = (front_neighbors[1] && (trusted_nei[localized_dirs[1]] ||
trusted_nei[localized_dirs[7]]));
}
next_pix = nei_i;
break;
}
if(!start_detached && !touching_start && !(inner_pix_i == on_pixel)) start_detached = true;
else if(start_detached && touching_start) {
start_detached = false;
if(pass) {
pixels[inner_pix_i].g = GCHAN_INNER_CLOSED;
pixels[touching_start].g = GCHAN_INNER_CLOSED;
border_scanning = true;
debug_step(pixels, &debug_tex, inner_pix_i, true);
break;
}
else {
pass = true;
pixels[inner_pix_i].g = GCHAN_INNER_VISITED;
inner_pix_i = on_pixel;
continue;
}
}
pixels[inner_pix_i].g = ((pass) ? GCHAN_INNER_CLOSED : GCHAN_INNER_VISITED);
//TODO remove
if(pass) pixels[next_pix].r = 0xff;
else { pixels[next_pix].b = 0xaa; }
if(next_pix < 0) {
debug_step(pixels, &debug_tex, inner_pix_i, true);
break;
}
else {
inner_pix_i = next_pix;
}
}
break;
case GCHAN_UNRENDERED:
if(border_scanning) {
//pixels[on_pixel] = get_color(ITERS);
//printf("interior\n");
pixels[on_pixel] = (Color){0xfe,0,0xfe,0xff};
break;
}
//printf("rendering %i, %i (%lu)\n", x, y, on_pixel);
int i = iterate(c);
total_iters += i;
pixels[on_pixel] = get_color(i);
if(i == ITERS) {
FixedCord this_coord = c;
size_t this_index = on_pixel;
bool seperated_from_start = false;
int nei_priority[8];
int last_nei_priority[8];
int nei_presort[8];
size_t backstack[BACKSTACK_SIZE];
size_t backstack_i = 0;
int backstack_calls = 0;
int nei_dir;
debug_step(pixels, &debug_tex, this_index, false);
bool debug_mode = false;
bool borders[8];
detect_borders(borders, inner_pix_i);
for(nei_dir = 0; nei_dir < 8; nei_dir++) {
size_t nei_i;
if(borders[nei_dir]) break;
nei_i = get_neighbor_index(on_pixel, nei_dir);
if(pixels[nei_i].g & GCHAN_EXTERNAL) break;
}
if(nei_dir >= 8) {
border_scanning = SCAN_MODE_INTERIOR;
break;
}
while(true) {
detect_borders(borders, this_index);
debug_step(pixels, &debug_tex, this_index, false);
if(debug_mode) debug_step(pixels, &debug_tex, on_pixel, debug_mode);
//step 1: check pixels around us, fill in neighbors.
bzero(nei_presort, sizeof(nei_presort));
this_coord.r = DOUBLE_TO_FIXED((((this_index % RES_X) / (double)RES_X) * (cam->max_r - cam->min_r)) + cam->min_r);
this_coord.i = DOUBLE_TO_FIXED((((this_index / (double)RES_X) / (double)RES_Y) * (cam->min_i - cam->max_i)) + cam->max_i);
/** now fill in neighbor info based on green channel,
* iterate if no info available.
* if this is to slow we could flatten this; it's predictable
* where there will be info
**/
// TODO replace modulos with bitwise ops
bool start_is_nei = false;
for(int nei_dir = 0; nei_dir < 8; nei_dir++) {
size_t nei_i;
uint8_t gchan_info;
//happens if we're pushed against the screen
if(borders[nei_dir]) {
nei_presort[nei_dir] = GCHAN_EXTERNAL;
continue;
}
nei_i = get_neighbor_index(this_index, nei_dir);
gchan_info = pixels[nei_i].g;
if(nei_i == on_pixel) start_is_nei = true;
//note that when we move this over, there will be no alpha channel.
//gchan_info will be extracted differently!!!
if(gchan_info) nei_presort[nei_dir] = gchan_info;
else {
int i = iterate(get_neighbor_coord(this_coord, nei_dir, scale));
pixels[nei_i] = get_color(i);
if(i == ITERS) nei_presort[nei_dir] = GCHAN_INTERNAL;
else {
//exterior
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
pixels[nei_i].g = nei_presort[nei_dir];
}
}
if(!start_is_nei && !seperated_from_start && (this_index != on_pixel)) seperated_from_start = true;
if(start_is_nei && seperated_from_start) {
//printf("success!\n");
pixels[this_index].g = GCHAN_BLOCKED;
break;
}
//go back if we're in the interior and not an edge
int edge_cnt = 0;
//sort into prioraties
for(int nei_dir = 0; nei_dir < 8; nei_dir += 2) {
int nei_edge_i;
if(nei_presort[nei_dir] != GCHAN_INTERNAL) {
nei_priority[nei_dir] = -1;
continue;
}
//TODO rename nei_edge_i
//printf("%i: \n", nei_dir);
for(nei_edge_i = -2; nei_edge_i <= 2; nei_edge_i++) {
int nei_edge_mod = mod((nei_dir + nei_edge_i), 8);
if((nei_presort[nei_edge_mod] == GCHAN_EXTERNAL) || borders[nei_edge_mod]) break;
}
if(nei_edge_i > 2) {
//no edge found
nei_priority[nei_dir] = -2; //TODO test; remove interior check if nessesary
continue;
}
//narrow bridge scenario
if(nei_presort[mod((nei_dir + 1), 8)] & nei_presort[mod((nei_dir - 1), 8)] & GCHAN_EXTERNAL) {
nei_i = get_neighbor_index(this_index, nei_dir);
//pixels[nei_i] = (Color) {0xff, pixels[nei_i].g, 0x00, 0xff};
nei_priority[nei_dir] = -1;
continue;
}
edge_cnt++;
nei_priority[nei_dir] = 0;
}
if(edge_cnt >= 2) {
backstack[backstack_i++ % BACKSTACK_SIZE] = this_index;
//printf("backstack increased\n");
}
//now go to canidate with lowest prioraty
pixels[this_index].g = GCHAN_BLOCKED;
for(int priority = 0; priority <= 5; priority++) { //TODO we might not need the priority system anymore
for(int nei_dir = 0; nei_dir < 8; nei_dir += 2) {
if(nei_priority[nei_dir] != priority) continue;
backstack_calls = 0;
this_index = get_neighbor_index(this_index, nei_dir);
this_coord = get_neighbor_coord(this_coord, nei_dir, scale);
//printf("--> (%zu, %zu)\n", this_index % RES_X, this_index / RES_X);
goto NEXT_PIXEL;
}
}
if((backstack_calls++ > BACKSTACK_SIZE) || (backstack_i < 1)) { //please don't cause issues...
//printf("cycled through backstack, questionable success...\n");
break;
}
this_index = backstack[--backstack_i % BACKSTACK_SIZE];
NEXT_PIXEL:
memcpy(last_nei_priority, nei_priority, sizeof(nei_priority));
}
debug_step(pixels, &debug_tex, this_index, true);
}
else pixels[on_pixel].g = GCHAN_EXTERNAL;
break;
case GCHAN_INNER_CLOSED:
//printf("bruh\n");
if(((x + 2) < RES_X) && (pixels[on_pixel + 1].g == GCHAN_UNRENDERED)) border_scanning = SCAN_MODE_NONE;
break;
default:
border_scanning = SCAN_MODE_NONE;
}
on_pixel++;
c.r += scale.r;
//printf("%u\n", on_pixel);
}
border_scanning = false;
}
debug_step(pixels, &debug_tex, 0, true);
for(size_t i = 0; i < (RES_X * RES_Y); i++) pixels[i].g = 0;
return total_iters;
}
unsigned int mandelbrot_unoptimized(struct camera *cam, Color *pixels) {
FixedCord scale = {
.r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X),
.i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y)};
FixedCord c = { .r = DOUBLE_TO_FIXED(cam->min_r), .i = DOUBLE_TO_FIXED(cam->max_i) };
unsigned int total_iters = 0;
size_t on_pixel = 0;
for(int y = 0; y < RES_Y; y++) {
c.r = DOUBLE_TO_FIXED(cam->min_r);
for(int x = 0; x < RES_X; x++) {
int i = iterate(c);
c.r = DOUBLE_TO_FIXED((((on_pixel % RES_X) / (double)RES_X) * (cam->max_r - cam->min_r)) + cam->min_r);
c.i = DOUBLE_TO_FIXED((((on_pixel / (double)RES_X) / (double)RES_Y) * (cam->min_i - cam->max_i)) + cam->max_i);
total_iters += i;
pixels[((y * RES_X) + x)] = get_color(i);
on_pixel++;
// c.r += scale.r;
}
c.i -= scale.i;
}
return total_iters;
}
int main() {
//test();
//return 0;
Color *pixels_unoptimized = malloc(RES_X * RES_Y * sizeof(Color));
Color *pixels_optimized = malloc(RES_X * RES_Y * sizeof(Color));
bool optimized = true;
//(1.514379082621093886019, 0.000033222739567139065) - (1.514381385800912305228, 0.000034374329476534746)
struct camera cam_default = {
.min_r = -1,
.max_r = 1
};
cam_default.min_i = ((double)RES_Y / RES_X) * cam_default.min_r;
cam_default.max_i = ((double)RES_Y / RES_X) * cam_default.max_r;
//done
//.min_r = 0.340060821337554164412, .min_i = -0.076399869494282027227, .max_r = 0.340671385211165078655, .max_i = -0.076094587557451340287
//done
//.min_r = 0.348347456407892719366, .min_i = -0.092130353675640097588, .max_r = 0.349033773135021985201, .max_i = -0.091787195312047098472
//has internal noise
//.min_r = 0.348416088080605645949, .min_i = -0.092130353675640097588, .max_r = 0.349102404807734911785, .max_i = -0.091787195312047098472
//needs diagnol transfer
//.min_r = 0.352126044212195454808, .min_i = -0.101818891004586714599, .max_r = 0.354169737175103083171, .max_i = -0.100797044523048578979
//works
//.min_r = 1.514379082621093886019, .min_i = 0.000033222739567139065, .max_r = 1.514381385800912305228, .max_i = 0.000034374329476534746
// unusual issue; complete rendered border
// .min_r = 0.426539347230382670517, .min_i = 0.218210183100018217939, .max_r = 0.427445609943903681582, .max_i = 0.218663314456816582076
struct camera cam = {
//.min_r = 0.348416088080605645949, .min_i = -0.092130353675640097588, .max_r = 0.349102404807734911785, .max_i = -0.091787195312047098472
.min_r = 0.348347456407892719366, .min_i = -0.092130353675640097588, .max_r = 0.349033773135021985201, .max_i = -0.091787195312047098472
};
InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test");
SetTraceLogLevel(LOG_ERROR);
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture tex = LoadTextureFromImage(img);
UnloadImage(img);
SetTargetFPS(60);
while(!WindowShouldClose()) {
switch(GetKeyPressed()) {
case KEY_UP:
shift_cam(&cam, 0, STEP_SIZE);
break;
case KEY_DOWN:
shift_cam(&cam, 0, -STEP_SIZE);
break;
case KEY_RIGHT:
shift_cam(&cam, STEP_SIZE, 0);
break;
case KEY_LEFT:
shift_cam(&cam, -STEP_SIZE, 0);
break;
case KEY_W:
zoom_cam(&cam, ZOOM_SIZE);
break;
case KEY_S:
zoom_cam(&cam, -ZOOM_SIZE);
break;
case KEY_SPACE:
optimized = !optimized;
break;
default:
BeginDrawing();
EndDrawing();
continue;
break;
}
printf(".min_r = %.21f, .min_i = %.21f, .max_r = %.21f, .max_i = %.21f\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i);
clock_t begin, end;
double time_unoptimized;
double time_optimized;
for(int i = 0; i < (RES_X * RES_Y); i++) { pixels_unoptimized[i] = (Color){0, 0, 0, 0xff}; }
for(int i = 0; i < (RES_X * RES_Y); i++) { pixels_optimized[i] = (Color){0, 0, 0, 0xff}; }
begin = clock();
unsigned int unoptimized_iters = mandelbrot_unoptimized(&cam, pixels_unoptimized);
end = clock();
time_unoptimized = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Unoptimized: %u iterations, %f seconds\n", unoptimized_iters, time_unoptimized);
begin = clock();
unsigned int optimized_iters = mandelbrot_bordertrace(&cam, pixels_optimized);
end = clock();
time_optimized = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Border tracing: %u iterations, %f seconds\n", optimized_iters, time_optimized);
printf("border tracing does %f%% of nieve approach\n", ((float)optimized_iters / unoptimized_iters) * 100);
BeginDrawing();
printf("%s\n", optimized ? "optimized mode" : "unoptimized mode");
UpdateTexture(tex, optimized ? pixels_optimized : pixels_unoptimized);
DrawTextureEx(tex, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
}
return 0;
}

View File

@ -1,204 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <raylib.h>
#include <raymath.h>
#include <limits.h>
#define WINDOW_SIZE_X 1600
#define WINDOW_SIZE_Y 800
#define RES_X 160
#define RES_Y 80
#define DEFAULT_CENTER_X 0
#define DEFAULT_CENTER_Y 0
#define MOUSE_BUTTON 0
#define STEP_SIZE .1
#define ZOOM_SIZE .1
#define DECIMAL_LOC 28
#define DOUBLE_SCALER (1 << DECIMAL_LOC)
#define DOUBLE_TO_FIXED(val) (int32_t)((val) * DOUBLE_SCALER)
#define FIXED_MULTIPLY(x,y) ((((uint64_t)(x))*(y)) >> DECIMAL_LOC)
#define FIXED_TO_DOUBLE(val) ((val) / (double)DOUBLE_SCALER)
#define INFTY 2
#define INFTY_SQR INFTY * INFTY
#define ITERS 255
#define INFTY_SQR_FIXED DOUBLE_TO_FIXED(INFTY_SQR)
//#define SHIP
#undef SHIP
#ifdef SHIP
Color get_color(int i) {
if(i == ITERS) return (Color){0, 0, 0, 255};
if(i == 0) return (Color){0, 0, 0, 255};
return (Color) {
2*(i - 128)+255,
0,
0,
255
};
}
#else
Color get_color(int i) {
// if((i == ITERS) || (i == 0)) return (Color){0, 0, 0, 255};
if(i == ITERS) return (Color){0,255,0,255};
if(i == 0) return (Color){0, 0, 0, 255};
if(i < 128) {
return (Color) {
(8*(i - 128)+255) & 0xff,
0,
(16*(i - 64)+255) & 0xff,
255
};
}
return (Color) {
0,
0,
((unsigned int)-2*(i - 128)+255) & 0xff,
255
};
}
#endif
struct camera {
double min_r, min_i, max_r, max_i;
};
struct vec2_double {
double x, y;
};
struct vec2_float {
int32_t x, y;
};
static inline int iterate(int32_t r, int32_t i) {
int32_t z_i = 0;
int32_t z_r = 0;
int32_t z_r_2, z_i_2, zn_r, zn_i;
for(int it = 0; it < ITERS; it++) {
z_r_2 = FIXED_MULTIPLY(z_r, z_r);
z_i_2 = FIXED_MULTIPLY(z_i, z_i);
zn_r = z_r_2 - z_i_2 + r;
#ifdef SHIP
zn_i = abs(FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + i;
#else
zn_i = (FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + i;
#endif
z_i = zn_i;
z_r = zn_r;
if(z_i_2 + z_r_2 > INFTY_SQR_FIXED) return it;
}
return ITERS;
}
//blllluuuuurg, matracies and vectors in raylib are floats and we need doubles
void shift_cam(struct camera *cam, double step_r, double step_i) {
double i_offset = (cam->max_i - cam->min_i) * step_i;
double r_offset = (cam->max_r - cam->min_r) * step_r;
cam->min_i += i_offset;
cam->max_i += i_offset;
cam->min_r += r_offset;
cam->max_r += r_offset;
}
void zoom_cam(struct camera *cam, double zoom) {
double i_scale = (cam->max_i - cam->min_i) * zoom;
double r_scale = (cam->max_r - cam->min_r) * zoom;
cam->min_i += i_scale;
cam->max_i -= i_scale;
cam->min_r += r_scale;
cam->max_r -= r_scale;
}
enum DIRECTIONS {
N, NE, E, SE, S, SW, W, NW
};
int main() {
Color *pixels = malloc(RES_X * RES_Y * sizeof(Color));
struct camera cam = {
.min_r = -1,
.max_r = 1,
// .min_i = -1,
// .max_i = 1
};
cam.min_i = ((double)RES_Y / RES_X) * cam.min_r;
cam.max_i = ((double)RES_Y / RES_X) * cam.max_r;
InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test");
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture tex = LoadTextureFromImage(img);
UnloadImage(img);
SetTargetFPS(10);
while(!WindowShouldClose()) {
switch(GetKeyPressed()) {
case KEY_UP:
shift_cam(&cam, 0, STEP_SIZE);
break;
case KEY_DOWN:
shift_cam(&cam, 0, -STEP_SIZE);
break;
case KEY_RIGHT:
shift_cam(&cam, STEP_SIZE, 0);
break;
case KEY_LEFT:
shift_cam(&cam, -STEP_SIZE, 0);
break;
case KEY_W:
zoom_cam(&cam, ZOOM_SIZE);
break;
case KEY_S:
zoom_cam(&cam, -ZOOM_SIZE);
break;
default:
BeginDrawing();
EndDrawing();
continue;
break;
}
printf("(%.21f, %.21f) - (%.21f, %.21f)\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i);
{
int32_t scale_i = DOUBLE_TO_FIXED((cam.max_i - cam.min_i) / (double)RES_Y);
int32_t scale_r = DOUBLE_TO_FIXED((cam.max_r - cam.min_r) / (double)RES_X);
int32_t c_i = DOUBLE_TO_FIXED(cam.max_i);
int32_t c_r;
for(int y = 0; y < RES_Y; y++) {
c_r = DOUBLE_TO_FIXED(cam.min_r);
for(int x = 0; x < RES_X; x++) {
int i = iterate(c_r, c_i);
if(i >= ITERS) {
int start_x = x;
int start_y = y;
do {
for(int canidate_d = 0; canidate_d < NW; canidate_d++) {
}
} while((x != start_x) && (y != start_y));
}
pixels[((y * RES_X) + x)] = get_color(iterate(c_r, c_i));
c_r += scale_r;
}
c_i -= scale_i;
}
}
BeginDrawing();
UpdateTexture(tex, pixels);
DrawTextureEx(tex, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
}
return 0;
}

View File

@ -1,427 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <raylib.h>
#include <raymath.h>
#include <limits.h>
#include <complex.h>
#include <string.h>
#define WINDOW_SIZE_X 1600
#define WINDOW_SIZE_Y 800
#define RES_X 1600
#define RES_Y 800
#define DEFAULT_CENTER_X 0
#define DEFAULT_CENTER_Y 0
#define MOUSE_BUTTON 0
#define STEP_SIZE .1
#define ZOOM_SIZE .1
#define DECIMAL_LOC 28
#define DOUBLE_SCALER (1 << DECIMAL_LOC)
#define DOUBLE_TO_FIXED(val) (int32_t)((val) * DOUBLE_SCALER)
#define FIXED_MULTIPLY(x,y) ((((uint64_t)(x))*(y)) >> DECIMAL_LOC)
#define FIXED_TO_DOUBLE(val) ((val) / (double)DOUBLE_SCALER)
#define INFTY 2
#define INFTY_SQR INFTY * INFTY
#define ITERS 255
#define INFTY_SQR_FIXED DOUBLE_TO_FIXED(INFTY_SQR)
//#define SHIP
//#undef SHIP
#ifdef SHIP
Color get_color(int i) {
if(i == ITERS) return (Color){0, 0, 0, 255};
if(i == 0) return (Color){0, 0, 0, 255};
return (Color) {
2*(i - 128)+255,
0,
0,
255
};
}
#else
Color get_color(int i) {
// if((i == ITERS) || (i == 0)) return (Color){0, 0, 0, 255};
if(i == ITERS) return (Color){0,0,0,255};
if(i == 0) return (Color){0, 0, 0, 255};
if(i < 128) {
return (Color) {
(8*(i - 128)+255) & 0xff,
0,
(16*(i - 64)+255) & 0xff,
255
};
}
return (Color) {
0,
0,
((unsigned int)-2*(i - 128)+255) & 0xff,
255
};
}
#endif
struct camera {
double min_r, min_i, max_r, max_i;
};
typedef struct {
int32_t r; int32_t i;
} FixedCord;
static inline int iterate(FixedCord c) {
int32_t z_i = 0;
int32_t z_r = 0;
int32_t z_r_2, z_i_2, zn_r, zn_i;
for(int it = 0; it < ITERS; it++) {
z_r_2 = FIXED_MULTIPLY(z_r, z_r);
z_i_2 = FIXED_MULTIPLY(z_i, z_i);
zn_r = z_r_2 - z_i_2 + c.r;
#ifdef SHIP
zn_i = abs(FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#else
zn_i = (FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#endif
z_i = zn_i;
z_r = zn_r;
if(z_i_2 + z_r_2 > INFTY_SQR_FIXED) return it;
}
return ITERS;
}
//blllluuuuurg, matracies and vectors in raylib are floats and we need doubles
void shift_cam(struct camera *cam, double step_r, double step_i) {
double i_offset = (cam->max_i - cam->min_i) * step_i;
double r_offset = (cam->max_r - cam->min_r) * step_r;
cam->min_i += i_offset;
cam->max_i += i_offset;
cam->min_r += r_offset;
cam->max_r += r_offset;
}
void zoom_cam(struct camera *cam, double zoom) {
double i_scale = (cam->max_i - cam->min_i) * zoom;
double r_scale = (cam->max_r - cam->min_r) * zoom;
cam->min_i += i_scale;
cam->max_i -= i_scale;
cam->min_r += r_scale;
cam->max_r -= r_scale;
}
enum DIRECTIONS {
N, NE, E, SE, S, SW, W, NW
};
//we can inline these if needed
inline bool bitarray_check(uint8_t *array, size_t i) {
return array[i/8] & (1 << (i%8));
}
inline void bitarray_set(uint8_t *array, size_t i) {
array[i/8] |= (1 << (i%8));
}
inline FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step) {
if((direction == NW) || (direction < E)) from_coord.i += step.i;
if((direction > N) && (direction < S)) from_coord.r += step.r;
if((direction > E) && (direction < W)) from_coord.i -= step.i;
if(direction > S) from_coord.r -= step.r;
return from_coord;
}
FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step);
size_t get_neighbor_index(size_t from_pixel, int direction) {
const size_t neighbor_index_accl[8] =
{-RES_X, -RES_X + 1, 1, RES_X + 1, RES_X, RES_X - 1, -1, -RES_X - 1};
from_pixel += neighbor_index_accl[direction];
//canidate for optimization; lots of branches. maybe inline
return from_pixel;
}
bool bitarray_check(uint8_t *array, size_t i);
void bitarray_set(uint8_t *array, size_t i);
#define BITARRAY_SET(array, i) ((array)[(i)/8] |= (1 << ((i) % 8)))
#define BITARRAY_CLEAR(array, i) ((array)[(i)/8] &= ~(1 << ((i) % 8)))
#define BITARRAY_CHECK(array, i) ((array)[(i)/8] & (1 << ((i) % 8)))
//a lot of these are just so I can keep track of my cases while I program this, simplification will happen later
enum CANIDATE_STATUS {
UNSOLVED = 0,
M_ELEMENT,
M_EXTERIOR,
M_INTERIOR,
M_VISITED, //part of the curve we've been drawing
M_SKETCHY_SUSPENSION_ROPE_BRIDGE_TYPE_SHIT
};
unsigned int mandelbrot_bordertrace(struct camera *cam, Color *pixels) {
//these lookup tables r cheap cuz on the stm32f1, 1 memory read is 1 instruction
FixedCord scale = {
.r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X),
.i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y)};
FixedCord c = {.r = 0, .i = DOUBLE_TO_FIXED(cam->max_i)};
unsigned int total_iters = 0;
size_t on_pixel = 0;
uint8_t border[(RES_X*RES_Y)/8] = {0};
//having these r kinda gross, will restructure later
int32_t cam_bord_fixed_n = DOUBLE_TO_FIXED(cam->min_i);
int32_t cam_bord_fixed_s = DOUBLE_TO_FIXED(cam->max_i);
int32_t cam_bord_fixed_e = DOUBLE_TO_FIXED(cam->max_r);
int32_t cam_bord_fixed_w = DOUBLE_TO_FIXED(cam->min_r);
/**
//for keeping track of border only. will organize later
uint8_t set[(160*80)/8] = {0};
uint8_t unset[(160*80)/8] = {0};
**/
for(int y = 0; y < RES_Y; y++) {
c.r = DOUBLE_TO_FIXED(cam->min_r);
for(int x = 0; x < RES_X; x++) {
uint8_t border_bit = BITARRAY_CHECK(border, on_pixel);
int i = iterate(c);
total_iters += i;
pixels[on_pixel] = get_color(i);
const Color debug_colors[] =
{ (Color) {0xff, 0x00, 0x00, 0xff},
(Color) {0xff, 0x00, 0xff, 0xff},
(Color) {0x00, 0xff, 0x00, 0xff},
(Color) {0x00, 0x00, 0xff, 0xff},
(Color) {0x6a, 0x00, 0xff, 0xff}
};
static int on_dbg_color = 0;
//this is where it all begins
uint8_t rendered[(RES_X*RES_Y)/8] = {0};
uint8_t deadend[(RES_X*RES_Y)/8] = {0};
if(i == ITERS) {
BORDER_START:
__attribute__((unused));
//just makes getting index of neigbor easier; doesn't cost extra cycles
FixedCord starting_bord_cord = c;
FixedCord current_bord_cord = c;
FixedCord last_bord_cord;
int previous_neighbors[8] = {UNSOLVED};
int current_neighbors[8] = {UNSOLVED};
current_neighbors[W] = UNSOLVED;
size_t current_bord_i = on_pixel;
uint8_t visited_border[(RES_X*RES_Y)/8] = {0};
int source_dir = 0;
size_t prev_bord_i = 0;
while(true) {
int filled_neighbors = 0;
//find if we're pushed against screen border.
//find a less gross way to do this
if((current_bord_cord.i - scale.i) < cam_bord_fixed_n) {
for(int nei_dir = SE; nei_dir <= SW; nei_dir++)
current_neighbors[nei_dir] = M_EXTERIOR;
}
if((current_bord_cord.i + scale.i) > cam_bord_fixed_s) {
current_neighbors[NE] = M_EXTERIOR;
current_neighbors[N] = M_EXTERIOR;
current_neighbors[NW] = M_EXTERIOR;
}
if((current_bord_cord.r - scale.r) < cam_bord_fixed_w) {
for(int nei_dir = SW; nei_dir < NW; nei_dir++)
current_neighbors[nei_dir] = M_EXTERIOR;
}
if((current_bord_cord.r + scale.r) > cam_bord_fixed_e) {
for(int nei_dir = NE; nei_dir < SE; nei_dir++)
current_neighbors[nei_dir] = M_EXTERIOR;
}
//get info on neighbors, fill in missing current_neighbors info
for(int nei_dir = 0; nei_dir < 8; nei_dir++) {
size_t nei_i = get_neighbor_index(current_bord_i, nei_dir);
if(current_neighbors[nei_dir] == M_EXTERIOR) continue;
if(current_neighbors[nei_dir] != UNSOLVED) {
filled_neighbors++;
continue;
}
if(current_neighbors[nei_dir] == M_VISITED) continue;
if(BITARRAY_CHECK(visited_border, nei_i)) {
current_neighbors[nei_dir] = M_VISITED;
filled_neighbors++;
continue;
}
int i = iterate(get_neighbor_coord(current_bord_cord, nei_dir, scale));
total_iters += i;
if(i == ITERS) {
current_neighbors[nei_dir] = M_ELEMENT;
filled_neighbors++;
continue;
}
current_neighbors[nei_dir] = M_EXTERIOR;
}
if(filled_neighbors >= 8) {
memcpy(current_neighbors, previous_neighbors, sizeof(current_neighbors));
current_bord_cord = last_bord_cord;
current_bord_i = prev_bord_i;
current_neighbors[source_dir] = M_INTERIOR;
}
BeginDrawing();
DrawPixel(current_bord_i % RES_X, current_bord_i / RES_X, debug_colors[on_dbg_color]);
EndDrawing();
int nei_dir;
memcpy(previous_neighbors, current_neighbors, sizeof(current_neighbors));
memset(current_neighbors, 0, sizeof(current_neighbors));
for(nei_dir = 0; nei_dir < 8; nei_dir++) {
//found a valid neighbor to switch to
if(previous_neighbors[nei_dir] == M_ELEMENT) {
BITARRAY_SET(visited_border, current_bord_i);
current_neighbors[(nei_dir + 4) % 8] = M_VISITED;
if(nei_dir % 2) { //diagnals
current_neighbors[(nei_dir + 3) % 8] = previous_neighbors[(nei_dir + 1) % 8];
current_neighbors[(nei_dir + 5) % 8] = previous_neighbors[(nei_dir - 1) % 8];
}
else {
current_neighbors[(nei_dir + 2) % 8] = previous_neighbors[(nei_dir + 1) % 8];
current_neighbors[(nei_dir + 3) % 8] = previous_neighbors[(nei_dir + 2) % 8];
current_neighbors[(nei_dir + 5) % 8] = previous_neighbors[(nei_dir - 2) % 8];
current_neighbors[(nei_dir + 6) % 8] = previous_neighbors[(nei_dir - 1) % 8];
}
last_bord_cord = current_bord_cord;
current_bord_cord = get_neighbor_coord(current_bord_cord, nei_dir, scale);
prev_bord_i = current_bord_i;
current_bord_i = get_neighbor_index(current_bord_i, nei_dir);
source_dir = nei_dir;
break;
}
}
if(!memcmp(&current_bord_cord, &starting_bord_cord, sizeof(current_bord_cord))) {
for(size_t bord_i = 0; bord_i < sizeof(border); bord_i++){
border[bord_i] |= visited_border[bord_i];
break;
}
}
printf("%zu: ", prev_bord_i);
printf("(%zu, %zu) -> (%zu, %zu) | {", prev_bord_i % RES_X, prev_bord_i / RES_X, current_bord_i % RES_X, current_bord_i / RES_X);
for(int i = 0; i < 8; i++) printf("%i, ", previous_neighbors[i]);
printf("} -> {");
for(int i = 0; i < 8; i++) printf("%i, ", current_neighbors[i]);
printf("}\n");
if(nei_dir > 7) break;
//printf("loop\n");
}
on_dbg_color = (on_dbg_color + 1) % (sizeof(debug_colors) / sizeof(*debug_colors));
}
on_pixel++;
c.r += scale.r;
}
c.i -= scale.i;
}
return total_iters;
}
unsigned int mandelbrot_unoptimized(struct camera *cam, Color *pixels) {
FixedCord scale = { .r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X), .i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y) };
FixedCord c = { .r = 0, .i = DOUBLE_TO_FIXED(cam->max_i) };
unsigned int total_iters = 0;
for(int y = 0; y < RES_Y; y++) {
c.r = DOUBLE_TO_FIXED(cam->min_r);
for(int x = 0; x < RES_X; x++) {
int i = iterate(c);
total_iters += i;
pixels[((y * RES_X) + x)] = get_color(i);
c.r += scale.r;
}
c.i -= scale.i;
}
return total_iters;
}
void test() {
uint8_t bitarray[(160*80)/8] = {0};
int test_i = 9;
BITARRAY_SET(bitarray, test_i);
printf("%s\n", BITARRAY_CHECK(bitarray, 9) ? "true" : "false");
}
int main() {
//test();
//return 0;
Color *pixels = malloc(RES_X * RES_Y * sizeof(Color));
struct camera cam = {
.min_r = -1,
.max_r = 1,
// .min_i = -1,
// .max_i = 1
};
cam.min_i = ((double)RES_Y / RES_X) * cam.min_r;
cam.max_i = ((double)RES_Y / RES_X) * cam.max_r;
InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test");
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture tex = LoadTextureFromImage(img);
UnloadImage(img);
SetTargetFPS(0);
while(!WindowShouldClose()) {
switch(GetKeyPressed()) {
case KEY_UP:
shift_cam(&cam, 0, STEP_SIZE);
break;
case KEY_DOWN:
shift_cam(&cam, 0, -STEP_SIZE);
break;
case KEY_RIGHT:
shift_cam(&cam, STEP_SIZE, 0);
break;
case KEY_LEFT:
shift_cam(&cam, -STEP_SIZE, 0);
break;
case KEY_W:
zoom_cam(&cam, ZOOM_SIZE);
break;
case KEY_S:
zoom_cam(&cam, -ZOOM_SIZE);
break;
default:
BeginDrawing();
EndDrawing();
continue;
break;
}
printf("(%.21f, %.21f) - (%.21f, %.21f)\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i);
printf("Unoptimized: %u iterations\n", mandelbrot_unoptimized(&cam, pixels));
printf("Border tracing: %u iterations\n", mandelbrot_bordertrace(&cam, pixels));
BeginDrawing();
UpdateTexture(tex, pixels);
DrawTextureEx(tex, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
}
return 0;
}

View File

@ -1,585 +0,0 @@
/** READ BEFORE JUDING!
* Yes, I know this code is a mess. Debug code is added
* happhazardly, two cameras are used, etc.
* That's because it's a temporary program
* to create optimizations and debug rendering issues without hardware.
* None of this is going to be included in the project, and the code is thus
* not extensible or organized; it really doesn't save any effort to do so.
*
* This code is meant for my eyes only. You've been warned!
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <raylib.h>
#include <raymath.h>
#include <limits.h>
#include <complex.h>
#include <string.h>
#include <unistd.h>
#define WINDOW_SIZE_X 1600
#define WINDOW_SIZE_Y 800
#define RES_X 1600
#define RES_Y 800
#define DEFAULT_CENTER_X 0
#define DEFAULT_CENTER_Y 0
#define MOUSE_BUTTON 0
#define STEP_SIZE .1
#define ZOOM_SIZE .1
#define DECIMAL_LOC 28
#define DOUBLE_SCALER (1 << DECIMAL_LOC)
#define DOUBLE_TO_FIXED(val) (int32_t)((val) * DOUBLE_SCALER)
#define FIXED_MULTIPLY(x,y) ((((uint64_t)(x))*(y)) >> DECIMAL_LOC)
#define FIXED_TO_DOUBLE(val) ((val) / (double)DOUBLE_SCALER)
#define INFTY 2
#define INFTY_SQR INFTY * INFTY
#define ITERS 255
#define INFTY_SQR_FIXED DOUBLE_TO_FIXED(INFTY_SQR)
//#define SHIP
//#undef SHIP
int debug_x, debug_y;
#ifdef SHIP
Color get_color(int i) {
if(i == ITERS) return (Color){0, 0, 0, 255};
if(i == 0) return (Color){0, 0, 0, 255};
return (Color) {
2*(i - 128)+255,
0,
0,
255
};
}
#else
Color get_color(int i) {
// if((i == ITERS) || (i == 0)) return (Color){0, 0, 0, 255};
if(i == ITERS) return (Color){0,0,0,255};
if(i == 0) return (Color){0,0,1,255};
if(i < 128) {
return (Color) {
(8*(i - 128)+255) & 0xff,
0,
(16*(i - 64)+255) & 0xff,
255
};
}
return (Color) {
0,
0,
((unsigned int)-2*(i - 128)+255) & 0xff,
255
};
}
#endif
//TODO remove
struct debug_info {
int32_t r, i;
int x, y;
};
__attribute__((used)) struct debug_info debug_get_coord(size_t i) {
struct debug_info ret;
ret.x = i % RES_X;
ret.y = i / RES_Y;
return ret;
}
struct camera {
double min_r, min_i, max_r, max_i;
};
typedef struct {
int32_t r; int32_t i;
} FixedCord;
static inline int iterate(FixedCord c) {
int32_t z_i = 0;
int32_t z_r = 0;
int32_t z_r_2, z_i_2, zn_r, zn_i;
for(int it = 0; it < ITERS; it++) {
z_r_2 = FIXED_MULTIPLY(z_r, z_r);
z_i_2 = FIXED_MULTIPLY(z_i, z_i);
zn_r = z_r_2 - z_i_2 + c.r;
#ifdef SHIP
zn_i = abs(FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#else
zn_i = (FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#endif
z_i = zn_i;
z_r = zn_r;
if(z_i_2 + z_r_2 > INFTY_SQR_FIXED) return it;
}
return ITERS;
}
//blllluuuuurg, matracies and vectors in raylib are floats and we need doubles
void shift_cam(struct camera *cam, double step_r, double step_i) {
double i_offset = (cam->max_i - cam->min_i) * step_i;
double r_offset = (cam->max_r - cam->min_r) * step_r;
cam->min_i += i_offset;
cam->max_i += i_offset;
cam->min_r += r_offset;
cam->max_r += r_offset;
}
void zoom_cam(struct camera *cam, double zoom) {
double i_scale = (cam->max_i - cam->min_i) * zoom;
double r_scale = (cam->max_r - cam->min_r) * zoom;
cam->min_i += i_scale;
cam->max_i -= i_scale;
cam->min_r += r_scale;
cam->max_r -= r_scale;
}
enum DIRECTIONS {
N, NE, E, SE, S, SW, W, NW
};
//we can inline these if needed
inline bool bitarray_check(uint8_t *array, size_t i) {
return array[i/8] & (1 << (i%8));
}
inline void bitarray_set(uint8_t *array, size_t i) {
array[i/8] |= (1 << (i%8));
}
inline FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step) {
if((direction == NW) || (direction < E)) from_coord.i += step.i;
if((direction > N) && (direction < S)) from_coord.r += step.r;
if((direction > E) && (direction < W)) from_coord.i -= step.i;
if(direction > S) from_coord.r -= step.r;
return from_coord;
}
FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step);
size_t get_neighbor_index(size_t from_pixel, int direction) {
const int neighbor_index_accl[8] =
{-RES_X, -RES_X + 1, 1, RES_X + 1, RES_X, RES_X - 1, -1, -RES_X - 1};
from_pixel += neighbor_index_accl[direction];
//canidate for optimization; lots of branches. maybe inline
return from_pixel;
}
bool bitarray_check(uint8_t *array, size_t i);
void bitarray_set(uint8_t *array, size_t i);
#define BITARRAY_SET(array, i) ((array)[(i)/8] |= (1 << ((i) % 8)))
#define BITARRAY_CLEAR(array, i) ((array)[(i)/8] &= ~(1 << ((i) % 8)))
#define BITARRAY_CHECK(array, i) ((array)[(i)/8] & (1 << ((i) % 8)))
#define PRESORT_UNSOLVED (1 << 0)
#define PRESORT_VISITED (1 << VISITED)
//#define PRESORT_INTERIOR (1 << INTERIOR) //in set, NOT an edge
//#define PRESORT_BACKTRACKED (1 << BACKTRACED)
//#define PRESORT_EXTERIOR (1 <<
//we'll be storing info in the green channel to utalize all available memory.
//the following is bitmasks to do so
#define GCHAN_RENDERED (1 << 0)
#define GCHAN_VISITED (1 << 1)
#define GCHAN_BLOCKED (1 << 2) //interior element or backtrack
#define GCHAN_EXTERNAL (1 << 3)
#define GCHAN_DEBUG (1 << 4) //extra, not nessesary
/**
void switch_pixel(coord &this_coord, const coord step, size_t this_index, int dir) {
}
**/
unsigned int mandelbrot_bordertrace(struct camera *cam, Color *pixels) {
//these lookup tables r cheap cuz on the stm32f1, 1 memory read is 1 instruction
FixedCord scale = {
.r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X),
.i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y)};
FixedCord c = {.r = 0, .i = DOUBLE_TO_FIXED(cam->max_i)};
unsigned int total_iters = 0;
size_t on_pixel = 0;
//for camera border calculations
int32_t cam_bord_fixed_n = DOUBLE_TO_FIXED(cam->min_i);
int32_t cam_bord_fixed_s = DOUBLE_TO_FIXED(cam->max_i);
int32_t cam_bord_fixed_e = DOUBLE_TO_FIXED(cam->max_r);
int32_t cam_bord_fixed_w = DOUBLE_TO_FIXED(cam->min_r);
//I know this is gross, just for debugigng!
//will clean up once I get things ironed out
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture debug_tex = LoadTextureFromImage(img);
UnloadImage(img);
Color *debug_pix = malloc(RES_X * RES_Y * sizeof(Color));
memcpy(debug_pix, pixels, RES_X * RES_Y * sizeof(Color));
static Camera2D debug_cam = {0};
debug_cam.zoom = (float)GetRenderWidth()/RES_X;
/**
//for keeping track of border only. will organize later
uint8_t set[(160*80)/8] = {0};
uint8_t unset[(160*80)/8] = {0};
**/
const Color debug_colors[] =
{ (Color) {0xff, 0x00, 0x00, 0xff},
(Color) {0xff, 0x00, 0xff, 0xff},
(Color) {0x00, 0xff, 0x00, 0xff},
(Color) {0x00, 0x00, 0xff, 0xff},
(Color) {0x6a, 0x00, 0xff, 0xff}
};
static int debug_color = 0;
for(int y = 0; y < RES_Y; y++) {
c.r = DOUBLE_TO_FIXED(cam->min_r);
for(int x = 0; x < RES_X; x++) {
int i = iterate(c);
total_iters += i;
pixels[on_pixel] = get_color(i);
if(i == ITERS) {
FixedCord this_coord = c;
size_t this_index = on_pixel;
int nei_priority[8];
int last_nei_priority[8];
int last_direction = E;
int nei_presort[8];
//only really need to zero green channel
bzero(pixels, RES_X * RES_Y * sizeof(*pixels));
//this is so fucking knarly
printf("NEW BORDER\n");
while(true) {
//step 1: check pixels around us, fill in neighbors.
bzero(nei_presort, sizeof(nei_presort));
//find if we're pushed against screen border.
//feels gross but I don't think there's a better way
if((this_coord.i - scale.i) < cam_bord_fixed_n) {
for(int nei_dir = SE; nei_dir <= SW; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
else if((this_coord.i + scale.i) > cam_bord_fixed_s) {
nei_presort[NE] = GCHAN_EXTERNAL;
nei_presort[N] = GCHAN_EXTERNAL;
nei_presort[NW] = GCHAN_EXTERNAL;
}
if((this_coord.r - scale.r) < cam_bord_fixed_w) {
for(int nei_dir = SW; nei_dir < NW; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
else if((this_coord.r + scale.r) > cam_bord_fixed_e) {
for(int nei_dir = NE; nei_dir < SE; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
/** now fill in neighbor info based on green channel,
* iterate if no info available.
* if this is to slow we could flatten this; it's predictable
* where there will be info
**/
// TODO replace modulos with something faster
bool interior = true;
for(int nei_dir = 0; nei_dir < 8; nei_dir++) {
size_t nei_i;
uint8_t gchan_info;
//happens if we're pushed against the screen
if(nei_presort[nei_dir] == GCHAN_EXTERNAL) {
interior = false;
continue;
}
nei_i = get_neighbor_index(this_index, nei_dir);
gchan_info = pixels[nei_i].g;
//note that when we move this over, there will be no alpha channel.
//gchan_info will be extracted differently!!!
if(gchan_info & GCHAN_RENDERED) {
gchan_info &= ~(GCHAN_RENDERED);
if(gchan_info & GCHAN_EXTERNAL) {
interior = false;
gchan_info = GCHAN_BLOCKED;
}
if(gchan_info & GCHAN_BLOCKED) gchan_info = GCHAN_BLOCKED;
nei_presort[nei_dir] = gchan_info;
}
else {
int i = iterate(get_neighbor_coord(this_coord, nei_dir, scale));
pixels[nei_i] = get_color(i);
pixels[nei_i].g = GCHAN_RENDERED;
if(i == ITERS) nei_presort[nei_dir] = 0;
else {
//exterior
interior = false;
nei_presort[nei_dir] = GCHAN_BLOCKED;
pixels[nei_i].g |= GCHAN_EXTERNAL;
}
}
}
if(interior) {
printf("interior\n");
asm volatile("interior_check:");
pixels[this_index].g = GCHAN_RENDERED | GCHAN_BLOCKED;
//printf("bruh\n");
memcpy(nei_priority, last_nei_priority, sizeof(nei_priority));
nei_priority[last_direction] = -1;
this_index = get_neighbor_index(this_index, (last_direction + 4) % 8);
this_coord = get_neighbor_coord(
this_coord, (last_direction + 4) % 8, scale);
pixels[this_index].g ^= GCHAN_VISITED; //so we don't think we need to backtrack
}
else {
int blocked_cnt = 0;
for(int nei_dir = 0; nei_dir < 8; nei_dir++) {
int offset_cw = (last_direction - nei_dir) % 8;
int offset_ccw = (nei_dir - last_direction) % 8;
int forward_offset;
switch(nei_presort[nei_dir]) {
case GCHAN_VISITED:
nei_priority[nei_dir] = 15;
break;
case GCHAN_BLOCKED:
case GCHAN_EXTERNAL:
nei_priority[nei_dir] = -1;
blocked_cnt++;
break;
default: //unvisited element
if((nei_presort[(nei_dir - 1) % 8] == 0) ||
(nei_presort[(nei_dir + 1) % 8] == 0)) {
nei_priority[nei_dir] = 3;
break;
}
if((nei_presort[(nei_dir - 1) % 8] == GCHAN_VISITED) ||
(nei_presort[(nei_dir + 1) % 8] == GCHAN_VISITED)) {
nei_priority[nei_dir] = 7;
break;
}
nei_priority[nei_dir] = 11;
break;
}
if(nei_priority[nei_dir] < 0) continue;
forward_offset = abs((offset_cw < offset_ccw) ?
offset_cw : offset_ccw);
if(forward_offset < 3) nei_priority[nei_dir] -= (3-forward_offset);
}
if(blocked_cnt == 8) {
for(int nd = 0; nd < 8; nd++) printf("%i, ", nei_priority[nd]);
printf("we blocked ourselves in!\n");
for(;;) sleep(10);
exit(1);
}
}
for(int priority = 0; priority < 17; priority++) {
for(int nei_dir = 0; nei_dir < 8; nei_dir++) {
if(nei_priority[nei_dir] != priority) continue;
if(nei_dir % 2) continue;
printf("(%zu, %zu): dir %i. [", this_index % RES_X, this_index / RES_X, nei_dir);
for(int nd = 0; nd < 8; nd++) printf("%i, ", nei_priority[nd]);
printf("] -> ");
// if(pixels[this_index].g & GCHAN_VISITED) {
if(priority >= 12) {
pixels[this_index].g |= GCHAN_BLOCKED;
printf("backtracking!!!\n");
}
else
pixels[this_index].g |= GCHAN_VISITED;
memcpy(last_nei_priority, nei_priority, sizeof(nei_priority));
last_direction = nei_dir;
this_index = get_neighbor_index(this_index, nei_dir);
this_coord = get_neighbor_coord(this_coord, nei_dir, scale);
printf("(%zu, %zu)\n", this_index % RES_X, this_index / RES_X);
debug_x = this_index % RES_X;
debug_y = this_index / RES_X;
/**
BeginDrawing();
DrawPixel(debug_x, debug_y,
debug_colors[debug_color % (sizeof(debug_colors) / sizeof(*debug_colors))]);
EndDrawing();
*/
//FOR VISUAL DEBUGGING- read warning on line 0!
{
static bool hit_debug_pix = false;
const float dbg_cam_step = 100;
const float dbg_cam_zoom = .25;
if((debug_x == 1046) && (debug_y == 126)) hit_debug_pix = true;
if(hit_debug_pix) {
for(;;) {
switch(GetKeyPressed()) {
case KEY_UP:
debug_cam.offset.y += dbg_cam_step;
break;
case KEY_DOWN:
debug_cam.offset.y -= dbg_cam_step;
break;
case KEY_RIGHT:
debug_cam.offset.x += dbg_cam_step;
break;
case KEY_LEFT:
debug_cam.offset.x -= dbg_cam_step;
break;
case KEY_W:
debug_cam.zoom += dbg_cam_zoom;
break;
case KEY_S:
debug_cam.zoom -= dbg_cam_zoom;
break;
case KEY_ENTER:
goto switch_pixel;
default:
// BeginDrawing();
BeginDrawing();
const int dbg_clrs = 32;
uint8_t this_dbg_clr =
((debug_color++) % dbg_clrs) * (255 / dbg_clrs);
debug_pix[this_index] =
(Color) {this_dbg_clr, this_dbg_clr, this_dbg_clr, 255};
BeginDrawing();
UpdateTexture(debug_tex, debug_pix);
DrawTextureEx(debug_tex, (Vector2)
{0 - debug_cam.offset.x, debug_cam.offset.y}, 0,
debug_cam.zoom, WHITE);
EndDrawing();
// EndDrawing();
}
}
}
}
goto switch_pixel;
}
}
switch_pixel:
}
debug_color++;
}
on_pixel++;
c.r += scale.r;
}
c.i -= scale.i;
}
return total_iters;
}
unsigned int mandelbrot_unoptimized(struct camera *cam, Color *pixels) {
FixedCord scale = { .r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X), .i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y) };
FixedCord c = { .r = 0, .i = DOUBLE_TO_FIXED(cam->max_i) };
unsigned int total_iters = 0;
for(int y = 0; y < RES_Y; y++) {
c.r = DOUBLE_TO_FIXED(cam->min_r);
for(int x = 0; x < RES_X; x++) {
int i = iterate(c);
total_iters += i;
pixels[((y * RES_X) + x)] = get_color(i);
c.r += scale.r;
}
c.i -= scale.i;
}
return total_iters;
}
void test() {
uint8_t bitarray[(160*80)/8] = {0};
int test_i = 9;
BITARRAY_SET(bitarray, test_i);
printf("%s\n", BITARRAY_CHECK(bitarray, 9) ? "true" : "false");
}
int main() {
//test();
//return 0;
Color *pixels = malloc(RES_X * RES_Y * sizeof(Color));
struct camera cam = {
.min_r = -1,
.max_r = 1,
// .min_i = -1,
// .max_i = 1
};
cam.min_i = ((double)RES_Y / RES_X) * cam.min_r;
cam.max_i = ((double)RES_Y / RES_X) * cam.max_r;
InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test");
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture tex = LoadTextureFromImage(img);
Texture backdrop = LoadTextureFromImage(img);
UnloadImage(img);
SetTargetFPS(60);
while(!WindowShouldClose()) {
switch(GetKeyPressed()) {
case KEY_UP:
shift_cam(&cam, 0, STEP_SIZE);
break;
case KEY_DOWN:
shift_cam(&cam, 0, -STEP_SIZE);
break;
case KEY_RIGHT:
shift_cam(&cam, STEP_SIZE, 0);
break;
case KEY_LEFT:
shift_cam(&cam, -STEP_SIZE, 0);
break;
case KEY_W:
zoom_cam(&cam, ZOOM_SIZE);
break;
case KEY_S:
zoom_cam(&cam, -ZOOM_SIZE);
break;
default:
BeginDrawing();
EndDrawing();
continue;
break;
}
printf("(%.21f, %.21f) - (%.21f, %.21f)\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i);
printf("Unoptimized: %u iterations\n", mandelbrot_unoptimized(&cam, pixels));
BeginDrawing();
UpdateTexture(backdrop, pixels);
DrawTextureEx(backdrop, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
/**
printf("Border tracing: %u iterations\n", mandelbrot_bordertrace(&cam, pixels));
BeginDrawing();
UpdateTexture(tex, pixels);
DrawTextureEx(tex, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
**/
}
return 0;
}

View File

@ -1,561 +0,0 @@
/** READ BEFORE JUDING!
* Yes, I know this code is a mess. Debug code is added
* happhazardly, two cameras are used, etc.
* That's because it's a temporary program
* to create optimizations and debug rendering issues without hardware.
* None of this is going to be included in the project, and the code is thus
* not extensible or organized; it really doesn't save any effort to do so.
*
* This code is meant for my eyes only. You've been warned!
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <raylib.h>
#include <raymath.h>
#include <limits.h>
#include <complex.h>
#include <string.h>
#include <unistd.h>
#define WINDOW_SIZE_X 1600
#define WINDOW_SIZE_Y 800
#define RES_X 1600
#define RES_Y 800
#define DEFAULT_CENTER_X 0
#define DEFAULT_CENTER_Y 0
#define MOUSE_BUTTON 0
#define STEP_SIZE .1
#define ZOOM_SIZE .1
#define DECIMAL_LOC 28
#define DOUBLE_SCALER (1 << DECIMAL_LOC)
#define DOUBLE_TO_FIXED(val) (int32_t)((val) * DOUBLE_SCALER)
#define FIXED_MULTIPLY(x,y) ((((uint64_t)(x))*(y)) >> DECIMAL_LOC)
#define FIXED_TO_DOUBLE(val) ((val) / (double)DOUBLE_SCALER)
#define INFTY 2
#define INFTY_SQR INFTY * INFTY
#define ITERS 255
#define INFTY_SQR_FIXED DOUBLE_TO_FIXED(INFTY_SQR)
//#define SHIP
//#undef SHIP
int debug_x, debug_y;
#ifdef SHIP
Color get_color(int i) {
if(i == ITERS) return (Color){0, 0, 0, 255};
if(i == 0) return (Color){0, 0, 0, 255};
return (Color) {
2*(i - 128)+255,
0,
0,
255
};
}
#else
Color get_color(int i) {
// if((i == ITERS) || (i == 0)) return (Color){0, 0, 0, 255};
if(i == ITERS) return (Color){0,0,0,255};
if(i == 0) return (Color){0,0,1,255};
if(i < 128) {
return (Color) {
(8*(i - 128)+255) & 0xff,
0,
(16*(i - 64)+255) & 0xff,
255
};
}
return (Color) {
0,
0,
((unsigned int)-2*(i - 128)+255) & 0xff,
255
};
}
#endif
//TODO remove
struct debug_info {
int32_t r, i;
int x, y;
};
__attribute__((used)) struct debug_info debug_get_coord(size_t i) {
struct debug_info ret;
ret.x = i % RES_X;
ret.y = i / RES_Y;
return ret;
}
struct camera {
double min_r, min_i, max_r, max_i;
};
typedef struct {
int32_t r; int32_t i;
} FixedCord;
static inline int iterate(FixedCord c) {
int32_t z_i = 0;
int32_t z_r = 0;
int32_t z_r_2, z_i_2, zn_r, zn_i;
for(int it = 0; it < ITERS; it++) {
z_r_2 = FIXED_MULTIPLY(z_r, z_r);
z_i_2 = FIXED_MULTIPLY(z_i, z_i);
zn_r = z_r_2 - z_i_2 + c.r;
#ifdef SHIP
zn_i = abs(FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#else
zn_i = (FIXED_MULTIPLY((DOUBLE_TO_FIXED(2)), (FIXED_MULTIPLY(z_r, z_i)))) + c.i;
#endif
z_i = zn_i;
z_r = zn_r;
if(z_i_2 + z_r_2 > INFTY_SQR_FIXED) return it;
}
return ITERS;
}
//blllluuuuurg, matracies and vectors in raylib are floats and we need doubles
void shift_cam(struct camera *cam, double step_r, double step_i) {
double i_offset = (cam->max_i - cam->min_i) * step_i;
double r_offset = (cam->max_r - cam->min_r) * step_r;
cam->min_i += i_offset;
cam->max_i += i_offset;
cam->min_r += r_offset;
cam->max_r += r_offset;
}
void zoom_cam(struct camera *cam, double zoom) {
double i_scale = (cam->max_i - cam->min_i) * zoom;
double r_scale = (cam->max_r - cam->min_r) * zoom;
cam->min_i += i_scale;
cam->max_i -= i_scale;
cam->min_r += r_scale;
cam->max_r -= r_scale;
}
enum DIRECTIONS {
N, NE, E, SE, S, SW, W, NW
};
//we can inline these if needed
inline bool bitarray_check(uint8_t *array, size_t i) {
return array[i/8] & (1 << (i%8));
}
inline void bitarray_set(uint8_t *array, size_t i) {
array[i/8] |= (1 << (i%8));
}
inline FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step) {
if((direction == NW) || (direction < E)) from_coord.i += step.i;
if((direction > N) && (direction < S)) from_coord.r += step.r;
if((direction > E) && (direction < W)) from_coord.i -= step.i;
if(direction > S) from_coord.r -= step.r;
return from_coord;
}
FixedCord get_neighbor_coord(FixedCord from_coord, int direction, FixedCord step);
size_t get_neighbor_index(size_t from_pixel, int direction) {
const int neighbor_index_accl[8] =
{-RES_X, -RES_X + 1, 1, RES_X + 1, RES_X, RES_X - 1, -1, -RES_X - 1};
from_pixel += neighbor_index_accl[direction];
//canidate for optimization; lots of branches. maybe inline
return from_pixel;
}
bool bitarray_check(uint8_t *array, size_t i);
void bitarray_set(uint8_t *array, size_t i);
#define BITARRAY_SET(array, i) ((array)[(i)/8] |= (1 << ((i) % 8)))
#define BITARRAY_CLEAR(array, i) ((array)[(i)/8] &= ~(1 << ((i) % 8)))
#define BITARRAY_CHECK(array, i) ((array)[(i)/8] & (1 << ((i) % 8)))
//we'll be storing info in the green channel to utalize available memory
//per pixel.
#define GCHAN_BLOCKED (1 << 0) //interior element or visiteed
#define GCHAN_INTERNAL (1 << 1) //part of set
#define GCHAN_EXTERNAL (1 << 2) //not part of set
#define GCHAN_DEBUG (1 << 3) //extra, not nessesary
#define BACKSTACK_SIZE 32
/**
void switch_pixel(coord &this_coord, const coord step, size_t this_index, int dir) {
}
**/
void debug_step(Color *pix, Texture *tex, size_t index) {
static Camera2D cam = {0};
if(!cam.zoom) cam.zoom = (float)GetRenderWidth()/RES_X;
static int debug_color = 0;
const Color debug_colors[] =
{ (Color) {0xff, 0x00, 0x00, 0xff},
(Color) {0xff, 0x00, 0xff, 0xff},
(Color) {0x00, 0xff, 0x00, 0xff},
(Color) {0x00, 0x00, 0xff, 0xff},
(Color) {0x6a, 0x00, 0xff, 0xff}
};
const float dbg_cam_step = 100;
const float dbg_cam_zoom = .25;
for(;;) {
switch(GetKeyPressed()) {
case KEY_UP:
cam.offset.y += dbg_cam_step;
break;
case KEY_DOWN:
cam.offset.y -= dbg_cam_step;
break;
case KEY_RIGHT:
cam.offset.x += dbg_cam_step;
break;
case KEY_LEFT:
cam.offset.x -= dbg_cam_step;
break;
case KEY_W:
cam.zoom += dbg_cam_zoom;
break;
case KEY_S:
cam.zoom -= dbg_cam_zoom;
break;
case KEY_ENTER:
return;
default:
BeginDrawing();
const int dbg_clrs = 32;
uint8_t this_dbg_clr =
((debug_color++) % dbg_clrs) * (255 / dbg_clrs);
pix[index] =
(Color) {this_dbg_clr, this_dbg_clr, this_dbg_clr, 255};
BeginDrawing();
UpdateTexture(*tex, pix);
DrawTextureEx(*tex, (Vector2)
{0 - cam.offset.x, cam.offset.y}, 0,
cam.zoom, WHITE);
EndDrawing();
}
}
}
unsigned int mandelbrot_bordertrace(struct camera *cam, Color *pixels) {
//these lookup tables r cheap cuz on the stm32f1, 1 memory read is 1 instruction
FixedCord scale = {
.r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X),
.i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y)};
FixedCord c = {.r = 0, .i = DOUBLE_TO_FIXED(cam->max_i)};
unsigned int total_iters = 0;
size_t on_pixel = 0;
//for camera border calculations
int32_t cam_bord_fixed_n = DOUBLE_TO_FIXED(cam->min_i);
int32_t cam_bord_fixed_s = DOUBLE_TO_FIXED(cam->max_i);
int32_t cam_bord_fixed_e = DOUBLE_TO_FIXED(cam->max_r);
int32_t cam_bord_fixed_w = DOUBLE_TO_FIXED(cam->min_r);
//I know this is gross, just for debugigng!
//will clean up once I get things ironed out
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture debug_tex = LoadTextureFromImage(img);
UnloadImage(img);
Color *debug_pix = malloc(RES_X * RES_Y * sizeof(Color));
memcpy(debug_pix, pixels, RES_X * RES_Y * sizeof(Color));
/**
//for keeping track of border only. will organize later
uint8_t set[(160*80)/8] = {0};
uint8_t unset[(160*80)/8] = {0};
**/
for(int y = 0; y < RES_Y; y++) {
c.r = DOUBLE_TO_FIXED(cam->min_r);
for(int x = 0; x < RES_X; x++) {
int i = iterate(c);
total_iters += i;
pixels[on_pixel] = get_color(i);
if(i == ITERS) {
FixedCord this_coord = c;
size_t this_index = on_pixel;
int nei_priority[8];
int last_nei_priority[8];
int last_direction = E;
int nei_presort[8];
size_t backstack[BACKSTACK_SIZE];
size_t backstack_i = 0;
//only really need to zero green channel
bzero(pixels, RES_X * RES_Y * sizeof(*pixels));
//this is so fucking knarly
printf("NEW BORDER\n");
while(true) {
//step 1: check pixels around us, fill in neighbors.
bzero(nei_presort, sizeof(nei_presort));
//find if we're pushed against screen border.
//feels gross but I don't think there's a better way
if((this_coord.i - scale.i) < cam_bord_fixed_n) {
for(int nei_dir = SE; nei_dir <= SW; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
else if((this_coord.i + scale.i) > cam_bord_fixed_s) {
nei_presort[NE] = GCHAN_EXTERNAL;
nei_presort[N] = GCHAN_EXTERNAL;
nei_presort[NW] = GCHAN_EXTERNAL;
}
if((this_coord.r - scale.r) < cam_bord_fixed_w) {
for(int nei_dir = SW; nei_dir < NW; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
else if((this_coord.r + scale.r) > cam_bord_fixed_e) {
for(int nei_dir = NE; nei_dir < SE; nei_dir++)
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
/** now fill in neighbor info based on green channel,
* iterate if no info available.
* if this is to slow we could flatten this; it's predictable
* where there will be info
**/
// TODO replace modulos with something faster
bool interior = true;
for(int nei_dir = 0; nei_dir < 8; nei_dir++) {
size_t nei_i;
uint8_t gchan_info;
//happens if we're pushed against the screen
if(nei_presort[nei_dir] == GCHAN_EXTERNAL) {
interior = false;
nei_presort[nei_dir] = GCHAN_EXTERNAL;
continue;
}
nei_i = get_neighbor_index(this_index, nei_dir);
gchan_info = pixels[nei_i].g;
//note that when we move this over, there will be no alpha channel.
//gchan_info will be extracted differently!!!
if(gchan_info) {
if(gchan_info & GCHAN_EXTERNAL) interior = false;
nei_presort[nei_dir] = gchan_info;
}
else {
int i = iterate(get_neighbor_coord(this_coord, nei_dir, scale));
pixels[nei_i] = get_color(i);
if(i == ITERS) nei_presort[nei_dir] = GCHAN_INTERNAL;
else {
//exterior
interior = false;
nei_presort[nei_dir] = GCHAN_EXTERNAL;
}
pixels[nei_i].g = nei_presort[nei_dir];
}
}
//go back if we're in the interior and not an edge
if(interior) {
printf("interior\n");
asm volatile("interior_check:");
pixels[this_index].g = GCHAN_BLOCKED;
//printf("bruh\n");
memcpy(nei_priority, last_nei_priority, sizeof(nei_priority));
nei_priority[last_direction] = -1;
this_index = get_neighbor_index(this_index, (last_direction + 4) % 8);
this_coord = get_neighbor_coord(
this_coord, (last_direction + 4) % 8, scale);
pixels[this_index].g = GCHAN_BLOCKED; //so we don't think we need to backtrack
}
else {
int edge_cnt = 0;
//sort into prioraties
for(int nei_dir = 0; nei_dir < 8; nei_dir += 2) {
int nei_1 = nei_presort[(nei_dir + 1) % 8];
int nei_2 = nei_presort[(nei_dir - 1) % 8];
if((nei_presort[nei_dir] != GCHAN_INTERNAL) || ((nei_1 & nei_2) & (GCHAN_EXTERNAL | GCHAN_BLOCKED))) {
nei_priority[nei_dir] = -1;
}
else if(((nei_1 ^ nei_2) & (GCHAN_INTERNAL | GCHAN_EXTERNAL)) == (GCHAN_INTERNAL | GCHAN_EXTERNAL)) {
edge_cnt++;
nei_priority[nei_dir] = 0;
}
else if(nei_1 & nei_2 & GCHAN_INTERNAL) {
nei_priority[nei_dir] = 1;
}
else if(((nei_1 ^ nei_2) & (GCHAN_BLOCKED | GCHAN_EXTERNAL)) == (GCHAN_BLOCKED | GCHAN_EXTERNAL)) {
nei_priority[nei_dir] = 2;
}
}
if(edge_cnt >= 2) {
backstack[backstack_i] = this_index;
if(backstack_i++ > BACKSTACK_SIZE) {
printf("max backstack\n");
for(;;);
}
printf("backstack increased\n");
}
}
//now go to canidate with lowest prioraty
for(int priority = 0; priority <= 1; priority++) {
for(int nei_dir = 0; nei_dir < 8; nei_dir += 2) {
if(nei_priority[nei_dir] != priority) continue;
printf("(%zu, %zu): dir %i. [", this_index % RES_X, this_index / RES_X, nei_dir);
for(int nd = 0; nd < 8; nd++) printf("%i, ", nei_priority[nd]);
printf("] -> ");
pixels[this_index].g = GCHAN_BLOCKED;
memcpy(last_nei_priority, nei_priority, sizeof(nei_priority));
this_index = get_neighbor_index(this_index, nei_dir);
this_coord = get_neighbor_coord(this_coord, nei_dir, scale);
printf("(%zu, %zu)\n", this_index % RES_X, this_index / RES_X);
debug_x = this_index % RES_X;
debug_y = this_index / RES_X;
//FOR VISUAL DEBUGGING- read warning on line 0!
{
static bool hit_debug_pix = true;
if((debug_x == 1046) && (debug_y == 126)) hit_debug_pix = true;
if(hit_debug_pix) debug_step(debug_pix, &debug_tex, this_index);
}
goto next_pixel;
}
}
printf("checking backtrack stack\nThis pri:");
for(int nd = 0; nd < 8; nd++) printf("%i, ", nei_priority[nd]);
printf("\n");
if(--backstack_i > BACKSTACK_SIZE) {
printf("backstack depleated, no recovery\n");
for(;;);
}
printf("%lu\n", backstack_i);
this_index = backstack[backstack_i];
this_coord.r = (((this_index % RES_X) / (float)RES_X) * (cam->max_r - cam->min_r)) + cam->min_r;
this_coord.i = (((this_index / RES_X) / (float)RES_Y) * (cam->max_i - cam->min_i)) + cam->min_i;
debug_step(debug_pix, &debug_tex, this_index);
next_pixel:
}
}
on_pixel++;
c.r += scale.r;
}
c.i -= scale.i;
}
return total_iters;
}
unsigned int mandelbrot_unoptimized(struct camera *cam, Color *pixels) {
FixedCord scale = { .r = DOUBLE_TO_FIXED((cam->max_r - cam->min_r) / (double)RES_X), .i = DOUBLE_TO_FIXED((cam->max_i - cam->min_i) / (double)RES_Y) };
FixedCord c = { .r = 0, .i = DOUBLE_TO_FIXED(cam->max_i) };
unsigned int total_iters = 0;
for(int y = 0; y < RES_Y; y++) {
c.r = DOUBLE_TO_FIXED(cam->min_r);
for(int x = 0; x < RES_X; x++) {
int i = iterate(c);
total_iters += i;
pixels[((y * RES_X) + x)] = get_color(i);
c.r += scale.r;
}
c.i -= scale.i;
}
return total_iters;
}
void test() {
uint8_t bitarray[(160*80)/8] = {0};
int test_i = 9;
BITARRAY_SET(bitarray, test_i);
printf("%s\n", BITARRAY_CHECK(bitarray, 9) ? "true" : "false");
}
int main() {
//test();
//return 0;
Color *pixels = malloc(RES_X * RES_Y * sizeof(Color));
struct camera cam = {
.min_r = -1,
.max_r = 1,
// .min_i = -1,
// .max_i = 1
};
cam.min_i = ((double)RES_Y / RES_X) * cam.min_r;
cam.max_i = ((double)RES_Y / RES_X) * cam.max_r;
InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test");
Image img = GenImageColor(RES_X, RES_Y, BLUE);
Texture tex = LoadTextureFromImage(img);
Texture backdrop = LoadTextureFromImage(img);
UnloadImage(img);
SetTargetFPS(60);
while(!WindowShouldClose()) {
switch(GetKeyPressed()) {
case KEY_UP:
shift_cam(&cam, 0, STEP_SIZE);
break;
case KEY_DOWN:
shift_cam(&cam, 0, -STEP_SIZE);
break;
case KEY_RIGHT:
shift_cam(&cam, STEP_SIZE, 0);
break;
case KEY_LEFT:
shift_cam(&cam, -STEP_SIZE, 0);
break;
case KEY_W:
zoom_cam(&cam, ZOOM_SIZE);
break;
case KEY_S:
zoom_cam(&cam, -ZOOM_SIZE);
break;
default:
BeginDrawing();
EndDrawing();
continue;
break;
}
printf("(%.21f, %.21f) - (%.21f, %.21f)\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i);
printf("Unoptimized: %u iterations\n", mandelbrot_unoptimized(&cam, pixels));
BeginDrawing();
UpdateTexture(backdrop, pixels);
DrawTextureEx(backdrop, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
printf("Border tracing: %u iterations\n", mandelbrot_bordertrace(&cam, pixels));
BeginDrawing();
UpdateTexture(tex, pixels);
DrawTextureEx(tex, (Vector2){0,0}, 0, (float)GetRenderWidth()/RES_X, WHITE);
EndDrawing();
}
return 0;
}

View File

@ -189,6 +189,7 @@ void switch_pixel(coord &this_coord, const coord step, size_t this_index, int di
**/ **/
void debug_step(Color *pix, Texture *tex, size_t index, bool pause) { void debug_step(Color *pix, Texture *tex, size_t index, bool pause) {
// return;
// SetTargetFPS(0); // SetTargetFPS(0);
static bool fuckin_manual_pause_iguess = false; static bool fuckin_manual_pause_iguess = false;
static Camera2D cam = {0}; static Camera2D cam = {0};
@ -197,7 +198,7 @@ void debug_step(Color *pix, Texture *tex, size_t index, bool pause) {
const float dbg_cam_step = 100; const float dbg_cam_step = 100;
const float dbg_cam_zoom = 1.5; const float dbg_cam_zoom = 1.5;
(pause || fuckin_manual_pause_iguess) ? SetTargetFPS(60) : SetTargetFPS(0); // (pause || fuckin_manual_pause_iguess) ? SetTargetFPS(60) : SetTargetFPS(0);
@ -232,14 +233,15 @@ void debug_step(Color *pix, Texture *tex, size_t index, bool pause) {
default: default:
BeginDrawing(); BeginDrawing();
pix[index] = pix[index] =
(Color) {0, pix[index].g, 255, 255}; (Color) {255, pix[index].g, 255, 255};
BeginDrawing(); BeginDrawing();
UpdateTexture(*tex, pix); UpdateTexture(*tex, pix);
DrawTextureEx(*tex, (Vector2) DrawTextureEx(*tex, (Vector2)
{0 - cam.offset.x, cam.offset.y}, 0, {0 - cam.offset.x, cam.offset.y}, 0,
cam.zoom, WHITE); cam.zoom, WHITE);
EndDrawing(); EndDrawing();
if(!pause && !fuckin_manual_pause_iguess) return; return;
// if(!pause && !fuckin_manual_pause_iguess) return;
} }
} }
} }
@ -316,7 +318,7 @@ unsigned int mandelbrot_bordertrace(struct camera *cam, Color *pixels) {
if(border_scanning) { if(border_scanning) {
//pixels[on_pixel] = get_color(ITERS); //pixels[on_pixel] = get_color(ITERS);
//printf("interior\n"); //printf("interior\n");
pixels[on_pixel] = (Color){0xfe,0,0xfe,0xff}; pixels[on_pixel] = (Color){0x00,0,0x0,0xff};
break; break;
} }
//printf("rendering %i, %i (%lu)\n", x, y, on_pixel); //printf("rendering %i, %i (%lu)\n", x, y, on_pixel);
@ -446,11 +448,6 @@ unsigned int mandelbrot_bordertrace(struct camera *cam, Color *pixels) {
} }
else pixels[on_pixel].g = GCHAN_EXTERNAL; else pixels[on_pixel].g = GCHAN_EXTERNAL;
break; break;
/**
case GCHAN_INNER_CLOSED:
if(((x + 2) < RES_X) && (pixels[on_pixel + 1].g == GCHAN_UNRENDERED)) border_scanning = SCAN_MODE_NONE;
break;
**/
default: default:
border_scanning = SCAN_MODE_NONE; border_scanning = SCAN_MODE_NONE;
} }
@ -525,9 +522,7 @@ int main() {
struct camera cam = { struct camera cam = (struct camera) {-0.641121775196897503157, 0.410802460984564632440, -0.638087553194557455249, 0.412319571985918953416};
.min_r = -0.640818352996663453958, .min_i = 0.410802460984564632440, .max_r = -0.637784130994323406050, .max_i = 0.412319571985918953416
};
// //
InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test"); InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test");
@ -537,7 +532,7 @@ int main() {
Texture tex = LoadTextureFromImage(img); Texture tex = LoadTextureFromImage(img);
UnloadImage(img); UnloadImage(img);
SetTargetFPS(60); SetTargetFPS(0);
while(!WindowShouldClose()) { while(!WindowShouldClose()) {
switch(GetKeyPressed()) { switch(GetKeyPressed()) {
@ -568,7 +563,8 @@ int main() {
continue; continue;
break; break;
} }
printf(".min_r = %.21f, .min_i = %.21f, .max_r = %.21f, .max_i = %.21f\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i); //printf(".min_r = %.21f, .min_i = %.21f, .max_r = %.21f, .max_i = %.21f\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i);
printf("(struct camera) {%.21f, %.21f, %.21f, %.21f}\n", cam.min_r, cam.min_i, cam.max_r, cam.max_i);
clock_t begin, end; clock_t begin, end;
@ -586,7 +582,7 @@ int main() {
printf("Unoptimized: %u iterations, %f seconds\n", unoptimized_iters, time_unoptimized); printf("Unoptimized: %u iterations, %f seconds\n", unoptimized_iters, time_unoptimized);
begin = clock(); begin = clock();
unsigned int optimized_iters = mandelbrot_bordertrace(&cam, pixels_optimized); unsigned int optimized_iters = mandelbrot_bordertrace(&cam, pixels_unoptimized);
end = clock(); end = clock();
time_optimized = (double)(end - begin) / CLOCKS_PER_SEC; time_optimized = (double)(end - begin) / CLOCKS_PER_SEC;

View File

@ -1,7 +1,6 @@
.default: make .default: make
make: make:
gcc main.c -O0 -ggdb3 -o mandelbrot -lraylib -lm -Wall -ggdb gcc main.c -Ofast -o mandelbrot -lraylib -lm -Wall -ggdb
#gcc main.c -Ofast -o mandelbrot -lraylib -lm -Wall -ggdb
clean: clean:
rm -f mandelbrot rm -f mandelbrot

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

BIN
writeup/bad_curcuit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
writeup/bordertracing.mkv Normal file

Binary file not shown.

BIN
writeup/closed_border.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
writeup/pcb_pads.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB