Reputation: 1071
I wrote an OpenGL program in windows about showing a texture on window. But it turns out the final result stretching to the initial size of window regardless there is no reference to window size in OpenGL commands. What I want to achieve is to draw the full texture even if the initial window size is smaller than the size of texture, no stretching is wanted. What did I miss?
code below:
#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);
}
Upvotes: 0
Views: 1344
Reputation: 162367
You never call glViewport
and thus the initial viewport size is set to the window dimensions at the moment of making OpenGL context current on the window for the first time.
To properly reflect window size changes you must call glViewport
(for setting the mapping between NDC space and window space) and also in the vertex shader apply an appropriate transformation from vertex position space into clip space (the transformation from clip space to NDC is hardwired). If you don't apply perspective divide then the clip space coordinate range [-1,1] maps to the extents of the window space viewport.
Upvotes: 3