3

Ubuntu でのフルスクリーン動作に奇妙な問題があります。ウィンドウ モードは問題なく動作しますが、「偽」( SDL_WINDOW_FULLSCREEN) と「本物」 ( SDL_WINDOW_FULLSCREEN_DESKTOP) の両方のフルスクリーン モードは動作しません。

Windows では、「偽の」フルスクリーン モードでビデオモードが変更され、ウィンドウのコンテンツがディスプレイ全体に引き伸ばされます。「リアル」フルスクリーン モードでは、デスクトップのサイズが使用されます。このモードでは、ウィンドウのコンテンツを左上隅に描画し、余分な領域を空のままにします。

Ubuntu では、「偽の」フルスクリーン モードがビデオモードの変更を行い、ウィンドウのコンテンツがディスプレイ全体に引き伸ばされますが、その一部のみが描画されます。上部 (ディスプレイの 90% 以上) または下部 (ディスプレイの 10% 未満) のいずれかです。描画されていない部分は、黒くなっているか、アプリケーション起動前に画面に描画されていたものが含まれています。アプリケーションが終了時にビデオモードを元に戻さないことがあります。下の部分しか描画されていない場合でも、カーソルは上の部分の内側にロックされます。

「リアル」フルスクリーン モードでは、完全に黒く表示されるか、ウィンドウの内容がディスプレイの中央に表示されます。コンテンツは上に移動し、その領域の周囲はすべて黒になります (ただし、背景色は黒ではありません)。このモードでは、カーソルはその領域内でロックされます。

実行時にフルスクリーン モードを変更すると、動作が少し異なります。描画領域 (カーソルがロックされている領域でもあります) は、「偽」モードの上部/下部や「本物」の中央だけでなく、どこにでも配置できます。

  • Windows での「偽の」フルスクリーン モード: (800x600 ビデオモード)
  • Windows の「リアル」フルスクリーン モード: 実際の窓 (800x600 ウィンドウのコンテンツは隅に描画され、他の領域は空です)
  • Ubuntu の「偽の」フルスクリーン モード: 偽のUbuntu (800x600 ビデオモードですが、領域全体は表示されません。ただし、gedit の一部は表示されます。)
  • Ubuntu の「リアル」フルスクリーン モード: 本当のubuntu (中央に 800x600 の領域がありますが、画像は上部に移動します (赤い四角は隅にあることを意味します))

SDL の代わりに手動で OpenGL を使用して画面に描画しています。問題を示す小さな例を書きました。800x600 のウィンドウを作成し、その中央に青い三角形を描画します。緑の四角が画面の隅に描かれ、赤の四角がウィンドウの隅に描かれます (同じ場所にある可能性があるため、緑の四角が大きくなり、その上に赤い四角が描かれます)。それぞれ '1'、'2'、または '3' キーを使用して、ウィンドウ化された「偽」または「本物」のフルスクリーン モードに入ることができます。エスケープ キーは、アプリケーションを閉じます。

#include <SDL.h>
#include <GL/gl.h>

#define FULLSCREEN 0
#define WIDTH 800
#define HEIGHT 600

//fullscreen:
// 0 - windowed mode,
// 1 - "fake" fullscreen mode,
// 2 - "real" fullscreen mode

int real_width;
int real_height;

//screen width & height - to draw green square that shows us actual screen size

void set_viewport(SDL_Window* window);
void draw(SDL_Window* window);

int main(int argc, char* argv[]) {
 SDL_Init(SDL_INIT_VIDEO);

 int position;
 #if FULLSCREEN == 0
  position = SDL_WINDOWPOS_CENTERED;
 #else
  position = 0;
 #endif

 //the only thing I've found - some guy said it works
 //if window is in (0,0) while entering fullscreen
 //well, it's not, but I've kept it

 int flags = SDL_WINDOW_OPENGL;
 #if FULLSCREEN == 1
  flags |= SDL_WINDOW_FULLSCREEN;
 #elif FULLSCREEN == 2
  flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
 #endif

 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

 SDL_Window* window = SDL_CreateWindow(
  "",
  position, position, /* centered/(0,0) */
  WIDTH, HEIGHT, /* request 800x600 window */
  flags /* needed mode */
 );

 //setup GL
 SDL_GLContext glcontext = SDL_GL_CreateContext(window);

 glShadeModel(GL_SMOOTH);
 glCullFace(GL_BACK);
 glFrontFace(GL_CCW);
 glEnable(GL_CULL_FACE);

 //viewport and projection
 set_viewport(window);

 draw(window);

 bool done = false;
 while(!done) {
  draw(window);

  SDL_Event event;
  while(SDL_PollEvent(&event)) {
   switch(event.type) {
    case SDL_QUIT: done = true; break;
    case SDL_KEYDOWN:
     if(event.key.keysym.scancode == SDL_SCANCODE_ESCAPE)
      done = true;
     else if(event.key.keysym.scancode == SDL_SCANCODE_1) {
      SDL_SetWindowFullscreen(window, 0);
      set_viewport(window);
     } else if(event.key.keysym.scancode == SDL_SCANCODE_2) {
      SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
      set_viewport(window);
     } else if(event.key.keysym.scancode == SDL_SCANCODE_3) {
      SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
      set_viewport(window);
     }
    break;
   }
  }
 }

 SDL_GL_DeleteContext(glcontext);
 SDL_DestroyWindow(window);
 SDL_Quit();
 return 0;
}

void set_viewport(SDL_Window* window) {
 SDL_GetWindowSize(window, &real_width, &real_height);

 glClearColor(1, 1, 1, 1);
 glViewport(0, 0, real_width, real_height);
 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 glOrtho(0, real_width, real_height, 0, -1, 0);
}

void draw_triangle();
void draw_square(int x, int y, float side);

void draw(SDL_Window* window) {
 glClear(GL_COLOR_BUFFER_BIT);
 glEnable(GL_BLEND);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

 //triangle on while background
 glClearColor(1, 1, 1, 1);
 draw_triangle();

 //green square at screen corner
 glColor3f(0, 1, 0);
 draw_square(real_width, real_height, 20);

 //red square at window corner
 glColor3f(1, 0, 0);
 draw_square(WIDTH, HEIGHT, 10);

 SDL_GL_SwapWindow(window);
}

void draw_triangle() {
 const float w = 460;
 const float h = 400;

 float colorBuffer[9] = {
  0, 0.43f, 0.85f /*#006dd9*/,
  0, 0.22f, 0.43f /*#00376e*/,
  0, 0.43f, 0.85f /*#006dd9*/
 };
 float vertexBuffer[9] = {
  0, 0, 0,
  w/2, h, 0,
  w, 0, 0
 };

 glEnableClientState(GL_VERTEX_ARRAY);
 glEnableClientState(GL_COLOR_ARRAY);

 glTranslatef((WIDTH-w)/2,(HEIGHT-h)/2,0);

 glColorPointer(3, GL_FLOAT, 0, colorBuffer);
 glVertexPointer(3, GL_FLOAT, 0, vertexBuffer);
 glDrawArrays(GL_TRIANGLE_FAN, 0, 3);

 glTranslatef(-(WIDTH-w)/2,-(HEIGHT-h)/2,0);

 glDisableClientState(GL_COLOR_ARRAY);
 glDisableClientState(GL_VERTEX_ARRAY);
}


void draw_square(int x, int y, float side) {
 float vertexBuffer[12] = {
  0, 0, 0, /*top left*/
  0, side, 0, /*bottom left*/
  side, side, 0, /*bottom right*/
  side, 0, 0 /*top right*/
 };

 glEnableClientState(GL_VERTEX_ARRAY);

 glTranslatef(x-side/2, y-side/2, 0);

 glVertexPointer(3, GL_FLOAT, 0, vertexBuffer);
 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

 glTranslatef(-x+side/2, -y+side/2, 0);

 glDisableClientState(GL_VERTEX_ARRAY);
}
4

1 に答える 1