#pragma option -d -WS -k-
/* -d doppelte Strings zusammenfassen
-WS Windows-Applikation, "intelligente" Rückrufe (via SS==DS)
-k- kein Standard-Stapelrahmen
*/
#include <windows.h>
#include <string.h> //memset
#include <stdlib.h> //exit
#include <dos.h> //_argc, _argv
#include "graphwin.h" //anstelle <graphics.h>
/* Wrapper für die GRAPHICS.LIB ... */
/* zurzeit: fest für VGA-Auflösung, alle 3 Modi */
/* Interne Arbeisweise, Schlüssel-Funktionen:
> Eine Bitmap verkörpert die Zeichenfläche, notwendig zur Restaurierung
teilweise verdeckter Flächen (Notwendigkeit bei allen Fenster-Systemen)
> Im DirectDraw-Modus wird gleichzeitig in das Fenster gezeichnet;
ansonsten wird die Bitmap bei "Arbeitspausen" hineinkopiert
> Die Funktion gdiproc() ist eine universelle Hülle für solche Doppelt-
und (später?) Dreifachzeichnungen
> Eine Reihe GDI-Objekte (Stift, Schrift, Hintergrund) wird stets parat
gehalten und per ChangeGdiObject() in allen Kontexten gewechselt
> Bei Moduswechseln wird die Fenstergröße an die dargestellte Pixelzahl
angepasst, und zwar bei WM_GetMinMaxInfo(!)
Bekannte Unzulänglichkeiten und Fehler:
- Fehlende Emulation der Palette (Win95 DibDraw erforderlich??)
- Inkorrekte Emulation der Hintergrundfarbe (wegen Palette im Original)
- Vorgabe des Fensters auf VGA-VGAHI (besser: Textmodus)
- Dürftige Emulation der CONIO (war nicht ursprünglicher Gegenstand)
- Fenstergrößen-Einstellung noch ohne Zoom und/oder Rollbalken
- Windows-Füllmuster unterscheiden sich von denen der GRAPHICS.LIB
- Emulation großer Aspektverhältnisse (z.B. VGALO) ist ebenso verzerrt
- Keine Windows-Fonts verfügbar, die wie die .CHR-Schriften aussehen
- Kein Signalhandler-Aufruf beim beabsichtigten Schließen des Fensters
- Projekt sollte mit "Warnung bei doppelten Symbolen AUS" übersetzt werden!
Bereits implementierte "Features":
+ Hauptprogramm startet mit main(), nicht mit WinMain()
+ Verwendung des "originalen" DOS-Zeichensatzes für identisches Aussehen
+ Einige Textmodus-typische Funktionen, insbesondere clrscr()
+ Caret- (=Schreibmarken-) Unterstützung - hat EASYWIN auch
+ Unterstützung von Cursor- und Funktionstasten (hat EASYWIN NICHT!)
+ Saubere OEM-Zeichensatz-Unterstützung, auch bei den Tastencodes
+ Sinus-Tabelle (sollte künftig auch extern zugreifbar sein)
+ Direktes Zeichnen sowohl ins Fenster als auch in Hintergrund-Bitmap,
ermöglicht Beobachtung des Bildaufbaus (="DirectDraw")
+ Indirektes Zeichnen mit Aktualisierung (nur) bei Tastaturabfragen und
yield() ist schneller, bisweilen schneller als DOS
+ Ganzzahlige Vergrößerung ist vorgesehen
+ Warnung beim "Killen" des Programms, Meldungstext auf deutsch umstellbar
+ Automatisches Schließen des Fensters bei Programmende, wenn nichts
auf dem Bildschirm steht
Evtl. vorgesehen:
* "Dritter Mitschnitt" in Speicher-Metadatei ermöglicht das Neuzeichnen bei
wechselnder Hintergrundfarbe und Zwischenablage-Export im Vektorformat
* Durchgängige CONIO-Unterstützung
* Unterstützung von "bunten" ANSI-Sequenzen
haftmann#software, 08/02
Bugfix 12/02 bei initgraph() sowie CrtWindow in .H-Datei
*/
/* Alle Variablen initialisiert Windows mit 0 */
BOOL CanClose;
//HANDLE ghInstance;
HWND CrtWindow;
static HDC ghScreenDC,ghActiveDC,ghVisualDC;
static HBITMAP ghNullBitmap; // für DC-Freigabe erforderlich
static HBITMAP pages[4]; // mehr als 4 Seiten hat kein Modus
/* Die Bitmaps haben die Auflösung des Windows-Bildschirms,
für maximale Geschwindigkeit von BitBlt() */
static int activepage,visualpage;
int scale=1; // für vergrößerte Darstellung, später POINT
static int width,height,numpages,colors;
static struct textsettingstype gTextSettings;
static struct usercharsizetype {
int multx,divx,multy,divy; } gUserCharSize={1,1,1,1};
static struct viewporttype gViewport; // für Viewport-bezogene Funktionen
static struct linesettingstype gLineSettings;
static struct arccoordstype gArcCoords;
static struct palettetype gDefaultPalette,gPalette;
static struct fillsettingstype gFillSettings;
static int gGraphResult;
static int gGraphDriver; // 0=Textmodus, 1..9,10=CGA..VGA,PC3270
static int gGraphMode; // je nach GraphDriver
static int gInGraphMode; // entscheidet über Cursor-Darstellung
static int gColor,gBkColor; // Farb-Indizes (0..15)
static POINT gAspect; // Seitenverhältnis (setzbar!)
static char gDriverName[16]="GRAPHWIN";
static BYTE gFillPattern[13][8]={ // funktionieren noch nicht!
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // EMPTY_FILL
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, // SOLID_FILL
{0x00,0x00,0xFF,0x00,0x00,0x00,0xFF,0x00}, // LINE_FILL ---
{0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}, // LTSLASH_FILL ///
{0x03,0x06,0x0C,0x18,0x30,0x60,0xC0,0x81}, // SLASH_FILL ///
{0x81,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03}, // BKSLASH_FILL \\\ .
{0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}, // LTBKSLASH_FILL \\\ .
{0x11,0x22,0x44,0x88,0x11,0x22,0x44,0x88}, // HATCH_FILL ///
{0x11,0xAA,0x44,0xAA,0x11,0xAA,0x44,0xAA}, // XHATCH_FILL XXX
{0x01,0x02,0x04,0x08,0x80,0x40,0x20,0x10}, // INTERLEAVE_FILL \/\ .
{0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00}, // WIDE_DOT_FILL
{0x00,0x66,0x66,0x00,0x00,0x66,0x66,0x00}, // CLOSE_DOT_FILL
{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}}; // USER_FILL
static HPEN ghPen,ghoPen; // Linienfarbe (Standard:Weiß)
static HBRUSH ghBrush,ghoBrush; // Füllfarbe (Standard: Schwarz?}
static HFONT ghFont,ghoFont; // Schrift ("Terminal")
static HFONT ghFont2; // Aktuelle "Schönschrift" für outtextxy
static COLORREF rgbpalette[MAXCOLORS+1]={
0x000000L,0xC00000L,0x00C000L,0xC0C000L,
0x0000C0L,0xC000C0L,0x0080C0L,0xC0C0C0L,
0x808080L,0xFF8080L,0x80FF80L,0xFFFF80L,
0x8080FFL,0xFF80FFL,0x80FFFFL,0xFFFFFFL};
static char *FontNames[5]={
"Terminal", // DEFAULT_FONT
"Times New Roman", // TRIPLEX_FONT
"Small Fonts", // SMALL_FONT
"Arial", // SANS_SERIF_FONT
"MS Gothic"}; // GOTHIC_FONT
void far pascal yield(void) {
MSG M;
while (PeekMessage(&M, 0, 0, 0, PM_REMOVE)) {
if (M.message==WM_QUIT) exit(255);
TranslateMessage(&M);
DispatchMessage(&M);
}
}
void far pascal setwindowtitle(char far*title) {
lstrcpyn(_WindowTitle,title,sizeof(_WindowTitle));
SetWindowText(CrtWindow,title);
}
/* von EasyWin gekupfert: */
HANDLE __hInstance;
HANDLE __hPrev;
int __cmdShow;
extern WORD (*__ReadBufFPtr)(char *Buffer, WORD Count);
extern void (*__WriteBufFPtr)(char *Buffer, WORD Count);
char _WindowTitle[80];
char * _InactiveTitle="(Inactive %s)";
char * _KillWarning="Program is running!\nKill now?\n\n"
"(You may loose data from this application)";
static char KeyBuffer[16];
static int KeyCount;
static POINT CharSize={8,16};// Größe der Zeichenzelle in Pixel
static POINT FontSize={8,12};// Größe des verwendeten Fonts in Pixel
static POINT FontCenter; // zur Zentrierung der Zeichen in Zeichenzellen
static int caret=2; // Höhe des Cursors in Pixel
static BOOL Changed;
static BOOL CanTerminate; // TRUE wenn Bildschirm leer
static BOOL Reading; // Caret im Textmodus zeigen
BOOL _AutoTracking=TRUE;
BOOL _CheckEOF=TRUE;
BOOL _CheckBreak=TRUE;
BOOL _DirectDraw=TRUE;
POINT _Cursor; // Schreibmarken-Position in Zeichenzellen
POINT _ScreenSize; // Fenster-Größe in Zeichenzellen
void pascal invalidate(void) {
if (Changed) {
InvalidateRect(CrtWindow,NULL,FALSE);
Changed=FALSE;
}
}
BOOL _KeyPressed(void) {
invalidate();
// CanTerminate=FALSE; // Wenn etwas geschrieben wurde, Fenster nicht schließen!
yield();
return KeyCount;
}
static HANDLE cdecl gdiproc(FARPROC func,int argc,...) {
/* Allgemeine Kapsel von GDI-Zeichenfunktionen
* argc enthält die Anzahl der folgenden int-Argumente
* LONG- und FAR*-Argumente müssen in der Reihenfolge HIGH-LOW (verdreht)
* übergeben werden
*
* Besondere Bits von argc:
* Bit15: Keine sichtbaren Veränderungen, verzögertes blt wird unterdrückt.
* Bit14: Bild ist leer, beendendes Programm darf das Fenster schließen
*
* Returnwert ist der von ghActiveDC, also von der Hintergrund-Bitmap
*
* Wie zum Geier schreibt man in diesem Inline-Assembler ein Unterprogramm???
*/
HANDLE retu;
asm{ cld
mov ax,[ghActiveDC]
push ax
lea si,argc
lodsw
mov ah,0
xchg cx,ax
jcxz l2
}l1: asm{
lodsw
push ax
loop l1
}l2: asm{
call [func]
mov [retu],ax
mov ax,[visualpage]
cmp ax,[activepage]
jne exi //niemals auf den Bildschirm!
cmp [_DirectDraw],0
jz le //verzögert bltten
mov ax,[ghScreenDC]
}sub: asm{
push ax
lea si,argc
lodsw
mov ah,0
xchg cx,ax
jcxz l4
}l3: asm{
lodsw
push ax
loop l3
}l4: asm{
call [func]
jmp exi
}le:
if (!(argc&0x8000)) Changed=TRUE; //nur wenn zeichnende Operation
exi:
if (!(argc&0xC000)) CanTerminate=FALSE;// Wenn zeichnend und nicht leer
return retu;
}
static void _ShowCursor(void) {
/* Action nur im Textmodus! */
if (gInGraphMode) return;
CreateCaret(CrtWindow,0,CharSize.x*scale,caret*scale);
SetCaretPos(_Cursor.x*CharSize.x*scale,((_Cursor.y+1)*CharSize.y-caret)*scale);
ShowCaret(CrtWindow);
}
static void _HideCursor(void) {
/* Action nur im Textmodus! */
if (gInGraphMode) return;
HideCaret(CrtWindow);
DestroyCaret();
}
static void _TrackCursor(void) {
/* Keine Action bei Fenster ohne Rollbalken */
}
int _ReadKey(void) {
int readkey;
_TrackCursor();
if (!_KeyPressed()) {
Reading=TRUE; if (GetFocus()==CrtWindow) _ShowCursor();
do; while (!_KeyPressed());
Reading=FALSE; if (GetFocus()==CrtWindow) _HideCursor();
}
readkey=KeyBuffer[0];
--KeyCount;
memmove(KeyBuffer,KeyBuffer+1,KeyCount);
return readkey;
}
static void pascal NewLine(void) {
_Cursor.x=0;
_Cursor.y++;
if (_Cursor.y>=_ScreenSize.y) {
_Cursor.y--;
gdiproc((FARPROC)ScrollDC,10,0,-CharSize.y,0,0,0,0,0,0,0,0);
gdiproc((FARPROC)PatBlt,6,0,_Cursor.y*CharSize.y,width,CharSize.y,
HIWORD(BLACKNESS),LOWORD(BLACKNESS));
}
}
static void pascal textout(char*buf,int slen) {
POINT curs;
RECT R;
curs.x=_Cursor.x*CharSize.x;
curs.y=_Cursor.y*CharSize.y;
SetRect(&R,curs.x,curs.y,curs.x+CharSize.x*slen,curs.y+CharSize.y);
if (!buf) slen=0;
gdiproc((FARPROC)ExtTextOut,10,curs.x+FontCenter.x,curs.y+FontCenter.y,
ETO_OPAQUE,HIWORD(&R),LOWORD(&R),_SS,LOWORD(buf),slen,0,0);
}
static void pascal PutText(char*buf,int slen) {
textout(buf,slen);
_Cursor.x+=slen;
if (_Cursor.x>=_ScreenSize.x) NewLine();
}
void _WriteBuf(char *Buffer, WORD Count) {
// int slen;
/* {
char b2[256];
wvsprintf(b2,"CharSize=%d:%d",&CharSize);
MessageBox(CrtWindow,b2,Buffer,0);
} */
gdiproc((FARPROC)SaveDC,0x8000); //Viewport retten
gdiproc((FARPROC)SetViewportOrg,0x8002,0,0);
gdiproc((FARPROC)SelectClipRgn,0x8001,0); //Falls vorhanden, Clipping weg
while (Count>0) {
switch (*Buffer) {
case 13: NewLine(); break;
case 10: break;
case 9: {
PutText(NULL,8-_Cursor.x%8); //1..8 Leerzeichen
}break;
case 8: if (_Cursor.x>0) {
--_Cursor.x;
PutText(NULL,1);
--_Cursor.x;
}break;
case 7: MessageBeep(0); break;
default: PutText(Buffer,1);
}
++Buffer;
--Count;
}
if (_AutoTracking) _TrackCursor();
gdiproc((FARPROC)RestoreDC,0x8001,-1);
}
void _WriteChar(char Ch) {
_WriteBuf(&Ch,1);
}
WORD _ReadBuf(char *Buffer, WORD Count) {
/* realisiert einen einfachen Zeileneditor */
unsigned char Ch;
WORD I;
I=0;
do {
Ch = _ReadKey();
if (Ch==8) { //Rückschritt
if (I > 0) {
--I;
_WriteChar(8);
}
}else if (Ch>=32) {
if (I<Count) {
Buffer[I++]=Ch;
_WriteChar(Ch);
}
}
}while (!((Ch==13) || (_CheckEOF && (Ch==26))));
if (I<Count-2) {
Buffer[I++]=Ch;
if (Ch==13) {
Buffer[I++] = 10;
_WriteChar(13);
}
}
_TrackCursor();
return I;
}
void _CursorTo(int x, int y) {
_Cursor.x=max(0,min(x,_ScreenSize.x-1));
_Cursor.y=max(0,min(y,_ScreenSize.y-1));
}
/* Ende EasyWin-gekupferte Sachen */
#define selobj(obj) gdiproc((FARPROC)SelectObject,0x8001,(obj))
#define setcol(proc,c) {COLORREF farbe=(c);\
gdiproc((FARPROC)(proc),0x8002,HIWORD(farbe),LOWORD(farbe));}
static void pascal CheckPageLoaded(int page) {
/* Bitmap-Seiten werden bei Bedarf erzeugt */
if (!pages[page]) {
pages[page]=CreateCompatibleBitmap(ghScreenDC,width,height);
}
}
static void pascal SetPages(int x,int y,int z,int c) {
/* erzeugt z Bitmap-Ebenen der Größe x*y der Farbtiefe c wie gewünscht */
int i;
if (ghNullBitmap) {
SelectObject(ghActiveDC,ghNullBitmap);
if (activepage!=visualpage) SelectObject(ghVisualDC,ghNullBitmap);
}
for (i=0; i<numpages; i++) {
if (pages[i] && DeleteObject(pages[i])) pages[i]=0;
if (i<z) pages[i]=CreateCompatibleBitmap(ghScreenDC,x,y);
}
activepage=0;
visualpage=0;
width=x;
height=y;
numpages=z;
colors=c;
if (z) {
CheckPageLoaded(0);
ghNullBitmap=SelectObject(ghActiveDC,pages[0]); // 1. Ebene aktiv
/* Dummerweise kann man eine Bitmap nicht gleich in zwei Kontexte stellen! */
clearviewport();
SetWindowPos(CrtWindow,0,0,0,10000,10000,SWP_NOMOVE|SWP_NOZORDER);
}
FontCenter.x=(CharSize.x-FontSize.x)/2;
FontCenter.y=(CharSize.y-FontSize.y)/2;
}
void far pascal internal_initgraph(int x, int y, int z, int c) {
int i;
gAspect.x=GetDeviceCaps(ghScreenDC,ASPECTX);
gAspect.y=GetDeviceCaps(ghScreenDC,ASPECTY);
gDefaultPalette.size=MAXCOLORS+1;
for (i=0; i<=MAXCOLORS; i++) gDefaultPalette.colors[i]=i;
gPalette=gDefaultPalette;
SetPages(x,y,z,c);
graphdefaults();
gInGraphMode=TRUE; // kein Cursor!
}
static HANDLE pascal ChangeGdiObject(HANDLE*ghandle,HANDLE nhandle) {
HANDLE ret=selobj(nhandle);
if (*ghandle==ret) DeleteObject(ret);
*ghandle=nhandle;
return ret;
}
static void pascal PenChange(void) {
//aufzurufen bei Änderung der Linienart, Linienstärke oder Vordergrundfarbe
static int PenStyles[5]={
PS_SOLID,PS_DOT,PS_DASHDOT,PS_DASH,PS_DASHDOTDOT}; //upattern nicht umsetzbar!
ChangeGdiObject(&ghPen,CreatePen(
PenStyles[gLineSettings.linestyle],
gLineSettings.thickness,
rgbpalette[gPalette.colors[gColor]]));
}
static void pascal CheckFont2(void) {
//Test und Laden Schönschrift-Font
/* Sehr wacklige Angelegenheit:
Sehen die Fonts passend aus?
Stimmen Größen und Abstände?
UserCharSize sollte eingebaut werden! */
if (!ghFont2) {
if (gTextSettings.font) {
ghFont2=CreateFont(gTextSettings.charsize*8,0/*gTextSettings.charsize*4*/,
gTextSettings.direction?900:0,0,700,0,0,0,
ANSI_CHARSET,0,0,0,0,
FontNames[gTextSettings.font]);
}else{
ghFont2=CreateFont(8,8,0,
gTextSettings.direction?900:0,0,0,0,0,
OEM_CHARSET,0,0,0,0,
FontNames[0]);
}
}
}
static void pascal Font2Change(void) {
//Bei Veränderungen den geladenen Font verwerfen
if (ghFont2) {
DeleteObject(ghFont2);
ghFont2=0;
}
}
static BOOL pascal NeedConvert(LPCSTR s) {
if (!s) return FALSE;
for (;*s;s++) {
if ((BYTE)(*s)>=0x80) return TRUE;
}
return FALSE;
}
static void pascal MakeGdiObjects(void) {
ghoPen= ChangeGdiObject(&ghPen, CreatePen(PS_SOLID,1,rgbpalette[15]));
ghoBrush=ChangeGdiObject(&ghBrush,CreateSolidBrush(rgbpalette[15]));
ghoFont= ChangeGdiObject(&ghFont, CreateFont(FontSize.y,FontSize.x,
0,0,0,0,0,0,OEM_CHARSET,0,0,0,0,FontNames[0]));
setcol(SetTextColor,rgbpalette[7]); // grau wie BIOS
setcol(SetBkColor,rgbpalette[0]); // schwarz wie BIOS
gdiproc(SetBkMode,0x8001,OPAQUE);
_ScreenSize.x=width/CharSize.x;
_ScreenSize.y=height/CharSize.y;
gViewport.right=width-1;
gViewport.bottom=height-1;
gViewport.clip=1;
}
static void pascal DestroyGdiObjects(void) {
ChangeGdiObject(&ghFont, ghoFont);
ChangeGdiObject(&ghBrush,ghoBrush);
ChangeGdiObject(&ghPen, ghoPen);
Font2Change();
}
/********************************************
* Ersatz für EASYWIN- und CONIO-Funktionen *
********************************************/
void textmode(int newmode) {
if (newmode==-1) return;
FontSize.x=CharSize.x=8;
FontSize.y=12;
CharSize.y=16;
_ScreenSize.y=25;
if (newmode&64) {
_ScreenSize.y=50;
FontSize.y=CharSize.y=8;
newmode&=~64;
}
_ScreenSize.x=80;
switch (newmode) {
case 0:
case 1: _ScreenSize.x=40;
FontSize.x=FontSize.y=CharSize.x=CharSize.y=16;
}
ChangeGdiObject(&ghFont,CreateFont(FontSize.y,FontSize.x,0,0,0,0,0,0,
OEM_CHARSET,0,0,0,0,FontNames[0]));
SetPages(_ScreenSize.x*CharSize.x,_ScreenSize.y*CharSize.y,1,16);
gInGraphMode=FALSE;
}
void gotoxy(int x, int y) { _CursorTo(x-1,y-1); }
void clreol(void) {
textout(NULL,_ScreenSize.x-_Cursor.x);
}
void clrscr(void) {
gdiproc((FARPROC)PatBlt,0x4006,0,0,width,height,
HIWORD(BLACKNESS),LOWORD(BLACKNESS));
CanTerminate=TRUE; // Da ist nichts mehr zu sehen
}
void _setcursortype(int cur_t) {
switch (cur_t) {
case 0: caret=0; // _NOCURSOR
case 1: caret=CharSize.y; // _SOLIDCURSOR
case 2: caret=2; // _NORMALCURSOR
}
}
void _InitEasyWin(void) {} // gar nichts tun!
/************************************
* Hilfsfunktionen für GRAPHICS.LIB *
************************************/
static unsigned char sintab[91]={
0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70,
75, 79, 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135,
139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 177, 180, 183, 186,
190, 192, 195, 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, 223, 225,
227, 229, 231, 233, 235, 236, 238, 240, 241, 243, 244, 245, 246, 247, 248,
249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255};
static int pascal isin(int angle) {
int negflag,y;
angle%=360;
negflag=angle>=180;
if (negflag) angle-=180; // Quadranten III und IV
if (angle>90) angle=180-angle; // Quadranten II und IV
y=sintab[angle];
if (negflag) y=-y;
return y;
}
static int pascal icos(int angle) {
return isin(angle+90);
}
int far pascal _ret(int x) {
return x;
}
/*******************************************
* Funktionsnachbildungen der GRAPHICS.LIB *
*******************************************/
void far arc(int x, int y, int stangle, int endangle, int radius) {
ellipse(x,y,stangle,endangle,radius,MulDiv(radius,gAspect.y,gAspect.x));
}
#pragma argsused
void far cdecl bar(int left, int top, int right, int bottom) {
right++;
bottom++;
gdiproc((FARPROC)FillRect,3,HIWORD((LPRECT)&left),LOWORD((LPRECT)&left),
ghBrush);
}
void far bar3d(int left, int top, int right, int bottom, int depth,
int topflag) {
gdiproc((FARPROC)Rectangle,4,left,top,right+1,bottom+1);
gdiproc((FARPROC)SaveDC,0x8000); //Position retten
moveto(right,top);
lineto(right+depth,top-depth/2);
lineto(right+depth,bottom-depth/2);
lineto(right,bottom);
if (topflag) {
moveto(right+depth,top-depth/2);
lineto(left+depth,top-depth/2);
lineto(left,top);
}
gdiproc((FARPROC)RestoreDC,0x8001,-1);
}
void far circle(int x, int y, int radius) {
POINT rad;
rad.x=radius;
rad.y=MulDiv(radius,gAspect.y,gAspect.x);
selobj(GetStockObject(HOLLOW_BRUSH));
gdiproc((FARPROC)Ellipse,4,x-rad.x,y-rad.y,x+rad.x+1,y+rad.y+1);
selobj(ghBrush);
}
void far cleardevice(void) {
setviewport(0,0,getmaxx(),getmaxy(),0);
clearviewport();
}
void far clearviewport(void) {
clrscr();
moveto(0,0);
}
void far closegraph() {
gGraphDriver=0;
textmode(3);
}
void far detectgraph(int far *graphdriver, int far *graphmode) {
*graphdriver=VGA;
*graphmode=VGAHI;
}
void far drawpoly(int c, const int far *p) {
gdiproc((FARPROC)Polyline,3,HIWORD(p),LOWORD(p),c);
}
void far ellipse(int x, int y, int stang, int endang, int xr, int yr) {
gArcCoords.x=x;
gArcCoords.y=y;
gArcCoords.xstart=x+MulDiv(icos(stang),xr,255);
gArcCoords.ystart=y-MulDiv(isin(stang),yr,255);
gArcCoords.xend=x+MulDiv(icos(endang),xr,255);
gArcCoords.yend=y-MulDiv(isin(endang),yr,255);
gdiproc((FARPROC)Arc,8,x-xr,y-yr,x+xr+1,y+yr+1,
gArcCoords.xstart,gArcCoords.ystart,gArcCoords.xend,gArcCoords.yend);
}
void far fillellipse(int x, int y, int xr, int yr) {
gdiproc((FARPROC)Ellipse,4,x-xr,y-yr,x+xr+1,y+yr+1);
}
void far fillpoly(int c, const int far *p) {
gdiproc((FARPROC)Polygon,3,HIWORD(p),LOWORD(p),c);
}
void far floodfill(int x, int y, int b) {
//kann das auf der Zeichenfläche gemacht werden?
COLORREF farbe;
if ((unsigned)b>getmaxcolor()) return;
farbe=rgbpalette[gPalette.colors[b]];
gdiproc((FARPROC)FloodFill,4,x,y,HIWORD(farbe),LOWORD(farbe));
}
void far getarccoords(struct arccoordstype far *arccoords) {
*arccoords=gArcCoords;
}
void far getaspectratio(int far *xasp, int far *yasp) {
*xasp=gAspect.x;
*yasp=gAspect.y;
}
int far getbkcolor(void) { return gBkColor; }
int far getcolor(void) { return gColor; }
struct palettetype far * far getdefaultpalette(void) {
return &gDefaultPalette; }
char *far getdrivername(void) { return gDriverName; }
void far getfillpattern(char far *pattern) {
hmemcpy(pattern,gFillPattern[USER_FILL],8);
}
void far getfillsettings (struct fillsettingstype far *fillinfo) {
*fillinfo=gFillSettings;
}
int far getgraphmode(void) { return gGraphMode; }
void far getimage(int left, int top, int right, int bottom,
void far *bitmap) {
HBITMAP bm;
HDC dc;
int w,h;
w=right+1-left; h=bottom+1-top;
bm=CreateCompatibleBitmap(ghScreenDC,w,h);
dc=CreateCompatibleDC(ghScreenDC);
SelectObject(dc,bm);
BitBlt(dc,0,0,w,h,ghActiveDC,left,top,SRCCOPY);
SelectObject(dc,ghNullBitmap);
DeleteDC(dc);
((LPWORD)bitmap)[0]=w;
((LPWORD)bitmap)[1]=h;
((LPWORD)bitmap)[2]=bm;
}
void far getlinesettings(struct linesettingstype far *lineinfo) {
*lineinfo=gLineSettings;
}
int far getmaxcolor(void) { return 15;}
int far getmaxmode(void) { return 2;}
#pragma argsused
char * far getmodename(int mode_number) {
static char buf[16];
wsprintf(buf,"%d x %d WIN",width,height);
return buf;
}
int far getmaxx(void) {return width-1;}
int far getmaxy(void) {return height-1;}
void far getmoderange(int graphdriver, int far* lowmode, int far* himode) {
//So ziemlich jeder Modus wird hier unterstützt
if (graphdriver) {
*lowmode=0;
*himode=2;
}
}
void far getpalette(struct palettetype far *palette) {
*palette=gPalette;
}
int far getpalettesize(void) { return gPalette.size; }
unsigned far getpixel(int x, int y) {
COLORREF c;
c=GetPixel(ghActiveDC,x,y);
for (x=0; x<=MAXCOLORS; x++) if (c==rgbpalette[x]) return x;
return 0;
}
void far gettextsettings(struct textsettingstype far* texttypeinfo) {
*texttypeinfo=gTextSettings;
}
void far getviewsettings(struct viewporttype far* viewport) {
*viewport=gViewport;
}
int far getx(void) {return (int)(LOWORD(GetCurrentPosition(ghActiveDC)));}
int far gety(void) {return (int)(HIWORD(GetCurrentPosition(ghActiveDC)));}
void far graphdefaults(void) {
setviewport(0,0,getmaxx(),getmaxy(),0);
moveto(0,0);
gPalette=gDefaultPalette;
setcolor(15);
setbkcolor(0);
setfillstyle(SOLID_FILL,15);
settextjustify(LEFT_TEXT,TOP_TEXT);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
}
char *far grapherrormsg(int errorcode) {
static char* msg[]={
"Ok","NoInitGraph","NotDetected","FileNotFound",
"InvalidDriver","NoLoadMem","NoScanMem","NoFloodMem",
"FontNotFound","NoFontMem","InvalidMode","Error",
"IOerror","InvalidFont","InvalidFontNum","InvalidDeviceNum",
"InvalidVersion"};
errorcode=-errorcode;
if ((unsigned)errorcode>18) return NULL;
return msg[errorcode];
}
int far graphresult(void) {
register int ret=gGraphResult;
gGraphResult=0;
return ret;
}
#pragma argsused
void far initgraph(int far *graphdriver,
int far *graphmode, const char far *pathtodriver) {
if (*graphdriver==DETECT) detectgraph(graphdriver,graphmode);
gGraphDriver=*graphdriver;
setgraphmode(*graphmode);
}
void far pascal initgraph2(int x, int y, int z, int c) {
gGraphDriver=UNIVERSAL; // alles mögliche
internal_initgraph(x,y,z,c);
}
#pragma argsused
void far _cdecl line(int x1, int y1, int x2, int y2) {
gdiproc((FARPROC)Polyline,3,HIWORD((LPPOINT)&x1),LOWORD((LPPOINT)&x1),2);
}
void far linerel(int x, int y) {
lineto(getx()+x,gety()+y);
}
void far lineto(int x, int y) {
gdiproc((FARPROC)LineTo,2,x,y);
}
void far moverel(int x, int y) {
moveto(getx()+x,gety()+y);
}
void far moveto(int x, int y) {
gdiproc((FARPROC)MoveTo,0x8002,x,y);
}
void far outtext(const char far *textstring) {
outtextxy(0x8000U,0x8000U,textstring); // Spezial-Code
}
void far outtextxy(int x, int y, const char far *textstring) {
static WORD horzalign[3]={TA_LEFT,TA_CENTER,TA_RIGHT};
static WORD vertalign[3]={TA_BOTTOM,TA_BASELINE,TA_TOP}; //TA_VCENTER gibt's nicht
char near*ansi=NULL;
WORD slen=lstrlen(textstring);
CheckFont2();
selobj(ghFont2);
gdiproc((FARPROC)SetTextAlign,0x8001,
((unsigned)x==0x8000U && (unsigned)y==0x8000U ? TA_UPDATECP : TA_NOUPDATECP)
| (gTextSettings.direction
? horzalign[gTextSettings.vert] | vertalign[2-gTextSettings.horiz]
: horzalign[gTextSettings.horiz] | vertalign[gTextSettings.vert]));
gdiproc((FARPROC)SetBkMode,0x8001,TRANSPARENT);
if (gTextSettings.font && NeedConvert(textstring)) {
ansi=(char near*)LocalAlloc(LMEM_FIXED,slen);
OemToAnsiBuff(textstring,ansi,slen); //ohne Null, wird nicht gebraucht
textstring=ansi; //Zeiger umsetzen
}
gdiproc((FARPROC)TextOut,5,x,y,HIWORD(textstring),LOWORD(textstring),slen);
if (ansi) LocalFree((HANDLE)ansi);
gdiproc((FARPROC)SetBkMode,0x8001,OPAQUE);
gdiproc((FARPROC)SetTextAlign,0x8001,0);
selobj(ghFont);
}
void far pieslice(int x, int y, int stangle, int endangle, int radius) {
gdiproc((FARPROC)Pie,8,x-radius,y-radius,x+radius+1,y+radius+1,
x+icos(stangle),y-isin(stangle),x+icos(endangle),y-isin(endangle));
}
void far putimage(int left, int top, const void far *bitmap, int op) {
int w=((LPWORD)bitmap)[0];
int h=((LPWORD)bitmap)[1];
HBITMAP bm=((LPWORD)bitmap)[2];
HDC dc=CreateCompatibleDC(ghScreenDC);
static DWORD rops[]={SRCCOPY,SRCINVERT,SRCPAINT,SRCAND,NOTSRCCOPY};
if ((unsigned)op>=4) return;
SelectObject(dc,bm);
gdiproc((FARPROC)BitBlt,9,left,top,w,h,dc,0,0,HIWORD(rops[op]),LOWORD(rops[op]));
SelectObject(dc,ghNullBitmap);
DeleteDC(dc);
}
void far putpixel(int x, int y, int c) {
COLORREF farbe;
if ((unsigned)c>MAXCOLORS) return;
farbe=rgbpalette[gPalette.colors[c]];
gdiproc((FARPROC)SetPixel,4,x,y,HIWORD(farbe),LOWORD(farbe));
}
void far rectangle(int left, int top, int right, int bottom) {
selobj(GetStockObject(HOLLOW_BRUSH));
gdiproc((FARPROC)Rectangle,4,left,top,right+1,bottom+1);
selobj(ghBrush);
}
void far restorecrtmode(void) {
// gGraphDriver=0;
textmode(3);
}
void far sector(int x, int y, int stang, int endang, int xr, int yr) {
gdiproc((FARPROC)Pie,8,x-xr,y-yr,x+xr+1,y+yr+1,
x+icos(stang),y-isin(stang),x+icos(endang),y-isin(endang));
}
void far setactivepage(int page) {
BOOL already_there;
if ((unsigned)page>=(unsigned)numpages) return;
if (page==activepage) return;
already_there=pages[page];
CheckPageLoaded(page);
activepage=page;
SelectObject(ghActiveDC,pages[page]);
if (!already_there) {
PatBlt(ghActiveDC,0,0,width,height,BLACKNESS);
}
}
void far setallpalette(const struct palettetype far *palette) {
gPalette=*palette;
}
void far setaspectratio(int xasp, int yasp) {
gAspect.x=xasp;
gAspect.y=yasp;
}
void far setbkcolor(int color) {
if ((unsigned)color>getmaxcolor()) return;
gBkColor=color;
setcol(SetBkColor,rgbpalette[gPalette.colors[color]]);
}
void far setcolor(int color) {
if ((unsigned)color>getmaxcolor()) return;
gColor=color;
setcol(SetTextColor,rgbpalette[gPalette.colors[color]]);
PenChange();
}
void far setfillpattern(const char far *upattern, int color) {
hmemcpy(gFillPattern[USER_FILL],upattern,8);
setfillstyle(USER_FILL,color);
}
void far setfillstyle(int pattern, int color) {
HBRUSH br;
static int HatchIndex[]={HS_HORIZONTAL,HS_FDIAGONAL,HS_FDIAGONAL,HS_BDIAGONAL,HS_BDIAGONAL,
HS_CROSS,HS_DIAGCROSS,HS_VERTICAL,HS_CROSS,HS_CROSS};
gFillSettings.pattern=pattern;
gFillSettings.color=color;
switch (gFillSettings.pattern) {
case EMPTY_FILL: br=GetStockObject(HOLLOW_BRUSH); break;
case SOLID_FILL: br=CreateSolidBrush(rgbpalette[gPalette.colors[gFillSettings.color]]); break;
case USER_FILL: {
HBITMAP bm;
WORD bits[8];
BYTE *bp;
int i;
for (bp=gFillPattern[gFillSettings.pattern],i=0; i<8; i++) bits[i]=*bp++;
bm=CreateBitmap(8,8,1,1,bits);
br=CreatePatternBrush(bm);
DeleteObject(bm);
}break;
default: br=CreateHatchBrush(HatchIndex[gFillSettings.pattern-LINE_FILL],
rgbpalette[gPalette.colors[color]]);
}
ChangeGdiObject(&ghBrush,br);
}
#pragma argsused
void far setgraphmode(int mode) {
static int vgalines[3]={200,350,480};
if (!gGraphDriver) return;
if ((unsigned)mode>2) return;
gGraphMode=mode;
internal_initgraph(640,vgalines[mode],mode<2?2:1,MAXCOLORS+1);
}
#pragma argsused
void far setlinestyle(int linestyle, unsigned upattern, int thickness) {
if ((unsigned)linestyle>USERBIT_LINE) return;
gLineSettings=*(struct linesettingstype*)&linestyle;
PenChange();
}
void far setpalette(int colornum, int color) {
if ((unsigned)colornum>=gPalette.size) return;
if ((unsigned)color>getmaxcolor()) return;
gPalette.colors[colornum]=color;
}
void far setrgbpalette(int colornum, int red, int green, int blue) {
if ((unsigned)colornum>=gPalette.size) return;
((RGBQUAD*)(&rgbpalette[colornum]))->rgbRed=red;
((RGBQUAD*)(&rgbpalette[colornum]))->rgbGreen=green;
((RGBQUAD*)(&rgbpalette[colornum]))->rgbBlue=blue;
//normalerweise und nur bei 256-Farben-Displays möglich: RealizePalette()
//Paletten-Animation ist, weil selten verwendet, nicht vorgesehen.
}
void far settextjustify(int horiz, int vert) {
if ((unsigned)horiz>2) return;
if ((unsigned)vert>2) return;
gTextSettings.horiz=horiz;
gTextSettings.vert=vert;
Font2Change();
}
void far settextstyle(int font, int direction, int charsize) {
gTextSettings.font=font<5?font:0;
gTextSettings.direction=direction;
gTextSettings.charsize=charsize;
Font2Change();
}
#pragma argsused
void far setusercharsize(int multx, int divx, int multy, int divy) {
gUserCharSize=*(struct usercharsizetype*)&multx;
Font2Change();
}
void far cdecl setviewport(int left, int top, int right, int bottom, int clip) {
HRGN hRegion;
gdiproc((FARPROC)SelectClipRgn,0x8001,0); // Falls vorhanden, Clipping entfernen
gViewport=*(struct viewporttype*)&left;
if (clip) {
hRegion=CreateRectRgn(left,top,right+1,bottom+1);
gdiproc((FARPROC)SelectClipRgn,0x8001,hRegion);
DeleteObject(hRegion);
}
gdiproc((FARPROC)SetViewportOrg,2,left,top);
}
void far setvisualpage(int page) {
if ((unsigned)page>=(unsigned)numpages) return;
if (page==visualpage) return;
CheckPageLoaded(page);
if (activepage!=visualpage) SelectObject(ghVisualDC,ghNullBitmap);
visualpage=page;
if (activepage!=visualpage) SelectObject(ghVisualDC,pages[page]);
Changed=TRUE;
if (_DirectDraw) {
invalidate();
UpdateWindow(CrtWindow); // Sofort aktualisieren
}
}
void far setwritemode(int mode) {
gdiproc((FARPROC)SetROP2,0x8001,mode ? R2_XORPEN : R2_COPYPEN);
}
long far pascal textextent(const char far *textstring) {
long ret;
CheckFont2();
SelectObject(ghActiveDC,ghFont2);
ret=GetTextExtent(ghActiveDC,textstring,lstrlen(textstring));
SelectObject(ghActiveDC,ghFont);
return ret;
}
int far textheight(const char far *textstring) {
return HIWORD(textextent(textstring));
}
int far textwidth(const char far *textstring) {
return LOWORD(textextent(textstring));
}
/********************************************
* Hier geht's mit richtigem Windows weiter *
********************************************/
long far pascal GraphWndProc(HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case WM_CREATE: {
CrtWindow=Wnd;
ghScreenDC=GetDC(Wnd);
ghActiveDC=CreateCompatibleDC(ghScreenDC);
ghVisualDC=CreateCompatibleDC(ghScreenDC);
SetPages(640,400,1,16); //mit VGA-Textmodus-Emulation geht's los!
MakeGdiObjects();
}break;
case WM_SETFOCUS: if (Reading) _ShowCursor(); break;
case WM_KILLFOCUS: if (Reading) _HideCursor(); break;
case WM_QUERYENDSESSION:
case WM_CLOSE: {
if (CanClose || MessageBox(Wnd,_KillWarning,_WindowTitle,
MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2)==IDYES) break;
// DefWindowProc() schließt - nur bei WM_Close
}return 0; // nicht schließen!
case WM_KEYDOWN: {
if ((VK_PRIOR<=wParam && wParam<=VK_DOWN)
|| (VK_INSERT<=wParam && wParam<=VK_HELP)
|| (VK_F1<=wParam && wParam<=VK_SCROLL)) {
if (KeyCount<sizeof(KeyBuffer)-1) {
KeyBuffer[KeyCount++]='\0';
KeyBuffer[KeyCount++]=LOBYTE(HIWORD(lParam));
}
}
}break;
case WM_GETMINMAXINFO: {
RECT R;
SetRect(&R,0,0,width*scale,height*scale);
AdjustWindowRect(&R,WS_OVERLAPPEDWINDOW,FALSE);
((LPPOINT)(lParam))[4].x=R.right-R.left;
((LPPOINT)(lParam))[4].y=R.bottom-R.top;
}break;
case WM_CHAR: {
if (_CheckBreak && (wParam==3)) DestroyWindow(Wnd);
if (KeyCount<sizeof(KeyBuffer)) {
AnsiToOemBuff((LPSTR)&wParam,KeyBuffer+KeyCount++,1); // convert the character!
}
}break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC src_dc= activepage!=visualpage ? ghVisualDC : ghActiveDC;
BeginPaint(Wnd,&ps);
if (scale==1) BitBlt(ps.hdc,0,0,width,height,src_dc,0,0,SRCCOPY);
else StretchBlt(ps.hdc,0,0,width*scale,height*scale,src_dc,0,0,width,height,SRCCOPY);
EndPaint(Wnd,&ps);
}return 0;
case WM_DESTROY: {
DestroyGdiObjects();
SetPages(0,0,0,0);
DeleteDC(ghActiveDC);
DeleteDC(ghVisualDC);
ReleaseDC(Wnd,ghScreenDC);
PostQuitMessage(0);
}break;
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
static void pascal EndMessageLoop(void) {
/* zum Stehenlassen des inaktiven Fensters */
MSG Msg;
char Title[128];
invalidate();
wsprintf(Title,_InactiveTitle,(char far*)_WindowTitle);
SetWindowText(CrtWindow,Title);
CanClose=TRUE;
while (GetMessage(&Msg,0,0,0)) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
//Deklaration von main()
int main(int argc,char**argv,char**envp);
#pragma argsused
int pascal WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow) {
int ret;
BOOL IsWin9x;
char fontname[80];
if (!hPrevInstance) {
WNDCLASS wc;
memset(&wc,0,sizeof(wc));
wc.lpfnWndProc=GraphWndProc;
wc.hInstance=hInstance;
wc.hIcon=LoadIcon(0,IDI_APPLICATION);
wc.hCursor=LoadCursor(0,IDC_ARROW);
wc.lpszClassName="GRAPHWIN";
RegisterClass(&wc);
}
GetModuleFileName(hInstance, _WindowTitle, sizeof(_WindowTitle));
OemToAnsi(_WindowTitle, _WindowTitle);
__ReadBufFPtr =_ReadBuf;
__WriteBufFPtr=_WriteBuf;
IsWin9x=HIBYTE(LOWORD(GetVersion()))>=95;
if (IsWin9x) {
ret=GetWindowsDirectory(fontname,sizeof(fontname)-7);
if (fontname[ret-1]!='\\') fontname[ret++]='\\';
lstrcpy(fontname+ret,"FONTS\\");
ret+=6;
}else{
ret=GetSystemDirectory(fontname,sizeof(fontname)-1);
if (fontname[ret-1]!='\\') fontname[ret++]='\\';
}
GetPrivateProfileString("386Enh","woafont","dosapp.fon",
fontname+ret,sizeof(fontname)-ret,"SYSTEM.INI");
AddFontResource(fontname);
CreateWindow("GRAPHWIN",_WindowTitle,
(WS_OVERLAPPEDWINDOW&~WS_MAXIMIZEBOX)|WS_VISIBLE,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
0,0,hInstance,NULL);
ret=main(_argc,_argv,environ);
if (CanTerminate) DestroyWindow(CrtWindow);
EndMessageLoop();
RemoveFontResource(fontname);
return ret;
}
Vorgefundene Kodierung: UTF-8 | 0
|