ref: 0430a5300ee18b367865bdd497d7982973abf578
author: aap <aap@papnet.eu>
date: Fri Aug 19 06:44:29 EDT 2022
first commit
--- /dev/null
+++ b/README
@@ -1,0 +1,10 @@
+A catclock based on the original box art.
+The image was vectorized in inkscape from a scan of the box,
+then converted to Plan 9 rasters for easy drawing.
+
+TODO:
+It would be nice to rasterize this at runtime and also
+rotate the tail a little bit.
+
+You can find a vector version here:
+http://aap.papnet.eu/pub/catclock.pdf
binary files /dev/null b/body.bit differ
binary files /dev/null b/eyes.bit differ
--- /dev/null
+++ b/main.c
@@ -1,0 +1,160 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <keyboard.h>
+#include <mouse.h>
+
+Mousectl *mctl;
+Keyboardctl *kctl;
+
+Image *body, *tail, *eyes;
+Point offset;
+float tailoffset = 0.0f;
+float tailspeed = 1.0f;
+float eyesoffset = 0.0f;
+float eyesspeed = 0.5f;
+
+int round(double x){
+ return x>=0.?x+.5:x-.5;
+}
+
+void
+drawhand(int length, int width, double theta)
+{
+ double c=cos(theta), s=sin(theta);
+ double ws=width*s, wc=width*c;
+ Point vhand[4];
+ vhand[0]=addpt(screen->r.min, addpt(offset, Pt(78+round(length*s), 240-round(length*c))));
+ vhand[1]=addpt(screen->r.min, addpt(offset, Pt(78-round(ws+wc), 240+round(wc-ws))));
+ vhand[2]=addpt(screen->r.min, addpt(offset, Pt(78-round(ws-wc), 240+round(wc+ws))));
+ vhand[3] = vhand[0];
+ fillpoly(screen, vhand, 4, 1, display->white,
+ addpt(screen->r.min, vhand[0]));
+ poly(screen, vhand, 4, Endsquare, Endsquare, 0, display->black,
+ addpt(screen->r.min, vhand[0]));
+}
+
+void
+drawstuff(void)
+{
+ Point p;
+ Tm tm = *localtime(time(0));
+
+ draw(screen, screen->r, display->white, nil, ZP);
+ p.x = -(offset.x + tailoffset);
+ p.y = -offset.y;
+ draw(screen, screen->r, tail, nil, p);
+ p.x = -offset.x;
+ p.y = -offset.y;
+ draw(screen, screen->r, body, nil, p);
+ p.x = -(offset.x + eyesoffset);
+ draw(screen, screen->r, eyes, nil, p);
+
+ drawhand(50, 6, 2.*PI*tm.min/60.);
+ drawhand(30, 6, 2.*PI*(tm.hour+tm.min/60.)/12.);
+ flushimage(display, 1);
+}
+
+void
+kbthread(void *arg)
+{
+ Keyboardctl *kc = arg;
+ Rune r;
+
+ for(;;){
+ recv(kc->c, &r);
+ switch(r){
+ case Kdel:
+ case Kesc:
+ case 'q':
+ threadexitsall(nil);
+ }
+ drawstuff();
+ }
+}
+
+void
+mthread(void*)
+{
+ Mouse m;
+ for(;;){
+ recv(mctl->c, &m);
+ }
+}
+void
+resthread(void *arg)
+{
+ Mousectl *mc = arg;
+ for(;;){
+ recvul(mc->resizec);
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("getwindow: %r");
+ print("resize\n");
+ offset.x = (Dx(screen->r)-Dx(body->r))/2;
+ offset.y = (Dy(screen->r)-Dy(body->r))/2;
+ drawstuff();
+ }
+}
+
+void
+init(void)
+{
+ int fd;
+
+ fd = open("body.bit", OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ body = readimage(display, fd, 0);
+ close(fd);
+
+ fd = open("tail.bit", OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ tail = readimage(display, fd, 0);
+ close(fd);
+
+ fd = open("eyes.bit", OREAD);
+ if(fd < 0)
+ sysfatal("open: %r");
+ eyes = readimage(display, fd, 0);
+ close(fd);
+
+ print("read imgs\n");
+
+ offset.x = (Dx(screen->r)-Dx(body->r))/2;
+ offset.y = (Dy(screen->r)-Dy(body->r))/2;
+}
+
+void
+threadmain(int, char *argv[])
+{
+ kctl = initkeyboard("/dev/cons");
+ if(kctl == nil)
+ sysfatal("initkeyboard: %r");
+ mctl = initmouse("/dev/mouse", screen);
+ if(mctl == nil)
+ sysfatal("initmouse: %r");
+
+ if(initdraw(nil, nil, argv[0]) < 0)
+ sysfatal("initdraw: %r");
+
+ threadcreate(mthread, nil, mainstacksize);
+ threadcreate(kbthread, kctl, 8*1024);
+ threadcreate(resthread, mctl, 8*1024);
+
+ init();
+
+ drawstuff();
+ while(1){
+ sleep(12);
+ tailoffset += tailspeed;
+ eyesoffset += eyesspeed;
+ if(tailoffset > 15.0f || tailoffset < -15.0f){
+ tailspeed *= -1.0f;
+ eyesspeed *= -1.0f;
+ }
+ drawstuff();
+ yield();
+ }
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,9 @@
+< /$objtype/mkfile
+
+TARG=catvclock
+OFILES=\
+ main.$O
+
+BIN=$home/bin/$objtype
+
+< /sys/src/cmd/mkone
binary files /dev/null b/screen.png differ
binary files /dev/null b/tail.bit differ