Windows / Androidで動作確認。Windowを作って描画するまでの最小セット。
シェーダーはmidiump / lowpを使って型を固定しておかないとAndroidでシェーダのコンパイルで失敗するので注意!
SimpleGLTestのダウンロード
//---------------------------------------------------- // // シェーダーテスト用の最小プログラム // //---------------------------------------------------- #include <windows.h> #include <windowsx.h> #include <lib/glew-2.1.0/include/GL/glew.h> //#include <GLES2/gl2.h> //#include <GLES2/gl2ext.h> #define WINDOW_WIDTH 512 #define WINDOW_HEIGHT 512 #define FPS (60) #pragma comment (lib, "opengl32.lib") #pragma comment (lib, "lib/glew-2.1.0/lib/Release/x64/glew32.lib") //buffer for texture int TextureWidth=256,TextureHeight=256; unsigned int texImage1[256 * 256 * 4]; //image buffer for ue4 texture unsigned int texImage2[256 * 256 * 4]; //image buffer for render texture unsigned int texImage3[256 * 256 * 4]; //image buffer for capture texture //shader programs const GLchar *vtxShader1[] = { "#version 330\n", "in vec3 a_position;\n", "in vec2 a_texCoord;\n", "in vec4 a_color;\n", "out vec4 v_vtxColor;\n", "out vec2 v_texCoord;\n", "void main(void)\n", "{\n", "gl_Position = vec4( a_position , 1 );\n", "v_vtxColor = a_color;\n", "v_texCoord = a_texCoord;\n", "}\n", }; const GLchar *pxlShader1[] = { "#version 330\n", "in vec4 v_vtxColor;\n", "in int v_palColor;\n", "in vec2 v_texCoord;\n", "uniform sampler2D u_textureID1;\n", "void main(void)\n", "{\n", " vec4 color1 = texture2D( u_textureID1 , v_texCoord.xy );\n", " gl_FragColor = color1;\n", "}\n", }; struct StWindow { HINSTANCE m_hInstance; HWND m_hWindow; WPARAM m_wParam; HACCEL m_hAccel; HDC m_WinDC; bool g_bExit = false; } Window; struct StOpenGL { HGLRC m_hRC; GLuint m_sTexIndex[8]; GLuint shaderProgram; int Sequence; GLuint s_offscreen_fbo; } OpenGL; typedef struct StCustomVertex2 { float x, y, z, rhw; unsigned int argb; float u, v; } StCustomVertex2; //Windows void makeWindow( ); void action(); void render(); void vSync(); LRESULT CALLBACK WindowProc(HWND hw, UINT iMsg, WPARAM wParam, LPARAM lParam); //openGL void initGL(); void initTexture(); void initShader(); void drawGL(); void drawPrim( StCustomVertex2 *pVertex , int width , int height ); //extern unsigned char ue4[]; #if 1 int APIENTRY wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { //Windows Main OpenGL.Sequence = 0; OpenGL.s_offscreen_fbo = -1; Window.m_hInstance = hInstance; //make Window makeWindow(); //show Windows ShowWindow( Window.m_hWindow, nCmdShow ); //main loop while(!Window.g_bExit) { action(); vSync(); SwapBuffers( Window.m_WinDC ); } } void makeWindow( ) { //make window WNDCLASSEX wndClass; wndClass.cbSize = sizeof(wndClass); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = Window.m_hInstance; wndClass.hIcon = NULL; wndClass.hCursor = NULL; wndClass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = TEXT("glTest"); wndClass.hIconSm = NULL; ATOM hr = RegisterClassEx(&wndClass); RECT desktop; GetWindowRect(GetDesktopWindow(), (LPRECT)&desktop); int x, y, w, h; RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT }; AdjustWindowRect( &rect, WS_OVERLAPPEDWINDOW|WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, FALSE ); w = rect.right - rect.left; h = rect.bottom - rect.top; x = (desktop.right - desktop.left)/2 - w/2; y = (desktop.bottom - desktop.top )/2 - h/2; if( x < 0) x = 0; if( y < 0) y = 0; Window.m_hWindow = CreateWindow( TEXT("glTest"), TEXT("ShaderTest"), WS_OVERLAPPEDWINDOW|WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, x, y, w, h, NULL, NULL, Window.m_hInstance, NULL); Window.m_WinDC = GetDC( Window.m_hWindow ); } void vSync() { //------------------------------------------ //wait vsync //------------------------------------------ MSG msg; static LONGLONG before = 0; static LONGLONG vsyncratio = 0; LONGLONG time; QueryPerformanceCounter( (LARGE_INTEGER*)&time ); if( vsyncratio == 0 ) { // init vsync ratio QueryPerformanceCounter ( (LARGE_INTEGER*)&before); QueryPerformanceFrequency((LARGE_INTEGER*)&vsyncratio); vsyncratio = vsyncratio / FPS; before = time; } do { // wait vsync QueryPerformanceCounter( (LARGE_INTEGER*)&time ); while(PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) ) { if( !GetMessage( &msg, NULL, 0, 0 ) ) { return; } if ( !TranslateAccelerator( Window.m_hWindow , Window.m_hAccel , &msg ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } } while( time < ( before + vsyncratio ) ); before = time; } LRESULT CALLBACK WindowProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { //------------------------------------------ //windows procedure //------------------------------------------ switch (iMsg) { case WM_CREATE: break; case WM_CLOSE: DestroyWindow( hWnd ); break; case WM_DESTROY: Window.g_bExit = true; PostQuitMessage(0); return 0; case WM_SYSCOMMAND: case WM_COMMAND: default: break; } return DefWindowProc( hWnd, iMsg, wParam, lParam ); } #endif //------------------------------------------------------------- // OpenGL code //------------------------------------------------------------- void action() { if ( OpenGL.Sequence == 0 ) { //init initGL(); initTexture(); initShader(); glEnable ( GL_TEXTURE_2D ); /*毒*/// glEnable ( GL_NORMALIZE ); /*毒*/// glEnable ( GL_ALPHA_TEST ); glEnable ( GL_BLEND ); glDisable( GL_DEPTH_TEST ); OpenGL.Sequence ++; } drawGL(); } void initGL() { //---------------------------------------------------------------------- // OpenGL initialize //---------------------------------------------------------------------- #if 1 int pixelFormat; 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 1, // no stencil buffer 1, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; pixelFormat = ChoosePixelFormat(Window.m_WinDC, &pfd); SetPixelFormat(Window.m_WinDC, pixelFormat, &pfd); OpenGL.m_hRC = wglCreateContext(Window.m_WinDC); wglMakeCurrent(Window.m_WinDC, OpenGL.m_hRC); GLenum err = glewInit(); //matrix glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); //Reset glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); BOOL(WINAPI *wglSwapIntervalEXT)(int) = NULL; wglSwapIntervalEXT = (BOOL(WINAPI*)(int))wglGetProcAddress("wglSwapIntervalEXT"); if (wglSwapIntervalEXT) { wglSwapIntervalEXT(0); } #endif } void initShader() { //---------------------------------------------------------------------- // init shader //---------------------------------------------------------------------- GLint status; GLsizei bufSize; GLsizei length; GLchar *infoLog; //make program OpenGL.shaderProgram = glCreateProgram(); //compile vtxShader GLuint vshader; vshader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vshader, sizeof(vtxShader1) / sizeof(vtxShader1[0]), (GLchar const* const*)vtxShader1, NULL); glCompileShader(vshader); glGetShaderiv(vshader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { glGetShaderiv(vshader, GL_INFO_LOG_LENGTH, &bufSize); infoLog = (GLchar*)malloc(bufSize); glGetShaderInfoLog(vshader, bufSize, &length, infoLog); infoLog[512 - 1] = 0x00; free(infoLog); } //compile pxlShader GLuint pshader; pshader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(pshader, sizeof(pxlShader1) / sizeof(pxlShader1[0]), (GLchar const* const*)pxlShader1, NULL); glCompileShader(pshader); glGetShaderiv(pshader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { glGetShaderiv(pshader, GL_INFO_LOG_LENGTH, &bufSize); infoLog = (GLchar*)malloc(bufSize); glGetShaderInfoLog(pshader, bufSize, &length, infoLog); free(infoLog); } //attach prog program glAttachShader( OpenGL.shaderProgram , vshader ); glAttachShader( OpenGL.shaderProgram , pshader ); //link shader program glLinkProgram ( OpenGL.shaderProgram ); glGetProgramiv(OpenGL.shaderProgram, GL_LINK_STATUS, &status); if (status == GL_FALSE) { glGetProgramiv(OpenGL.shaderProgram, GL_INFO_LOG_LENGTH, &bufSize); infoLog = (GLchar*)malloc(bufSize); glGetProgramInfoLog(OpenGL.shaderProgram, bufSize, &length, infoLog); free(infoLog); } glDeleteShader( vshader ); glDeleteShader( pshader ); } void initTexture() { //---------------------------------------------------------------------- //init texture x2 //---------------------------------------------------------------------- glGenTextures( 8, OpenGL.m_sTexIndex ); //make src texture 1( ue4 ) unsigned int argb; for (int ii = 0; ii < 256 * 256 * 1;ii++) { argb = *(int*)(&texImage1[ii*4]); texImage1[ii] = ((argb>>24)&0xff)<<24 | ((argb>>16)&0xff)<<8 | ((argb>>8)&0xff)<<16 | ((argb>>0)&0xff)<<0; //ue4 } //make dst texture 2( noise ) for (int ii = 0; ii < 512 * 512 * 1;ii++) { texImage2[ii] = 0xff000000 | (rand()%255)<<16 | (rand()%255)<<8 | (rand()%255)<<0 ; //noise } // bind texture1 glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[0] ); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage1 ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); //<--- important! glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); // bind texture2 glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[1] ); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage2 ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); // bind texture3 glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[2] ); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage3 ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); //-------------------------------------------------------------- //create frame buffer object( fbo ) from texture //-------------------------------------------------------------- if( OpenGL.s_offscreen_fbo != -1 ) { glDeleteFramebuffers( 1 , &OpenGL.s_offscreen_fbo ); } glGenFramebuffers( 1, &OpenGL.s_offscreen_fbo ); glBindFramebuffer( GL_FRAMEBUFFER, OpenGL.s_offscreen_fbo ); //attach texture as color buffer of frame buffer glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OpenGL.m_sTexIndex[1], 0 ); //restore frame buffer state glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glBindTexture( GL_TEXTURE_2D, 0 ); } void drawGL() { //---------------------------------------------------------------------- //rendering //---------------------------------------------------------------------- //clear bg( red ) glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glClearColor( 1.0f, 0.0f, 0.0f, 1.f ); glClear( GL_COLOR_BUFFER_BIT ); render(); //restore default glBindFramebuffer( GL_FRAMEBUFFER, 0 ); // glActiveTexture(GL_TEXTURE0 + 0); // glActiveTexture(GL_TEXTURE0 + 1); } void render() { //---------------------------------------------------------------------- //rendering //---------------------------------------------------------------------- StCustomVertex2 pVertex1[4] = { //rect1 Z { 0.f ,0.f ,0.f ,1.f , 0xffffffff , 0.f ,0.f }, { 256.f ,0.f ,0.f ,1.f , 0xffffffff , 1.0 ,0.0 }, { 0.f ,256.f ,0.f ,1.f , 0xffffffff , 0.0 ,1.0 }, { 256/2.f ,256.f ,0.f ,1.f , 0xffffffff , 1.0 ,1.0 }, }; StCustomVertex2 pVertex2[4] = { //rect2 { 256 ,256 ,0 ,1 , 0xffffffff , 0 ,0 }, { 512 ,256 ,0 ,1 , 0xffffffff , 1.0 ,0.0 }, { 256 ,512 ,0 ,1 , 0xffffffff , 0.0 ,1.0 }, { 512 ,512 ,0 ,1 , 0xffffffff , 1.0 ,1.0 }, }; StCustomVertex2 pVertex3[4] = { //rect3 { 0 ,256 ,0 ,1 , 0xffffffff , 0 ,0 }, { 256 ,256 ,0 ,1 , 0xffffffff , 1.0 ,0.0 }, { 0 ,512 ,0 ,1 , 0xffffffff , 0.0 ,1.0 }, { 256 ,512 ,0 ,1 , 0xffffffff , 1.0 ,1.0 }, }; glActiveTexture( GL_TEXTURE0 + 0 ); //-------------------------------------------------- //src draw to "render texture" //-------------------------------------------------- { //adjust screensize to Texture size glViewport( 0, 0, TextureWidth , TextureHeight ); glBindFramebuffer( GL_FRAMEBUFFER, OpenGL.s_offscreen_fbo ); //clear "render texture" glClearColor( 0.0f, 1.0f, 0.0f, 1.f ); //(green) glClear(GL_COLOR_BUFFER_BIT); glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[0] ); //use "noise texture" drawPrim( pVertex1 , TextureWidth , TextureHeight ); } //-------------------------------------------------- //"render texture" draw to "frame buffer" //-------------------------------------------------- { //adjust screensize to Window size glViewport(0, 0, WINDOW_WIDTH,WINDOW_HEIGHT ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[1] ); //use "render texture" drawPrim( pVertex2 , WINDOW_WIDTH , WINDOW_HEIGHT ); } //-------------------------------------------------- //capture "rgba data" from "render texture" //-------------------------------------------------- glBindFramebuffer( GL_FRAMEBUFFER, OpenGL.s_offscreen_fbo ); // glReadBuffer(GL_COLOR_ATTACHMENT0); glReadPixels( 0, 0, TextureWidth, TextureHeight, GL_RGBA, GL_UNSIGNED_BYTE, texImage3 ); //make "capture texture" from "rgba data" glBindTexture( GL_TEXTURE_2D, OpenGL.m_sTexIndex[2] ); glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage3 ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); //<--- important! glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); //draw "capture texture" to "frame buffer" glBindFramebuffer( GL_FRAMEBUFFER, 0 ); drawPrim( pVertex3 , WINDOW_WIDTH , WINDOW_HEIGHT ); } void drawPrim( StCustomVertex2 *pVertex , int width , int height ) { //---------------------------------------------------------------------- //render primitive //div rect to triangle x2. //---------------------------------------------------------------------- //vtx (-1,+1) - (+1,+1) // (-1,-1) - (+1,-1) //uvs ( 0,+1) - (+1,+1) // ( 0, 0) - (+1, 0) //---------------------------------------------------------------------- float vtx[] = { //Vertices pVertex[0].x / (width / 2) - 1.0f, -(pVertex[0].y / (height / 2) - 1.0f) , 0.0f, pVertex[1].x / (width / 2) - 1.0f, -(pVertex[1].y / (height / 2) - 1.0f) , 0.0f, pVertex[2].x / (width / 2) - 1.0f, -(pVertex[2].y / (height / 2) - 1.0f) , 0.0f, pVertex[2].x / (width / 2) - 1.0f, -(pVertex[2].y / (height / 2) - 1.0f) , 0.0f, pVertex[1].x / (width / 2) - 1.0f, -(pVertex[1].y / (height / 2) - 1.0f) , 0.0f, pVertex[3].x / (width / 2) - 1.0f, -(pVertex[3].y / (height / 2) - 1.0f) , 0.0f, }; float uvs[] = { //UVs pVertex[0].u , 1.0f-pVertex[0].v, pVertex[1].u , 1.0f-pVertex[1].v, pVertex[2].u , 1.0f-pVertex[2].v, pVertex[2].u , 1.0f-pVertex[2].v, pVertex[1].u , 1.0f-pVertex[1].v, pVertex[3].u , 1.0f-pVertex[3].v, }; GLfloat cols[] = { //Colors (int((pVertex[0].argb>>24)&0xff)/255.0f),(int((pVertex[0].argb>>16)&0xff)/255.0f),(int((pVertex[0].argb>>8)&0xff)/255.0f),(int((pVertex[0].argb>>0)&0xff)/255.0f), //1.0 ,1.0 ,1.0 , 1.0, (int((pVertex[1].argb>>24)&0xff)/255.0f),(int((pVertex[1].argb>>16)&0xff)/255.0f),(int((pVertex[1].argb>>8)&0xff)/255.0f),(int((pVertex[1].argb>>0)&0xff)/255.0f), //1.0 ,1.0 ,1.0 , 1.0, (int((pVertex[2].argb>>24)&0xff)/255.0f),(int((pVertex[2].argb>>16)&0xff)/255.0f),(int((pVertex[2].argb>>8)&0xff)/255.0f),(int((pVertex[2].argb>>0)&0xff)/255.0f), //1.0 ,1.0 ,1.0 , 1.0, (int((pVertex[2].argb>>24)&0xff)/255.0f),(int((pVertex[2].argb>>16)&0xff)/255.0f),(int((pVertex[2].argb>>8)&0xff)/255.0f),(int((pVertex[2].argb>>0)&0xff)/255.0f), //1.0 ,1.0 ,1.0 , 1.0, (int((pVertex[1].argb>>24)&0xff)/255.0f),(int((pVertex[1].argb>>16)&0xff)/255.0f),(int((pVertex[1].argb>>8)&0xff)/255.0f),(int((pVertex[1].argb>>0)&0xff)/255.0f), //1.0 ,1.0 ,1.0 , 1.0, (int((pVertex[3].argb>>24)&0xff)/255.0f),(int((pVertex[3].argb>>16)&0xff)/255.0f),(int((pVertex[3].argb>>8)&0xff)/255.0f),(int((pVertex[3].argb>>0)&0xff)/255.0f), //1.0 ,1.0 ,1.0 , 1.0, }; //draw with shader glEnableVertexAttribArray( 0 ); GLuint position = glGetAttribLocation( OpenGL.shaderProgram, "a_position" ); glVertexAttribPointer( position, 3, GL_FLOAT, GL_FALSE, 0, vtx ); glEnableVertexAttribArray(position); GLuint texcoord = glGetAttribLocation( OpenGL.shaderProgram, "a_texCoord" ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, GL_FALSE, 0, uvs ); glEnableVertexAttribArray( texcoord ); GLuint color = glGetAttribLocation( OpenGL.shaderProgram, "a_color" ); glVertexAttribPointer( color, 4, GL_FLOAT, GL_FALSE, 0, cols ); glEnableVertexAttribArray( color ); int textureID1; textureID1 = glGetUniformLocation( OpenGL.shaderProgram, "u_textureID1" ); glUniform1i(textureID1, 0 ); glUseProgram( OpenGL.shaderProgram ); glDrawArrays( GL_TRIANGLES, 0, 6 ); glDisableVertexAttribArray( 0 ); }