mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-05-09 09:41:23 +08:00
demos: Make the demos work in the macOS build.
This commit is contained in:
parent
7b07d77396
commit
b389fa89e4
Notes:
Henri Verbeet
2025-05-06 19:05:45 +02:00
Approved-by: Henri Verbeet (@hverbeet) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1482
23
Makefile.am
23
Makefile.am
@ -4,6 +4,11 @@ AM_CPPFLAGS = -I$(srcdir)/include -I$(srcdir)/include/private -I$(builddir)/incl
|
|||||||
AM_LDFLAGS = -no-undefined
|
AM_LDFLAGS = -no-undefined
|
||||||
VKD3D_PERL = $(PERL) -w
|
VKD3D_PERL = $(PERL) -w
|
||||||
|
|
||||||
|
objc_headers = \
|
||||||
|
include/private/appkit.h \
|
||||||
|
include/private/foundation.h \
|
||||||
|
include/private/quartzcore.h
|
||||||
|
|
||||||
widl_headers = \
|
widl_headers = \
|
||||||
include/vkd3d_d3d12.h \
|
include/vkd3d_d3d12.h \
|
||||||
include/vkd3d_d3d12sdklayers.h \
|
include/vkd3d_d3d12sdklayers.h \
|
||||||
@ -323,11 +328,12 @@ vkd3d_demos = \
|
|||||||
vkd3d_demos_headers = \
|
vkd3d_demos_headers = \
|
||||||
demos/demo.h \
|
demos/demo.h \
|
||||||
demos/demo_d3d12.h \
|
demos/demo_d3d12.h \
|
||||||
|
demos/demo_macos.h \
|
||||||
demos/demo_vkd3d.h \
|
demos/demo_vkd3d.h \
|
||||||
demos/demo_win32.h \
|
demos/demo_win32.h \
|
||||||
demos/demo_xcb.h
|
demos/demo_xcb.h
|
||||||
|
|
||||||
BUILT_SOURCES = $(widl_headers) \
|
BUILT_SOURCES = $(objc_headers) $(widl_headers) \
|
||||||
include/private/spirv_grammar.h \
|
include/private/spirv_grammar.h \
|
||||||
include/private/vkd3d_version.h
|
include/private/vkd3d_version.h
|
||||||
|
|
||||||
@ -549,6 +555,16 @@ endif
|
|||||||
|
|
||||||
noinst_HEADERS = $(vkd3d_test_headers) $(vkd3d_demos_headers)
|
noinst_HEADERS = $(vkd3d_test_headers) $(vkd3d_demos_headers)
|
||||||
|
|
||||||
|
VKD3D_V_PERL = $(vkd3d_v_perl_@AM_V@)
|
||||||
|
vkd3d_v_perl_ = $(vkd3d_v_perl_@AM_DEFAULT_V@)
|
||||||
|
vkd3d_v_perl_0 = @echo " PERL " $@;
|
||||||
|
vkd3d_v_perl_1 =
|
||||||
|
|
||||||
|
CLEANFILES += $(objc_headers)
|
||||||
|
${objc_headers}: %.h: demos/make_objc %.json
|
||||||
|
@$(MKDIR_P) $(@D)
|
||||||
|
$(VKD3D_V_PERL)$(VKD3D_PERL) $^ > $@.tmp && mv $@.tmp $@
|
||||||
|
|
||||||
VKD3D_V_WIDL = $(vkd3d_v_widl_@AM_V@)
|
VKD3D_V_WIDL = $(vkd3d_v_widl_@AM_V@)
|
||||||
vkd3d_v_widl_ = $(vkd3d_v_widl_@AM_DEFAULT_V@)
|
vkd3d_v_widl_ = $(vkd3d_v_widl_@AM_DEFAULT_V@)
|
||||||
vkd3d_v_widl_0 = @echo " WIDL " $@;
|
vkd3d_v_widl_0 = @echo " WIDL " $@;
|
||||||
@ -589,11 +605,6 @@ libvkd3d.pc: $(srcdir)/libs/vkd3d/libvkd3d.pc.in Makefile
|
|||||||
-e 's![@]PACKAGE_VERSION[@]!$(PACKAGE_VERSION)!g' \
|
-e 's![@]PACKAGE_VERSION[@]!$(PACKAGE_VERSION)!g' \
|
||||||
$< > $@
|
$< > $@
|
||||||
|
|
||||||
VKD3D_V_PERL = $(vkd3d_v_perl_@AM_V@)
|
|
||||||
vkd3d_v_perl_ = $(vkd3d_v_perl_@AM_DEFAULT_V@)
|
|
||||||
vkd3d_v_perl_0 = @echo " PERL " $@;
|
|
||||||
vkd3d_v_perl_1 =
|
|
||||||
|
|
||||||
include/private/spirv_grammar.h: libs/vkd3d-shader/make_spirv include/private/spirv.core.grammar.json
|
include/private/spirv_grammar.h: libs/vkd3d-shader/make_spirv include/private/spirv.core.grammar.json
|
||||||
@$(MKDIR_P) $(@D)
|
@$(MKDIR_P) $(@D)
|
||||||
$(VKD3D_V_PERL)$(VKD3D_PERL) $^ > $@.tmp && mv $@.tmp $@
|
$(VKD3D_V_PERL)$(VKD3D_PERL) $^ > $@.tmp && mv $@.tmp $@
|
||||||
|
@ -187,6 +187,10 @@ case $host_os in
|
|||||||
AC_SUBST([DEMO_LIBS],["-lgdi32"])
|
AC_SUBST([DEMO_LIBS],["-lgdi32"])
|
||||||
AC_SUBST([DEMO_CFLAGS],["-municode"])
|
AC_SUBST([DEMO_CFLAGS],["-municode"])
|
||||||
;;
|
;;
|
||||||
|
darwin*)
|
||||||
|
AC_SUBST([DEMO_LIBS],["-framework Foundation -framework AppKit -framework QuartzCore"])
|
||||||
|
AC_SUBST([DEMO_CFLAGS],[""])
|
||||||
|
;;
|
||||||
*) AS_IF([test "x$enable_demos" = "xyes" -a "x$HAVE_XCB" != "xyes"],
|
*) AS_IF([test "x$enable_demos" = "xyes" -a "x$HAVE_XCB" != "xyes"],
|
||||||
[AC_MSG_ERROR([libxcb is required for demos.])])
|
[AC_MSG_ERROR([libxcb is required for demos.])])
|
||||||
AC_SUBST([DEMO_LIBS],[$XCB_LIBS])
|
AC_SUBST([DEMO_LIBS],[$XCB_LIBS])
|
||||||
|
@ -43,13 +43,17 @@
|
|||||||
#define DEMO_ASM_PUSHSECTION ".section rdata\n\t"
|
#define DEMO_ASM_PUSHSECTION ".section rdata\n\t"
|
||||||
#define DEMO_ASM_POPSECTION ".text\n\t"
|
#define DEMO_ASM_POPSECTION ".text\n\t"
|
||||||
#define DEMO_ASM_OBJECT_TYPE(name)
|
#define DEMO_ASM_OBJECT_TYPE(name)
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define DEMO_ASM_PUSHSECTION ".pushsection __TEXT,__const\n\t"
|
||||||
|
#define DEMO_ASM_POPSECTION ".popsection\n\t"
|
||||||
|
#define DEMO_ASM_OBJECT_TYPE(name)
|
||||||
#else
|
#else
|
||||||
#define DEMO_ASM_PUSHSECTION ".pushsection .rodata\n\t"
|
#define DEMO_ASM_PUSHSECTION ".pushsection .rodata\n\t"
|
||||||
#define DEMO_ASM_POPSECTION ".popsection\n\t"
|
#define DEMO_ASM_POPSECTION ".popsection\n\t"
|
||||||
#define DEMO_ASM_OBJECT_TYPE(name) ".type "name", @object\n\t"
|
#define DEMO_ASM_OBJECT_TYPE(name) ".type "name", @object\n\t"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__WIN32__) && defined(__i386__)
|
#if (defined(__WIN32__) && defined(__i386__)) || defined(__APPLE__)
|
||||||
#define DEMO_ASM_NAME(name) "_"#name
|
#define DEMO_ASM_NAME(name) "_"#name
|
||||||
#else
|
#else
|
||||||
#define DEMO_ASM_NAME(name) #name
|
#define DEMO_ASM_NAME(name) #name
|
||||||
|
310
demos/demo_macos.h
Normal file
310
demos/demo_macos.h
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Henri Verbeet
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef long NSInteger;
|
||||||
|
typedef unsigned long NSUInteger;
|
||||||
|
|
||||||
|
typedef struct NSPoint
|
||||||
|
{
|
||||||
|
double x, y;
|
||||||
|
} NSPoint;
|
||||||
|
|
||||||
|
typedef struct NSRect
|
||||||
|
{
|
||||||
|
double x, y;
|
||||||
|
double w, h;
|
||||||
|
} NSRect;
|
||||||
|
|
||||||
|
#define BOOL OBJC_BOOL
|
||||||
|
#include "private/appkit.h"
|
||||||
|
#include "private/foundation.h"
|
||||||
|
#include "private/quartzcore.h"
|
||||||
|
#undef BOOL
|
||||||
|
|
||||||
|
extern const id NSDefaultRunLoopMode;
|
||||||
|
|
||||||
|
enum NSBackingStoreType
|
||||||
|
{
|
||||||
|
NSBackingStoreBuffered = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NSEventType
|
||||||
|
{
|
||||||
|
NSEventTypeKeyDown = 0xa,
|
||||||
|
NSEventTypeApplicationDefined = 0xf,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NSWindowStyleMask
|
||||||
|
{
|
||||||
|
NSWindowStyleMaskBorderless = 0x0000,
|
||||||
|
NSWindowStyleMaskTitled = 0x0001,
|
||||||
|
NSWindowStyleMaskClosable = 0x0002,
|
||||||
|
NSWindowStyleMaskMiniaturizable = 0x0004,
|
||||||
|
NSWindowStyleMaskResizable = 0x0008,
|
||||||
|
NSWindowStyleMaskUtilityWindow = 0x0010,
|
||||||
|
NSWindowStyleMaskDocModalWindow = 0x0040,
|
||||||
|
NSWindowStyleMaskNonactivatingPanel = 0x0080,
|
||||||
|
NSWindowStyleMaskUnifiedTitleAndToolbar = 0x1000,
|
||||||
|
NSWindowStyleMaskHUDWindow = 0x2000,
|
||||||
|
NSWindowStyleMaskFullScreen = 0x4000,
|
||||||
|
NSWindowStyleMaskFullSizeContentView = 0x8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DemoWindowDestroyed,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct demo_window_macos
|
||||||
|
{
|
||||||
|
struct demo_window w;
|
||||||
|
id window;
|
||||||
|
id layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct demo_window_macos *demo_macos_find_macos_window(struct demo *demo, id window)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < demo->window_count; ++i)
|
||||||
|
{
|
||||||
|
struct demo_window_macos *window_macos = CONTAINING_RECORD(demo->windows[i], struct demo_window_macos, w);
|
||||||
|
|
||||||
|
if (window_macos->window == window)
|
||||||
|
return window_macos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VkSurfaceKHR demo_window_macos_create_vk_surface(struct demo_window *window, VkInstance vk_instance)
|
||||||
|
{
|
||||||
|
struct demo_window_macos *window_macos = CONTAINING_RECORD(window, struct demo_window_macos, w);
|
||||||
|
struct VkMetalSurfaceCreateInfoEXT surface_desc;
|
||||||
|
VkSurfaceKHR vk_surface;
|
||||||
|
id l, v;
|
||||||
|
|
||||||
|
l = window_macos->layer = CAMetalLayer_layer();
|
||||||
|
CAMetalLayer_setContentsScale(l, NSScreen_backingScaleFactor(NSScreen_mainScreen()));
|
||||||
|
v = NSWindow_contentView(window_macos->window);
|
||||||
|
NSView_setLayer(v, l);
|
||||||
|
NSView_setWantsLayer(v, true);
|
||||||
|
|
||||||
|
surface_desc.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
|
||||||
|
surface_desc.pNext = NULL;
|
||||||
|
surface_desc.flags = 0;
|
||||||
|
surface_desc.pLayer = l;
|
||||||
|
if (vkCreateMetalSurfaceEXT(vk_instance, &surface_desc, NULL, &vk_surface) < 0)
|
||||||
|
return VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
return vk_surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void demo_window_macos_destroy(struct demo_window *window)
|
||||||
|
{
|
||||||
|
struct demo_window_macos *window_macos = CONTAINING_RECORD(window, struct demo_window_macos, w);
|
||||||
|
|
||||||
|
NSWindow_close(window_macos->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void demo_window_macos_destroyed(struct demo_window_macos *window_macos)
|
||||||
|
{
|
||||||
|
CAMetalLayer_release(window_macos->layer);
|
||||||
|
NSWindow_release(window_macos->window);
|
||||||
|
demo_window_cleanup(&window_macos->w);
|
||||||
|
free(window_macos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct demo_window *demo_window_macos_create(struct demo *demo,
|
||||||
|
const char *title, unsigned int width, unsigned int height, void *user_data)
|
||||||
|
{
|
||||||
|
unsigned long style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
|
||||||
|
struct demo_window_macos *window_macos;
|
||||||
|
NSRect r = {0, 0, width, height};
|
||||||
|
double scale;
|
||||||
|
id w, s;
|
||||||
|
|
||||||
|
if (!(window_macos = malloc(sizeof(*window_macos))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!demo_window_init(&window_macos->w, demo, user_data,
|
||||||
|
demo_window_macos_create_vk_surface, demo_window_macos_destroy))
|
||||||
|
{
|
||||||
|
free(window_macos);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = NSScreen_mainScreen();
|
||||||
|
scale = NSScreen_backingScaleFactor(s);
|
||||||
|
r.w /= scale;
|
||||||
|
r.h /= scale;
|
||||||
|
|
||||||
|
w = window_macos->window = class_createInstance(objc_getClass("DemoWindow"), 0);
|
||||||
|
NSWindow_initWithContentRect(w, r, style, NSBackingStoreBuffered, true, s);
|
||||||
|
NSWindow_setReleasedWhenClosed(w, false);
|
||||||
|
NSWindow_setDelegate(w, w);
|
||||||
|
NSWindow_center(w);
|
||||||
|
NSWindow_setTitle(w, NSString_stringWithUTF8String(title));
|
||||||
|
|
||||||
|
NSWindow_makeKeyAndOrderFront(w, nil);
|
||||||
|
window_macos->layer = nil;
|
||||||
|
|
||||||
|
return &window_macos->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void demo_macos_get_dpi(struct demo *demo, double *dpi_x, double *dpi_y)
|
||||||
|
{
|
||||||
|
*dpi_x = *dpi_y = 96.0 * NSScreen_backingScaleFactor(NSScreen_mainScreen());
|
||||||
|
}
|
||||||
|
|
||||||
|
static demo_key demo_key_from_nsevent(id event)
|
||||||
|
{
|
||||||
|
enum vkey
|
||||||
|
{
|
||||||
|
kVK_ANSI_A = 0x00,
|
||||||
|
kVK_Escape = 0x35,
|
||||||
|
kVK_LeftArrow = 0x7b,
|
||||||
|
kVK_RightArrow = 0x7c,
|
||||||
|
kVK_DownArrow = 0x7d,
|
||||||
|
kVK_UpArrow = 0x7e,
|
||||||
|
} vkey;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
enum vkey vkey;
|
||||||
|
demo_key demo_key;
|
||||||
|
}
|
||||||
|
lookup[] =
|
||||||
|
{
|
||||||
|
{kVK_ANSI_A, 'a'},
|
||||||
|
{kVK_Escape, DEMO_KEY_ESCAPE},
|
||||||
|
{kVK_LeftArrow, DEMO_KEY_LEFT},
|
||||||
|
{kVK_RightArrow, DEMO_KEY_RIGHT},
|
||||||
|
{kVK_UpArrow, DEMO_KEY_UP},
|
||||||
|
{kVK_DownArrow, DEMO_KEY_DOWN},
|
||||||
|
};
|
||||||
|
|
||||||
|
vkey = NSEvent_keyCode(event);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(lookup); ++i)
|
||||||
|
{
|
||||||
|
if (lookup[i].vkey == vkey)
|
||||||
|
return lookup[i].demo_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEMO_KEY_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void demo_macos_process_events(struct demo *demo)
|
||||||
|
{
|
||||||
|
struct demo_window_macos *window_macos;
|
||||||
|
struct demo_window *window;
|
||||||
|
id a, event;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < demo->window_count; ++i)
|
||||||
|
{
|
||||||
|
if ((window = demo->windows[i])->expose_func)
|
||||||
|
window->expose_func(window, window->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
a = NSApplication_sharedApplication();
|
||||||
|
while (demo->window_count)
|
||||||
|
{
|
||||||
|
if (!demo->idle_func)
|
||||||
|
{
|
||||||
|
if (!(event = NSApplication_nextEventMatchingMask(a, ~(uint64_t)0,
|
||||||
|
NSDate_distantFuture(), NSDefaultRunLoopMode, true)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (!(event = NSApplication_nextEventMatchingMask(a, ~(uint64_t)0, nil, NSDefaultRunLoopMode, true)))
|
||||||
|
{
|
||||||
|
demo->idle_func(demo, demo->user_data);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (NSEvent_type(event))
|
||||||
|
{
|
||||||
|
case NSEventTypeKeyDown:
|
||||||
|
if (NSMenu_performKeyEquivalent(NSApplication_mainMenu(a), event))
|
||||||
|
continue;
|
||||||
|
if (!(window_macos = demo_macos_find_macos_window(demo, NSEvent_window(event)))
|
||||||
|
|| !window_macos->w.key_press_func)
|
||||||
|
break;
|
||||||
|
window_macos->w.key_press_func(&window_macos->w,
|
||||||
|
demo_key_from_nsevent(event), window_macos->w.user_data);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case NSEventTypeApplicationDefined:
|
||||||
|
if (NSEvent_subtype(event) != DemoWindowDestroyed
|
||||||
|
|| !(window_macos = demo_macos_find_macos_window(demo, NSEvent_window(event))))
|
||||||
|
break;
|
||||||
|
demo_window_macos_destroyed(window_macos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSApplication_sendEvent(a, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DemoWindow_windowWillClose(id window, SEL sel, id notification)
|
||||||
|
{
|
||||||
|
id event;
|
||||||
|
|
||||||
|
event = NSEvent_otherEventWithType(NSEventTypeApplicationDefined, (NSPoint){0.0, 0.0},
|
||||||
|
0, 0.0, NSWindow_windowNumber(window), nil, DemoWindowDestroyed, 0, 0);
|
||||||
|
NSApplication_postEvent(NSApplication_sharedApplication(), event, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void demo_macos_cleanup(struct demo *demo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool demo_macos_init(struct demo_macos *macos)
|
||||||
|
{
|
||||||
|
id application, item, menu, submenu;
|
||||||
|
Class c;
|
||||||
|
|
||||||
|
if ((c = objc_allocateClassPair(objc_getClass("NSWindow"), "DemoWindow", 0)))
|
||||||
|
{
|
||||||
|
class_addMethod(c, sel_registerName("windowWillClose:"), (IMP)DemoWindow_windowWillClose, "v@:@");
|
||||||
|
objc_registerClassPair(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
application = NSApplication_sharedApplication();
|
||||||
|
NSApplication_setActivationPolicy(application, 0);
|
||||||
|
|
||||||
|
menu = NSMenu_new();
|
||||||
|
|
||||||
|
submenu = NSMenu_new();
|
||||||
|
NSMenu_addItemWithTitle(submenu, NSString_stringWithUTF8String("Quit"),
|
||||||
|
sel_registerName("terminate:"), NSString_stringWithUTF8String("q"));
|
||||||
|
|
||||||
|
item = NSMenuItem_new();
|
||||||
|
NSMenuItem_setSubmenu(item, submenu);
|
||||||
|
NSMenu_release(submenu);
|
||||||
|
NSMenu_addItem(menu, item);
|
||||||
|
NSMenuItem_release(item);
|
||||||
|
|
||||||
|
NSApplication_setMainMenu(application, menu);
|
||||||
|
NSMenu_release(menu);
|
||||||
|
|
||||||
|
NSApplication_finishLaunching(application);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#define VK_NO_PROTOTYPES
|
#define VK_NO_PROTOTYPES
|
||||||
|
#ifdef __APPLE__
|
||||||
|
# define VK_USE_PLATFORM_METAL_EXT
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define VK_USE_PLATFORM_WIN32_KHR
|
# define VK_USE_PLATFORM_WIN32_KHR
|
||||||
#endif
|
#endif
|
||||||
@ -44,6 +47,9 @@
|
|||||||
DECLARE_VK_PFN(vkAcquireNextImageKHR)
|
DECLARE_VK_PFN(vkAcquireNextImageKHR)
|
||||||
DECLARE_VK_PFN(vkCreateFence)
|
DECLARE_VK_PFN(vkCreateFence)
|
||||||
DECLARE_VK_PFN(vkCreateSwapchainKHR)
|
DECLARE_VK_PFN(vkCreateSwapchainKHR)
|
||||||
|
#ifdef __APPLE__
|
||||||
|
DECLARE_VK_PFN(vkCreateMetalSurfaceEXT)
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DECLARE_VK_PFN(vkCreateWin32SurfaceKHR)
|
DECLARE_VK_PFN(vkCreateWin32SurfaceKHR)
|
||||||
#endif
|
#endif
|
||||||
@ -61,6 +67,12 @@ DECLARE_VK_PFN(vkQueuePresentKHR)
|
|||||||
DECLARE_VK_PFN(vkResetFences)
|
DECLARE_VK_PFN(vkResetFences)
|
||||||
DECLARE_VK_PFN(vkWaitForFences)
|
DECLARE_VK_PFN(vkWaitForFences)
|
||||||
|
|
||||||
|
struct demo_macos
|
||||||
|
{
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
struct demo_win32
|
struct demo_win32
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -83,6 +95,7 @@ struct demo
|
|||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
struct demo_macos macos;
|
||||||
struct demo_win32 win32;
|
struct demo_win32 win32;
|
||||||
struct demo_xcb xcb;
|
struct demo_xcb xcb;
|
||||||
} u;
|
} u;
|
||||||
@ -167,6 +180,9 @@ static inline void demo_window_cleanup(struct demo_window *window)
|
|||||||
demo_remove_window(window->demo, window);
|
demo_remove_window(window->demo, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
# include "demo_macos.h"
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include "demo_win32.h"
|
# include "demo_win32.h"
|
||||||
#endif
|
#endif
|
||||||
@ -200,6 +216,9 @@ static void load_vulkan_procs(void)
|
|||||||
LOAD_VK_PFN(vkAcquireNextImageKHR)
|
LOAD_VK_PFN(vkAcquireNextImageKHR)
|
||||||
LOAD_VK_PFN(vkCreateFence)
|
LOAD_VK_PFN(vkCreateFence)
|
||||||
LOAD_VK_PFN(vkCreateSwapchainKHR)
|
LOAD_VK_PFN(vkCreateSwapchainKHR)
|
||||||
|
#ifdef __APPLE__
|
||||||
|
LOAD_VK_PFN(vkCreateMetalSurfaceEXT)
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
LOAD_VK_PFN(vkCreateWin32SurfaceKHR)
|
LOAD_VK_PFN(vkCreateWin32SurfaceKHR)
|
||||||
#endif
|
#endif
|
||||||
@ -244,6 +263,15 @@ static inline void demo_cleanup(struct demo *demo)
|
|||||||
|
|
||||||
static inline bool demo_init(struct demo *demo, void *user_data)
|
static inline bool demo_init(struct demo *demo, void *user_data)
|
||||||
{
|
{
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (demo_macos_init(&demo->u.macos))
|
||||||
|
{
|
||||||
|
demo->create_window = demo_window_macos_create;
|
||||||
|
demo->get_dpi = demo_macos_get_dpi;
|
||||||
|
demo->process_events = demo_macos_process_events;
|
||||||
|
demo->cleanup = demo_macos_cleanup;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (demo_win32_init(&demo->u.win32))
|
if (demo_win32_init(&demo->u.win32))
|
||||||
{
|
{
|
||||||
|
143
demos/make_objc
Executable file
143
demos/make_objc
Executable file
@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
#
|
||||||
|
# Copyright 2025 Henri Verbeet
|
||||||
|
#
|
||||||
|
# This library is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This library is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use JSON;
|
||||||
|
use open ':utf8';
|
||||||
|
binmode STDOUT, ':utf8';
|
||||||
|
|
||||||
|
sub method_name($)
|
||||||
|
{
|
||||||
|
shift->{selector} =~ s/(:.*)//r;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub method_parameters($$)
|
||||||
|
{
|
||||||
|
my ($method, $method_type) = @_;
|
||||||
|
|
||||||
|
my $parameters = join ", ", $method_type eq "class" ? () : "id self",
|
||||||
|
map {"$_->{type} $_->{name}"} @{$method->{parameters}};
|
||||||
|
|
||||||
|
length $parameters ? $parameters : "void";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub send_function($)
|
||||||
|
{
|
||||||
|
shift->{'return-float'} ? "objc_msgSend_fpret" : "objc_msgSend";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub invocation_type($$)
|
||||||
|
{
|
||||||
|
my ($method, $method_type) = @_;
|
||||||
|
|
||||||
|
"$method->{'return-type'} (*)(" . join(", ", $method_type eq "class" ? "Class" : "id", "SEL",
|
||||||
|
map {$_->{type}} @{$method->{parameters}}) . ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub invocation_parameters($$$)
|
||||||
|
{
|
||||||
|
my ($method, $interface_name, $method_type) = @_;
|
||||||
|
|
||||||
|
join ", ", $method_type eq "class" ? "objc_getClass(\"$interface_name\")" : "self",
|
||||||
|
"sel_registerName(\"$method->{selector}\")", map {$_->{name}} @{$method->{parameters}};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub invocation($$$)
|
||||||
|
{
|
||||||
|
my ($method, $interface_name, $method_type) = @_;
|
||||||
|
|
||||||
|
($method->{'return-type'} eq "void" ? "" : "return ")
|
||||||
|
. "((${\invocation_type $method, $method_type})f)"
|
||||||
|
. "(${\invocation_parameters $method, $interface_name, $method_type});";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_method($$$)
|
||||||
|
{
|
||||||
|
my ($method, $interface_name, $method_type) = @_;
|
||||||
|
|
||||||
|
print "static inline $method->{'return-type'} "
|
||||||
|
. "${interface_name}_${\method_name $method}(${\method_parameters $method, $method_type})\n";
|
||||||
|
print "{\n";
|
||||||
|
print " void *f = ${\send_function $method};\n";
|
||||||
|
print " ${\invocation $method, $interface_name, $method_type}\n";
|
||||||
|
print "}\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_property($$)
|
||||||
|
{
|
||||||
|
my ($property, $interface_name) = @_;
|
||||||
|
|
||||||
|
my $method =
|
||||||
|
{
|
||||||
|
'return-type' => $property->{type},
|
||||||
|
'return-float' => $property->{float},
|
||||||
|
selector => $property->{getter} // $property->{name},
|
||||||
|
};
|
||||||
|
my $method_type = $property->{class} ? "class" : "instance";
|
||||||
|
|
||||||
|
print_method $method, $interface_name, $method_type;
|
||||||
|
if (!$property->{readonly})
|
||||||
|
{
|
||||||
|
$method->{'return-type'} = "void";
|
||||||
|
$method->{'return-float'} = 0;
|
||||||
|
$method->{selector} = "set${\ucfirst $property->{name}}:";
|
||||||
|
$method->{parameters} = [$property];
|
||||||
|
print_method $method, $interface_name, $method_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_interface(_)
|
||||||
|
{
|
||||||
|
my ($interface) = @_;
|
||||||
|
|
||||||
|
print_method $_, $interface->{name}, "class" foreach (@{$interface->{'class-methods'}});
|
||||||
|
print_method $_, $interface->{name}, "instance" foreach (@{$interface->{'instance-methods'}});
|
||||||
|
print_property $_, $interface->{name} foreach (@{$interface->{properties}});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_header($)
|
||||||
|
{
|
||||||
|
my ($grammar) = @_;
|
||||||
|
|
||||||
|
my $guard = "__VKD3D_${\uc $grammar->{name}}_H__";
|
||||||
|
|
||||||
|
print "/*\n";
|
||||||
|
print " * This file is automatically generated.\n";
|
||||||
|
print " * The original source is covered by the following license:\n";
|
||||||
|
print " *\n";
|
||||||
|
print map {" * $_" =~ s/ +$//r . "\n"} @{$grammar->{copyright}};
|
||||||
|
print " */\n\n";
|
||||||
|
|
||||||
|
print "#ifndef $guard\n";
|
||||||
|
print "#define $guard\n\n";
|
||||||
|
|
||||||
|
print "#include <objc/objc-runtime.h>\n\n";
|
||||||
|
|
||||||
|
print_interface foreach (@{$grammar->{interfaces}});
|
||||||
|
|
||||||
|
print "#endif /* $guard */\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
die "No input file specified.\n" unless @ARGV;
|
||||||
|
print_header do
|
||||||
|
{
|
||||||
|
local $/;
|
||||||
|
open my $fh, '<', $ARGV[0] or die $!;
|
||||||
|
decode_json <$fh>;
|
||||||
|
};
|
205
include/private/appkit.json
Normal file
205
include/private/appkit.json
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
{
|
||||||
|
"copyright" : [
|
||||||
|
"Copyright 2025 Henri Verbeet",
|
||||||
|
"",
|
||||||
|
"This library is free software; you can redistribute it and/or",
|
||||||
|
"modify it under the terms of the GNU Lesser General Public",
|
||||||
|
"License as published by the Free Software Foundation; either",
|
||||||
|
"version 2.1 of the License, or (at your option) any later version.",
|
||||||
|
"",
|
||||||
|
"This library is distributed in the hope that it will be useful,",
|
||||||
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of",
|
||||||
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU",
|
||||||
|
"Lesser General Public License for more details.",
|
||||||
|
"",
|
||||||
|
"You should have received a copy of the GNU Lesser General Public",
|
||||||
|
"License along with this library; if not, write to the Free Software",
|
||||||
|
"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA"
|
||||||
|
],
|
||||||
|
"name" : "AppKit",
|
||||||
|
"interfaces" : [
|
||||||
|
{
|
||||||
|
"name" : "NSApplication",
|
||||||
|
"instance-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "finishLaunching",
|
||||||
|
"return-type" : "void"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "nextEventMatchingMask:untilDate:inMode:dequeue:",
|
||||||
|
"return-type" : "id",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "uint64_t", "name" : "mask"},
|
||||||
|
{"type" : "id", "name" : "expiration"},
|
||||||
|
{"type" : "id", "name" : "mode"},
|
||||||
|
{"type" : "BOOL", "name" : "dequeue"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "postEvent:atStart:",
|
||||||
|
"return-type" : "void",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "id", "name" : "event"},
|
||||||
|
{"type" : "BOOL", "name" : "at_start"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "sendEvent:",
|
||||||
|
"return-type" : "void",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "id", "name" : "event"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "setActivationPolicy:",
|
||||||
|
"return-type" : "BOOL",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "long", "name" : "policy"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "id", "name" : "mainMenu"},
|
||||||
|
{"type" : "id", "name" : "sharedApplication", "readonly" : true, "class" : true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NSEvent",
|
||||||
|
"class-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:",
|
||||||
|
"return-type" : "id",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "unsigned long", "name" : "type"},
|
||||||
|
{"type" : "NSPoint", "name" : "location"},
|
||||||
|
{"type" : "NSUInteger", "name" : "flags"},
|
||||||
|
{"type" : "double", "name" : "time"},
|
||||||
|
{"type" : "NSInteger", "name" : "window"},
|
||||||
|
{"type" : "id", "name" : "context"},
|
||||||
|
{"type" : "short", "name" : "subtype"},
|
||||||
|
{"type" : "NSInteger", "name" : "d1"},
|
||||||
|
{"type" : "NSInteger", "name" : "d2"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "unsigned short", "name" : "keyCode", "readonly" : true},
|
||||||
|
{"type" : "short", "name" : "subtype", "readonly" : true},
|
||||||
|
{"type" : "NSUInteger", "name" : "type", "readonly" : true},
|
||||||
|
{"type" : "id", "name" : "window", "readonly" : true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NSMenu",
|
||||||
|
"class-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "new",
|
||||||
|
"return-type" : "id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"instance-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "addItem:",
|
||||||
|
"return-type" : "void",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "id", "name" : "item"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "addItemWithTitle:action:keyEquivalent:",
|
||||||
|
"return-type" : "id",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "id", "name" : "title"},
|
||||||
|
{"type" : "SEL", "name" : "selector"},
|
||||||
|
{"type" : "id", "name" : "key"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "performKeyEquivalent:",
|
||||||
|
"return-type" : "BOOL",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "id", "name" : "event"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "release",
|
||||||
|
"return-type" : "void"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NSMenuItem",
|
||||||
|
"class-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "new",
|
||||||
|
"return-type" : "id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"instance-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "release",
|
||||||
|
"return-type" : "void"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "id", "name" : "submenu"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NSScreen",
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "double", "name" : "backingScaleFactor", "readonly" : true, "float" : true},
|
||||||
|
{"type" : "id", "name" : "mainScreen", "readonly" : true, "class" : true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NSView",
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "id", "name" : "layer"},
|
||||||
|
{"type" : "BOOL", "name" : "wantsLayer"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NSWindow",
|
||||||
|
"instance-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "center",
|
||||||
|
"return-type" : "void"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "close",
|
||||||
|
"return-type" : "void"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "initWithContentRect:styleMask:backing:defer:screen:",
|
||||||
|
"return-type" : "id",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "NSRect", "name" : "rect"},
|
||||||
|
{"type" : "NSUInteger", "name" : "style"},
|
||||||
|
{"type" : "NSUInteger", "name" : "backing_store_type"},
|
||||||
|
{"type" : "BOOL", "name" : "defer"},
|
||||||
|
{"type" : "id", "name" : "screen"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "makeKeyAndOrderFront:",
|
||||||
|
"return-type" : "void",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "id", "name" : "sender"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"selector" : "release",
|
||||||
|
"return-type" : "void"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "id", "name" : "contentView"},
|
||||||
|
{"type" : "id", "name" : "delegate"},
|
||||||
|
{"type" : "BOOL", "name" : "releasedWhenClosed", "getter" : "isReleasedWhenClosed"},
|
||||||
|
{"type" : "id", "name" : "title"},
|
||||||
|
{"type" : "NSInteger", "name" : "windowNumber", "readonly" : true}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
40
include/private/foundation.json
Normal file
40
include/private/foundation.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"copyright" : [
|
||||||
|
"Copyright 2025 Henri Verbeet",
|
||||||
|
"",
|
||||||
|
"This library is free software; you can redistribute it and/or",
|
||||||
|
"modify it under the terms of the GNU Lesser General Public",
|
||||||
|
"License as published by the Free Software Foundation; either",
|
||||||
|
"version 2.1 of the License, or (at your option) any later version.",
|
||||||
|
"",
|
||||||
|
"This library is distributed in the hope that it will be useful,",
|
||||||
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of",
|
||||||
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU",
|
||||||
|
"Lesser General Public License for more details.",
|
||||||
|
"",
|
||||||
|
"You should have received a copy of the GNU Lesser General Public",
|
||||||
|
"License along with this library; if not, write to the Free Software",
|
||||||
|
"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA"
|
||||||
|
],
|
||||||
|
"name" : "Foundation",
|
||||||
|
"interfaces" : [
|
||||||
|
{
|
||||||
|
"name" : "NSDate",
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "id", "name" : "distantFuture", "readonly" : true, "class" : true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NSString",
|
||||||
|
"class-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "stringWithUTF8String:",
|
||||||
|
"return-type" : "id",
|
||||||
|
"parameters" : [
|
||||||
|
{"type" : "const char *", "name" : "s"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
40
include/private/quartzcore.json
Normal file
40
include/private/quartzcore.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"copyright" : [
|
||||||
|
"Copyright 2025 Henri Verbeet",
|
||||||
|
"",
|
||||||
|
"This library is free software; you can redistribute it and/or",
|
||||||
|
"modify it under the terms of the GNU Lesser General Public",
|
||||||
|
"License as published by the Free Software Foundation; either",
|
||||||
|
"version 2.1 of the License, or (at your option) any later version.",
|
||||||
|
"",
|
||||||
|
"This library is distributed in the hope that it will be useful,",
|
||||||
|
"but WITHOUT ANY WARRANTY; without even the implied warranty of",
|
||||||
|
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU",
|
||||||
|
"Lesser General Public License for more details.",
|
||||||
|
"",
|
||||||
|
"You should have received a copy of the GNU Lesser General Public",
|
||||||
|
"License along with this library; if not, write to the Free Software",
|
||||||
|
"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA"
|
||||||
|
],
|
||||||
|
"name" : "QuartzCore",
|
||||||
|
"interfaces" : [
|
||||||
|
{
|
||||||
|
"name" : "CAMetalLayer",
|
||||||
|
"class-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "layer",
|
||||||
|
"return-type" : "id"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"instance-methods" : [
|
||||||
|
{
|
||||||
|
"selector" : "release",
|
||||||
|
"return-type" : "void"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties" : [
|
||||||
|
{"type" : "double", "name" : "contentsScale", "float" : true}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user