2010年6月1日火曜日

Cygwin+Opengl+Makefile

Check
ここんところこんなのばっかですね。SDLもいいけど、結局Windows用とX用にそれぞれべた書きしたほうがシンプルでいいんじゃないかという気がしてきた。今win32apiのほうのウィンドウを作成しているところです。

まずは、ビルドしたいソースファイル一式。

main.cpp
#include <windows.h>
#include <GL/gl.h>
#include "utilGL.hpp"

namespace
{
const char *APP_NAME = "Hoge";
const int APP_W = 400;
const int APP_H = 300;
}

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
   switch(msg)
   {
      case WM_DESTROY:
         PostQuitMessage(0);
         return 0;
   }
   return DefWindowProc(hWnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int)
{
   WNDCLASS wc;
   memset(&wc, 0, sizeof(wc));
   wc.lpfnWndProc   = MyWndProc;
   wc.hInstance     = hInst;
   wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
   wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_3DFACE);
   wc.lpszClassName = APP_NAME;
   if(!RegisterClass(&wc)) return -1;

   RECT r;
   SetRect(&r, 0, 0, APP_W, APP_H);
   AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, FALSE);
   
   HWND hWnd = CreateWindow(wc.lpszClassName, wc.lpszClassName,
                            WS_OVERLAPPEDWINDOW,
                            CW_USEDEFAULT, CW_USEDEFAULT,
                            r.right - r.left, r.bottom - r.top,
                            NULL, NULL, wc.hInstance, NULL);
   ShowWindow(hWnd, SW_SHOW);
   UpdateWindow(hWnd);

   while(true)
   {
      MSG msg;
      while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0)
      {
         DispatchMessage(&msg);
      }
      if(msg.message == WM_QUIT) break;


      HDC hdc = GetGLDC(hWnd);
      glClear(GL_COLOR_BUFFER_BIT);
      glBegin(GL_POLYGON);
      glColor3f(1, 0, 0); glVertex2f(-0.8f, -0.8f);
      glColor3f(0, 1, 0); glVertex2f( 0.8f,  0.8f);
      glColor3f(0, 0, 1); glVertex2f( 0.8f, -0.8f);
      glEnd();
      glFlush();
      SwapBuffers(hdc);
      ReleaseGLDC(hWnd, hdc);
   }
   ExitGL();
   return 0;
}
utilGL.hpp
#ifndef UTILGL_HPP_4bf0ab006de93374665ede990dbc4458
#define UTILGL_HPP_4bf0ab006de93374665ede990dbc4458
#include <windows.h>
#include <GL/gl.h>

HDC GetGLDC(HWND hWnd);
void ReleaseGLDC(HWND hWnd, HDC hdc);
void ExitGL();

#endif//UTILGL_HPP_4bf0ab006de93374665ede990dbc4458
utilGL.cpp
#include "utilGL.hpp"

static HGLRC hGLRC = NULL;

HDC GetGLDC(HWND hWnd)
{
   HDC hdc;
   int pf;
   static PIXELFORMATDESCRIPTOR pfd =
      {
         sizeof(PIXELFORMATDESCRIPTOR), 1,
         PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
         PFD_TYPE_RGBA,
         24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0,
         PFD_MAIN_PLANE, 0, 0, 0, 0
      };
   hdc = GetDC(hWnd);
   pf = ChoosePixelFormat(hdc, &pfd);
   SetPixelFormat(hdc, pf, &pfd);
   if(!hGLRC) hGLRC = wglCreateContext(hdc);
   wglMakeCurrent(hdc, hGLRC);

   return hdc;
}

void ReleaseGLDC(HWND hWnd, HDC hdc)
{
   wglMakeCurrent(hdc, 0);
   ReleaseDC(hWnd, hdc);
}

void ExitGL()
{
   if(!hGLRC) wglDeleteContext(hGLRC);
}
Makefile
program = glvertex
srcs = $(wildcard *.cpp)
objs = $(subst .cpp,.o,$(srcs))

CC := g++
CPPFLAGS = -I /usr/include/opengl
CXXFLAGS = -mno-cygwin
LDFLAGS = -mno-cygwin -lopengl32 -lgdi32

$(program): $(objs)
    @echo $(objs)
    $(CXX) $^ $(LDFLAGS) $(OUTPUT_OPTION)

%.o: %.cpp
    @echo $(srcs)
    $(COMPILE.C) $<

.PHONY: clean

clean:
    $(RM) $(program) $(objs) *~

以上4ファイル。


実行結果
さて、ここから覚え書き。

Makefileにある
$(CXX) $^ $(LDFLAGS) $(OUTPUT_OPTION)
ですが、こいつは展開されると、
g++ main.o utilGL.o -mno-cygwin -lopengl32 -lgdi32 -o glvertex
になります。

実はこの行、修正したものでして、修正前の状態だと
$(LINK.o) $^ $(OUTPUT_OPTION)
でした。これは、展開されると
$(CC) $(LDFLAGS) $(TARGET_ARCH) $(OUTPUT_OPTION)
g++ -mno-cygwin -lopengl32 -lgdi32 main.o utilGL.o -o glvertex
となり、リンクエラーを起こしてしまいます。原因はおそらく、リンクするオブジェクト(main.o utilGL.o)より前に-lopengl32 -lgdi32を書いてしまったことかと思います。


詳しくはよくわからないのですが、-lオプションをつけた依存ファイルは、ローカルの依存ファイル(main.o utilGL.o)より後ろに書いておくのが正解なようです。

参考サイト
Win32API+OpenGL(GLUTに頼らない方法)
GDI関係のライブラリ解決に役立った
GNU Make関数リファレンス
GNU Makeの使い方

0 件のコメント:

コメントを投稿