#include // TCGETATTR, winsize #include #include #include #include // signal, SIGWINCH #include // rand, calloc #include // va_... #include // sin, cos #include // vector #include // cout /* These aren't ansi and so won't * pass -ansi without being declared. */ //extern "C" int ioctl(int,int,...); //extern "C" void usleep(unsigned long); using namespace std; static const bool AnsiOpt = true; // Be not brainless? static const bool Colors = true; // Use colors? static const bool Trust_TabSize = true; // Assume regular tabs of 8? static const bool Use_VerticalTabs = true; // Enable VT? static const bool Trust_DefaultColors = false; // Trust white on black? static const bool Enable_LossySpeedup = true; // This decreases bandwidth // but causes mostly invisible // color errors in image static const unsigned StarCount = 2000; static class Banner { private: int linelen, pos; const unsigned char *ban; public: Banner(void) : ban((const unsigned char *) "___ . _ _ _ _ _ _ _ . _ _ _ _ _ . _ ___ _ _ _ _ _ _ _ . _ _ .___ _____ _ . . _ . _ . _ _ .___ " " | |_||(_` |_)|_)/ !/ _|_)|_||!/| |(_` / / !|_)!_/|_)|/ _|_| | (C) |(_)(_) _) |(_)(_)(_) |_)|(_`/ !| || | / |_| | | |_). // ||/| |_ | / |_)|(_`/ !| || | / !" " | | ||._) | | !!_/!_/| !| || | |._) !_!_/| | | !|!_/| | | | _) _)(_ / | _) _) _) |_)|._)!_X|/!|| | ! | | | | | . // ||!| . | | / |_)|._)!_X|/!|| | / /") { unsigned banlen; for(banlen=0; ban[banlen]; banlen++); linelen = banlen / 3; pos = -linelen; } void Update(unsigned char *&e); } Banner; static class vt100 { private: unsigned Frames; unsigned char OldAttr; unsigned char TextAttr; unsigned wx, wy; unsigned char *Field, *Color, *efi; unsigned EC, EL, EC2, EL3; public: unsigned COLS, LINES; public: void Refresh(void) { GetSize(); cout << "\33[J" "\33[?25l"; // "\33[?5h"; OldAttr = 255; SetAttr(7); if(efi) { free(efi); efi=NULL; } if(Color) { free(Color); Color=NULL; } } inline void PSet(const float x, const float y, const unsigned char c) { register int X = int(x*(EC2)); register int Y = int(y*(EL3)); SetP(X, Y, c); } void Line(const float X1, const float Y1, const float X2, const float Y2, const unsigned char c=0) { int x1,y1, x2,y2; x1=int(X1*(EC2)); x2=int(X2*(EC2)); y1=int(Y1*(EL3)); y2=int(Y2*(EL3)); unsigned NumPixels, i; unsigned DeltaX, DeltaY; int d, dinc1, dinc2; int x, xinc1, xinc2; int y, yinc1, yinc2; /* Calculate DeltaX and DeltaY for init */ DeltaX = abs(x2 - x1); DeltaY = abs(y2 - y1); /* Initialize all vars based on which is the independent variable k1 */ if(DeltaX >= DeltaY) { /* x is independent variable */ NumPixels = DeltaX + 1; d = DeltaY * 2 - DeltaX; dinc1 = DeltaY * 2; dinc2 = ((int)DeltaY - (int)DeltaX) * 2; yinc1 = 0, xinc1 = xinc2 = yinc2 = 1; } else { /* y is independent variable */ NumPixels = DeltaY + 1; d = DeltaX * 2 - DeltaY; dinc1 = DeltaX * 2; dinc2 = ((int)DeltaX - (int)DeltaY) * 2; xinc1 = 0, yinc1 = yinc2 = xinc2 = 1; } /* Make sure x and y move in the right directions */ if(x1 > x2) {xinc1 = -xinc1; xinc2 = -xinc2;} if(y1 > y2) {yinc1 = -yinc1; yinc2 = -yinc2;} /* Start drawing at */ x = x1; y = y1; /* Draw the pixels */ for(i=1; i oldy)cout << "\33[" << newy-oldy << 'B'; return; } if(newy == oldy) { /***/if(newx == oldx+1)cout << "\33[C"; else if(newx == oldx-2)cout << "\b\b"; else if(newx == oldx-3)cout << "\b\b\b"; else if(newx < oldx)cout << "\33[" << oldx-newx << 'D'; else if(newx > oldx)cout << "\33[" << newx-oldx << 'C'; return; } #if 0 if(newx==(oldx&~7)+7 && newx/?" "r}/P" /* e */ ".::="",\\?@[\]^_{|}~ */ if(efi) { unsigned char *E = efi; Banner.Update(E); #define buf 3 unsigned char C; for(C=0; C<3; C++) { unsigned char *e = E; unsigned x, y; const unsigned char *s=Field, *c=Color; SetAttr("\6\1\11"[C]); for(y=3; y0 unsigned edch[buf], last=buf; #endif for(x=0; x0 if(Enable_LossySpeedup && *c != C) { last = buf; continue; } #endif unsigned ch = Buf[ s[0] | (s[EC]<<2) | (s[EC2]<<4)]; #if buf>0 if(!Enable_LossySpeedup && *c != C) goto Diff; #endif if(*e != ch) { #if buf if(last < buf) { unsigned i, k; for(i=k=last; i; i--) AddCh(e[-i] = edch[--k]); } else #endif Goto(x, y); #if buf last=0; #endif AddCh(*e = ch); } #if buf>0 else { Diff: #if buf>1 for(unsigned i=buf-1; i; i--) edch[i] = edch[i-1]; #endif edch[0] = ch; last++; } #endif } } if(!Colors)break; } #undef buf } } free(Field); Flush(); } private: inline void SetP(const int x, const int y, const unsigned char c) { if(x<0||y<0)return; unsigned X=x, Y=y; if(X >= EC2 || Y >= EL3-9)return; unsigned y3 = (unsigned)y / 3; unsigned x2 = (unsigned)x / 2; Field[EC * Y + x2] |= 1 << (X&1); Color[EC * y3 + x2] = c; } void FlushSetAttr(void) { if(TextAttr == OldAttr)return; if(Colors) { cout << "\33["; if(TextAttr != 7 || !Trust_DefaultColors) { static const char Swap[] = "04261537"; if(AnsiOpt) { bool pp = false; if((OldAttr&0x80) > (TextAttr&0x80) || (OldAttr&0x08) > (TextAttr&0x08)) { cout << '0'; pp = true; OldAttr = (TextAttr&0x77) ^ 0x77; } if((TextAttr&0x08) && !(OldAttr&0x08)){if(pp)cout<<';';cout<<'1';pp=true;} if((TextAttr&0x80) && !(OldAttr&0x80)){if(pp)cout<<';';cout<<'5';pp=true;} if((TextAttr&0x70) != (OldAttr&0x70)) { if(pp)cout << ';'; cout << '4' << Swap[(TextAttr>>4)&7]; pp = true; } if((TextAttr&7) != (OldAttr&7)) { if(pp)cout << ';'; cout << '3' << Swap[TextAttr&7]; } } else { cout << '0'; if(TextAttr&0x08)cout << ";1"; if(TextAttr&0x80)cout << ";5"; cout << ";4" << Swap[(TextAttr>>4)&7] << ";3" << Swap[TextAttr&7]; } } cout << 'm'; } OldAttr = TextAttr; } void GetSize(void) { struct winsize ws; LINES = COLS = 0; if(ioctl(1, TIOCGWINSZ, &ws) >= 0) { LINES = ws.ws_row; COLS = ws.ws_col; } if(!LINES || !COLS)LINES=24, COLS=80; wx=wy=0; cout << "\33[H"; } } vt100; void Banner::Update(unsigned char *&e) { unsigned x, y; #define buf 2 vt100 = 3; for(y=0; y<3; y++) { int nx; #if buf>0 unsigned char edch[buf]; unsigned last = buf; #endif for(nx=pos, x=0; x=0 && nx0 if(last < buf) { unsigned i, k; for(i=k=last; i; i--) vt100 += (e[-i] = edch[--k]); } else #endif vt100.Goto(x, y); #if buf>0 last = 0; #endif vt100 += (*e = ch); } #if buf>0 else { #if buf>1 for(unsigned i=buf-1; i; i--)edch[i] = edch[i-1]; #endif edch[0] = ch; last++; } #endif } } if(++pos >= linelen) pos = -(int)vt100.width(); #undef buf } class Matrix { private: typedef float matx[4][4]; matx dah; public: Matrix(const float ax, const float ay, const float az) { matx m[3]; register int i, j; memset(&m, 0, sizeof(m)); m[0][1][1]=m[0][2][2]=cos(ax); m[0][2][1]=-(m[0][1][2]=sin(ax)); m[1][0][0]=m[1][2][2]=cos(ay); m[1][0][2]=-(m[1][2][0]=sin(ay)); m[2][0][0]=m[2][1][1]=cos(az); m[2][1][0]=-(m[2][0][1]=sin(az)); m[0][0][0] = m[0][3][3] = 1; m[1][1][1] = m[1][3][3] = 1; m[2][2][2] = m[2][3][3] = 1; for(i=0; i<4; i++) { float m2[4]; for(j=0; j<4; j++) m2[j] = m[1][i][0] * m[0][0][j] + m[1][i][1] * m[0][1][j] + m[1][i][2] * m[0][2][j] + m[1][i][3] * m[0][3][j]; for(j=0; j<4; j++) dah[i][j] = m2[0] * m[2][0][j] + m2[1] * m[2][1][j] + m2[2] * m[2][2][j] + m2[3] * m[2][3][j]; } } void RotatePoint(float &x, float &y, float &z) const { register float tx = x*dah[0][0] + y*dah[1][0] + z*dah[2][0] + dah[3][0]; register float ty = x*dah[0][1] + y*dah[1][1] + z*dah[2][1] + dah[3][1]; z = x*dah[0][2] + y*dah[1][2] + z*dah[2][2] + dah[3][2]; y = ty; x = tx; } }; class line { float x1,y1,z1, x2,y2,z2; int isline; unsigned char color; public: line(const float X1, const float Y1, const float Z1, const float X2, const float Y2, const float Z2) : isline(1) { x1 = (X1/31 - 0.5) * 20; y1 = (Y1/11 - 0.5) * 20; z1 = Z1; x2 = (X2/31 - 0.5) * 20; y2 = (Y2/11 - 0.5) * 20; z2 = Z2; } line(const float x, const float y, const float z, unsigned char c) : x1(x),y1(y),z1(z),isline(0), color(c) { if(!Colors)color=0; } void Draw(const float cx, const float cy, const float cz, const Matrix &m) const { if(isline) { float X1=x1, Y1=y1, Z1=z1; float X2=x2, Y2=y2, Z2=z2; m.RotatePoint(X1,Y1,Z1); m.RotatePoint(X2,Y2,Z2); X1-=cx; Y1-=cy; Z1-=cz; X2-=cx; Y2-=cy; Z2-=cz; if(Z1 > 0 && Z2 > 0) vt100.Line(0.5+X1/Z1, 0.5+Y1/Z1, 0.5+X2/Z2, 0.5+Y2/Z2); } else { float x = x1, y = y1, z = z1; m.RotatePoint(x,y,z); x-=cx, y-=cy, z-=cz; if(z > 0) vt100.PSet(0.5+x/z, 0.5+y/z, color); } } }; static class World { private: vector lines; public: void Insert(const line *Line) { lines.insert(lines.end(), Line); } void operator += (const line *Line) { Insert(Line); } void AddPoly(const int pax, const int x, const int y, ...) { va_list ap; va_start(ap, y); float x1=x/10.0, y1=y/10.0; float z1=pax/100.0; float z2=-z1; for(;;) { int X = va_arg(ap, int); int Y = va_arg(ap, int); float x2 = X / 10.0; float y2 = Y / 10.0; Insert(new line(x1,y1, z1, x2,y2, z1)); if(pax) { Insert(new line(x1,y1, z2, x2,y2, z2)); Insert(new line(x1,y1, z1, x1,y1, z2)); Insert(new line(x2,y2, z1, x2,y2, z2)); } if(X==x && Y==y)break; x1=x2, y1=y2; } va_end(ap); } void Draw(const float cx, const float cy, const float cz, const Matrix &m) const { unsigned i, c = lines.size(); for(i=0; iDraw(cx,cy,cz, m); } } World; static int Quitti=0; static void Term(int dummy) { dummy=dummy; Quitti++; } static void Refresh(int dummy) { dummy=dummy; vt100.Refresh(); } int main(int argc, char **argv) { unsigned i; for(i=0; --argc; i++) *(i?&vt100.LINES:&vt100.COLS) = atoi(*++argv); for(i=0; i