monolithic kernel

プラグイン無しでOpenGLを用いた描画を行う

HSPからOpenGLを使う方法のメモ。プラグインは使わないのでコンテストのHSPTV部門でも利用可能です。

文章では説明しづらいので以下サンプルのソースコード。HSPTV部門での利用を想定して定数の演算を最適化しています。pfd_nの値は一部0になるので更なる最適化も可能だとは思いますが、そこは本質ではないので割愛。

#uselib "gdi32"
#func  SwapBuffers       "SwapBuffers"        int
#cfunc ChoosePixelFormat "ChoosePixelFormat"  int, var
#func  SetPixelFormat    "SetPixelFormat"     int, int, var

#uselib "opengl32"
#cfunc wglCreateContext  "wglCreateContext"   int
#func  wglMakeCurrent    "wglMakeCurrent"     int, int
#func  wglDeleteContext  "wglDeleteContext"   int
#cfunc wglGetCurrentDC   "wglGetCurrentDC"
#func  glClear           "glClear"            int
#func  glFinish          "glFinish"
#func  glBegin           "glBegin"            int
#func  glEnd             "glEnd"
#func  glVertex2d        "glVertex2d"         double, double
#func  glColor3d         "glColor3d"          double, double, double

#uselib "user32"
#cfunc GetDC "GetDC" int
#func ReleaseDC "ReleaseDC" int, int

#define GL_TRIANGLES        0x0004
#define GL_COLOR_BUFFER_BIT 0x00004000
#define PFD_DOUBLEBUFFER    0x00000001
#define PFD_DRAW_TO_WINDOW  0x00000004
#define PFD_SUPPORT_OPENGL  0x00000020
#define PFD_TYPE_RGBA       0
#define PFD_MAIN_PLANE      0

// screen 0のDCを取得する。
// システム変数hdcの値は内部バッファのDCなので利用できない。
hdc_ = GetDC(hwnd)

// PIXELFORMATDESCRIPTOR構造体の値を定義する。
#const pfd_nSize            40
#const pfd_nVersion         1
#const pfd_dwFlags          (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER)
#const pfd_iPixelType       PFD_TYPE_RGBA
#const pfd_cColorBits       24
#const pfd_cRedBits         0
#const pfd_cRedShift        0
#const pfd_cGreenBits       0
#const pfd_cGreenShift      0
#const pfd_cBlueBits        0
#const pfd_cBlueShift       0
#const pfd_cAlphaBits       0
#const pfd_cAlphaShift      0
#const pfd_cAccumBits       0
#const pfd_cAccumRedBits    0
#const pfd_cAccumGreenBits  0
#const pfd_cAccumBlueBits   0
#const pfd_cAccumAlphaBits  0
#const pfd_cDepthBits       0
#const pfd_cStencliBits     0
#const pfd_cAuxBuffers      16
#const pfd_iLayerType       PFD_MAIN_PLANE
#const pfd_bReserved        0
#const pfd_dwLayerMask      0
#const pfd_dwVisibleMask    0
#const pfd_dwDamageMask     0

// PIXELFORMATDESCRIPTOR構造体を初期化する。
#const pfd_0 ((pfd_nVersion << 16) | pfd_nSize)
#const pfd_1 (pfd_dwFlags)
#const pfd_2 ((pfd_cRedShift << 24) | (pfd_cRedBits << 16) | (pfd_cColorBits << 8) | pfd_iPixelType)
#const pfd_3 ((pfd_cBlueShift << 24) | (pfd_cBlueBits << 16) | (pfd_cGreenShift << 8) | pfd_cGreenBits)
#const pfd_4 ((pfd_cAccumRedBits << 24) | (pfd_cAccumBits << 16) | (pfd_cAlphaShift << 8) | pfd_cAlphaBits)
#const pfd_5 ((pfd_cDepthBits << 24) | (pfd_cAccumAlphaBits << 16) | (pfd_cAccumBlueBits << 8) | pfd_cAccumGreenBits)
#const pfd_6 ((pfd_bReserved << 24) | (pfd_iLayerType << 16) | (pfd_cAuxBuffers << 8) | pfd_cStencliBits)
#const pfd_7 (pfd_dwLayerMask)
#const pfd_8 (pfd_dwVisibleMask)
#const pfd_9 (pfd_dwDamageMask)

pfd = pfd_0, pfd_1, pfd_2, pfd_3, pfd_4, pfd_5, pfd_6, pfd_7, pfd_8, pfd_9

#undef pfd_0
#undef pfd_1
#undef pfd_2
#undef pfd_3
#undef pfd_4
#undef pfd_5
#undef pfd_6
#undef pfd_7
#undef pfd_8
#undef pfd_9

// ピクセルフォーマットを設定する。
SetPixelFormat hdc_, ChoosePixelFormat(hdc_, pfd), pfd

// コンテキストを生成し、設定する。
hrc = wglCreateContext(hdc_)
wglMakeCurrent hdc_, hrc

onexit *close

*main
  // バッファをクリアする。
  glClear GL_COLOR_BUFFER_BIT

  // 描画を行う。
  glBegin GL_TRIANGLES
    glColor3d 1
    glVertex2d , 1
    glColor3d , 1
    glVertex2d -1, -1
    glColor3d , , 1
    glVertex2d 1, -1
  glEnd

  // 描画を終了する。
  glFinish
  SwapBuffers wglGetCurrentDC()

  await 30
  goto *main

*close
  // コンテキストを元に戻し、破棄する。
  wglMakeCurrent hdc_
  wglDeleteContext hrc
  ReleaseDC hwnd, hdc_

  end

このコードは最小限なので本格的に開発する場合にはgl.hあたりから定義をとってくる必要があります。

実際にプログラムに利用した例としては、2007年のコンテストに応募したameのソースコードが参考になるかもしれません。

追記

  • 2010/12/10
    • デバイスコンテキストのリークを修正

Related articles