123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- #if defined(VIDEO_CGL)
- #include <ruby/video/cgl.cpp>
- #endif
- #if defined(VIDEO_DIRECT3D)
- #include <ruby/video/direct3d.cpp>
- #endif
- #if defined(VIDEO_DIRECTDRAW)
- #include <ruby/video/directdraw.cpp>
- #endif
- #if defined(VIDEO_GDI)
- #include <ruby/video/gdi.cpp>
- #endif
- #if defined(VIDEO_GLX)
- #include <ruby/video/glx.cpp>
- #endif
- #if defined(VIDEO_GLX2)
- #include <ruby/video/glx2.cpp>
- #endif
- #if defined(VIDEO_WGL)
- #include <ruby/video/wgl.cpp>
- #endif
- #if defined(VIDEO_XSHM)
- #include <ruby/video/xshm.cpp>
- #endif
- #if defined(VIDEO_XVIDEO)
- #include <ruby/video/xvideo.cpp>
- #endif
- namespace ruby {
- auto Video::setFullScreen(bool fullScreen) -> bool {
- if(instance->fullScreen == fullScreen) return true;
- if(!instance->hasFullScreen()) return false;
- if(!instance->setFullScreen(instance->fullScreen = fullScreen)) return false;
- return true;
- }
- auto Video::setMonitor(string monitor) -> bool {
- if(instance->monitor == monitor) return true;
- if(!instance->hasMonitor()) return false;
- if(!instance->setMonitor(instance->monitor = monitor)) return false;
- return true;
- }
- auto Video::setExclusive(bool exclusive) -> bool {
- if(instance->exclusive == exclusive) return true;
- if(!instance->hasExclusive()) return false;
- if(!instance->setExclusive(instance->exclusive = exclusive)) return false;
- return true;
- }
- auto Video::setContext(uintptr context) -> bool {
- if(instance->context == context) return true;
- if(!instance->hasContext()) return false;
- if(!instance->setContext(instance->context = context)) return false;
- return true;
- }
- auto Video::setBlocking(bool blocking) -> bool {
- if(instance->blocking == blocking) return true;
- if(!instance->hasBlocking()) return false;
- if(!instance->setBlocking(instance->blocking = blocking)) return false;
- return true;
- }
- auto Video::setFlush(bool flush) -> bool {
- if(instance->flush == flush) return true;
- if(!instance->hasFlush()) return false;
- if(!instance->setFlush(instance->flush = flush)) return false;
- return true;
- }
- auto Video::setFormat(string format) -> bool {
- if(instance->format == format) return true;
- if(!instance->hasFormat(format)) return false;
- if(!instance->setFormat(instance->format = format)) return false;
- return true;
- }
- auto Video::setShader(string shader) -> bool {
- if(instance->shader == shader) return true;
- if(!instance->hasShader()) return false;
- if(!instance->setShader(instance->shader = shader)) return false;
- return true;
- }
- //
- auto Video::focused() -> bool {
- return instance->focused();
- }
- auto Video::clear() -> void {
- return instance->clear();
- }
- auto Video::size() -> Size {
- Size result;
- instance->size(result.width, result.height);
- return result;
- }
- auto Video::acquire(uint width, uint height) -> Acquire {
- Acquire result;
- if(instance->acquire(result.data, result.pitch, width, height)) return result;
- return {};
- }
- auto Video::release() -> void {
- return instance->release();
- }
- auto Video::output(uint width, uint height) -> void {
- return instance->output(width, height);
- }
- auto Video::poll() -> void {
- return instance->poll();
- }
- //
- auto Video::onUpdate(const function<void (uint, uint)>& onUpdate) -> void {
- update = onUpdate;
- }
- auto Video::doUpdate(uint width, uint height) -> void {
- if(update) return update(width, height);
- }
- //
- auto Video::create(string driver) -> bool {
- self.instance.reset();
- if(!driver) driver = optimalDriver();
- #if defined(VIDEO_CGL)
- if(driver == "OpenGL 3.2") self.instance = new VideoCGL(*this);
- #endif
- #if defined(VIDEO_DIRECT3D)
- if(driver == "Direct3D 9.0") self.instance = new VideoDirect3D(*this);
- #endif
- #if defined(VIDEO_DIRECTDRAW)
- if(driver == "DirectDraw 7.0") self.instance = new VideoDirectDraw(*this);
- #endif
- #if defined(VIDEO_GDI)
- if(driver == "GDI") self.instance = new VideoGDI(*this);
- #endif
- #if defined(VIDEO_GLX)
- if(driver == "OpenGL 3.2") self.instance = new VideoGLX(*this);
- #endif
- #if defined(VIDEO_GLX2)
- if(driver == "OpenGL 2.0") self.instance = new VideoGLX2(*this);
- #endif
- #if defined(VIDEO_WGL)
- if(driver == "OpenGL 3.2") self.instance = new VideoWGL(*this);
- #endif
- #if defined(VIDEO_XSHM)
- if(driver == "XShm") self.instance = new VideoXShm(*this);
- #endif
- #if defined(VIDEO_XVIDEO)
- if(driver == "XVideo") self.instance = new VideoXVideo(*this);
- #endif
- if(!self.instance) self.instance = new VideoDriver(*this);
- return self.instance->create();
- }
- auto Video::hasDrivers() -> vector<string> {
- return {
- #if defined(VIDEO_WGL)
- "OpenGL 3.2",
- #endif
- #if defined(VIDEO_DIRECT3D)
- "Direct3D 9.0",
- #endif
- #if defined(VIDEO_DIRECTDRAW)
- "DirectDraw 7.0",
- #endif
- #if defined(VIDEO_GDI)
- "GDI",
- #endif
- #if defined(VIDEO_CGL)
- "OpenGL 3.2",
- #endif
- #if defined(VIDEO_GLX)
- "OpenGL 3.2",
- #endif
- #if defined(VIDEO_GLX2)
- "OpenGL 2.0",
- #endif
- #if defined(VIDEO_XVIDEO)
- "XVideo",
- #endif
- #if defined(VIDEO_XSHM)
- "XShm",
- #endif
- "None"};
- }
- auto Video::optimalDriver() -> string {
- #if defined(VIDEO_WGL)
- return "OpenGL 3.2";
- #elif defined(VIDEO_DIRECT3D)
- return "Direct3D 9.0";
- #elif defined(VIDEO_DIRECTDRAW)
- return "DirectDraw 7.0";
- #elif defined(VIDEO_GDI)
- return "GDI";
- #elif defined(VIDEO_CGL)
- return "OpenGL 3.2";
- #elif defined(VIDEO_GLX)
- return "OpenGL 3.2";
- #elif defined(VIDEO_GLX2)
- return "OpenGL 2.0";
- #elif defined(VIDEO_XVIDEO)
- return "XVideo";
- #elif defined(VIDEO_XSHM)
- return "XShm";
- #else
- return "None";
- #endif
- }
- auto Video::safestDriver() -> string {
- #if defined(VIDEO_DIRECT3D)
- return "Direct3D 9.0";
- #elif defined(VIDEO_WGL)
- return "OpenGL 3.2";
- #elif defined(VIDEO_DIRECTDRAW)
- return "DirectDraw 7.0";
- #elif defined(VIDEO_GDI)
- return "GDI";
- #elif defined(VIDEO_CGL)
- return "OpenGL 3.2";
- #elif defined(VIDEO_XSHM)
- return "XShm";
- #elif defined(VIDEO_XVIDEO)
- return "XVideo";
- #elif defined(VIDEO_GLX2)
- return "OpenGL 2.0";
- #elif defined(VIDEO_GLX)
- return "OpenGL 3.2";
- #else
- return "None";
- #endif
- }
- #if defined(DISPLAY_WINDOWS)
- static auto CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
- vector<Video::Monitor>& monitors = *(vector<Video::Monitor>*)dwData;
- MONITORINFOEX mi{};
- mi.cbSize = sizeof(MONITORINFOEX);
- GetMonitorInfo(hMonitor, &mi);
- Video::Monitor monitor;
- string deviceName = (const char*)utf8_t(mi.szDevice);
- if(deviceName.beginsWith(R"(\\.\DISPLAYV)")) return true; //ignore pseudo-monitors
- DISPLAY_DEVICE dd{};
- dd.cb = sizeof(DISPLAY_DEVICE);
- EnumDisplayDevices(mi.szDevice, 0, &dd, 0);
- string displayName = (const char*)utf8_t(dd.DeviceString);
- monitor.name = {1 + monitors.size(), ": ", displayName};
- monitor.primary = mi.dwFlags & MONITORINFOF_PRIMARY;
- monitor.x = lprcMonitor->left;
- monitor.y = lprcMonitor->top;
- monitor.width = lprcMonitor->right - lprcMonitor->left;
- monitor.height = lprcMonitor->bottom - lprcMonitor->top;
- monitors.append(monitor);
- return true;
- }
- auto Video::hasMonitors() -> vector<Monitor> {
- vector<Monitor> monitors;
- EnumDisplayMonitors(nullptr, nullptr, MonitorEnumProc, (LPARAM)&monitors);
- vector<Monitor> sorted;
- for(auto& monitor : monitors) { if(monitor.primary == 1) sorted.append(monitor); }
- for(auto& monitor : monitors) { if(monitor.primary == 0) sorted.append(monitor); }
- return sorted;
- }
- #endif
- #if defined(DISPLAY_QUARTZ)
- static auto MonitorKeyArrayCallback(const void* key, const void* value, void* context) -> void {
- CFArrayAppendValue((CFMutableArrayRef)context, key);
- }
- auto Video::hasMonitors() -> vector<Monitor> {
- vector<Monitor> monitors;
- @autoreleasepool {
- uint count = [[NSScreen screens] count];
- for(uint index : range(count)) {
- auto screen = [[NSScreen screens] objectAtIndex:index];
- auto rectangle = [screen frame];
- Monitor monitor;
- monitor.name = {1 + monitors.size(), ": Monitor"}; //fallback in case name lookup fails
- monitor.primary = monitors.size() == 0; //on macOS, the primary monitor is always the first monitor.
- monitor.x = rectangle.origin.x;
- monitor.y = rectangle.origin.y;
- monitor.width = rectangle.size.width;
- monitor.height = rectangle.size.height;
- //getting the name of the monitor on macOS: "Think Different"
- auto screenDictionary = [screen deviceDescription];
- auto screenID = [screenDictionary objectForKey:@"NSScreenNumber"];
- auto displayID = [screenID unsignedIntValue];
- auto displayPort = CGDisplayIOServicePort(displayID);
- auto dictionary = IODisplayCreateInfoDictionary(displayPort, 0);
- CFRetain(dictionary);
- if(auto names = (CFDictionaryRef)CFDictionaryGetValue(dictionary, CFSTR(kDisplayProductName))) {
- auto languageKeys = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- CFDictionaryApplyFunction(names, MonitorKeyArrayCallback, (void*)languageKeys);
- auto orderLanguageKeys = CFBundleCopyPreferredLocalizationsFromArray(languageKeys);
- CFRelease(languageKeys);
- if(orderLanguageKeys && CFArrayGetCount(orderLanguageKeys)) {
- auto languageKey = CFArrayGetValueAtIndex(orderLanguageKeys, 0);
- auto localName = CFDictionaryGetValue(names, languageKey);
- monitor.name = {1 + monitors.size(), ": ", [(__bridge NSString*)localName UTF8String]};
- CFRelease(localName);
- }
- CFRelease(orderLanguageKeys);
- }
- CFRelease(dictionary);
- monitors.append(monitor);
- }
- }
- return monitors;
- }
- #endif
- #if defined(DISPLAY_XORG)
- auto Video::hasMonitors() -> vector<Monitor> {
- vector<Monitor> monitors;
- auto display = XOpenDisplay(nullptr);
- auto screen = DefaultScreen(display);
- auto rootWindow = RootWindow(display, screen);
- auto resources = XRRGetScreenResourcesCurrent(display, rootWindow);
- auto primary = XRRGetOutputPrimary(display, rootWindow);
- for(uint index : range(resources->noutput)) {
- Monitor monitor;
- auto output = XRRGetOutputInfo(display, resources, resources->outputs[index]);
- if(output->connection != RR_Connected || output->crtc == None) {
- XRRFreeOutputInfo(output);
- continue;
- }
- auto crtc = XRRGetCrtcInfo(display, resources, output->crtc);
- monitor.name = {1 + monitors.size(), ": ", output->name}; //fallback name
- monitor.primary = false;
- for(uint n : range(crtc->noutput)) monitor.primary |= crtc->outputs[n] == primary;
- monitor.x = crtc->x;
- monitor.y = crtc->y;
- monitor.width = crtc->width;
- monitor.height = crtc->height;
- //Linux: "Think Low-Level"
- Atom actualType;
- int actualFormat;
- unsigned long size;
- unsigned long bytesAfter;
- unsigned char* data = nullptr;
- Atom edid = XInternAtom(display, "EDID", False);
- auto property = XRRGetOutputProperty(
- display, resources->outputs[index],
- edid, 0, 384,
- 0, 0, 0, &actualType, &actualFormat, &size, &bytesAfter, &data
- );
- if(size >= 128) {
- string name{" "};
- //there are four lights! er ... descriptors. one of them is the monitor name.
- if(data[0x39] == 0xfc) memory::copy(name.get(), &data[0x3b], 13);
- if(data[0x4b] == 0xfc) memory::copy(name.get(), &data[0x4d], 13);
- if(data[0x5d] == 0xfc) memory::copy(name.get(), &data[0x5f], 13);
- if(data[0x6f] == 0xfc) memory::copy(name.get(), &data[0x71], 13);
- if(name.strip()) { //format: "name\n " -> "name"
- monitor.name = {1 + monitors.size(), ": ", name, " [", output->name, "]"};
- }
- }
- XFree(data);
- monitors.append(monitor);
- XRRFreeCrtcInfo(crtc);
- XRRFreeOutputInfo(output);
- }
- XRRFreeScreenResources(resources);
- XCloseDisplay(display);
- vector<Monitor> sorted;
- for(auto& monitor : monitors) { if(monitor.primary == 1) sorted.append(monitor); }
- for(auto& monitor : monitors) { if(monitor.primary == 0) sorted.append(monitor); }
- return sorted;
- }
- #endif
- auto Video::monitor(string name) -> Monitor {
- auto monitors = Video::hasMonitors();
- //try to find by name if possible
- for(auto& monitor : monitors) {
- if(monitor.name == name) return monitor;
- }
- //fall back to primary if not found
- for(auto& monitor : monitors) {
- if(monitor.primary) return monitor;
- }
- //Video::monitors() should never let this occur
- Monitor monitor;
- monitor.name = "Primary";
- monitor.primary = true;
- monitor.x = 0;
- monitor.y = 0;
- monitor.width = 640;
- monitor.height = 480;
- return monitor;
- }
- }
|