home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Supergames for Windows 3
/
wingames3.zip
/
wingames3
/
U-Z
/
YALIFE
/
LIFE.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-08
|
13KB
|
425 lines
// (c) Jean MICHEL June 1993 -- any modifications must be signaled to the
// author
// Class TLifeWindow is for the main program window
#include <stdio.h>
#include <stdlib.h>
#include <owl.h>
#include <commdlg.h>
#include <dir.h>
#include <io.h>
#include <string.h>
#include <filedial.h>
#include <static.h>
#include "efns.h"
#include "cell.h"
#include "shapewnd.h"
#include "life.h"
HPEN Pens[3]; HBRUSH Brushes[3];
COLORREF Colors[3];
class TLife : public TApplication
{
public:
TLife(LPSTR AName, HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
: TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {};
virtual void InitMainWindow();
};
_CLASSDEF(TLifeWindow)
class TLifeWindow : public TWindow
{
public:
cellpop v;
cell_type box_start,box_end;
BOOL drawing;
HDC DrawDC;
int magnification;
RECT ScrollRange;
long gencounter;
struct {long x;long y;}origin;// Logical coordinates of top left
void setorigin();
void info();
void DrawBox();
void Run(long count);
cell_type coordtocell(TMessage::tagLP);
int update(cellpop& w);
void pixel(HDC DC,cell_type c,int color);
char *GetFileName();
TLifeWindow(PTWindowsObject AParent, LPSTR ATitle);
~TLifeWindow();
void adjustscroll(int newmag);
virtual void SetupWindow();
virtual void Paint(HDC DC, PAINTSTRUCT& PS);
virtual void WMLButtonDown(RTMessage Msg)
= [WM_FIRST + WM_LBUTTONDOWN];
virtual void WMRButtonDown(RTMessage Msg)
= [WM_FIRST + WM_RBUTTONDOWN];
virtual void WMRButtonUp(RTMessage Msg)
= [WM_FIRST + WM_RBUTTONUP];
virtual void WMMouseMove(RTMessage Msg)
= [WM_FIRST + WM_MOUSEMOVE];
virtual void CMShape(RTMessage Msg)
= [CM_FIRST + CM_SHAPE];
virtual void CMUFileSave(RTMessage Msg)
= [CM_FIRST + CM_U_FILESAVEAS];
virtual void CMUFileSaveArea(RTMessage Msg)
= [CM_FIRST + CM_U_FILESAVEAREAAS];
virtual void CMErase(RTMessage Msg)
= [CM_FIRST + CM_ERASE];
virtual void CMColorSet(RTMessage Msg)
= [CM_FIRST + CM_COLOR_SET];
virtual void CMColorReset(RTMessage Msg)
= [CM_FIRST + CM_COLOR_RESET];
virtual void CMColorUnset(RTMessage Msg)
= [CM_FIRST + CM_COLOR_UNSET];
virtual void CMClearGen(RTMessage Msg)
= [CM_FIRST + CM_CLEAR_GEN];
void CMUColor(int index);
virtual void CMFileNew(RTMessage Msg)
= [CM_FIRST + CM_FILENEW];
virtual void CMHelp(RTMessage Msg)
= [CM_FIRST + CM_HELP];
virtual void CMHelphelp(RTMessage Msg)
= [CM_FIRST + CM_HELPHELP];
virtual void CMAbout(RTMessage Msg)
= [CM_FIRST + CM_ABOUT];
virtual void CMZoomOut(RTMessage Msg)
= [CM_FIRST + CM_ZOOMOUT];
virtual void CMZoomIn(RTMessage Msg)
= [CM_FIRST + CM_ZOOMIN];
virtual void CMStep(RTMessage Msg)
= [CM_FIRST + CM_STEP];
virtual void CMRun(RTMessage Msg)
= [CM_FIRST + CM_RUN];
};
int mags[]={1,2,3,5,7,10,15,25};int magindex=4;
TLifeWindow::TLifeWindow(PTWindowsObject AParent, LPSTR ATitle)
: TWindow(AParent, ATitle)
{ AssignMenu("COMMANDS");
Attr.Style|= WS_VSCROLL|WS_HSCROLL;
magnification=mags[magindex];origin.x=origin.y=0;
drawing=FALSE;
Scroller=new TScroller(this,1,1,1,1); // meaningless values -- setup by SetupWindow
selected_shape=cellpop("o\n");
v=cellpop();gencounter=0;
Colors[UNSET]=RGB(120,255,120);
Colors[SET]=RGB(255,0,0);
Colors[RESET]=RGB(200,0,0);
for(int i=0;i<3;i++)
{ Brushes[i]=CreateSolidBrush(Colors[i]);
Pens[i]=CreatePen(PS_SOLID,1,Colors[i]);
}
}
void TLifeWindow::SetupWindow()
{ TWindow::SetupWindow();
RECT r;GetClientRect(HWindow,&r);
ScrollRange.left=-(r.right-r.left)/(2*magnification);
ScrollRange.top=-(r.bottom-r.top)/(2*magnification);
ScrollRange.right=ScrollRange.left+1;
ScrollRange.bottom=ScrollRange.top+1;
Scroller->AutoOrg=FALSE;
adjustscroll(magnification);
readshapelib("life.lib");
}
TLifeWindow::~TLifeWindow()
{ for(int i=0;i<3;i++)
{ DeleteObject(Brushes[i]);
DeleteObject(Pens[i]);
}
}
void TLifeWindow::Paint(HDC DC, PAINTSTRUCT&)
{ setorigin();
for(int i=0;i<v.pop;i++)pixel(DC,v.v[i],RESET);
info();
}
void TLifeWindow::info()
{ RECT r;GetClientRect(HWindow,&r);
char text[130];
sprintf(text,
"Life Pop:%5d Gen:%5ld Mag:%d X:[%ld,%ld] Y:[%ld,%ld]",
v.pop,gencounter,magnification,
Scroller->XPos+ScrollRange.left,Scroller->XPos+ScrollRange.left+(r.right-r.left)/magnification,
Scroller->YPos+ScrollRange.top,Scroller->YPos+ScrollRange.top+(r.bottom-r.top)/magnification);
SetCaption(text);
}
int TLifeWindow::update(cellpop& w)
{ int iw=0,iv=0,nbchg=0;
DrawDC = GetDC(HWindow);
setorigin();
while(iw!=w.pop || iv!=v.pop)
{ if (w.v[iw]<v.v[iv]){ pixel(DrawDC,w.v[iw],SET);nbchg++;iw++;}
else if(w.v[iw]==v.v[iv]){ pixel(DrawDC,w.v[iw],RESET);iw++;iv++;}
else { pixel(DrawDC,v.v[iv],UNSET);nbchg++;iv++;}
}
ReleaseDC(HWindow, DrawDC);
v=w;info();
return nbchg;
}
void TLifeWindow::setorigin()
{ origin.x=Scroller->XPos+ScrollRange.left;
origin.y=Scroller->YPos+ScrollRange.top;
}
void TLifeWindow::pixel(HDC DC,cell_type c,int color)
{ int border=magnification>3,x,y;
SelectObject(DC,Pens[color]);
SelectObject(DC,Brushes[color]);
x=magnification*(c.cellx()-origin.x);
y=magnification*(c.celly()-origin.y);
if(magnification>1)
Rectangle(DC,x,y,x+magnification-border,y+magnification-border);
else SetPixel(DC,x,y,Colors[color]);
}
cell_type TLifeWindow::coordtocell(TMessage::tagLP LP)
{ return cell_type(LP.Lo/magnification+origin.x,LP.Hi/magnification+origin.y);}
void TLifeWindow::WMLButtonDown(RTMessage Msg)
{ cellpop w=v;
w.add(w,selected_shape,coordtocell(Msg.LP),LAY_XOR);
if(selected_shape.pop!=1)selected_shape="o";
update(w);
}
void TLifeWindow::DrawBox()
{ int x1=magnification*(box_start.cellx()-origin.x);
int y1=magnification*(box_start.celly()-origin.y);
int x2=magnification*(box_end.cellx()-origin.x);
int y2=magnification*(box_end.celly()-origin.y);
DrawDC=GetDC(HWindow);
SetROP2(DrawDC,R2_NOT);
MoveTo(DrawDC,x1,y1);
LineTo(DrawDC,x1,y2);
LineTo(DrawDC,x2,y2);
LineTo(DrawDC,x2,y1);
LineTo(DrawDC,x1,y1);
ReleaseDC(HWindow,DrawDC);
}
void TLifeWindow::WMRButtonDown(RTMessage Msg)
{ drawing=TRUE;SetCapture(HWindow);
DrawBox();box_start=box_end=coordtocell(Msg.LP);DrawBox();
}
void TLifeWindow::WMMouseMove(RTMessage Msg)
{ if(drawing)
{ DrawBox(); box_end=coordtocell(Msg.LP);DrawBox();}
#if 0
setorigin();
char buf[20]; sprintf(buf,"%04ld,%04ld",origin.x,origin.y);
DrawDC = GetDC(HWindow);
TextOut(DrawDC,10,10,buf,strlen(buf));
ReleaseDC(HWindow,DrawDC);
#endif
}
void TLifeWindow::WMRButtonUp(RTMessage Msg)
{ drawing=FALSE;
ReleaseCapture();
}
void TLifeWindow::Run(long count)
{ MSG msg;//PeekMessage(&msg,NULL,0,0,PM_REMOVE);
cellpop w,res;res.pop=-1;
do
{ w.nextgen(v);
if(w.error())return;
if(w==v){efns(WARNING_,"stable");return;}
if(w==res){efns(WARNING_,"period 2");return;}
gencounter++;res=v;
update(w);
if(w.pop==0){efns(WARNING_,"dead");return;}
if( PeekMessage(&msg,NULL,0x00A1,0x0209,PM_REMOVE))
{ TranslateMessage(&msg);
DispatchMessage(&msg);
if((msg.message<=0xA9 || msg.message>=0x106)
&& (msg.message<=0x108 || msg.message>=0x201))
break;
}
}
while(--count>0);
}
void TLifeWindow::CMStep(RTMessage m){Run(1);}
void TLifeWindow::CMRun(RTMessage m){Run(10000);}
void TLifeWindow::adjustscroll(int newmag)
{ RECT r;GetClientRect(HWindow,&r);
Scroller->XPos+=(newmag-magnification)*(r.right-r.left)/(2*newmag*magnification);
Scroller->YPos+=(newmag-magnification)*(r.bottom-r.top)/(2*newmag*magnification);
magnification=newmag;
Scroller->XLine=Scroller->YLine=25/magnification;
Scroller->SetUnits(magnification,magnification);
RECT NewRange;
if(v.pop>0)
{ NewRange.left=v.firstx().cellx();
NewRange.right=v.lastx().cellx();
NewRange.top=v.firsty().celly();
NewRange.bottom=v.lasty().celly();
}
else
{ NewRange.left=0;
NewRange.right=0;
NewRange.top=0;
NewRange.bottom=0;
}
NewRange.left-=(r.right-r.left)/magnification;
NewRange.top-=(r.bottom-r.top)/magnification;
Scroller->XPos+=ScrollRange.left-NewRange.left;
Scroller->YPos+=ScrollRange.top-NewRange.top;
ScrollRange=NewRange;
Scroller->SetRange(ScrollRange.right-ScrollRange.left,ScrollRange.bottom-ScrollRange.top);
InvalidateRect(HWindow, NULL, TRUE);
}
void TLifeWindow::CMZoomIn(RTMessage)
{ if(magnification==25)return;
adjustscroll(mags[++magindex]);
}
void TLifeWindow::CMZoomOut(RTMessage)
{ if(magnification==1)return;
adjustscroll(mags[--magindex]);
}
void TLifeWindow::CMFileNew(RTMessage)
{ v.clear_pop();gencounter=0;
InvalidateRect(HWindow, NULL, TRUE);}
void TLifeWindow::CMErase(RTMessage)
{ cellpop w=v;
w.erase_rect(box_start,box_end);update(w);
DrawBox();box_end=box_start;
}
char *TLifeWindow::GetFileName()
{ OPENFILENAME ofnTemp;
static char FileName[MAXPATH];
char szTemp[] = "All Files (*.*)\0*.*\0Life Files (*.lfe)\0*.lfe\0";
/*
Some Windows structures require the size of themselves in an effort to
provide backward compatibility with future versions of Windows. If the
lStructSize member is not set the call to GetOpenFileName() will fail.
*/
ofnTemp.lStructSize = sizeof( OPENFILENAME );
ofnTemp.hwndOwner = HWindow; // An invalid hWnd causes non-modality
ofnTemp.hInstance = 0;
ofnTemp.lpstrFilter = (LPSTR)szTemp; // See previous note concerning string
ofnTemp.lpstrCustomFilter = NULL;
ofnTemp.nMaxCustFilter = 0;
ofnTemp.nFilterIndex = 2;
FileName[0]='\0';
ofnTemp.lpstrFile = FileName; // Stores the result in this variable
ofnTemp.nMaxFile = sizeof( FileName );
ofnTemp.lpstrFileTitle = NULL;
ofnTemp.nMaxFileTitle = 0;
ofnTemp.lpstrInitialDir = NULL;
ofnTemp.lpstrTitle = "Save Area"; // Title for dialog
ofnTemp.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN|OFN_OVERWRITEPROMPT;
ofnTemp.nFileOffset = 0;
ofnTemp.nFileExtension = 0;
ofnTemp.lpstrDefExt = "lfe";
ofnTemp.lCustData = NULL;
ofnTemp.lpfnHook = NULL;
ofnTemp.lpTemplateName = NULL;
/*
If the call to GetOpenFileName() fails you can call CommDlgExtendedError()
to retrieve the type of error that occured.
*/
if(GetSaveFileName( &ofnTemp ) != TRUE)
{ DWORD Errval=CommDlgExtendedError();
if(Errval!=0) // 0 value means user selected Cancel
efns(WARNING_,"GetSaveFileName returned Error #%ld",Errval);
}
return FileName;
}
void TLifeWindow::CMUFileSave( RTMessage )
{v.save(GetFileName());}
void TLifeWindow::CMUFileSaveArea( RTMessage )
{ DrawBox();
v.save_rect(GetFileName(),box_start,box_end);
box_end=box_start;
}
void TLifeWindow::CMColorUnset(RTMessage Msg){CMUColor(UNSET);}
void TLifeWindow::CMColorReset(RTMessage Msg){CMUColor(RESET);}
void TLifeWindow::CMColorSet(RTMessage Msg){CMUColor(SET);}
void TLifeWindow::CMClearGen(RTMessage Msg){gencounter=0;info();}
void TLifeWindow::CMUColor(int index)
{ CHOOSECOLOR ccTemp;
COLORREF crTemp[16]; // Important, sometimes unused, array
ccTemp.lStructSize = sizeof( CHOOSECOLOR );
ccTemp.hwndOwner = HWindow;
ccTemp.hInstance = 0;
ccTemp.rgbResult = Colors[index]; // CC_RGBINIT flag makes this the default color
/*
lpCustColors must be set to a valid array of 16 COLORREF's, even if it
is not used. If it isn't you will probably fail with a GP fault in
COMMDLG.DLL.
*/
ccTemp.lpCustColors=crTemp;
ccTemp.Flags= CC_RGBINIT;
ccTemp.lCustData=0L;
ccTemp.lpfnHook=NULL;
ccTemp.lpTemplateName=NULL;
if(ChooseColor(&ccTemp)==TRUE)
{ Colors[index]=ccTemp.rgbResult;
DeleteObject(Brushes[index]);
DeleteObject(Pens[index]);
Brushes[index]=CreateSolidBrush(Colors[index]);
Pens[index]=CreatePen(PS_SOLID,1,Colors[index]);
InvalidateRect( HWindow, NULL, TRUE );
}
}
void TLifeWindow::CMHelp(RTMessage)
{ WinHelp(HWindow,"LIFE.HLP",HELP_CONTENTS,0l);}
void TLifeWindow::CMHelphelp(RTMessage)
{ WinHelp(HWindow,NULL,HELP_HELPONHELP,0l);}
void TLifeWindow::CMAbout(RTMessage Msg)
{ MessageBox(HWindow,"Windows Life\n\n"
"Version 0.1 June 1993\n\n"
"(C) Jean MICHEL\n\n"
" 22, rue de Wattignies 75012 Paris France\n"
" E-Mail: michel@dmi.ens.fr","About Life",MB_OK);}
void TLifeWindow::CMShape(RTMessage)
{ PTWindow ShapeWindow;
ShapeWindow = new TShapeWindow(this);
GetApplication()->MakeWindow(ShapeWindow);
}
void TLife::InitMainWindow()
{ MainWindow = new TLifeWindow(NULL, Name);
}
#include "winerror.h"
void (cdecl *efns)(int errcode,char *fmt,...)=error;
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{ TLife Life("Windows Life (C) Jean MICHEL Version 0.0", hInstance, hPrevInstance,
lpCmdLine, nCmdShow);
Life.Run();
return Life.Status;
}