shithub: cardgen

ref: 4a0b3479f227e484b1a65b6443ba59a7bdb49962
dir: /cardgen.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>


/* configuration parameters */

/* card dimensions */
int cardwid = 200;
int cardhgt = 300;

/* radius for card corners (for template card) */
int cardrad = 7;

/* symbol dimensions */
int symwid = 30;
int symhgt = 30;

/* symbol locations */
Point symlocs[2] = {
	{ 10, 10 },
	{ 200-30-10, 300-30-10 },
};

/* label locations */
Point lbllocs[2] = {
	{ 10+30+10, 10+15 },
	{ 200-30-10-10, 300-30-10+15 },
};

/* label alignment */
/* 0 left, 1 right */
int lblalign[2] = {
	0,
	1,
};

/* labels for card values */
/* nils will be skipped */
char *labels[15] = {
	nil,
	nil,
	"2",
	"3",
	"4",
	"5",
	"6",
	"7",
	"8",
	"9",
	"10",
	"J (11)",
	"Q (12)",
	"K (13)",
	"A (14)",
};


/* code */

static void
usage(void)
{
	fprint(2, "usage: %s [-dt] [-f subfont]\n", argv0);
	exits("usage");
}

Memimage *memred;
Memimage *memgreen;
Memsubfont *memfont;
int fontheight;
int debug = 0;

static void
drawspades(Memimage *mi)
{
	/*
	     /\
	   *    *
	     |
	*/
	
	Point c, p, q;
	int d, r;
	
	Point tip[3];
	Point bot[5];
	
	r = Dx(mi->r)/5;
	c.x = Dx(mi->r)/2 - 1;
	c.y = Dy(mi->r)/2 - 1;
	
	/* points */
	d = Dx(mi->r)/4.5;
	p.x = c.x - d;
	p.y = c.y+1;
	q.x = c.x;
	q.y = Dy(mi->r)/4;
	memimageline(mi, p, q, Enddisc, Enddisc, r, memblack, ZP, SoverD);
	
	p.x = c.x + d;
	memimageline(mi, p, q, Enddisc, Enddisc, r, memblack, ZP, SoverD);
	
	tip[0] = Pt(c.x+d/2, (p.y - q.y)/2);
	tip[1] = Pt(c.x, (p.y - q.y)/10-1);
	tip[2] = Pt(c.x-d/2, (p.y - q.y)/2);
	
	bot[0] = Pt(c.x, c.y);
	d = Dx(mi->r)/10.;
	r = Dx(mi->r)/6.;
	bot[1] = Pt(c.x-d, Dy(mi->r)/15.*13.);
	bot[2] = Pt(c.x-r, Dy(mi->r)/15.*14.5);
	bot[3] = Pt(c.x+r, Dy(mi->r)/15.*14.5);
	bot[4] = Pt(c.x+d, Dy(mi->r)/15.*13.);
	
	memfillpoly(mi, tip, nelem(tip), 0, memblack, ZP, SoverD);
	memfillpoly(mi, bot, nelem(bot), 0, memblack, ZP, SoverD);
}

static void
drawclubs(Memimage *mi)
{
	/*
	     *
	   *   *
	     |
	*/
	
	Point p;
	int r;
	int cx;
	float d;
	
	r = Dx(mi->r) / 4.5;
	d = 4.;
	
	/* center point */
	p.x = cx = Dx(mi->r) / 2 -1;
	p.y = Dy(mi->r) / 5 + 1;
	memimageline(mi, p, p, Enddisc, Enddisc, r, memblack, ZP, SoverD);
	
	/* left point */
	p.y = Dy(mi->r) / 2 + 1;
	p.x = cx - Dx(mi->r) / d;
	memimageline(mi, p, p, Enddisc, Enddisc, r, memblack, ZP, SoverD);
	
	/* right point */
	p.x = cx + Dx(mi->r) / d;
	memimageline(mi, p, p, Enddisc, Enddisc, r, memblack, ZP, SoverD);
	
	/* line */
	p.x = Dx(mi->r) / 2 -1;
	p.y = Dy(mi->r) / 5 + 1;
	memimageline(mi, p, Pt(p.x, Dy(mi->r)/15.*14.),
		Endsquare, Endsquare, Dx(mi->r)/20, memblack, ZP, SoverD);
}

static void
drawhearts(Memimage *mi)
{
	/*
	    *  *
	     \/
	*/
	
	Point p, q, c;
	int r, d;
	float f = 0.7;
	
	c.x = Dx(mi->r)/2 - 1;
	c.y = Dy(mi->r)/2;
	
	r = Dx(mi->r)/4.5;
	d = Dx(mi->r)/4.5;
	p.x = c.x - d;
	p.y = c.y - d;
	q.x = c.x + r*f;
	q.y = c.y + r*f;
	memimageline(mi, p, q, Enddisc, Endsquare, r, memred, ZP, SoverD);
	p.x = c.x + d;
	q.x = c.x - r*f;
	memimageline(mi, p, q, Enddisc, Endsquare, r, memred, ZP, SoverD);
}

static void
drawdiamonds(Memimage *mi)
{
	/* circle, starting at (1.0, 0.0), counterclockwise. */
	Point p[12];
	Point c;
	int i;
	float x, y, f;
	float outer, inner;
	
	/* outer distance: diamond corners.
	   inner distance: inner curve. */
	outer = Dx(mi->r)/2.;
	inner = Dx(mi->r)/3.4;
	
	c.x = Dx(mi->r)/2. -1;
	c.y = Dy(mi->r)/2. -1;
	
	for (i = 0; i < nelem(p); i++) {
		f = ( ((float)i) / nelem(p) ) * PI*2.;
		x = cos(f);
		y = sin(f);
		f = i%3 == 0 ? outer : inner;
		p[i].x = c.x + x * f;
		p[i].y = c.y + y * f;
	}
	memfillpoly(mi, p, nelem(p), 0, memred, ZP, SoverD);
}

static void
drawborder(Memimage *mi)
{
	memimageline(mi,
		Pt(mi->r.min.x, mi->r.min.y),
		Pt(mi->r.max.x, mi->r.min.y),
		Endsquare, Endsquare, 0, memblack, ZP, S);
	memimageline(mi,
		Pt(mi->r.max.x-1, mi->r.min.y),
		Pt(mi->r.max.x-1, mi->r.max.y),
		Endsquare, Endsquare, 0, memblack, ZP, S);
	memimageline(mi,
		Pt(mi->r.max.x, mi->r.max.y-1),
		Pt(mi->r.min.x, mi->r.max.y-1),
		Endsquare, Endsquare, 0, memblack, ZP, S);
	memimageline(mi,
		Pt(mi->r.min.x, mi->r.max.y),
		Pt(mi->r.min.x, mi->r.min.y),
		Endsquare, Endsquare, 0, memblack, ZP, S);
}

int gentemplates = 0;

static void
dogentemplates(void)
{
	Memimage *mi;
	int fcard;
	int fsym;
	int fdiamonds;
	int fhearts;
	int fclubs;
	int fspades;
	Rectangle r;
	Point p;
	
	fcard = create("tcard", OWRITE, 0664);
	if (fcard < 0)
		sysfatal("%r");
	fsym = create("tsym", OWRITE, 0664);
	if (fsym < 0)
		sysfatal("%r");
	fdiamonds = create("tsym0", OWRITE, 0664);
	if (fdiamonds < 0)
		sysfatal("%r");
	fhearts = create("tsym1", OWRITE, 0664);
	if (fhearts < 0)
		sysfatal("%r");
	fclubs = create("tsym2", OWRITE, 0664);
	if (fclubs < 0)
		sysfatal("%r");
	fspades = create("tsym3", OWRITE, 0664);
	if (fspades < 0)
		sysfatal("%r");

#define FINISH(A) drawborder(mi);writememimage(A, mi);freememimage(mi);close(A);
	
	mi = allocmemimage(Rect(-1, -1, cardwid+1, cardhgt+1), RGBA32);
	if (!mi)
		sysfatal("%r");
	
	memfillcolor(mi, DTransparent);
	p = Pt(cardrad*2, cardrad*2);
	memimageline(mi, p, p, Enddisc, Enddisc, cardrad*2, memwhite, ZP, SoverD);
	p = Pt(cardwid-cardrad*2, cardrad*2);
	memimageline(mi, p, p, Enddisc, Enddisc, cardrad*2, memwhite, ZP, SoverD);
	p = Pt(cardwid-cardrad*2, cardhgt-cardrad*2);
	memimageline(mi, p, p, Enddisc, Enddisc, cardrad*2, memwhite, ZP, SoverD);
	p = Pt(cardrad*2, cardhgt-cardrad*2);
	memimageline(mi, p, p, Enddisc, Enddisc, cardrad*2, memwhite, ZP, SoverD);
	r.min = Pt(cardrad*2, 0);
	r.max = Pt(cardwid-cardrad*2, cardhgt);
	memdraw(mi, r, memwhite, ZP, nil, ZP, S);
	r.min = Pt(0, cardrad*2);
	r.max = Pt(cardwid, cardhgt-cardrad*2);
	memdraw(mi, r, memwhite, ZP, nil, ZP, S);
	
	FINISH(fcard)
	
	mi = allocmemimage(Rect(-1, -1, symwid+1, symhgt+1), RGBA32);
	if (!mi)
		sysfatal("%r");
	
	memfillcolor(mi, DTransparent);
	FINISH(fsym);
	
	mi = allocmemimage(Rect(-1, -1, symwid+1, symhgt+1), RGBA32);
	if (!mi)
		sysfatal("%r");
	memfillcolor(mi, DTransparent);
	drawdiamonds(mi);
	FINISH(fdiamonds);
	
	mi = allocmemimage(Rect(-1, -1, symwid+1, symhgt+1), RGBA32);
	if (!mi)
		sysfatal("%r");
	memfillcolor(mi, DTransparent);
	drawhearts(mi);
	FINISH(fhearts);
	
	mi = allocmemimage(Rect(-1, -1, symwid+1, symhgt+1), RGBA32);
	if (!mi)
		sysfatal("%r");
	memfillcolor(mi, DTransparent);
	drawclubs(mi);
	FINISH(fclubs);
	
	mi = allocmemimage(Rect(-1, -1, symwid+1, symhgt+1), RGBA32);
	if (!mi)
		sysfatal("%r");
	memfillcolor(mi, DTransparent);
	drawspades(mi);
	FINISH(fspades);
	
#undef FINISH
}

static Memimage*
load(char *name)
{
	Memimage *mi;
	int fd;
	fd = open(name, OREAD);
	if (fd < 0)
		sysfatal("%r");
	mi = readmemimage(fd);
	if (!mi)
		sysfatal("creadmemimage %s: %r", name);
	close(fd);
	return mi;
}

Memimage *card;
Memimage *syms[4];

static void
gencard(int num, Memimage *sym, int fadd, Memimage *face)
{
	Memimage *mi;
	int i, fd;
	char *file;
	char *label;
	Point text;
	Point p;
	Rectangle r;
	
	label = labels[num];
	if (!label)
		return;
	
	text = memsubfontwidth(memfont, label);
	
	mi = allocmemimage(Rect(0, 0, cardwid, cardhgt), RGBA32);
	if (!mi)
		sysfatal("%r");
	
	memfillcolor(mi, DTransparent);
	memdraw(mi, mi->r, card, ZP, nil, ZP, S);
	r = insetrect(sym->r, 1);
	for (i = 0; i < nelem(symlocs); i++) {
		memdraw(mi, rectaddpt(r, symlocs[i]), sym, ZP, nil, ZP, SatopD);
	}
	
	for (i = 0; i < nelem(lbllocs); i++) {
		p = lbllocs[i];
		if (lblalign[i])
			p.x -= text.x;
		if (debug)
			memimageline(mi, p, p, Enddisc, Enddisc, 0, memgreen, ZP, SoverD);
		p.y -= fontheight/2.;
		memimagestring(mi, p, memblack, ZP, memfont, label);
	}
	
	if (face) {
		p.x = (Dx(mi->r) - Dx(face->r))/2.;
		p.y = (Dy(mi->r) - Dy(face->r))/2.;
		memdraw(mi, rectaddpt(face->r, p), face, ZP, nil, ZP, SatopD);
	}
	
	file = smprint("out/%d", num+fadd);
	if (!file)
		sysfatal("%r");
	fd = create(file, OWRITE, 0644);
	if (fd < 0)
		sysfatal("%r");
	writememimage(fd, mi);
	freememimage(mi);
	close(fd);
}

static Memimage*
loadface(int value, int color)
{
	char file[512];
	int fd;
	Memimage *mi;
	
	snprint(file, sizeof file, "face/%d.%d", color, value);
	fd = open(file, OREAD);
	if (fd < 0)
		return nil;
	mi = readmemimage(fd);
	close(fd);
	return mi;
}

void
main(int argc, char **argv)
{
	int i, j;
	char *fontfile = getenv("cardfont");
	Memimage *face;
	
	ARGBEGIN{
	case 't':
		gentemplates++;
		break;
	case 'f':
		fontfile = EARGF(usage());
		break;
	case 'd':
		debug++;
		break;
	case 'h':
		usage();
	}ARGEND;
	
	if (memimageinit() < 0)
		sysfatal("memimageinit: %r");
	
	memred = allocmemimage(Rect(0, 0, 1, 1), RGB24);
	memfillcolor(memred, 0xFF0000FF);
	memred->flags |= Frepl;
	memred->clipr = memblack->clipr;
	
	memgreen = allocmemimage(Rect(0, 0, 1, 1), RGB24);
	memfillcolor(memgreen, 0x00CC00FF);
	memgreen->flags |= Frepl;
	memgreen->clipr = memblack->clipr;
	
	if (fontfile) {
		memfont = openmemsubfont(fontfile, 0);
		if (!memfont)
			fprint(2, "error: %r. Falling back to default font!\n");
	}
	if (!memfont)
		memfont = getmemdefont();
	
	fontheight = memsubfontwidth(memfont, "M").y;
	
	if (gentemplates) {
		dogentemplates();
		exits(nil);
	}
	
	card = load("card");
	syms[0] = load("sym0");
	syms[1] = load("sym1");
	syms[2] = load("sym2");
	syms[3] = load("sym3");
	
	for (j = 0; j < 4; j++) {
		for (i = 0; i < nelem(labels); i++) {
			face = loadface(i, j);
			gencard(i, syms[j], j*nelem(labels), face);
			freememimage(face);
		}
	}
	exits(nil);
}