cen64/os/winapi/gl_window.c
Derek "Turtle" Roe 8b89df2fdc See long description
Replaced all references to simulation with emulation
Updated copyright year
Updated .gitignore to reduce chances of random files being uploaded to
the repo
Added .gitattributes to normalize all text files, and to ignore binary
files (which includes the logo and the NEC PDF)
2015-07-01 18:44:21 -05:00

204 lines
5.4 KiB
C

//
// os/winapi/gl_window.h: WinAPI/OpenGL window definitions.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "common.h"
#include "device/device.h"
#include "gl_common.h"
#include "gl_window.h"
#include "thread.h"
#include "timer.h"
#include "vi/controller.h"
#include "vi/render.h"
#include <windows.h>
static bool cen64_gl_window_pump_events(struct vi_controller *vi,
cen64_time *time, unsigned *frame_count);
static LRESULT CALLBACK WndProc(HWND hwnd,
UINT message, WPARAM w_param, LPARAM l_param) {
switch(message) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
gl_window_resize_cb(LOWORD(l_param), HIWORD(l_param));
break;
default:
return DefWindowProc(hwnd, message, w_param, l_param);
}
return 0;
}
// Handles events that come from Windows.
bool cen64_gl_window_pump_events(struct vi_controller *vi,
cen64_time *last_update_time, unsigned *frame_count) {
struct bus_controller *bus;
bool exit_requested = false;
MSG msg;
memcpy(&bus, vi, sizeof(bus));
while (1) {
GetMessage(&msg, NULL, 0, 0);
if (msg.message == WM_QUIT) {
cen64_mutex_lock(&vi->window->event_mutex);
vi->window->exit_requested = exit_requested = true;
cen64_mutex_unlock(&vi->window->event_mutex);
break;
}
else if (msg.message == WM_KEYDOWN) {
cen64_mutex_lock(&vi->window->event_mutex);
keyboard_press_callback(bus, msg.wParam);
cen64_mutex_unlock(&vi->window->event_mutex);
}
else if (msg.message == WM_KEYUP) {
cen64_mutex_lock(&vi->window->event_mutex);
keyboard_release_callback(bus, msg.wParam);
cen64_mutex_unlock(&vi->window->event_mutex);
}
else if (msg.message == WM_USER) {
cen64_gl_window window = vi->window;
cen64_mutex_lock(&window->render_mutex);
gl_window_render_frame(vi, window->frame_buffer,
window->frame_hres, window->frame_vres,
window->frame_hskip, window->frame_type);
cen64_mutex_unlock(&window->render_mutex);
// Update the window title every 60 VIs
// to display the current VI/s rate.
if (++(*frame_count) == 60) {
char title[128];
cen64_time current_time;
float ns;
// Compute time spent rendering last 60 frames, reset timer/counter.
get_time(&current_time);
ns = compute_time_difference(&current_time, last_update_time);
*last_update_time = current_time;
*frame_count = 0;
sprintf(title,
"CEN64 ["CEN64_COMPILER" - "CEN64_ARCH_DIR"/"CEN64_ARCH_SUPPORT"]"
" - %.1f VI/s", (60 / (ns / NS_PER_SEC)));
cen64_gl_window_set_title(window, title);
}
}
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return exit_requested;
}
cen64_gl_window cen64_gl_window_create(
cen64_gl_display display, cen64_gl_screen screen,
const cen64_gl_config *config, const char *title) {
cen64_gl_window window;
WNDCLASS wc;
DWORD dw_ex_style;
DWORD dw_style;
RECT window_rect;
if ((window = malloc(sizeof(*window))) == NULL)
return CEN64_GL_WINDOW_BAD;
window_rect.left = 0;
window_rect.right = 640;
window_rect.top = 0;
window_rect.bottom = 480;
window->hinstance = GetModuleHandle(NULL);
window->pixel_format = config->pixel_format;
memset(&wc, 0, sizeof(wc));
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = window->hinstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "CEN64";
if (!RegisterClass(&wc)) {
free(window);
return CEN64_GL_WINDOW_BAD;
}
dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dw_style = WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
if ((window->hwnd = CreateWindowEx(dw_ex_style, "CEN64", title,
dw_style | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0,
window_rect.right - window_rect.left, window_rect.bottom - window_rect.top,
NULL, NULL, window->hinstance, NULL)) == NULL) {
UnregisterClass("CEN64", window->hinstance);
free(window);
return CEN64_GL_WINDOW_BAD;
}
// Store the pointer to the gl_window in the HWND attribute.
// We'll need it later to perform callbacks on resize and such.
// Also grab the window's device context so we can create a GL RC.
SetLastError(0);
SetWindowLongPtr(window->hwnd, GWLP_USERDATA, (uintptr_t) window);
if (GetLastError() || (window->hdc = GetDC(window->hwnd)) == NULL) {
DestroyWindow(window->hwnd);
UnregisterClass("CEN64", window->hinstance);
free(window);
return CEN64_GL_WINDOW_BAD;
}
SetPixelFormat(window->hdc, window->pixel_format, &config->pfd);
cen64_mutex_create(&window->event_mutex);
cen64_mutex_create(&window->render_mutex);
window->thread_id = GetCurrentThreadId();
return window;
}
// Thread that controls the user interface, etc.
int cen64_gl_window_thread(struct cen64_device *device) {
cen64_time last_update_time;
unsigned frame_count;
get_time(&last_update_time);
frame_count = 0;
while (!cen64_gl_window_pump_events(&device->vi,
&last_update_time, &frame_count));
return 0;
}