[cairo-commit] cairo-demo/gameoflife README,NONE,1.1 cgol.cpp,NONE,1.1 cgol.h,NONE,1.1 cgolwin.cpp,NONE,1.1 cgolwin.h,NONE,1.1 ctk.cpp,NONE,1.1 ctk.h,NONE,1.1 main.cpp,NONE,1.1 Makefile,1.2,1.3 gameoflife.cpp,1.2,NONE qblabel.h,1.1,NONE wmtricks.h,1.1,NONE
Andrew Chant
commit at pdx.freedesktop.org
Mon Nov 24 18:06:58 PST 2003
Committed by: chant
Update of /cvs/cairo/cairo-demo/gameoflife
In directory pdx:/tmp/cvs-serv31180
Modified Files:
Makefile
Added Files:
README cgol.cpp cgol.h cgolwin.cpp cgolwin.h ctk.cpp ctk.h
main.cpp
Removed Files:
gameoflife.cpp qblabel.h wmtricks.h
Log Message:
Rewrite, seperate game logic from graphics code from X handling code.
Looks nice. Always in colour.
Beware - can hog CPU.
--- NEW FILE: README ---
Hi,
this is my version of Conway's game of life.
I came up with the algorithm while bored in lecture.
I'm sure the implementation is not original, nor is it optimal.
It uses cairo for the drawing operations, double buffered
using pixmaps. All cairo ops are in 'cgolwin.cpp', in the
render function.
the game of life code itself is seperate, and is in cgol.h/cpp.
only thing is that cgolwin.cpp expects its list of cells back
in the proper format.
Any questions/comments/patches should go to
andrew.chant at utoronto.ca
--- NEW FILE: cgol.cpp ---
/* cgol.cpp
* - implementation of gameoflife class
* (c) 2003 Andrew Chant
* licensed under GPL
*
* This file is part of cgol.
cgol 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 2 of the License, or
(at your option) any later version.
cgol 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 cgol; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cgol.h"
#include <iostream>
using std::cout;
using std::endl;
gameoflife::gameoflife(int r, int c)
{
rows = r;
cols = c;
srand(time(NULL));
/* create board layout structures */
score = (unsigned int *)malloc(rows*cols*sizeof(unsigned int));
cells = new list<struct cell>;
/* initialize to random */
for (int x = 0; x < cols; x++)
for (int y = 0; y < rows; y++)
if (random() % 2)
{
cell newcell;
newcell.x = x;
newcell.y = y;
newcell.dna = ALIVE; // 1st gen black
cells->push_back(newcell);
}
}
void gameoflife::advance()
{
/* clear score matrix */
memset(score,0,rows*cols*sizeof(unsigned int));
/* take list of 'live' cells, traverse, create score matrix */
for (list<struct cell>::iterator i = cells->begin();
i != cells->end(); i++)
{
score[i->y*cols + i->x] += i->dna; // mark alive & color
// there has got to be a more efficient way of doing
// scoring
if (i->y > 0) // go above one
{
//up is ok
score[(i->y-1)*cols + i->x] +=1;
if (i->x > 0) // up & left ok
score[(i->y-1)*cols + i->x - 1 ] +=1;
if (i->x + 1 < cols) // up & right ok
score[(i->y-1)*cols + i->x + 1] +=1;
}
if (i->x > 0) // left ok
score[i->y*cols + i->x -1] +=1;
if (i->x + 1 < cols) // right ok
score[i->y*cols + i->x +1] +=1;
if ( (i->y + 1) < rows) // go down one
{
// down is ok
score[(i->y +1) * cols + i->x] +=1;
if (i->x > 0) // down & left ok
score[(i->y + 1) * cols + i->x -1] +=1;
if (i->x + 1 < cols) // down & right ok
score[(i->y + 1) * cols + i->x + 1] +=1;
}
}
/* create new cell color (dna) for this round */
unsigned int currdna = ALIVE;
if (random() % 2) currdna |= R1;
if (random() % 2) currdna |= R2;// red comp
if (random() % 2) currdna |= B1;
if (random() % 2) currdna |= B2;
if (random() % 2) currdna |= G1;
if (random() % 2) currdna |= G2;
/* from score matrix, create a new list of live cells */
list<struct cell> * newcells = new list<struct cell>;
for (int i = 0; i < rows * cols; i++)
{ // cases: if score[i] == 3, score[i] & DNAMASK != 0
if (score[i] == 3)
{
cell newcell;
newcell.x = i % cols;
newcell.y = i / cols;
newcell.dna = currdna;
newcells->push_back(newcell);
}
else if ( (score[i] & ALIVE) && ( ((score[i] & ~DNAMASK) == 2) || ((score[i] & ~DNAMASK) == 3)) )
{
cell newcell;
newcell.x = i % cols;
newcell.y = i / cols;
newcell.dna = score[i] & DNAMASK;
newcells->push_back(newcell);
}
}
/* replace old list with new list */
delete cells;
cells = newcells;
}
list<struct cell> * gameoflife::getboard()
{
/* return current list of live cells */
// cout << "returning " << cells->size() << " cells\n";
return cells;
}
/*
int main (void)
{
gameoflife MyGame(200,300);
list<struct cell> * rval = MyGame.getboard();
while (rval->begin() != rval->end())
{
MyGame.advance();
rval = MyGame.getboard();
}
return 0;
} */
--- NEW FILE: cgol.h ---
/* cgol.h
* - defines gameoflife class & helpers
* (c) 2003 Andrew Chant
* licensed under GPL
*
* This file is part of cgol.
cgol 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 2 of the License, or
(at your option) any later version.
cgol 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 cgol; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CGOL_H
#define CGOL_H
#include <list>
using std::list;
/*
class myapp: public ctkapp()
{
public:
myapp();
void eventloop(void);
};
*/
/* cell structure for use by gameoflife */
struct cell
{
unsigned int dna; // alive & color
int x;
int y;
};
/* provide the logic for game of life */
class gameoflife
{
public:
gameoflife(int,int);
void advance();
list<struct cell> * getboard();
private:
int rows, cols;
unsigned int * score;
list<struct cell> * cells;
};
const unsigned int R1 = (1 << 4);
const unsigned int R2 = (1 << 5);
const unsigned int B1 = (1 << 6);
const unsigned int B2 = (1 << 7);
const unsigned int G1 = (1 << 8);
const unsigned int G2 = (1 << 9);
const unsigned int ALIVE = (1 << 10);
const unsigned int DNAMASK = R1 | R2 | B1 | B2 | G1 | G2 | ALIVE;
#endif // CGOL_H
--- NEW FILE: cgolwin.cpp ---
/* cgolwin.cpp
* - implementation of gameoflifeWin
* - render does most of the important stuff
* - event takes the X events
*
* (c) 2003 Andrew Chant
* licensed under GPL
*
* This file is part of cgol.
cgol 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 2 of the License, or
(at your option) any later version.
cgol 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 cgol; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cairo-xlib.h>
#include <math.h>
#include <iostream>
#include <assert.h>
#include "cgolwin.h"
using std::cout;
gameoflifeWin::gameoflifeWin(Ctkapp * app, int wi, int h, int r, int c)
:Ctkwin(app,wi,h)
{
rows = r;
cols = c;
width = wi;
height = h;
game = new gameoflife(rows, cols);
cr = cairo_create();
XGCValues xgcv;
// Helps prevent *some* choking on opaque resize
xgcv.graphics_exposures = false;
gc = XCreateGC(dpy, w, GCGraphicsExposures, &xgcv);
XSetForeground(dpy, gc, WhitePixel(dpy, DefaultScreen(dpy)));
// MAX 24 fps, really just means 1/24 s between advancements
app->regtimer(0,1000000/24,-1,advanceTimer, (void *)this);
buffer = grid = 0;
}
void gameoflifeWin::event(XEvent * e)
{
switch (e->type)
{
case Expose:
if (((XExposeEvent *)e)->count == 0) // NOT RELIABLE :(
{
if (!XPending(dpy)) //This is an ugly hack
render();
}
break;
case ConfigureNotify:
width = ((XConfigureEvent *)e)->width;
height = ((XConfigureEvent *)e)->height;
if (grid != 0)
{
XFreePixmap(dpy, grid);
XFreePixmap(dpy, buffer);
buffer = grid = 0;
}
break;
default:
//cout << "Unhandled Event " << e->type << "\n";
;
}
}
void gameoflifeWin::advanceTimer(void * obj)
{
gameoflifeWin * game = (gameoflifeWin *)obj;
game->game->advance(); // yeah ok bad naming shoot me
game->render();
}
void gameoflifeWin::render()
{
if (grid == 0)
{ // new or resized
cellwidth = (double)width / (double)cols;
cellheight = (double) height / (double) rows;
cairo_set_line_width(cr, (cellwidth + cellheight) / 20.0);
radius = (cellwidth > cellheight) ? cellheight : cellwidth;
radius /= 2.0;
radius -= .5;
grid = XCreatePixmap(dpy, w, width, height, DefaultDepth(dpy, DefaultScreen(dpy)));
buffer = XCreatePixmap(dpy, w, width, height, DefaultDepth(dpy, DefaultScreen(dpy)));
/* draw the grid into a pixmap which can be copied over the buffer each cycle */
XFillRectangle(dpy, grid, gc, 0, 0, width, height);
cairo_set_target_drawable(cr, dpy, grid);
cairo_set_rgb_color(cr, .7, .7, .7);
for (int col = 0; col <= cols; col++)
{
cairo_move_to(cr, col*cellwidth, 0);
cairo_rel_line_to(cr, 0, cellheight * rows);
}
for (int row = 0; row <= rows; row++)
{
cairo_move_to(cr, 0, row*cellheight);
cairo_rel_line_to(cr, cellwidth*cols, 0);
}
cairo_stroke(cr);
cairo_set_rgb_color(cr, 0, 0, 0);
}
cells = game->getboard();
XCopyArea(dpy, grid, buffer, gc, 0, 0, width, height, 0, 0);
cairo_set_target_drawable(cr, dpy, buffer);
for (list<struct cell>::const_iterator i = cells->begin();
i != cells->end(); i++)
{
double red,green,blue;
red = green = blue = 0;
//Note colour weighting avoids white (Max .75 of each)
if (i->dna & B1) blue += .50;
if (i->dna & B2) blue += .25;
if (i->dna & R1) red += .50;
if (i->dna & R2) red += .25;
if (i->dna & G1) green += .50;
if (i->dna & G2) green += .25;
cairo_set_rgb_color(cr, red, green, blue);
cairo_arc(cr, cellwidth*(i->x + .5), cellheight * (i->y + .5), radius, 0, 2*M_PI);
cairo_fill(cr);
}
cairo_set_rgb_color(cr, 0, 0, 0);
XCopyArea(dpy, buffer, w, gc, 0, 0, width, height, 0, 0);
XFlush(dpy);
}
--- NEW FILE: cgolwin.h ---
/* cgolwin.h
* - gameoflifeWin class described
* - uses homebrew 'ctk' toolkit
* (c) 2003 Andrew Chant
* licensed under GPL
*
* This file is part of cgol.
cgol 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 2 of the License, or
(at your option) any later version.
cgol 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 cgol; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ctk.h"
#include "cgol.h"
#include <cairo.h>
class gameoflifeWin : public Ctkwin
{
public:
gameoflifeWin(Ctkapp *, int, int, int, int);
void event(XEvent *);
static void advanceTimer(void *);
void render();
//These two really shouldn't be private
//but need to be accessed from a passed pointer to this
//given to advanceTimer. I really need to find a better way
//of kludging timers.
list<struct cell> * cells;
gameoflife * game;
private:
Pixmap grid, buffer, cellpix;
cairo * cr;
int rows, cols, width, height;
double cellheight, cellwidth;
double radius;
GC gc;
};
--- NEW FILE: ctk.cpp ---
/* ctk.cpp
* - implementation of ctk
* 'crappy toolkit'
* s/crappy/chant
* (c) 2003 Andrew Chant
* licensed under GPL
*
* This file is part of cgol.
cgol 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 2 of the License, or
(at your option) any later version.
cgol 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 cgol; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* C++ Xlib skeleton */
/* Main class takes a pointer to a fn for the main loop
* and you can add timers */
#include <X11/Xlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include "ctk.h"
Ctkapp::Ctkapp()
{
dpy = XOpenDisplay(NULL);
assert(dpy != NULL);
timeout = NULL;
}
void Ctkapp::reg(Ctkwin * cw)
{
//Add w to list of windows to monitor
windows.push_back(cw);
}
void Ctkapp::regtimer(int s, int us, int reps, void fn (void *), void * obj)
{
// append a timer struct onto the end of the list
timers.push_back(Ctktimer(s,us,reps,fn, obj));
if (timeout == NULL)
timeout = new struct timeval;
}
void Ctkapp::setTimeout(void)
{
if (timeout == NULL)
return;
list<Ctktimer>::const_iterator min = timers.begin();
for (list<Ctktimer>::const_iterator i = ++(timers.begin()); i != timers.end(); i++)
if (*i < *min)
min = i;
timeout->tv_sec = min->rem.tv_sec;
timeout->tv_usec = min->rem.tv_usec;
}
void Ctkapp::updateTimers(void)
{
for (list<Ctktimer>::iterator i = timers.begin(); i != timers.end(); ++i)
{
i->rem.tv_sec -= timeout->tv_sec;
i->rem.tv_usec -= timeout->tv_usec;
if (i->rem.tv_usec < 0)
{
i->rem.tv_usec += 1000000;
i->rem.tv_sec -=1;
}
if (i->rem.tv_sec < 0)
i->rem = i->full;
if ((i->rem.tv_sec == 0) && (i->rem.tv_usec == 0))
i->rem = i->full;
}
}
int Ctkapp::go(void)
{
int result;
while(1)
{
setTimeout();
FD_ZERO(&reads);
FD_SET(ConnectionNumber(dpy), &reads);
result = select(ConnectionNumber(dpy)+1, &reads, NULL, NULL, timeout);
if (result > 0)
{
while (XPending(dpy) != 0)
{
XNextEvent(dpy, &e);
(*(windows.begin()) )->event(&e);
}
//send off event to proper window.
} else if (result == 0)
{
timers.begin()->fn(timers.begin()->obj); // Timer Expired
timers.begin()->rem = timers.begin()->full;
if (timers.begin()->reps >= 0)
{
if (--timers.begin()->reps < 0)
timers.erase(timers.begin()); ;
}
}
else {
return 1;
}
updateTimers();
}
}
Ctkwin::Ctkwin(Ctkapp * theApp, int width, int height)
{
app = theApp;
dpy = app->getDisplay();
XSetWindowAttributes attribs;
attribs.background_pixel = WhitePixel(dpy, DefaultScreen(dpy));
w = XCreateWindow(dpy, /* display */
DefaultRootWindow(dpy),
0,0,width,height, /* x,y,w,h */
0, /* border width */
CopyFromParent, /* depth */
InputOutput, /* type */
CopyFromParent, /* visualtype */
CWBackPixel, /* valuemask */
&attribs); /* values */
XSelectInput(dpy, w, StructureNotifyMask | ExposureMask);
XStoreName(dpy, w, "Goodbye Cruel World");
decorate();
XMapWindow(dpy, w);
app->reg(this);
}
void Ctkwin::decorate()
{
Atom bomb = XInternAtom(dpy, "_MOTIF_WM_HINTS", 1);
struct mwmhints_t {
unsigned int flags;
unsigned int functions;
unsigned int decorations;
int input_mode;
unsigned int status;
} mwmhints;
mwmhints.decorations = mwmhints.functions = (1l << 0);
mwmhints.flags = (1l << 0) | (1l << 1);
XChangeProperty(dpy,w,bomb,bomb,32,PropModeReplace,(unsigned char *)&mwmhints, sizeof(mwmhints)/sizeof(long));
return;
}
Ctktimer::Ctktimer(int s, int us, int repeats, void function(void *), void * object)
{
full.tv_sec = s;
full.tv_usec = us;
rem.tv_sec = full.tv_sec;
rem.tv_usec = full.tv_usec;
reps = repeats;
fn = function;
obj = object;
}
bool Ctktimer::operator< (const Ctktimer other) const
{
if (this->rem.tv_sec < other.rem.tv_sec)
return true;
else if (this->rem.tv_sec > other.rem.tv_sec)
return false;
else if (this->rem.tv_usec < other.rem.tv_usec)
return true;
else
return false;
}
void timedfn();
/*
int main(int argc, char ** argv)
{
Ctkapp myapp;
Ctkwin mywin(&myapp,100,100);
// myapp.regtimer(1,0,-1, timedfn, NULL);
myapp.go();
return 0;
}
*/
--- NEW FILE: ctk.h ---
/* ctk.h -
* - description of 'crappy toolkit' classes
* s/crappy/chant
* (c) 2003 Andrew Chant
* licensed under GPL
*
* This file is part of cgol.
cgol 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 2 of the License, or
(at your option) any later version.
cgol 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 cgol; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CTK_H
#define CTK_H
#include <X11/Xlib.h>
#include <sys/select.h>
#include <sys/times.h>
#include <unistd.h>
#include <list>
using std::list;
class Ctkwin;
class Ctktimer
{
public:
Ctktimer (int, int, int, void (void *), void *);
struct timeval full;
struct timeval rem;
int reps;
void (*fn)(void *);
void * obj;
bool operator< (const Ctktimer) const;
};
class Ctkapp
{
public:
Ctkapp();
int go(void);
void reg(Ctkwin *);
void regtimer(int, int, int, void (void *), void *);
Display *const getDisplay(void) {return dpy;};
private:
void event(XEvent *);
void setTimeout(void);
void updateTimers(void);
list <Ctkwin *> windows;
list <Ctktimer> timers;
//Xlib related stuff
XEvent e;
Display * dpy;
//For select
struct timeval * timeout;
fd_set reads;
};
class Ctkwin
{
public:
Ctkwin(Ctkapp *, int, int);
Window getw(void) {return w;};
virtual void event(XEvent *)=0;
protected:
Ctkapp * app;
Display *dpy;
Window w;
void decorate();
};
#endif // CTK_H
--- NEW FILE: main.cpp ---
/* main.cpp
* - throws all the objects together
* (c) 2003 Andrew Chant
* licensed under GPL
*
* This file is part of cgol.
cgol 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 2 of the License, or
(at your option) any later version.
cgol 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 cgol; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <iostream>
#include "cgolwin.h"
#include "ctk.h"
using std::cout;
using std::endl;
void usage(char * name)
{
std::cout << "Usage: " << name << " [-w width] [-h height] [-c columns] [-r rows]\n";
}
int main(int argc, char * argv[])
{
int width = 200;
int height = 200;
int rows = 20;
int cols = 20;
char action;
int traverse = 0;
while (++traverse < argc)
{
if (argv[traverse][0] == '-')
action = argv[traverse][1];
else
action = argv[traverse][0];
switch(action)
{
case 'w':
if (++traverse > argc)
{
usage(argv[0]);
exit(0);
}
width = atoi(argv[traverse]);
break;
case 'h':
if (++traverse > argc)
{
usage(argv[0]);
exit(0);
}
height = atoi(argv[traverse]);
break;
case 'r':
if (++traverse > argc)
{
usage(argv[0]);
exit(0);
}
rows = atoi(argv[traverse]);
break;
case 'c':
if (++traverse > argc)
{
usage(argv[0]);
exit(0);
}
cols = atoi(argv[traverse]);
break;
default:
usage(argv[0]);
exit(0);
break;
}
}
Ctkapp myapp;
gameoflifeWin mywin(&myapp,width,height, rows, cols);
myapp.go();
return 0;
}
Index: Makefile
===================================================================
RCS file: /cvs/cairo/cairo-demo/gameoflife/Makefile,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** Makefile 18 Nov 2003 14:32:38 -0000 1.2
--- Makefile 25 Nov 2003 02:06:56 -0000 1.3
***************
*** 1,7 ****
! all: gameoflife
! gameoflife: gameoflife.cpp
! g++ -g -Wall -I/usr/include/X11/Xft -I/usr/include/freetype2 -L/usr/X11R6/lib -lX11 -lXft -lcairo -o gameoflife gameoflife.cpp
clean:
! rm -f gameoflife
--- 1,7 ----
! all: cgol
! cgol: cgol.cpp ctk.cpp main.cpp cgolwin.cpp ctk.h cgolwin.h cgol.h
! g++ -Wall -o cgol cgol.cpp main.cpp ctk.cpp cgolwin.cpp -L/usr/X11R6/lib -lX11 -I/usr/include/X11/Xft -I/usr/include/freetype2 -lcairo
clean:
! rm -f cgol
--- gameoflife.cpp DELETED ---
--- qblabel.h DELETED ---
--- wmtricks.h DELETED ---
More information about the cairo-commit
mailing list