/* * 複数のレンダリングコンテキスト */ #include #include #define ID_CHILD 1000 class glCanvas{ static LRESULT CALLBACK initChildWndProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK staticChildWndProc(HWND, UINT, WPARAM, LPARAM); protected: int count; static char *cwdName; static HINSTANCE hInstance; public: glCanvas::glCanvas() : count(0){}; glCanvas::~glCanvas(){}; HWND glCanvas::createWindow(HWND, int, int, int, int); static unsigned short registClass(HINSTANCE); LRESULT ChildWindowProc(HWND, UINT, WPARAM, LPARAM); }; char* glCanvas::cwdName = "canvas00"; HINSTANCE glCanvas::hInstance; typedef struct _st_child{ HWND hWnd; HDC hdc; HGLRC hrc; glCanvas *glc; }st_child; static int child_count = 0; static st_child *child = NULL; static void initChild(st_child *); static void addChild(HWND, glCanvas *); static void deleteChild(HWND); void initChild(st_child *child){ child->hWnd = NULL; child->hrc = NULL; child->glc = NULL; } void addChild(HWND hWnd, glCanvas *glc){ if(child == NULL){ child = new st_child[1]; initChild(&child[0]); child_count = 1; } int i; for(i = 0; i < child_count; i++){ if(child[i].hWnd == NULL){ child[i].hWnd = hWnd; child[i].glc = glc; return; } } if(i == child_count){ st_child *new_child = new st_child[child_count << 1]; for(i = 0; i < child_count; i++){ new_child[i] = child[i]; } new_child[i].hWnd = hWnd; new_child[i].glc = glc; child_count = child_count << 1; for(i = i + 1; i < child_count; i++){ initChild(&new_child[i]); } delete [] child; child = new_child; } } void deleteChild(HWND hWnd){ int i; for(i = 0; i < child_count; i++){ if(child[i].hWnd == hWnd){ initChild(&child[i]); return; } } } HWND glCanvas::createWindow(HWND hWnd, int x, int y, int w, int h){ CREATESTRUCT CS; CS.lpCreateParams = this; HWND hCanvas = CreateWindow(cwdName, "", WS_CHILD | WS_VISIBLE, x, y, w, h, hWnd, (HMENU)ID_CHILD + count, hInstance, &CS); count++; return hCanvas; } unsigned short glCanvas::registClass(HINSTANCE hInst){ WNDCLASS cwd; cwd.style = 0; cwd.lpfnWndProc = (WNDPROC)initChildWndProc; cwd.cbClsExtra = 0; cwd.cbWndExtra = 0; cwd.hInstance = hInst; cwd.hIcon = NULL; cwd.hCursor = NULL; cwd.hbrBackground = GetSysColorBrush(COLOR_BTNFACE); cwd.lpszMenuName = NULL; cwd.lpszClassName = cwdName; hInstance = hInst; return RegisterClass(&cwd); } LRESULT CALLBACK glCanvas::initChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: { // hWnd と glCanvas * を関連付け addChild(hWnd, (glCanvas *)((LPCREATESTRUCT)lParam)->lpCreateParams); SetWindowLong(hWnd, GWL_WNDPROC, (LONG)staticChildWndProc); return ((glCanvas *)((LPCREATESTRUCT)lParam)->lpCreateParams)->ChildWindowProc(hWnd, message, wParam, lParam); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } } LRESULT CALLBACK glCanvas::staticChildWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { for(int i = 0; i < child_count; i++){ if(hWnd == child[i].hWnd){ break; } } return (child[i].glc)->ChildWindowProc(hWnd, message, wParam, lParam); } static BOOL bSetupPixelFormat(HDC hdc); void nmgl_init(void){ glClearColor(0.0, 0.0, 0.0, 0.0); glViewport(0, 0, 80, 80); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.33, 1.33, -1.0, 1.0, 1.0, 5.0); glMatrixMode(GL_MODELVIEW); } void nmgl_resize(int w, int h){ glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.33, 1.33, -1.0, 1.0, 1.0, 5.0); glMatrixMode(GL_MODELVIEW); } void nmgl_paint(float r){ glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslated(0.0, 0.0, -3.0); glRotated(r, 0.0, 0.0, 1.0); glPushMatrix(); glBegin(GL_TRIANGLES); glColor3d(1.0, 0.0, 0.0); glVertex3d(1.0, -0.6, 0.0); glVertex3d(-1.0, -0.6, 0.0); glVertex3d(0.0, 1.0, 0.0); glEnd(); glPopMatrix(); } LRESULT glCanvas::ChildWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { for(int i = 0; i < child_count; i++){ if(hWnd == child[i].hWnd){ break; } } switch (message) { case WM_CREATE: { // hWnd と hdc を関連付け child[i].hdc = GetDC(hWnd); bSetupPixelFormat(child[i].hdc); // hWnd と hrc を関連付け child[i].hrc = wglCreateContext(child[i].hdc); wglMakeCurrent(child[i].hdc, child[i].hrc); nmgl_init(); wglMakeCurrent(child[i].hdc, 0); } break; case WM_ERASEBKGND: { wglMakeCurrent(child[i].hdc, child[i].hrc); nmgl_paint(90.0f * i); SwapBuffers(child[i].hdc); } break; case WM_SIZE: { RECT rect; GetClientRect(hWnd, &rect); nmgl_resize(rect.right, rect.bottom); } break; case WM_DESTROY: { wglMakeCurrent(child[i].hdc, 0); wglDeleteContext(child[i].hrc); ReleaseDC(hWnd, child[i].hdc); deleteChild(hWnd); PostQuitMessage(0); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // メイン int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int nCmdShow) { WNDCLASSEX wcex; char *wdName = "OpenGL on Win32API"; HWND hWnd; MSG msg; if(!hPrevInstance){ if(glCanvas::registClass(hInstance) == FALSE){ return FALSE; } } if(!hPrevInstance){ wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = wdName; wcex.hIconSm = NULL; if(!RegisterClassEx(&wcex)){ return 0; } } hWnd = CreateWindow( wcex.lpszClassName, wdName, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); while(GetMessage(&msg, NULL, 0, 0)){ TranslateMessage(&msg); DispatchMessage(&msg); } if(child){ delete [] child; } return msg.wParam; } // ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static glCanvas *glc; switch (message) { case WM_CREATE: { glc = new glCanvas[4]; glc[0].createWindow(hWnd, 10, 10, 80, 80); glc[1].createWindow(hWnd, 100, 10, 80, 80); glc[2].createWindow(hWnd, 190, 10, 80, 80); glc[3].createWindow(hWnd, 280, 10, 80, 80); } break; case WM_DESTROY: { delete [] glc; PostQuitMessage(0); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } // ピクセルフォーマットの設定 BOOL bSetupPixelFormat(HDC hdc) { static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */ 1, /* version number */ PFD_DRAW_TO_WINDOW | /* support window */ PFD_SUPPORT_OPENGL | /* support OpenGL */ PFD_DOUBLEBUFFER, /* double buffered */ PFD_TYPE_RGBA, /* RGBA type */ 24, /* 24-bit color depth */ 0, 0, 0, 0, 0, 0, /* color bits ignored */ 0, /* no alpha buffer */ 0, /* shift bit ignored */ 0, /* no accumulation buffer */ 0, 0, 0, 0, /* accum bits ignored */ 32, /* 32-bit z-buffer */ 0, /* no stencil buffer */ 0, /* no auxiliary buffer */ PFD_MAIN_PLANE, /* main layer */ 0, /* reserved */ 0, 0, 0 /* layer masks ignored */ }; int pixelformat; if((pixelformat = ChoosePixelFormat(hdc, &pfd)) == 0){ MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); return FALSE; } if(SetPixelFormat(hdc, pixelformat, &pfd) == FALSE) { MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); return FALSE; } return TRUE; }