orca/src/graphics_surface.c

433 lines
10 KiB
C

/************************************************************//**
*
* @file: graphics_surface.c
* @author: Martin Fouilleul
* @date: 25/04/2023
*
*****************************************************************/
#include"graphics_surface.h"
//---------------------------------------------------------------
// per-thread selected surface
//---------------------------------------------------------------
mp_thread_local mg_surface __mgSelectedSurface = {0};
//---------------------------------------------------------------
// typed handles functions
//---------------------------------------------------------------
mg_surface mg_surface_handle_alloc(mg_surface_data* surface)
{
mg_surface handle = {.h = mg_handle_alloc(MG_HANDLE_SURFACE, (void*)surface) };
return(handle);
}
mg_surface_data* mg_surface_data_from_handle(mg_surface handle)
{
mg_surface_data* data = mg_data_from_handle(MG_HANDLE_SURFACE, handle.h);
return(data);
}
mg_image mg_image_handle_alloc(mg_image_data* image)
{
mg_image handle = {.h = mg_handle_alloc(MG_HANDLE_IMAGE, (void*)image) };
return(handle);
}
mg_image_data* mg_image_data_from_handle(mg_image handle)
{
mg_image_data* data = mg_data_from_handle(MG_HANDLE_IMAGE, handle.h);
return(data);
}
//---------------------------------------------------------------
// surface API
//---------------------------------------------------------------
#if MG_COMPILE_GL
#if PLATFORM_WINDOWS
#include"wgl_surface.h"
#define gl_surface_create_for_window mg_wgl_surface_create_for_window
#endif
#endif
#if MG_COMPILE_GLES
#include"egl_surface.h"
#endif
#if MG_COMPILE_METAL
#include"mtl_surface.h"
#endif
#if MG_COMPILE_CANVAS
#if PLATFORM_MACOS
mg_surface_data* mtl_canvas_surface_create_for_window(mp_window window);
#elif PLATFORM_WINDOWS
mg_surface_data* gl_canvas_surface_create_for_window(mp_window window);
#endif
#endif
bool mg_is_surface_backend_available(mg_surface_api api)
{
bool result = false;
switch(api)
{
#if MG_COMPILE_METAL
case MG_METAL:
#endif
#if MG_COMPILE_GL
case MG_GL:
#endif
#if MG_COMPILE_GLES
case MG_GLES:
#endif
#if MG_COMPILE_CANVAS
case MG_CANVAS:
#endif
result = true;
break;
default:
break;
}
return(result);
}
mg_surface mg_surface_nil() { return((mg_surface){.h = 0}); }
bool mg_surface_is_nil(mg_surface surface) { return(surface.h == 0); }
mg_surface mg_surface_create_for_window(mp_window window, mg_surface_api api)
{
if(__mgData.init)
{
mg_init();
}
mg_surface surfaceHandle = mg_surface_nil();
mg_surface_data* surface = 0;
switch(api)
{
#if MG_COMPILE_GL
case MG_GL:
surface = gl_surface_create_for_window(window);
break;
#endif
#if MG_COMPILE_GLES
case MG_GLES:
surface = mg_egl_surface_create_for_window(window);
break;
#endif
#if MG_COMPILE_METAL
case MG_METAL:
surface = mg_mtl_surface_create_for_window(window);
break;
#endif
#if MG_COMPILE_CANVAS
case MG_CANVAS:
#if PLATFORM_MACOS
surface = mtl_canvas_surface_create_for_window(window);
#elif PLATFORM_WINDOWS
surface = gl_canvas_surface_create_for_window(window);
#endif
break;
#endif
default:
break;
}
if(surface)
{
surfaceHandle = mg_surface_handle_alloc(surface);
}
return(surfaceHandle);
}
mg_surface mg_surface_create_remote(u32 width, u32 height, mg_surface_api api)
{
if(!__mgData.init)
{
mg_init();
}
mg_surface surfaceHandle = mg_surface_nil();
mg_surface_data* surface = 0;
switch(api)
{
#if MG_COMPILE_GLES
case MG_GLES:
surface = mg_egl_surface_create_remote(width, height);
break;
#endif
default:
break;
}
if(surface)
{
surfaceHandle = mg_surface_handle_alloc(surface);
}
return(surfaceHandle);
}
mg_surface mg_surface_create_host(mp_window window)
{
if(!__mgData.init)
{
mg_init();
}
mg_surface handle = mg_surface_nil();
mg_surface_data* surface = 0;
#if PLATFORM_MACOS
surface = mg_osx_surface_create_host(window);
#elif PLATFORM_WINDOWS
surface = mg_win32_surface_create_host(window);
#endif
if(surface)
{
handle = mg_surface_handle_alloc(surface);
}
return(handle);
}
void mg_surface_destroy(mg_surface handle)
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* surface = mg_surface_data_from_handle(handle);
if(surface)
{
if(surface->backend && surface->backend->destroy)
{
surface->backend->destroy(surface->backend);
}
surface->destroy(surface);
mg_handle_recycle(handle.h);
}
}
void mg_surface_deselect()
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* prevSurface = mg_surface_data_from_handle(__mgSelectedSurface);
if(prevSurface && prevSurface->deselect)
{
prevSurface->deselect(prevSurface);
}
__mgSelectedSurface = mg_surface_nil();
}
void mg_surface_prepare(mg_surface surface)
{
DEBUG_ASSERT(__mgData.init);
if(surface.h != __mgSelectedSurface.h)
{
mg_surface_deselect();
}
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->prepare)
{
surfaceData->prepare(surfaceData);
__mgSelectedSurface = surface;
}
}
void mg_surface_present(mg_surface surface)
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->present)
{
surfaceData->present(surfaceData);
}
}
void mg_surface_swap_interval(mg_surface surface, int swap)
{
DEBUG_ASSERT(__mgData.init);
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->swapInterval)
{
surfaceData->swapInterval(surfaceData, swap);
}
}
vec2 mg_surface_contents_scaling(mg_surface surface)
{
DEBUG_ASSERT(__mgData.init);
vec2 scaling = {1, 1};
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->contentsScaling)
{
scaling = surfaceData->contentsScaling(surfaceData);
}
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);
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->setHidden)
{
surfaceData->setHidden(surfaceData, hidden);
}
}
bool mg_surface_get_hidden(mg_surface surface)
{
DEBUG_ASSERT(__mgData.init);
bool res = false;
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->getHidden)
{
res = surfaceData->getHidden(surfaceData);
}
return(res);
}
void* mg_surface_native_layer(mg_surface surface)
{
void* res = 0;
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->nativeLayer)
{
res = surfaceData->nativeLayer(surfaceData);
}
return(res);
}
mg_surface_id mg_surface_remote_id(mg_surface handle)
{
mg_surface_id remoteId = 0;
mg_surface_data* surface = mg_surface_data_from_handle(handle);
if(surface && surface->remoteID)
{
remoteId = surface->remoteID(surface);
}
return(remoteId);
}
void mg_surface_host_connect(mg_surface handle, mg_surface_id remoteID)
{
mg_surface_data* surface = mg_surface_data_from_handle(handle);
if(surface && surface->hostConnect)
{
surface->hostConnect(surface, remoteID);
}
}
void mg_surface_render_commands(mg_surface surface,
mg_color clearColor,
u32 primitiveCount,
mg_primitive* primitives,
u32 eltCount,
mg_path_elt* elements)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend)
{
surfaceData->backend->render(surfaceData->backend,
clearColor,
primitiveCount,
primitives,
eltCount,
elements);
}
}
//------------------------------------------------------------------------------------------
//NOTE(martin): images
//------------------------------------------------------------------------------------------
vec2 mg_image_size(mg_image image)
{
vec2 res = {0};
mg_image_data* imageData = mg_image_data_from_handle(image);
if(imageData)
{
res = imageData->size;
}
return(res);
}
mg_image mg_image_create(mg_surface surface, u32 width, u32 height)
{
mg_image image = mg_image_nil();
mg_surface_data* surfaceData = mg_surface_data_from_handle(surface);
if(surfaceData && surfaceData->backend)
{
DEBUG_ASSERT(surfaceData->api == MG_CANVAS);
mg_image_data* imageData = surfaceData->backend->imageCreate(surfaceData->backend, (vec2){width, height});
if(imageData)
{
imageData->surface = surface;
image = mg_image_handle_alloc(imageData);
}
}
return(image);
}
void mg_image_destroy(mg_image image)
{
mg_image_data* imageData = mg_image_data_from_handle(image);
if(imageData)
{
mg_surface_data* surface = mg_surface_data_from_handle(imageData->surface);
if(surface && surface->backend)
{
surface->backend->imageDestroy(surface->backend, imageData);
mg_handle_recycle(image.h);
}
}
}
void mg_image_upload_region_rgba8(mg_image image, mp_rect region, u8* pixels)
{
mg_image_data* imageData = mg_image_data_from_handle(image);
if(imageData)
{
mg_surface_data* surfaceData = mg_surface_data_from_handle(imageData->surface);
if(surfaceData)
{
DEBUG_ASSERT(surfaceData->backend);
surfaceData->backend->imageUploadRegion(surfaceData->backend, imageData, region, pixels);
}
}
}