526 lines
14 KiB
C
526 lines
14 KiB
C
/*******************************************************************
|
|
*
|
|
* grwin32.c graphics driver for Win32 platform. 0.1
|
|
*
|
|
* This is the driver for displaying inside a window under Win32,
|
|
* used by the graphics utility of the FreeType test suite.
|
|
*
|
|
* Written by Antoine Leca.
|
|
* Copyright 1999-2000 by Antoine Leca, David Turner
|
|
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
|
*
|
|
* Borrowing liberally from the other FreeType drivers.
|
|
*
|
|
* This file is part of the FreeType project, and may only be used
|
|
* modified and distributed under the terms of the FreeType project
|
|
* license, LICENSE.TXT. By continuing to use, modify or distribute
|
|
* this file you indicate that you have read the license and
|
|
* understand and accept it fully.
|
|
*
|
|
******************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
#include "grwin32.h"
|
|
#include "grdevice.h"
|
|
|
|
|
|
/* logging facility */
|
|
#include <stdarg.h>
|
|
|
|
#define DEBUGxxx
|
|
|
|
#ifdef DEBUG
|
|
#define LOG(x) LogMessage##x
|
|
#else
|
|
#define LOG(x) /* rien */
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
static void LogMessage( const char* fmt, ... )
|
|
{
|
|
va_list ap;
|
|
|
|
va_start( ap, fmt );
|
|
vfprintf( stderr, fmt, ap );
|
|
va_end( ap );
|
|
}
|
|
#endif
|
|
/*-------------------*/
|
|
|
|
/* Size of the window. */
|
|
#define WIN_WIDTH 640u
|
|
#define WIN_HEIGHT 450u
|
|
|
|
/* These values can be changed, but WIN_WIDTH should remain for now a */
|
|
/* multiple of 32 to avoid padding issues. */
|
|
|
|
typedef struct _Translator
|
|
{
|
|
ULONG winkey;
|
|
grKey grkey;
|
|
|
|
} Translator;
|
|
|
|
static
|
|
Translator key_translators[] =
|
|
{
|
|
{ VK_BACK, grKeyBackSpace },
|
|
{ VK_TAB, grKeyTab },
|
|
{ VK_RETURN, grKeyReturn },
|
|
{ VK_ESCAPE, grKeyEsc },
|
|
{ VK_HOME, grKeyHome },
|
|
{ VK_LEFT, grKeyLeft },
|
|
{ VK_UP, grKeyUp },
|
|
{ VK_RIGHT, grKeyRight },
|
|
{ VK_DOWN, grKeyDown },
|
|
{ VK_PRIOR, grKeyPageUp },
|
|
{ VK_NEXT, grKeyPageDown },
|
|
{ VK_END, grKeyEnd },
|
|
{ VK_F1, grKeyF1 },
|
|
{ VK_F2, grKeyF2 },
|
|
{ VK_F3, grKeyF3 },
|
|
{ VK_F4, grKeyF4 },
|
|
{ VK_F5, grKeyF5 },
|
|
{ VK_F6, grKeyF6 },
|
|
{ VK_F7, grKeyF7 },
|
|
{ VK_F8, grKeyF8 },
|
|
{ VK_F9, grKeyF9 },
|
|
{ VK_F10, grKeyF10 },
|
|
{ VK_F11, grKeyF11 },
|
|
{ VK_F12, grKeyF12 }
|
|
};
|
|
|
|
static
|
|
Translator syskey_translators[] =
|
|
{
|
|
{ VK_F1, grKeyF1 }
|
|
};
|
|
|
|
/* This is a minimalist driver, it is only able to display */
|
|
/* a _single_ window. Moreover, only monochrome and gray */
|
|
/* bitmaps are supported.. */
|
|
|
|
/* handle of the window. */
|
|
static HWND hwndGraphic;
|
|
|
|
static int window_width, window_height;
|
|
|
|
/* the following variables are used to set the window title lazily */
|
|
static int title_set = 1;
|
|
static const char* the_title;
|
|
|
|
/* bitmap information */
|
|
static LPBITMAPINFO pbmi;
|
|
static HBITMAP hbm;
|
|
|
|
/* local event to pass on */
|
|
static grEvent ourevent;
|
|
static int eventToProcess = 0;
|
|
|
|
/* destroys the surface*/
|
|
static
|
|
void done_surface( grSurface* surface )
|
|
{
|
|
/* The graphical window has perhaps already destroyed itself */
|
|
if ( hwndGraphic )
|
|
{
|
|
DestroyWindow ( hwndGraphic );
|
|
PostMessage( hwndGraphic, WM_QUIT, 0, 0 );
|
|
}
|
|
grDoneBitmap( &surface->bitmap );
|
|
if ( pbmi ) free ( pbmi );
|
|
}
|
|
|
|
static
|
|
const int pixel_mode_bit_count[] =
|
|
{
|
|
0,
|
|
1, /* mono */
|
|
4, /* pal4 */
|
|
8, /* pal8 */
|
|
8, /* grays */
|
|
15, /* rgb15 */
|
|
16, /* rgb16 */
|
|
24, /* rgb24 */
|
|
32 /* rgb32 */
|
|
};
|
|
|
|
static
|
|
void refresh_rectangle( grSurface* surface,
|
|
int x,
|
|
int y,
|
|
int w,
|
|
int h )
|
|
{
|
|
HDC hDC;
|
|
int row_bytes;
|
|
|
|
LOG(( "Win32: refresh_rectangle( %08lx, %d, %d, %d, %d )\n",
|
|
(long)surface, x, y, w, h ));
|
|
(void)x;
|
|
(void)y;
|
|
(void)w;
|
|
(void)h;
|
|
|
|
row_bytes = surface->bitmap.pitch;
|
|
if (row_bytes < 0) row_bytes = -row_bytes;
|
|
|
|
if ( row_bytes*8 != pbmi->bmiHeader.biWidth * pbmi->bmiHeader.biBitCount )
|
|
pbmi->bmiHeader.biWidth = row_bytes * 8 / pbmi->bmiHeader.biBitCount;
|
|
|
|
hDC = GetDC ( hwndGraphic );
|
|
SetDIBits ( hDC, hbm,
|
|
0,
|
|
surface->bitmap.rows,
|
|
surface->bitmap.buffer,
|
|
pbmi,
|
|
DIB_RGB_COLORS );
|
|
|
|
ReleaseDC ( hwndGraphic, hDC );
|
|
|
|
ShowWindow( hwndGraphic, SW_SHOW );
|
|
InvalidateRect ( hwndGraphic, NULL, FALSE );
|
|
UpdateWindow ( hwndGraphic );
|
|
}
|
|
|
|
static
|
|
void set_title( grSurface* surface, const char* title )
|
|
{
|
|
(void)surface;
|
|
|
|
/* the title will be set on the next listen_event, just */
|
|
/* record it there.. */
|
|
the_title = title;
|
|
title_set = 0;
|
|
}
|
|
|
|
static
|
|
void listen_event( grSurface* surface,
|
|
int event_mask,
|
|
grEvent* grevent )
|
|
{
|
|
MSG msg;
|
|
|
|
(void)surface;
|
|
(void)event_mask;
|
|
|
|
if ( hwndGraphic && !title_set )
|
|
{
|
|
SetWindowText( hwndGraphic, the_title );
|
|
title_set = 1;
|
|
}
|
|
|
|
eventToProcess = 0;
|
|
while (GetMessage( &msg, 0, 0, 0 ))
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
if (eventToProcess)
|
|
break;
|
|
}
|
|
|
|
*grevent = ourevent;
|
|
}
|
|
|
|
/*
|
|
* set graphics mode
|
|
* and create the window class and the message handling.
|
|
*/
|
|
|
|
/* Declarations of the Windows-specific functions that are below. */
|
|
static BOOL RegisterTheClass ( void );
|
|
static BOOL CreateTheWindow ( int width, int height );
|
|
|
|
static
|
|
grSurface* init_surface( grSurface* surface,
|
|
grBitmap* bitmap )
|
|
{
|
|
static RGBQUAD black = { 0, 0, 0, 0 };
|
|
static RGBQUAD white = { 0xFF, 0xFF, 0xFF, 0 };
|
|
|
|
if( ! RegisterTheClass() ) return 0; /* if already running, fails. */
|
|
|
|
/* find some memory for the bitmap header */
|
|
if ( (pbmi = malloc ( sizeof ( BITMAPINFO ) + sizeof ( RGBQUAD ) * 256 ) )
|
|
/* 256 should really be 2 if not grayscale */
|
|
== NULL )
|
|
/* lack of memory; fails the process */
|
|
return 0;
|
|
|
|
LOG(( "Win32: init_surface( %08lx, %08lx )\n",
|
|
(long)surface, (long)bitmap ));
|
|
|
|
LOG(( " -- input bitmap =\n" ));
|
|
LOG(( " -- mode = %d\n", bitmap->mode ));
|
|
LOG(( " -- grays = %d\n", bitmap->grays ));
|
|
LOG(( " -- width = %d\n", bitmap->width ));
|
|
LOG(( " -- height = %d\n", bitmap->rows ));
|
|
|
|
/* create the bitmap - under Win32, we support all modes as the GDI */
|
|
/* handles all conversions automatically.. */
|
|
if ( grNewBitmap( bitmap->mode,
|
|
bitmap->grays,
|
|
bitmap->width,
|
|
bitmap->rows,
|
|
bitmap ) )
|
|
return 0;
|
|
|
|
LOG(( " -- output bitmap =\n" ));
|
|
LOG(( " -- mode = %d\n", bitmap->mode ));
|
|
LOG(( " -- grays = %d\n", bitmap->grays ));
|
|
LOG(( " -- width = %d\n", bitmap->width ));
|
|
LOG(( " -- height = %d\n", bitmap->rows ));
|
|
|
|
bitmap->pitch = -bitmap->pitch;
|
|
surface->bitmap = *bitmap;
|
|
|
|
/* initialize the header to appropriate values */
|
|
memset( pbmi, 0, sizeof ( BITMAPINFO ) + sizeof ( RGBQUAD ) * 256 );
|
|
|
|
switch ( bitmap->mode )
|
|
{
|
|
case gr_pixel_mode_mono:
|
|
pbmi->bmiHeader.biBitCount = 1;
|
|
pbmi->bmiColors[0] = white;
|
|
pbmi->bmiColors[1] = black;
|
|
break;
|
|
|
|
case gr_pixel_mode_gray:
|
|
pbmi->bmiHeader.biBitCount = 8;
|
|
pbmi->bmiHeader.biClrUsed = bitmap->grays;
|
|
{
|
|
int count = bitmap->grays;
|
|
int x;
|
|
RGBQUAD* color = pbmi->bmiColors;
|
|
|
|
for ( x = 0; x < count; x++, color++ )
|
|
{
|
|
color->rgbRed =
|
|
color->rgbGreen =
|
|
color->rgbBlue = (((count-x)*255)/count);
|
|
color->rgbReserved = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
free ( pbmi );
|
|
return 0; /* Unknown mode */
|
|
}
|
|
|
|
pbmi->bmiHeader.biSize = sizeof ( BITMAPINFOHEADER );
|
|
pbmi->bmiHeader.biWidth = bitmap->width;
|
|
pbmi->bmiHeader.biHeight = bitmap->rows;
|
|
pbmi->bmiHeader.biPlanes = 1;
|
|
|
|
if( ! CreateTheWindow( bitmap->width, bitmap->rows ) )
|
|
{
|
|
free ( pbmi );
|
|
return 0;
|
|
}
|
|
|
|
surface->done = (grDoneSurfaceFunc) done_surface;
|
|
surface->refresh_rect = (grRefreshRectFunc) refresh_rectangle;
|
|
surface->set_title = (grSetTitleFunc) set_title;
|
|
surface->listen_event = (grListenEventFunc) listen_event;
|
|
|
|
return surface;
|
|
}
|
|
|
|
|
|
/* ---- Windows-specific stuff ------------------------------------------- */
|
|
|
|
LRESULT CALLBACK Message_Process( HWND, UINT, WPARAM, LPARAM );
|
|
|
|
static
|
|
BOOL RegisterTheClass ( void )
|
|
{
|
|
WNDCLASS ourClass = {
|
|
/* UINT style */ 0,
|
|
/* WNDPROC lpfnWndProc */ Message_Process,
|
|
/* int cbClsExtra */ 0,
|
|
/* int cbWndExtra */ 0,
|
|
/* HANDLE hInstance */ 0,
|
|
/* HICON hIcon */ 0,
|
|
/* HCURSOR hCursor */ 0,
|
|
/* HBRUSH hbrBackground*/ 0,
|
|
/* LPCTSTR lpszMenuName */ NULL,
|
|
/* LPCTSTR lpszClassName*/ "FreeTypeTestGraphicDriver"
|
|
};
|
|
|
|
ourClass.hInstance = GetModuleHandle( NULL );
|
|
ourClass.hIcon = LoadIcon(0, IDI_APPLICATION);
|
|
ourClass.hCursor = LoadCursor(0, IDC_ARROW);
|
|
ourClass.hbrBackground= GetStockObject(BLACK_BRUSH);
|
|
|
|
return RegisterClass(&ourClass) != 0; /* return False if it fails. */
|
|
}
|
|
|
|
static
|
|
BOOL CreateTheWindow ( int width, int height )
|
|
{
|
|
window_width = width;
|
|
window_height = height;
|
|
|
|
if ( ! (hwndGraphic = CreateWindow(
|
|
/* LPCSTR lpszClassName; */ "FreeTypeTestGraphicDriver",
|
|
/* LPCSTR lpszWindowName; */ "FreeType Test Graphic Driver",
|
|
/* DWORD dwStyle; */ WS_OVERLAPPED | WS_SYSMENU,
|
|
/* int x; */ CW_USEDEFAULT,
|
|
/* int y; */ CW_USEDEFAULT,
|
|
/* int nWidth; */ width + 2*GetSystemMetrics(SM_CXBORDER),
|
|
/* int nHeight; */ height+ GetSystemMetrics(SM_CYBORDER)
|
|
+ GetSystemMetrics(SM_CYCAPTION),
|
|
/* HWND hwndParent; */ HWND_DESKTOP,
|
|
/* HMENU hmenu; */ 0,
|
|
/* HINSTANCE hinst; */ GetModuleHandle( NULL ),
|
|
/* void FAR* lpvParam; */ NULL))
|
|
)
|
|
/* creation failed... */
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Message processing for our Windows class */
|
|
LRESULT CALLBACK Message_Process( HWND handle, UINT mess,
|
|
WPARAM wParam, LPARAM lParam )
|
|
{
|
|
|
|
switch( mess )
|
|
{
|
|
case WM_DESTROY:
|
|
/* warn the main thread to quit if it didn't know */
|
|
ourevent.type = gr_event_key;
|
|
ourevent.key = grKeyEsc;
|
|
eventToProcess = 1;
|
|
hwndGraphic = 0;
|
|
PostQuitMessage ( 0 );
|
|
DeleteObject ( hbm );
|
|
return 0;
|
|
|
|
case WM_CREATE:
|
|
{
|
|
HDC hDC;
|
|
|
|
hDC = GetDC ( handle );
|
|
hbm = CreateDIBitmap (
|
|
/* HDC hdc; handle of device context */ hDC,
|
|
/* BITMAPINFOHEADER FAR* lpbmih; addr.of header*/ &pbmi->bmiHeader,
|
|
/* DWORD dwInit; CBM_INIT to initialize bitmap */ 0,
|
|
/* const void FAR* lpvBits; address of values */ NULL,
|
|
/* BITMAPINFO FAR* lpbmi; addr.of bitmap data */ pbmi,
|
|
/* UINT fnColorUse; RGB or palette indices */ DIB_RGB_COLORS);
|
|
ReleaseDC ( handle, hDC );
|
|
break;
|
|
}
|
|
|
|
case WM_PAINT:
|
|
{
|
|
HDC hDC, memDC;
|
|
HANDLE oldbm;
|
|
PAINTSTRUCT ps;
|
|
|
|
hDC = BeginPaint ( handle, &ps );
|
|
memDC = CreateCompatibleDC(hDC);
|
|
oldbm = SelectObject(memDC, hbm);
|
|
BitBlt ( hDC, 0, 0, window_width, window_height, memDC, 0, 0, SRCCOPY);
|
|
ReleaseDC ( handle, hDC );
|
|
SelectObject ( memDC, oldbm );
|
|
DeleteObject ( memDC );
|
|
EndPaint ( handle, &ps );
|
|
return 0;
|
|
}
|
|
|
|
case WM_SYSKEYDOWN:
|
|
{
|
|
int count = sizeof( syskey_translators )/sizeof( syskey_translators[0] );
|
|
Translator* trans = syskey_translators;
|
|
Translator* limit = trans + count;
|
|
for ( ; trans < limit; trans++ )
|
|
if ( wParam == trans->winkey )
|
|
{
|
|
ourevent.key = trans->grkey;
|
|
goto Do_Key_Event;
|
|
}
|
|
return DefWindowProc( handle, mess, wParam, lParam );
|
|
}
|
|
|
|
|
|
case WM_KEYDOWN:
|
|
switch ( wParam )
|
|
{
|
|
case VK_ESCAPE:
|
|
ourevent.type = gr_event_key;
|
|
ourevent.key = grKeyEsc;
|
|
eventToProcess = 1;
|
|
PostQuitMessage ( 0 );
|
|
return 0;
|
|
|
|
default:
|
|
/* lookup list of translated keys */
|
|
{
|
|
int count = sizeof( key_translators )/sizeof( key_translators[0] );
|
|
Translator* trans = key_translators;
|
|
Translator* limit = trans + count;
|
|
for ( ; trans < limit; trans++ )
|
|
if ( wParam == trans->winkey )
|
|
{
|
|
ourevent.key = trans->grkey;
|
|
goto Do_Key_Event;
|
|
}
|
|
}
|
|
|
|
/* the key isn't found, default processing */
|
|
/* return DefWindowProc( handle, mess, wParam, lParam ); */
|
|
return DefWindowProc( handle, mess, wParam, lParam );
|
|
}
|
|
|
|
case WM_CHAR:
|
|
{
|
|
ourevent.key = wParam;
|
|
|
|
Do_Key_Event:
|
|
ourevent.type = gr_event_key;
|
|
eventToProcess = 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc( handle, mess, wParam, lParam );
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int init_device( void )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void done_device( void )
|
|
{
|
|
}
|
|
|
|
grDevice gr_win32_device =
|
|
{
|
|
sizeof( grSurface ),
|
|
"win32",
|
|
|
|
init_device,
|
|
done_device,
|
|
|
|
(grDeviceInitSurfaceFunc) init_surface,
|
|
|
|
0,
|
|
0
|
|
};
|
|
|
|
|
|
/* End */
|