⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 graphics.cpp

📁 由一个古老的BASIC解释器改进而成, 保留了ANSI C固有的艺术美感.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// graphics.cpp

#ifdef __BORLANDC__
#pragma warn -8027
#endif

#include "graphics.h"
#include "sysvar.h"
#include "error.h"
#include "var.h"
//#include "cursor.h"
#include "key.h"
#include "util.h"

// Para depuracion
#include <iostream>
using std::cerr;
using std::endl;
#include <cassert>
#define ASSERT assert

#include <map>
#include <queue>
#include <cmath>

#ifdef BLASSIC_USE_SVGALIB

#include <unistd.h>
#include <sys/types.h>
#include <vga.h>
#include <vgagl.h>

char * font= NULL;

#endif

#ifdef BLASSIC_USE_X

#include <X11/Xlib.h>
#include <X11/Xutil.h>

Display * display= 0;
int screen;
Window window;
Pixmap pixmap;
bool pixmap_created= false;
GC gc, gcp;
XGCValues gcvalues, gcvaluesp;

XEvent x_event;

long eventusedmask= ExposureMask | KeyPressMask |
	ButtonPressMask | ButtonReleaseMask |
	PointerMotionMask | EnterWindowMask;
	
XColor xcBlack, xcBlue, xcGreen, xcCyan,
        xcRed, xcMagenta, xcBrown, xcLightGrey,
	xcDarkGrey, xcLightBlue, xcLightGreen, xcLightCyan,
        xcLightRed, xcLightMagenta, xcYellow, xcWhite;
typedef XColor * pcolor;

#endif

#ifdef BLASSIC_USE_WINDOWS

#include <process.h>
#include <windows.h>

ATOM atomClass;
HANDLE hEvent;
HWND window;
HDC hdc;
HBITMAP pixmap;
HDC hdcPixmap;
HPEN xcBlack, xcBlue, xcGreen, xcCyan,
        xcRed, xcMagenta, xcBrown, xcLightGrey,
	xcDarkGrey, xcLightBlue, xcLightGreen, xcLightCyan,
        xcLightRed, xcLightMagenta, xcYellow, xcWhite;
typedef HPEN * pcolor;

#endif

#if defined (BLASSIC_USE_WINDOWS) || defined (BLASSIC_USE_X)

pcolor pforeground, pbackground,
	default_foreground, default_background;

#endif

#include <string>
#include <algorithm>

namespace {

bool fSynchro= false;

class CriticalSection {
public:
        CriticalSection ()
        {
                #ifdef BLASSIC_USE_WINDOWS
                InitializeCriticalSection (& cs);
                #endif
        }
        ~CriticalSection ()
        {
                #ifdef BLASSIC_USE_WINDOWS
                DeleteCriticalSection (& cs);
                #endif
        }
        void enter ()
        {
                #ifdef BLASSIC_USE_WINDOWS
                EnterCriticalSection (& cs);
                #endif
        }
        void leave ()
        {
                #ifdef BLASSIC_USE_WINDOWS
                LeaveCriticalSection (& cs);
                #endif
        }
private:
        #ifdef BLASSIC_USE_WINDOWS
        CRITICAL_SECTION cs;
        #endif
};

class CriticalLock {
public:
        CriticalLock (CriticalSection & cs) :
                cs (cs)
        {
                cs.enter ();
        }
        ~CriticalLock ()
        {
                cs.leave ();
        }
private:
        CriticalSection & cs;
};

class QueueKey {
public:
        QueueKey ()
        {
        }
        void push (const std::string & str)
        {
                CriticalLock lock (cs);
                q.push (str);
        }
        std::string pop ()
        {
                CriticalLock lock (cs);
                std::string str= q.front ();
                q.pop ();
                return str;
        }
        bool empty ()
        {
                return q.empty ();
        }
private:
        std::queue <std::string> q;
        CriticalSection cs;
};

QueueKey queuekey;

bool inited= false;
bool window_created= false;
bool opaquemode= true;

int xmousepos, ymousepos;

const int text_mode= 0, user_mode= -1;

int actualmode= text_mode;

inline void requiregraphics ()
{
	if (actualmode == text_mode)
		throw ErrNoGraphics;
}

#ifdef BLASSIC_USE_SVGALIB

bool svgalib= false;

#else

//const bool svgalib= false;

#endif

int screenwidth, screenheight;
int lastx, lasty;

#if defined BLASSIC_USE_X

static const int
	drawmode_copy= GXcopy,
	drawmode_xor= GXxor,
	drawmode_and= GXand,
	drawmode_or= GXor,
	drawmode_invert= GXinvert;

#elif defined BLASSIC_USE_WINDOWS

static const int
	drawmode_copy= R2_COPYPEN,
	drawmode_xor= R2_XORPEN,
	// Revisar los valores para and y or.
	drawmode_and= R2_MASKPEN,
	drawmode_or= R2_MERGEPEN,
	drawmode_invert= R2_NOT;

#endif

int drawmode= drawmode_copy;

void reinit_pixmap ()
{
        #ifdef BLASSIC_USE_WINDOWS
        RECT r = { 0, 0, screenwidth, screenheight };
        FillRect (hdcPixmap, & r, (HBRUSH) GetStockObject (WHITE_BRUSH) );
        #endif

        #ifdef BLASSIC_USE_X
	XSetForeground (display, gcp, WhitePixel (display, screen) );
	XFillRectangle (display, pixmap, gcp, 0, 0, screenwidth, screenheight);
	XSetForeground (display, gcp, BlackPixel (display, screen) );
        #endif
}

void reinit_window ()
{
        #ifdef BLASSIC_USE_WINDOWS
        //HDC hdc= GetDC (window);
        BitBlt (hdc, 0, 0, screenwidth, screenheight, hdcPixmap, 0, 0, SRCCOPY);
        //ReleaseDC (window, hdc);
        #endif

        #ifdef BLASSIC_USE_X
	XSetFunction (display, gc, drawmode_copy);
	XCopyArea (display, pixmap, window, gc,
		0, 0, screenwidth, screenheight, 0, 0);
	XSetForeground (display, gc, BlackPixel (display, screen) );
	XSetForeground (display, gc, pforeground->pixel);
	XFlush (display);
	XSetFunction (display, gc, drawmode);
        #endif
}

#ifdef BLASSIC_USE_WINDOWS

const UINT
        WM_USER_CREATE_WINDOW= WM_USER + 3,
        WM_USER_DESTROY_WINDOW= WM_USER + 4;

HANDLE hthread= NULL;
DWORD idthread= 0;

LRESULT APIENTRY windowproc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        static int width, height;
        switch (uMsg) {
        case WM_SIZE:
                width= LOWORD (lParam);
                height= HIWORD (lParam);
                return TRUE;
        case WM_ERASEBKGND:
                return TRUE;
        case WM_PAINT:
                {
                //err << "WM_PAINT " << width << ", " << height << endl;
                PAINTSTRUCT paintstruct;
                HDC hdc= BeginPaint (hwnd, & paintstruct);
                BitBlt (hdc, 0, 0, width, height, hdcPixmap, 0, 0, SRCCOPY);
                EndPaint (hwnd, & paintstruct);
                }
                return FALSE;
        case WM_KEYDOWN:
                {
                        WORD k= (WORD) wParam;
                        //std::string str= string_from_virtual_key (k);
                        std::string str= string_from_key (k);
                        if (! str.empty () )
                        {
                                queuekey.push (str);
                                return TRUE;
                        }
                }
                return FALSE;
        case WM_CHAR:
                {
                        char c= (char) wParam;
                        queuekey.push (std::string (1, c) );
                }
                return TRUE;
        case WM_MOUSEMOVE:
                xmousepos= LOWORD (lParam);
                ymousepos= HIWORD (lParam);
                return TRUE;
        case WM_LBUTTONDOWN:
                queuekey.push (strCLICK);
                return TRUE;
        case WM_RBUTTONDOWN:
        	queuekey.push (strSCLICK);
        	return TRUE;
        case WM_LBUTTONUP:
                queuekey.push (strRELEASE);
                return TRUE;
        case WM_RBUTTONUP:
        	queuekey.push (strSRELEASE);
        	return TRUE;
        case WM_DESTROY:
                SetEvent (hEvent);
                return TRUE;
        default:
                return DefWindowProc (hwnd, uMsg, wParam, lParam);
        }
}

void thread_create_window (int width, int height)
{
        HDC hdcscreen= CreateDC ("DISPLAY", NULL, NULL, NULL);
        if (hdcscreen == NULL)
                return;
        pixmap= CreateCompatibleBitmap (hdcscreen, width, height);
        if (pixmap == NULL)
        {
                DeleteDC (hdcscreen);
                return;
        }
        hdcPixmap= CreateCompatibleDC (hdcscreen);
        DeleteDC (hdcscreen);
        if (hdcPixmap == NULL)
        {
                DeleteObject (pixmap);
                pixmap= NULL;
                return;
        }
        SelectObject (hdcPixmap, pixmap);
        reinit_pixmap ();

        window= CreateWindow (
                LPCTSTR (atomClass),
                "blassic",
                WS_VISIBLE,
                0, 0,
                width + GetSystemMetrics (SM_CXDLGFRAME) * 2,
                height + GetSystemMetrics (SM_CYDLGFRAME) * 2 +
                        GetSystemMetrics (SM_CYCAPTION),
                NULL,
                NULL,
                GetModuleHandle (0),
                NULL);
        if (window)
        {
                SetActiveWindow (window);
                hdc= GetDC (window);
                window_created= true;
        }
        else
        {
                DeleteDC (hdcPixmap);
                DeleteObject (pixmap);
                pixmap= NULL;
        }
}

// Testing new method of create and destroy windows.

struct ThreadParams {
        int width, height;
};

unsigned WINAPI threadproc (void * arg)
{
        MSG msg;
        ThreadParams * tp= reinterpret_cast <ThreadParams *> (arg);
        thread_create_window (tp->width, tp->height);
        // Ensure the message queue exist before the main thread continues.
        // Perhpas unnecesary with the new method, but...
        PeekMessage (& msg, NULL, 0, UINT (-1), PM_NOREMOVE);
        SetEvent (hEvent);
        if (! window_created)
                return 0;
        while (GetMessage (& msg, NULL, 0, 0) )
        {
                switch (msg.message)
                {
                case WM_USER_CREATE_WINDOW:
                        //thread_create_window (msg.wParam, msg.lParam);
                        SetEvent (hEvent);
                        break;
                case WM_USER_DESTROY_WINDOW:
                        if (DestroyWindow (window) == 0)
                                cerr << "Error al destruir: " <<
                                        GetLastError () << endl;
                        break;
                default:
                        TranslateMessage (& msg);
                        DispatchMessage (& msg);
                }
        }
        return 0;
}

void create_thread (int width, int height)
{
        ThreadParams tp= { width, height };
        hthread= HANDLE (_beginthreadex (NULL, 0, threadproc,
                & tp, 0, (unsigned int *) (& idthread) ) );
        if (hthread == NULL)
        {
                cerr << "Error al crear thread para graficos" << endl;
                throw ErrBlassicInternal;
        }
        WaitForSingleObject (hEvent, INFINITE);
        if (! window_created)
        {
                WaitForSingleObject (hthread, INFINITE);
                CloseHandle (hthread);
                idthread= 0;
                hthread= NULL;
        }
}

void destroy_thread ()
{
        if (idthread)
        {
                BOOL r= PostThreadMessage (idthread, WM_QUIT, 0, 0);
                if (r == 0)
                {
                        TerminateThread (hthread, 0);
                }
                else
                {
                        WaitForSingleObject (hthread, INFINITE);
                }
                CloseHandle (hthread);
                idthread= 0;
                hthread= NULL;
        }
}

#endif // WINDOWS

void create_window (int width, int height)
{
        #ifdef BLASSIC_USE_WINDOWS
        if (hthread == NULL)
        {
                create_thread (width, height);
                if (hthread == NULL)
                        throw ErrBlassicInternal;
        }
        BOOL r= PostThreadMessage (idthread, WM_USER_CREATE_WINDOW,
                WPARAM (width), LPARAM (height) );
        if (r == 0)
        {
                cerr << "Error al comunicarse con thread de graficos. "
                        "GetLastError =" << GetLastError () <<
                        endl;
                destroy_thread ();
                throw ErrBlassicInternal;
        }
        WaitForSingleObject (hEvent, INFINITE);
        if (! window_created)
        {
                cerr << "Error al crear ventana" << endl;
                throw ErrBlassicInternal;
        }
        #endif

	#ifdef BLASSIC_USE_X
	#if 1
	window= XCreateSimpleWindow (display,
		RootWindow (display, screen),
		0, 0, width, height,
		5, BlackPixel (display, screen),
		WhitePixel (display, screen) );
	#else
	int depth= 8;
	window= XCreateWindow (display,
		RootWindow (display, screen),
		0, 0, width, height,
		5,
		depth,
		InputOutput,
		CopyFromParent,
		0,
		NULL);
	#endif
	window_created= true;

	#if 1
	int depth= DefaultDepth (display, DefaultScreen (display) );
	#endif
	pixmap= XCreatePixmap (display, window,
		width, height, depth);
	pixmap_created= true;

	gc= XCreateGC (display, window, 0, & gcvalues);
	gcp= XCreateGC (display, pixmap, 0, & gcvaluesp);

	//XSetForeground (display, gcp, WhitePixel (display, screen) );
	//XFillRectangle (display, pixmap, gcp, 0, 0, width, height);
	//XSetForeground (display, gcp, BlackPixel (display, screen) );
	reinit_pixmap ();

	XSetStandardProperties (display, window,
			"blassic", "blassic", None,
			0, 0, NULL);

	XSelectInput (display, window, eventusedmask);

	XMapWindow (display, window);

	graphics::idle ();
        #endif
}

void destroy_window ()
{
        #ifdef BLASSIC_USE_WINDOWS
        PostThreadMessage (idthread, WM_USER_DESTROY_WINDOW, 0, 0);
        WaitForSingleObject (hEvent, INFINITE);
        DeleteDC (hdcPixmap);
        DeleteObject (pixmap);
        window= 0;
        window_created= false;
        destroy_thread ();
        #endif

        #ifdef BLASSIC_USE_X
	XDestroyWindow (display, window);
	window_created= false;
	XFreePixmap (display, pixmap);
	pixmap_created= false;
	XFlush (display);
	graphics::idle ();
        #endif
}

#ifdef BLASSIC_USE_WINDOWS

struct assign_color {
	pcolor pxc;
	int r, g, b;
};

class assign_elem {
public:
	void operator () (const assign_color & elem) const
	{
		* elem.pxc= CreatePen (PS_SOLID, 1,
			RGB (elem.r, elem.g, elem.b) );
	}
};

void init_wincolors ()
{
        #ifdef __BORLANDC__
        // With const Borland can't expand the for_each.
        typedef assign_color const_assign_color;
        #else
        typedef const assign_color const_assign_color;
        #endif
        static const_assign_color table_colors []= {
		#if 0

	        { &xcBlack,        0, 0, 0 },
        	{ &xcBlue,         0, 0, 42 * 4 },

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -