📄 winmain.cpp
字号:
// Simple application framework
#include <Context.h>
#include "App.h"
#include "dprintf.h"
#include "SoundContext.h"
#include <lang/Array.h>
#include <lang/Globals.h>
#include <lang/Throwable.h>
#include <stdint.h>
#include <io.h>
#include <time.h>
#include <stdio.h>
#include <direct.h>
#include <windows.h>
#include <assert.h>
#include <crtdbg.h>
#include <config.h>
using namespace lang;
class Win32SoundContext :
public SoundContext
{
public:
Win32SoundContext() {}
void playSound( const char* basename, int channel )
{
dprintf( "playSound( \"%s\", %d )\n", basename, channel );
}
};
//#define DOUBLE_SIZE
const int MAX_FPS = 32;
const int SCREEN_WIDTH = 240; //176;
const int SCREEN_HEIGHT = 320; //208;
const int WINDOW_MARGIN_WIDTH = 200;
const int WINDOW_MARGIN_HEIGHT = 100;
#ifdef DOUBLE_SIZE
const int SCREENW = SCREEN_WIDTH * 2;
const int SCREENH = SCREEN_HEIGHT * 2;
const int WINDOWMARGINW = WINDOW_MARGIN_WIDTH * 2;
const int WINDOWMARGINH = WINDOW_MARGIN_HEIGHT * 2;
#else
const int SCREENW = SCREEN_WIDTH;
const int SCREENH = SCREEN_HEIGHT;
const int WINDOWMARGINW = WINDOW_MARGIN_WIDTH;
const int WINDOWMARGINH = WINDOW_MARGIN_HEIGHT;
#endif
static App* s_app = 0;
static int s_screenscale = 1;
static bool s_active = true;
static void refreshWindowSize( HWND hwnd )
{
int width = WINDOWMARGINW + SCREENW*s_screenscale;
int height = WINDOWMARGINH + SCREENH*s_screenscale;
RECT cr;
GetClientRect( hwnd, &cr );
RECT wr;
GetWindowRect( hwnd, &wr );
MoveWindow( hwnd, wr.left, wr.top, width+(wr.right-cr.right-wr.left), height+(wr.bottom-cr.bottom-wr.top), TRUE );
}
static int currentTimeMillis()
{
LARGE_INTEGER freq;
if ( QueryPerformanceFrequency(&freq) )
{
LARGE_INTEGER cur;
QueryPerformanceCounter( &cur );
if ( freq.QuadPart >= 1000 )
{
__int64 msdiv = __int64(freq.QuadPart) / __int64(1000);
__int64 c = __int64(cur.QuadPart) / msdiv;
return (int)c;
}
}
return 0;
}
static const int s_keyToVk[] =
{
0,
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
VK_LEFT,
VK_RIGHT,
VK_UP,
VK_DOWN,
'Q',
'W',
VK_LSHIFT,
VK_RSHIFT,
};
static LRESULT wndproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
{
switch ( msg )
{
case WM_CLOSE:
//App::deleteApp();
DestroyWindow( hwnd );
PostQuitMessage(0);
return 0;
case WM_KEYDOWN:
case WM_KEYUP:{
int vk = (int)wp;
bool keydown = WM_KEYDOWN==msg;
if ( keydown )
{
int oldscreenscale = s_screenscale;
if ( VK_ADD == vk )
++s_screenscale;
if ( VK_SUBTRACT == vk )
--s_screenscale;
if ( s_screenscale < 1 )
s_screenscale = 1;
else if ( s_screenscale > 4 )
s_screenscale = 4;
if ( oldscreenscale != s_screenscale )
refreshWindowSize( hwnd );
}
for ( int i = 0 ; i < App::KEY_COUNT ; ++i )
{
App::KeyType kt = (App::KeyType)i;
if ( s_keyToVk[i] == vk ||
(vk == VK_RETURN && kt == App::KEY_5) )
{
if ( keydown )
s_app->keyDown( kt );
else
s_app->keyUp( kt );
break;
}
}
break;}
case WM_ACTIVATE:{
s_active = ( LOWORD(wp) != WA_INACTIVE );
char name[256];
GetWindowText( hwnd, name, sizeof(name) );
break;}
}
return DefWindowProc( hwnd, msg, wp, lp );
}
static HWND createMainWindow( const char* classname, const char* name,
int width, int height, bool fullscreen, HINSTANCE instance, int iconresid )
{
DWORD style = WS_VISIBLE|WS_OVERLAPPEDWINDOW;
DWORD exstyle = 0;
if ( fullscreen )
{
style = WS_VISIBLE|WS_POPUP;
exstyle = WS_EX_TOPMOST;
}
HWND parenthwnd = 0;
HICON icon = 0;
if ( iconresid > 0 )
icon = LoadIcon( instance, MAKEINTRESOURCE(iconresid) );
WNDCLASSEXA wndclassex;
wndclassex.cbSize = sizeof(WNDCLASSEXA);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = (WNDPROC)wndproc;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = (HINSTANCE)instance;
wndclassex.hIcon = icon;
wndclassex.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclassex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclassex.lpszMenuName = 0;
wndclassex.lpszClassName = classname;
wndclassex.hIconSm = 0;
bool ok = RegisterClassExA(&wndclassex) != 0;
assert( ok );
void* userparam = 0;
HWND hwnd = CreateWindowExA( exstyle, classname, name, style, 0, 0, width, height, parenthwnd, 0, instance, userparam );
if ( !hwnd )
{
UnregisterClass( classname, instance );
return 0;
}
refreshWindowSize( hwnd );
if ( fullscreen )
ShowCursor( FALSE );
return hwnd;
}
static bool flushMessages()
{
MSG msg;
while ( PeekMessage(&msg,0,0,0,PM_NOREMOVE) )
{
if ( !GetMessage(&msg,0,0,0) )
return false;
DispatchMessage( &msg );
}
return true;
}
static int run( HINSTANCE instance )
{
HWND hwnd = 0;
Win32SoundContext soundcontext;
try
{
remove( "C:/log.txt" );
time_t t;
time( &t );
dprintf( "Game session: %s---------------------------------------------------\n", asctime( localtime( &t ) ) );
assert( sizeof(s_keyToVk)/sizeof(s_keyToVk[0]) == App::KEY_COUNT && "App::KeyType codes don't match Win32 virtual key codes" );
// allocate app
s_app = init();
// create main window
hwnd = createMainWindow( __FILE__, s_app->name(), SCREENW*s_screenscale, SCREENH*s_screenscale, false, instance, 0 );
if ( !hwnd )
{
MessageBox( 0, "Failed to create main window", "Error", MB_OK );
return 1;
}
// init Context
Context contextobj;
Context* context = &contextobj;
const int size = SCREENW*SCREENH;
Array<uint16_t> backbuffer(SCREENW*SCREENH);
for ( int i = 0 ; i < size ; ++i )
backbuffer[i] = 0xF00;
context->set( backbuffer.begin(), SCREENW*2, SCREENW, SCREENH );
// create frame buffer
Array<uint16_t> framebuffer(SCREENW*SCREENH);
memset( framebuffer.begin(), 0, sizeof(framebuffer) );
char bminfomem[ sizeof(BITMAPINFO) + 16 ];
memset( &bminfomem, 0, sizeof(bminfomem) );
BITMAPINFO& bminfo = *reinterpret_cast<BITMAPINFO*>(bminfomem);
bminfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
bminfo.bmiHeader.biPlanes = 1;
bminfo.bmiHeader.biBitCount = 16;
bminfo.bmiHeader.biCompression = BI_BITFIELDS;
bminfo.bmiHeader.biWidth = context->width();
bminfo.bmiHeader.biHeight = -context->height();
((unsigned long*)bminfo.bmiColors)[0] = 31 << 11;
((unsigned long*)bminfo.bmiColors)[1] = 63 << 5;
((unsigned long*)bminfo.bmiColors)[2] = 31;
// init App
s_app->init( context, &soundcontext );
// main loop
int oldtime = currentTimeMillis();
while ( flushMessages() )
{
int time = currentTimeMillis();
if ( !s_active )
oldtime = time;
bool updated = false;
const int dt = 32;
while ( s_active && time-oldtime > dt )
{
oldtime += dt;
if ( !s_app->update( Fix(8), context ) )
{
PostQuitMessage( 0 );
}
int16_t buf[500];
soundcontext.mix( buf, 500 );
updated = true;
}
if ( updated )
{
HDC hdc = GetDC( hwnd );
// back buffer -> frame buffer -> window
const int size = SCREENW*SCREENH;
for ( int i = 0 ; i < size ; ++i )
{
int c = backbuffer[i];
int r = (c>>8)&0xF;
int g = (c>>4)&0xF;
int b = (c)&0xF;
framebuffer[i] = uint16_t( (r<<12) + (g<<7) + (b<<1) );
}
StretchDIBits( hdc, 0, 0, SCREENW*s_screenscale, SCREENH*s_screenscale, 0, 0,
SCREENW, SCREENH, framebuffer.begin(), &bminfo, DIB_RGB_COLORS, SRCCOPY );
ReleaseDC( hwnd, hdc );
}
}
}
catch ( lang::Throwable& e )
{
// minimize window so that it doesn't overlap message box
ShowCursor( TRUE );
MoveWindow( hwnd, 0, 0, 4, 4, TRUE );
//MessageBox( hwnd, "Application error. See debug log at C:\\log.txt", "Error", MB_OK );
MessageBox( hwnd, e.getMessage().format().c_str(), "Game Error", MB_OK );
}
delete s_app;
s_app = 0;
DestroyWindow( hwnd );
hwnd = 0;
return 0;
}
int WINAPI WinMain( HINSTANCE instance, HINSTANCE, LPSTR /*commandline*/, int /*commandshow*/ )
{
int* p = new int(1234);
int retval = run( instance );
lang::Globals::cleanup();
delete p;
_CrtDumpMemoryLeaks();
return retval;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -