diff --git a/CMakeLists.txt b/CMakeLists.txt index 24603af..94ee4f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ project(${PROJECT_NAME}) message("Processing " ${PROJECT_NAME}) +# Detect iOS +#-------------------------------------- if(NOT DEFINED IOS) if(DEFINED CMAKE_SYSTEM_NAME) string(TOLOWER CMAKE_SYSTEM_NAME CMAKE_SYSTEM_NAME_LOWER) @@ -14,6 +16,8 @@ if(NOT DEFINED IOS) endif() endif() +# Sources +#-------------------------------------- set(SrcLib include/MiniFB.h include/MiniFB_cpp.h @@ -27,11 +31,13 @@ set(SrcLib src/WindowData.h ) +#-- set(SrcWindows src/windows/WinMiniFB.c src/windows/WindowData_Win.h ) +#-- set(SrcMacOSX src/macosx/MacMiniFB.m src/macosx/OSXWindow.h @@ -43,6 +49,7 @@ set(SrcMacOSX src/macosx/WindowData_OSX.h ) +#-- set(SrcIOS src/ios/WindowData_IOS.h src/ios/iOSMiniFB.m @@ -55,18 +62,25 @@ set(SrcIOS include/MiniFB_ios.h ) +#-- set(SrcWayland src/wayland/WaylandMiniFB.c src/wayland/WindowData_Way.h src/MiniFB_linux.c ) +#-- set(SrcX11 src/x11/X11MiniFB.c src/x11/WindowData_X11.h src/MiniFB_linux.c ) +set(SrcGL + src/gl/MiniFB_GL.h + src/gl/MiniFB_GL.c +) + # Avoid RelWithDebInfo and MinSizeRel #-------------------------------------- set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) @@ -88,9 +102,17 @@ set(CMAKE_CXX_EXTENSIONS OFF) #-------------------------------------- option(MINIFB_BUILD_EXAMPLES "Build minifb example programs" TRUE) +if(APPLE AND NOT IOS) + option(USE_METAL_API "Build the project using metal API code" ON) +elseif(UNIX) + option(USE_WAYLAND_API "Build the project using wayland API code" OFF) +elseif(WIN32) + option(USE_OPENGL_API "Build the project using OpenGL API code" ON) +endif() + # Set GCC/Clang flags #-------------------------------------- -if (NOT MSVC) +if(NOT MSVC) # Avoid default flag values #-------------------------------------- set(CMAKE_C_FLAGS "" CACHE STRING "" FORCE) @@ -113,56 +135,62 @@ if (NOT MSVC) #-------------------------------------- add_compile_options("$<$:-g>") add_compile_options("$,-O0,-O2>") - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") - set (CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") - set (CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") -endif() - -# Set default cmake flags -#-------------------------------------- -if (APPLE AND NOT IOS) - OPTION(USE_METAL_API "Build the project using metal API code" ON) -elseif (UNIX) - OPTION(USE_WAYLAND_API "Build the project using wayland API code" OFF) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -Wno-switch -Wno-unused-function -Wno-implicit-fallthrough") + set(CMAKE_OBJC_FLAGS "${CMAKE_C_FLAGS}") + set(CMAKE_OBJCXX_FLAGS "${CMAKE_CXX_FLAGS}") endif() # Set compiler/platform specific flags and dependencies #-------------------------------------- -if (MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) - add_definitions(-D_WIN32_WINNT=0x0600) +if(WIN32) - list (APPEND SrcLib ${SrcWindows}) -elseif (MINGW) - add_definitions(-D_WIN32_WINNT=0x0600) + if(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + endif() + add_definitions(-D_WIN32_WINNT=0x0601) # Windows 7 (we are in 2020) + + if(USE_OPENGL_API) + list(APPEND SrcLib ${SrcGL}) + + add_definitions(-DUSE_OPENGL_API) + endif() list(APPEND SrcLib ${SrcWindows}) -elseif (IOS) + +elseif(IOS) + list(APPEND SrcLib ${SrcIOS}) -elseif (APPLE) + +elseif(APPLE) + if(USE_METAL_API) add_definitions(-DUSE_METAL_API) endif() - + list(APPEND SrcLib ${SrcMacOSX}) -elseif (UNIX) + +elseif(UNIX) + if(USE_WAYLAND_API) list(APPEND SrcLib ${SrcWayland}) else() list(APPEND SrcLib ${SrcX11}) endif() + endif() # Library #-------------------------------------- -add_library(minifb STATIC +add_library(minifb STATIC ${SrcLib} ) +# Link #-------------------------------------- -if (APPLE) +if(APPLE) + if(IOS) - target_link_libraries(minifb + target_link_libraries(minifb "-framework UIKit" "-framework QuartzCore" "-framework Metal" @@ -176,17 +204,28 @@ if (APPLE) "-framework MetalKit" ) endif() -elseif (UNIX) + +elseif(UNIX) + if(USE_WAYLAND_API) - target_link_libraries(minifb + target_link_libraries(minifb "-lwayland-client" "-lwayland-cursor" ) else() - target_link_libraries(minifb + target_link_libraries(minifb "-lX11" ) endif() + +elseif(WIN32) + + if(USE_OPENGL_API) + target_link_libraries(minifb + "Opengl32.lib" + ) + endif() + endif() # For all projects @@ -198,7 +237,7 @@ link_libraries(minifb) # Examples #-------------------------------------- -if (MINIFB_BUILD_EXAMPLES) +if(MINIFB_BUILD_EXAMPLES) if(NOT IOS) add_executable(noise diff --git a/src/MiniFB_internal.c b/src/MiniFB_internal.c index bc65b2b..1cd1f41 100644 --- a/src/MiniFB_internal.c +++ b/src/MiniFB_internal.c @@ -97,8 +97,8 @@ calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height) { //------------------------------------- void resize_dst(SWindowData *window_data, uint32_t width, uint32_t height) { - window_data->dst_offset_x = width * window_data->factor_x; - window_data->dst_offset_y = height * window_data->factor_y; - window_data->dst_width = width * window_data->factor_width; - window_data->dst_height = height * window_data->factor_height; + window_data->dst_offset_x = (uint32_t) (width * window_data->factor_x); + window_data->dst_offset_y = (uint32_t) (height * window_data->factor_y); + window_data->dst_width = (uint32_t) (width * window_data->factor_width); + window_data->dst_height = (uint32_t) (height * window_data->factor_height); } diff --git a/src/WindowData.h b/src/WindowData.h index da2ee8c..13ed2dd 100644 --- a/src/WindowData.h +++ b/src/WindowData.h @@ -43,6 +43,7 @@ typedef struct { uint32_t mod_keys; bool is_active; + bool is_initialized; bool close; } SWindowData; diff --git a/src/gl/MiniFB_GL.c b/src/gl/MiniFB_GL.c new file mode 100644 index 0000000..f8e0f76 --- /dev/null +++ b/src/gl/MiniFB_GL.c @@ -0,0 +1,170 @@ +#if defined(USE_OPENGL_API) + +#include "MiniFB_GL.h" +#if defined(_WIN32) || defined(WIN32) + #include +#endif +#include +#include + +//#define kUse_Clean_UP +#if defined(kUse_Clean_UP) + #define UseCleanUp(x) x +#else + #define UseCleanUp(x) +#endif + +//------------------------------------- +void setup_pixel_format(HDC hDC); + +//------------------------------------- +void +create_GL_context(SWindowData *window_data) { + SWindowData_Win *window_data_win; + + window_data_win = (SWindowData_Win *) window_data->specific; + setup_pixel_format(window_data_win->hdc); + window_data_win->hGLRC = wglCreateContext(window_data_win->hdc); + wglMakeCurrent(window_data_win->hdc, window_data_win->hGLRC); + init_GL(window_data); +} + +//------------------------------------- +void +setup_pixel_format(HDC hDC) { + int pixelFormat; + + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size + 1, // version + PFD_SUPPORT_OPENGL | // + PFD_DRAW_TO_WINDOW | // + PFD_DOUBLEBUFFER, // support double-buffering + PFD_TYPE_RGBA, // color type + 24, // preferred color depth + 0, 0, 0, 0, 0, 0, // color and shift bits (ignored) + 0, // no alpha buffer + 0, // alpha bits (ignored) + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits (ignored) + 24, // depth buffer + 8, // no stencil buffer + 0, // no auxiliary buffers + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0, // no layer, visible, damage masks + }; + + pixelFormat = ChoosePixelFormat(hDC, &pfd); + if (pixelFormat == 0) { + MessageBox(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error", MB_ICONERROR | MB_OK); + exit(1); + } + + if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) { + MessageBox(WindowFromDC(hDC), "SetPixelFormat failed.", "Error", MB_ICONERROR | MB_OK); + exit(1); + } +} + +#define TEXTURE0 0x84C0 + +//------------------------------------- +void +init_GL(SWindowData *window_data) { + SWindowData_Win *window_data_win; + + window_data_win = (SWindowData_Win *) window_data->specific; + + glViewport(0, 0, window_data->window_width, window_data->window_height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + + glEnable(GL_TEXTURE_2D); + + glGenTextures(1, &window_data_win->text_id); + //glActiveTexture(TEXTURE0); + glBindTexture(GL_TEXTURE_2D, window_data_win->text_id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); + UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY)); + UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0)); +} + +//------------------------------------- +void +resize_GL(SWindowData *window_data) { + if(window_data->is_initialized) { + glViewport(0, 0, window_data->window_width, window_data->window_height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048); + + glClear(GL_COLOR_BUFFER_BIT); + } +} + +//------------------------------------- +void +redraw_GL(SWindowData *window_data, const void *pixels) { + float x, y, w, h; + SWindowData_Win *window_data_ex; + + window_data_ex = (SWindowData_Win *) window_data->specific; + + x = (float) window_data->dst_offset_x; + y = (float) window_data->dst_offset_y; + w = (float) window_data->dst_offset_x + window_data->dst_width; + h = (float) window_data->dst_offset_y + window_data->dst_height; + + float vertices[] = { + x, y, + 0, 0, + + w, y, + 1, 0, + + x, h, + 0, 1, + + w, h, + 1, 1, + }; + + glClear(GL_COLOR_BUFFER_BIT); + + UseCleanUp(glBindTexture(GL_TEXTURE_2D, window_data_ex->text_id)); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_data->buffer_width, window_data->buffer_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, window_data->buffer_width, window_data->buffer_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + UseCleanUp(glEnableClientState(GL_VERTEX_ARRAY)); + UseCleanUp(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); + glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), vertices); + glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), vertices + 2); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); + UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY)); + UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0)); + + SwapBuffers(window_data_ex->hdc); +} + +#endif \ No newline at end of file diff --git a/src/gl/MiniFB_GL.h b/src/gl/MiniFB_GL.h new file mode 100644 index 0000000..2526aed --- /dev/null +++ b/src/gl/MiniFB_GL.h @@ -0,0 +1,12 @@ +#pragma once + +#if defined(USE_OPENGL_API) + + #include "WindowData.h" + + void create_GL_context(SWindowData *window_data); + void init_GL(SWindowData *window_data); + void redraw_GL(SWindowData *window_data, const void *pixels); + void resize_GL(SWindowData *window_data); + +#endif diff --git a/src/ios/iOSMiniFB.m b/src/ios/iOSMiniFB.m index 0f9716b..847c307 100644 --- a/src/ios/iOSMiniFB.m +++ b/src/ios/iOSMiniFB.m @@ -95,6 +95,7 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) } [window makeKeyAndVisible]; + window_data->is_initialized = true; return (struct mfb_window *) window_data; } } diff --git a/src/macosx/MacMiniFB.m b/src/macosx/MacMiniFB.m index 432ebd2..959cd1c 100644 --- a/src/macosx/MacMiniFB.m +++ b/src/macosx/MacMiniFB.m @@ -151,14 +151,17 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); +#if defined(_DEBUG) || defined(DEBUG) #if defined(USE_METAL_API) NSLog(@"Window created using Metal API"); #else NSLog(@"Window created using Cocoa API"); #endif +#endif + window_data->is_initialized = true; return (struct mfb_window *) window_data; - } + } } //------------------------------------- diff --git a/src/wayland/WaylandMiniFB.c b/src/wayland/WaylandMiniFB.c index 081e7ed..cc4e672 100644 --- a/src/wayland/WaylandMiniFB.c +++ b/src/wayland/WaylandMiniFB.c @@ -661,13 +661,17 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); +#if defined(_DEBUG) || defined(DEBUG) printf("Window created using Wayland API\n"); +#endif + window_data->is_initialized = true; return (struct mfb_window *) window_data; out: close(window_data_way->fd); destroy(window_data); + return 0x0; } diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index 00d5fd4..834aa96 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -2,7 +2,9 @@ #include #include #include "WindowData_Win.h" - +#if defined(USE_OPENGL_API) + #include "gl/MiniFB_GL.h" +#endif #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -29,31 +31,18 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { +#if !defined(USE_OPENGL_API) case WM_PAINT: { if (window_data && window_data->draw_buffer && window_data_win) { - //if (window_data->dst_offset_x > 0) { - // BitBlt(window_data_win->hdc, 0, window_data->dst_offset_y, window_data->dst_offset_x, window_data->dst_height, 0, 0, 0, BLACKNESS); - //} - //if (window_data->dst_offset_y > 0) { - // BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->dst_offset_y, 0, 0, 0, BLACKNESS); - //} - //uint32_t offsetY = window_data->dst_offset_y + window_data->dst_height; - //if (offsetY < window_data->window_height) { - // BitBlt(window_data_win->hdc, 0, offsetY, window_data->window_width, window_data->window_height - offsetY, 0, 0, 0, BLACKNESS); - //} - //uint32_t offsetX = window_data->dst_offset_x + window_data->dst_width; - //if (offsetX < window_data->window_width) { - // BitBlt(window_data_win->hdc, offsetX, window_data->dst_offset_y, window_data->window_width - offsetX, window_data->dst_height, 0, 0, 0, BLACKNESS); - //} - StretchDIBits(window_data_win->hdc, window_data->dst_offset_x, window_data->dst_offset_y, window_data->dst_width, window_data->dst_height, 0, 0, window_data->buffer_width, window_data->buffer_height, window_data->draw_buffer, window_data_win->bitmapInfo, DIB_RGB_COLORS, SRCCOPY); } ValidateRect(hWnd, 0x0); break; } +#endif case WM_DESTROY: case WM_CLOSE: @@ -187,7 +176,12 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { window_data->window_width = LOWORD(lParam); window_data->window_height = HIWORD(lParam); resize_dst(window_data, LOWORD(lParam), HIWORD(lParam)); + +#if !defined(USE_OPENGL_API) BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS); +#else + resize_GL(window_data); +#endif kCall(resize_func, window_data->dst_width, window_data->dst_height); } break; @@ -334,12 +328,17 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) ShowWindow(window_data_win->window, SW_NORMAL); + window_data_win->hdc = GetDC(window_data_win->window); + +#if !defined(USE_OPENGL_API) + window_data_win->bitmapInfo = (BITMAPINFO *) calloc(1, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3); if(window_data_win->bitmapInfo == 0x0) { free(window_data); free(window_data_win); return 0x0; } + window_data_win->bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); window_data_win->bitmapInfo->bmiHeader.biPlanes = 1; window_data_win->bitmapInfo->bmiHeader.biBitCount = 32; @@ -350,12 +349,25 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) window_data_win->bitmapInfo->bmiColors[1].rgbGreen = 0xff; window_data_win->bitmapInfo->bmiColors[2].rgbBlue = 0xff; - window_data_win->hdc = GetDC(window_data_win->window); +#else + + create_GL_context(window_data); + +#endif window_data_win->timer = mfb_timer_create(); mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); +#if defined(_DEBUG) || defined(DEBUG) + #if defined(USE_OPENGL_API) + printf("Window created using OpenGL API\n"); + #else + printf("Window created using GDI API\n"); + #endif +#endif + + window_data->is_initialized = true; return (struct mfb_window *) window_data; } @@ -385,11 +397,20 @@ mfb_update_ex(struct mfb_window *window, void *buffer, unsigned width, unsigned window_data->buffer_height = height; SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; + +#if !defined(USE_OPENGL_API) + window_data_win->bitmapInfo->bmiHeader.biWidth = window_data->buffer_width; window_data_win->bitmapInfo->bmiHeader.biHeight = -(LONG) window_data->buffer_height; InvalidateRect(window_data_win->window, 0x0, TRUE); SendMessage(window_data_win->window, WM_PAINT, 0, 0); +#else + + redraw_GL(window_data, buffer); + +#endif + while (window_data->close == false && PeekMessage(&msg, window_data_win->window, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); @@ -481,10 +502,18 @@ destroy_window_data(SWindowData *window_data) { SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; - window_data->draw_buffer = 0x0; +#if !defined(USE_OPENGL_API) if (window_data_win->bitmapInfo != 0x0) { free(window_data_win->bitmapInfo); + window_data_win->bitmapInfo = 0x0; } +#else + if (window_data_win->hGLRC) { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(window_data_win->hGLRC); + window_data_win->hGLRC = 0; + } +#endif if (window_data_win->window != 0 && window_data_win->hdc != 0) { ReleaseDC(window_data_win->window, window_data_win->hdc); @@ -492,11 +521,13 @@ destroy_window_data(SWindowData *window_data) { } window_data_win->window = 0; - window_data_win->hdc = 0; - window_data_win->bitmapInfo = 0x0; + window_data_win->hdc = 0; + mfb_timer_destroy(window_data_win->timer); window_data_win->timer = 0x0; - window_data->close = true; + + window_data->draw_buffer = 0x0; + window_data->close = true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -686,7 +717,6 @@ translate_key(unsigned int wParam, unsigned long lParam) { bool mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y, unsigned width, unsigned height) { SWindowData *window_data = (SWindowData *) window; - SWindowData_Win *window_data_win = 0x0; if(window_data == 0x0) { return false; @@ -707,8 +737,12 @@ mfb_set_viewport(struct mfb_window *window, unsigned offset_x, unsigned offset_y calc_dst_factor(window_data, window_data->window_width, window_data->window_height); +#if !defined(USE_OPENGL_API) + SWindowData_Win *window_data_win = 0x0; + window_data_win = (SWindowData_Win *) window_data->specific; BitBlt(window_data_win->hdc, 0, 0, window_data->window_width, window_data->window_height, 0, 0, 0, BLACKNESS); +#endif return true; } diff --git a/src/windows/WindowData_Win.h b/src/windows/WindowData_Win.h index 5ccf068..8cca346 100644 --- a/src/windows/WindowData_Win.h +++ b/src/windows/WindowData_Win.h @@ -5,12 +5,16 @@ #define WIN32_LEAN_AND_MEAN #include - typedef struct { HWND window; WNDCLASS wc; HDC hdc; +#if defined(USE_OPENGL_API) + HGLRC hGLRC; + uint32_t text_id; +#else BITMAPINFO *bitmapInfo; +#endif struct mfb_timer *timer; bool mouse_inside; } SWindowData_Win; diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index ec8f3fb..7265c30 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -189,8 +189,11 @@ mfb_open_ex(const char *title, unsigned width, unsigned height, unsigned flags) mfb_set_keyboard_callback((struct mfb_window *) window_data, keyboard_default); +#if defined(_DEBUG) || defined(DEBUG) printf("Window created using X11 API\n"); +#endif + window_data->is_initialized = true; return (struct mfb_window *) window_data; }