From 712fd30652d29dc9e936f11d7837d1cb079575fc Mon Sep 17 00:00:00 2001 From: aiju Date: Wed, 30 Jul 2014 15:57:14 +0200 Subject: added sprite editor spred --- sys/src/cmd/spred/spr.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 sys/src/cmd/spred/spr.c (limited to 'sys/src/cmd/spred/spr.c') diff --git a/sys/src/cmd/spred/spr.c b/sys/src/cmd/spred/spr.c new file mode 100644 index 000000000..f61b59781 --- /dev/null +++ b/sys/src/cmd/spred/spr.c @@ -0,0 +1,371 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dat.h" +#include "fns.h" + +Spr * +newspr(char *f) +{ + Spr *s; + + s = emalloc(sizeof(*s)); + s->type = SPR; + filinit(s, f); + return s; +} + +void +putspr(Spr *s) +{ + if(s->pal != nil && !decref(s->pal) && s->pal->change <= 0) + putfil(s->pal); + free(s->palfile); + free(s->data); +} + +int +readspr(Spr *s, Biobuf *bp) +{ + char *args0[8], *p, *ss, **args; + int n, i, j; + + args = nil; + ss = nil; + if(tline(bp, &ss, args0, nelem(args0)) != 4) + goto err; + if(strcmp(args0[0], "sprite") != 0) + goto err; + n = strtol(args0[1], &p, 0); + if(*p != 0 || n < 0) + goto err; + s->w = n; + n = strtol(args0[2], &p, 0); + if(*p != 0 || n < 0) + goto err; + s->h = n; + if(*args0[3] != 0) + s->palfile = strdup(args0[3]); + else + s->palfile = nil; + free(ss); + ss = nil; + s->data = emalloc(s->w * s->h * sizeof(u32int)); + args = emalloc((s->w + 1) * sizeof(char *)); + for(i = 0; i < s->h; i++){ + if(tline(bp, &ss, args, s->w + 1) != s->w) + goto err; + for(j = 0; j < s->w; j++){ + n = strtol(args[j], &p, 0); + if(*p != 0 || n < 0) + goto err; + s->data[i * s->w + j] = n; + } + free(ss); + ss = nil; + } + free(args); + return 0; +err: + werrstr("invalid format"); + free(s->data); + free(args); + s->w = 0; + s->h = 0; + return -1; +} + +int +writespr(Spr *s, char *file) +{ + Biobuf *bp; + int n, rc; + int i, j; + + if(file == nil) + file = s->name; + bp = Bopen(file, OWRITE); + if(bp == nil){ + cmdprint("?%r\n"); + return -1; + } + rc = Bprint(bp, "sprite %d %d %q\n", s->w, s->h, s->palfile != nil ? s->palfile : ""); + if(rc < 0) goto err; + n = rc; + for(i = 0; i < s->h; i++) + for(j = 0; j < s->w; j++){ + rc = Bprint(bp, "%d%c", s->data[s->w * i + j], j == s->w - 1 ? '\n' : ' '); + if(rc < 0) goto err; + n += rc; + } + if(Bterm(bp) < 0){ + cmdprint("?%r\n"); + return -1; + } + s->change = 0; + quitok = 0; + cmdprint("%s: #%d\n", file, n); + return 0; +err: + cmdprint("?%r\n"); + Bterm(bp); + return -1; +} + +int +sprinit(Win *w) +{ + w->zoom = 4; + return 0; +} + +static Rectangle +sprrect(Win *w, Rectangle s) +{ + Rectangle r; + Point p, q; + Spr *t; + + t = (Spr *) w->f; + p = Pt(t->w * w->zoom, t->h * w->zoom); + q = addpt(divpt(addpt(s.min, s.max), 2), w->scr); + r.min = subpt(q, divpt(p, 2)); + r.max = addpt(r.min, p); + return r; +} + +static void +scrollbars(Win *w) +{ + Rectangle r, s; + int dx, dy; + int t0, t1; + + if(rectinrect(w->sprr, w->inner)) + return; + r = w->inner; + dx = Dx(r) - SCRTSIZ; + dy = Dy(r) - SCRTSIZ; + if(dx <= 0 || dy <= 0) + return; + s = r; + if(!rectclip(&s, w->sprr)) + return; + draw(w->im, Rect(r.min.x, r.max.y - SCRBSIZ, r.max.x - SCRTSIZ, r.max.y), w->tab->cols[BORD], nil, ZP); + draw(w->im, Rect(r.max.x - SCRBSIZ, r.min.y, r.max.x, r.max.y - SCRTSIZ), w->tab->cols[BORD], nil, ZP); + t0 = (s.min.x - w->sprr.min.x) * dx / Dx(w->sprr) + r.min.x; + t1 = (s.max.x - w->sprr.min.x) * dx / Dx(w->sprr) + r.min.x; + draw(w->im, Rect(t0, r.max.y - SCRBSIZ + 1, t1, r.max.y), w->tab->cols[BACK], nil, ZP); + t0 = (s.min.y - w->sprr.min.y) * dy / Dy(w->sprr) + r.min.y; + t1 = (s.max.y - w->sprr.min.y) * dy / Dy(w->sprr) + r.min.y; + draw(w->im, Rect(r.max.x - SCRBSIZ, t0, r.max.x, t1), w->tab->cols[BACK], nil, ZP); +} + +void +sprdraw(Win *w) +{ + Rectangle r, t; + Spr *s; + Pal *p; + int i, j; + Image *im; + u32int *d; + + if(w->type != SPR || w->f == nil) + sysfatal("sprdraw: phase error"); + s = (Spr *) w->f; + p = s->pal; + draw(w->im, w->inner, w->tab->cols[BACK], nil, ZP); + r = sprrect(w, w->inner); + w->sprr = r; + if(!rectinrect(r, w->inner)){ + t = w->inner; + t.max.x -= SCRTSIZ; + t.max.y -= SCRTSIZ; + r = sprrect(w, t); + w->sprr = r; + rectclip(&r, t); + scrollbars(w); + } + d = s->data; + for(j = 0; j < s->h; j++) + for(i = 0; i < s->w; i++, d++){ + t.min = addpt(w->sprr.min, Pt(i * w->zoom, j * w->zoom)); + t.max = addpt(t.min, Pt(w->zoom, w->zoom)); + if(!rectclip(&t, r)) + continue; + if(p != nil && *d < p->ncol) + im = p->ims[*d]; + else + im = invcol; + draw(w->im, t, im, nil, ZP); + } +} + +static int +sprbars(Win *w, Mousectl *mc) +{ + int d; + + if(rectinrect(w->sprr, w->inner)) + return -1; + if(mc->xy.x >= w->inner.max.x - SCRBSIZ){ + d = Dy(w->inner) / 5; + switch(mc->buttons){ + case 1: w->scr.y += d; break; + case 4: w->scr.y -= d; break; + default: return 0; + } + sprdraw(w); + return 0; + } + if(mc->xy.y >= w->inner.max.y - SCRBSIZ){ + d = Dx(w->inner) / 5; + switch(mc->buttons){ + case 1: w->scr.x += d; break; + case 4: w->scr.x -= d; break; + default: return 0; + } + sprdraw(w); + return 0; + } + return -1; +} + +void +sprclick(Win *w, Mousectl *mc) +{ + Spr *s; + Pal *p; + Point q; + + if(w->f == nil) + sysfatal("sprclick: phase error"); + if(sprbars(w, mc) >= 0) + return; + s = (Spr *) w->f; + p = s->pal; + if(p == nil || p->sel < 0 || p->sel >= p->ncol) + return; + do{ + q = divpt(subpt(mc->xy, w->sprr.min), w->zoom); + if(q.x < 0 || q.y < 0 || q.x >= s->w || q.y >= s->h) + continue; + if(s->data[q.y * s->w + q.x] != p->sel){ + s->data[q.y * s->w + q.x] = p->sel; + s->change = 1; + quitok = 0; + sprdraw(w); + } + }while(readmouse(mc) >= 0 && (mc->buttons & 1) != 0); +} + +void +sprsize(Spr *s, int n, int m) +{ + u32int *v; + int i, j, w, h; + + v = s->data; + if(s->w == n && s->h == m) + return; + s->data = emalloc(n * m * sizeof(u32int)); + w = n < s->w ? n : s->w; + h = m < s->h ? m : s->h; + for(j = 0; j < h; j++) + for(i = 0; i < w; i++) + s->data[j * n + i] = v[j * w + i]; + s->w = n; + s->h = m; + s->change = 1; + quitok = 0; + filredraw(s); +} + +static char * +palfile(char *, char *n) +{ + return strdup(n); +} + +static void +sprmenu(Win *w, Mousectl *mc) +{ + enum { MPAL }; + static char *menus[] = { + "pal", + nil, + }; + static Menu menu = {menus}; + Win *wp; + Spr *s; + + if(w->f == nil) + sysfatal("sprmenu: phase error"); + s = (Spr *) w->f; + switch(menuhit(2, mc, &menu, scr)){ + case MPAL: + wp = winsel(mc, 2); + if(wp == nil || wp->type != PAL) + break; + if(wp->f == nil) + sysfatal("sprmenu: pal phase error"); + if(s->pal != (Pal *) wp->f){ + if(s->pal != nil && decref(s->pal) == 0 && s->pal->change <= 0) + putfil(s->pal); + incref(wp->f); + s->pal = (Pal *) wp->f; + free(s->palfile); + s->palfile = palfile(s->name, s->pal->name); + s->change = 1; + quitok = 0; + filredraw(s); + } + break; + } +} + +static void +sprzerox(Win *w, Win *v) +{ + v->zoom = w->zoom; + v->scr = w->scr; +} + +static void +sprkey(Win *w, Rune r) +{ + static char keys[] = "1234567890qwertyuiop"; + char *p; + Spr *s; + + s = (Spr *) w->f; + if(s == nil) + sysfatal("sprkey: phase error"); + if(r < 0x100 && (p = strchr(keys, r)) != nil){ + if(s->pal == nil || p - keys >= s->pal->ncol) + return; + s->pal->sel = p - keys; + filredraw(s->pal); + } +} + +Wintab sprtab = { + .init = sprinit, + .click = sprclick, + .draw = sprdraw, + .menu = sprmenu, + .rmb = sprbars, + .zerox = sprzerox, + .key = sprkey, + .hexcols = { + [BORD] 0x00AA00FF, + [DISB] 0x88CC88FF, + [BACK] 0xCCFFCCFF, + }, +}; -- cgit v1.2.3