/*
* Piece editor for plumb
*
* min
* |-------|
* | |
* | smallr |
* | |
* |-------|
* max
* min
* |---------------------------------|
* | |
* ~~~~~~~~ ~~~~~
* | bigr edit screen |
* ~~~~ ~~~~~
* |---------------------------------|
* max
*/
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include <draw.h>
#include <event.h>
#define SIZE 48
#define MAG 10
#define BORDER 4
#define NVAL 4
struct{
char *name;
Image *image;
}piece[]={
" 0 N/E", 0,
" 1 N/S", 0,
" 2 N/W", 0,
" 3 E/S", 0,
" 4 E/W", 0,
" 5 S/W", 0,
" 6 N/S+E/W", 0,
" 7 N/E one way", 0,
" 8 N/S one way", 0,
" 9 N/W one way", 0,
"10 E/N one way", 0,
"11 E/S one way", 0,
"12 E/W one way", 0,
"13 S/N one way", 0,
"14 S/E one way", 0,
"15 S/W one way", 0,
"16 W/N one way", 0,
"17 W/E one way", 0,
"18 W/S one way", 0,
"19 start N", 0,
"20 start E", 0,
"21 start S", 0,
"22 start W", 0,
"23 finish N", 0,
"24 finish E", 0,
"25 finish S", 0,
"26 finish W", 0,
"27 N/S reservoir", 0,
"28 E/W reservoir", 0,
"29 N/S bonus", 0,
"30 E/W bonus", 0,
"31 obstacle", 0,
"32 empty", 0,
};
#define NPIECE (sizeof piece/sizeof piece[0])
Image *flat[NVAL];
char pix[SIZE][SIZE];
char curval=3;
enum{ Paint, Fill, Relief}mode=Paint;
Rectangle bigr, smallr;
/* colors for plumb */
Image *darkgreen;
Image *palegreen;
Image *bgcolor;
char pattern[16][16]={
3,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,
0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,
0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,
0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,
3,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,
0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,
0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,
0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,
3,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,
0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,
0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,
0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,
3,0,0,0,3,0,0,0,3,0,0,0,3,0,0,0,
0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,
0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,
0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,
};
void
rectf(Image *b, Rectangle r, Image *color){
draw(b, r, color, 0, ZP);
}
void
show(Point p){
Point pp;
int v=pix[p.y][p.x];
pp = addpt(bigr.min, mulpt(p, MAG));
draw(screen, Rpt(pp, addpt(pp, Pt(MAG, MAG))), flat[v], 0, flat[v]->r.min);
pp = addpt(smallr.min, p);
draw(screen, Rpt(pp, addpt(pp, Pt(1, 1))), flat[v], 0, addpt(ZP, Pt(1, 1)));
}
/* set the pixel value to v */
void
set(Point p, char v){
if(v==4)
v=pattern[p.y%16][p.x%16];
if(pix[p.y][p.x]!=v){
pix[p.y][p.x]=v;
show(p);
}
}
char region[SIZE][SIZE];
void
getregion1(Point p, char v){
if(pix[p.y][p.x]!=v || region[p.y][p.x]) return;
region[p.y][p.x]=1;
if(p.x!=SIZE-1) getregion1(Pt(p.x+1, p.y), v);
if(p.x!=0) getregion1(Pt(p.x-1, p.y), v);
if(p.y!=SIZE-1) getregion1(Pt(p.x, p.y+1), v);
if(p.y!=0) getregion1(Pt(p.x, p.y-1), v);
}
void
getregion(Point p){
int x, y;
for(y=0;y!=SIZE;y++) for(x=0;x!=SIZE;x++) region[y][x]=0;
getregion1(p, pix[p.y][p.x]);
}
void
fill(Point p, char v){
int x, y;
getregion(p);
for(y=0;y!=SIZE;y++)
for(x=0;x!=SIZE;x++)
if(region[y][x])
set(Pt(x, y), v);
}
int
inregion(int x, int y){
return 0<=x && x<SIZE && 0<=y && y<SIZE && region[y][x];
}
void
relief(Point p){
int x, y;
getregion(p);
for(y=0;y!=SIZE;y++) for(x=0;x!=SIZE;x++) if(inregion(x, y)){
if(!inregion(x, y-1) || !inregion(x-1, y))
set(Pt(x, y), 0);
else if(!inregion(x, y+1) || !inregion(x+1, y))
set(Pt(x, y), 2);
}
}
void
eresized(int new){
int x, y;
Image *color;
if(new && getwindow(display, Refmesg) < 0)
fprint(2,"can't reattach to window");
smallr.min=addpt(screen->r.min, Pt(3*BORDER, 3*BORDER));
smallr.max=addpt(smallr.min, Pt(SIZE, SIZE));
bigr.min=addpt(smallr.max, Pt(3*BORDER, 3*BORDER));
bigr.max=addpt(bigr.min, Pt(MAG*SIZE, MAG*SIZE));
if(!ptinrect(addpt(bigr.max, Pt(BORDER-1, BORDER-1)), screen->r)){
fprintf(stderr, "window too small, must be at least %d x %d\n",
bigr.max.x-screen->r.min.x+BORDER-1,
bigr.max.y-screen->r.min.y+BORDER-1);
exits("window too big");
}
rectf(screen, screen->r, bgcolor);
color = darkgreen;
border(screen, screen->r, BORDER, color, ZP);
for(y=0; y!=SIZE; y++)
for(x=0; x!=SIZE; x++)
show(Pt(x, y));
}
/* make magnufied lattice pattern image */
void
initflats(void){
int i, scale;
for(i=0; i<NVAL; i++){
scale = i*255/NVAL;
flat[i]=allocimage(display, Rect(0, 0, 1, 1), GREY8, 1, cmap2rgba(scale));
}
}
char *mbut2[]={
"white", /* white, pixel value = 3 */
"light", /* light, pixel value = 2 */
"dark", /* dark, pixel value = 1 */
"black", /* pixel value = 0 */
"pattern",
"paint",
"fill",
"relief",
0
};
Menu menu2={mbut2};
char *mbut3[]={
"next",
"prev",
"write",
"exit",
0
};
Menu menu3={mbut3};
void
see(Image *b){
uchar buf[SIZE][SIZE/4]; /* for ldepth =1 or depth = 2 image only */
int x, y;
unloadimage(b, Rect(0, 0, SIZE, SIZE), (uchar*)buf, sizeof buf);
for(y=0; y!=SIZE; y++)
for(x=0; x!=SIZE; x++)
set(Pt(x, y), (buf[y][x/4]>>(6-x%4*2))&3);
}
void
save(Image *b){
draw(b, b->r, screen, 0, smallr.min);
}
void
input(char *name){
int i;
Image *b;
int fd=open(name, OREAD);
if(fd<0){
Bad:
fprintf(stderr, "Bad input %s\n", name);
exits("bad input");
}
for(i=0; i!=NPIECE; i++){
b=readimage(display, fd, 0);
if(!b || !eqrect(b->r, Rect(0, 0, SIZE, SIZE)) || b->depth!=2)
goto Bad;
piece[i].image=b;
}
close(fd);
}
void
output(char *name){
int i;
int fd=create(name, OWRITE, 0666);
if(fd<0){
fprintf(stderr, "Can't create %s\n", name);
exits("bad output");
}
for(i=0; i!=NPIECE; i++)
writeimage(fd, piece[i].image, 0);
close(fd);
}
void
main(int argc, char *argv[]){
Mouse m;
int i=0;
if(argc!=3){
fprintf(stderr, "Usage: %s input output\n", argv[0]);
exits("usage");
}
initdraw(0, 0, "plumb");
einit(Emouse|Ekeyboard);
darkgreen=allocimage(display, Rect(0, 0, 1, 1), display->windows->chan, 1, DDarkgreen);
palegreen = allocimage(display, Rect(0,0,1,1), display->windows->chan, 1, DPalegreen);
bgcolor = palegreen;
initflats();
eresized(0);
input(argv[1]);
see(piece[i].image);
for(;;){
m=emouse();
switch(m.buttons){
case 1:
if(ptinrect(m.xy, bigr)){
switch(mode){
case Fill:
fill(divpt(subpt(m.xy, bigr.min), MAG), curval);
do m=emouse(); while(m.buttons);
break;
case Paint:
set(divpt(subpt(m.xy, bigr.min), MAG), curval);
break;
case Relief:
relief(divpt(subpt(m.xy, bigr.min), MAG));
do m=emouse(); while(m.buttons);
break;
}
}
break;
case 2:
switch(emenuhit(2, &m, &menu2)){
case 0: curval=3; break;
case 1: curval=2; break;
case 2: curval=1; break;
case 3: curval=0; break;
case 4: curval=4; break;
case 5: mode=Paint; break;
case 6: mode=Fill; break;
case 7: mode=Relief; break;
}
break;
case 4:
switch(emenuhit(3, &m, &menu3)){
case 0:
if(i<NPIECE-1){
save(piece[i].image);
see(piece[++i].image);
}
break;
case 1:
if(i>0){
save(piece[i].image);
see(piece[--i].image);
}
break;
case 2:
save(piece[i].image);
output(argv[2]);
break;
case 3:
save(piece[i].image);
output(argv[2]);
exits(0);
}
break;
}
}
}
|