diff --git a/examples/canvas/main.c b/examples/canvas/main.c index eb5c0c9..1596add 100644 --- a/examples/canvas/main.c +++ b/examples/canvas/main.c @@ -161,6 +161,9 @@ int main() mg_set_color_rgba(0, 1, 1, 1); mg_clear(); + mg_set_color_rgba(1, 0, 1, 1); + mg_rectangle_fill(0, 0, 100, 100); + // head mg_set_color_rgba(1, 1, 0, 1); diff --git a/examples/simpleWindow/build.bat b/examples/simpleWindow/build.bat index 971b6e5..2f24fa7 100644 --- a/examples/simpleWindow/build.bat +++ b/examples/simpleWindow/build.bat @@ -1,2 +1,2 @@ set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext -cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib user32.lib opengl32.lib gdi32.lib /out:../../bin/example_window.exe +cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib user32.lib /out:../../bin/example_simple_window.exe diff --git a/examples/simpleWindow/build.sh b/examples/simpleWindow/build.sh index 4c97e8e..67d5f3e 100755 --- a/examples/simpleWindow/build.sh +++ b/examples/simpleWindow/build.sh @@ -9,4 +9,6 @@ INCLUDES="-I$SRCDIR -I$SRCDIR/util -I$SRCDIR/platform -I$SRCDIR/app" LIBS="-L$BINDIR -lmilepost -framework Carbon -framework Cocoa -framework Metal -framework QuartzCore" FLAGS="-mmacos-version-min=10.15.4 -DDEBUG -DLOG_COMPILE_DEBUG" -clang -g $FLAGS -Wl,-dead_strip $LIBS $INCLUDES -o test main.c +clang -g $FLAGS -Wl,-dead_strip $LIBS $INCLUDES -o $BINDIR/example_simple_window main.c + +install_name_tool -add_rpath "@executable_path" $BINDIR/example_simple_window diff --git a/examples/simpleWindow/main.c b/examples/simpleWindow/main.c index c659847..eddccde 100644 --- a/examples/simpleWindow/main.c +++ b/examples/simpleWindow/main.c @@ -22,6 +22,8 @@ int main() mp_window_bring_to_front(window); mp_window_focus(window); + mp_window_center(window); + while(!mp_should_quit()) { mp_pump_events(0); @@ -37,36 +39,44 @@ int main() case MP_EVENT_WINDOW_RESIZE: { - printf("resized, rect = {%f, %f, %f, %f}\n", - event->frame.rect.x, - event->frame.rect.y, - event->frame.rect.w, - event->frame.rect.h); + printf("resized, frame = {%f, %f, %f, %f}, content = {%f, %f, %f, %f}\n", + event->move.frame.x, + event->move.frame.y, + event->move.frame.w, + event->move.frame.h, + event->move.content.x, + event->move.content.y, + event->move.content.w, + event->move.content.h); } break; case MP_EVENT_WINDOW_MOVE: { - printf("moved, rect = {%f, %f, %f, %f}\n", - event->frame.rect.x, - event->frame.rect.y, - event->frame.rect.w, - event->frame.rect.h); + printf("moved, frame = {%f, %f, %f, %f}, content = {%f, %f, %f, %f}\n", + event->move.frame.x, + event->move.frame.y, + event->move.frame.w, + event->move.frame.h, + event->move.content.x, + event->move.content.y, + event->move.content.w, + event->move.content.h); } break; case MP_EVENT_MOUSE_MOVE: { printf("mouse moved, pos = {%f, %f}, delta = {%f, %f}\n", - event->move.x, - event->move.y, - event->move.deltaX, - event->move.deltaY); + event->mouse.x, + event->mouse.y, + event->mouse.deltaX, + event->mouse.deltaY); } break; case MP_EVENT_MOUSE_WHEEL: { printf("mouse wheel, delta = {%f, %f}\n", - event->move.deltaX, - event->move.deltaY); + event->mouse.deltaX, + event->mouse.deltaY); } break; case MP_EVENT_MOUSE_ENTER: diff --git a/examples/smooth_resize/build.bat b/examples/smooth_resize/build.bat new file mode 100644 index 0000000..4f2c691 --- /dev/null +++ b/examples/smooth_resize/build.bat @@ -0,0 +1,4 @@ + +set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext /I ../../ext/angle_headers /I ..\..\..\..\vcpkg\packages\pthreads_x64-windows\include + +cl /we4013 /Zi /Zc:preprocessor /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.dll.lib /LIBPATH:..\..\..\..\vcpkg\packages\pthreads_x64-windows\lib pthreadVC3.lib /out:../../bin/example_smooth_resize.exe diff --git a/examples/smooth_resize/main.c b/examples/smooth_resize/main.c index 645828d..276c0e4 100644 --- a/examples/smooth_resize/main.c +++ b/examples/smooth_resize/main.c @@ -6,6 +6,7 @@ * @revision: * *****************************************************************/ +#include #include #include #include @@ -13,45 +14,55 @@ #define _USE_MATH_DEFINES //NOTE: necessary for MSVC #include +#define MG_INCLUDE_GL_API #include"milepost.h" #include -#define LOG_SUBSYSTEM "Main" +unsigned int program; +const char* vshaderSource = + "#version 430\n" + "attribute vec4 vPosition;\n" + "uniform mat4 transform;\n" + "void main()\n" + "{\n" + " gl_Position = transform*vPosition;\n" + "}\n"; -mg_font create_font() +const char* fshaderSource = + "#version 430\n" + "precision mediump float;\n" + "void main()\n" + "{\n" + " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" + "}\n"; + +void compile_shader(GLuint shader, const char* source) { - //NOTE(martin): create font - str8 fontPath = path_executable_relative(mem_scratch(), STR8("../resources/OpenSansLatinSubset.ttf")); - char* fontPathCString = str8_to_cstring(mem_scratch(), fontPath); + glShaderSource(shader, 1, &source, 0); + glCompileShader(shader); - FILE* fontFile = fopen(fontPathCString, "r"); - if(!fontFile) + int err = glGetError(); + if(err) { - log_error("Could not load font file '%s': %s\n", fontPathCString, strerror(errno)); - return(mg_font_nil()); + printf("gl error: %i\n", err); } - unsigned char* fontData = 0; - fseek(fontFile, 0, SEEK_END); - u32 fontDataSize = ftell(fontFile); - rewind(fontFile); - fontData = (unsigned char*)malloc(fontDataSize); - fread(fontData, 1, fontDataSize, fontFile); - fclose(fontFile); - unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN, - UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, - UNICODE_RANGE_LATIN_EXTENDED_A, - UNICODE_RANGE_LATIN_EXTENDED_B, - UNICODE_RANGE_SPECIALS}; - - mg_font font = mg_font_create_from_memory(fontDataSize, fontData, 5, ranges); - free(fontData); - - return(font); + int status = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(!status) + { + char buffer[256]; + int size = 0; + glGetShaderInfoLog(shader, 256, &size, buffer); + printf("shader error: %.*s\n", size, buffer); + } } +GLfloat vertices[] = { + -0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0}; + typedef struct app_data { mp_window window; @@ -59,13 +70,7 @@ typedef struct app_data mg_canvas canvas; mg_font font; - f32 x; - f32 y; - f32 dx; - f32 dy; - f32 speed; - f32 frameTime; - + GLuint vertexBuffer; } app_data; void process_event(app_data* app, mp_event event) @@ -79,33 +84,7 @@ void process_event(app_data* app, mp_event event) case MP_EVENT_WINDOW_RESIZE: { - mp_rect frame = {0, 0, event.frame.rect.w, event.frame.rect.h}; - mg_surface_set_frame(app->surface, frame); - } break; - - case MP_EVENT_KEYBOARD_KEY: - { - if(event.key.action == MP_KEY_PRESS || event.key.action == MP_KEY_REPEAT) - { - f32 factor = (event.key.mods & MP_KEYMOD_SHIFT) ? 10 : 1; - - if(event.key.code == MP_KEY_LEFT) - { - app->x-=0.3*factor; - } - else if(event.key.code == MP_KEY_RIGHT) - { - app->x+=0.3*factor; - } - else if(event.key.code == MP_KEY_UP) - { - app->y-=0.3*factor; - } - else if(event.key.code == MP_KEY_DOWN) - { - app->y+=0.3*factor; - } - } + log_info("resizing window!\n"); } break; default: @@ -115,95 +94,89 @@ void process_event(app_data* app, mp_event event) void update_and_render(app_data* app) { - mp_rect contentRect = mp_window_get_content_rect(app->window); - - if(app->x-200 < 0) - { - app->x = 200; - app->dx = app->speed; - } - if(app->x+200 > contentRect.w) - { - app->x = contentRect.w - 200; - app->dx = -app->speed; - } - if(app->y-200 < 0) - { - app->y = 200; - app->dy = app->speed; - } - if(app->y+200 > contentRect.h) - { - app->y = contentRect.h - 200; - app->dy = -app->speed; - } - app->x += app->dx; - app->y += app->dy; - - f64 startTime = mp_get_time(MP_CLOCK_MONOTONIC); - mg_surface_prepare(app->surface); - // background - mg_set_color_rgba(0, 1, 1, 1); - mg_clear(); + glClearColor(0.3, 0.3, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); - // head - mg_set_color_rgba(1, 1, 0, 1); + static float alpha = 0; + //f32 aspect = frameSize.x/frameSize.y; + f32 aspect = 800/(f32)600; - mg_circle_fill(app->x, app->y, 200); + GLfloat matrix[] = {cosf(alpha)/aspect, sinf(alpha), 0, 0, + -sinf(alpha)/aspect, cosf(alpha), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1}; - // smile - f32 frown = app->frameTime > 0.033 ? -100 : 0; + alpha += 2*M_PI/120; - mg_set_color_rgba(0, 0, 0, 1); - mg_set_width(20); - mg_move_to(app->x-100, app->y+100); - mg_cubic_to(app->x-50, app->y+150+frown, app->x+50, app->y+150+frown, app->x+100, app->y+100); - mg_stroke(); + glUniformMatrix4fv(0, 1, false, matrix); - // eyes - mg_ellipse_fill(app->x-70, app->y-50, 30, 50); - mg_ellipse_fill(app->x+70, app->y-50, 30, 50); - // text - mg_set_color_rgba(0, 0, 1, 1); - mg_set_font(app->font); - mg_set_font_size(12); - mg_move_to(50, 600-50); + glBindBuffer(GL_ARRAY_BUFFER, app->vertexBuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); - str8 text = str8_pushf(mem_scratch(), - "Milepost vector graphics test program (frame time = %fs, fps = %f)...", - app->frameTime, - 1./app->frameTime); - mg_text_outlines(text); - mg_fill(); + glDrawArrays(GL_TRIANGLES, 0, 3); - printf("Milepost vector graphics test program (frame time = %fs, fps = %f)...\n", - app->frameTime, - 1./app->frameTime); - - mg_flush(); mg_surface_present(app->surface); mem_arena_clear(mem_scratch()); - app->frameTime = mp_get_time(MP_CLOCK_MONOTONIC) - startTime; } void* render(void* user) { app_data* app = (app_data*)user; - mg_canvas_prepare(app->canvas); + //NOTE: init shader and gl state + mg_surface_prepare(app->surface); + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + glGenBuffers(1, &app->vertexBuffer); + + GLfloat vertices[] = { + -0.866/2, -0.5/2, 0, 0.866/2, -0.5/2, 0, 0, 0.5, 0}; + + glBindBuffer(GL_ARRAY_BUFFER, app->vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + + unsigned int vshader = glCreateShader(GL_VERTEX_SHADER); + unsigned int fshader = glCreateShader(GL_FRAGMENT_SHADER); + program = glCreateProgram(); + + compile_shader(vshader, vshaderSource); + compile_shader(fshader, fshaderSource); + + glAttachShader(program, vshader); + glAttachShader(program, fshader); + glLinkProgram(program); + + int status = 0; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(!status) + { + char buffer[256]; + int size = 0; + glGetProgramInfoLog(program, 256, &size, buffer); + printf("link error: %.*s\n", size, buffer); + } + + glUseProgram(program); while(!mp_should_quit()) { - mp_event event = {0}; - while(mp_next_event(&event)) + mp_event* event = 0; + + while((event = mp_next_event(mem_scratch())) != 0) { - process_event(app, event); + process_event(app, *event); } update_and_render(app); + mem_arena_clear(mem_scratch()); } return(0); @@ -211,8 +184,6 @@ void* render(void* user) int main() { - LogLevel(LOG_LEVEL_WARNING); - mp_init(); mp_clock_init(); //TODO put that in mp_init()? @@ -220,19 +191,16 @@ int main() mp_window window = mp_window_create(windowRect, "test", 0); //NOTE: create surface - mg_surface surface = mg_surface_create_for_window(window, MG_BACKEND_DEFAULT); - mg_surface_swap_interval(surface, 0); - - //TODO: create canvas - mg_canvas canvas = mg_canvas_create(surface); - - if(mg_canvas_is_nil(canvas)) + mg_surface surface = mg_surface_create_for_window(window, MG_GL); + if(mg_surface_is_nil(surface)) { - printf("Error: couldn't create canvas\n"); + printf("Error: couldn't create surface\n"); return(-1); } - mg_font font = create_font(); + mg_surface_swap_interval(surface, 1); + mg_surface_deselect(); + // start app mp_window_bring_to_front(window); @@ -240,13 +208,7 @@ int main() //TODO: start thread app_data app = {.window = window, - .surface = surface, - .canvas = canvas, - .font = font, - .x = 400, - .y = 300, - .dx = 0, - .dy = 0}; + .surface = surface}; pthread_t renderThread; pthread_create(&renderThread, 0, render, &app); @@ -254,21 +216,11 @@ int main() while(!mp_should_quit()) { mp_pump_events(0); - /* - mp_event event = {0}; - while(mp_next_event(&event)) - { - process_event(&app, event); - } - update_and_render(&app); - //*/ } void* res; pthread_join(renderThread, &res); - mg_font_destroy(font); - mg_canvas_destroy(canvas); mg_surface_destroy(surface); mp_window_destroy(window); diff --git a/src/gl_canvas.c b/src/gl_canvas.c index cc1a635..30c6b35 100644 --- a/src/gl_canvas.c +++ b/src/gl_canvas.c @@ -130,6 +130,10 @@ typedef struct mg_gl_canvas_backend mg_canvas_backend interface; mg_wgl_surface* surface; + int msaaCount; + vec2 frameSize; + + // gl stuff GLuint vao; GLuint pathSetup; @@ -155,17 +159,12 @@ typedef struct mg_gl_canvas_backend GLuint tileOpCountBuffer; GLuint screenTilesBuffer; GLuint rasterDispatchBuffer; - GLuint dummyVertexBuffer; - int msaaCount; - vec2 frameSize; - //encoding context int pathCount; int eltCount; - ///////////////// int pathBatchStart; int eltBatchStart; @@ -1201,10 +1200,28 @@ void mg_gl_render_batch(mg_gl_canvas_backend* backend, backend->eltBatchStart = backend->eltCount; } -///////////////////////////////////////////////////////////////////////// -//TODO -void mg_gl_canvas_resize(mg_gl_canvas_backend* backend, vec2 size); -///////////////////////////////////////////////////////////////////////// +void mg_gl_canvas_resize(mg_gl_canvas_backend* backend, vec2 size) +{ + int tileSize = MG_GL_TILE_SIZE; + int nTilesX = (int)(size.x + tileSize - 1)/tileSize; + int nTilesY = (int)(size.y + tileSize - 1)/tileSize; + + glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->screenTilesBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, nTilesX*nTilesY*sizeof(mg_gl_screen_tile), 0, GL_DYNAMIC_COPY); + + if(backend->outTexture) + { + //NOTE: do we need to explicitly glDeleteTextures()? + glDeleteTextures(1, &backend->outTexture); + glGenTextures(1, &backend->outTexture); + glBindTexture(GL_TEXTURE_2D, backend->outTexture); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size.x, size.y); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + backend->frameSize = size; +} void mg_gl_canvas_render(mg_canvas_backend* interface, mg_color clearColor, @@ -1224,23 +1241,25 @@ void mg_gl_canvas_render(mg_canvas_backend* interface, backend->bufferSync[backend->bufferIndex] = 0; } - //TODO update screen tiles buffer size + //NOTE update screen tiles buffer size mg_wgl_surface* surface = backend->surface; - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 surfaceSize = surface->interface.getSize((mg_surface_data*)surface); vec2 contentsScaling = surface->interface.contentsScaling((mg_surface_data*)surface); - //TODO support scaling in both axes + //TODO support scaling in both axes? f32 scale = contentsScaling.x; - vec2 viewportSize = {frame.w * scale, frame.h * scale}; + vec2 viewportSize = {surfaceSize.x * scale, surfaceSize.y * scale}; int tileSize = MG_GL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize; + int nTilesX = (int)(viewportSize.x + tileSize - 1)/tileSize; + int nTilesY = (int)(viewportSize.y + tileSize - 1)/tileSize; if(viewportSize.x != backend->frameSize.x || viewportSize.y != backend->frameSize.y) { - //TODO: mg_gl_canvas_resize(backend, viewportSize); + mg_gl_canvas_resize(backend, viewportSize); } + glViewport(0, 0, viewportSize.x, viewportSize.y); + //NOTE: clear screen and reset input buffer offsets glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -1544,12 +1563,14 @@ mg_canvas_backend* gl_canvas_backend_create(mg_wgl_surface* surface) } //NOTE: create out texture - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 size = surface->interface.getSize((mg_surface_data*)surface); vec2 scale = surface->interface.contentsScaling((mg_surface_data*)surface); + backend->frameSize = (vec2){size.x * scale.x, size.y * scale.y}; + glGenTextures(1, &backend->outTexture); glBindTexture(GL_TEXTURE_2D, backend->outTexture); - glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, frame.w*scale.x, frame.h*scale.y); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, backend->frameSize.x, backend->frameSize.y); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -1611,8 +1632,8 @@ mg_canvas_backend* gl_canvas_backend_create(mg_wgl_surface* surface) glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int), 0, GL_DYNAMIC_COPY); int tileSize = MG_GL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale.x + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale.y + tileSize - 1)/tileSize; + int nTilesX = (int)(backend->frameSize.x + tileSize - 1)/tileSize; + int nTilesY = (int)(backend->frameSize.y + tileSize - 1)/tileSize; glGenBuffers(1, &backend->screenTilesBuffer); glBindBuffer(GL_SHADER_STORAGE_BUFFER, backend->screenTilesBuffer); diff --git a/src/graphics.h b/src/graphics.h index 2eac71a..3a9a875 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -105,9 +105,8 @@ MP_API void mg_surface_present(mg_surface surface); MP_API void mg_surface_deselect(void); MP_API void mg_surface_swap_interval(mg_surface surface, int swap); +MP_API vec2 mg_surface_get_size(mg_surface surface); MP_API vec2 mg_surface_contents_scaling(mg_surface surface); -MP_API mp_rect mg_surface_get_frame(mg_surface surface); -MP_API void mg_surface_set_frame(mg_surface surface, mp_rect frame); MP_API bool mg_surface_get_hidden(mg_surface surface); MP_API void mg_surface_set_hidden(mg_surface surface, bool hidden); diff --git a/src/graphics_surface.c b/src/graphics_surface.c index 5715f89..e3d3023 100644 --- a/src/graphics_surface.c +++ b/src/graphics_surface.c @@ -147,6 +147,7 @@ mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api) if(surface) { surfaceHandle = mg_surface_handle_alloc(surface); + mg_surface_prepare(surfaceHandle); } return(surfaceHandle); } @@ -174,6 +175,7 @@ mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api) if(surface) { surfaceHandle = mg_surface_handle_alloc(surface); + mg_surface_prepare(surfaceHandle); } return(surfaceHandle); } @@ -263,6 +265,18 @@ void mg_surface_swap_interval(mg_surface surface, int swap) } } +vec2 mg_surface_get_size(mg_surface surface) +{ + DEBUG_ASSERT(__mgData.init); + vec2 size = {0}; + mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); + if(surfaceData && surfaceData->getSize) + { + size = surfaceData->getSize(surfaceData); + } + return(size); +} + vec2 mg_surface_contents_scaling(mg_surface surface) { DEBUG_ASSERT(__mgData.init); @@ -275,29 +289,6 @@ vec2 mg_surface_contents_scaling(mg_surface surface) return(scaling); } - -void mg_surface_set_frame(mg_surface surface, mp_rect frame) -{ - DEBUG_ASSERT(__mgData.init); - mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); - if(surfaceData && surfaceData->setFrame) - { - surfaceData->setFrame(surfaceData, frame); - } -} - -mp_rect mg_surface_get_frame(mg_surface surface) -{ - DEBUG_ASSERT(__mgData.init); - mp_rect res = {0}; - mg_surface_data* surfaceData = mg_surface_data_from_handle(surface); - if(surfaceData && surfaceData->getFrame) - { - res = surfaceData->getFrame(surfaceData); - } - return(res); -} - void mg_surface_set_hidden(mg_surface surface, bool hidden) { DEBUG_ASSERT(__mgData.init); diff --git a/src/graphics_surface.h b/src/graphics_surface.h index fed7d6c..0dca19b 100644 --- a/src/graphics_surface.h +++ b/src/graphics_surface.h @@ -26,9 +26,8 @@ typedef void (*mg_surface_prepare_proc)(mg_surface_data* surface); typedef void (*mg_surface_deselect_proc)(mg_surface_data* surface); typedef void (*mg_surface_present_proc)(mg_surface_data* surface); typedef void (*mg_surface_swap_interval_proc)(mg_surface_data* surface, int swap); +typedef vec2 (*mg_surface_get_size_proc)(mg_surface_data* surface); typedef vec2 (*mg_surface_contents_scaling_proc)(mg_surface_data* surface); -typedef mp_rect (*mg_surface_get_frame_proc)(mg_surface_data* surface); -typedef void (*mg_surface_set_frame_proc)(mg_surface_data* surface, mp_rect frame); typedef bool (*mg_surface_get_hidden_proc)(mg_surface_data* surface); typedef void (*mg_surface_set_hidden_proc)(mg_surface_data* surface, bool hidden); typedef void* (*mg_surface_native_layer_proc)(mg_surface_data* surface); @@ -45,9 +44,8 @@ typedef struct mg_surface_data mg_surface_present_proc present; mg_surface_deselect_proc deselect; mg_surface_swap_interval_proc swapInterval; + mg_surface_get_size_proc getSize; mg_surface_contents_scaling_proc contentsScaling; - mg_surface_get_frame_proc getFrame; - mg_surface_set_frame_proc setFrame; mg_surface_get_hidden_proc getHidden; mg_surface_set_hidden_proc setHidden; mg_surface_native_layer_proc nativeLayer; @@ -79,34 +77,6 @@ typedef struct mg_image_data } mg_image_data; -typedef struct mg_vertex_layout -{ - u32 maxVertexCount; - u32 maxIndexCount; - - char* posBuffer; - u32 posStride; - - char* cubicBuffer; - u32 cubicStride; - - char* shapeIndexBuffer; - u32 shapeIndexStride; - - char* colorBuffer; - u32 colorStride; - - char* clipBuffer; - u32 clipStride; - - char* uvTransformBuffer; - u32 uvTransformStride; - - char* indexBuffer; - u32 indexStride; - -} mg_vertex_layout; - typedef void (*mg_canvas_backend_destroy_proc)(mg_canvas_backend* backend); typedef void (*mg_canvas_backend_begin_proc)(mg_canvas_backend* backend, mg_color clearColor); typedef void (*mg_canvas_backend_end_proc)(mg_canvas_backend* backend); @@ -133,8 +103,6 @@ typedef void (*mg_canvas_backend_render_proc)(mg_canvas_backend* backend, typedef struct mg_canvas_backend { -// mg_vertex_layout vertexLayout; - mg_canvas_backend_destroy_proc destroy; mg_canvas_backend_begin_proc begin; mg_canvas_backend_end_proc end; @@ -144,7 +112,6 @@ typedef struct mg_canvas_backend mg_canvas_backend_image_destroy_proc imageDestroy; mg_canvas_backend_image_upload_region_proc imageUploadRegion; - mg_canvas_backend_render_proc render; } mg_canvas_backend; diff --git a/src/input_state.c b/src/input_state.c index 1a1f385..074c805 100644 --- a/src/input_state.c +++ b/src/input_state.c @@ -136,11 +136,11 @@ void mp_input_process_event(mp_input_state* state, mp_event* event) break; case MP_EVENT_MOUSE_MOVE: - mp_update_mouse_move(state, event->move.x, event->move.y, event->move.deltaX, event->move.deltaY); + mp_update_mouse_move(state, event->mouse.x, event->mouse.y, event->mouse.deltaX, event->mouse.deltaY); break; case MP_EVENT_MOUSE_WHEEL: - mp_update_mouse_wheel(state, event->move.deltaX, event->move.deltaY); + mp_update_mouse_wheel(state, event->mouse.deltaX, event->mouse.deltaY); break; case MP_EVENT_MOUSE_BUTTON: diff --git a/src/mp_app.c b/src/mp_app.c index cb053c3..7cc9f68 100644 --- a/src/mp_app.c +++ b/src/mp_app.c @@ -179,3 +179,39 @@ mp_event* mp_next_event(mem_arena* arena) } return(event); } + +//--------------------------------------------------------------- +// window rects helpers +//--------------------------------------------------------------- + +void mp_window_set_content_position(mp_window window, vec2 position) +{ + mp_rect rect = mp_window_get_content_rect(window); + rect.x = position.x; + rect.y = position.y; + mp_window_set_content_rect(window, rect); +} + +void mp_window_set_content_size(mp_window window, vec2 size) +{ + mp_rect rect = mp_window_get_content_rect(window); + rect.w = size.x; + rect.h = size.y; + mp_window_set_content_rect(window, rect); +} + +void mp_window_set_frame_position(mp_window window, vec2 position) +{ + mp_rect frame = mp_window_get_frame_rect(window); + frame.x = position.x; + frame.y = position.y; + mp_window_set_frame_rect(window, frame); +} + +void mp_window_set_frame_size(mp_window window, vec2 size) +{ + mp_rect frame = mp_window_get_frame_rect(window); + frame.w = size.x; + frame.h = size.y; + mp_window_set_frame_rect(window, frame); +} diff --git a/src/mp_app.h b/src/mp_app.h index 237b598..ffe79fb 100644 --- a/src/mp_app.h +++ b/src/mp_app.h @@ -222,19 +222,20 @@ typedef struct mp_char_event // character input u8 seqLen; } mp_char_event; -typedef struct mp_move_event // mouse move/scroll +typedef struct mp_mouse_event // mouse move/scroll { f32 x; f32 y; f32 deltaX; f32 deltaY; mp_keymod_flags mods; -} mp_move_event; +} mp_mouse_event; -typedef struct mp_frame_event // window resize / move +typedef struct mp_move_event // window resize / move { - mp_rect rect; -} mp_frame_event; + mp_rect frame; + mp_rect content; +} mp_move_event; typedef struct mp_event { @@ -246,8 +247,8 @@ typedef struct mp_event { mp_key_event key; mp_char_event character; - mp_move_event move; - mp_frame_event frame; + mp_mouse_event mouse; + mp_move_event move; str8_list paths; }; @@ -314,10 +315,15 @@ MP_API void mp_window_unfocus(mp_window window); MP_API void mp_window_send_to_back(mp_window window); MP_API void mp_window_bring_to_front(mp_window window); -MP_API mp_rect mp_window_get_content_rect(mp_window window); MP_API mp_rect mp_window_get_frame_rect(mp_window window); -MP_API void mp_window_set_content_rect(mp_window window, mp_rect contentRect); -MP_API void mp_window_set_frame_rect(mp_window window, mp_rect frameRect); +MP_API void mp_window_set_frame_rect(mp_window window, mp_rect rect); +MP_API void mp_window_set_frame_position(mp_window window, vec2 position); +MP_API void mp_window_set_frame_size(mp_window window, vec2 size); + +MP_API mp_rect mp_window_get_content_rect(mp_window window); +MP_API void mp_window_set_content_rect(mp_window window, mp_rect rect); +MP_API void mp_window_set_content_position(mp_window window, vec2 position); +MP_API void mp_window_set_content_size(mp_window window, vec2 size); MP_API void mp_window_center(mp_window window); diff --git a/src/mp_app_internal.h b/src/mp_app_internal.h index e801a96..931934b 100644 --- a/src/mp_app_internal.h +++ b/src/mp_app_internal.h @@ -39,8 +39,6 @@ typedef struct mp_window_data list_elt freeListElt; u32 generation; - mp_rect contentRect; - mp_rect frameRect; mp_window_style style; bool shouldClose; //TODO could be in status flags diff --git a/src/mtl_renderer.m b/src/mtl_renderer.m index 53d805a..8cd5811 100644 --- a/src/mtl_renderer.m +++ b/src/mtl_renderer.m @@ -1159,6 +1159,8 @@ void mg_mtl_canvas_resize(mg_mtl_canvas_backend* backend, vec2 size) backend->outTexture = [backend->surface->device newTextureWithDescriptor:texDesc]; + backend->surface->mtlLayer.drawableSize = (CGSize){size.x, size.y}; + backend->frameSize = size; } } @@ -1179,13 +1181,13 @@ void mg_mtl_canvas_render(mg_canvas_backend* interface, //NOTE: ensure screen tiles buffer is correct size mg_mtl_surface* surface = backend->surface; - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 frameSize = surface->interface.getSize((mg_surface_data*)surface); f32 scale = surface->mtlLayer.contentsScale; - vec2 viewportSize = {frame.w * scale, frame.h * scale}; + vec2 viewportSize = {frameSize.x * scale, frameSize.y * scale}; int tileSize = MG_MTL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize; + int nTilesX = (int)(viewportSize.x * scale + tileSize - 1)/tileSize; + int nTilesY = (int)(viewportSize.y * scale + tileSize - 1)/tileSize; if(viewportSize.x != backend->frameSize.x || viewportSize.y != backend->frameSize.y) { @@ -1482,10 +1484,10 @@ mg_canvas_backend* mtl_canvas_backend_create(mg_mtl_surface* surface) backend->blitPipeline = [surface->device newRenderPipelineStateWithDescriptor: pipelineStateDescriptor error:&err]; //NOTE: create textures - mp_rect frame = surface->interface.getFrame((mg_surface_data*)surface); + vec2 size = surface->interface.getSize((mg_surface_data*)surface); f32 scale = surface->mtlLayer.contentsScale; - backend->frameSize = (vec2){frame.w*scale, frame.h*scale}; + backend->frameSize = (vec2){size.x*scale, size.y*scale}; MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init]; texDesc.textureType = MTLTextureType2D; @@ -1540,8 +1542,8 @@ mg_canvas_backend* mtl_canvas_backend_create(mg_mtl_surface* surface) options: bufferOptions]; int tileSize = MG_MTL_TILE_SIZE; - int nTilesX = (int)(frame.w * scale + tileSize - 1)/tileSize; - int nTilesY = (int)(frame.h * scale + tileSize - 1)/tileSize; + int nTilesX = (int)(backend->frameSize.x + tileSize - 1)/tileSize; + int nTilesY = (int)(backend->frameSize.y + tileSize - 1)/tileSize; backend->screenTilesBuffer = [surface->device newBufferWithLength: nTilesX*nTilesY*sizeof(mg_mtl_screen_tile) options: bufferOptions]; diff --git a/src/mtl_surface.m b/src/mtl_surface.m index c4811ba..179e6b5 100644 --- a/src/mtl_surface.m +++ b/src/mtl_surface.m @@ -116,6 +116,7 @@ void mg_mtl_surface_swap_interval(mg_surface_data* interface, int swap) } } +/* void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame) { mg_mtl_surface* surface = (mg_mtl_surface*)interface; @@ -135,6 +136,7 @@ void mg_mtl_surface_set_frame(mg_surface_data* interface, mp_rect frame) CGSize drawableSize = (CGSize){.width = frame.w * scale.x, .height = frame.h * scale.y}; surface->mtlLayer.drawableSize = drawableSize; } +*/ //TODO fix that according to real scaling, depending on the monitor settings @@ -162,8 +164,6 @@ mg_surface_data* mg_mtl_surface_create_for_window(mp_window window) surface->interface.present = mg_mtl_surface_present; surface->interface.swapInterval = mg_mtl_surface_swap_interval; - surface->interface.setFrame = mg_mtl_surface_set_frame; - @autoreleasepool { //----------------------------------------------------------- @@ -203,7 +203,7 @@ mg_surface_data* mg_mtl_surface_create_for_window(mp_window window) [surface->mtlLayer setOpaque:NO]; - + surface->mtlLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; [surface->interface.layer.caLayer addSublayer: (CALayer*)surface->mtlLayer]; //----------------------------------------------------------- diff --git a/src/osx_app.m b/src/osx_app.m index affb7d7..093f0d6 100644 --- a/src/osx_app.m +++ b/src/osx_app.m @@ -26,44 +26,6 @@ // mp window struct and utility functions //-------------------------------------------------------------------- -static mp_rect mp_osx_to_user_screen_rect(mp_rect rect) -{ - @autoreleasepool - { - NSRect screenRect = [[NSScreen mainScreen] frame]; - rect.y = screenRect.size.height - rect.y - rect.h; - } - return(rect); -} - -static mp_rect mp_user_to_osx_screen_rect(mp_rect rect) -{ - @autoreleasepool - { - NSRect screenRect = [[NSScreen mainScreen] frame]; - rect.y = screenRect.size.height - rect.y - rect.h; - } - return(rect); -} - -static void mp_window_update_rect_cache(mp_window_data* window) -{ - @autoreleasepool - { - NSRect frame = [window->osx.nsWindow frame]; - window->frameRect = mp_osx_to_user_screen_rect((mp_rect){frame.origin.x, frame.origin.y, frame.size.width, frame.size.height}); - - const NSRect contentRect = [[window->osx.nsWindow contentView] frame]; - - window->contentRect = (mp_rect){ contentRect.origin.x, - contentRect.origin.y, - contentRect.size.width, - contentRect.size.height }; - - window->contentRect.y = window->frameRect.h - window->contentRect.y - window->contentRect.h; - } -} - static u32 mp_osx_get_window_style_mask(mp_window_style style) { u32 mask = 0; @@ -657,16 +619,22 @@ void mp_install_keyboard_layout_listener() - (void)windowDidMove:(NSNotification *)notification { const NSRect contentRect = [[mpWindow->osx.nsWindow contentView] frame]; - - mp_window_update_rect_cache(mpWindow); + const NSRect frameRect = [mpWindow->osx.nsWindow frame]; + NSScreen* screen = mpWindow->osx.nsWindow.screen; mp_event event = {}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_MOVE; - event.frame.rect.x = contentRect.origin.x; - event.frame.rect.y = contentRect.origin.y; - event.frame.rect.w = contentRect.size.width; - event.frame.rect.h = contentRect.size.height; + + event.move.frame.x = frameRect.origin.x; + event.move.frame.y = screen.frame.size.height - frameRect.origin.y - frameRect.size.height; + event.move.frame.w = frameRect.size.width; + event.move.frame.h = frameRect.size.height; + + event.move.content.x = frameRect.origin.x + contentRect.origin.x; + event.move.content.y = screen.frame.size.height - frameRect.origin.y - contentRect.origin.y - contentRect.size.height; + event.move.content.w = contentRect.size.width; + event.move.content.h = contentRect.size.height; mp_queue_event(&event); } @@ -674,16 +642,22 @@ void mp_install_keyboard_layout_listener() - (void)windowDidResize:(NSNotification *)notification { const NSRect contentRect = [[mpWindow->osx.nsWindow contentView] frame]; - - mp_window_update_rect_cache(mpWindow); + const NSRect frameRect = [mpWindow->osx.nsWindow frame]; + NSScreen* screen = mpWindow->osx.nsWindow.screen; mp_event event = {}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_WINDOW_RESIZE; - event.frame.rect.x = contentRect.origin.x; - event.frame.rect.y = contentRect.origin.y; - event.frame.rect.w = contentRect.size.width; - event.frame.rect.h = contentRect.size.height; + + event.move.frame.x = frameRect.origin.x; + event.move.frame.y = screen.frame.size.height - frameRect.origin.y - frameRect.size.height; + event.move.frame.w = frameRect.size.width; + event.move.frame.h = frameRect.size.height; + + event.move.content.x = frameRect.origin.x + contentRect.origin.x; + event.move.content.y = screen.frame.size.height - frameRect.origin.y - contentRect.origin.y - contentRect.size.height; + event.move.content.w = contentRect.size.width; + event.move.content.h = contentRect.size.height; if(__mpApp.liveResizeCallback) { @@ -869,11 +843,11 @@ static void mp_process_mouse_button(NSEvent* nsEvent, mp_window_data* window, mp mp_event event = {}; event.type = MP_EVENT_MOUSE_MOVE; event.window = mp_window_handle_from_ptr(window); - event.move.x = p.x; - event.move.y = frame.size.height - p.y; - event.move.deltaX = [nsEvent deltaX]; - event.move.deltaY = [nsEvent deltaY]; - event.move.mods = mp_convert_osx_mods([nsEvent modifierFlags]); + event.mouse.x = p.x; + event.mouse.y = frame.size.height - p.y; + event.mouse.deltaX = [nsEvent deltaX]; + event.mouse.deltaY = [nsEvent deltaY]; + event.mouse.mods = mp_convert_osx_mods([nsEvent modifierFlags]); mp_queue_event(&event); } @@ -885,11 +859,11 @@ static void mp_process_mouse_button(NSEvent* nsEvent, mp_window_data* window, mp event.type = MP_EVENT_MOUSE_WHEEL; double factor = [nsEvent hasPreciseScrollingDeltas] ? 0.1 : 1.0; - event.move.x = 0; - event.move.y = 0; - event.move.deltaX = -[nsEvent scrollingDeltaX]*factor; - event.move.deltaY = -[nsEvent scrollingDeltaY]*factor; - event.move.mods = mp_convert_osx_mods([nsEvent modifierFlags]); + event.mouse.x = 0; + event.mouse.y = 0; + event.mouse.deltaX = -[nsEvent scrollingDeltaX]*factor; + event.mouse.deltaY = -[nsEvent scrollingDeltaY]*factor; + event.mouse.mods = mp_convert_osx_mods([nsEvent modifierFlags]); mp_queue_event(&event); } @@ -1331,15 +1305,6 @@ str8 mp_clipboard_get_data_for_tag(mem_arena* arena, const char* tag) // Window public API //--------------------------------------------------------------- -/* -//TODO(martin): review include scheme -extern "C" { - mp_graphics_surface mp_metal_surface_create_for_window_ptr(mp_window_data* window); - mp_graphics_surface mp_graphics_surface_null_handle(); - mp_graphics_surface mp_graphics_surface_handle_from_ptr(mp_graphics_surface_data* surface); -} -*/ - mp_window mp_window_create(mp_rect contentRect, const char* title, mp_window_style style) {@autoreleasepool{ mp_window_data* window = mp_window_alloc(); @@ -1392,7 +1357,6 @@ mp_window mp_window_create(mp_rect contentRect, const char* title, mp_window_sty [window->osx.nsWindow makeFirstResponder:view]; [window->osx.nsWindow setAcceptsMouseMovedEvents:YES]; - mp_window_update_rect_cache(window); mp_window windowHandle = mp_window_handle_from_ptr(window); @@ -1545,122 +1509,82 @@ void mp_window_bring_to_front_and_focus(mp_window window) mp_window_focus(window); } +mp_rect mp_window_get_frame_rect(mp_window window) +{ + mp_rect rect = {0}; + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + NSRect frameRect = windowData->osx.nsWindow.frame; + NSScreen* screen = windowData->osx.nsWindow.screen; -mp_rect mp_window_content_rect_for_frame_rect(mp_rect frameRect, mp_window_style style) -{@autoreleasepool{ - u32 mask = mp_osx_get_window_style_mask(style); - mp_rect nativeFrame = mp_user_to_osx_screen_rect(frameRect); - NSRect frame = NSMakeRect(nativeFrame.x, nativeFrame.y, nativeFrame.w, nativeFrame.h); - NSRect content = [NSWindow contentRectForFrameRect:frame styleMask:mask]; - mp_rect result = {content.origin.x, content.origin.y, content.size.width, content.size.height}; - result = mp_osx_to_user_screen_rect(result); - return(result); -}} + rect = (mp_rect){ + frameRect.origin.x, + screen.frame.size.height - frameRect.origin.y - frameRect.size.height, + frameRect.size.width, + frameRect.size.height + }; + } + return(rect); +} -mp_rect mp_window_frame_rect_for_content_rect(mp_rect contentRect, mp_window_style style) +void mp_window_set_frame_rect(mp_window window, mp_rect rect) {@autoreleasepool{ - uint32 mask = mp_osx_get_window_style_mask(style); - mp_rect nativeContent = mp_user_to_osx_screen_rect(contentRect); - NSRect content = NSMakeRect(nativeContent.x, nativeContent.y, nativeContent.w, nativeContent.h); - NSRect frame = [NSWindow frameRectForContentRect:content styleMask:mask]; - mp_rect result = {frame.origin.x, frame.origin.y, frame.size.width, frame.size.height}; - result = mp_osx_to_user_screen_rect(result); - return(result); + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + NSScreen* screen = windowData->osx.nsWindow.screen; + NSRect frameRect = { + rect.x, + screen.frame.size.height - rect.y - rect.h, + rect.w, + rect.h + }; + [windowData->osx.nsWindow setFrame:frameRect display:YES]; + } }} mp_rect mp_window_get_content_rect(mp_window window) -{ +{@autoreleasepool{ mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - return(windowData->contentRect); - } - else - { - return((mp_rect){}); - } -} + NSScreen* screen = [windowData->osx.nsWindow screen]; + NSView* view = [windowData->osx.nsWindow contentView]; + NSRect contentRect = [windowData->osx.nsWindow convertRectToScreen: view.frame]; + + mp_rect rect = { + contentRect.origin.x, + screen.frame.size.height - contentRect.origin.y - contentRect.size.height, + contentRect.size.width, + contentRect.size.height}; -mp_rect mp_window_get_absolute_content_rect(mp_window window) -{ - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - mp_rect rect = windowData->contentRect; - rect.x += windowData->frameRect.x; - rect.y += windowData->frameRect.y; return(rect); } else { return((mp_rect){}); } -} - -mp_rect mp_window_get_frame_rect(mp_window window) -{ - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - return(windowData->frameRect); - } - else - { - return((mp_rect){}); - } -} - -void mp_window_set_content_rect(mp_window window, mp_rect contentRect) -{@autoreleasepool{ - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - u32 mask = mp_osx_get_window_style_mask(windowData->style); - - mp_rect nativeRect = mp_user_to_osx_screen_rect(contentRect); - NSRect content = NSMakeRect(nativeRect.x, nativeRect.y, nativeRect.w, nativeRect.h); - NSRect frame = [NSWindow frameRectForContentRect:content styleMask:mask]; - - [windowData->osx.nsWindow setFrame:frame display:YES]; - - mp_window_update_rect_cache(windowData); - } -}} -void mp_window_set_frame_rect(mp_window window, mp_rect frameRect) -{@autoreleasepool{ - mp_window_data* windowData = mp_window_ptr_from_handle(window); - if(windowData) - { - mp_rect nativeRect = mp_user_to_osx_screen_rect(frameRect); - NSRect frame = NSMakeRect(nativeRect.x, nativeRect.y, nativeRect.w, nativeRect.h); - [windowData->osx.nsWindow setFrame:frame display:YES]; - - mp_window_update_rect_cache(windowData); - NSRect contentRect = [[windowData->osx.nsWindow contentView] frame]; - } }} -void mp_window_set_frame_size(mp_window window, int width, int height) -{ - mp_rect frame = mp_window_get_frame_rect(window); - frame.w = width; - frame.h = height; - mp_window_set_frame_rect(window, frame); -} +void mp_window_set_content_rect(mp_window window, mp_rect rect) +{@autoreleasepool{ -void mp_window_set_content_size(mp_window window, int width, int height) -{ mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - mp_rect frame = windowData->frameRect; - mp_rect content = mp_window_content_rect_for_frame_rect(frame, windowData->style); - content.w = width; - content.h = height; - frame = mp_window_frame_rect_for_content_rect(content, windowData->style); - mp_window_set_frame_rect(window, frame); + NSScreen* screen = [windowData->osx.nsWindow screen]; + NSRect contentRect = { + rect.x, + screen.frame.size.height - rect.y - rect.h, + rect.w, + rect.h + }; + + NSRect frameRect = [windowData->osx.nsWindow frameRectForContentRect: contentRect]; + [windowData->osx.nsWindow setFrame:frameRect display:YES]; } -} +}} //-------------------------------------------------------------------- // platform surface @@ -1678,26 +1602,13 @@ vec2 mg_osx_surface_contents_scaling(mg_surface_data* surface) return(res); }} -mp_rect mg_osx_surface_get_frame(mg_surface_data* surface) +vec2 mg_osx_surface_get_size(mg_surface_data* surface) {@autoreleasepool{ - CGRect frame = surface->layer.caLayer.frame; - mp_rect res = {frame.origin.x, - frame.origin.y, - frame.size.width, - frame.size.height}; + CGRect bounds = surface->layer.caLayer.bounds; + vec2 res = {bounds.size.width, bounds.size.height}; return(res); }} -void mg_osx_surface_set_frame(mg_surface_data* surface, mp_rect frame) -{@autoreleasepool{ - CGRect cgFrame = {{frame.x, frame.y}, {frame.w, frame.h}}; - - [CATransaction begin]; - [CATransaction setDisableActions:YES]; - [surface->layer.caLayer setFrame: cgFrame]; - [CATransaction commit]; -}} - bool mg_osx_surface_get_hidden(mg_surface_data* surface) {@autoreleasepool{ return([surface->layer.caLayer isHidden]); @@ -1721,8 +1632,7 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window surface->nativeLayer = mg_osx_surface_native_layer; surface->contentsScaling = mg_osx_surface_contents_scaling; - surface->getFrame = mg_osx_surface_get_frame; - surface->setFrame = mg_osx_surface_set_frame; + surface->getSize = mg_osx_surface_get_size; surface->getHidden = mg_osx_surface_get_hidden; surface->setHidden = mg_osx_surface_set_hidden; @@ -1734,6 +1644,8 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window surface->layer.caLayer.frame = (CGRect){{0, 0}, size}; surface->layer.caLayer.contentsScale = window->osx.nsView.layer.contentsScale; + surface->layer.caLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable; + [window->osx.nsView.layer addSublayer: surface->layer.caLayer]; }} @@ -1758,8 +1670,7 @@ void mg_surface_init_remote(mg_surface_data* surface, u32 width, u32 height) surface->nativeLayer = mg_osx_surface_native_layer; surface->contentsScaling = mg_osx_surface_contents_scaling; - surface->getFrame = mg_osx_surface_get_frame; - surface->setFrame = mg_osx_surface_set_frame; + surface->getSize = mg_osx_surface_get_size; surface->getHidden = mg_osx_surface_get_hidden; surface->setHidden = mg_osx_surface_set_hidden; surface->remoteID = mg_osx_surface_remote_id; @@ -1786,8 +1697,7 @@ void mg_surface_init_host(mg_surface_data* surface, mp_window_data* window) surface->api = MG_HOST; surface->nativeLayer = mg_osx_surface_native_layer; surface->contentsScaling = mg_osx_surface_contents_scaling; - surface->getFrame = mg_osx_surface_get_frame; - surface->setFrame = mg_osx_surface_set_frame; + surface->getSize = mg_osx_surface_get_size; surface->getHidden = mg_osx_surface_get_hidden; surface->setHidden = mg_osx_surface_set_hidden; surface->hostConnect = mg_osx_surface_host_connect; diff --git a/src/win32_app.c b/src/win32_app.c index c438847..89b9f97 100644 --- a/src/win32_app.c +++ b/src/win32_app.c @@ -240,9 +240,9 @@ static void process_wheel_event(mp_window_data* window, f32 x, f32 y) mp_event event = {0}; event.window = mp_window_handle_from_ptr(window); event.type = MP_EVENT_MOUSE_WHEEL; - event.move.deltaX = x/30.0f; - event.move.deltaY = -y/30.0f; - event.move.mods = mp_get_mod_keys(); + event.mouse.deltaX = x/30.0f; + event.mouse.deltaY = -y/30.0f; + event.mouse.mods = mp_get_mod_keys(); mp_queue_event(&event); } @@ -254,26 +254,20 @@ static void win32_update_child_layers(mp_window_data* window) POINT point = {0}; ClientToScreen(window->win32.hWnd, &point); - int w = clientRect.right - clientRect.left; - int h = clientRect.bottom - clientRect.top; + int clientWidth = (clientRect.right - clientRect.left); + int clientHeight = (clientRect.bottom - clientRect.top); HWND insertAfter = window->win32.hWnd; for_list(&window->win32.layers, layer, mp_layer, listElt) { - mp_rect clipped = {0}; - clipped.x = Clamp(layer->frame.x, 0, w); - clipped.y = Clamp(layer->frame.y, 0, h); - clipped.w = Clamp(layer->frame.w, 0, w - layer->frame.x); - clipped.h = Clamp(layer->frame.h, 0, h - layer->frame.y); - SetWindowPos(layer->hWnd, - insertAfter, - point.x + clipped.x, - point.y + clipped.y, - clipped.w, - clipped.h, - SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER); + insertAfter, + point.x, + point.y, + clientWidth, + clientHeight, + SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER); insertAfter = layer->hWnd; } @@ -321,30 +315,17 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) } break; case WM_SIZING: - { - //TODO: take dpi into account - - RECT* rect = (RECT*)lParam; - - mp_event event = {0}; - event.window = mp_window_handle_from_ptr(mpWindow); - event.type = MP_EVENT_WINDOW_RESIZE; - event.frame.rect = (mp_rect){rect->left, rect->bottom, rect->bottom - rect->top, rect->right - rect->left}; - mp_queue_event(&event); - - win32_update_child_layers(mpWindow); - } break; - case WM_MOVING: { - //TODO: take dpi into account - RECT* rect = (RECT*)lParam; mp_event event = {0}; + event.type = message == WM_SIZING ? MP_EVENT_WINDOW_RESIZE : MP_EVENT_WINDOW_MOVE; event.window = mp_window_handle_from_ptr(mpWindow); - event.type = MP_EVENT_WINDOW_MOVE; - event.frame.rect = (mp_rect){rect->left, rect->bottom, rect->bottom - rect->top, rect->right - rect->left}; + + event.move.frame = mp_window_get_frame_rect(event.window); + event.move.content = mp_window_get_content_rect(event.window); + mp_queue_event(&event); win32_update_child_layers(mpWindow); @@ -429,15 +410,15 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) mp_event event = {0}; event.window = mp_window_handle_from_ptr(mpWindow); event.type = MP_EVENT_MOUSE_MOVE; - event.move.x = LOWORD(lParam) / scaling; - event.move.y = HIWORD(lParam) / scaling; + event.mouse.x = LOWORD(lParam) / scaling; + event.mouse.y = HIWORD(lParam) / scaling; if(__mpApp.win32.mouseTracked || __mpApp.win32.mouseCaptureMask) { - event.move.deltaX = event.move.x - __mpApp.win32.lastMousePos.x; - event.move.deltaY = event.move.y - __mpApp.win32.lastMousePos.y; + event.mouse.deltaX = event.mouse.x - __mpApp.win32.lastMousePos.x; + event.mouse.deltaY = event.mouse.y - __mpApp.win32.lastMousePos.y; } - __mpApp.win32.lastMousePos = (vec2){event.move.x, event.move.y}; + __mpApp.win32.lastMousePos = (vec2){event.mouse.x, event.mouse.y}; if(!__mpApp.win32.mouseTracked) { @@ -452,8 +433,8 @@ LRESULT WinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam) mp_event enter = {.window = event.window, .type = MP_EVENT_MOUSE_ENTER, - .move.x = event.move.x, - .move.y = event.move.y}; + .mouse.x = event.mouse.x, + .mouse.y = event.mouse.y}; mp_queue_event(&enter); } @@ -599,12 +580,24 @@ mp_window mp_window_create(mp_rect rect, const char* title, mp_window_style styl HMONITOR monitor = MonitorFromPoint((POINT){rect.x, rect.y}, MONITOR_DEFAULTTOPRIMARY); GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); - f32 dpiScalingX = (f32)dpiX/96.; - f32 dpiScalingY = (f32)dpiY/96.; + f32 scaleX = (f32)dpiX/96.; + f32 scaleY = (f32)dpiY/96.; + + RECT frame = { + rect.x * scaleX, + rect.y * scaleY, + (rect.x + rect.w)*scaleX, + (rect.y + rect.h)*scaleY + }; + + DWORD winStyle = WS_OVERLAPPEDWINDOW; + AdjustWindowRect(&frame, winStyle, FALSE); HWND windowHandle = CreateWindow("ApplicationWindowClass", "Test Window", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - rect.w * dpiScalingX, rect.h * dpiScalingY, + winStyle, + frame.left, frame.top, + frame.right-frame.left, + frame.bottom-frame.top, 0, 0, windowClass.hInstance, 0); if(!windowHandle) @@ -808,45 +801,167 @@ void mp_window_bring_to_front(mp_window window) } } +mp_rect mp_window_get_frame_rect(mp_window window) +{ + mp_rect rect = {0}; + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + //NOTE: GetWindowRect() includes the drop shadow, which we don't want, so we call + // DwmGetWindowAttribute() instead. + // Note that contrary to what the GetWindowRect() docs suggests when mentionning + // this, DwmGetWindowAttributes() _does_ seem to adjust for DPI. + u32 dpi = GetDpiForWindow(windowData->win32.hWnd); + f32 scale = (float)dpi/96.; + + RECT frame; + HRESULT res = DwmGetWindowAttribute(windowData->win32.hWnd, + DWMWA_EXTENDED_FRAME_BOUNDS, + &frame, + sizeof(RECT)); + if(res == S_OK) + { + rect = (mp_rect){ + frame.left / scale, + frame.top / scale, + (frame.right - frame.left)/scale, + (frame.bottom - frame.top)/scale}; + } + } + return(rect); +} + +mp_rect win32_get_drop_shadow_offsets(HWND hWnd) +{ + RECT frameIncludingShadow; + RECT frameExcludingShadow; + + GetWindowRect(hWnd, &frameIncludingShadow); + DwmGetWindowAttribute(hWnd, + DWMWA_EXTENDED_FRAME_BOUNDS, + &frameExcludingShadow, + sizeof(RECT)); + + mp_rect extents = { + .x = frameIncludingShadow.left - frameExcludingShadow.left, + .y = frameIncludingShadow.top - frameExcludingShadow.top, + .w = frameIncludingShadow.right - frameExcludingShadow.right, + .h = frameIncludingShadow.bottom- frameExcludingShadow.bottom + }; + + return(extents); +} + +void mp_window_set_frame_rect(mp_window window, mp_rect rect) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + u32 dpi = GetDpiForWindow(windowData->win32.hWnd); + f32 scale = (float)dpi/96.; + + //NOTE compute the size of the drop shadow to add it in setwindowpos + mp_rect shadowOffsets = win32_get_drop_shadow_offsets(windowData->win32.hWnd); + + RECT frame = { + rect.x * scale + shadowOffsets.x, + rect.y * scale + shadowOffsets.y, + (rect.x + rect.w)*scale + shadowOffsets.w, + (rect.y + rect.h)*scale + shadowOffsets.h + }; + + SetWindowPos(windowData->win32.hWnd, + HWND_TOP, + frame.left, + frame.top, + frame.right - frame.left, + frame.bottom - frame.top, + SWP_NOZORDER|SWP_NOACTIVATE); + } +} + mp_rect mp_window_get_content_rect(mp_window window) { mp_rect rect = {0}; mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - RECT winRect; - if(GetClientRect(windowData->win32.hWnd, &winRect)) + RECT client; + if(GetClientRect(windowData->win32.hWnd, &client)) { u32 dpi = GetDpiForWindow(windowData->win32.hWnd); f32 scale = (float)dpi/96.; - rect = (mp_rect){0, 0, (winRect.right - winRect.left)/scale, (winRect.bottom - winRect.top)/scale}; + + POINT origin = {0, 0}; + ClientToScreen(windowData->win32.hWnd, &origin); + + rect = (mp_rect){ + origin.x/scale, + origin.y/scale, + (client.right - client.left)/scale, + (client.bottom - client.top)/scale}; } } return(rect); } -//TODO: set content rect, center +void mp_window_set_content_rect(mp_window window, mp_rect rect) +{ + mp_window_data* windowData = mp_window_ptr_from_handle(window); + if(windowData) + { + u32 dpi = GetDpiForWindow(windowData->win32.hWnd); + f32 scale = (float)dpi/96.; + + RECT frame = { + rect.x * scale, + rect.y * scale, + (rect.x + rect.w)*scale, + (rect.y + rect.h)*scale}; + + DWORD style = GetWindowLong(windowData->win32.hWnd, GWL_STYLE); + BOOL menu = (GetMenu(windowData->win32.hWnd) != NULL); + AdjustWindowRect(&frame, style, menu); + + SetWindowPos(windowData->win32.hWnd, + HWND_TOP, + frame.left, + frame.top, + frame.right - frame.left, + frame.bottom - frame.top, + SWP_NOZORDER|SWP_NOACTIVATE); + } +} + void mp_window_center(mp_window window) { mp_window_data* windowData = mp_window_ptr_from_handle(window); if(windowData) { - RECT winRect; - GetWindowRect(windowData->win32.hWnd, &winRect); - HMONITOR monitor = MonitorFromPoint((POINT){winRect.left, winRect.top}, MONITOR_DEFAULTTOPRIMARY); - MONITORINFO monitorInfo = {.cbSize = sizeof(MONITORINFO)}; - GetMonitorInfoW(monitor, &monitorInfo); + mp_rect frame = mp_window_get_frame_rect(window); - int monW = monitorInfo.rcWork.right - monitorInfo.rcWork.left; - int monH = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; - int winW = winRect.right - winRect.left; - int winH = winRect.bottom - winRect.top; + HMONITOR monitor = MonitorFromWindow(windowData->win32.hWnd, MONITOR_DEFAULTTOPRIMARY); + if(monitor) + { + MONITORINFO monitorInfo = {.cbSize = sizeof(MONITORINFO)}; + GetMonitorInfoW(monitor, &monitorInfo); - int winX = 0.5*(monW-winW); - int winY = 0.5*(monW-winW); + int dpiX, dpiY; + GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + f32 scaleX = dpiX/96.; + f32 scaleY = dpiY/96.; - SetWindowPos(windowData->win32.hWnd, NULL, winX, winY, winW, winH, SWP_NOZORDER|SWP_NOACTIVATE); + f32 monX = monitorInfo.rcWork.left/scaleX; + f32 monY = monitorInfo.rcWork.top/scaleY; + f32 monW = (monitorInfo.rcWork.right - monitorInfo.rcWork.left)/scaleX; + f32 monH = (monitorInfo.rcWork.bottom - monitorInfo.rcWork.top)/scaleY; + + frame.x = monX + 0.5*(monW - frame.w); + frame.y = monY + 0.5*(monH - frame.h); + + mp_window_set_frame_rect(window, frame); + } } } @@ -935,37 +1050,17 @@ vec2 mg_win32_surface_contents_scaling(mg_surface_data* surface) return(contentsScaling); } -mp_rect mg_win32_surface_get_frame(mg_surface_data* surface) +vec2 mg_win32_surface_get_size(mg_surface_data* surface) { - RECT rect = {0}; - GetClientRect(surface->layer.hWnd, &rect); - - vec2 scale = mg_win32_surface_contents_scaling(surface); - - mp_rect res = {rect.left/scale.x, - rect.bottom/scale.y, - (rect.right - rect.left)/scale.x, - (rect.bottom - rect.top)/scale.y}; - return(res); -} - -void mg_win32_surface_set_frame(mg_surface_data* surface, mp_rect frame) -{ - HWND parent = GetParent(surface->layer.hWnd); - RECT parentContentRect; - - GetClientRect(parent, &parentContentRect); - int parentHeight = parentContentRect.bottom - parentContentRect.top; - - vec2 scale = mg_win32_surface_contents_scaling(surface); - - SetWindowPos(surface->layer.hWnd, - HWND_TOP, - frame.x * scale.x, - parentHeight - (frame.y + frame.h) * scale.y, - frame.w * scale.x, - frame.h * scale.y, - SWP_NOACTIVATE | SWP_NOZORDER); + vec2 size = {0}; + RECT rect; + if(GetClientRect(surface->layer.hWnd, &rect)) + { + u32 dpi = GetDpiForWindow(surface->layer.hWnd); + f32 scale = (float)dpi/96.; + size = (vec2){(rect.right - rect.left)/scale, (rect.bottom - rect.top)/scale}; + } + return(size); } bool mg_win32_surface_get_hidden(mg_surface_data* surface) @@ -1030,8 +1125,7 @@ LRESULT LayerWinProc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lPar void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window) { surface->contentsScaling = mg_win32_surface_contents_scaling; - surface->getFrame = mg_win32_surface_get_frame; - surface->setFrame = mg_win32_surface_set_frame; + surface->getSize = mg_win32_surface_get_size; surface->getHidden = mg_win32_surface_get_hidden; surface->setHidden = mg_win32_surface_set_hidden; surface->nativeLayer = mg_win32_surface_native_layer; @@ -1050,12 +1144,12 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window POINT point = {0}; ClientToScreen(window->win32.hWnd, &point); - int width = parentRect.right - parentRect.left; - int height = parentRect.bottom - parentRect.top; + int clientWidth = parentRect.right - parentRect.left; + int clientHeight = parentRect.bottom - parentRect.top; surface->layer.hWnd = CreateWindow("layer_window_class", "layer", WS_POPUP | WS_VISIBLE, - point.x, point.y, width, height, + point.x, point.y, clientWidth, clientHeight, window->win32.hWnd, 0, layerWindowClass.hInstance, @@ -1076,7 +1170,6 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window log_error("couldn't enable blur behind\n"); } - surface->layer.frame = (mp_rect){0, 0, width, height}; surface->layer.parent = window; list_append(&window->win32.layers, &surface->layer.listElt); } @@ -1084,8 +1177,7 @@ void mg_surface_init_for_window(mg_surface_data* surface, mp_window_data* window void mg_surface_init_remote(mg_surface_data* surface, u32 width, u32 height) { surface->contentsScaling = mg_win32_surface_contents_scaling; - surface->getFrame = mg_win32_surface_get_frame; - surface->setFrame = mg_win32_surface_set_frame; + surface->getSize = mg_win32_surface_get_size; surface->getHidden = mg_win32_surface_get_hidden; surface->setHidden = mg_win32_surface_set_hidden; surface->nativeLayer = mg_win32_surface_native_layer; diff --git a/src/win32_app.h b/src/win32_app.h index e6783e0..2eb0e44 100644 --- a/src/win32_app.h +++ b/src/win32_app.h @@ -28,7 +28,6 @@ typedef struct mp_layer { mp_window_data* parent; list_elt listElt; - mp_rect frame; HWND hWnd; } mp_layer;