2017-08-24 56 views
0

我在窗口中写了一个关于在窗口上显示纹理的OpenGL程序。但是,最终的结果是扩展到窗口的初始大小,而不管OpenGL命令中是否没有对窗口大小的引用。我想要实现的是即使初始窗口大小小于纹理大小,也可以绘制出完整的纹理,不需要拉伸。我错过了什么?下面如何防止opengl绘图拉伸到窗口大小?

代码:

#include "stdafx.h" 
#include <wingdi.h> 
#include <gl\gl.h> 
#include <stdio.h> 
#include <assert.h> 
#pragma comment(lib, "opengl32.lib") 

#define MAX_LOADSTRING 100 

HINSTANCE hInst; 

TCHAR szWindowClass[MAX_LOADSTRING]; 

HANDLE g_hEvent; 

static HWND wgl_Wnd; 


ATOM    MyRegisterClass(HINSTANCE hInstance); 
HWND    InitInstance(HINSTANCE, int); 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 

DWORD WINAPI 
WindowThread(LPVOID lpParam) 
{ 
    MSG msg; 
    HINSTANCE hInstance = (HINSTANCE)lpParam; 

    HWND hWnd = InitInstance(hInstance, SW_SHOW); 
    if (!hWnd) { 
     return 0; 
    } 

    wgl_Wnd = hWnd; 
    SetEvent(g_hEvent); 

    while (GetMessage(&msg, NULL, 0, 0)) { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
    return 0; 
} 

char *g_data = NULL; 

#define IWIDTH 752 
#define IHEIGHT 1334 
#define FWIDTH 752.0f 
#define FHEIGHT 1334.0f 

#define GLSL(version, shader) "#version " #version "\n" #shader 

static const char* SIMPLE_VS = GLSL(120, 
    attribute vec4 a_pos; 
    attribute vec2 a_tex; 
    varying vec2 v_tex; 
    uniform mat4 u_pm; 
    uniform mat4 u_mm; 
    void main() { 
     gl_Position = u_pm * u_mm * a_pos; 
     v_tex = a_tex; 
    } 
); 

static const char* SIMPLE_FS = GLSL(120, 
    uniform sampler2DRect u_tex; 
    varying vec2 v_tex; 
    void main() { 
     gl_FragColor.a = 1.0; 
     gl_FragColor.rgb = texture2DRect(u_tex, v_tex).rgb; 
    } 
); 

static void print_shader_compile_info(GLuint shader) { 
    GLint status = 0; 
    GLint count = 0; 
    glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 
    if (!status) { 
     assert(0); 
    } 
} 

static GLuint create_shader(GLenum type, const char* src) { 
    GLuint s = glCreateShader(type); 
    glShaderSource(s, 1, &src, NULL); 
    glCompileShader(s); 
    print_shader_compile_info(s); 
    return s; 
} 

GLuint g_tex; 
GLuint g_glbuf; 
GLuint g_prog; 
GLuint g_vao; 
GLfloat g_pm[16]; 
GLint g_u_mm; 
GLint g_u_pm; 
GLint g_u_tex; 

static VOID loadData() 
{ 
    FILE *file = fopen("f:\\tmp\\test001.raw", "rb"); 
    long fsize; 
    fseek(file, 0, SEEK_END); 
    fsize = ftell(file); 
    fseek(file, 0, SEEK_SET); 

    g_data = new char[fsize]; 
    fread(g_data, 1, fsize, file); 

    fclose(file); 
} 



static VOID wglRender(HDC hdc) 
{ 
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, g_glbuf); 
    void *glptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); 

    memcpy(glptr, g_data, IWIDTH * IHEIGHT * 4); 
    glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); 

    glBindTexture(GL_TEXTURE_RECTANGLE, g_tex); 
    glTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, 0, 0, IWIDTH, IHEIGHT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0); 

    GLfloat mm[16] = { 
     1.0f, 0.0f, 0.0f, 0.0f, 
     0.0f, 1.0f, 0.0f, 0.0f, 
     0.0f, 0.0f, 1.0f, 0.0f, 
     0.0f, 0.0f, -5.0f, 1.0f 
    }; 

    glBindVertexArray(g_vao); 
    glUseProgram(g_prog); 

    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_RECTANGLE, g_tex); 
    glUniform1i(g_u_tex, 0); 

    glUniformMatrix4fv(g_u_mm, 1, GL_FALSE, mm); 
    glUniformMatrix4fv(g_u_pm, 1, GL_FALSE, g_pm); 
    glDrawArrays(GL_TRIANGLES, 0, 6); 

    SwapBuffers(hdc); 
} 

int APIENTRY _tWinMain(HINSTANCE hInstance, 
         HINSTANCE hPrevInstance, 
         LPTSTR lpCmdLine, 
         int  nCmdShow) 
{ 
    UNREFERENCED_PARAMETER(hPrevInstance); 
    UNREFERENCED_PARAMETER(lpCmdLine); 

    MyRegisterClass(hInstance); 

    // custom code starts here. 

    g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 
    CloseHandle(CreateThread(NULL, 0, WindowThread, (LPVOID)hInstance, 0, NULL)); 
    WaitForSingleObject(g_hEvent, INFINITE); 
    CloseHandle(g_hEvent); 

    PIXELFORMATDESCRIPTOR pfd = {0}; 
    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); 
    pfd.nVersion = 1; 
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 
    pfd.iPixelType = PFD_TYPE_RGBA; 
    pfd.cColorBits = 0x20; 
    pfd.cRedBits = 8; 
    pfd.cGreenBits = 8; 
    pfd.cBlueBits = 8; 
    pfd.cDepthBits = 0x18; 

    HDC hdc = GetDC(wgl_Wnd); 
    int pf = ChoosePixelFormat(hdc, &pfd); 
    SetPixelFormat(hdc, pf, &pfd); 

    HGLRC hGlrc = wglCreateContext(hdc); 
    wglMakeCurrent(hdc, hGlrc); 

    loadData(); 

    GLuint vert = create_shader(GL_VERTEX_SHADER, SIMPLE_VS); 
    GLuint frag = create_shader(GL_FRAGMENT_SHADER, SIMPLE_FS); 
    g_prog = glCreateProgram(); 
    glAttachShader(g_prog, vert); 
    glAttachShader(g_prog, frag); 
    glLinkProgram(g_prog); 

    g_u_mm = glGetUniformLocation(g_prog, "u_mm"); 
    g_u_pm = glGetUniformLocation(g_prog, "u_pm"); 
    g_u_tex = glGetUniformLocation(g_prog, "u_tex"); 

    float n = 0.0f; 
    float f = 10.0f; 
    float ww = FWIDTH; 
    float hh = FHEIGHT; 
    float fmn = f - n; 

    for (int i = 0; i < 16; i++) { 
     g_pm[i] = 0.0f; 
    } 


    g_pm[0] = 2.0f/ww; 
    g_pm[5] = 2.0f/-hh; 
    g_pm[10] = -2.0f/fmn; 
    g_pm[12] = -(ww)/ww; 
    g_pm[13] = -(hh)/-hh; 
    g_pm[14] = -(f + n)/fmn; 
    g_pm[15] = 1.0f; 
    // 

    glBindTexture(GL_TEXTURE_RECTANGLE, 0); 
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 
    glUseProgram(0); 

    glGenTextures(1, &g_tex); 
    glBindTexture(GL_TEXTURE_RECTANGLE, g_tex); 
    glGenBuffers(1, &g_glbuf); 
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, g_glbuf); 
    glBufferData(GL_PIXEL_UNPACK_BUFFER, IWIDTH * IHEIGHT* 4, NULL, GL_DYNAMIC_DRAW); 
    glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, IWIDTH, IHEIGHT, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); 
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

    glGenVertexArrays(1, &g_vao); 
    glBindVertexArray(g_vao); 
    GLfloat vertices[] = { 
     0.0f, 0.0f, 0.0f, 0.0f, 
     IWIDTH, 0.0f, IWIDTH, 0.0f, 
     IWIDTH, IHEIGHT, IWIDTH, IHEIGHT, 

     0.0f, 0.0f, 0.0f, 0.0f, 
     IWIDTH, IHEIGHT, IWIDTH, IHEIGHT, 
     0.0f, IHEIGHT, 0.0f, IHEIGHT 
    }; 


    GLuint vbo; 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 

    glEnableVertexAttribArray(0); // pos 
    glEnableVertexAttribArray(1); // tex 
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (GLvoid*)0); 
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (GLvoid*)8); 


    while(TRUE) { 
     if(!IsWindow(wgl_Wnd)) { 
      break; 
     } 
     Sleep(1); 

     wglRender(hdc); 
    } 

    wglMakeCurrent(NULL, NULL); 
    wglDeleteContext(hGlrc); 
    ReleaseDC(wgl_Wnd, hdc); 
    DestroyWindow(wgl_Wnd); 

    return 0; 
} 

ATOM MyRegisterClass(HINSTANCE hInstance) 
{ 
    WNDCLASSEX wcex; 

    wcex.cbSize = sizeof(WNDCLASSEX); 

    wcex.style   = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 
    wcex.lpfnWndProc = WndProc; 
    wcex.cbClsExtra  = 0; 
    wcex.cbWndExtra  = 0; 
    wcex.hInstance  = hInstance; 
    wcex.hIcon  = NULL; 
    wcex.hCursor  = NULL; 
    wcex.hbrBackground = NULL; 
    wcex.lpszMenuName = NULL; 
    wcex.lpszClassName = _T("MyClassName"); 
    wcex.hIconSm  = NULL; 

    return RegisterClassEx(&wcex); 
} 

HWND InitInstance(HINSTANCE hInstance, int nCmdShow) 
{ 
    HWND hWnd; 

    hInst = hInstance; 

    RECT rect = { 0, 0, 600, 600 }; 
    AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_CLIENTEDGE); 

    hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, _T("MyClassName"), _T("MyTitle"), WS_OVERLAPPEDWINDOW, 
     CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, 0, NULL); 

    if (!hWnd) 
    { 
     return NULL; 
    } 

    ShowWindow(hWnd, nCmdShow); 
    UpdateWindow(hWnd); 

    return hWnd; 
} 

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    return DefWindowProc(hWnd, message, wParam, lParam); 
} 
+0

WS_OVERLAPPEDWINDOW是我认为让你的窗口调整大小。尝试WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX –

+0

窗口可调整大小是我想要的。但我不希望我的OpenGL图形拉伸到初始窗口大小(OpenGL图形不能在窗口创建和调整大小后拉伸,它只能拉伸到INITIAL窗口大小的大小) – jay

回答

3

你永远不会调用glViewport,因此最初的视口大小以使该窗口首次对OpenGL上下文当前的时刻设置为窗口的尺寸。

,以正确反映窗口大小的变化,你必须调用glViewport(设置NDC空间和窗口空间之间的映射),并在顶点着色器应用从顶点位置空间适当的变换到剪辑空间(从裁剪空间的改造NDC是硬连线的)。如果不应用透视分割,则剪辑空间坐标范围[-1,1]将映射到窗口空间视口的范围。