/* g_cam.c
*
* Micropolis, Unix Version. This game was released for the Unix platform
* in or about 1990 and has been modified for inclusion in the One Laptop
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
* you need assistance with this program, you may contact:
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details. You should have received a
* copy of the GNU General Public License along with this program. If
* not, see .
*
* ADDITIONAL TERMS per GNU GPL Section 7
*
* No trademark or publicity rights are granted. This license does NOT
* give you any right, title or interest in the trademark SimCity or any
* other Electronic Arts trademark. You may not distribute any
* modification of this program using the trademark SimCity or claim any
* affliation or association with Electronic Arts Inc. or its employees.
*
* Any propagation or conveyance of this program must include this
* copyright notice and these terms.
*
* If you convey this program (or any modifications of it) and assume
* contractual liability for the program to recipients of it, you agree
* to indemnify Electronic Arts for any liability that those contractual
* assumptions impose on Electronic Arts.
*
* You may not misrepresent the origins of this program; modified
* versions of the program must be marked as such and not identified as
* the original program.
*
* This disclaimer supplements the one included in the General Public
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
* NOT APPLY TO YOU.
*/
#include "sim.h"
#ifdef CAM
Can *
new_can(int w, int h, Byte *mem, int line_bytes)
{
Can *can = (Can *)malloc(sizeof(Can));
can->width = w;
can->height = h;
can->line_bytes = line_bytes;
can->mem = mem;
return (can);
}
Cam *
new_cam(SimCam *scam, int x, int y, int w, int h, int dx, int dy, vf func)
{
Cam *cam = (Cam *)malloc(sizeof(Cam));
int ww, hh;
cam->x = x;
cam->y = y;
cam->ideal_width = w;
cam->ideal_height = h;
w = (w + 1) & ~1;
h = (h + 1) & ~1;
ww = w + 2;
hh = h + 2;
cam->width = w;
cam->height = h;
cam->back = new_can(ww, hh, (Byte *)malloc(ww * hh), ww);
cam->front = new_can(w, h,
(Byte *)scam->data + x + (y * scam->line_bytes),
scam->line_bytes);
cam->neighborhood = func;
cam->rule = NULL;
cam->rule_size = 0;
cam->phase = 0;
cam->wrap = 3;
cam->frob = -1;
cam->steps = 1;
cam->dx = dx;
cam->dy = dy;
cam->gx = 0;
cam->gy = 0;
cam->dragging = 0;
cam->set_x = -1;
cam->set_y = -1;
cam->set_width = -1;
cam->set_height = -1;
cam->set_x0 = -1;
cam->set_y0 = -1;
cam->set_x1 = -1;
cam->set_y1 = -1;
cam->name = NULL;
cam->next = scam->cam_list;
scam->cam_list = cam;
scam->cam_count++;
return (cam);
}
scam_randomize(SimCam *scam)
{
u_char *data = scam->data;
int line_bytes = scam->line_bytes;
int pixels = line_bytes * scam->w_height;
int i;
for (i = 0; i < pixels; i++) {
*data = (char)(Rand16() >>4);
data++;
}
}
cam_randomize(Cam *cam)
{
int x, y, w, h, lb;
Byte *image;
w = cam->width;
h = cam->height;
lb = cam->front->line_bytes;
image = cam->front->mem;
for (y = 0; y < h; y++, image += lb) {
for (x = 0; x < w; x++) {
image[x] = (char)(Rand16() >> 4);
}
}
}
cam_do_rule(SimCam *scam, Cam *cam)
{
Byte *back, *front;
int frontline, backline;
int w, h;
int steps = cam->steps;
int step;
back = cam->back->mem;
backline = cam->back->line_bytes;
front = cam->front->mem;
frontline = cam->front->line_bytes;
w = cam->width;
h = cam->height;
for (step=0; step < steps; step++) {
int x, y;
Byte *p = back + backline + 1,
*f = front;
/*
* Copy wrapping edges from front=>back:
*
* 0 ff f0 f1 ... fe ff f0
*
* 1 0f 00 01 ... 0e 0f 00
* 2 1f 10 11 ... 1e 1f 10
* .. .. .. .. .. ..
* ef e0 e1 ... ee ef e0
* h ff f0 f1 ... fe ff f0
*
* h+1 0f 00 01 ... 0e 0f 00
*
* wrap value: effect:
* 0 no effect
* 1 copy front=>back, no wrap
* 2 no copy, wrap edges
* 3 copy front=>back, wrap edges
* 4 copy front=>back, same edges
* 5 copy edges from screen
*/
switch (cam->wrap) {
case 0:
break;
case 1:
for (y=0; yx == 0) ? 1 : 0;
int right = (cam->x + cam->front->width == scam->w_width) ? 1 : 0;
int top = (cam->y == 0) ? 1 : 0;
int bottom = (cam->y + cam->front->height == scam->w_height) ? 1 : 0;
if (!left && !right && !top && !bottom) {
p = back;
f = front - 1 - frontline;
for (y=-1; y<=h; y++) {
memcpy(p, f, w + 2);
p += backline;
f += frontline;
}
} else {
p = back + backline + 1;
f = front;
p[-1 - backline] = f[left - 1 - (top ? 0 : frontline)];
memcpy(p - backline, f, w);
p[w - backline] = f[w - right - (top ? 0 : frontline)];
for (y=0; yneighborhood)(cam);
cam->phase = !cam->phase;
cam_update(scam, cam);
cam_adjust(scam, cam);
} /* for step */
}
cam_slide(SimCam *scam, Cam *cam)
{
int x = cam->x;
int y = cam->y;
int last_x = x;
int last_y = y;
int width = cam->width;
int height = cam->height;
int dx = cam->dx;
int dy = cam->dy;
int dragging = cam->dragging;
int bounce = 0;
int dagnabit = 0;
if (dragging ||
(cam->set_x >= 0) ||
(cam->set_y >= 0)) {
if (cam->set_x >= 0) {
x = cam->set_x;
cam->set_x = -1;
}
if (cam->set_y >= 0) {
y = cam->set_y;
cam->set_y = -1;
}
} else {
x += dx;
y += dy;
}
if (x < 0) {
x = 0;
if (!dragging) {
dx = ABS(dx);
bounce = 1;
}
} else if ((x + width) > scam->w_width) {
x = scam->w_width - width;
if (!dragging) {
dx = -ABS(dx);
bounce = 1;
}
}
if (y < 0) {
y = 0;
if (!dragging) {
dy = ABS(dy);
bounce = 1;
}
else {
dagnabit = 1;
printf("dagnabit\n");
}
} else if ((y + height) > scam->w_height) {
y = scam->w_height - height;
if (!dragging) {
dy = -ABS(dy);
bounce = 1;
}
}
if (dragging) {
dx = x - last_x;
dy = y - last_y;
} else {
if (bounce) {
cam->frob = (Rand16() & 15) * ((cam->frob > 0) ? -1 : 1);
}
}
cam->x = x;
cam->y = y;
cam->front->mem = (Byte *)scam->data + x + (scam->line_bytes * y);
cam->dx = dx + cam->gx;
cam->dy = dy + cam->gy;
if (dagnabit) {
printf("x %d y %d dx %d dy %d\n", cam->x, cam->y, cam->dx, cam->dy);
}
}
cam_update(SimCam *scam, Cam *cam)
{
if (scam->x->shared) {
XShmPutImage(scam->x->dpy, Tk_WindowId(scam->tkwin), scam->x->gc,
scam->image, cam->x, cam->y,
cam->x, cam->y, cam->width, cam->height,
False);
} else {
XPutImage(scam->x->dpy, Tk_WindowId(scam->tkwin), scam->x->gc,
scam->image, cam->x, cam->y,
cam->x, cam->y, cam->width, cam->height);
}
}
cam_adjust(SimCam *scam, Cam *cam)
{
int x0 = cam->set_x0;
int y0 = cam->set_y0;
int x1 = cam->set_x1;
int y1 = cam->set_y1;
int width = cam->set_width;
int height = cam->set_height;
int min_size = 8;
int tmp;
if ((x0 >= 0) ||
(y0 >= 0) ||
(x1 >= 0) ||
(y1 >= 0) ||
(width > 0) ||
(height > 0)) {
if (x0 < 0) x0 = cam->x;
if (y0 < 0) y0 = cam->y;
if (x1 < 0) x1 = cam->x + cam->ideal_width;
if (y1 < 0) y1 = cam->y + cam->ideal_height;
if (width > 0) x1 = x0 + width;
if (height > 0) y1 = y0 + height;
cam->set_width = cam->set_height =
cam->set_x0 = cam->set_y0 =
cam->set_x1 = cam->set_y1 = -1;
if (x0 > x1) {
tmp = x0; x0 = x1; x1 = tmp;
}
if (y0 > y1) {
tmp = y0; y0 = y1; y1 = tmp;
}
if (x0 < 0) x0 = 0;
if (y0 < 0) y0 = 0;
if (x0 > scam->w_width - min_size) x0 = scam->w_width - min_size;
if (y0 > scam->w_height - min_size) x0 = scam->w_height - min_size;
if (x1 < x0 + min_size) x1 = x0 + min_size;
if (y1 < y0 + min_size) y1 = y0 + min_size;
if (x1 > scam->w_width) x1 = scam->w_width;
if (y1 > scam->w_height) y1 = scam->w_height;
cam->x = x0;
cam->y = y0;
cam->ideal_width = x1 - x0;
cam->ideal_height = y1 - y0;
cam->width = cam->ideal_width & ~1;
cam->height = cam->ideal_height & ~1;
cam->front->mem = (Byte *)scam->data + x0 + (y0 * scam->line_bytes);
cam->front->width = cam->width;
cam->front->height = cam->height;
free(cam->back->mem);
cam->back->mem = (Byte *)malloc((cam->width + 2) * (cam->height + 2));
cam->back->width = cam->width + 2;
cam->back->height = cam->height + 2;
cam->back->line_bytes = cam->back->width;
}
}
void
n_moore_a(Cam *cam)
{
/* 0 1 2 3 4 5 6 7 8 9 */
/* c c' se sw ne nw e w s n */
/* 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 */
#define MOORE_A ( \
((NORTHWEST&1)<<5) | ((NORTH&1)<<9) |((NORTHEAST&1)<<4) | \
((WEST&1)<<7) | (CENTER&3) | ((EAST&1)<<6) | \
((SOUTHWEST&1)<<3) | ((SOUTH&1)<<8) |((SOUTHEAST&1)<<2) \
)
CAM_TABLE_LOOP(MOORE_A)
}
void
n_moore_ab(Cam *cam)
{
/* 0 1 2 3 4 5 6 7 8 9 10 11 */
/* c c' se sw ne nw e w s n &c &c' */
/* 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 0x400 0x800 */
#define MOORE_AB (MOORE_A | ((CENTER&12)<<8))
CAM_TABLE_LOOP(MOORE_AB)
}
void
n_vonn_neumann(Cam *cam)
{
/* 0 1 2 3 4 5 6 7 8 9 */
/* c c' e' w' s' n' e w s n */
/* 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 */
#define VON_NEUMANN ( \
(CENTER&3) | \
((EAST&1)<<6) | ((EAST&2)<<1) | \
((WEST&1)<<7) | ((WEST&2)<<2) | \
((SOUTH&1)<<8) | ((SOUTH&2)<<3) | \
((NORTH&1)<<9) | ((NORTH&2)<<4) \
)
CAM_TABLE_LOOP(VON_NEUMANN)
}
void
n_margolis(Cam *cam)
{
register Byte i;
/* 0 1 2 3 4 5 6 7 8 9 */
/* c c' cw ccw opp cw' ccw' opp' */
/* 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 */
#define MARGOLIS_ODD ( \
(CENTER & 3) | \
(i=(x&1 ? (y&1 ? (EAST) : (NORTH)) \
: (y&1 ? (SOUTH) : (WEST))), \
(((i&1)<<2) | ((i&2)<<4))) | \
(i=(x&1 ? (y&1 ? (SOUTH) : (EAST)) \
: (y&1 ? (WEST) : (NORTH))), \
(((i&1)<<3) | ((i&2)<<5))) | \
(i=(x&1 ? (y&1 ? (SOUTHEAST):(NORTHEAST)) \
: (y&1 ? (SOUTHWEST):(NORTHWEST))), \
(((i&1)<<4) | ((i&2)<<6))) \
)
#define MARGOLIS_EVEN ( \
(CENTER & 3) | \
(i=(x&1 ? (y&1 ? (WEST) : (SOUTH)) \
: (y&1 ? (NORTH) : (EAST))), \
(((i&1)<<2) | ((i&2)<<4))) | \
(i=(x&1 ? (y&1 ? (NORTH) : (WEST)) \
: (y&1 ? (EAST) : (SOUTH))), \
(((i&1)<<3) | ((i&2)<<5))) | \
(i=(x&1 ? (y&1 ? (NORTHWEST) : (SOUTHWEST)) \
: (y&1 ? (NORTHEAST) : (SOUTHEAST))), \
(((i&1)<<4) | ((i&2)<<6))) \
)
if (cam->phase) {
CAM_TABLE_LOOP(MARGOLIS_ODD)
} else {
CAM_TABLE_LOOP(MARGOLIS_EVEN)
}
}
void
n_margolis_ph(Cam *cam)
{
register Byte i;
/* 0 1 2 3 4 5 6 7 8 9 */
/* c c' cw ccw opp cw' ccw' opp' pha pha' */
/* 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 */
#define MARGOLIS_ODD_PH (MARGOLIS_ODD | 0x100)
#define MARGOLIS_EVEN_PH (MARGOLIS_EVEN | 0x200)
if (cam->phase) {
CAM_TABLE_LOOP(MARGOLIS_ODD_PH)
} else {
CAM_TABLE_LOOP(MARGOLIS_EVEN_PH)
}
}
void
n_margolis_hv(Cam *cam)
{
register Byte i;
/* 0 1 2 3 4 5 6 7 8 9 */
/* c c' cw ccw opp cw' ccw' opp' horz vert */
/* 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 */
#define MARGOLIS_ODD_HV (MARGOLIS_ODD | ((x&1)<<8) | ((y&1)<<9))
#define MARGOLIS_EVEN_HV (MARGOLIS_EVEN | ((x&1)<<8) | ((y&1)<<9))
if (cam->phase) {
CAM_TABLE_LOOP(MARGOLIS_ODD_HV)
} else {
CAM_TABLE_LOOP(MARGOLIS_EVEN_HV)
}
}
void
n_life(Cam *cam)
{
int s;
#define LIFE ( \
((CENTER&1) ? (((s = SUM8) == 2) || (s == 3)) \
: (SUM8 == 3)) | \
(CENTER<<1) \
)
CAM_LOOP(LIFE)
}
void
n_brain(Cam *cam)
{
int s;
#define BRAIN ( \
(((((s = CENTER)&3) == 0) && (SUM8 == 2)) ? 1 : 0) | \
(s<<1) \
)
CAM_LOOP(BRAIN)
}
void
n_heat(Cam *cam)
{
int frob = cam->frob;
#define HEAT ( \
((QUAD)(NORTHWEST + NORTH + NORTHEAST + \
WEST + EAST + \
SOUTHWEST + SOUTH + SOUTHEAST + frob)) >> 3 \
)
CAM_LOOP(HEAT)
}
void
n_dheat(Cam *cam)
{
int frob = cam->frob;
int last = 0;
#define DHEAT \
last += NORTHWEST + NORTH + NORTHEAST + \
WEST + frob + EAST + \
SOUTHWEST + SOUTH + SOUTHEAST; \
*front = last >> 3; \
last &= 7;
CAM_LOOP_BODY(DHEAT)
}
void
n_lheat(Cam *cam)
{
int frob = cam->frob;
#define LHEAT ( \
((QUAD)(NORTH + WEST + EAST + SOUTH + frob)) >> 2 \
)
CAM_LOOP(LHEAT)
}
void
n_ldheat(Cam *cam)
{
int frob = cam->frob;
int last; /* I meant to do that! */
#define LDHEAT ( \
((last = (QUAD)(NORTH + WEST + EAST + SOUTH + frob \
+ (last&0x03))), last >> 2) \
)
CAM_LOOP(LDHEAT)
}
void
n_abdheat(Cam *cam)
{
int frob = cam->frob;
int lasta = 0, lastb = 0; /* I meant to do that! */
#define YUM(x) (((QUAD)(x))&0x0f)
#define YUK(x) (((QUAD)(x))&0xf0)
#define ABDHEAT ( \
(lasta = (QUAD)(YUM(NORTHWEST) + YUM(NORTH) + YUM(NORTHEAST) + \
YUM(WEST) + YUM(EAST) + \
YUM(SOUTHWEST) + YUM(SOUTH) + YUM(SOUTHEAST) + \
frob + (lasta&0x07))), \
(lastb = (QUAD)(YUK(NORTHWEST) + YUK(NORTH) + YUK(NORTHEAST) + \
YUK(WEST) + YUK(EAST) + \
YUK(SOUTHWEST) + YUK(SOUTH) + YUK(SOUTHEAST) + \
(frob<<4) + (lastb&0x70))), \
(((lasta>>3)&0x0f) | ((lastb>>3)&0xf0)) \
)
CAM_LOOP(ABDHEAT)
}
void
n_abcdheat(Cam *cam)
{
int last;
int frob = cam->frob;
CAM_LOOP(HEAT)
}
void
n_edheat(Cam *cam)
{
int frob = cam->frob;
int last = 0;
#define EDHEAT ( \
(last = (QUAD)(YUM(NORTHWEST) + YUM(NORTH) + YUM(NORTHEAST) + \
YUM(WEST) + YUM(EAST) + \
YUM(SOUTHWEST) + YUM(SOUTH) + YUM(SOUTHEAST) + \
frob + (last&0x07))), \
(((last>>3)&0x0f) | ((CENTER<<4)&0xf0)) \
)
CAM_LOOP(EDHEAT)
}
int ranch(QUAD l0, QUAD l1, QUAD l2)
{
int s = SUM8;
int v = SUM9p(1);
int o = 0;
o = (CENTER&4)<<1;
if (v < 4 || v == 5) {
o |= 0x04;
} else {
}
return (o);
}
void
n_ranch(Cam *cam)
{
#define RANCH ranch(l0, l1, l2)
CAM_LOOP(RANCH)
}
void
n_anneal(Cam *cam)
{
int s;
#define ANNEAL ( \
((s = SUM9) > 5) || (s == 4) \
)
CAM_LOOP(ANNEAL)
}
void
n_anneal4(Cam *cam)
{
int s;
#define ANNEAL4 ( \
((((s = SUM9p(0)) > 5) || (s == 4)) ? 1 : 0) | \
((((s = SUM9p(1)) > 5) || (s == 4)) ? 2 : 0) | \
((((s = SUM9p(2)) > 5) || (s == 4)) ? 4 : 0) | \
((((s = SUM9p(3)) > 5) || (s == 4)) ? 8 : 0) | \
(CENTER << 4) \
)
CAM_LOOP(ANNEAL4)
}
void
n_anneal8(Cam *cam)
{
int s;
#define ANNEAL8 ( \
((((s = SUM9p(0)) > 5) || (s == 4)) ? 1 : 0) | \
((((s = SUM9p(1)) > 5) || (s == 4)) ? 2 : 0) | \
((((s = SUM9p(2)) > 5) || (s == 4)) ? 4 : 0) | \
((((s = SUM9p(3)) > 5) || (s == 4)) ? 8 : 0) | \
((((s = SUM9p(4)) > 5) || (s == 4)) ? 16 : 0) | \
((((s = SUM9p(5)) > 5) || (s == 4)) ? 32 : 0) | \
((((s = SUM9p(6)) > 5) || (s == 4)) ? 64 : 0) | \
((((s = SUM9p(7)) > 5) || (s == 4)) ? 128 : 0) \
)
CAM_LOOP(ANNEAL8)
}
void
n_eco(Cam *cam)
{
int s;
#define ANTILIFE ( \
((CENTER&1) ? (SUM8 != 5) \
: (((s = SUM8) != 5) && (s != 6))) | \
(CENTER<<1) \
)
#define ECO ( \
(((s = SUM9p(7)) > 5) || (s == 4) ? 128 : 0) | \
((CENTER&128) ? ((ANTILIFE)&127) : ((BRAIN)&127)) \
)
CAM_LOOP(ECO)
}
void
n_torben(Cam *cam)
{
int s;
/* 0 0 0 1 0 1 0 1 1 1 */
#define TORBEN ( \
(CENTER << 1) | ((((s = SUM9) > 6) || (s == 5) || (s == 3)) ? 1 : 0) \
)
CAM_LOOP(TORBEN)
}
void
n_torben2(Cam *cam)
{
int s;
/* 0 0 0 1 0 1 0 1 1 1 */
/* 0 0 1 0 1 0 1 0 1 1 */
#define TORBEN2 ( \
TORBEN | (CENTER <<1) \
)
CAM_LOOP(TORBEN2)
}
void
n_torben3(Cam *cam)
{
int s;
/* 0 0 0 1 1 0 0 1 1 1 */
#define TORBEN3 ( \
((s = SUM9) > 6) || (s == 3) || (s == 4) \
)
CAM_LOOP(TORBEN3)
}
void
n_torben4(Cam *cam)
{
int s;
/* 0 0 0 1 0 1 0 1 1 1 */
/* 0 0 1 0 1 0 1 0 1 1 */
#define TORBEN4 ( \
TORBEN3 | (CENTER <<1) \
)
CAM_LOOP(TORBEN4)
}
void
n_ball(Cam *cam)
{
char p = (cam->phase ? 1 : 0);
int x, y, r = Rand16();
int backline = cam->back->line_bytes,
frontline = cam->front->line_bytes;
Byte *back = cam->back->mem,
*front = cam->front->mem;
if (!p) {
back += 1 + backline;
}
for (y = p + (cam->height >>1); y > 0; y--) {
for (x = p + (cam->width >>1); x > 0; x--) {
Byte nw = back[0], ne = back[1],
sw = back[backline], se = back[backline+1];
r += nw + ne + sw + sw; r >>= 1;
switch ((nw&1) + (ne&1) + (sw&1) + (se&1)) {
case 0:
case 3:
case 4:
/* same */
back[0] = nw; back[1] = ne;
back[backline] = sw; back[backline+1] = se;
break;
case 1:
/* reflect */
back[0] = se; back[1] = sw;
back[backline] = ne; back[backline+1] = nw;
break;
case 2:
/* turn */
switch (((nw&1) <<3) | ((ne&1) <<2) | ((sw&1) <<1) | (se&1)) {
case 6:
case 9:
if (r&1) {
/* clockwise */
back[0] = sw; back[1] = nw;
back[backline] = se; back[backline+1] = ne;
} else {
/* counterclockwise */
back[0] = ne; back[1] = se;
back[backline] = nw; back[backline+1] = sw;
}
default:
back[0] = nw; back[1] = ne;
back[backline] = sw; back[backline+1] = se;
break;
}
break;
}
back += 2;
}
back += backline + backline - cam->width - (2*p);
}
back = cam->back->mem + backline + 1,
front = cam->front->mem;
for (y = cam->height; y > 0; y--) {
memcpy(front, back, cam->width);
back += backline;
front += frontline;
}
}
void
n_logic(Cam *cam)
{
char p = (cam->phase ? 1 : 0);
int x, y;
int backline = cam->back->line_bytes,
frontline = cam->front->line_bytes;
Byte tmp;
Byte *back = cam->back->mem,
*front = cam->front->mem;
/* bit 8 is center' */
/* bit 7 is center */
if (cam->phase) {
back += 1 + backline;
front += 1 + frontline;
}
for (y = cam->height >>1; y > 0; y--) {
for (x = cam->width >>1; x > 0; x--) {
Byte nw = back[0], ne = back[1],
sw = back[backline], se = back[backline+1];
switch (((nw&128) >>4) | ((ne&128) >>5) |
((sw&128) >>6) | ((se&128) >>7)) {
case 0:
break;
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
case 10:
break;
case 11:
break;
case 12:
break;
case 13:
break;
case 14:
break;
case 15:
tmp = nw; nw = se; se = tmp;
tmp = sw; ne = sw; sw = tmp;
break;
}
back += 2; front += 2;
}
back += backline + backline - cam->width;
front += frontline + frontline - cam->width;
}
back = cam->back->mem + backline + 1,
front = cam->front->mem;
for (y = cam->height; y > 0; y--) {
memcpy(front, back, cam->width);
back += backline;
front += frontline;
}
}
void
n_party(Cam *cam)
{
#define PARTY (CENTER ^ NORTH ^ SOUTH ^ EAST ^ WEST)
CAM_LOOP(PARTY)
}
vf neighborhoods[] = {
/* 0 1 2 3 */
&n_moore_a, &n_moore_a, &n_moore_ab, &n_vonn_neumann,
/* 4 5 6 */
&n_margolis, &n_margolis_ph, &n_margolis_hv,
/* 7 8 9 10 11 12 */
&n_life, &n_brain, &n_heat, &n_dheat, &n_lheat, &n_ldheat,
/* 13 14 15 16 17 */
&n_ranch, &n_anneal, &n_anneal4, &n_anneal8, &n_eco,
/* 18 19 20 21 22 */
&n_abdheat, &n_edheat, &n_abcdheat, &n_torben, &n_torben2,
/* 23 24 25 26 27 */
&n_torben3, &n_torben4, &n_ball, &n_logic, &n_party
};
cam_set_neighborhood(Cam *cam, int code)
{
cam->neighborhood = neighborhoods[code];
}
cam_load_rule(Cam *cam, char *filename)
{
FILE *fp;
QUAD magic, neighborhood, rule_size;
Byte *rule;
if ((fp = fopen(filename, "r")) == NULL) {
fprintf(stderr, "cam: Can't open rule file \"%s\"\n", filename);
return;
}
/* XXX: Make this byte order independent!!! */
#if defined(MSDOS) || defined(OSF1) || defined(IS_INTEL)
#define SWAPQUAD(x) ((x = ((x <<24) & 0xff000000) | \
((x <<8) & 0x00ff0000) | \
((x >>8) & 0x0000ff00) | \
((x >>24) & 0x000000ff)), 0)
#else
#define SWAPQUAD(x) 0
#endif
if ((fread(&magic, 1, sizeof(QUAD), fp) != sizeof(QUAD)) ||
SWAPQUAD(magic) ||
(magic != 0xcac0cac0) ||
(fread(&neighborhood, 1, sizeof(QUAD), fp) != sizeof(QUAD)) ||
SWAPQUAD(neighborhood) ||
(fread(&rule_size, 1, sizeof(QUAD), fp) != sizeof(QUAD)) ||
SWAPQUAD(rule_size) ||
((rule = (Byte *)malloc(rule_size)) == NULL) ||
(fread(rule, 1, rule_size, fp) != rule_size)) {
fprintf(stderr, "cam: Bad rule file \"%s\"\n", filename);
fclose(fp);
return;
}
fclose(fp);
if (cam->rule != NULL)
free(cam->rule);
cam->rule = rule;
cam->rule_size = rule_size;
cam_set_neighborhood(cam, neighborhood);
}
Cam *
find_cam(SimCam *scam, int x, int y)
{
Cam *cam;
for (cam = scam->cam_list; cam != NULL; cam = cam->next) {
if ((x >= cam->x) &&
(y >= cam->y) &&
(x < cam->x + cam->width) &&
(y < cam->y + cam->height)) {
break;
}
}
return cam;
}
Cam *
find_cam_by_name(SimCam *scam, char *name)
{
Cam *cam;
for (cam = scam->cam_list; cam != NULL; cam = cam->next) {
if ((cam->name != NULL) &&
(strcmp(name, cam->name) == 0)) {
return cam;
}
}
return NULL;
}
Cam *
get_cam_number(SimCam *scam, int i)
{
Cam *cam;
for (cam = scam->cam_list;
(i != 0) && (cam != NULL);
(i--), (cam = cam->next)) ;
return cam;
}
cam_layout(SimCam *scam)
{
int x, y, gap, border, maxwidth, lastmax;
Cam *cam;
border = 8;
gap = 8;
x = border; y = border;
maxwidth = lastmax = gap;
for (cam = scam->cam_list; cam != NULL; cam = cam->next) {
cam->dx = 0; cam->dy = 0;
if (cam->width > maxwidth) {
lastmax = maxwidth;
maxwidth = cam->width;
}
if (y + cam->height + border > scam->w_height) {
y = border; x = x + maxwidth + gap;
maxwidth = lastmax = gap;
}
if ((x + cam->width > scam->w_width) ||
(y + cam->height > scam->w_height)) {
cam->x = 0; cam->y = 0;
cam->front->mem = (Byte *)scam->data;
maxwidth = lastmax;
} else {
cam->x = x; cam->y = y;
cam->front->mem =
scam->data + x + (scam->line_bytes * y);
y = y + cam->height + gap;
}
}
}
init_scam(SimCam *scam)
{
scam_randomize(scam);
}
handle_scam(SimCam *scam)
{
Cam *cam;
for (cam = scam->cam_list; cam != NULL; cam = cam->next) {
cam_do_rule(scam, cam);
}
}
#endif /* CAM */