創作內容

5 GP

【程式】多個螢幕時的全螢幕模式

作者:Shark│2017-08-07 21:39:50│巴幣:66│人氣:1712
上星期在做一個功能:如果電腦接兩個以上的螢幕,讓遊戲的全螢幕模式正常,順便研究取得螢幕解析度的方法。

首先關於全螢幕模式的做法,早期的硬體為了減少效能消耗,會修改螢幕本身的解析度和frame rate,例如原本1366×768的螢幕改成640×480。
個人不太建議這個方法,這樣會有些問題,而且現在的硬體比起那個時候要好很多了。
我的做法是不修改螢幕解析度,而是開一個跟螢幕一樣大的視窗,再用double buffer處理內定解析度不同的問題。

本篇目的是讓全螢幕模式在每個螢幕都可以用,例如視窗在螢幕2的時候將遊戲調成全螢幕模式,就讓視窗剛好佔滿螢幕2,其他螢幕不影響。



電腦接兩個螢幕的時候,人類看到的是下圖紅色的兩個螢幕,但電子妖精看到的(程式裡的坐標)只有包含全部的一個螢幕,人看到的螢幕是其中的一個範圍,如何把坐標對應到兩個螢幕是作業系統和驅動程式處理掉。

Windows主螢幕左上角是(0,0),所以螢幕坐標有可能是負數。
X Window最左上的螢幕是(0,0),至少我測試時如此,不知道有沒有其他情況。

之前用如下方法取得螢幕大小

Windows:
DEVMODE devMode;
devMode.dmSize=sizeof(DEVMODE);
devMode.dmDriverExtra=0;
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode);
此時devMode.dmPelsWidth、devMode.dmPelsHeight是螢幕寬高。
EnumDisplaySettings第一參數填NULL只能取得主螢幕的範圍,所以如果在副螢幕上開全螢幕模式,也會變成在主螢幕開。

X Window:
Display* dsp;
int screen=DefaultScreen(dsp);
int width = DisplayWidth(dsp,screen);
int height = DisplayHeight(dsp,screen);
dsp是X Window的物件,在建立視窗的時候設好。
這個方法取得的是上圖電子妖精看到的螢幕,所以遊戲畫面會變成如下跨兩個螢幕。

雖然有screen這個參數,但不是用在一台電腦接多個螢幕,即使接多個螢幕screen還是只有一個,手上沒有實際環境看這個參數到底是做什麼用的。
(Linux版我目前直接用X window,沒有用Gtk、Qt等視窗函式庫)

本來想找有沒有函式自動檢查視窗位於哪個螢幕,然後指定螢幕就放大到剛好蓋滿螢幕…………發現辦不到,必須自己取得每個螢幕的範圍做計算。
改成如下的方法

Windows
#define UNICODE
#include<windows.h>

//要用的變數和struct
BOOL ret;
DISPLAY_DEVICE displayDevice;
displayDevice.cb=sizeof(DISPLAY_DEVICE);
DEVMODE devMode;
devMode.dmSize=sizeof(DEVMODE);
devMode.dmDriverExtra=0;

for(int i=0;;i++){
  ret=EnumDisplayDevices(NULL,i,&displayDevice,0);
  //傳回false代表i>目前螢幕數量,所有螢幕都檢查完了
  if(!ret){ break; }
  if(!(displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE)){
    continue;
  }

  EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
  int isPrimaryScreen = (displayDevice.StateFlags&DISPLAY_DEVICE_PRIMARY_DEVICE);
  /*
  此時devMode.dmPosition.x、devMode.dmPosition.y、devMode.dmPelsWidth、devMode.dmPelsHeight就是螢幕範圍了
  在這裡檢查視窗是否在螢幕裡
  另外有對主螢幕做特別處理
  */

}
用EnumDisplayDevices取得螢幕的DeviceName,再用EnumDisplaySettings取得目前的解析度設定。
好像沒有函式可以直接取得螢幕數量,要跑迴圈直到EnumDisplayDevices傳回false。
附帶一提修改螢幕解析度是用ChangeDisplaySettingsEx(),有興趣自己試試看吧。

X Window
要使用Xrandr這個擴充。
有另一個擴充Xinerama也可以取得螢幕大小,這是較舊的規格,功能也沒有Xrandr多,只用Xrandr就好了。
#include<X11/extensions/Xrandr.h>

Display* dsp;
Window window;
int number;
XRRMonitorInfo* monitorInfo=XRRGetMonitors(dsp, window, 1, &number);
//此時number是螢幕數量,跑迴圈檢查各個螢幕
for(int i=0;i<number;i++){
  XRRMonitorInfo* tempInfo=monitorInfo+i;
  /*
  此時tempInfo->x、tempInfo->y、tempInfo->width、tempInfo->height是螢幕範圍
  tempInfo->primary是是否為主螢幕
  在此檢查視窗是否在螢幕裡
  */

}
window也是X Window的物件,在建立視窗時建好。
XRRGetMonitors第三參數是get_active,填1代表只取得有在使用的螢幕。

如上取得螢幕範圍之後要檢查視窗是否在螢幕裡,我用不精確但是容易做的方法:視窗中心點是否在範圍內,如果中心點在所有螢幕外面,無法判定就用主螢幕代替。

知道在哪個螢幕後就要修改視窗大小和位置,還有把標題和邊框消除,Windows很簡單。
HWND window; //初始化時建好的視窗handle
int screenRect[4]; //用上面的方法求出螢幕的範圍

SetWindowLongPtr(window, GWL_STYLE, WS_POPUP|WS_VISIBLE);
SetWindowPos(window, 0, 0,0,0,0, SWP_NOSIZE|SWP_NOZORDER|SWP_NOMOVE|SWP_FRAMECHANGED);
  //沒有上面這行滑鼠坐標會錯
SetWindowPos(window, HWND_TOP, screenRect[0],screenRect[1],screenRect[2],screenRect[3], 0);

但X Window麻煩很多,是另一門學問,以後有空再介紹。



為了方便作業買了另一個螢幕,才發現引擎要對多螢幕做處理,雖然不知道有多少玩家會用多螢幕,但至少在作者的電腦上不能出問題,否則就不能製作了。
做了才發現又是個難關,要自己取得所有螢幕的大小做計算。
尤其X Window討厭的地方是說明文件很少,常常只能看header猜函式的用途,做這部分的時候也一樣。
另外試了幾個遊戲的全螢幕模式想參考一下,發現很多還是用舊式改解析度的做法,這樣不能在多螢幕用,而且其他視窗會被亂移,我的似乎是獨創的做法。



同時繼續研究Fedora,Fedora有個好處是可以同時裝32 bit和64 bit的開發用套件,Mint和Mageia就不行。
但是筆電會莫名其妙變得很燙,明明沒執行程式,用系統監控看CPU佔用率也很低,推測是顯卡在做什麼多餘的工但我找不到原因,把特效關掉、移除nouveau驅動程式也一樣,Mint就沒有這個問題。
裝軟體和設定也比較麻煩,有時更新了某個套件之後就進不了圖形介面,要按Ctrl+Alt+F2進命令列模式去救。
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=3674215
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:程式|Linux程式設計|Windows程式設計

留言共 0 篇留言

我要留言提醒:您尚未登入,請先登入再留言

5喜歡★shark0r 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:FF30遊戲攤位一覽&a... 後一篇:我過去的作品:「卡比金剛...

追蹤私訊切換新版閱覽

作品資料夾

asld12347🔉🐷🤓😁
紅燒翅膀 我喜歡吃~看更多我要大聲說7小時前


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】