提交 d7a04aea 编写于 作者: P Palana

added osx cocoa support files

上级 595dad2e
/******************************************************************************
Copyright (C) 2013 by Ruwen Hahn <palana@stunned.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <GL/glew.h>
#include "gl-subsystem.h"
#include <OpenGL/OpenGL.h>
#import <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
//#include "util/darray.h"
struct gl_windowinfo {
NSView *view;
};
struct gl_platform {
NSOpenGLContext *context;
GLuint vao;
struct gs_swap_chain swap;
};
static NSOpenGLContext *gl_context_create(struct gs_init_data *info)
{
unsigned attrib_count = 0;
#define ADD_ATTR(x) { attributes[attrib_count++] = (NSOpenGLPixelFormatAttribute)x; }
#define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); }
NSOpenGLPixelFormatAttribute attributes[40];
switch(info->num_backbuffers) {
case 0:
break;
case 1:
ADD_ATTR(NSOpenGLPFADoubleBuffer);
break;
case 2:
ADD_ATTR(NSOpenGLPFATripleBuffer);
break;
default:
blog(LOG_ERROR, "Requested backbuffers (%d) not supported", info->num_backbuffers);
}
ADD_ATTR(NSOpenGLPFAClosestPolicy);
ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
int color_bits = 0;//get_color_format_bits(info->format);
if(color_bits == 0) color_bits = 24;
else if(color_bits < 15) color_bits = 15;
ADD_ATTR2(NSOpenGLPFAColorSize, color_bits);
ADD_ATTR2(NSOpenGLPFAAlphaSize, 8);
ADD_ATTR2(NSOpenGLPFADepthSize, 16);
ADD_ATTR(0);
#undef ADD_ATTR2
#undef ADD_ATTR
NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];;
if(!pf) {
blog(LOG_ERROR, "Failed to create pixel format");
return NULL;
}
NSOpenGLContext *context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
[pf release];
if(!context) {
blog(LOG_ERROR, "Failed to create context");
return NULL;
}
[context setView:info->view];
return context;
}
static inline void required_extension_error(const char *extension)
{
blog(LOG_ERROR, "OpenGL extension %s is required", extension);
}
static bool gl_init_extensions(device_t device)
{
glewExperimental=true;
GLenum error = glewInit();
if(error != GLEW_OK) {
blog(LOG_ERROR, "glewInit failed, %u\n%s\n", error, glewGetErrorString(error));
return false;
}
if(!GLEW_VERSION_2_1) {
blog(LOG_ERROR, "OpenGL 2.1 minimum required by the graphics "
"adapter");
return false;
}
if(!GLEW_ARB_framebuffer_object) {
required_extension_error("GL_ARB_framebuffer_object");
return false;
}
if(!GLEW_ARB_separate_shader_objects) {
required_extension_error("GL_ARB_separate_shader_objects");
return false;
}
glGetError(); //something inside glew produces error code 1280 (invalid enum)
device->copy_type = COPY_TYPE_FBO_BLIT;
return true;
}
static bool gl_init_default_swap(struct gl_platform *plat, device_t dev,
struct gs_init_data *info)
{
if(!(plat->context = gl_context_create(info)))
return false;
plat->swap.device = dev;
plat->swap.info = *info;
plat->swap.wi = gl_windowinfo_create(info);
return plat->swap.wi != NULL;
}
struct gl_platform *gl_platform_create(device_t device,
struct gs_init_data *info)
{
struct gl_platform *plat = bmalloc(sizeof(struct gl_platform));
memset(plat, 0, sizeof(struct gl_platform));
if(!gl_init_default_swap(plat, device, info))
goto fail;
[plat->context makeCurrentContext];
if(!gl_init_extensions(device))
goto fail;
gl_gen_vertex_arrays(1, &plat->vao);
gl_bind_vertex_array(plat->vao);
if (GLEW_ARB_seamless_cube_map) {
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
gl_success("GL_TEXTURE_CUBE_MAP_SEAMLESS");
}
return plat;
fail:
blog(LOG_ERROR, "gl_platform_create failed");
gl_platform_destroy(plat);
return NULL;
}
struct gs_swap_chain *gl_platform_getswap(struct gl_platform *platform)
{
if(platform)
return &platform->swap;
return NULL;
}
void gl_platform_destroy(struct gl_platform *platform)
{
if(!platform)
return;
gl_delete_vertex_arrays(1, &platform->vao);
[platform->context release];
platform->context = nil;
gl_windowinfo_destroy(platform->swap.wi);
bfree(platform);
}
struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info)
{
if(!info)
return NULL;
if(!info->view)
return NULL;
struct gl_windowinfo *wi = bmalloc(sizeof(struct gl_windowinfo));
memset(wi, 0, sizeof(struct gl_windowinfo));
wi->view = info->view;
return wi;
}
void gl_windowinfo_destroy(struct gl_windowinfo *wi)
{
if(!wi)
return;
wi->view = nil;
bfree(wi);
}
void device_entercontext(device_t device)
{
[device->plat->context makeCurrentContext];
//gl_bind_vertex_array(device->plat->vao);
}
void device_leavecontext(device_t device)
{
[NSOpenGLContext clearCurrentContext];
}
void device_load_swapchain(device_t device, swapchain_t swap)
{
if(!swap)
swap = &device->plat->swap;
if(device->cur_swap == swap)
return;
device->cur_swap = swap;
}
void device_present(device_t device)
{
[device->plat->context flushBuffer];
}
void gl_getclientsize(struct gs_swap_chain *swap, uint32_t *width, uint32_t *height)
{
if(width) *width = swap->info.cx;
if(height) *height = swap->info.cy;
}
......@@ -19,6 +19,9 @@
#include "../util/bmem.h"
#include "input.h"
#ifdef __APPLE__
#include <objc/objc-runtime.h>
#endif
/*
* This is an API-independent graphics subsystem wrapper.
......@@ -410,7 +413,7 @@ struct gs_init_data {
#if defined(_WIN32)
void *hwnd;
#elif defined(__APPLE__)
/* TODO */
__unsafe_unretained id view;
#elif defined(__posix__)
/* TODO */
#endif
......
/******************************************************************************
Copyright (C) 2013 by Ruwen Hahn <palana@stunned.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "util/platform.h"
#include "util/dstr.h"
#include "obs.h"
#include "obs-data.h"
#include <unistd.h>
// support both foo.so and libfoo.so for now
static const char *plugin_patterns[] = {
"../plugins/%s.so",
"../plugins/lib%s.so"
};
static const int plugin_patterns_size = sizeof(plugin_patterns)/sizeof(plugin_patterns[0]);
char *find_plugin(const char *plugin)
{
struct dstr path;
dstr_init(&path);
for(int i = 0; i < plugin_patterns_size; i++) {
dstr_printf(&path, plugin_patterns[i], plugin);
if(!access(path.array, F_OK))
break;
}
return path.array;
}
/* on windows, points to [base directory]/libobs */
char *find_libobs_data_file(const char *file)
{
struct dstr path;
dstr_init_copy(&path, "../libobs/");
dstr_cat(&path, file);
return path.array;
}
/* on windows, data files should always be in [base directory]/data */
char *obs_find_plugin_file(const char *file)
{
struct dstr path;
dstr_init_copy(&path, "../data/");
dstr_cat(&path, file);
return path.array;
}
/******************************************************************************
Copyright (c) 2013 by Ruwen Hahn <palana@stunned.de>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
******************************************************************************/
#include "base.h"
#include "platform.h"
#include "dstr.h"
#include <dlfcn.h>
#include <time.h>
#include <unistd.h>
#include <CoreServices/CoreServices.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
void *os_dlopen(const char *path)
{
struct dstr dylib_name;
dstr_init_copy(&dylib_name, path);
if(!dstr_find(&dylib_name, ".so"))
dstr_cat(&dylib_name, ".so");
void *res = dlopen(dylib_name.array, RTLD_LAZY);
if(!res)
blog(LOG_ERROR, "os_dlopen(%s->%s): %s\n",
path, dylib_name.array, dlerror());
dstr_free(&dylib_name);
return res;
}
void *os_dlsym(void *module, const char *func)
{
return dlsym(module, func);
}
void os_dlclose(void *module)
{
dlclose(module);
}
void os_sleepto_ns(uint64_t time_target)
{
uint64_t current = os_gettime_ns();
if(time_target < current)
return;
time_target -= current;
struct timespec req,
remain;
memset(&req, 0, sizeof(req));
memset(&remain, 0, sizeof(remain));
req.tv_sec = time_target/1000000000;
req.tv_nsec = time_target%1000000000;
while(nanosleep(&req, &remain))
{
req = remain;
memset(&remain, 0, sizeof(remain));
}
}
void os_sleep_ms(uint32_t duration)
{
usleep(duration*1000);
}
uint64_t os_gettime_ns(void)
{
uint64_t t = mach_absolute_time();
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
Nanoseconds nano = AbsoluteToNanoseconds(*(AbsoluteTime*) &t);
#pragma clang diagnostic pop
return *(uint64_t*) &nano;
}
uint64_t os_gettime_ms(void)
{
return os_gettime_ns()/1000000;
}
#include <stdio.h>
#include <time.h>
#include <functional>
#include <memory>
#import <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
#import <OpenGL/OpenGL.h>
#include "util/base.h"
#include "obs.h"
static const int cx = 800;
static const int cy = 600;
/* --------------------------------------------------- */
using SourceContext = std::unique_ptr<obs_source,
std::function<void(obs_source_t)>>;
static SourceContext autorelease(obs_source_t s)
{
return SourceContext(s, obs_source_destroy);
}
using SceneContext = std::unique_ptr<obs_scene,
std::function<void(obs_scene_t)>>;
static SceneContext autorelease(obs_scene_t s)
{
return SceneContext(s, obs_scene_destroy);
}
/* --------------------------------------------------- */
static void CreateOBS(NSWindow *win)
{
struct video_info vi;
memset(&vi, 0, sizeof(struct video_info));
vi.fps_num = 30000;
vi.fps_den = 1001;
vi.width = cx;
vi.height = cy;
vi.name = "video";
struct gs_init_data gsid;
memset(&gsid, 0, sizeof(gsid));
gsid.view = [win contentView];
gsid.cx = cx;
gsid.cy = cy;
gsid.num_backbuffers = 2;
gsid.format = GS_RGBA;
if (!obs_startup("libobs-opengl", &gsid, &vi, NULL))
throw "Couldn't create OBS";
}
static void AddTestItems(obs_scene_t scene, obs_source_t source)
{
obs_sceneitem_t item = NULL;
struct vec2 v2;
item = obs_scene_add(scene, source);
vec2_set(&v2, 100.0f, 200.0f);
obs_sceneitem_setpos(item, &v2);
obs_sceneitem_setrot(item, 10.0f);
vec2_set(&v2, 20.0f, 2.0f);
obs_sceneitem_setscale(item, &v2);
item = obs_scene_add(scene, source);
vec2_set(&v2, 200.0f, 100.0f);
obs_sceneitem_setpos(item, &v2);
obs_sceneitem_setrot(item, -45.0f);
vec2_set(&v2, 5.0f, 7.0f);
obs_sceneitem_setscale(item, &v2);
}
@interface window_closer : NSObject {}
@end
@implementation window_closer
+(id)window_closer
{
return [[window_closer alloc] init];
}
-(void)windowWillClose:(NSNotification *)notification
{
[NSApp stop:self];
}
@end
static NSWindow *CreateTestWindow()
{
[NSApplication sharedApplication];
ProcessSerialNumber psn = {0, kCurrentProcess};
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
SetFrontProcess(&psn);
#pragma clang diagnostic pop
NSRect content_rect = NSMakeRect(0, 0, cx, cy);
NSWindow *win = [[NSWindow alloc]
initWithContentRect:content_rect
styleMask:NSTitledWindowMask | NSClosableWindowMask
backing:NSBackingStoreBuffered
defer:NO];
if(!win)
return nil;
[win orderFrontRegardless];
NSView *view = [[NSView alloc] initWithFrame:content_rect];
if(!view)
return nil;
[win setContentView:view];
[win setTitle:@"foo"];
[win center];
[win makeMainWindow];
[win setDelegate:[window_closer window_closer]];
return win;
}
static void test()
{
try {
NSWindow *win = CreateTestWindow();
if (!win)
throw "Couldn't create main window";
CreateOBS(win);
/* ------------------------------------------------------ */
/* load module */
if (obs_load_module("test-input") != 0)
throw "Couldn't load module";
/* ------------------------------------------------------ */
/* create source */
SourceContext source = autorelease(obs_source_create(SOURCE_INPUT,
"random", NULL));
if (!source)
throw "Couldn't create random test source";
/* ------------------------------------------------------ */
/* create filter */
SourceContext filter = autorelease(obs_source_create(SOURCE_FILTER,
"test", NULL));
if (!filter)
throw "Couldn't create test filter";
obs_source_filter_add(source.get(), filter.get());
/* ------------------------------------------------------ */
/* create scene and add source to scene (twice) */
SceneContext scene = autorelease(obs_scene_create());
if (!scene)
throw "Couldn't create scene";
AddTestItems(scene.get(), source.get());
/* ------------------------------------------------------ */
/* set the scene as the primary draw source and go */
obs_set_primary_source(obs_scene_getsource(scene.get()));
[NSApp run];
obs_set_primary_source(NULL);
} catch (char const *error) {
printf("%s\n", error);
}
obs_shutdown();
blog(LOG_INFO, "Number of memory leaks: %zu", bnum_allocs());
}
/* --------------------------------------------------- */
int main()
{
@autoreleasepool {
test();
}
return 0;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册