سؤال

I have downloaded the class Setting Up OpenGL in an MFC Control and customized it for my purpose ( showing an image and making zooms and other translates on it ):

OpenGLControl.h

#pragma once  
#include "afxwin.h"
#include "gl\GL.h"
#include "gl\GLU.h"
#include "gdal_priv.h"
#include <algorithm>
#include <math.h>
#include <vector>


using std::vector;
using std::min;


class COpenGLControl2D : public CWnd
{
public:
COpenGLControl2D(void);        //Constructor and destructor
virtual ~COpenGLControl2D(void);

void oglCreate(CRect , CWnd *); //Manually added functions
void oglInitialize(void);
void oglDrawScene(void);
//call this function just first time of calling OnTimer and after setting pImage
//for the next calls of OnTimer and when updating pImage there's no need to call 
//this function. If you do so, your client code slows down
void setImageWidthHeightType(int,int,GDALDataType);
//For second and more calls of OnTimer you should call this function after setting pImage
//In the first call of OnTimer and before calling setImageWidthHeightType(int,int,GDALDataType)
//this function should not be called and if so, the program will encounter an unhandled exception
//because there you still don't have any texture object to be updated
void updataTextureObject();
void ZoomToFullExtent();
 /******************/
 /* PUBLIC MEMBERS */
 /******************/
 // Timer
 UINT_PTR m_unpTimer;
 //you should update value of this member variable whenever you want to call OnTimer
 vector<unsigned char>pImage;
private:
 //used internally by function ZoomIn,ZoomOut and Pan and etc
 float m_fLastX;
 float m_fLastY;
 float m_fPosX;
 float m_fPosY; 
 float m_fZoom;
 //texture object used internally by the class
 GLuint *textures;
 GLsizei numberOfTextures;

private:
 /*******************/
 /* PRIVATE MEMBERS */
 /*******************/
 // Window information
 CWnd *hWnd;
 HDC hdc;
 HGLRC hrc;
 int m_nPixelFormat;
 CRect m_rect;
 CRect m_oldWindow;
 CRect m_originalRect;
 GLsizei ImageWidth;
 GLsizei ImageHeight;
 GLsizei oglWindowWidth;
 GLsizei oglWindowHeight;
 GLenum format;
 GLenum type;
 GLenum target;
 GLint level;
 GLint internalformat;
 GLint border;
 GLint xOffset;
 GLint yOffset;
private:
//used internally by the public member function setImageWidthHeightType of the class
void InitializeTextureObject();
public:
DECLARE_MESSAGE_MAP()
afx_msg void OnPaint();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDraw(CDC *pDC);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnSize(UINT nType, int cx, int cy);
//afx_msg void OnMouseMove(UINT nFlags, CPoint point);
};  

OpenGLControl.cpp

#include "StdAfx.h"
#include "OpenGLControl.h"


COpenGLControl2D::COpenGLControl2D(void)
{
ImageWidth = 0;
ImageHeight = 0;
format = GL_LUMINANCE;
type = GL_BITMAP;
m_fPosX = 0.0f; // X position of model in camera view
m_fPosY = 0.0f; // Y position of model in camera view
m_fZoom = 1.0f; // Zoom on model in camera view
oglWindowWidth = 0;
oglWindowHeight = 0;
textures = new GLuint();
numberOfTextures = 1;
target = GL_TEXTURE_2D;
level = 0;
internalformat = format;
border = 0;
xOffset = 0;
yOffset = 0;
}


COpenGLControl2D::~COpenGLControl2D(void)
{
delete textures;
}

void COpenGLControl2D::oglCreate(CRect rect, CWnd *parent)
{
CString className = AfxRegisterWndClass(CS_HREDRAW |
CS_VREDRAW | CS_OWNDC, NULL,
(HBRUSH)GetStockObject(BLACK_BRUSH), NULL);

char *windowName = "OpenGL";
CA2T TwindowName(windowName);
CString strTwindowName = TwindowName.m_psz;

CreateEx(0, className, strTwindowName, WS_CHILD | WS_VISIBLE |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN, rect, parent, 0);

// Set initial variables' values
m_oldWindow = rect;
m_originalRect = rect;

oglWindowWidth = rect.right - rect.left;
oglWindowHeight = rect.bottom - rect.top;

hWnd = parent;
}


BEGIN_MESSAGE_MAP(COpenGLControl2D, CWnd)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_TIMER()
ON_WM_SIZE()
//ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()


void COpenGLControl2D::OnPaint()
{
//CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CWnd::OnPaint() for painting messages
ValidateRect(NULL);
}


int COpenGLControl2D::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
    return -1;

// TODO:  Add your specialized creation code here
oglInitialize();
return 0;
}


void COpenGLControl2D::oglInitialize(void)
{
// Initial Setup:
//
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32, //bit depth
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
16, // z-buffer depth
0, 0, 0, 0, 0, 0, 0,
};

// Get device context only once.
hdc = GetDC()->m_hDC;

// Pixel format.
m_nPixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, m_nPixelFormat, &pfd);

// Create the OpenGL Rendering Context.



//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
hrc = wglCreateContext(hdc);
GLenum error1 = glGetError();





wglMakeCurrent(hdc, hrc);
// Basic Setup:
//
// Set color to use when clearing the background.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClearDepth(1.0f);
// Turn on backface culling
glFrontFace(GL_CCW);
glCullFace(GL_BACK);
// Turn on depth testing
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);   
// Send draw request
OnDraw(NULL);





//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
wglMakeCurrent(NULL, NULL);
GLenum error9 = glGetError();








}


void COpenGLControl2D::OnDraw(CDC *pDC)
{
wglMakeCurrent(hdc, hrc);
// TODO: Camera controls.
glLoadIdentity();
glScalef(m_fZoom,m_fZoom,1);
GLenum error42 = glGetError();


//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
wglMakeCurrent(NULL,NULL);
GLenum error12 = glGetError();




}




void COpenGLControl2D::OnTimer(UINT_PTR nIDEvent)
{
wglMakeCurrent(hdc, hrc);
// TODO: Add your message handler code here and/or call default
switch (nIDEvent)
{   
case 1:
    {
    // Clear color and depth buffer bits
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Draw OpenGL scene
    oglDrawScene();

    // Swap buffers
    SwapBuffers(hdc);

    break;
    }

    default:
    break;
}

CWnd::OnTimer(nIDEvent);
}





void COpenGLControl2D::setImageWidthHeightType(int localWidth,int localHeight,GDALDataType localType)
{
ImageWidth = localWidth;
ImageHeight = localHeight;

switch (localType)
{
case GDT_Byte:
    {
        type = GL_UNSIGNED_BYTE;
        break;
    }
case GDT_UInt16:
    {
        type = GL_UNSIGNED_SHORT;
        break;
    }
case GDT_Int16:
    {
        type = GL_SHORT;
        break;
    }
case GDT_UInt32:
    {
        type = GL_UNSIGNED_INT;
        break;
    }
case GDT_Int32:
    {
        type = GL_INT;
        break;
    }
}
InitializeTextureObject();
}


void COpenGLControl2D::oglDrawScene(void)
{
wglMakeCurrent(hdc, hrc);
float x0 = 0; // top left corner of image
float y0 = 0;
float x1 = x0 + ImageWidth; // bottom right corner of image
float y1 = y0 + ImageHeight;

glBegin(GL_TRIANGLE_STRIP);
{
    glTexCoord2f(0, 1); glVertex2f(x0, y1);
    glTexCoord2f(0, 0); glVertex2f(x0, y0);
    glTexCoord2f(1, 1); glVertex2f(x1, y1);
    glTexCoord2f(1, 0); glVertex2f(x1, y0);
}




//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
glEnd();
GLenum error24 = glGetError();













//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
wglMakeCurrent(NULL, NULL);
GLenum error26 = glGetError();

}


void COpenGLControl2D::OnSize(UINT nType, int cx, int cy)
{
wglMakeCurrent(hdc, hrc);
CWnd::OnSize(nType, cx, cy);

// TODO: Add your message handler code here

if (0 >= cx || 0 >= cy || nType == SIZE_MINIMIZED) return;

oglWindowWidth = cx;
oglWindowHeight = cy;

// Map the OpenGL coordinates.
glViewport(0, 0, oglWindowWidth, oglWindowHeight);
// Projection view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set our current view perspective
glOrtho(0, oglWindowWidth, oglWindowHeight,0, -1, 1);
// Model view
glMatrixMode(GL_MODELVIEW);




//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
wglMakeCurrent(NULL, NULL);
GLenum error33 = glGetError();

}




void COpenGLControl2D::InitializeTextureObject()
{
wglMakeCurrent(hdc, hrc);
glGenTextures(numberOfTextures,textures);
glBindTexture(GL_TEXTURE_2D, *textures);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexImage2D(target,level,internalformat,ImageWidth,ImageHeight,border,format,type,&pImage[0]);





//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
wglMakeCurrent(NULL, NULL);
GLenum error38 = glGetError();

}


void COpenGLControl2D::updataTextureObject()
{
wglMakeCurrent(hdc, hrc);
glTexSubImage2D(target,level,xOffset,yOffset,ImageWidth,ImageHeight,format,type,&pImage[0]);




//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!PRODUCES ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!
wglMakeCurrent(NULL, NULL);
GLenum error41 = glGetError();

}


void COpenGLControl2D::ZoomToFullExtent()
{
float zoom1 = oglWindowWidth/ImageWidth;
float zoom2 = oglWindowHeight/ImageHeight;
float minZoom = min(zoom1,zoom2);
m_fZoom = floor(minZoom);
OnDraw(NULL);
}

void COpenGLControl2D::FixedZoomIn()
{
m_fZoom = 2*m_fZoom;
}

when I use this class with this code:

COpenGLControl m_oglWindow;
m_oglWindow = new COpenGLControl2D();
CRect rect;
GetDlgItem(IDC_OPENGL)->GetWindowRect(rect);
ScreenToClient(rect);
m_oglWindow -> oglCreate(rect, this);  
const char* filename = "D:\\DataPrevious\\globalMapper.tif";
GDALDataset  *poDataset = NULL ;
GDALAllRegister();
poDataset = (GDALDataset *) GDALOpen( filename, GA_ReadOnly );
m_files -> ReadRasterData(poDataset);
m_oglWindow -> pImage = m_files -> pRasterData;
m_oglWindow -> setImageWidthHeightType(m_files->RasterXSize,m_files->RasterYSize,m_files->eType);

m_oglWindow -> m_unpTimer = m_oglWindow -> SetTimer(1, 1, 0);
m_oglWindow ->updataTextureObject();
m_oglWindow ->ZoomToFullExtent();
m_oglWindow ->FixedZoomIn();  

I get this for my 512x512 image:

enter image description here

you see the texture isn't applied on the geometry. and also the functions FixedZoomIn() and ZoomToFullExtent() seem to do nothing. I think this is maybe because of that the OpenGL does the drawing only in the OnTimer function?
anyway I have used glGetError() after all of the functions that start with the prefix gl and noticed that there is an INVALID_OPERATION(1282) error thrown in the locations that I have specified. I mean it seem that the hrc(rendering context) is not created but I don't understand how could opengl draw that white geometry there? and also glEnd() is throwing that error, too.
Maybe you question why I have used wglMakeCurrent(hdc,hrc) and wglMakeCurrent(NULL,NULL) in several functions in the class?

that is because of what I have studied here, OpenGL two different 3d rendering picture control on single MFC dialog not working

So my question is if the rendering context is not created or the device context is not valid how could opengl draw that white rectangle?
If the problem is something else then what is it?
why the texture isn't applied on the rectangle geometry?
why functions like glScale() that are used in zoom operations don't work?
why glEnd() produces the 1282 error, too? Is it because of functions glTexCoord or glVertex?
and also if the problem is that the context's not created how can I create it please note that I'm getting the error INVALID_OPERATION after the function hrc = wglCreateContext(hdc) when the class is just starting?

هل كانت مفيدة؟

المحلول

So my question is if the rendering context is not created or the device context is not valid how could opengl draw that white rectangle?

I really don't have the patience to wade through the mess the code is you posted. But I'd say, because at the time a rectangle is being drawn, there is a context active.

why the texture isn't applied on the rectangle geometry?

Incomplete picture definition and mipmaping enabled. No texture target bound and active at time of drawing. Such is usually the reason.

why functions like glScale() that are used in zoom operations don't work?

You seem to think that glScale would have some kind of immediate effect on what has been drawn previously. That's not what glScale does. All what glScale does is modifying the currently top element of the active matrix stack. Nothing more.

In general OpenGL doesn't maintain a scene or objects. If you want something to appear differently, you must redraw.

BTW: There's so much mess in your code, besides errorneous use of OpenGL, that I strongly suggest you revisit your C++ 101. There are tons of wrong constructs in your code. For starters consider this (what is the problem with the following, and even wrong if numberOfTextures is not 1?):

textures = new GLuint(); 
…
glGenTextures(numberOfTextures,textures);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top