qemacs-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemacs-commit] qemacs Makefile tests/mandelbrot.sh fractal.c


From: Charlie Gordon
Subject: [Qemacs-commit] qemacs Makefile tests/mandelbrot.sh fractal.c
Date: Thu, 27 Apr 2017 19:04:10 -0400 (EDT)

CVSROOT:        /sources/qemacs
Module name:    qemacs
Changes by:     Charlie Gordon <chqrlie>        17/04/27 19:04:10

Modified files:
        .              : Makefile 
        tests          : mandelbrot.sh 
Added files:
        .              : fractal.c 

Log message:
        tests: add fractal test functions
        - improve mandelbrot shell script
        - add fractal.c: a fractal generator and navigator that can
          be used as a terminal stress test.
        - add fractal-mode for easy fractal navigation and zooming
          with key bindings.
        - try it out with C-h m SP / SP / SP ...

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/qemacs/Makefile?cvsroot=qemacs&r1=1.97&r2=1.98
http://cvs.savannah.gnu.org/viewcvs/qemacs/fractal.c?cvsroot=qemacs&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/qemacs/tests/mandelbrot.sh?cvsroot=qemacs&r1=1.2&r2=1.3

Patches:
Index: Makefile
===================================================================
RCS file: /sources/qemacs/qemacs/Makefile,v
retrieving revision 1.97
retrieving revision 1.98
diff -u -b -r1.97 -r1.98
--- Makefile    11 Apr 2017 06:46:13 -0000      1.97
+++ Makefile    27 Apr 2017 23:04:10 -0000      1.98
@@ -69,7 +69,7 @@
 OBJS:= qe.o util.o cutils.o charset.o buffer.o search.o parser.o input.o 
display.o hex.o \
        list.o
 TOBJS:= $(OBJS)
-OBJS+= extras.o variables.o
+OBJS+= extras.o variables.o fractal.o
 
 ifdef CONFIG_DARWIN
   LDFLAGS += -L/opt/local/lib/

Index: tests/mandelbrot.sh
===================================================================
RCS file: /sources/qemacs/qemacs/tests/mandelbrot.sh,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- tests/mandelbrot.sh 12 Apr 2017 07:33:20 -0000      1.2
+++ tests/mandelbrot.sh 27 Apr 2017 23:04:10 -0000      1.3
@@ -1,52 +1,69 @@
 #!/usr/bin/env ksh
+#!/bin/bash
 
 # Charles Cooke's 16-color Mandelbrot
 # http://earth.gkhs.net/ccooke/shell.html
 # Combined Bash/ksh93 flavors by Dan Douglas (ormaaj)
+# Charlie Gordon 2017: Fix aspect ratio, use half block to double vertical 
resolution
+
+declare lastbg=x lastfg=x
 
 function doBash {
-    typeset P Q X Y a b c i j v x y cb m
-    for 
((cb=0,m=16,P=10**8,Q=P/100,X=320*Q/cols,Y=210*Q/lines,y=-105*Q,y1=y+Y/2,v=-220*Q,x=v;
 y<105*Q; x=v,y+=Y,y1+=Y)); do
-        for ((;x<P;a=b=i=j=c=0,x+=X)); do
-            for ((; a**2+b**2<4*P**2&&i++<99; 
a=((c=a)**2-b**2)/P+x,b=2*c*b/P+y)); do :
+    declare -i i j nx ny cols=$1 rows=$2 cb=0 m=16
+    declare -i P=10**8 Q=P/10 bb=4*P**2 xc=-4*Q yc=0 dx=32*Q/cols dy=12*dx/10 
x y a b c
+    for ((y=yc-dy*rows,ny=0; ny++<rows; y+=dy+dy)); do
+      for ((x=xc-dx*cols/2,nx=0; nx++<cols; x+=dx)); do
+        for ((a=b=i=0; a**2+b**2<=bb && i++<99; 
c=a,a=(a**2-b**2)/P+x,b=2*c*b/P+y)); do :
             done
-            for ((; a**2+b**2<4*P**2&&j++<99; 
a=((c=a)**2-b**2)/P+x,b=2*c*b/P+y1)); do :
+        for ((a=b=j=0; a**2+b**2<=bb && j++<99; 
c=a,a=(a**2-b**2)/P+x,b=2*c*b/P+y+dy)); do :
             done
-            #colorBox $((i<99?i%m+cb:cb)) $((j<99?j%m+cb:cb))
-          . colorBox $((i<99?i%m:0)) $((j<99?j%m:0))
+        colorBox $((i<99?i%m+cb:cb)) $((j<99?j%m+cb:cb))
         done
-        echo
+      resetColor
     done
 }
 
 function doKsh {
-    integer i j cb=0 m=16
-    float a b c x=2.2 y=-1.05 y2=y+Y/2 X=3.2/cols Y=2.1/lines 
-    while
-        for ((a=b=i=0;(c=a)**2+b**2<=2&&i++<99&&(a=a**2-b**2+x,b=2*c*b+y);)); 
do :
-        done
-        for ((a=b=j=0;(c=a)**2+b**2<=2&&j++<99&&(a=a**2-b**2+x,b=2*c*b+y2);)); 
do :
-        done
-          #colorBox $((i<99?i%m+cb:cb)) $((j<99?j%m+cb:cb))
-        . colorBox $((i<99?i%m:0)) $((j<99?j%m:0))
-        if ((x<1?!(x+=X):(y+=Y,y2+=Y,x=-2.2))); then
-            print
-            ((y<1.05)) 
-        fi
-        do :
+    integer i j nx ny cols=$1 rows=$2 cb=0 m=16
+    float xc=-0.4 yc=0 dx=3.2/cols dy=1.2*dx x y a b c
+    for ((y=yc-dy*rows,ny=0; ny++<rows; y+=dy+dy)); do :
+      for ((x=xc-dx*cols/2,nx=0; nx++<cols; x+=dx)); do :
+        for ((a=b=i=0; a**2+b**2<=4 && i++<99; c=a,a=a**2-b**2+x,b=2*c*b+y)); 
do :
+        done
+        for ((a=b=j=0; a**2+b**2<=4 && j++<99; 
c=a,a=a**2-b**2+x,b=2*c*b+y+dy)); do :
+        done
+        . colorBox $((i<99?i%m+cb:cb)) $((j<99?j%m+cb:cb))
+      done
+      resetColor
     done
 }
 
+function resetColor {
+    lastbg=x
+    lastfg=x
+    echo -e "\033[m"
+}
+
 function colorBox {
-    printf "\033[48;5;$1m"
-    printf "\033[38;5;$2m"
+    # \u2584 (in utf-8 \xE2\x96\x84 is the top square
     #(($1==lastclr)) || printf %s "${colrs[lastclr=$1]:=$(tput setab "$1")}"
-    #(($2==lastclr2)) || printf %s "${colrs[lastclr2=$2]:=$(tput setaf "$2")}"
-    printf '\u2584'
+    #printf "\033[48;5;${1}m"
+    #printf "\033[38;5;${2}m"
+    #printf '\u2584'
+    if [ $1 != $lastbg ]; then
+        printf "\033[48;5;$((lastbg=$1))m"
+    fi
+    if [ $1 == $2 ]; then
+        printf " "
+    else
+        if [ $2 != $lastfg ]; then
+            printf "\033[38;5;$((lastfg=$2))m"
+        fi
+        printf "\342\226\204"
+    fi
 }
 
-unset -v lastclr
-((cols=$(tput cols)-2, lines=$(tput lines)))
-typeset -a colrs
-trap 'tput sgr0; echo' EXIT
-${KSH_VERSION+. doKsh} ${BASH_VERSION+doBash}
+#unset -v lastclr
+#typeset -a colrs
+trap 'tput sgr0' EXIT
+${KSH_VERSION+. doKsh} ${BASH_VERSION+doBash} $(($(tput cols)-2)) $(($(tput 
lines)-1))

Index: fractal.c
===================================================================
RCS file: fractal.c
diff -N fractal.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ fractal.c   27 Apr 2017 23:04:10 -0000      1.1
@@ -0,0 +1,655 @@
+/*
+ * QEmacs, character based fractal rendering
+ *
+ * Copyright (c) 2017 Charlie Gordon.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <math.h>
+
+#include "qe.h"
+#include "qfribidi.h"
+#include "variables.h"
+
+/*---------------- Fractint formula syntax ----------------*/
+
+static const char fractint_keywords[] = {
+    "if|else|elseif|endif|pixel"
+};
+
+static const char fractint_types[] = {
+    ""
+};
+
+enum {
+    FRACTINT_STYLE_DEFAULT    = 0,
+    FRACTINT_STYLE_PREPROCESS = QE_STYLE_PREPROCESS,
+    FRACTINT_STYLE_COMMENT    = QE_STYLE_COMMENT,
+    FRACTINT_STYLE_DEFINITION = QE_STYLE_TYPE,
+    FRACTINT_STYLE_NUMBER     = QE_STYLE_NUMBER,
+    FRACTINT_STYLE_COLORS     = QE_STYLE_STRING,
+    FRACTINT_STYLE_KEYWORD    = QE_STYLE_KEYWORD,
+    FRACTINT_STYLE_FUNCTION   = QE_STYLE_FUNCTION,
+    FRACTINT_STYLE_STRING     = QE_STYLE_STRING,
+    FRACTINT_STYLE_STRING_Q   = QE_STYLE_STRING_Q,
+    FRACTINT_STYLE_TYPE       = QE_STYLE_TYPE,
+};
+
+/* fractint-mode colorization states */
+enum {
+    IN_FRACTINT_COMMENT    = 0x01,  /* inside multiline comment */
+    IN_FRACTINT_BLOCK      = 0x02,  /* inside definition block */
+    IN_FRACTINT_COLORS     = 0x04,  /* inside a color palette definition */
+    IN_FRACTINT_STRING     = 0x10,  /* double-quoted string */
+    IN_FRACTINT_STRING_Q   = 0x20,  /* single-quoted string */
+};
+
+static void fractint_colorize_line(QEColorizeContext *cp,
+                               unsigned int *str, int n, ModeDef *syn)
+{
+    int i = 0, start, indent, c, state, state1, style, klen, delim;
+    char kbuf[64];
+
+    for (indent = 0; qe_isblank(str[indent]); indent++)
+        continue;
+
+    state = cp->colorize_state;
+
+    start = i;
+    c = 0;
+    style = FRACTINT_STYLE_DEFAULT;
+
+    if (i >= n)
+        goto the_end;
+
+    if (state) {
+        /* if already in a state, go directly in the code parsing it */
+        if (state & IN_FRACTINT_COMMENT)
+            goto parse_comment;
+        if (state & IN_FRACTINT_COLORS) {
+            i = indent;
+            goto parse_colors;
+        }
+        if (state & IN_FRACTINT_STRING)
+            goto parse_string;
+        if (state & IN_FRACTINT_STRING_Q)
+            goto parse_string_q;
+    }
+
+    while (i < n) {
+        start = i;
+        c = str[i++];
+        switch (c) {
+        case ';':      /* line comment */
+            style = FRACTINT_STYLE_COMMENT;
+            i = n;
+            break;
+        case ':':      /* iteration definition */
+            style = FRACTINT_STYLE_KEYWORD;
+            break;
+        case '\'':     /* character constant */
+        parse_string_q:
+            state1 = IN_FRACTINT_STRING_Q;
+            style = FRACTINT_STYLE_STRING_Q;
+            delim = '\'';
+            goto string;
+
+        case '\"':      /* string literal */
+        parse_string:
+            state1 = IN_FRACTINT_STRING;
+            style = FRACTINT_STYLE_STRING;
+            delim = '\"';
+        string:
+            while (i < n) {
+                c = str[i++];
+                if (c == '\\') {
+                    if (i >= n) {
+                        /* continuation line */
+                        state |= state1;
+                        break;
+                    }
+                    i++;
+                } else
+                if (c == delim) {
+                    break;
+                }
+            }
+            break;
+        case '{':
+            if (state & IN_FRACTINT_BLOCK) {
+                /* a '{' inside a definition seems to start a comment */
+                /* consider it part of the comment, otherwise skip it */
+                goto parse_comment;
+            }
+            if (str[i] == '-' || str[i] == '=') {
+                /* invalid block, parse as comment */
+                start++;
+                goto parse_comment;
+            }
+            state |= IN_FRACTINT_BLOCK;
+            break;
+        case '}':
+            state &= ~IN_FRACTINT_COMMENT;
+            state &= ~IN_FRACTINT_BLOCK;
+            break;
+        case ' ':
+        case '\t':
+        case '\r':
+            continue;
+        default:
+            if (!(state & IN_FRACTINT_BLOCK)) {
+                klen = 0;
+                kbuf[klen++] = qe_tolower(c);
+                while (i < n && str[i] != '{') {
+                    if (str[i] != ' ' && klen < countof(kbuf) - 1)
+                        kbuf[klen++] = qe_tolower(str[i]);
+                    i++;
+                }
+                if (kbuf[klen - 1] == '=')
+                    klen--;
+                kbuf[klen] = '\0';
+                if (i >= n) {
+                    style = FRACTINT_STYLE_COMMENT;
+                    break;
+                }
+                if (strequal(kbuf, "comment")) {
+                    SET_COLOR(str, start, i, FRACTINT_STYLE_PREPROCESS);
+                    start = i + 1;
+                parse_comment:
+                    state |= IN_FRACTINT_COMMENT;
+                    for (; i < n; i++) {
+                        if (str[i] == '}') {
+                            break;
+                        }
+                    }
+                    style = FRACTINT_STYLE_COMMENT;
+                } else {
+                    eb_add_property(cp->b, cp->offset + start,
+                                    QE_PROP_TAG, qe_strdup(kbuf));
+                    style = FRACTINT_STYLE_DEFINITION;
+                }
+                break;
+            }
+            if (c == '.' || qe_isdigit(c)) {
+                int j;
+                // Integers:
+                // 0x[0-9a-fA-F]+      //
+                // [0-9][0-9]*         //
+                // Floats:
+                // [0-9][0-9]*\.[0-9]*([eE][-\+]?[0-9]+)?
+                // [0-9][0-9]*(\.[0-9]*)?[eE][-\+]?[0-9]+
+                // number suffixes:
+                if (c == '0' && str[i] == 'x' && qe_isxdigit(str[i + 1])) {
+                    for (i += 3; qe_isxdigit(str[i]); i++)
+                        continue;
+                } else {
+                    while (qe_isdigit(str[i]))
+                        i++;
+                    if (c != '.' && str[i] == '.' && qe_isdigit(str[i + 1])) {
+                        for (i += 2; qe_isdigit(str[i]); i++)
+                            continue;
+                    }
+                    if (str[i] == 'e' || str[i] == 'E') {
+                        j = i + 1;
+                        if (str[j] == '+' || str[j] == '-')
+                            j++;
+                        if (qe_isdigit(str[j])) {
+                            for (i = j + 1; qe_isdigit(str[i]); i++)
+                                continue;
+                        }
+                    }
+                }
+                if (str[i] == 'i' || str[i] == 'I') {
+                    /* imaginary number */
+                    i++;
+                }
+                if (!qe_isalpha_(str[i])) {
+                    style = FRACTINT_STYLE_NUMBER;
+                    break;
+                }
+                i = start + 1;
+            }
+            if (qe_isalpha_(c)) {
+                /* identifiers match:
+                 * "[a-zA-Z_\x80-\xff][a-zA-Z_0-9\x80-\xff]*"
+                 */
+                klen = 0;
+                kbuf[klen++] = qe_tolower(c);
+                while (qe_isalnum_(str[i]) || str[i] == '.') {
+                    if (klen < countof(kbuf) - 1)
+                        kbuf[klen++] = qe_tolower(str[i]);
+                    i++;
+                }
+                kbuf[klen] = '\0';
+                if (strfind(syn->keywords, kbuf)) {
+                    style = FRACTINT_STYLE_KEYWORD;
+                    break;
+                }
+                if (strfind(syn->types, kbuf)) {
+                    style = FRACTINT_STYLE_TYPE;
+                    break;
+                }
+                if (check_fcall(str, i)) {
+                    /* function call */
+                    style = FRACTINT_STYLE_FUNCTION;
+                    break;
+                }
+                if (strequal(kbuf, "colors") && str[i] == '=') {
+                    start = ++i;
+                parse_colors:
+                    state &= ~IN_FRACTINT_COLORS;
+                    for (; i < n; i++) {
+                        c = str[i];
+                        if (!qe_isalnum_(c) && c != '`' && c != '<' && c != 
'>')
+                            break;
+                    }
+                    if (i == n - 1 && str[i] == '\\') {
+                        state |= IN_FRACTINT_COLORS;
+                        i++;
+                    }
+                    style = FRACTINT_STYLE_COLORS;
+                    break;
+                }
+                break;
+            }
+            continue;
+        }
+        if (style) {
+            SET_COLOR(str, start, i, style);
+            style = 0;
+        }
+    }
+ the_end:
+    /* set style on eol char */
+    SET_COLOR1(str, n, style);
+
+    cp->colorize_state = state;
+}
+
+static int fractint_mode_probe(ModeDef *mode, ModeProbeData *pd)
+{
+    if (match_extension(pd->filename, mode->extensions)) {
+        /* This is a quick and dirty hack: assume Fractint formula
+         * files are located somewhere below a directory with a
+         * name relating to fractals.
+         */
+        if (strstr(pd->real_filename, "frac")) {
+            /* Favor Fractint mode for formula files */
+            return 82;
+        } else {
+            /* Favor Visual Basic Form mode */
+            return 78;
+        }
+    }
+    return 1;
+}
+
+static ModeDef fractint_mode = {
+    .name = "Fractint",
+    .extensions = "frm|par|ifs|l",
+    .mode_probe = fractint_mode_probe,
+    .colorize_func = fractint_colorize_line,
+    .keywords = fractint_keywords,
+    .types = fractint_types,
+    .fallback = &c_mode,
+};
+
+/*---------------- Interactive fractal explorer ----------------*/
+
+static ModeDef fractal_mode;
+
+#if 1
+typedef long double fnum_t;
+#define MFT  "%.21Lg"
+#else
+typedef long double fnum_t;
+#define MFT  "%.16Lg"
+#endif
+
+typedef struct FractalState FractalState;
+
+struct FractalState {
+    int cols, rows;
+    int maxiter;        /* maximum iteration number */
+    int cb, nc;         /* color palette base and length */
+    int rot;            /* rotation in degrees */
+    int zoom;           /* zoom level in dB */
+    fnum_t scale;     /* zoom factor = pow(10, -mzoom/10) */
+    fnum_t bailout; /* maximum module */
+    fnum_t x, y;      /* center position */
+    fnum_t m0, m1, m2, m3; /* rotation matrix */
+};
+
+const char fractal_default_parameters[] = {
+    " maxiter=215"
+    " cb=16"
+    " nc=216"
+    " rot=0"
+    " zoom=0"
+    " bailout=4"
+    // This place zooms to level 180, scale=1e-18:
+    " x=-0.747698434201463097446  y=0.0794508470293983774563"
+    // This place on the X axis is interesting:
+    //" x=-1.78935604483808219844, y=0"
+};
+
+/* XXX: should be allocated as buffer mode data */
+static FractalState fractal_state;
+
+static void fractal_set_rotation(FractalState *ms, int rot) {
+    ms->rot = rot;
+    /* compute rotation matrix */
+    ms->m0 = cos(-ms->rot * M_PI / 180.0);
+    ms->m1 = sin(-ms->rot * M_PI / 180.0);
+    ms->m2 = -ms->m1;
+    ms->m3 = ms->m0;
+}
+
+static void fractal_set_zoom(FractalState *ms, int level) {
+    ms->zoom = level;
+    ms->scale = pow(10.0, -ms->zoom / 10.0);
+}
+
+static void fractal_set_parameters(EditState *s, FractalState *ms, const char 
*parms)
+{
+    const char *p;
+
+    ms->cols = ms->rows = 0;    /* force refresh */
+
+    for (p = parms;;) {
+        p += strspn(p, ";, \t\r\n");
+        if (*p == '\0')
+            break;
+        if (strstart(p, "maxiter=", &p)) {
+            ms->maxiter = strtol(p, (char **)&p, 0);
+        } else
+        if (strstart(p, "cb=", &p)) {
+            ms->cb = strtol(p, (char **)&p, 0);
+        } else
+        if (strstart(p, "nc=", &p)) {
+            ms->nc = strtol(p, (char **)&p, 0);
+        } else
+        if (strstart(p, "rot=", &p)) {
+            fractal_set_rotation(ms, strtol(p, (char **)&p, 0));
+        } else
+        if (strstart(p, "zoom=", &p)) {
+            fractal_set_zoom(ms, strtol(p, (char **)&p, 0));
+        } else
+        if (strstart(p, "bailout=", &p)) {
+            ms->bailout = strtold(p, (char **)&p);
+        } else
+        if (strstart(p, "x=", &p)) {
+            ms->x = strtold(p, (char **)&p);
+        } else
+        if (strstart(p, "y=", &p)) {
+            ms->y = strtold(p, (char **)&p);
+        } else {
+            put_status(s, "invalid parameter: %s", p);
+            break;
+        }
+    }
+}
+
+static void do_fractal_draw(EditState *s, FractalState *ms)
+{
+    int cols = ms->cols, rows = ms->rows, zoom = ms->zoom;
+    int maxiter = ms->maxiter + zoom, cb = ms->cb, nc = ms->nc;
+    int i, j, nx, ny, fg, bg;
+    fnum_t xc = ms->x, yc = ms->y, scale = ms->scale;
+    fnum_t bailout = ms->bailout;
+    fnum_t sx, sy, x, y, dx, dy, xr, yr, a, b, c;
+
+    if (s->height == 0 || s->width == 0 || rows == 0 || cols == 0 || nc == 0)
+        return;
+
+    sx = 3.2 * scale;
+    if (s->width == s->cols) {
+        /* character based, assume 80x25 4/3 aspect ratio */
+        sy = sx * 3 / 4 * 80 / 23 * rows / cols;
+    } else {
+        /* pixel based, assume 100% pixel aspect ratio */
+        sy = sx * s->height / s->width;
+    }
+    dx = sx / cols;
+    dy = sy / rows;
+
+    s->b->flags &= ~BF_READONLY;
+
+    eb_delete_range(s->b, 0, s->b->total_size);
+
+    for (ny = 0, y = -sy / 2; ny < rows; ny++, y += dy) {
+        for (nx = 0, x = -sx / 2; nx < cols; nx++, x += dx) {
+            xr = xc + x * ms->m0 + y * ms->m1;
+            yr = yc + x * ms->m2 + y * ms->m3;
+            for (a = b = i = 0;
+                 a * a + b * b <= bailout && i++ < maxiter;
+                 c = a, a = a * a - b * b + xr, b = 2 * c * b + yr)
+                continue;
+            //xr = xc + x * ms->m0 + (y + dy / 2) * ms->m1;
+            //yr = yc + x * ms->m2 + (y + dy / 2) * ms->m3;
+            xr += dy / 2 * ms->m1;
+            yr += dy / 2 * ms->m3;
+            for (a = b = j = 0;
+                 a * a + b * b <= bailout && j++ < maxiter;
+                 c = a, a = a * a - b * b + xr, b = 2 * c * b + yr)
+                continue;
+            bg = i >= maxiter ? 0 : cb + i % nc;
+            fg = j >= maxiter ? 0 : cb + j % nc;
+            s->b->cur_style = QE_TERM_COMPOSITE | QE_TERM_MAKE_COLOR(fg, bg);
+            eb_insert_uchar(s->b, s->b->total_size, fg == bg ? ' ' : 0x2584);
+        }
+        s->b->cur_style = QE_STYLE_DEFAULT;
+        eb_insert_uchar(s->b, s->b->total_size, '\n');
+    }
+    s->b->flags |= BF_READONLY;
+
+    put_status(s, "Mandelbrot set x="MFT", y="MFT", zoom=%d, scale=%.6g, 
rot=%d",
+               ms->x, ms->y, ms->zoom, (double)ms->scale, ms->rot);
+}
+
+static void do_fractal_refresh(EditState *s) {
+    FractalState *ms = &fractal_state;
+    ms->cols = s->cols;
+    ms->rows = s->rows;
+    do_fractal_draw(s, ms);
+}
+
+static void do_fractal_move(EditState *s, int deltax, int deltay) {
+    FractalState *ms = &fractal_state;
+    fnum_t dx = deltax * ms->scale / 40;
+    fnum_t dy = deltay * ms->scale / 40;
+    ms->x += dx * ms->m0 + dy * ms->m1;
+    ms->y += dx * ms->m2 + dy * ms->m3;
+    do_fractal_refresh(s);
+}
+
+static void do_fractal_move_x(EditState *s, int delta) {
+    do_fractal_move(s, delta, 0);
+}
+
+static void do_fractal_move_y(EditState *s, int delta) {
+    do_fractal_move(s, 0, delta);
+}
+
+static void do_fractal_zoom(EditState *s, int delta) {
+    FractalState *ms = &fractal_state;
+    fractal_set_zoom(ms, ms->zoom + delta);
+    do_fractal_refresh(s);
+}
+
+static void do_fractal_rotate(EditState *s, int delta) {
+    FractalState *ms = &fractal_state;
+    fractal_set_rotation(ms, delta ? ms->rot + delta : 0);
+    do_fractal_refresh(s);
+}
+
+static void do_fractal_iter(EditState *s, int delta) {
+    FractalState *ms = &fractal_state;
+    ms->maxiter += delta;
+    do_fractal_refresh(s);
+}
+
+static void do_fractal_module(EditState *s, int delta) {
+    FractalState *ms = &fractal_state;
+    ms->bailout += delta;
+    do_fractal_refresh(s);
+}
+
+static void do_fractal_set_parameters(EditState *s, const char *params) {
+    FractalState *ms = &fractal_state;
+    fractal_set_parameters(s, ms, params);
+}
+
+static void do_fractal_help(EditState *s)
+{
+    FractalState *ms = &fractal_state;
+    EditBuffer *b;
+    int w = 16;
+
+    b = new_help_buffer();
+    if (!b)
+        return;
+
+    eb_printf(b, "Fractal description:\n\n");
+
+    eb_printf(b, "%*s: %s\n", w, "type", "Mandelbrot");
+    eb_printf(b, "%*s: "MFT"\n", w, "x", ms->x);
+    eb_printf(b, "%*s: "MFT"\n", w, "y", ms->y);
+    eb_printf(b, "%*s: %d\n", w, "maxiter", ms->maxiter);
+    eb_printf(b, "%*s: %d\n", w, "rot", ms->rot);
+    eb_printf(b, "%*s: %d\n", w, "zoom", ms->zoom);
+    eb_printf(b, "%*s: %.6g\n", w, "scale", (double)ms->scale);
+    eb_printf(b, "%*s: "MFT"\n", w, "bailout", ms->bailout);
+    eb_printf(b, "%*s: cb=%d nc=%d\n", w, "colors", ms->cb, ms->nc);
+
+    eb_printf(b, "\nFractal navigator:\n\n");
+
+    // XXX: should use print_bindings(b, "Fractal commands", 0, &fractal_mode);
+
+    eb_printf(b, "%*s: %s\n", w, "left, right", "move center point 
horizontally");
+    eb_printf(b, "%*s: %s\n", w, "up, down", "move center point vertically");
+    eb_printf(b, "%*s: %s\n", w, "+, SP", "zoom in");
+    eb_printf(b, "%*s: %s\n", w, "-, _", "zoom out");
+    eb_printf(b, "%*s: %s\n", w, "/", "rotate right");
+    eb_printf(b, "%*s: %s\n", w, "\\, .", "rotate left");
+    eb_printf(b, "%*s: %s\n", w, "|", "reset rotation");
+    eb_printf(b, "%*s: %s\n", w, "[, ]", "change maxiter");
+    eb_printf(b, "%*s: %s\n", w, "<, >", "change bailout");
+    eb_printf(b, "%*s: %s\n", w, "=", "set fractal parameters");
+
+    b->flags |= BF_READONLY;
+    show_popup(s, b);
+}
+
+static void fractal_display_hook(EditState *s) {
+    FractalState *ms = &fractal_state;
+    if (s->rows != ms->rows || s->cols != ms->cols)
+        do_fractal_refresh(s);
+}
+
+static CmdDef fractal_commands[] = {
+    CMD3( KEY_LEFT, KEY_NONE,
+          "fractal-left", do_fractal_move_x, ESi, -1, "v")
+    CMD3( KEY_RIGHT, KEY_NONE,
+          "fractal-right", do_fractal_move_x, ESi, +1, "v")
+    CMD3( KEY_UP, KEY_NONE,
+          "fractal-up", do_fractal_move_y, ESi, -1, "v")
+    CMD3( KEY_DOWN, KEY_NONE,
+          "fractal-down", do_fractal_move_y, ESi, +1, "v")
+    CMD3( '+', ' ',
+          "fractal-zoom-in", do_fractal_zoom, ESi, +1, "v")
+    CMD3( '-', '_',
+          "fractal-zoom-out", do_fractal_zoom, ESi, -1, "v")
+    CMD3( '\\', '.',
+          "fractal-rotate-left", do_fractal_rotate, ESi, +1, "v")
+    CMD3( '/', KEY_NONE,
+          "fractal-rotate-right", do_fractal_rotate, ESi, -1, "v")
+    CMD3( '|', KEY_NONE,
+          "fractal-rotate-none", do_fractal_rotate, ESi, 0, "v")
+    CMD3( '[', KEY_NONE,
+          "fractal-iter-less", do_fractal_iter, ESi, -1, "v")
+    CMD3( ']', KEY_NONE,
+          "fractal-iter-more", do_fractal_iter, ESi, +1, "v")
+    CMD3( '<', KEY_NONE,
+          "fractal-module-less", do_fractal_module, ESi, -1, "v")
+    CMD3( '>', KEY_NONE,
+          "fractal-module-more", do_fractal_module, ESi, +1, "v")
+    CMD2( '=', KEY_NONE,
+          "fractal-set-parameters", do_fractal_set_parameters, ESs,
+          "s{Fractal parameters: }[mparm]|mparm|")
+    CMD0( '?', KEY_F1,
+          "fractal-help", do_fractal_help)
+    CMD_DEF_END,
+};
+
+static int fractal_mode_probe(ModeDef *mode, ModeProbeData *p)
+{
+    if (p->b->default_mode == &fractal_mode)
+        return 100;
+    else
+        return 0;
+}
+
+static void do_mandelbrot_test(EditState *s) {
+    EditBuffer *b;
+    FractalState *ms = &fractal_state;
+
+    if (!fractal_mode.name) {
+        /* populate and register shell mode and commands */
+        memcpy(&fractal_mode, &text_mode, sizeof(ModeDef));
+        fractal_mode.name = "fractal";
+        fractal_mode.mode_name = NULL;
+        fractal_mode.mode_probe = fractal_mode_probe;
+        fractal_mode.default_wrap = WRAP_TRUNCATE;
+        fractal_mode.display_hook = fractal_display_hook;
+        qe_register_mode(&fractal_mode, MODEF_NOCMD | MODEF_VIEW);
+        qe_register_cmd_table(fractal_commands, &fractal_mode);
+    }
+
+    b = eb_find("*Mandelbrot*");
+    if (b) {
+        eb_clear(b);
+    } else {
+        b = eb_new("*Mandelbrot*", BF_UTF8 | BF_STYLE4);
+    }
+    if (!b)
+        return;
+
+    if (!ms->maxiter) {
+        fractal_set_parameters(s, ms, fractal_default_parameters);
+    }
+
+    b->default_mode = &fractal_mode;
+    eb_set_charset(b, &charset_ucs2be, EOL_UNIX);
+    do_delete_other_windows(s, 0);
+    switch_to_buffer(s, b);
+    do_fractal_refresh(s);
+}
+
+static CmdDef fractal_global_commands[] = {
+    CMD0( KEY_CTRLH('m'), KEY_NONE,
+          "mandelbrot-test", do_mandelbrot_test)
+    CMD_DEF_END,
+};
+
+static int fractal_init(void)
+{
+    qe_register_mode(&fractint_mode, MODEF_SYNTAX);
+    qe_register_cmd_table(fractal_global_commands, NULL);
+    return 0;
+}
+
+qe_module_init(fractal_init);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]