From a542cc0d6c8f40917f872e0f99d633efeb56155d Mon Sep 17 00:00:00 2001 From: Pavel V Date: Sat, 20 May 2023 19:14:17 +0300 Subject: [PATCH] vermiculate --- CMakeLists.txt | 3 +- art.hpp | 19 +- main.cpp | 4 +- settings.cpp | 13 + settings.hpp | 7 +- vermiculate.cpp | 1720 ++++++++++++++++++++++------------------------- vermiculate.h | 90 +++ 7 files changed, 926 insertions(+), 930 deletions(-) create mode 100644 vermiculate.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bd1f38..4a75aa5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ target_sources(cloudlife PUBLIC cloudlife.cpp mtron.cpp timer.cpp - ifs.cpp) + ifs.cpp + vermiculate.cpp) target_link_libraries(cloudlife IMGUI glfw GL colormap) set_target_properties(cloudlife PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/art.hpp b/art.hpp index c8a1e8f..23f4cfb 100644 --- a/art.hpp +++ b/art.hpp @@ -4,6 +4,13 @@ #include #include + +template +static inline void +fill0(T &container) { + std::fill(container.begin(), container.end(), 0); +} + class Art { public: Art(std::string _name) @@ -31,6 +38,8 @@ class Art { virtual void reinit() { resize(w, h); } + virtual ~Art() = default; + protected: void default_resize(int _w, int _h) { w = _w; @@ -38,9 +47,16 @@ class Art { //data = (uint8_t *)xrealloc(data, w*h*sizeof(uint32_t)); pixels.resize(w*h); clear(); + /* TODO: fill square in drawdot() if pscale > 1 + pscale = 1; + if (xgwa.width > 2560 || xgwa.height > 2560) + pscale = 3; // Retina displays + */ + } void clear() { - std::fill(pixels.begin(), pixels.end(), 0); + fill0(pixels); + //std::fill(pixels.begin(), pixels.end(), 0); } int w, h; //uint8_t *data() { return reinterpret_cast(pixels.data()); } @@ -48,3 +64,4 @@ class Art { std::vector pixels; std::string m_name; }; + diff --git a/main.cpp b/main.cpp index c6a3a45..4cca237 100644 --- a/main.cpp +++ b/main.cpp @@ -23,6 +23,7 @@ #include "cloudlife.hpp" #include "mtron.hpp" #include "ifs.h" +#include "vermiculate.h" std::unique_ptr art; @@ -162,7 +163,8 @@ int main(int argc, char *argv[]) //art.reset(new Cloudlife); //art.reset(new Minskytron); - art.reset(new IFS); + //art.reset(new IFS); + art.reset(new Vermiculate); IMGUI_CHECKVERSION(); diff --git a/settings.cpp b/settings.cpp index a36f8d3..3f34d0f 100644 --- a/settings.cpp +++ b/settings.cpp @@ -36,3 +36,16 @@ bool PaletteSetting::RenderGui() { } return ret; } + +void PaletteSetting::rescale(uint32_t ncolours) { + value = value.rescale(0., ncolours); +} + +uint32_t PaletteSetting::get_color(uint32_t color_n) { + auto c = value(color_n); + return 0xff000000 | + c.getRed().getValue() << 0 | + c.getGreen().getValue() << 8 | + c.getBlue().getValue() << 16; + +} diff --git a/settings.hpp b/settings.hpp index 22e5ca2..d12bf9a 100644 --- a/settings.hpp +++ b/settings.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include + class Setting { public: virtual bool RenderGui() = 0; @@ -26,8 +28,11 @@ class PaletteSetting : public Setting { pal_t & operator*() {return value;} pal_t value = colormap::palettes.at("inferno"); + + void rescale(uint32_t ncolours); + uint32_t get_color(uint32_t color_n); + private: int item_current_idx = 0; - }; diff --git a/vermiculate.cpp b/vermiculate.cpp index 7debe04..a0d7dd0 100644 --- a/vermiculate.cpp +++ b/vermiculate.cpp @@ -11,55 +11,37 @@ * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. + * + * Dear ImGui port by Pavel Vasilyev , May 2023 */ -#include "screenhack.h" #include #include -#define degs 360 +#include "imgui_elements.h" +#include "random.h" +#include "vermiculate.h" + #define degs2 (degs/2) #define degs4 (degs/4) #define degs8 (degs/8) -#define dtor 0.0174532925 /* pi / degs2; */ -#define thrmax 120 +#define dtor 0.0174532925 /* pi / degs2; */ #define tailmax (thrmax * 2 + 1) #define tmodes '7' -#define ymax (st->hei - 1) +#define ymax (h - 1) #define ymin 0 -#define xmax (st->wid - 1) +#define xmax (w - 1) #define xmin 0 -#define rlmax 200 #define SPEEDINC 10 #define SPEEDMAX 1000 -#define wraparound(VAL,LOWER,UPPER) { \ - if (VAL >= UPPER) \ - VAL -= UPPER - LOWER; \ - else if (VAL < LOWER) \ - VAL += UPPER - LOWER; } +#define wraparound(VAL,LOWER,UPPER) { \ + if (VAL >= UPPER) \ + VAL -= UPPER - LOWER; \ + else if (VAL < LOWER) \ + VAL += UPPER - LOWER; } #define arrcpy(DEST,SRC) memcpy (DEST, SRC, sizeof(DEST)) -typedef double real; -typedef unsigned char banktype[thrmax]; - -typedef struct linedata -{ - int deg, spiturn, turnco, turnsize; - unsigned char col; - Bool dead; - - char orichar; - real x, y; - int tmode, tsc, tslen, tclim, otslen, ctinc, reclen, recpos, circturn, prey, - slice; - int xrec[rlmax + 1], yrec[rlmax + 1]; - int turnseq[50]; - Bool filled, killwalls, vhfollow, - selfbounce, tailfollow, realbounce, little; -} -linedata; - static const struct stringAndSpeed { const char * const str; @@ -67,13 +49,13 @@ static const struct stringAndSpeed } sampleStrings[] = { -/* { "]]]]]]]]7ces123400-9-8#c123456#s9998880004#ma3#car9ma6#c-#r1", 600} , - { "bmarrrr#c1234#lc5678#lyet]", 600} , */ +/* { "]]]]]]]]7ces123400-9-8#c123456#s9998880004#ma3#car9ma6#c-#r1", 600} , + { "bmarrrr#c1234#lc5678#lyet]", 600} , */ { "AEBMN222222223#CAR9CAD4CAOV", 150} , { "mn333#c23#f1#]]]]]]]]]]]3bc9#r9#c78#f9#ma4#", 600} , - { "AEBMN22222#CAD4CAORc1#f2#c1#r6", 100} , + { "AEBMN22222#CAD4CAORc1#f2#c1#r6", 100} , /* { "mn6666666#c1i#f1#y2#sy2#vyety1#ry13i#l", 40} , */ - { "aebmnrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr#", 500} , + { "aebmnrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr#", 500} , /* { "bg+++++++++++++++++++++++#mnrrrrrrrrrrrrrrrrrrrrrrr#y1#k", 500}, */ /* { "BMN22222223#CAD4CAOVYAS", 150}, */ /* { "aebmnrrrrrrrrrrrrrrrr#yaryakg--#", 100} , */ @@ -85,289 +67,249 @@ sampleStrings[] = { "baMn111111222222333333444444555555#Ct1#lCt2#lCt3#lCt4#lCt5#lCerrYerYetYt1i#lYt1i#sYt1#v", 1400 } }; -struct state { - Display *dpy; - Window window; - - GC mygc; - Colormap mycmap; - XWindowAttributes xgwa; - XColor mycolors[tailmax]; - - int hei, wid, speed; - Bool erasing, cleared, autopal; - char *oinstring; /* allocated */ - const char *instring; /* consumed */ - int max_ticks; - real sinof[degs], cosof[degs], tanof[degs]; - unsigned char *point; - - linedata thread[thrmax]; - banktype bank; - int bnkt; - int boxw, boxh, curviness, gridden, ogd, bordcorn; - unsigned char bordcol, threads; - char ch, boolop; - - int reset_p; - int cyc; - int pscale; -}; - -static void -consume_instring(struct state *st); - -static Bool -wasakeypressed (struct state *st) +bool Vermiculate::wasakeypressed () { - if (*st->instring != 0) - return True; + if (*instring != 0) + return true; else - return False; + return false; } -static char -readkey (struct state *st) +char Vermiculate::readkey () { char readkey_result; - if (*st->instring == 0) + if (*instring == 0) { readkey_result = '#'; } else { - readkey_result = *st->instring; - st->instring++; + readkey_result = *instring; + instring++; }; return toupper (readkey_result); } -static unsigned int -random1 (unsigned int i) +unsigned int Vermiculate::random1 (unsigned int i) { - return (ya_random () % i); + return (xoshiro256plus () % i); } -static unsigned long -waitabit (struct state *st) +unsigned long Vermiculate::waitabit () { int result = 0; - st->cyc += st->threads; - while (st->cyc > st->speed) + cyc += threads; + while (cyc > speed) { result += 10000; - st->cyc -= st->speed; + cyc -= speed; } return result; } -static void -clearscreen (struct state *st) +void Vermiculate::clearscreen () { - XClearWindow (st->dpy, st->window); - memset (st->point, 0, st->wid * st->hei); + clear(); + + fill0(point); } -static void -sp (struct state *st, int x, int y, int c) +void +Vermiculate::sp (int x, int y, uint32_t c) { - XSetForeground (st->dpy, st->mygc, st->mycolors[c].pixel); - XFillRectangle (st->dpy, st->window, st->mygc, x, y, st->pscale, st->pscale); - st->point[(st->wid * y) + x] = c; + uint32_t color = pal.get_color(c); + if (c == 0) + color = 0; + drawdot(x, y, color); + + point[(w * y) + x] = c; } -static int -gp (struct state *st, int x, int y) +int +Vermiculate::gp (int x, int y) { - return st->point[(st->wid * y) + x]; + return point[(w * y) + x]; } -static void -redraw (struct state *st, int x, int y, int width, int height) +void +Vermiculate::redraw (int x, int y, int width, int height) { int xc, yc; for (xc = x; xc <= x + width - 1; xc++) for (yc = y; yc <= y + height - 1; yc++) - if (st->point[st->wid * yc + xc] != 0) - sp (st, xc, yc, st->point[st->wid * yc + xc]); + if (point[w * yc + xc] != 0) + sp (xc, yc, point[w * yc + xc]); } -static void -palupdate (struct state *st, Bool forceUpdate) +void +Vermiculate::palupdate (bool forceUpdate) { - if (forceUpdate || *st->instring == 0) + if (forceUpdate || *instring == 0) { - redraw (st, xmin, ymin, st->wid, st->hei); + redraw (xmin, ymin, w, h); } } -static void -randpal (struct state *st) +void +Vermiculate::randpal () { int ncolors = tailmax - 1; - make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->mycmap, - &st->mycolors[1], &ncolors, True, True, 0, True); - if (ncolors < tailmax - 1) - { - int c; - for (c = 1; c < tailmax; c++) - st->mycolors[c].pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); - } + pal.rescale(ncolors); } -static void -gridupdate (struct state *st, Bool interruptible) +void +Vermiculate::gridupdate (bool interruptible) { int x, y; - if (st->gridden > 0) - for (x = 0; x <= xmax && !(wasakeypressed (st) && interruptible); x += st->boxw) - for (y = 0; y <= ymax; y += st->boxh) - { - if (random1 (15) < st->gridden) - { + if (gridden > 0) + for (x = 0; x <= xmax && !(wasakeypressed () && interruptible); x += boxw) + for (y = 0; y <= ymax; y += boxh) + { + if (random1 (15) < gridden) + { #define lesser(A,B) ( ((A)<(B)) ? (A) : (B) ) - int max = lesser (x + st->boxw, xmax); - int xc; - for (xc = x; xc <= max; xc++) - sp (st, xc, y, 1); - } - if (random1 (15) < st->gridden) - { - int max = lesser (y + st->boxh, ymax); - int yc; - for (yc = y; yc <= max; yc++) - sp (st, x, yc, 1); - } - } + int max = lesser (x + boxw, xmax); + int xc; + for (xc = x; xc <= max; xc++) + sp (xc, y, 1); + } + if (random1 (15) < gridden) + { + int max = lesser (y + boxh, ymax); + int yc; + for (yc = y; yc <= max; yc++) + sp (x, yc, 1); + } + } } -static void -bordupdate (struct state *st) +void +Vermiculate::bordupdate () { int xbord, ybord; - if (st->bordcorn == 0 || st->bordcorn == 1) + if (bordcorn == 0 || bordcorn == 1) ybord = ymin; else ybord = ymax; - if (st->bordcorn == 0 || st->bordcorn == 3) + if (bordcorn == 0 || bordcorn == 3) xbord = xmin; else xbord = xmax; { int x, y; for (x = xmin; x <= xmax; x++) - sp (st, x, ybord, st->bordcol); + sp (x, ybord, bordcol); for (y = ymin; y <= ymax; y++) - sp (st, xbord, y, st->bordcol); + sp (xbord, y, bordcol); } } -static Bool -inbank (struct state *st, unsigned char thr) +bool +Vermiculate::inbank (unsigned char thr) { int c; - if (st->bnkt > 0) - for (c = 1; c <= st->bnkt; c++) - if (st->bank[c - 1] == thr) - return True; - return False; + if (bnkt > 0) + for (c = 1; c <= bnkt; c++) + if (bank[c - 1] == thr) + return true; + return false; } -static void -pickbank (struct state *st) +void +Vermiculate::pickbank () { unsigned char thr = 1; - st->bnkt = 0; - st->ch = '\0'; + bnkt = 0; + ch = '\0'; do { - while (inbank (st, thr)) - thr = thr % st->threads + 1; - - palupdate (st, False); - st->ch = readkey (st); - palupdate (st, False); - switch (st->ch) - { - case '+': - case '-': - do - { - if (st->ch == '+') - thr++; - else - thr--; - wraparound (thr, 1, st->threads + 1); - } - while (inbank (st, thr)); - break; - case ' ': - st->bank[++st->bnkt - 1] = thr; - break; - case '1': case '2': case '3': + while (inbank (thr)) + thr = thr % threads + 1; + + palupdate (false); + ch = readkey (); + palupdate (false); + switch (ch) + { + case '+': + case '-': + do + { + if (ch == '+') + thr++; + else + thr--; + wraparound (thr, 1, threads + 1); + } + while (inbank (thr)); + break; + case ' ': + bank[++bnkt - 1] = thr; + break; + case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - st->bank[++st->bnkt - 1] = st->ch - '0'; - if (st->bank[st->bnkt - 1] > st->threads) - st->bnkt--; - break; - case 'I': - { - banktype tbank; - int tbankt = 0; - int c; - for (c = 1; c <= st->threads; c++) - if (!inbank (st, c)) - tbank[++tbankt - 1] = c; - st->bnkt = tbankt; - arrcpy (st->bank, tbank); - } - break; - case 'T': - st->ch = readkey (st); - switch (st->ch) - { - case '1': case '2': case '3': + bank[++bnkt - 1] = ch - '0'; + if (bank[bnkt - 1] > threads) + bnkt--; + break; + case 'I': + { + banktype tbank; + int tbankt = 0; + int c; + for (c = 1; c <= threads; c++) + if (!inbank (c)) + tbank[++tbankt - 1] = c; + bnkt = tbankt; + arrcpy (bank, tbank); + } + break; + case 'T': + ch = readkey (); + switch (ch) + { + case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - { - int c; - for (c = 1; c <= st->threads; c++) - if (st->thread[c - 1].tmode == st->ch - '0') - st->bank[++st->bnkt - 1] = c; - } - break; - } - break; - case 'A': - for (st->bnkt = 1; st->bnkt <= st->threads; st->bnkt++) - st->bank[st->bnkt - 1] = st->bnkt; - st->bnkt = st->threads; - break; - case 'E': - for (st->bnkt = 1; st->bnkt <= thrmax; st->bnkt++) - st->bank[st->bnkt - 1] = st->bnkt; - st->bnkt = thrmax; - break; - } + { + int c; + for (c = 1; c <= threads; c++) + if (thread[c - 1].tmode == ch - '0') + bank[++bnkt - 1] = c; + } + break; + } + break; + case 'A': + for (bnkt = 1; bnkt <= threads; bnkt++) + bank[bnkt - 1] = bnkt; + bnkt = threads; + break; + case 'E': + for (bnkt = 1; bnkt <= thrmax; bnkt++) + bank[bnkt - 1] = bnkt; + bnkt = thrmax; + break; + } } - while (!(st->bnkt >= st->threads || st->ch == 'N' || st->ch == '\15' || st->ch == '#')); - if (st->bnkt == 0 && st->ch != 'N') + while (!(bnkt >= threads || ch == 'N' || ch == '\15' || ch == '#')); + if (bnkt == 0 && ch != 'N') { - st->bnkt = 1; - st->bank[0] = thr; + bnkt = 1; + bank[0] = thr; } - palupdate (st, False); + palupdate (false); } -static void -bankmod (char boolop, Bool * Bool_) +void +Vermiculate::bankmod (char boolop, bool * Bool_) { switch (boolop) { @@ -375,46 +317,46 @@ bankmod (char boolop, Bool * Bool_) *Bool_ = !*Bool_; break; case 'Y': - *Bool_ = True; + *Bool_ = true; break; case 'N': - *Bool_ = False; + *Bool_ = false; break; } } -static void -newonscreen (struct state *st, unsigned char thr) +void +Vermiculate::newonscreen (unsigned char thr) { - linedata *LP = &st->thread[thr - 1]; - LP->filled = False; - LP->dead = False; - LP->reclen = (LP->little) ? - random1 (10) + 5 : random1 (rlmax - 30) + 30; + linedata *LP = &thread[thr - 1]; + LP->filled = false; + LP->dead = false; + LP->reclen = (LP->little) ? + random1 (10) + 5 : random1 (rlmax - 30) + 30; LP->deg = random1 (degs); - LP->y = random1 (st->hei); - LP->x = random1 (st->wid); + LP->y = random1 (h); + LP->x = random1 (w); LP->recpos = 0; LP->turnco = 2; LP->turnsize = random1 (4) + 2; } -static void -firstinit (struct state *st, unsigned char thr) +void +Vermiculate::firstinit (unsigned char thr) { - linedata *LP = &st->thread[thr - 1]; + linedata *LP = &thread[thr - 1]; LP->col = thr + 1; LP->prey = 0; LP->tmode = 1; LP->slice = degs / 3; LP->orichar = 'R'; LP->spiturn = 5; - LP->selfbounce = False; - LP->realbounce = False; - LP->vhfollow = False; - LP->tailfollow = False; - LP->killwalls = False; - LP->little = False; + LP->selfbounce = false; + LP->realbounce = false; + LP->vhfollow = false; + LP->tailfollow = false; + LP->killwalls = false; + LP->little = false; LP->ctinc = random1 (2) * 2 - 1; LP->circturn = ((thr % 2) * 2 - 1) * ((thr - 1) % 7 + 1); LP->tsc = 1; @@ -428,271 +370,270 @@ firstinit (struct state *st, unsigned char thr) LP->tclim = (unsigned char) (((real) degs) / 2 / 12); } -static void -maininit (struct state *st) +void +Vermiculate::maininit () { - if (!st->instring) + if (!instring) { int n = random1 (sizeof (sampleStrings) / sizeof (sampleStrings[0])); - if (st->oinstring) free (st->oinstring); - st->instring = st->oinstring = strdup (sampleStrings[n].str); - st->speed = sampleStrings[n].speed; + if (oinstring) free (oinstring); + instring = oinstring = strdup (sampleStrings[n].str); + speed = sampleStrings[n].speed; } - st->boxh = 10; - st->boxw = 10; - st->gridden = 0; - st->bordcorn = 0; - st->threads = 4; - st->curviness = 30; - st->bordcol = 1; - st->ogd = 8; - st->ch = '\0'; - st->erasing = True; + boxh = 10; + boxw = 10; + gridden = 0; + bordcorn = 0; + threads = 4; + curviness = 30; + bordcol = 1; + ogd = 8; + ch = '\0'; + erasing = true; { unsigned char thr; for (thr = 1; thr <= thrmax; thr++) { - firstinit (st, thr); - newonscreen (st, thr); + firstinit (thr); + newonscreen (thr); } } { int d; for (d = degs - 1; d >= 0; d--) { - st->sinof[d] = sin (d * dtor); - st->cosof[d] = cos (d * dtor); - if (d % degs4 == 0) - st->tanof[d] = st->tanof[d + 1]; - else - st->tanof[d] = tan (d * dtor); + sinof[d] = sin (d * dtor); + cosof[d] = cos (d * dtor); + if (d % degs4 == 0) + tanof[d] = tanof[d + 1]; + else + tanof[d] = tan (d * dtor); } } - randpal (st); + randpal (); } -static Bool -move (struct state *st, unsigned char thr) +bool Vermiculate::move (unsigned char thr) { - linedata *LP = &st->thread[thr - 1]; + linedata *LP = &thread[thr - 1]; if (LP->dead) - return (False); + return (false); if (LP->prey == 0) switch (LP->tmode) { case 1: - LP->deg += random1 (2 * LP->turnsize + 1) - LP->turnsize; - break; + LP->deg += random1 (2 * LP->turnsize + 1) - LP->turnsize; + break; case 2: - if (LP->slice == degs || LP->slice == degs2 || LP->slice == degs4) - { - if (LP->orichar == 'D') - { - if (LP->deg % degs4 != degs8) - LP->deg = degs4 * random1 (4) + degs8; - } - else if (LP->orichar == 'V') - if (LP->deg % degs4 != 0) - LP->deg = degs4 * random1 (4); - } - if (random1 (100) == 0) - { - if (LP->slice == 0) - LP->deg = LP->deg - degs4 + random1 (degs2); - else - LP->deg += (random1 (2) * 2 - 1) * LP->slice; - } - break; + if (LP->slice == degs || LP->slice == degs2 || LP->slice == degs4) + { + if (LP->orichar == 'D') + { + if (LP->deg % degs4 != degs8) + LP->deg = degs4 * random1 (4) + degs8; + } + else if (LP->orichar == 'V') + if (LP->deg % degs4 != 0) + LP->deg = degs4 * random1 (4); + } + if (random1 (100) == 0) + { + if (LP->slice == 0) + LP->deg = LP->deg - degs4 + random1 (degs2); + else + LP->deg += (random1 (2) * 2 - 1) * LP->slice; + } + break; case 3: - LP->deg += LP->circturn; - break; + LP->deg += LP->circturn; + break; case 4: - if (abs (LP->spiturn) > 11) - LP->spiturn = 5; - else - LP->deg += LP->spiturn; - if (random1 (15 - abs (LP->spiturn)) == 0) - { - LP->spiturn += LP->ctinc; - if (abs (LP->spiturn) > 10) - LP->ctinc *= -1; - } - break; + if (abs (LP->spiturn) > 11) + LP->spiturn = 5; + else + LP->deg += LP->spiturn; + if (random1 (15 - abs (LP->spiturn)) == 0) + { + LP->spiturn += LP->ctinc; + if (abs (LP->spiturn) > 10) + LP->ctinc *= -1; + } + break; case 5: - LP->turnco = abs (LP->turnco) - 1; - if (LP->turnco == 0) - { - LP->turnco = st->curviness + random1 (10); - LP->circturn *= -1; - } - LP->deg += LP->circturn; - break; + LP->turnco = abs (LP->turnco) - 1; + if (LP->turnco == 0) + { + LP->turnco = curviness + random1 (10); + LP->circturn *= -1; + } + LP->deg += LP->circturn; + break; case 6: - if (abs (LP->turnco) == 1) - LP->turnco *= -1 * (random1 (degs2 / abs (LP->circturn)) + 5); - else if (LP->turnco == 0) - LP->turnco = 2; - else if (LP->turnco > 0) - { - LP->turnco--; - LP->deg += LP->circturn; - } - else - LP->turnco++; - break; + if (abs (LP->turnco) == 1) + LP->turnco *= -1 * (random1 (degs2 / abs (LP->circturn)) + 5); + else if (LP->turnco == 0) + LP->turnco = 2; + else if (LP->turnco > 0) + { + LP->turnco--; + LP->deg += LP->circturn; + } + else + LP->turnco++; + break; case 7: - LP->turnco++; - if (LP->turnco > LP->tclim) - { - LP->turnco = 1; - LP->tsc = (LP->tsc % LP->tslen) + 1; - } - LP->deg += LP->turnseq[LP->tsc - 1]; - break; + LP->turnco++; + if (LP->turnco > LP->tclim) + { + LP->turnco = 1; + LP->tsc = (LP->tsc % LP->tslen) + 1; + } + LP->deg += LP->turnseq[LP->tsc - 1]; + break; } else { int desdeg; real dy, dx; if (LP->tailfollow || LP->prey == thr) - { - dx = st->thread[LP->prey - 1].xrec[st->thread[LP->prey - 1].recpos] - LP->x; - dy = st->thread[LP->prey - 1].yrec[st->thread[LP->prey - 1].recpos] - LP->y; - } + { + dx = thread[LP->prey - 1].xrec[thread[LP->prey - 1].recpos] - LP->x; + dy = thread[LP->prey - 1].yrec[thread[LP->prey - 1].recpos] - LP->y; + } else - { - dx = st->thread[LP->prey - 1].x - LP->x; - dy = st->thread[LP->prey - 1].y - LP->y; - } + { + dx = thread[LP->prey - 1].x - LP->x; + dy = thread[LP->prey - 1].y - LP->y; + } desdeg = - (LP->vhfollow) ? - ((fabs (dx) > fabs (dy)) ? - ((dx > 0) ? - 0 * degs4 - : - 2 * degs4) - : - ((dy > 0) ? - 1 * degs4 - : - 3 * degs4)) - : - ((dx > 0) ? - ((dy > 0) ? - 1 * degs8 : 7 * degs8) : ((dy > 0) ? 3 * degs8 : 5 * degs8)); + (LP->vhfollow) ? + ((fabs (dx) > fabs (dy)) ? + ((dx > 0) ? + 0 * degs4 + : + 2 * degs4) + : + ((dy > 0) ? + 1 * degs4 + : + 3 * degs4)) + : + ((dx > 0) ? + ((dy > 0) ? + 1 * degs8 : 7 * degs8) : ((dy > 0) ? 3 * degs8 : 5 * degs8)); if (desdeg - desdeg % degs4 != LP->deg - LP->deg % degs4 - || LP->vhfollow) - { - if (!LP->vhfollow) - { + || LP->vhfollow) + { + if (!LP->vhfollow) + { /* Using atan2 here doesn't seem to slow things down: */ desdeg = atan2 (dy, dx) / dtor; wraparound (desdeg, 0, degs); - } - if (abs (desdeg - LP->deg) <= abs (LP->circturn)) - LP->deg = desdeg; - else - LP->deg += - (desdeg > LP->deg) ? - ((desdeg - LP->deg > degs2) ? - -abs (LP->circturn) : abs (LP->circturn)) - : ((LP->deg - desdeg > degs2) ? - abs (LP->circturn) : -abs (LP->circturn)); - } + } + if (abs (desdeg - LP->deg) <= abs (LP->circturn)) + LP->deg = desdeg; + else + LP->deg += + (desdeg > LP->deg) ? + ((desdeg - LP->deg > degs2) ? + -abs (LP->circturn) : abs (LP->circturn)) + : ((LP->deg - desdeg > degs2) ? + abs (LP->circturn) : -abs (LP->circturn)); + } else - LP->deg += - (st->tanof[LP->deg] > - dy / dx) ? -abs (LP->circturn) : abs (LP->circturn); + LP->deg += + (tanof[LP->deg] > + dy / dx) ? -abs (LP->circturn) : abs (LP->circturn); } wraparound (LP->deg, 0, degs); { unsigned char oldcol; real oldy = LP->y, oldx = LP->x; - LP->x += st->cosof[LP->deg]; + LP->x += cosof[LP->deg]; wraparound (LP->x, xmin, xmax + 1); - LP->y += st->sinof[LP->deg]; + LP->y += sinof[LP->deg]; wraparound (LP->y, ymin, ymax + 1); #define xi ((int) LP->x) #define yi ((int) LP->y) - oldcol = gp (st, xi, yi); + oldcol = gp (xi, yi); if (oldcol != 0) { - Bool vertwall = False, horiwall = False; - if (oldcol == 1 && ((LP->killwalls && st->gridden > 0) || LP->realbounce)) - { - vertwall = (gp (st, xi, (int) oldy) == 1); - horiwall = (gp (st, (int) oldx, yi) == 1); - } - if (oldcol == 1 && LP->realbounce && (vertwall || horiwall)) - { - if (vertwall) - LP->deg = -LP->deg + degs2; - else - LP->deg = -LP->deg; - } - else - { - if ((oldcol != LP->col && LP->realbounce) - || (oldcol == LP->col && LP->selfbounce)) - LP->deg += degs4 * (random1 (2) * 2 - 1); - else if (oldcol != LP->col) - LP->deg += degs2; - } - if (LP->killwalls && st->gridden > 0 && oldcol == 1) - { - if (vertwall && xi + 1 <= xmax) - { - int yy; - for (yy = yi - yi % st->boxh; - yy <= yi - yi % st->boxh + st->boxh && yy <= ymax; yy++) - if (gp (st, xi + 1, yy) != 1 || yy == ymax) - sp (st, xi, yy, 0); - } - if (horiwall && yi + 1 <= ymax) - { - int xx; - for (xx = xi - xi % st->boxw; - xx <= xi - xi % st->boxw + st->boxw && xx <= xmax; xx++) - if (gp (st, xx, yi + 1) != 1 || xx == xmax) - sp (st, xx, yi, 0); - } - } - if (oldcol != LP->col || LP->selfbounce) - { - LP->x = oldx; - LP->y = oldy; - } - wraparound (LP->deg, 0, degs); + bool vertwall = false, horiwall = false; + if (oldcol == 1 && ((LP->killwalls && gridden > 0) || LP->realbounce)) + { + vertwall = (gp (xi, (int) oldy) == 1); + horiwall = (gp ((int) oldx, yi) == 1); + } + if (oldcol == 1 && LP->realbounce && (vertwall || horiwall)) + { + if (vertwall) + LP->deg = -LP->deg + degs2; + else + LP->deg = -LP->deg; + } + else + { + if ((oldcol != LP->col && LP->realbounce) + || (oldcol == LP->col && LP->selfbounce)) + LP->deg += degs4 * (random1 (2) * 2 - 1); + else if (oldcol != LP->col) + LP->deg += degs2; + } + if (LP->killwalls && gridden > 0 && oldcol == 1) + { + if (vertwall && xi + 1 <= xmax) + { + int yy; + for (yy = yi - yi % boxh; + yy <= yi - yi % boxh + boxh && yy <= ymax; yy++) + if (gp (xi + 1, yy) != 1 || yy == ymax) + sp (xi, yy, 0); + } + if (horiwall && yi + 1 <= ymax) + { + int xx; + for (xx = xi - xi % boxw; + xx <= xi - xi % boxw + boxw && xx <= xmax; xx++) + if (gp (xx, yi + 1) != 1 || xx == xmax) + sp (xx, yi, 0); + } + } + if (oldcol != LP->col || LP->selfbounce) + { + LP->x = oldx; + LP->y = oldy; + } + wraparound (LP->deg, 0, degs); } } - sp (st, xi, yi, LP->col); + sp (xi, yi, LP->col); if (LP->filled) { - if (st->erasing) - sp (st, LP->xrec[LP->recpos], LP->yrec[LP->recpos], 0); + if (erasing) + sp (LP->xrec[LP->recpos], LP->yrec[LP->recpos], 0); else - sp (st, LP->xrec[LP->recpos], LP->yrec[LP->recpos], LP->col + thrmax); + sp (LP->xrec[LP->recpos], LP->yrec[LP->recpos], LP->col + thrmax); } LP->yrec[LP->recpos] = yi; LP->xrec[LP->recpos] = xi; if (LP->recpos == LP->reclen - 1) - LP->filled = True; - if (LP->filled && !st->erasing) + LP->filled = true; + if (LP->filled && !erasing) { int co = LP->recpos; - LP->dead = True; + LP->dead = true; do - { - int nextco = co + 1; - wraparound (nextco, 0, LP->reclen); - if (LP->yrec[co] != LP->yrec[nextco] - || LP->xrec[co] != LP->xrec[nextco]) - LP->dead = False; - co = nextco; - } + { + int nextco = co + 1; + wraparound (nextco, 0, LP->reclen); + if (LP->yrec[co] != LP->yrec[nextco] + || LP->xrec[co] != LP->xrec[nextco]) + LP->dead = false; + co = nextco; + } while (!(!LP->dead || co == LP->recpos)); } LP->recpos++; @@ -700,529 +641,456 @@ move (struct state *st, unsigned char thr) return (!LP->dead); } -static unsigned long -vermiculate_draw (Display *dpy, Window window, void *closure) +void Vermiculate::render (uint32_t *p) { - struct state *st = (struct state *) closure; - int had_instring = (st->instring != 0); + int had_instring = (instring != 0); int tick = 0; int this_delay = 0; int loop = 0; - + AGAIN: - if (st->reset_p) + if (reset_p) { - st->reset_p = 0; + reset_p = 0; - clearscreen (st); + clearscreen (); { - unsigned char thr; - for (thr = 1; thr <= st->threads; thr++) - newonscreen (st, thr); + unsigned char thr; + for (thr = 1; thr <= threads; thr++) + newonscreen (thr); } - if (st->autopal) - { - randpal (st); - palupdate (st, False); - } - bordupdate (st); - gridupdate (st, False); + if (autopal) + { + randpal (); + palupdate (false); + } + bordupdate (); + gridupdate (false); } { - Bool alltrap = True; + bool alltrap = true; unsigned char thr; - for (thr = 1; thr <= st->threads; thr++) - if (move (st, thr)) - alltrap = False; - if (alltrap) /* all threads are trapped */ - st->reset_p = True; - if (st->speed != SPEEDMAX) - this_delay = waitabit (st); + for (thr = 1; thr <= threads; thr++) + if (move (thr)) + alltrap = false; + if (alltrap) /* all threads are trapped */ + reset_p = true; + //if (speed != SPEEDMAX) + // this_delay = waitabit (); } - if (tick++ > st->max_ticks && !had_instring) + if (tick++ > max_ticks && !had_instring) { tick = 0; - if (st->oinstring) free (st->oinstring); - st->instring = st->oinstring = 0; - maininit(st); - st->reset_p = True; - st->autopal = False; + if (oinstring) free (oinstring); + instring = oinstring = 0; + maininit(); + reset_p = true; + autopal = false; } - if (this_delay == 0 && loop++ < 1000) + //if (this_delay == 0 && loop++ < 1000) + if (loop++ < cycles) goto AGAIN; - return this_delay; + std::copy(pixels.begin(), pixels.end(), p); } -static void * -vermiculate_init (Display *d, Window w) +bool Vermiculate::render_gui () { - struct state *st = (struct state *) calloc (1, sizeof(*st)); - st->dpy = d; - st->window = w; - st->reset_p = 1; - st->oinstring = get_string_resource (st->dpy, "instring", "Instring"); - if (st->oinstring && !*st->oinstring) { - free (st->oinstring); - st->oinstring = 0; - } - st->instring = st->oinstring; + bool up = false; - st->max_ticks = get_integer_resource (st->dpy, "ticks", "Integer"); - st->speed = get_integer_resource (st->dpy, "speed", "Speed"); - if (st->speed <= 0) st->speed = 1; - st->mycolors[0].pixel = BlackPixel (st->dpy, DefaultScreen (st->dpy)); + ScrollableSliderInt("ticks", &max_ticks, 0, 20000, "%d", 8); + ScrollableSliderInt("cycles", &cycles, 0, 1024, "%d", 1); + //up |= ScrollableSliderInt("Speed", &speed, 1, 1024, "%d", 1); + up |= pal.RenderGui(); - XSetWindowBackground (st->dpy, st->window, - BlackPixel (st->dpy, DefaultScreen (st->dpy))); - { - XGetWindowAttributes (st->dpy, st->window, &st->xgwa); - st->wid = st->xgwa.width; - st->hei = st->xgwa.height; - st->mycmap = st->xgwa.colormap; - } - { - XGCValues mygcv; - st->mygc = XCreateGC (st->dpy, st->window, 0, &mygcv); - } + // TODO: select instring - st->pscale = 1; - if (st->xgwa.width > 2560 || st->xgwa.height > 2560) - st->pscale = 3; /* Retina displays */ - /* We aren't increasing the spacing between the pixels, just the size. */ + if (up) { + resize(w, h); + } - st->point = (unsigned char *) calloc (1, st->wid * st->hei); - maininit (st); - palupdate (st, True); - consume_instring(st); - return st; + return up; } -static void -vermiculate_reshape (Display *dpy, Window window, void *closure, - unsigned int w, unsigned int h) -{ - struct state *st = (struct state *) closure; - st->wid = w; - st->hei = h; - free (st->point); - st->point = (unsigned char *) calloc (1, st->wid * st->hei); -} - -static Bool -vermiculate_event (Display *dpy, Window window, void *closure, XEvent *event) +void Vermiculate::resize (int _w, int _h) { - struct state *st = (struct state *) closure; - if (screenhack_event_helper (dpy, window, event)) - { - st->reset_p = 1; - return True; - } - return False; + default_resize(_w, _h); + point.resize(w*h); + fill0(point); + reset_p = 1; + instring = 0; + maininit (); + palupdate (true); + consume_instring(); } -static void -consume_instring(struct state *st) +void Vermiculate::consume_instring() { char boolop; - while (wasakeypressed (st)) - { - st->ch = readkey (st); - switch (st->ch) - { - case 'M': - st->ch = readkey (st); - switch (st->ch) - { - case 'A': - case 'N': - { - unsigned char othreads = st->threads; - if (st->ch == 'N') - st->threads = 0; - do - { - st->ch = readkey (st); - switch (st->ch) - { - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - st->thread[++st->threads - 1].tmode = st->ch - '0'; - break; - case 'R': - st->thread[++st->threads - 1].tmode = - random1 (tmodes - '0') + 1; - break; - } - } - while (!(st->ch == '\15' || st->ch == '#' - || st->threads == thrmax)); - if (st->threads == 0) - st->threads = othreads; - st->reset_p = 1; - } - break; - } - break; - case 'C': - pickbank (st); - if (st->bnkt > 0) - { - st->ch = readkey (st); - switch (st->ch) - { - case 'D': - st->ch = readkey (st); - switch (st->ch) - { + while (wasakeypressed ()) + { + ch = readkey (); + switch (ch) + { + case 'M': + ch = readkey (); + switch (ch) + { + case 'A': + case 'N': + { + unsigned char othreads = threads; + if (ch == 'N') + threads = 0; + do + { + ch = readkey (); + switch (ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + thread[++threads - 1].tmode = ch - '0'; + break; + case 'R': + thread[++threads - 1].tmode = + random1 (tmodes - '0') + 1; + break; + } + } + while (!(ch == '\15' || ch == '#' + || threads == thrmax)); + if (threads == 0) + threads = othreads; + reset_p = 1; + } + break; + } + break; + case 'C': + pickbank (); + if (bnkt > 0) + { + ch = readkey (); + switch (ch) + { + case 'D': + ch = readkey (); + switch (ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + /* Careful! The following macro needs to be at the beginning of any + block in which it's invoked, since it declares variables: */ + #define forallinbank(LDP) linedata *LDP; int bankc; \ + for (bankc = 1; \ + ((bankc <= bnkt) ? ( \ + (LDP = &thread[bank[bankc - 1] - 1], 1) \ + ) : 0) ; bankc++) + { + forallinbank (L) L->slice = degs / (ch - '0'); + } + break; + case 'M': + { + forallinbank (L) L->slice = 0; + } + break; + } + break; + case 'S': + { + forallinbank (L) + { + L->otslen = L->tslen; + L->tslen = 0; + } + } + do + { + char oldch = ch; + ch = readkey (); + { + forallinbank (L) + { + switch (ch) + { + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': -/* Careful! The following macro needs to be at the beginning of any -block in which it's invoked, since it declares variables: */ -#define forallinbank(LDP) linedata *LDP; int bankc; \ - for (bankc = 1; \ - ((bankc <= st->bnkt) ? ( \ - (LDP = &st->thread[st->bank[bankc - 1] - 1], 1) \ - ) : 0) ; bankc++) - { - forallinbank (L) L->slice = degs / (st->ch - '0'); - } - break; - case 'M': - { - forallinbank (L) L->slice = 0; - } - break; - } - break; - case 'S': - { - forallinbank (L) - { - L->otslen = L->tslen; - L->tslen = 0; - } - } - do - { - char oldch = st->ch; - st->ch = readkey (st); - { - forallinbank (L) - { - switch (st->ch) - { - case '0': - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - L->tslen++; - L->turnseq[L->tslen - 1] = st->ch - '0'; - if (oldch == '-') - L->turnseq[L->tslen - 1] *= -1; - if (bankc % 2 == 0) - L->turnseq[L->tslen - 1] *= -1; - break; - } - } - } - } - while (!(st->ch == '\15' || st->ch == '#' - || st->thread[st->bank[0] - 1].tslen == 50)); - { - forallinbank (L) - { - int seqSum = 0, c; - - if (L->tslen == 0) - L->tslen = L->otslen; - for (c = 1; c <= L->tslen; c++) - seqSum += L->turnseq[c - 1]; - if (seqSum == 0) - L->tclim = 1; - else - L->tclim = - (int) (((real) degs2) / abs (seqSum)); - L->tsc = random1 (L->tslen) + 1; - } - } - break; - case 'T': - { - st->ch = readkey (st); - { - forallinbank (L) - { - switch (st->ch) - { - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - L->tmode = st->ch - '0'; - break; - case 'R': - L->tmode = random1 (tmodes - '0') + 1; - break; - } - } - } - } - break; - case 'O': - st->ch = readkey (st); - { - forallinbank (L) L->orichar = st->ch; - } - break; - case 'F': - { - banktype fbank; - arrcpy (fbank, st->bank); - { - int fbnkt = st->bnkt; - int bankc; - pickbank (st); - for (bankc = 1; bankc <= fbnkt; bankc++) - { - linedata *L = &st->thread[fbank[bankc - 1] - 1]; - if (st->ch == 'N') - L->prey = 0; - else - L->prey = st->bank[0 + (bankc - 1) % st->bnkt]; - } - } - } - break; - case 'L': - { - forallinbank (L) L->prey = st->bank[bankc % st->bnkt]; - } - break; - case 'R': - st->ch = readkey (st); - { - forallinbank (L) switch (st->ch) - { - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - L->circturn = 10 - (st->ch - '0'); - break; - case 'R': - L->circturn = random1 (7) + 1; - break; - } - } - break; - } - } - break; - case 'T': - case 'Y': - case 'N': - boolop = st->ch; - pickbank (st); - if (st->bnkt > 0) - { - st->ch = readkey (st); - { - forallinbank (L) - { - switch (st->ch) - { - case 'S': - bankmod (boolop, &L->selfbounce); - break; - case 'V': - bankmod (boolop, &L->vhfollow); - break; - case 'R': - bankmod (boolop, &L->realbounce); - break; - case 'L': - bankmod (boolop, &L->little); - st->cleared = True; - break; - case 'T': - bankmod (boolop, &L->tailfollow); - break; - case 'K': - bankmod (boolop, &L->killwalls); - break; - } - } - } - } - break; - case 'R': - if (st->bordcol == 1) - { - st->bordcol = 0; - bordupdate (st); - st->bordcorn = (st->bordcorn + 1) % 4; - st->bordcol = 1; - bordupdate (st); - } - break; - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': - { - int c; - for (c = 1; c <= thrmax; c++) - st->thread[c - 1].tmode = st->ch - '0'; - } - break; - case '\40': - st->cleared = True; - break; - case 'E': - st->erasing = !st->erasing; - break; - case 'P': - randpal (st); - palupdate (st, True); - break; - case 'G': - { - char dimch = 'B'; - Bool gridchanged = True; - if (st->gridden == 0) - st->gridden = st->ogd; - do - { - int msize = 0; - if (gridchanged) - { - clearscreen (st); - gridupdate (st, True); - } - st->ch = readkey (st); - gridchanged = True; - switch (st->ch) - { - case '+': - msize = 1; - break; - case '-': - msize = -1; - break; - case ']': - if (st->gridden < 15) - st->gridden++; - break; - case '[': - if (st->gridden > 0) - st->gridden--; - break; - case 'O': - st->ogd = st->gridden; - st->gridden = 0; - break; - case 'S': - st->boxw = st->boxh; - case 'W': - case 'H': - case 'B': - dimch = st->ch; - break; - default: - gridchanged = False; - } - if (dimch == 'W' || dimch == 'B') - st->boxw += msize; - if (dimch == 'H' || dimch == 'B') - st->boxh += msize; - if (st->boxw == 0) - st->boxw = 1; - if (st->boxh == 0) - st->boxh = 1; - } - while (!(st->ch == '\15' || st->ch == '#' || st->ch == 'O')); - st->cleared = True; - } - break; - case 'A': - st->autopal = !st->autopal; - break; - case 'B': - st->bordcol = 1 - st->bordcol; - bordupdate (st); - break; - case '-': - st->speed -= SPEEDINC; - if (st->speed < 1) - st->speed = 1; - break; - case '+': - st->speed += SPEEDINC; - if (st->speed > SPEEDMAX) - st->speed = SPEEDMAX; - break; - case '/': - if (st->curviness > 5) - st->curviness -= 5; - break; - case '*': - if (st->curviness < 50) - st->curviness += 5; - break; - case ']': - if (st->threads < thrmax) - newonscreen (st, ++st->threads); - break; - case '[': - if (st->threads > 1) - { - linedata *L = &st->thread[st->threads - 1]; - int lastpos = (L->filled) ? L->reclen - 1 : L->recpos; - int c; - for (c = 0; c <= lastpos; c++) - sp (st, L->xrec[c], L->yrec[c], 0); - st->threads--; - } - break; - } - } -} - -static void -vermiculate_free (Display *dpy, Window window, void *closure) -{ - struct state *st = (struct state *) closure; - XFreeGC (dpy, st->mygc); - if (st->oinstring) free (st->oinstring); - if (st->point) free(st->point); - free (st); + L->tslen++; + L->turnseq[L->tslen - 1] = ch - '0'; + if (oldch == '-') + L->turnseq[L->tslen - 1] *= -1; + if (bankc % 2 == 0) + L->turnseq[L->tslen - 1] *= -1; + break; + } + } + } + } + while (!(ch == '\15' || ch == '#' + || thread[bank[0] - 1].tslen == 50)); + { + forallinbank (L) + { + int seqSum = 0, c; + if (L->tslen == 0) + L->tslen = L->otslen; + for (c = 1; c <= L->tslen; c++) + seqSum += L->turnseq[c - 1]; + if (seqSum == 0) + L->tclim = 1; + else + L->tclim = + (int) (((real) degs2) / abs (seqSum)); + L->tsc = random1 (L->tslen) + 1; + } + } + break; + case 'T': + { + ch = readkey (); + { + forallinbank (L) + { + switch (ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + L->tmode = ch - '0'; + break; + case 'R': + L->tmode = random1 (tmodes - '0') + 1; + break; + } + } + } + } + break; + case 'O': + ch = readkey (); + { + forallinbank (L) L->orichar = ch; + } + break; + case 'F': + { + banktype fbank; + arrcpy (fbank, bank); + { + int fbnkt = bnkt; + int bankc; + pickbank (); + for (bankc = 1; bankc <= fbnkt; bankc++) + { + linedata *L = &thread[fbank[bankc - 1] - 1]; + if (ch == 'N') + L->prey = 0; + else + L->prey = bank[0 + (bankc - 1) % bnkt]; + } + } + } + break; + case 'L': + { + forallinbank (L) L->prey = bank[bankc % bnkt]; + } + break; + case 'R': + ch = readkey (); + { + forallinbank (L) switch (ch) + { + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + L->circturn = 10 - (ch - '0'); + break; + case 'R': + L->circturn = random1 (7) + 1; + break; + } + } + break; + } + } + break; + case 'T': + case 'Y': + case 'N': + boolop = ch; + pickbank (); + if (bnkt > 0) + { + ch = readkey (); + { + forallinbank (L) + { + switch (ch) + { + case 'S': + bankmod (boolop, &L->selfbounce); + break; + case 'V': + bankmod (boolop, &L->vhfollow); + break; + case 'R': + bankmod (boolop, &L->realbounce); + break; + case 'L': + bankmod (boolop, &L->little); + cleared = true; + break; + case 'T': + bankmod (boolop, &L->tailfollow); + break; + case 'K': + bankmod (boolop, &L->killwalls); + break; + } + } + } + } + break; + case 'R': + if (bordcol == 1) + { + bordcol = 0; + bordupdate (); + bordcorn = (bordcorn + 1) % 4; + bordcol = 1; + bordupdate (); + } + break; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + { + int c; + for (c = 1; c <= thrmax; c++) + thread[c - 1].tmode = ch - '0'; + } + break; + case '\40': + cleared = true; + break; + case 'E': + erasing = !erasing; + break; + case 'P': + randpal (); + palupdate (true); + break; + case 'G': + { + char dimch = 'B'; + bool gridchanged = true; + if (gridden == 0) + gridden = ogd; + do + { + int msize = 0; + if (gridchanged) + { + clearscreen (); + gridupdate (true); + } + ch = readkey (); + gridchanged = true; + switch (ch) + { + case '+': + msize = 1; + break; + case '-': + msize = -1; + break; + case ']': + if (gridden < 15) + gridden++; + break; + case '[': + if (gridden > 0) + gridden--; + break; + case 'O': + ogd = gridden; + gridden = 0; + break; + case 'S': + boxw = boxh; + case 'W': + case 'H': + case 'B': + dimch = ch; + break; + default: + gridchanged = false; + } + if (dimch == 'W' || dimch == 'B') + boxw += msize; + if (dimch == 'H' || dimch == 'B') + boxh += msize; + if (boxw == 0) + boxw = 1; + if (boxh == 0) + boxh = 1; + } + while (!(ch == '\15' || ch == '#' || ch == 'O')); + cleared = true; + } + break; + case 'A': + autopal = !autopal; + break; + case 'B': + bordcol = 1 - bordcol; + bordupdate (); + break; + case '-': + speed -= SPEEDINC; + if (speed < 1) + speed = 1; + break; + case '+': + speed += SPEEDINC; + if (speed > SPEEDMAX) + speed = SPEEDMAX; + break; + case '/': + if (curviness > 5) + curviness -= 5; + break; + case '*': + if (curviness < 50) + curviness += 5; + break; + case ']': + if (threads < thrmax) + newonscreen (++threads); + break; + case '[': + if (threads > 1) + { + linedata *L = &thread[threads - 1]; + int lastpos = (L->filled) ? L->reclen - 1 : L->recpos; + int c; + for (c = 0; c <= lastpos; c++) + sp (L->xrec[c], L->yrec[c], 0); + threads--; + } + break; + } + } } - - -static const char *vermiculate_defaults[] = { -/* ".lowrez: true", */ - ".background: Black", - "*ticks: 20000", - "*fpsSolid: true", - "*speed: 1", - "*instring: ", -#ifdef HAVE_MOBILE - "*ignoreRotation: True", -#endif - 0 -}; - -static XrmOptionDescRec vermiculate_options[] = { - {"-speed", ".speed", XrmoptionSepArg, 0}, - {"-instring", ".instring", XrmoptionSepArg, 0}, - {0, 0, 0, 0} -}; - - -XSCREENSAVER_MODULE ("Vermiculate", vermiculate) diff --git a/vermiculate.h b/vermiculate.h new file mode 100644 index 0000000..5ec0fc4 --- /dev/null +++ b/vermiculate.h @@ -0,0 +1,90 @@ +#include "art.hpp" +#include "imgui.h" +#include + +#include "settings.hpp" + + +#define degs 360 +#define thrmax 120 +#define rlmax 200 + +typedef double real; +typedef unsigned char banktype[thrmax]; + +typedef struct linedata +{ + int deg, spiturn, turnco, turnsize; + unsigned char col; + bool dead; + + char orichar; + real x, y; + int tmode, tsc, tslen, tclim, otslen, ctinc, reclen, recpos, circturn, prey, + slice; + int xrec[rlmax + 1], yrec[rlmax + 1]; + int turnseq[50]; + bool filled, killwalls, vhfollow, + selfbounce, tailfollow, realbounce, little; +} +linedata; + + +class Vermiculate : public Art { +public: + Vermiculate() + : Art("Vermiculate") {} + virtual bool render_gui() override; + virtual void resize(int _w, int _h) override; + virtual void render(uint32_t *p) override; +private: + + + int speed = 1; + bool erasing, cleared, autopal; + char *oinstring = 0; /* allocated */ + const char *instring = 0; /* consumed */ + int max_ticks = 20000; + + real sinof[degs], cosof[degs], tanof[degs]; + std::vector point; + + linedata thread[thrmax]; + banktype bank; + int bnkt; + int boxw, boxh, curviness, gridden, ogd, bordcorn; + unsigned char bordcol, threads; + char ch, boolop; + + int reset_p = 1; + int cyc; + int cycles = 1; + + PaletteSetting pal; + + bool wasakeypressed(); + char readkey (); + unsigned int random1 (unsigned int i); + unsigned long waitabit (); + void clearscreen (); + void sp (int x, int y, uint32_t c); + int gp (int x, int y); + void redraw (int x, int y, int width, int height); + void palupdate (bool forceUpdate); + void randpal (); + void gridupdate (bool interruptible); + void bordupdate (); + + bool inbank (unsigned char thr); + void pickbank (); + + void bankmod (char boolop, bool * Bool_); + void newonscreen (unsigned char thr); + void firstinit (unsigned char thr); + void maininit (); + bool move (unsigned char thr); + void consume_instring(); + + +}; +