picolisp

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/picolisp.git/
Log | Files | Refs | README | LICENSE

z3d.l (19454B)


      1 # 13apr13abu
      2 # (c) Software Lab. Alexander Burger
      3 
      4 (load "@lib/native.l")
      5 
      6 ### Z-Buffer 3D library ###
      7 (gcc "rcsim" '("-L/usr/X11R6/lib" "-lXext" "-lX11")
      8    (z3dX (M X) z3dX NIL M (cons X 1.0))
      9    (z3dY (M Y) z3dY NIL M (cons Y 1.0))
     10    (z3dZ (M Z) z3dZ NIL M (cons Z 1.0))
     11    (z3dDX (M DX) z3dDX NIL M (cons DX 1.0))
     12    (z3dDY (M DY) z3dDY NIL M (cons DY 1.0))
     13    (z3dDZ (M DZ) z3dDZ NIL M (cons DZ 1.0))
     14    (z3dXrot (M A) z3dXrot NIL M (cons A 1.0))
     15    (z3dYrot (M A) z3dYrot NIL M (cons A 1.0))
     16    (z3dZrot (M A) z3dZrot NIL M (cons A 1.0))
     17    (z3dArot (M A) z3dArot NIL M (cons A 1.0))
     18    (z3dRotate (M X Y Z VarX VarY VarZ Flg) z3dRotate NIL
     19       M
     20       (cons X 1.0)
     21       (cons Y 1.0)
     22       (cons Z 1.0)
     23       (if VarX (list @ (8 . 1.0)) 0)
     24       (if VarY (list @ (8 . 1.0)) 0)
     25       (if VarZ (list @ (8 . 1.0)) 0)
     26       (if Flg 1 0) )
     27    (z3dSpot (VarX VarY X Y Z) z3dSpot NIL
     28       (list VarX (8 . 1.0))
     29       (list VarY (8 . 1.0))
     30       (cons X 1.0)
     31       (cons Y 1.0)
     32       (cons Z 1.0) )
     33    (z3dWindow (Ttl DX DY) z3dWindow 'S Ttl DX DY)
     34    (z3dCamera (Foc Yaw Pitch X Y Z Sky Gnd) z3dCamera NIL
     35       (cons Foc 1.0)
     36       (cons Yaw 1.0)
     37       (cons Pitch 1.0)
     38       (cons X 1.0)
     39       (cons Y 1.0)
     40       (cons Z 1.0)
     41       Sky
     42       Gnd )
     43    (z3dDraw (M) z3dDraw NIL M)
     44    (z3dPut () z3dPut)
     45    (z3dText (X Y S) z3dText NIL X Y S)
     46    (z3dSync () z3dSync) )
     47 
     48 #include <stdint.h>
     49 #include <stdlib.h>
     50 #include <unistd.h>
     51 #include <string.h>
     52 #include <math.h>
     53 
     54 #include <X11/Xlib.h>
     55 #include <X11/Xutil.h>
     56 #include <sys/shm.h>
     57 #include <X11/extensions/XShm.h>
     58 
     59 #define SCL 1000000.0
     60 
     61 typedef struct {double x, y, z;} vector;
     62 typedef struct {vector a, b, c;} matrix;
     63 
     64 typedef struct face {
     65    int col1, col2;                     // Foreground and background color
     66    int cnt, _x_;                       // Number of points
     67    vector pt[1];                       // Points
     68 } face;
     69 
     70 typedef struct model {
     71    vector pos;                         // Position
     72    matrix rot;                         // Orientation
     73    void *lst[1];                       // List of faces and submodels
     74 } model;
     75 
     76 typedef struct {
     77    int h[2];                           // Horizontal
     78    unsigned z[2];                      // Depth
     79 } edge;
     80 
     81 static double FocLen, PosX, PosY, PosZ, Pos6, Pos9;
     82 static double Coeff1, Coeff2, Coeff4, Coeff5, Coeff6, Coeff7, Coeff8, Coeff9;
     83 
     84 static Display *Disp;
     85 static int Scrn;
     86 static Colormap Cmap;
     87 static int Dpth;
     88 static int PixSize;
     89 static GC Gc;
     90 static Window Win;
     91 
     92 static int SizX, SizY, OrgX, OrgY;
     93 static unsigned *Zbuff;
     94 static edge *Edges;
     95 static XImage *Img;
     96 static XShmSegmentInfo Info;
     97 
     98 // (z3dX 'model 'x)
     99 void z3dX(model *p, double x) {
    100    p->pos.x = x;
    101 }
    102 
    103 // (z3dY 'model 'y)
    104 void z3dY(model *p, double y) {
    105    p->pos.y = y;
    106 }
    107 
    108 // (z3dZ 'model 'z)
    109 void z3dZ(model *p, double z) {
    110    p->pos.z = z;
    111 }
    112 
    113 // (z3dDX 'model 'dx)
    114 void z3dDX(model *p, double dx) {
    115    p->pos.x += dx;
    116 }
    117 
    118 // (z3dDY 'model 'dy)
    119 void z3dDY(model *p, double dy) {
    120    p->pos.y += dy;
    121 }
    122 
    123 // (z3dDZ 'model 'dz)
    124 void z3dDZ(model *p, double dz) {
    125    p->pos.z += dz;
    126 }
    127 
    128 static void xrot(matrix *p, double ca, double sa) {
    129    matrix m = *p;
    130 
    131    p->b.x = ca * m.b.x - sa * m.c.x;
    132    p->b.y = ca * m.b.y - sa * m.c.y;
    133    p->b.z = ca * m.b.z - sa * m.c.z;
    134    p->c.x = sa * m.b.x + ca * m.c.x;
    135    p->c.y = sa * m.b.y + ca * m.c.y;
    136    p->c.z = sa * m.b.z + ca * m.c.z;
    137 }
    138 
    139 static void yrot(matrix *p, double ca, double sa) {
    140    matrix m = *p;
    141 
    142    p->a.x = ca * m.a.x + sa * m.c.x;
    143    p->a.y = ca * m.a.y + sa * m.c.y;
    144    p->a.z = ca * m.a.z + sa * m.c.z;
    145    p->c.x = ca * m.c.x - sa * m.a.x;
    146    p->c.y = ca * m.c.y - sa * m.a.y;
    147    p->c.z = ca * m.c.z - sa * m.a.z;
    148 }
    149 
    150 static void zrot(matrix *p, double ca, double sa) {
    151    matrix m = *p;
    152 
    153    p->a.x = ca * m.a.x + sa * m.b.x;
    154    p->a.y = ca * m.a.y + sa * m.b.y;
    155    p->a.z = ca * m.a.z + sa * m.b.z;
    156    p->b.x = ca * m.b.x - sa * m.a.x;
    157    p->b.y = ca * m.b.y - sa * m.a.y;
    158    p->b.z = ca * m.b.z - sa * m.a.z;
    159 }
    160 
    161 // (z3dXrot 'model 'angle)
    162 void z3dXrot(model *p, double a) {
    163    xrot(&p->rot, cos(a), sin(a));
    164 }
    165 
    166 // (z3dYrot 'model 'angle)
    167 void z3dYrot(model *p, double a) {
    168    yrot(&p->rot, cos(a), sin(a));
    169 }
    170 
    171 // (z3dZrot 'model 'angle)
    172 void z3dZrot(model *p, double a) {
    173    zrot(&p->rot, cos(a), sin(a));
    174 }
    175 
    176 // (z3dArot 'model 'angle)
    177 void z3dArot(model *p, double a) {
    178    double n;
    179    vector *v;
    180 
    181    v = ((face*)p->lst[0])->pt;
    182    n = sqrt(v->x * v->x + v->y * v->y + v->z * v->z);
    183    v->x /= n,  v->y /= n,  v->z /= n;  // Axis unit vector
    184    if ((n = sqrt(v->y * v->y + v->z * v->z)) < 1.0/SCL)  // Axis parallel to x-axis
    185       a *= v->x,  xrot(&p->rot, cos(a), sin(a));
    186    else {
    187       xrot(&p->rot, v->z / n, -v->y / n);
    188       yrot(&p->rot, n, v->x);
    189       zrot(&p->rot, cos(a), sin(a));
    190       yrot(&p->rot, n, -v->x);
    191       xrot(&p->rot, v->z / n, v->y / n);
    192    }
    193 }
    194 
    195 // (z3dRotate 'model 'X 'Y 'Z 'varX 'varY 'varZ ['flg])
    196 void z3dRotate(model *p, double vx, double vy, double vz,
    197                               double *xp, double *yp, double *zp, int flg) {
    198    if (!flg) {
    199       if (xp)
    200          *xp = vx * p->rot.a.x + vy * p->rot.b.x + vz * p->rot.c.x;
    201       if (yp)
    202          *yp = vx * p->rot.a.y + vy * p->rot.b.y + vz * p->rot.c.y;
    203       if (zp)
    204          *zp = vx * p->rot.a.z + vy * p->rot.b.z + vz * p->rot.c.z;
    205    }
    206    else {
    207       if (xp)
    208          *xp = vx * p->rot.a.x + vy * p->rot.a.y + vz * p->rot.a.z;
    209       if (yp)
    210          *yp = vx * p->rot.b.x + vy * p->rot.b.y + vz * p->rot.b.z;
    211       if (zp)
    212          *zp = vx * p->rot.c.x + vy * p->rot.c.y + vz * p->rot.c.z;
    213    }
    214 }
    215 
    216 // (z3dSpot 'varX 'varY 'dx 'dy 'dz)
    217 void z3dSpot(double *xp, double *yp, double dx, double dy, double dz) {
    218    double d = sqrt(dx*dx + dy*dy + dz*dz);
    219 
    220    *xp = atan2(dy,dx);
    221    *yp = d < 1.0/SCL? 0.0 : asin(dz/d);
    222 }
    223 
    224 // (z3dWindow 'ttl 'dx 'dy) -> str
    225 char *z3dWindow(char *ttl, int dx, int dy) {
    226    XPixmapFormatValues *pmFormat;
    227    int n, i;
    228 
    229    if ((Disp = XOpenDisplay(NULL)) == NULL)
    230       return "Can't open Display";
    231    Scrn = DefaultScreen(Disp);
    232    Cmap = DefaultColormap(Disp,Scrn);
    233    Dpth = PixSize = 0;
    234    pmFormat = XListPixmapFormats(Disp, &n);
    235    for (i = 0; i < n; i++) {
    236       if (pmFormat[i].depth == 24) {
    237          Dpth = 24;
    238          if (PixSize != 4)
    239             PixSize = (pmFormat[i].bits_per_pixel + 7) / 8 & ~8;
    240       }
    241       else if (pmFormat[i].depth == 16 && (PixSize < 3 || PixSize > 4)) {
    242          Dpth = 16;
    243          PixSize = (pmFormat[i].bits_per_pixel + 7) / 8 & ~8;
    244       }
    245       else if (pmFormat[i].depth == 8 && (PixSize < 2 || PixSize > 4)) {
    246          Dpth = 8;
    247          PixSize = (pmFormat[i].bits_per_pixel + 7) / 8 & ~8;
    248       }
    249    }
    250    if (!Dpth)
    251       return "Bad Display Depth";
    252    Gc = XCreateGC(Disp,RootWindow(Disp,Scrn), 0, NULL);
    253 
    254    OrgX = (SizX = dx) / 2;
    255    OrgY = (SizY = dy) / 2;
    256 
    257    /* Create Window */
    258    Win = XCreateSimpleWindow(Disp, RootWindow(Disp,Scrn), 0, 0, SizX, SizY,
    259                         1, BlackPixel(Disp,Scrn), WhitePixel(Disp,Scrn) );
    260    XStoreName(Disp, Win, ttl);
    261    XMapWindow(Disp, Win);
    262 
    263    /* Create Image */
    264    SizX = SizX + 3 & ~3;
    265    SizY = SizY + 3 & ~3;
    266    if ((Zbuff = malloc(SizX * SizY * sizeof(unsigned))) == NULL  ||
    267          (Edges = malloc(SizY * sizeof(edge))) == NULL )
    268       return "No memory";
    269    if (!XShmQueryExtension(Disp)  ||
    270          !(Img = XShmCreateImage(Disp, DefaultVisual(Disp, Scrn),
    271                   Dpth, ZPixmap, NULL, &Info, SizX, SizY ))  ||
    272          (Info.shmid = shmget(IPC_PRIVATE,
    273                   SizX * SizY * PixSize, IPC_CREAT | 0777 )) < 0  ||
    274          (Info.shmaddr = Img->data =
    275                            shmat(Info.shmid, 0, 0) ) == (char*)-1  ||
    276          !XShmAttach(Disp, &Info) )
    277       return "Can't create XImage";
    278    return NULL;
    279 }
    280 
    281 // (z3dCamera 'foc 'yaw 'pitch 'x 'y 'z 'sky 'gnd ['h 'v])
    282 void z3dCamera(double foc, double yaw, double pitch,
    283                            double x, double y, double z, int sky, int gnd) {
    284    double a, sinY, cosY, sinP, cosP;
    285    int i, v, hor, pix;
    286    char *frame;
    287 
    288    FocLen = foc;
    289 
    290    sinY = sin(yaw),  cosY = cos(yaw);
    291    sinP = sin(pitch),  cosP = cos(pitch);
    292    Coeff1 = -sinY;
    293    Coeff2 = cosY;
    294    Coeff4 = cosY * sinP;
    295    Coeff5 = sinY * sinP;
    296    Coeff6 = -cosP;
    297    Coeff7 = cosY * cosP;
    298    Coeff8 = sinY * cosP;
    299    Coeff9 = sinP;
    300 
    301    PosX = x;
    302    PosY = y;
    303    PosZ = z;
    304    Pos6 = Coeff6 * PosZ;
    305    Pos9 = Coeff9 * PosZ;
    306 
    307    if (cosP > - 1.0/SCL  &&  cosP < 1.0/SCL)
    308       hor = sinP > 0.0? +16383 : -16384;
    309    else if ((a = FocLen * sinP/cosP) > +16383.0)
    310       hor = +16383;
    311    else if (a < -16384.0)
    312       hor = -16384;
    313    else
    314       hor = (int)a;
    315 
    316    for (v = 0; v < SizY; ++v) {
    317       pix  =  v < hor? sky : gnd;
    318       frame = Img->data + v * SizX * PixSize;
    319       switch (PixSize) {
    320       case 1:
    321          memset(frame, pix, SizX);
    322          break;
    323       case 2:
    324          pix |= pix<<16;
    325          i = 0;
    326          do
    327             *(int*)frame = pix,  frame += 4;
    328          while ((i+=2) < SizX);
    329          break;
    330       case 3:
    331          i = 0;
    332          do {
    333             frame[0] = pix;
    334             frame[1] = (pix >> 8);
    335             frame[2] = (pix >> 16);
    336             frame += 3;
    337          } while (++i < SizX);
    338          break;
    339       case 4:
    340          i = 0;
    341          do
    342             *(int*)frame = pix,  frame += 4;
    343          while (++i < SizX);
    344          break;
    345       }
    346    }
    347    memset(Zbuff, 0xFF, SizX * SizY * sizeof(unsigned));
    348 }
    349 
    350 static void rotate(vector *src, matrix *p, vector *dst) {
    351    dst->x = src->x * p->a.x + src->y * p->b.x + src->z * p->c.x;
    352    dst->y = src->x * p->a.y + src->y * p->b.y + src->z * p->c.y;
    353    dst->z = src->x * p->a.z + src->y * p->b.z + src->z * p->c.z;
    354 }
    355 
    356 static void shadowPt(double vx, double vy, int *xp, int *yp, int *zp) {
    357    double z;
    358 
    359    z = Coeff7 * vx + Coeff8 * vy - Pos9;
    360    *xp = (int)(FocLen * (Coeff1 * vx + Coeff2 * vy) / z);
    361    *yp = (int)(FocLen * (Coeff4 * vx + Coeff5 * vy - Pos6) / z);
    362    *zp = (int)(1000.0 * z);
    363 }
    364 
    365 static void transPt(double vx, double vy, double vz, int *xp, int *yp, int *zp) {
    366    double z;
    367 
    368    z = Coeff7 * vx + Coeff8 * vy + Coeff9 * vz;
    369    *xp = (int)(FocLen * (Coeff1 * vx + Coeff2 * vy) / z);
    370    *yp = (int)(FocLen * (Coeff4 * vx + Coeff5 * vy + Coeff6 * vz) / z);
    371    *zp = (int)(1000.0 * z);
    372 }
    373 
    374 static int getColor(int c) {
    375    XColor col;
    376 
    377    col.red   = c >> 8  &  0xFF00;
    378    col.green = c & 0xFF00;
    379    col.blue  = (c & 0xFF) << 8;
    380    col.flags = DoRed | DoGreen | DoBlue;
    381    XAllocColor(Disp, Cmap, &col);
    382    return col.pixel;
    383 }
    384 
    385 static void mkEdge(int x1, int y1, int z1, int x2, int y2, int z2) {
    386    int a, dx, dy, dz, sx, xd, xe, sz, zd, ze;
    387    edge *p;
    388 
    389    if (y2 < y1) {
    390       a = x1,  x1 = x2,  x2 = a;
    391       a = y1,  y1 = y2,  y2 = a;
    392       a = z1,  z1 = z2,  z2 = a;
    393    }
    394    if (y1 > OrgY  ||  ((y2 += OrgY) <= 0))
    395       return;
    396    if ((dy  =  y2 - (y1 += OrgY)) == 0)
    397       return;
    398    dx = x2 - x1,  dz = z2 - z1;
    399    if (y1 < 0) {
    400       x1 += -y1 * dx / dy;
    401       z1 += -y1 * dz / dy;
    402       y1 = 0;
    403       if ((dy = y2) == 0)
    404          return;
    405       dx = x2 - x1,  dz = z2 - z1;
    406    }
    407    if (y2 > SizY) {
    408       x2 += (SizY - y2) * dx / dy;
    409       z2 += (SizY - y2) * dz / dy;
    410       y2 = SizY;
    411       if ((dy = y2 - y1) == 0)
    412          return;
    413       dx = x2 - x1,  dz = z2 - z1;
    414    }
    415    sx = 0;
    416    if (dx > 0)
    417       sx = 1;
    418    else if (dx < 0)
    419       dx = -dx,  sx = -1;
    420    xd = 0;
    421    if (dx > dy)
    422       xd = dx/dy,  dx -= xd*dy,  xd *= sx;
    423    xe = (dx *= 2) - dy;
    424    sz = 0;
    425    if (dz > 0)
    426       sz = 1;
    427    else if (dz < 0)
    428       dz = -dz,  sz = -1;
    429    zd = 0;
    430    if (dz > dy)
    431       zd = dz/dy,  dz -= zd*dy,  zd *= sz;
    432    ze = (dz *= 2) - dy;
    433    dy *= 2;
    434    x1 += OrgX;
    435    p = Edges + y1;
    436    do {
    437       if ((a = x1) < 0)
    438          a = 0;
    439       else if (a > SizX)
    440          a = SizX;
    441       if (a < p->h[1]) {
    442          p->h[0] = a;
    443          p->z[0] = z1;
    444       }
    445       else {
    446          p->h[0] = p->h[1];
    447          p->z[0] = p->z[1];
    448          p->h[1] = a;
    449          p->z[1] = z1;
    450       }
    451       ++p;
    452       x1 += xd;
    453       if (xe >= 0)
    454          x1 += sx,  xe -= dy;
    455       xe += dx;
    456       z1 += zd;
    457       if (ze >= 0)
    458          z1 += sz,  ze -= dy;
    459       ze += dz;
    460    } while (++y1 < y2);
    461 }
    462 
    463 static void zDots(int i, int h, int h2, unsigned z, unsigned z2) {
    464    char *frame;
    465    unsigned *zbuff;
    466 
    467    i = i * SizX + h;
    468    frame = Img->data + i * PixSize;
    469    zbuff = Zbuff + i;
    470    i = h2 - h;
    471    switch (PixSize) {
    472    case 1:
    473       if (z < *zbuff)
    474          *zbuff = z,  *frame = 0;
    475       if (z2 < *(zbuff += i))
    476          *zbuff = z2,  *(frame + i) = 0;
    477       break;
    478    case 2:
    479       if (z < *zbuff)
    480          *zbuff = z,  *(short*)frame = (short)0;
    481       if (z2 < *(zbuff += i))
    482          *zbuff = z2,  *(short*)(frame + 2 * i) = (short)0;
    483       break;
    484    case 3:
    485       if (z < *zbuff) {
    486          *zbuff = z;
    487          frame[0] = 0;
    488          frame[1] = 0;
    489          frame[2] = 0;
    490       }
    491       if (z2 < *(zbuff += i)) {
    492          *zbuff = z2;
    493          frame += 3 * i;
    494          frame[0] = 0;
    495          frame[1] = 0;
    496          frame[2] = 0;
    497       }
    498       break;
    499    case 4:
    500       if (z < *zbuff)
    501          *zbuff = z,  *(int*)frame = 0;
    502       if (z2 < *(zbuff += i))
    503          *zbuff = z2,  *(int*)(frame + 4 * i) = 0;
    504       break;
    505    }
    506 }
    507 
    508 static void zLine(int pix, int v, int h, int h2, unsigned z, unsigned z2) {
    509    char *frame;
    510    unsigned *zbuff;
    511    int d, e, dh, dz, sz;
    512 
    513    if (dh = h2 - h) {
    514       v = v * SizX + h;
    515       frame = Img->data + v * PixSize;
    516       zbuff = Zbuff + v;
    517       sz = 0;
    518       if ((dz = z2 - z) > 0)
    519          sz = 1;
    520       else if (dz < 0)
    521          dz = -dz,  sz = -1;
    522       d = 0;
    523       if (dz > dh)
    524          d = dz/dh,  dz -= d*dh,  d *= sz;
    525       e = (dz *= 2) - dh;
    526       dh *= 2;
    527       switch (PixSize) {
    528       case 1:
    529          do {
    530             if (z < *zbuff)
    531                *zbuff = z,  *frame = pix;
    532             z += d;
    533             if (e >= 0)
    534                z += sz,  e -= dh;
    535             ++zbuff,  ++frame;
    536             e += dz;
    537          } while (++h < h2);
    538          break;
    539       case 2:
    540          do {
    541             if (z < *zbuff)
    542                *zbuff = z,  *(short*)frame = (short)pix;
    543             z += d;
    544             if (e >= 0)
    545                z += sz,  e -= dh;
    546             ++zbuff,  frame += 2;
    547             e += dz;
    548          } while (++h < h2);
    549          break;
    550       case 3:
    551          do {
    552             if (z < *zbuff) {
    553                *zbuff = z;
    554                frame[0] = pix;
    555                frame[1] = (pix >> 8);
    556                frame[2] = (pix >> 16);
    557             }
    558             z += d;
    559             if (e >= 0)
    560                z += sz,  e -= dh;
    561             ++zbuff,  frame += 3;
    562             e += dz;
    563          } while (++h < h2);
    564          break;
    565       case 4:
    566          do {
    567             if (z < *zbuff)
    568                *zbuff = z,  *(int*)frame = pix;
    569             z += d;
    570             if (e >= 0)
    571                z += sz,  e -= dh;
    572             ++zbuff,  frame += 4;
    573             e += dz;
    574          } while (++h < h2);
    575          break;
    576       }
    577    }
    578 }
    579 
    580 static void doDraw(model *p, matrix *r, double x, double y, double z) {
    581    int i, n, pix, x0, y0, z0, x1, y1, z1, x2, y2, z2;
    582    double dx, dy, dz;
    583    vector pos, pt1, pt2, pt3, v, w, nv;
    584    matrix rot;
    585    void **q;
    586    edge *e;
    587 
    588    pos = p->pos;
    589    rot = p->rot;
    590    if (!r)
    591       r = &rot;
    592    else {
    593       v = pos,  rotate(&v, r, &pos);
    594       pos.x += x,  pos.y += y,  pos.z += z;
    595       v = rot.a,  rotate(&v, r, &rot.a);
    596       v = rot.b,  rotate(&v, r, &rot.b);
    597       v = rot.c,  rotate(&v, r, &rot.c);
    598    }
    599    dx = pos.x - PosX;
    600    dy = pos.y - PosY;
    601    dz = pos.z - PosZ;
    602    /* Rough clipping */
    603    if ((z = Coeff7*dx + Coeff8*dy + Coeff9*dz) < 0.1)
    604       return;
    605    if (z < fabs(Coeff1*dx + Coeff2*dy))
    606       return;
    607    if (z < fabs(Coeff4*dx + Coeff5*dy + Coeff6*dz))
    608       return;
    609    /* Faces */
    610    for (q = p->lst; *(face**)q; ++q) {
    611       face *f = *(face**)q;
    612 
    613       if ((f->pt[0].x || f->pt[0].y || f->pt[0].z) && (f->pt[1].x || f->pt[1].y || f->pt[1].z))
    614          r = &rot,  rotate(f->pt, r, &pt1),  rotate(f->pt + 1, r, &pt2);
    615       else
    616          rotate(f->pt, r, &pt1),  rotate(f->pt + 1, r, &pt2),  r = &rot;
    617       rotate(f->pt + 2, r, &pt3);
    618       memset(Edges, 0, SizY * sizeof(edge));
    619       if (f->col2 == 0x2000000) {
    620          shadowPt(pt1.x + dx + pt1.z + pos.z, pt1.y + dy, &x0, &y0, &z0);
    621          shadowPt(pt2.x + dx + pt2.z + pos.z, pt2.y + dy, &x1, &y1, &z1);
    622          mkEdge(x0, y0, z0, x1, y1, z1);
    623          for (i = 2;;) {
    624             shadowPt(pt3.x + dx + pt3.z + pos.z, pt3.y + dy, &x2, &y2, &z2);
    625             mkEdge(x1, y1, z1, x2, y2, z2);
    626             if (++i == f->cnt)
    627                break;
    628             rotate(f->pt + i, r, &pt3);
    629             x1 = x2,  y1 = y2,  z1 = z2;
    630          }
    631          mkEdge(x2, y2, z2, x0, y0, z0);
    632          i = 0,  e = Edges;
    633          pix = getColor(0);  // Face color black
    634          do
    635             if (e->h[1])
    636                zLine(pix, i, e->h[0], e->h[1], e->z[0], e->z[1]);
    637          while (++e, ++i < SizY);
    638       }
    639       else {
    640          v.x = pt1.x - pt2.x;
    641          v.y = pt1.y - pt2.y;
    642          v.z = pt1.z - pt2.z;
    643          w.x = pt3.x - pt2.x;
    644          w.y = pt3.y - pt2.y;
    645          w.z = pt3.z - pt2.z;
    646          nv.x = v.y * w.z - v.z * w.y;
    647          nv.y = v.z * w.x - v.x * w.z;
    648          nv.z = v.x * w.y - v.y * w.x;
    649          pt1.x += dx,  pt1.y += dy,  pt1.z += dz;
    650          if (f->col1 == 0x1000000  &&  f->col2 == 0x1000000)
    651             pix = -1;  // Transparent
    652          else {
    653             if (pt1.x * nv.x + pt1.y * nv.y + pt1.z * nv.z >= 0.0) {
    654                if (f->col1 == 0x1000000)
    655                   continue;  // Backface culling
    656                pix = f->col1;
    657                n = 80 - (int)(14.14 * (nv.z-nv.x) / sqrt(nv.x*nv.x + nv.y*nv.y + nv.z*nv.z));
    658             }
    659             else {
    660                if (f->col2 == 0x1000000)
    661                   continue;  // Backface culling
    662                pix = f->col2;
    663                n = 80 + (int)(14.14 * (nv.z-nv.x) / sqrt(nv.x*nv.x + nv.y*nv.y + nv.z*nv.z));
    664             }
    665             pix = ((pix >> 16) & 255) * n / 100 << 16  |
    666                   ((pix >> 8) & 255) * n / 100 << 8  |  (pix & 255) * n / 100;
    667          }
    668          transPt(pt1.x, pt1.y, pt1.z, &x0, &y0, &z0);
    669          transPt(pt2.x + dx, pt2.y + dy, pt2.z + dz, &x1, &y1, &z1);
    670          mkEdge(x0, y0, z0, x1, y1, z1);
    671          for (i = 2;;) {
    672             transPt(pt3.x + dx, pt3.y + dy, pt3.z + dz, &x2, &y2, &z2);
    673             mkEdge(x1, y1, z1, x2, y2, z2);
    674             if (++i == f->cnt)
    675                break;
    676             rotate(f->pt + i, r, &pt3);
    677             x1 = x2,  y1 = y2,  z1 = z2;
    678          }
    679          mkEdge(x2, y2, z2, x0, y0, z0);
    680          i = 0,  e = Edges;
    681          if (pix < 0) {
    682             do  // Transparent
    683                if (e->h[1])
    684                   zDots(i, e->h[0], e->h[1], e->z[0], e->z[1]);
    685             while (++e, ++i < SizY);
    686          }
    687          else {
    688             pix = getColor(pix);  // Face color
    689             do
    690                if (e->h[1])
    691                   zLine(pix, i, e->h[0], e->h[1], e->z[0], e->z[1]);
    692             while (++e, ++i < SizY);
    693          }
    694       }
    695    }
    696    /* Submodels */
    697    while (*(model**)++q)
    698       doDraw(*(model**)q, &rot, pos.x, pos.y, pos.z);
    699 }
    700 
    701 // (z3dDraw ['model])
    702 void z3dDraw(model *p) {
    703    doDraw(p, NULL, 0.0, 0.0, 0.0);
    704 }
    705 
    706 // (z3dPut)
    707 void z3dPut(void) {
    708    XShmPutImage(Disp, Win, Gc, Img, 0, 0, 0, 0, SizX, SizY, False);
    709 }
    710 
    711 // (z3dText 'x 'y 'str)
    712 void z3dText(int x, int y, char *str) {
    713    XDrawString(Disp, Win, Gc, x, y, str, strlen(str));
    714 }
    715 
    716 // (z3dSync)
    717 void z3dSync(void) {
    718    XSync(Disp,False);
    719 }
    720 
    721 /**/
    722 
    723 # vi:et:ts=3:sw=3