lwjgl/src/native/win32/org_lwjgl_Window.cpp

601 lines
16 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2002 Light Weight Java Game Library Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'Light Weight Java Game Library' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* $Id: org_lwjglWindow.cpp,v 1.0 2003/02/12 09:29:07 cix_foo Exp $
*
* Base Win32 window
*
* @author cix_foo <cix_foo@users.sourceforge.net>
* @version $Revision: 1.0 $
*/
#define _PRIVATE_WINDOW_H_
#include "Window.h"
#include "org_lwjgl_Window.h"
bool oneShotInitialised = false; // Registers the LWJGL window class
HWND hwnd = NULL; // Handle to the window
HDC hdc = NULL; // Device context
2003-08-03 18:10:03 -04:00
HGLRC hglrc = NULL; // OpenGL context
LPDIRECTINPUT lpdi = NULL; // DirectInput
bool isFullScreen = false; // Whether we're fullscreen or not
2003-03-28 14:02:24 -05:00
bool isMinimized = false; // Whether we're minimized or not
2003-03-28 16:04:43 -05:00
JNIEnv * environment = NULL; // Cached environment
2003-08-03 18:10:03 -04:00
jclass window; // Cached Java Window class
extern HINSTANCE dll_handle; // Handle to the LWJGL dll
2003-05-16 14:39:46 -04:00
RECT clientSize;
2003-08-03 18:10:03 -04:00
//CAS: commented these out as no longer used
//extern void tempRestoreDisplayMode();
//extern void tempResetDisplayMode();
#define WINDOWCLASSNAME "LWJGL"
/*
* Utility function to throw an Exception
*/
void throwException(JNIEnv * env, const char * err)
{
jclass cls = env->FindClass("java/lang/Exception");
env->ThrowNew(cls, err);
env->DeleteLocalRef(cls);
}
2003-03-29 16:52:14 -05:00
/*
* Utility function to throw a RuntimeException
*/
void throwRuntimeException(JNIEnv * env, const char * err)
{
jclass cls = env->FindClass("java/lang/RuntimeException");
env->ThrowNew(cls, err);
env->DeleteLocalRef(cls);
}
2003-08-03 18:10:03 -04:00
/*
* Find an appropriate pixel format
*/
static int findPixelFormat(JNIEnv *env, unsigned int flags, int bpp, int alpha, int depth, int stencil)
{
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
flags, // RGBA type
PFD_TYPE_RGBA,
(BYTE)bpp,
0, 0, 0, 0, 0, 0, // color bits ignored
(BYTE)alpha,
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
(BYTE)depth,
(BYTE)stencil,
0, // No auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
// get the best available match of pixel format for the device context
int iPixelFormat = ChoosePixelFormat(hdc, &pfd);
if (iPixelFormat == 0) {
throwException(env, "Failed to choose pixel format");
return -1;
}
#ifdef _DEBUG
printf("Pixel format is %d\n", iPixelFormat);
#endif
// make that the pixel format of the device context
if (SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE) {
printf("Failed to set pixel format\n");
throwException(env, "Failed to choose pixel format");
return -1;
}
// 3. Check the chosen format matches or exceeds our specifications
PIXELFORMATDESCRIPTOR desc;
if (DescribePixelFormat(hdc, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &desc) == 0) {
throwException(env, "Could not describe pixel format");
return -1;
}
if (desc.cColorBits < bpp) {
throwException(env, "This application requires a greater colour depth");
return -1;
}
if (desc.cAlphaBits < alpha) {
throwException(env, "This application requires a greater alpha depth");
return -1;
}
if (desc.cStencilBits < stencil) {
throwException(env, "This application requires a greater stencil depth");
return -1;
}
if (desc.cDepthBits < depth) {
throwException(env, "This application requires a greater depth buffer depth");
return -1;
}
if ((desc.dwFlags & PFD_GENERIC_FORMAT) != 0 || (desc.dwFlags & PFD_GENERIC_ACCELERATED) != 0) {
throwException(env, "Mode not supported by hardware");
return -1;
}
if ((desc.dwFlags & flags) != flags) {
throwException(env, "Capabilities not supported");
return -1;
}
// 4. Initialise other things now
if (extgl_Open() != 0) {
throwException(env, "Failed to open extgl");
return -1;
}
return iPixelFormat;
}
/*
* Create DirectInput.
* Returns true for success, or false for failure
*/
2003-08-03 18:10:03 -04:00
static bool createDirectInput()
{
// Create input
HRESULT ret = DirectInputCreate(dll_handle, DIRECTINPUT_VERSION, &lpdi, NULL);
if (ret != DI_OK && ret != DIERR_BETADIRECTINPUTVERSION ) {
printf("Failed to create directinput");
switch (ret) {
case DIERR_INVALIDPARAM :
printf(" - Invalid parameter\n");
break;
case DIERR_OLDDIRECTINPUTVERSION :
printf(" - Old Version\n");
break;
case DIERR_OUTOFMEMORY :
printf(" - Out Of Memory\n");
break;
default:
printf(" - Unknown failure\n");
}
return false;
} else {
return true;
}
}
/*
* Close the window
*/
2003-08-03 18:10:03 -04:00
static void closeWindow()
{
// Release DirectInput
if (lpdi != NULL) {
#ifdef _DEBUG
printf("Destroying directinput\n");
#endif
lpdi->Release();
lpdi = NULL;
}
// Release device context
2003-03-28 16:04:43 -05:00
if (hdc != NULL && hwnd != NULL) {
#ifdef _DEBUG
printf("Releasing DC\n");
#endif
ReleaseDC(hwnd, hdc);
}
// Close the window
if (hwnd != NULL) {
#ifdef _DEBUG
printf("Destroy window\n");
#endif
// Vape the window
DestroyWindow(hwnd);
#ifdef _DEBUG
printf("Destroyed window\n");
#endif
hwnd = NULL;
}
}
/*
* Called when the application is alt-tabbed to or from
*/
2003-08-03 18:10:03 -04:00
static void appActivate(bool active)
{
// if (!active) {
// tempResetDisplayMode();
// }
if (active) {
SetForegroundWindow(hwnd);
ShowWindow(hwnd, SW_RESTORE);
2003-05-16 14:39:46 -04:00
} else if (isFullScreen) {
ShowWindow(hwnd, SW_MINIMIZE);
2003-05-16 14:39:46 -04:00
}
// if (active) {
// tempRestoreDisplayMode();
// }
}
/*
* WindowProc for the GL window.
*/
LRESULT CALLBACK lwjglWindowProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
2003-03-28 16:04:43 -05:00
if (environment == NULL) {
return DefWindowProc(hWnd, msg, wParam, lParam);
}
switch (msg) {
// disable screen saver and monitor power down messages which wreak havoc
case WM_SYSCOMMAND:
{
switch (wParam) {
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0L;
case SC_MINIMIZE:
2003-08-03 18:10:03 -04:00
environment->SetStaticBooleanField(window, environment->GetFieldID(environment->GetObjectClass(window), "minimized", "Z"), JNI_TRUE);
appActivate(false);
break;
case SC_RESTORE:
2003-08-03 18:10:03 -04:00
environment->SetStaticBooleanField(window, environment->GetFieldID(environment->GetObjectClass(window), "minimized", "Z"), JNI_FALSE);
appActivate(true);
break;
case SC_CLOSE:
2003-08-03 18:10:03 -04:00
environment->SetStaticBooleanField(window, environment->GetFieldID(environment->GetObjectClass(window), "closeRequested", "Z"), JNI_TRUE);
//don't continue processing this command since this
//would shutdown the window, which the application might not want to
return 0L;
}
}
break;
case WM_ACTIVATE:
{
switch(LOWORD(wParam)) {
case WA_ACTIVE:
case WA_CLICKACTIVE:
2003-08-03 18:10:03 -04:00
environment->SetStaticBooleanField(window, environment->GetFieldID(environment->GetObjectClass(window), "minimized", "Z"), JNI_FALSE);
isMinimized = false;
break;
case WA_INACTIVE:
2003-08-03 18:10:03 -04:00
environment->SetStaticBooleanField(window, environment->GetFieldID(environment->GetObjectClass(window), "minimized", "Z"), JNI_TRUE);
isMinimized = true;
break;
}
appActivate(!isMinimized);
}
break;
case WM_QUIT:
{
2003-08-03 18:10:03 -04:00
environment->SetStaticBooleanField(window, environment->GetFieldID(environment->GetObjectClass(window), "closeRequested", "Z"), JNI_TRUE);
return 0L;
}
case WM_PAINT:
{
2003-08-03 18:10:03 -04:00
environment->SetStaticBooleanField(window, environment->GetFieldID(environment->GetObjectClass(window), "dirty", "Z"), JNI_TRUE);
}
}
// default action
return DefWindowProc(hWnd, msg, wParam, lParam);
}
/*
* Register the LWJGL window class.
* Returns true for success, or false for failure
*/
2003-08-03 18:10:03 -04:00
static bool registerWindow()
{
if (!oneShotInitialised) {
WNDCLASS windowClass;
windowClass.style = CS_GLOBALCLASS | CS_OWNDC;
windowClass.lpfnWndProc = lwjglWindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = dll_handle;
windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = WINDOWCLASSNAME;
if (RegisterClass(&windowClass) == 0) {
printf("Failed to register window class\n");
return false;
}
#ifdef _DEBUG
2003-03-28 14:02:24 -05:00
printf("Window registered\n");
#endif
oneShotInitialised = true;
}
return true;
}
2003-08-03 18:10:03 -04:00
/*
* Handle native Win32 messages
*/
static void handleMessages(JNIEnv * env, jclass clazz)
{
// Cache env and obj
environment = env;
window = clazz;
/*
* Now's our chance to deal with Windows messages that are
* otherwise just piling up and causing everything not to
* work properly
*/
MSG msg;
while (PeekMessage(
&msg, // message information
hwnd, // handle to window
0, // first message
0, // last message
PM_REMOVE // removal options
))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
};
environment = NULL;
window = NULL;
}
/*
* Create a window with the specified title, position, size, and
* fullscreen attribute. The window will have DirectInput associated
* with it.
*
* Returns true for success, or false for failure
*/
2003-08-03 18:10:03 -04:00
static bool createWindow(const char * title, int x, int y, int width, int height, bool fullscreen)
{
// 1. Register window class if necessary
if (!registerWindow())
return false;
// 2. Create the window
int exstyle, windowflags;
if (fullscreen) {
2003-06-07 08:48:21 -04:00
exstyle = WS_EX_APPWINDOW | WS_EX_TOPMOST;
windowflags = WS_POPUP | WS_VISIBLE;
} else {
2003-06-07 08:48:21 -04:00
exstyle = WS_EX_APPWINDOW;
windowflags = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_VISIBLE | WS_MINIMIZEBOX | WS_SYSMENU;
}
// If we're not a fullscreen window, adjust the height to account for the
// height of the title bar:
clientSize.bottom = height;
clientSize.left = 0;
clientSize.right = width;
clientSize.top = 0;
AdjustWindowRectEx(
&clientSize, // client-rectangle structure
windowflags, // window styles
FALSE, // menu-present option
exstyle // extended window style
);
// Create the window now, using that class:
hwnd = CreateWindowEx (
exstyle,
WINDOWCLASSNAME,
title,
windowflags,
2003-05-16 14:39:46 -04:00
x, y, clientSize.right - clientSize.left, clientSize.bottom - clientSize.top,
NULL,
NULL,
dll_handle,
NULL);
if (hwnd == NULL) {
printf("Failed to create window\n");
return false;
}
2003-03-28 16:04:43 -05:00
#ifdef _DEBUG
printf("Created window\n");
#endif
// ShowWindow(hwnd, SW_SHOWNORMAL);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
SetForegroundWindow(hwnd);
SetFocus(hwnd);
hdc = GetWindowDC(hwnd);
// Success! Now you need to initialize a GL object, which creates a GL rendering context;
// and then to issue commands to it, you need to call gl::makeCurrent().
// 3. Hide the mouse if necessary
isFullScreen = fullscreen == JNI_TRUE;
// 4. Create DirectInput
if (!createDirectInput()) {
// Close the window
closeWindow();
return false;
}
return true;
}
/*
* Class: org_lwjgl_Window
* Method: nSetTitle
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_Window_nSetTitle
2003-08-03 18:10:03 -04:00
(JNIEnv * env, jclass clazz, jstring title_obj)
{
2003-03-30 14:26:39 -05:00
const char * title = env->GetStringUTFChars(title_obj, NULL);
SetWindowText(hwnd, title);
2003-03-30 14:26:39 -05:00
env->ReleaseStringUTFChars(title_obj, title);
}
/*
* Class: org_lwjgl_Window
* Method: tick
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_Window_tick
2003-08-03 18:10:03 -04:00
(JNIEnv * env, jclass clazz)
{
2003-08-03 18:10:03 -04:00
handleMessages(env, clazz);
2003-03-30 14:26:39 -05:00
}
2003-06-04 18:10:24 -04:00
/*
* Class: org_lwjgl_Window
* Method: minimize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_Window_minimize
2003-08-03 18:10:03 -04:00
(JNIEnv * env, jclass clazz)
2003-06-04 18:10:24 -04:00
{
if (isMinimized)
return;
ShowWindow(hwnd, SW_MINIMIZE);
}
/*
* Class: org_lwjgl_Window
* Method: minimize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_Window_restore
2003-08-03 18:10:03 -04:00
(JNIEnv * env, jclass clazz)
2003-06-04 18:10:24 -04:00
{
if (!isMinimized)
return;
ShowWindow(hwnd, SW_RESTORE);
}
2003-08-03 18:10:03 -04:00
/*
* Class: org_lwjgl_Window
* Method: swapBuffers
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_Window_swapBuffers
(JNIEnv * env, jclass clazz)
{
wglSwapLayerBuffers(hdc, WGL_SWAP_MAIN_PLANE);
}
/*
* Class: org_lwjgl_Window
* Method: nCreate
* Signature: (Ljava/lang/String;IIIIZIIII)V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_Window_nCreate
(JNIEnv * env, jclass clazz, jstring title, jint x, jint y, jint width, jint height, jboolean fullscreen, jint bpp, jint alpha, jint depth, jint stencil)
{
// 1. Create a window
const char * titleString = env->GetStringUTFChars(title, NULL);
if (!createWindow(titleString, x, y, width, height, fullscreen == JNI_TRUE ? true : false)) {
env->ReleaseStringUTFChars((jstring) title, titleString);
closeWindow();
throwException(env, "Failed to create the window.");
return;
}
env->ReleaseStringUTFChars(title, titleString);
// 2. Choose a pixel format and set it
unsigned int flags = PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER; // double buffered
int iPixelFormat = findPixelFormat(env, flags, bpp, alpha, depth, stencil);
if (iPixelFormat == -1) {
closeWindow();
return;
}
// Create a rendering context
hglrc = wglCreateContext(hdc);
if (hglrc == NULL) {
throwException(env, "Failed to create OpenGL rendering context");
closeWindow();
return;
}
// Automatically make it the current context
wglMakeCurrent(hdc, hglrc);
// Initialise GL extensions
if (extgl_Initialize() != 0) {
closeWindow();
throwException(env, "Failed to initialize GL extensions");
return;
}
}
/*
* Class: org_lwjgl_Window
* Method: doDestroy
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_org_lwjgl_Window_nDestroy
(JNIEnv * env, jclass clazz)
{
wglMakeCurrent(NULL, NULL);
// Delete the rendering context
if (hglrc != NULL) {
#ifdef _DEBUG
printf("Delete GL context\n");
#endif
wglDeleteContext(hglrc);
hglrc = NULL;
}
closeWindow();
extgl_Close();
}