Created
September 10, 2025 15:17
-
-
Save kirkegaard/335fcd19fea3a6e06fd6cdcce81c49e4 to your computer and use it in GitHub Desktop.
Hexagons
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <math.h> | |
| #include <proto/dos.h> | |
| #include <proto/exec.h> | |
| #include <proto/graphics.h> | |
| #include <proto/intuition.h> | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| #define SCREEN_WIDTH 320 | |
| #define SCREEN_HEIGHT 256 | |
| #define DEPTH 2 | |
| #define HEX_BASE 12 // base hex radius in pixels | |
| #define SINLEN 1024 // sine table length (power of two) | |
| #define FP_SCALE 1024 // fixed-point scale for sin/cos table | |
| #define MAX_HEXAGONS 200 // max number of hexagons in grid | |
| #define NOISE_SOURCES 12 // number of rotating noise activation points | |
| struct Screen *screen = NULL; | |
| struct Window *window = NULL; | |
| struct RastPort *frontBuffer = NULL; | |
| struct RastPort backBuffer; | |
| struct BitMap *backBitMap = NULL; | |
| static int16_t sin_table[SINLEN]; | |
| typedef struct { | |
| int x, y; | |
| int radius; | |
| } HexCell; | |
| static HexCell hex_grid[MAX_HEXAGONS]; | |
| static int hex_count = 0; | |
| static int framecount = 0; | |
| static int simple_noise(int x, int y, int z) { | |
| int hash = ((x * 73) + (y * 137) + (z * 241)) & (SINLEN - 1); | |
| return sin_table[hash]; | |
| } | |
| static void init_sin_table(void) { | |
| const double two_pi = 2.0 * M_PI; | |
| for (int i = 0; i < SINLEN; ++i) { | |
| double rad = (i * two_pi) / SINLEN; | |
| sin_table[i] = (int16_t)round(sin(rad) * FP_SCALE); | |
| } | |
| } | |
| static void init_hex_grid(void) { | |
| const int r = HEX_BASE; | |
| const int x_span = (r * 173) / 100; | |
| const int margin = r * 2; | |
| hex_count = 0; | |
| BOOL row_offset = FALSE; | |
| for (int y = margin; y <= SCREEN_HEIGHT - margin && hex_count < MAX_HEXAGONS; | |
| y += (r * 3) / 2) { | |
| int x_start = margin + (row_offset ? x_span / 2 : 0); | |
| for (int x = x_start; | |
| x <= SCREEN_WIDTH - margin && hex_count < MAX_HEXAGONS; x += x_span) { | |
| // Center coordinates relative to screen center | |
| hex_grid[hex_count].x = x - SCREEN_WIDTH / 2; | |
| hex_grid[hex_count].y = y - SCREEN_HEIGHT / 2; | |
| hex_grid[hex_count].radius = 0.0; | |
| hex_count++; | |
| } | |
| row_offset = !row_offset; | |
| } | |
| } | |
| static void clearBuffer(struct RastPort *rport) { | |
| BltBitMap(rport->BitMap, 0, 0, rport->BitMap, 0, 0, SCREEN_WIDTH, | |
| SCREEN_HEIGHT, 0x00, 0xFF, NULL); | |
| } | |
| static void drawHexagon(struct RastPort *rport, int cx, int cy, int r, | |
| UBYTE color) { | |
| int vx[6], vy[6]; | |
| SetAPen(rport, color); | |
| for (int i = 0; i < 6; ++i) { | |
| int angle_idx = ((i * SINLEN) / 6 + (SINLEN / 12)) & (SINLEN - 1); | |
| int s = sin_table[angle_idx]; | |
| int c = sin_table[(angle_idx + (SINLEN / 4)) & (SINLEN - 1)]; | |
| vx[i] = cx + (r * c) / FP_SCALE; | |
| vy[i] = cy + (r * s) / FP_SCALE; | |
| } | |
| Move(rport, vx[0], vy[0]); | |
| for (int i = 1; i < 6; ++i) { | |
| Draw(rport, vx[i], vy[i]); | |
| } | |
| Draw(rport, vx[0], vy[0]); | |
| } | |
| static void updateHexGrid(void) { | |
| for (int i = 0; i < hex_count; i++) { | |
| if (hex_grid[i].radius > 0) { | |
| hex_grid[i].radius--; | |
| } | |
| } | |
| int f = framecount / 2; | |
| int noise_base_x = (simple_noise(f / 32, f, 0) * 100) / FP_SCALE; | |
| int noise_base_y = (simple_noise(0, f, f / 16) * 100) / FP_SCALE; | |
| for (int source = 0; source < NOISE_SOURCES; source++) { | |
| int angle_deg = source * 30; | |
| int angle_idx = (angle_deg * SINLEN) / 360; | |
| int cos_val = sin_table[(angle_idx + (SINLEN / 4)) & (SINLEN - 1)]; | |
| int sin_val = sin_table[angle_idx]; | |
| // Position noise source in circle around base position | |
| int source_x = noise_base_x + (cos_val * 20) / FP_SCALE; | |
| int source_y = noise_base_y + (sin_val * 20) / FP_SCALE; | |
| // Check which hexagons are within distance | |
| for (int i = 0; i < hex_count; i++) { | |
| int dx = hex_grid[i].x - source_x; | |
| int dy = hex_grid[i].y - source_y; | |
| int dist_sq = dx * dx + dy * dy; | |
| // If within radius, increase radius | |
| if (dist_sq < 30 * 30) { | |
| hex_grid[i].radius += 1; | |
| if (hex_grid[i].radius > HEX_BASE) { | |
| hex_grid[i].radius = HEX_BASE; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| static void drawHexGrid(struct RastPort *rport) { | |
| for (int i = 0; i < hex_count; i++) { | |
| int screen_x = hex_grid[i].x + SCREEN_WIDTH / 2; | |
| int screen_y = hex_grid[i].y + SCREEN_HEIGHT / 2; | |
| int radius = hex_grid[i].radius; | |
| UBYTE color = (radius > 4) ? 1 : 2; | |
| drawHexagon(rport, screen_x, screen_y, radius, color); | |
| } | |
| } | |
| int main(void) { | |
| // Open a screen | |
| screen = OpenScreenTags(NULL, SA_Width, SCREEN_WIDTH, SA_Height, | |
| SCREEN_HEIGHT, SA_Depth, DEPTH, SA_ShowTitle, FALSE, | |
| SA_Quiet, TRUE, TAG_DONE); | |
| if (!screen) { | |
| return 1; | |
| } | |
| // Open a window on that screen; listen for RAWKEY and CLOSEWINDOW | |
| window = | |
| OpenWindowTags(NULL, WA_CustomScreen, (ULONG)screen, WA_Left, 0, WA_Top, | |
| 0, WA_Width, SCREEN_WIDTH, WA_Height, SCREEN_HEIGHT, | |
| WA_Borderless, TRUE, WA_Backdrop, TRUE, WA_Activate, TRUE, | |
| WA_IDCMP, IDCMP_RAWKEY | IDCMP_CLOSEWINDOW, TAG_DONE); | |
| if (!window) { | |
| CloseScreen(screen); | |
| return 1; | |
| } | |
| // Initialize front and back buffers | |
| frontBuffer = window->RPort; | |
| backBitMap = AllocBitMap(SCREEN_WIDTH, SCREEN_HEIGHT, DEPTH, BMF_CLEAR, | |
| screen->RastPort.BitMap); | |
| if (!backBitMap) { | |
| CloseWindow(window); | |
| CloseScreen(screen); | |
| return 1; | |
| } | |
| InitRastPort(&backBuffer); | |
| backBuffer.BitMap = backBitMap; | |
| // Set up color palette | |
| SetRGB4(&screen->ViewPort, 0, 0, 0, 0); | |
| SetRGB4(&screen->ViewPort, 1, 15, 8, 0); | |
| SetRGB4(&screen->ViewPort, 2, 0, 15, 15); | |
| // SetRGB4(&screen->ViewPort, 3, 15, 8, 0); | |
| // Precompute sin table and initialize hex grid | |
| init_sin_table(); | |
| init_hex_grid(); | |
| BOOL running = TRUE; | |
| int frame = 0; | |
| while (running) { | |
| struct IntuiMessage *msg; | |
| while ((msg = (struct IntuiMessage *)GetMsg(window->UserPort))) { | |
| if (msg->Class == IDCMP_RAWKEY && msg->Code == 0x45) { | |
| running = FALSE; | |
| } | |
| ReplyMsg((struct Message *)msg); | |
| } | |
| clearBuffer(&backBuffer); | |
| updateHexGrid(); | |
| drawHexGrid(&backBuffer); | |
| // Copy back buffer to front buffer | |
| BltBitMap(backBitMap, 0, 0, frontBuffer->BitMap, 0, 0, SCREEN_WIDTH, | |
| SCREEN_HEIGHT, 0xC0, 0xFF, NULL); | |
| WaitBlit(); | |
| WaitTOF(); | |
| framecount++; | |
| } | |
| if (backBitMap) { | |
| FreeBitMap(backBitMap); | |
| } | |
| CloseWindow(window); | |
| CloseScreen(screen); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment