pre-readme
							
								
								
									
										
											BIN
										
									
								
								datasheets/SMD291AX50T3.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								imgs/twopaths.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 489 B | 
							
								
								
									
										1
									
								
								kicad/stm32card/#auto_saved_files#
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | ||||
| /home/indigo/projects/stm32_buisnesscard/kicad/stm32card/_autosave-stm32card.kicad_sch | ||||
							
								
								
									
										17475
									
								
								kicad/stm32card/_autosave-stm32card.kicad_sch
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -11,7 +11,7 @@ | ||||
|       "images": 1.0, | ||||
|       "pads": 1.0, | ||||
|       "shapes": 1.0, | ||||
|       "tracks": 1.0, | ||||
|       "tracks": 0.27000001072883606, | ||||
|       "vias": 1.0, | ||||
|       "zones": 0.7099999785423279 | ||||
|     }, | ||||
|  | ||||
| @ -459,6 +459,7 @@ | ||||
|       "single_global_label": "ignore", | ||||
|       "unannotated": "error", | ||||
|       "unconnected_wire_endpoint": "warning", | ||||
|       "undefined_netclass": "error", | ||||
|       "unit_value_mismatch": "error", | ||||
|       "unresolved_variable": "error", | ||||
|       "wire_dangling": "error" | ||||
| @ -528,10 +529,10 @@ | ||||
|       "gencad": "", | ||||
|       "idf": "", | ||||
|       "netlist": "", | ||||
|       "plot": "../../v3_career_fair/", | ||||
|       "plot": "../stm32card_stencil/", | ||||
|       "pos_files": "", | ||||
|       "specctra_dsn": "", | ||||
|       "step": "", | ||||
|       "step": "stm32card.step", | ||||
|       "svg": "", | ||||
|       "vrml": "" | ||||
|     }, | ||||
|  | ||||
| @ -5259,6 +5259,16 @@ | ||||
| 		) | ||||
| 		(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!" | ||||
| 		(exclude_from_sim no) | ||||
| 		(at 43.434 -3.556 0) | ||||
| @ -15482,13 +15492,12 @@ | ||||
| 		(dnp no) | ||||
| 		(uuid "b24b357b-0b8d-43fe-933c-61bdb6083d63") | ||||
| 		(property "Reference" "R21" | ||||
| 			(at 104.648 140.97 0) | ||||
| 			(at 104.902 142.24 0) | ||||
| 			(effects | ||||
| 				(font | ||||
| 					(size 1.27 1.27) | ||||
| 				) | ||||
| 				(justify right) | ||||
| 				(hide yes) | ||||
| 			) | ||||
| 		) | ||||
| 		(property "Value" "10k" | ||||
| @ -15498,6 +15507,7 @@ | ||||
| 					(size 1.27 1.27) | ||||
| 				) | ||||
| 				(justify right) | ||||
| 				(hide yes) | ||||
| 			) | ||||
| 		) | ||||
| 		(property "Footprint" "Resistor_SMD:R_0603_1608Metric" | ||||
|  | ||||
							
								
								
									
										1
									
								
								kicad/stm32card/~stm32card.kicad_sch.lck
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1 @@ | ||||
| {"hostname":"indigosDesktop","username":"indigo"} | ||||
							
								
								
									
										56
									
								
								kicad/stm32card_stencil/pcb_stencil_gen/kicadExportDxf.py
									
									
									
									
									
										Executable 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) | ||||
							
								
								
									
										48
									
								
								kicad/stm32card_stencil/pcb_stencil_gen/pcbStencilGenerator.scad
									
									
									
									
									
										Executable 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); | ||||
							
								
								
									
										2570
									
								
								kicad/stm32card_stencil/stm32card-Edge_Cuts.dxf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										36
									
								
								kicad/stm32card_stencil/stm32card-Edge_Cuts.svg
									
									
									
									
									
										Normal 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 | 
							
								
								
									
										5748
									
								
								kicad/stm32card_stencil/stm32card-F_Cu.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 124 KiB | 
							
								
								
									
										44570
									
								
								kicad/stm32card_stencil/stm32card-F_Paste.dxf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										3696
									
								
								kicad/stm32card_stencil/stm32card-F_Paste.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 79 KiB | 
| @ -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 | ||||
| c | ||||
| next | ||||
| n | ||||
| print borders | ||||
| n | ||||
| print nei_dir | ||||
| n | ||||
| n | ||||
| print nei_dir | ||||
| print from_pixel + neighbor_index_accl[direction] | ||||
| print direction  | ||||
| print from_pixel - win.w | ||||
| print from_pixel - (win.w + 1) | ||||
| print from_pixel + neighbor_index_accl[1] | ||||
| print from_pixel - win.w + 1 | ||||
| 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 pixels[this_index] | ||||
| print framebuffer[this_index] | ||||
| print framebuffer[this_index] & G_MASK | ||||
| print framebuffer[this_index+1] & G_MASK | ||||
| next | ||||
| print gchan_info | ||||
| 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 | ||||
| d | ||||
| d | ||||
| c | ||||
| quit | ||||
| quit | ||||
| c | ||||
| c | ||||
| quit | ||||
| c | ||||
| quit | ||||
| c | ||||
| quit | ||||
| c | ||||
| quit | ||||
| quit | ||||
| c | ||||
| c | ||||
| quit | ||||
| next | ||||
| qiot | ||||
| quit | ||||
| c | ||||
| quit | ||||
| c | ||||
| print unoptimized_times  | ||||
| cat optimized_times  | ||||
| 
 | ||||
| print optimized_times  | ||||
| exit() | ||||
| quit | ||||
| quit | ||||
| c | ||||
| quit | ||||
| c | ||||
| context | ||||
| quit | ||||
| quit | ||||
| c | ||||
| c | ||||
| f 2 | ||||
| context | ||||
| print cam | ||||
| quit | ||||
| c | ||||
| quit | ||||
| c | ||||
| quit | ||||
| 'c | ||||
| c | ||||
| c | ||||
| quit | ||||
| c | ||||
| HAL_GPIO_TogglePin | ||||
| print HAL_GPIO_TogglePin() | ||||
| b idle  | ||||
| c | ||||
| 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 | ||||
| f 2 | ||||
| print cam | ||||
| c | ||||
| f 2 | ||||
| print cam | ||||
| c | ||||
| f 2 | ||||
| print cam | ||||
| c | ||||
| print cam | ||||
| f 2 | ||||
| print cam | ||||
| quit | ||||
|  | ||||
| @ -2,6 +2,4 @@ | ||||
| #include <signal.h> | ||||
| #include "main.h" | ||||
| 
 | ||||
| 
 | ||||
| void benchmark_start(); | ||||
| void benchmark_stop(); | ||||
| void benchmark(); | ||||
|  | ||||
| @ -7,15 +7,26 @@ | ||||
|   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_RIGHT        GPIO_PIN_2 | ||||
| #define BUTTON_DOWN         GPIO_PIN_0 | ||||
| #define BUTTON_LEFT         GPIO_PIN_1 | ||||
| #define BUTTON_A            GPIO_PIN_13 | ||||
| #define BUTTON_B            GPIO_PIN_14 | ||||
| 
 | ||||
| #define CHARGING_PORT       GPIOB | ||||
| #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; | ||||
| void HAL_GPIO_EXTI_Callback(uint16_t pin); | ||||
|  | ||||
| @ -1,3 +1,17 @@ | ||||
| #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); | ||||
|  | ||||
| @ -30,138 +30,7 @@ extern SPI_HandleTypeDef ST7735_SPI_PORT; | ||||
| #define BACKLIGHT_PORT       GPIOB | ||||
| #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
 | ||||
| #define ST7735_IS_160X80 1 | ||||
| @ -171,18 +40,6 @@ shutdown command invoked | ||||
| #define ST7735_HEIGHT 80 | ||||
| #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 | ||||
|  | ||||
| @ -1,20 +1,77 @@ | ||||
| #include <signal.h> | ||||
| #include "mandelbrot.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() { | ||||
|   TIM4->CNT = 0; | ||||
|   TIM4->CR1 |= TIM_CR1_CEN; | ||||
| } | ||||
| void benchmark_stop() { | ||||
| 
 | ||||
| float benchmark_stop() { | ||||
|   TIM4->CR1 ^= TIM_CR1_CEN; | ||||
|   time = (float)(TIM4->CNT + 1) * (TIM4->PSC + 1) / HAL_RCC_GetSysClockFreq(); | ||||
|   BENCHMARK_CHECKTIME: | ||||
|   __NOP(); | ||||
| //  __BKPT();
 | ||||
|   return (float)(TIM4->CNT + 1) * (TIM4->PSC + 1) / HAL_RCC_GetSysClockFreq(); | ||||
| } | ||||
| 
 | ||||
| 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(); | ||||
| } | ||||
|  | ||||
| @ -2,8 +2,20 @@ | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| 
 | ||||
| 
 | ||||
| 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 = gpio_event; | ||||
|   gpio_event = EVENT_NONE; | ||||
| @ -12,5 +24,4 @@ int event_get() { | ||||
| 
 | ||||
| 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(GPIO_EXTI_REG, CHARGING_PIN); }
 | ||||
| bool charging_batt() { return HAL_GPIO_ReadPin(CHARGING_PORT, CHARGING_PIN); } | ||||
|  | ||||
| @ -125,9 +125,11 @@ int main(void) | ||||
| 
 | ||||
|   /* Infinite loop */ | ||||
|   /* USER CODE BEGIN WHILE */ | ||||
| //  benchmark();
 | ||||
|   while (1) | ||||
|   { | ||||
|     draw_mandelbrot(); | ||||
|     render_loop(); | ||||
| //    benchmark();
 | ||||
|     /* USER CODE END WHILE */ | ||||
| 
 | ||||
|     /* USER CODE BEGIN 3 */ | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "main.h" | ||||
| #include "gpio.h" | ||||
| #include "idle.h" | ||||
| #include "stm32f1xx_hal_spi.h" | ||||
| 
 | ||||
| #define RES_X             160 | ||||
| #define RES_Y             80 | ||||
| @ -24,12 +25,6 @@ | ||||
| #define ITERS     255 | ||||
| #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 | ||||
| 
 | ||||
| //imaginary axis set automatically
 | ||||
| @ -59,24 +54,24 @@ typedef struct { | ||||
|   int32_t r; int32_t i; | ||||
| } 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.
 | ||||
| //TODO optimize for mod 8. Benchmark
 | ||||
| inline int mod(int n, int d) { | ||||
|   int r = n % d; | ||||
|   return (r < 0) ? r + d : r; | ||||
| int mod8(int n) { | ||||
|   //I don't understand how, but somehow just anding the result is slower...?
 | ||||
|   //I've got too many things on my plate to disassemble this, but feel free to look into it yourself
 | ||||
|   int r = n % 8; | ||||
|   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 > N) && (direction < S)) from_coord.r += step.r;    //right
 | ||||
|   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) { | ||||
|   //TODO gross since window is no longer constant
 | ||||
|   int neighbor_index_accl[8] =  | ||||
|     {-win.w, -win.w + 1, 1, win.w + 1, win.w, win.w - 1, -1, -win.w - 1}; | ||||
|   from_pixel += neighbor_index_accl[direction]; | ||||
|   return from_pixel; | ||||
|   switch(direction) { | ||||
|     case N:   return from_pixel - win.w; | ||||
|     case NE:  return from_pixel - win.w + 1; | ||||
|     case E:   return from_pixel + 1; | ||||
|     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) { | ||||
| @ -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) { | ||||
|   uint16_t *tc = scheme; | ||||
|   for(unsigned int i = 0; i <= ITERS; i++) { | ||||
| @ -132,15 +131,6 @@ void init_colorscheme(uint16_t *scheme) { | ||||
|   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) { | ||||
|   double i_offset = (cam->max_i - cam->min_i) * step_i; | ||||
|   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; | ||||
| } | ||||
| 
 | ||||
| inline int  __attribute__((always_inline)) iterate(FixedCord c) { | ||||
| 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; | ||||
| @ -182,7 +172,12 @@ inline int  __attribute__((always_inline)) 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; | ||||
|   size_t on_pixel = 0; | ||||
|   bool border_scanning = false; | ||||
| @ -214,7 +209,8 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme | ||||
|           int i = iterate(c); | ||||
|           total_iters += i; | ||||
|           framebuffer[on_pixel] = colorscheme[i]; | ||||
|           if(i == ITERS) { | ||||
|           if(i != ITERS) { framebuffer[on_pixel] |= GCHAN_EXTERNAL; } | ||||
|           else { | ||||
|             FixedCord this_coord = c; | ||||
|             size_t this_index = on_pixel; | ||||
|             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) { | ||||
|                 bzero(nei_presort, sizeof(nei_presort)); | ||||
|                 bzero(nei_canidate, sizeof(nei_canidate)); | ||||
|                 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.
 | ||||
| 
 | ||||
| @ -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++) { | ||||
|                     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; | ||||
|                   } | ||||
| 
 | ||||
| @ -296,7 +297,7 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme | ||||
|                   if(nei_edge_i > 2) continue; | ||||
| 
 | ||||
|                   //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; | ||||
| 
 | ||||
|                   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++; | ||||
|       c.r += scale.r; | ||||
| @ -334,20 +333,19 @@ unsigned int mandelbrot_bordertrace(uint16_t *framebuffer, uint16_t *colorscheme | ||||
|   return total_iters; | ||||
| } | ||||
| 
 | ||||
| //TODO rename
 | ||||
| unsigned int render_mandelbrot(uint16_t *framebuffer, uint16_t *colorscheme, struct camera cam, int x0, int y0, int w, int h) { | ||||
| unsigned int mandelbrot_unoptimized(uint16_t *framebuffer, const uint16_t *colorscheme, const struct camera cam, const struct window win) { | ||||
|   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 - cam.min_i) * (RES_Y - 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_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) * win.x0) / RES_X) + cam.min_r); | ||||
|   int32_t c_r, z_i, z_r, zn_r, z_r_2, z_i_2; | ||||
|   size_t fb_index = 0; | ||||
|   int i;  | ||||
|   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; | ||||
|     for(int x = x0; x < x0 + w; x++) { | ||||
|     for(int x = win.x0; x < win.x0 + win.w; x++) { | ||||
|       z_i = 0; | ||||
|       z_r = 0; | ||||
|       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_Y RES_Y | ||||
| 
 | ||||
| //TODO rename
 | ||||
| void draw_mandelbrot() { | ||||
| 
 | ||||
| void render_loop() { | ||||
|   uint16_t framebuffer[FB_SIZE_X * FB_SIZE_Y]; | ||||
|   uint16_t columnbuffer[(size_t)(STEP_SIZE * RES_X * RES_Y)]; | ||||
|   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 = { | ||||
|     .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]; | ||||
| 
 | ||||
| 
 | ||||
|    | ||||
|   /** 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); | ||||
|   bzero(framebuffer, sizeof(framebuffer)); | ||||
|   bzero(columnbuffer, sizeof(columnbuffer)); | ||||
| 
 | ||||
|   //ggyaaaagh!!!
 | ||||
|   //I will clean this up later.
 | ||||
|   while(true) { | ||||
|     const int y_offset = STEP_SIZE * FB_SIZE_Y; | ||||
|     const int x_offset = STEP_SIZE * RES_X; | ||||
| @ -446,14 +447,27 @@ void draw_mandelbrot() { | ||||
|         cam_zoom(&cam, -ZOOM_SIZE); | ||||
|         mandelbrot_bordertrace(framebuffer, colorscheme, cam, (struct window){left_line, 0, FB_SIZE_X, FB_SIZE_Y}); | ||||
|         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: | ||||
|         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;  | ||||
|     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(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
| ifeq ($(DEBUG), 1) | ||||
| CFLAGS += -ggdb -g3 | ||||
| CFLAGS += -ggdb -g3 -DNAME=DEBUG_BUILD | ||||
| endif | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| # delete file | ||||
| file build/stm32f1_buisnesscard_v1.elf | ||||
| target extended localhost:3333  | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
| @ -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 *** | ||||
							
								
								
									
										7
									
								
								program/stm32f1_buisnesscard_v1/optimization_results
									
									
									
									
									
										Normal 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} | ||||
| 
 | ||||
| 
 | ||||
| @ -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 | ||||
							
								
								
									
										6
									
								
								program/stm32f1_buisnesscard_v1/todo
									
									
									
									
									
										Normal 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 | ||||
| 
 | ||||
| @ -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; | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
| @ -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(¤t_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; | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
| @ -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) { | ||||
| //  return;
 | ||||
| //        SetTargetFPS(0);
 | ||||
|   static bool fuckin_manual_pause_iguess = false; | ||||
|   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_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: | ||||
|         BeginDrawing(); | ||||
|         pix[index] =  | ||||
|           (Color) {0, pix[index].g, 255, 255}; | ||||
|           (Color) {255, pix[index].g, 255, 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; | ||||
|         return; | ||||
|  //       if(!pause && !fuckin_manual_pause_iguess) return;
 | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @ -316,7 +318,7 @@ unsigned int mandelbrot_bordertrace(struct camera *cam, Color *pixels) { | ||||
|           if(border_scanning) { | ||||
|             //pixels[on_pixel] = get_color(ITERS);
 | ||||
|             //printf("interior\n");
 | ||||
|             pixels[on_pixel] = (Color){0xfe,0,0xfe,0xff}; | ||||
|             pixels[on_pixel] = (Color){0x00,0,0x0,0xff}; | ||||
|             break; | ||||
|           } | ||||
|           //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; | ||||
|           break; | ||||
|           /**
 | ||||
|         case GCHAN_INNER_CLOSED: | ||||
|           if(((x + 2) < RES_X) && (pixels[on_pixel + 1].g == GCHAN_UNRENDERED)) border_scanning = SCAN_MODE_NONE; | ||||
|           break; | ||||
|           **/ | ||||
|         default:  | ||||
|           border_scanning = SCAN_MODE_NONE; | ||||
|       } | ||||
| @ -525,9 +522,7 @@ int main() { | ||||
| 
 | ||||
| 
 | ||||
|    | ||||
|   struct camera cam = { | ||||
|     .min_r = -0.640818352996663453958, .min_i = 0.410802460984564632440, .max_r = -0.637784130994323406050, .max_i = 0.412319571985918953416 | ||||
|   }; | ||||
|   struct camera cam = (struct camera) {-0.641121775196897503157, 0.410802460984564632440, -0.638087553194557455249, 0.412319571985918953416}; | ||||
| 
 | ||||
| //
 | ||||
|   InitWindow(WINDOW_SIZE_X, WINDOW_SIZE_Y, "mandelbrot fixed point test"); | ||||
| @ -537,7 +532,7 @@ int main() { | ||||
|   Texture tex = LoadTextureFromImage(img); | ||||
|   UnloadImage(img); | ||||
| 
 | ||||
|   SetTargetFPS(60); | ||||
|   SetTargetFPS(0); | ||||
| 
 | ||||
|   while(!WindowShouldClose()) { | ||||
|     switch(GetKeyPressed()) { | ||||
| @ -568,7 +563,8 @@ int main() { | ||||
|         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); | ||||
|     //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; | ||||
| @ -586,7 +582,7 @@ int main() { | ||||
|     printf("Unoptimized: %u iterations, %f seconds\n", unoptimized_iters, time_unoptimized); | ||||
| 
 | ||||
|     begin = clock(); | ||||
|     unsigned int optimized_iters = mandelbrot_bordertrace(&cam, pixels_optimized); | ||||
|     unsigned int optimized_iters = mandelbrot_bordertrace(&cam, pixels_unoptimized); | ||||
|     end = clock(); | ||||
| 
 | ||||
|     time_optimized = (double)(end - begin) / CLOCKS_PER_SEC; | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| .default: 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: | ||||
| 	rm -f mandelbrot | ||||
|  | ||||
| Before Width: | Height: | Size: 4.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								writeup/bad_curcuit.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 14 KiB | 
							
								
								
									
										
											BIN
										
									
								
								writeup/bordertracing.mkv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								writeup/closed_border.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 23 KiB | 
							
								
								
									
										
											BIN
										
									
								
								writeup/pcb_pads.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 141 KiB |