I'm trying to collate several native PNG images into Opengl & I'm having some roadblocks. I'm already using a Cximage library, so would prefer to stick to this if I can help it.
3 related issues;
PNGs are showing as black & white in OpenGL. The image isn't the issue as Other image types work but I'd rather not convert unless it's easy & doesn't require disk saving or another library.
PNG having black background which are suppose to be transparent.
OpenGL view/Orientation issue. Image is skewed in OpenGL ie not orientated properly. The PNGs contain isometric views, which I'm trying to display.
Sample of code I am currently using;
*And Yes I realise I'm using depreciated Opengl. I need to due to legacy code I am working with.
int MyScene::LoadTexture
{
m_pImgCol = new CxImage((BYTE *)pdatabuffer, (DWORD)filesize, CXIMAGE_FORMAT_PNG);
DWORD iDest(0), iSrc(0);
DWORD dwSize = m_pImgCol->GetWidth()*m_pImgCol->GetHeight();
BYTE *pSrc = m_pImgCol->GetBits();
BYTE *pDest = new BYTE[dwSize * 4];
BYTE *pSrcA = m_pImgAlpha ? m_pImgAlpha->GetBits() : NULL;
BYTE alpha;
for (DWORD iX = 0; iX<dwSize; iX++)
{
alpha = 255;
if (pSrcA)
alpha = pSrcA[iX];
else
{
if (pSrc[iSrc] == 0 && pSrc[iSrc + 1] == 0 && pSrc[iSrc + 2] == 0)
alpha = 0;
}
pDest[iDest++] = pSrc[iSrc++];
pDest[iDest++] = pSrc[iSrc++];
pDest[iDest++] = pSrc[iSrc++];
pDest[iDest++] = alpha;
}
GLuint iTexture=0;
glGenTextures(1, &iTexture);
glBindTexture(GL_TEXTURE_2D, 0);
glTexImage2D(GL_TEXTURE_2D, 0, 4, m_pImgCol->GetWidth(), m_pImgCol->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, pDest);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnable(GL_TEXTURE_2D);
}
int MyScene::DrawGLScene()
{
CRect rWnd;
GetClientRect(&rWnd);
glViewport(0,0,rWnd.Width(),rWnd.Height());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-20 * m_Zoom, 20 * m_Zoom, -15 * m_Zoom, 25 * m_Zoom, 20000, -20000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glTranslatef(0, -0.5f, 0.0f);
glRotatef(m_rx, 1.0f, 0.0f, 0.0f);
glRotatef(m_rz, 0.0f, 0.0f, 1.0f);
glRotatef(m_ry, 0.0f, 1.0f, 0.0f);
DrawScene();
SwapBuffers(m_pView->m_hDC);
return TRUE;
}
int MyScene::DrawScene
{
float dL = -8;
float dR = 8;
float dT = -8;
float dB = 8;
glBindTexture(GL_TEXTURE_2D, 0);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glVertex3f(dL, dT, 0);
glTexCoord2f(0, 0);
glVertex3f(dL, dB, 0);
glTexCoord2f(0, 1);
glVertex3f(dR, dB, 0);
glTexCoord2f(1, 1);
glVertex3f(dR, dT, 0);
glTexCoord2f(1, 0);
glEnd();
}
If necessary I can provide more code, but this is as basic as I can break it down to.
Found http://ysflight.in.coocan.jp/programming/pngdecoder/pngdecodere.html & modified it to read existing buffer. Minimal fuss, no disk saving or library.
got PNG transparency working by adding;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Imaging tearing; seems I had following in wrong order;
glTexCoord2f(0, 0);
glVertex3f(dL, dT, 0);
Related
I'm using Qt 5.7 with c++ on ubuntu 16.04. I'm trying to implement a class that inherits qglwidget, that renders images to the screen at a given rate (3-10 Hz).
In addition to that I want to draw a small rect somewhere on the screen that changes its color from black to white and vice-versa. It should switch from white to black when the image appears, and switch back to black some predefined time before the next image comes.
Right now I'm using a texture to load the images (from QImage objects), using
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
and this is my paintGL() overload:
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
drawTexture(QRect(0,0,1,1),texture,GL_TEXTURE_2D);
swapBuffers();
glDisable(GL_TEXTURE_2D);
and I was wondering if it possible to draw on the widget and make it render both the rect and image at the same time. I've tried using QPainter but kept getting that drawing the rect made the image disappear(the rect shouldn't be on the image, but on some corner of the widget where nothing is drawn now).
Would appreciate any help!
This is a minimal sample application which mixes OpenGL code and QPainter in paint handler:
#include <QtWidgets>
#include <QOpenGLFunctions_1_1>
// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;
extern const struct Image {
guint width;
guint height;
guint bytes_per_pixel; /* 3:RGB, 4:RGBA */
guint8 pixel_data[1];
} fluffyCat;
class GLWidget: public QOpenGLWidget, protected QOpenGLFunctions_1_1 {
private:
float _step;
GLuint _idTex;
QTimer _qTimer;
public:
GLWidget(QWidget *parent = 0):
QOpenGLWidget(parent),
_step(0.0f), _idTex(0)
{
_qTimer.setInterval(100); // 100 ms -> 10 Hz
QObject::connect(&_qTimer, &QTimer::timeout,
this, &GLWidget::timeout);
}
protected:
virtual void initializeGL();
virtual void paintGL();
private:
void timeout();
};
void GLWidget::initializeGL()
{
initializeOpenGLFunctions();
glClearColor(0.525, 0.733f, 0.851, 1.0);
glGenTextures(1, &_idTex);
glBindTexture(GL_TEXTURE_2D, _idTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, fluffyCat.width, fluffyCat.height, 0,
GL_RGB, GL_UNSIGNED_BYTE, fluffyCat.pixel_data);
glBindTexture(GL_TEXTURE_2D, 0);
_qTimer.start();
}
void GLWidget::paintGL()
{
// prepare OpenGL rendering
QPainter qPainter(this);
qPainter.beginNativePainting();
// do OpenGL rendering
glColor3f(1.0f, 1.0f, 1.0f);
bool tex2dOld = glIsEnabled(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
static GLfloat envColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
glBindTexture(GL_TEXTURE_2D, _idTex);
float x = sin(_step) * 0.5f, y = cos(_step) * 0.5f;
#if 0 // does not work (no tex-coords)
glRectf(x - 0.5f, y - 0.5f, x + 0.5f, y + 0.5f);
#else // (not) 0
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glTexCoord2i(0, 1);
glVertex2f(x - 0.5f, y - 0.5f);
glTexCoord2i(1, 1);
glVertex2f(x + 0.5f, y - 0.5f);
glTexCoord2i(1, 0);
glVertex2f(x + 0.5f, y + 0.5f);
glTexCoord2i(0, 0);
glVertex2f(x - 0.5f, y + 0.5f);
glEnd();
#endif // 0
glBindTexture(GL_TEXTURE_2D, 0);
//if (!tex2dOld) glDisable(GL_TEXTURE_2D);
// prepare Qt painting
qPainter.endNativePainting();
// do Qt painting (HUD)
QPen qPen;
qPen.setWidth(1);
qPen.setColor(QColor(Qt::black));
qPen.setStyle(Qt::SolidLine);
qPainter.resetMatrix();
qPainter.setPen(qPen);
qPainter.drawLine(0, 0, width(), height());
qPainter.drawLine(0, height(), width(), 0);
}
void GLWidget::timeout()
{
_step = fmod(_step + 0.1, 2 * 3.141);
update(); // force redraw
}
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QMainWindow win;
GLWidget view3d;
win.setCentralWidget(&view3d);
win.show();
return app.exec();
}
and the source for the texture image:
/* GIMP RGB C-Source image dump (fluffyCat.cc) */
// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;
struct Image {
guint width;
guint height;
guint bytes_per_pixel; /* 3:RGB, 4:RGBA */
guint8 pixel_data[16 * 16 * 3 + 1];
};
extern const Image fluffyCat;
const Image fluffyCat = {
16, 16, 3,
"x\211s\215\232\200gw`fx`at[cx^cw^fu\\itZerWn|ap~cv\204jnzedq^fr^kzfhv^Ra"
"GRbMWdR\\jXer^qw_\311\256\226\271\253\235\275\264\252\315\277\260\304\255"
"\231u~i\213\225\207l{fly`jx\\^nRlz_z\206nlx`t~i\221\211s\372\276\243\375"
"\336\275\376\352\340\356\312\301\235\216\212judgwcl~f\212\226u}\206h\212"
"\224q\231\237z\232\236{\216\225v\225\230\200\306\274\244\376\360\327\376"
"\361\331\376\360\341\326\275\272\253\240\244{\203p\202\220xp~e{\204^\222"
"\230n\212\217g\240\242{\234\236z\214\222r\270\271\247\360\353\340\376\370"
"\336\376\363\334\375\357\336\310\254\262\232\223\234\\gRfrX\204\220z\212"
"\225g\225\232j\254\255\177\252\250{\225\226u\304\302\265\374\365\351\376"
"\375\366\376\367\341\376\361\320\374\346\324\306\241\242\237\232\235n{fj"
"xckyfu~fUX#VZCfnT\231\231\207\374\374\371\377\372\354\376\376\374\376\376"
"\372\376\362\332\375\340\301\341\300\264\260\253\262jvdbq\\XkVJTDNTCCG8O"
"TE\322\321\313\377\377\375\376\376\373\376\377\376\376\376\375\376\374\362"
"\376\360\342\344\311\306\250\244\254R_PL^HXkT<#2OP#`dP\217\220\177\374\374"
"\370\377\377\374\376\375\371\377\377\376\376\374\360\377\367\336\376\350"
"\316\342\303\274\246\236\245jtbXdQTdNQYGU\\KchV\317\315\302\377\376\372\377"
"\376\367\376\373\360\377\376\367\376\366\337\376\355\312\374\331\271\323"
"\263\251\216\214\214\\hTP^HL\\FR[LMXI^dW\355\352\342\376\375\366\377\374"
"\360\376\374\361\376\374\361\376\356\321\374\331\264\374\330\266\330\270"
"\260\200||Y`SLVE>K9BJ<CN?VYP\347\330\322\376\366\345\376\363\330\376\367"
"\337\377\372\350\374\342\314\326\243\210\375\350\314\352\317\304shc^`TV`"
"RVbT>B4IS?PTD\244\232\216\374\355\320\376\354\311\376\351\306\376\362\332"
"\374\344\321\267\206u\375\362\337\326\274\272\\POMNBT]LNZH:<*<A*TV>OI;\242"
"\222\207\340\304\243\375\335\262\372\336\272\376\361\334\320\241\212\374"
"\352\322\266\233\237c\\WFH;MR>\\`F~xP\220\214[pqE\211\202\\g]=\230\214`\313"
"\266\207\344\303\240\362\336\274\323\257\201\333\304\240\305\252\204\254"
"\232p\216\206\\\206\203U\232\224b\234\244b\246\257m\220\232`\224\227h~\202"
"W\206\213]\204\210W\227\227i|\177RvzNlsGrtJwtLz}N{\204RlxF",
};
(Sorry, for the low image quality. Hi-res picture whould have been too large for this site.)
The two files have to compiled and to to be linked together. (Instead of using a header, I simply (re-)declared the variable in fluffyCat.cc at the beginning of the other file.)
The Qt project file testQGLWidgetHUD.pro:
SOURCES = testQGLWidgetHUD.cc fluffyCat.cc
QT += widgets opengl
By the way, I didn't realize the OP was asking for QGLWidget. The sample uses the new QOpenGLWidget which is recommended since Qt5+.
The QTimer is used for very simple kind of animation (to show that periodical painting is done).
Btw. I stumbled upon a mistake (which hit me not the first time...)
It is important to set GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER because these are two of the rare OpenGL states which do not work if left with default values.
Well, finally this worked for adding a small rect -
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
QPainter qPainter(this);
QPainterPath path;
path.addRect(10, 10, 30,30);
QPen pen(Qt::black, 1);
qPainter.setPen(pen);
qPainter.fillPath(path, Qt::black);
qPainter.drawPath(path);
qPainter.end();
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glShadeModel( GL_FLAT );
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_TEXTURE_2D);
glColor3f(0.5, 0.5, 0);
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.5f, -0.5f); // vertex 1
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.5f, 0.5f); // vertex 2
glTexCoord2f(1.0f, 0.0f); glVertex2f(-0.5f, 0.5f); // vertex 3
glTexCoord2f(1.0f, 1.0f); glVertex2f(-0.5f, -0.5f); // vertex 4
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
I am trying to render a simple 2d Image with the QOpenGLWidget using a quad as a texture. But no matter what I am trying, I always get a black box.
I have read many tutorials, I have a simple pixelbuffer like this
uchar* m_pData;
which stores my RGB values. This is valid, since I have it tested with glDrawPixles(). I will post the three most important functions considering the OpenGLWidget.
initializeGL() first:
void QGLImageviewer::initializeGL()
{
initializeOpenGLFunctions();
// Clear the color
float r = ((float)m_backColor.darker().red())/255.0f;
float g = ((float)m_backColor.darker().green())/255.0f;
float b = ((float)m_backColor.darker().blue())/255.0f;
glClearColor(r,g,b,1.0f);
// Set shading model.
glShadeModel(GL_SMOOTH);
// Set the viewport
glViewport(0.f, 0.f, m_origW, m_origH);
// Init. Projection Matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, m_origW, m_origH,0.0,1.0,-1.0);
// Init Modelview Matrix
glClearColor(0.f, 0.f, 0.f, 1.f);
// Enable texturing
glEnable(GL_TEXTURE_2D);
// Generate texture ID
glGenTextures(1, &m_textureID);
// Bind texture ID
glBindTexture(GL_TEXTURE_2D, m_textureID);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Generate Texture, and assign pixles to our texture ID
if (m_pData != nullptr)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_origW, m_origH, 0, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*)m_pData);
}
else
{
qCritical("Buffer is empty!!");
}
// Unbind texture
glBindTexture(GL_TEXTURE_2D, NULL);
// Check for Error
GLenum error_ = glGetError();
if (error_ != GL_NO_ERROR)
{
qCritical("Error Loading Texture!");
}
}
Then paintGL():
void QGLImageviewer::paintGL()
{
makeCurrent();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Clear Screen And Depth Buffer
glClear(GL_COLOR_BUFFER_BIT);
if (!(m_renderQtImg->isNull()))
{
//QImage image;
int imWidth = m_renderQtImg->width();
int imHeight = m_renderQtImg->height();
// The image has to be resized to fit the widget
if (imWidth != this->size().width() &&
imHeight != this->size().height())
{
imWidth = this->size().width();
imHeight = this->size().height();
}
else
{
//image = *m_renderQtImg;
imWidth = m_origW;
imHeight = m_origH;
}
if (m_textureID != 0)
{
glMatrixMode(GL_MODELVIEW);
// Remove any previous transformations
glLoadIdentity();
glPushMatrix();
// Move to rendering point
glTranslatef(0.f, 0.f, 0.f);
glColor3f(0.0f, 0.0f, 0.5f);
// Set texture ID
glBindTexture(GL_TEXTURE_2D, m_textureID);
glBegin(GL_QUADS);
glTexCoord2f(0.f, 0.f); glVertex2f(0.f, 0.f);
glTexCoord2f(1.f, 0.f); glVertex2f(imWidth, 0.f);
glTexCoord2f(1.f, 1.f); glVertex2f(imWidth, imHeight);
glTexCoord2f(0.f, 1.f); glVertex2f(0.f, imHeight);
glEnd();
//glDisable(GL_TEXTURE_2D);
glPopMatrix();
glFlush();
}
}
}
And last but not least resizeGL():
void QGLImageviewer::resizeGL(int width, int height)
{
makeCurrent();
glViewport(0,0,(GLint)width,(GLint)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluOrtho2D(0.0, width, 0.0, height);
glOrtho(0.0, width, 0.0, height, 0.0, 1.0);
}
I am using Qt5.6 and the Microsoft Visual Studio 2015 compiler.
Damn, the problem was on
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_origW , m_origH, 0, GL_RGB, GL_UNSIGNED_BYTE, (float*)m_pData);
My member variables m_orgiW and m_orgiH were initialized to 0. So quite unsurprising that my code did not work.
For the record I will post my running code, the three most important functions of the QOpenGLWidget, hope that it will be useful to somebody with the same issue.
void QGLImageviewer::initializeGL()
{
initializeOpenGLFunctions();
float r = ((float)m_backColor.darker().red())/255.0f;
float g = ((float)m_backColor.darker().green())/255.0f;
float b = ((float)m_backColor.darker().blue())/255.0f;
glClearColor(r,g,b,1.0f);
// Generate texture ID
glGenTextures(1, &m_textureID);
// Bind texture ID
glBindTexture(GL_TEXTURE_2D, m_textureID);
if (m_pData != nullptr)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_origW , m_origH, 0, GL_RGB, GL_UNSIGNED_BYTE, (float*)m_pData);
}
else
{
qCritical("Buffer is empty!!");
}
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); //IMPORTANT FOR NON POWER OF 2 TEXTURES
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Enable texturing Mapping
glEnable(GL_TEXTURE_2D);
// Enable Smooth Shading
glShadeModel(GL_SMOOTH);
// Black Background
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
// Depth Buffer Setup
glClearDepth(1.0f);
// Enables Depth Testing
glEnable(GL_DEPTH_TEST);
// Type of depth testing to do
glDepthFunc(GL_LEQUAL);
// Really Nice Perspective Calculations
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
// Unbind Texture
glBindTexture(GL_TEXTURE_2D, NULL);
}
Now paintGL()
void QGLImageviewer::paintGL()
{
makeCurrent();
// Clear Screen And Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_textureID);
glBegin(GL_QUADS);
// Drawing the quad with the texture mapped on it
//
// OpenGL 2D Coordinates
// Sticking with the Coordinate Convention mentioned here
glTexCoord2f(1.0f, 0.0f); glVertex2f(m_width, 0.0f); // vertex 1
glTexCoord2f(1.0f, 1.0f); glVertex2f(m_width, m_height); // vertex 2
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, m_height); // vertex 3
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); // vertex 4
glEnd();
}
And resizeGL()
void QGLImageviewer::resizeGL(int width, int height)
{
makeCurrent();
m_width = width;
m_height = height;
// Compute aspect ratio of the new window
if (height == 0) height = 1; // To prevent divide by 0
GLfloat aspect = (GLfloat)width / (GLfloat)height;
// Set the viewport to cover the new window
glViewport(0, 0, width, height);
// Set the aspect ratio of the clipping area to match the viewport
glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity(); // Reset the projection matrix
glOrtho(0, m_width/ m_zoomFactor, m_height/ m_zoomFactor,0, -1, 1);
}
I started with opengl texturing and everything was working well. Now I am trying to load a bmp and make white part transparent using glEnable(GL_BLEND); and glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
This is my source code:
float kSpeedForw=0.0f;
GLuint texture[1];
CCamera g_Camera;
GLfloat xrot = 0;
GLfloat yrot = 0;
GLfloat zrot = 0;
bool g_bFullScreen = true;
HWND g_hWnd;
RECT g_rRect;
HDC g_hDC;
HGLRC g_hRC;
HINSTANCE g_hInstance;
float jump = -0.1;
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f, 1.0f };
void Init(HWND hWnd)
{
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); // Position The Light
glEnable(GL_LIGHT1); // Enable Light One
glColor4f(1.0f, 1.0f, 1.0f, 0.5); // Full Brightness. 50% Alpha
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
g_hWnd = hWnd;
GetClientRect(g_hWnd, &g_rRect);
InitializeOpenGL(g_rRect.right, g_rRect.bottom);
g_Camera.PositionCamera(0, 1.5f, 6, 0, 1.5f, 5, 0, 1, 0);
ShowCursor(false);
}
GLuint LoadTexture(const char * filename)
{
glEnable(GL_TEXTURE_2D);
GLuint texture;
int width, height;
unsigned char * data;
FILE * file;
file = fopen(filename, "rb");
if (file == NULL) return 0;
if (filename=="Data/weed.bmp"){
width = 200;
height = 200;
}
if (filename == "Data/gun.bmp"){
width = 300;
height = 300;
}
data = (unsigned char *)malloc(width * height * 3);
fread(data, width * height * 3, 1, file);
fclose(file);
for (int i = 0; i < width * height; ++i)
{
int index = i * 3;
unsigned char B, R;
B = data[index];
R = data[index + 2];
data[index] = R;
data[index + 2] = B;
}
if (filename == "Data/weed.bmp"){
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
free(data);
}
if (filename == "Data/gun.bmp"){
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3,width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
return texture;
}
WPARAM MainLoop() // main function
{
MSG msg;
Init(g_hWnd);
glClearColor(0, 0, 255, 0);
while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if (LockFrameRate(60))
{
g_Camera.SetViewByMouse();
kSpeedForw = 0;
if (jump > -0.1)jump-=0.01;
CheckForMovement();
g_Camera.MoveCamera(kSpeedForw, jump);
RenderScene();
}
}
DeInit();
return(msg.wParam);
}
void RenderScene()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glDisable(GL_BLEND);
glEnable(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(g_Camera.m_vPosition.x, g_Camera.m_vPosition.y, g_Camera.m_vPosition.z,
g_Camera.m_vView.x, g_Camera.m_vView.y, g_Camera.m_vView.z,
g_Camera.m_vUpVector.x, g_Camera.m_vUpVector.y, g_Camera.m_vUpVector.z);
GLuint texture;
texture = LoadTexture("Data/weed.bmp");
glBindTexture(GL_TEXTURE_2D, texture);
glBegin(GL_QUADS);
float i = 0;
glColor3f(1,1,1);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-10 + i / 5, 0, 10 - i / 5);
glTexCoord2f(50.0f, 0.0f);
glVertex3f(-10 + i / 5, 0, -10 + i / 5);
glTexCoord2f(50.0f, 50.0f);
glVertex3f(10 - i / 5, 0, -10 + i / 5);
glTexCoord2f(0.0f, 50.0f);
glVertex3f(10 - i / 5, 0, 10 - i / 5);
glEnd();
////////////////////////////////////////////////////////////HUD
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SMOOTH);
glEnable(GL_BLEND); // Turn Blending On
int vPort[4];
glGetIntegerv(GL_VIEWPORT, vPort);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, vPort[2], 0, vPort[3], -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
GLuint ruka;
ruka = LoadTexture("Data/gun.bmp");
glBindTexture(GL_TEXTURE_2D, ruka);
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0, 0);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(450,0);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(450,450);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0,450);
glEnd();
SwapBuffers(g_hDC);
}
The code works well for loading and rendering the platform(weed.bmp) and it also loads and renders gun fine. But big part of gun.bmp is white. I was hoping to get that part transparent. I was also hoping to add more HUD features, which would also need to be partly transparent.
My gun.bmp file: https://drive.google.com/file/d/0BxxlNcAI0eh9cHZGd1ZfMTFwYmM/view?usp=sharing
If you know a solution of this problem please post it. Thanks
You load image as GL_RGB, you want GL_RGBA to have an alpha channel.
Also, you need a 32 bits Bitmap (8 bits/channel × 4 channels = 32 bits).
I'm currently trying to interop Cuda and OpenGL on my project but it's proving to be a challenging task. I'm currently using the following code:
GLuint _frameTextureGL;
cudaGraphicsResource_t _frameTextureCUDA;
void GLInit(){
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &_frameTextureGL);
glBindTexture(GL_TEXTURE_2D, _frameTextureGL);
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RES_X, RES_Y, 0, GL_RGBA, GL_FLOAT, NULL);
}
glBindTexture(GL_TEXTURE_2D, 0);
CudaErrorCheck(cudaGraphicsGLRegisterImage(&_frameTextureCUDA, _frameTextureGL, GL_TEXTURE_2D, cudaGraphicsRegisterFlagsWriteDiscard));
}
void DrawFrame(){
LaunchKernel();
glBindTexture(GL_TEXTURE_2D, _frameTextureGL);
{
glBegin(GL_QUADS);
{
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0.0f, 1.0f);
}
glEnd();
}
glBindTexture(GL_TEXTURE_2D, 0);
glFinish();
glutPostRedisplay();
}
LaunchKernel(){
CudaErrorCheck (cudaGraphicsMapResources(1, &_frameTextureCUDA)); //error happens here
cudaArray_t frameCudaArray;
CudaErrorCheck( cudaGraphicsSubResourceGetMappedArray(&frameCudaArray, _frameTextureCUDA, 0, 0));
cudaResourceDesc frameCudaArrayResourceDesc;
frameCudaArrayResourceDesc.resType = cudaResourceTypeArray;
frameCudaArrayResourceDesc.res.array.array = frameCudaArray;
cudaSurfaceObject_t frameCudaSurfaceObject;
CudaErrorCheck( cudaCreateSurfaceObject(&frameCudaSurfaceObject, &frameCudaArrayResourceDesc));
KernelFunction<< <(RES_X * RES_Y / CUDA_THREADS_PER_BLOCK) + 1, CUDA_THREADS_PER_BLOCK >> >( frameCudaSurfaceObject);
CudaErrorCheck( cudaDestroySurfaceObject(frameCudaSurfaceObject));
CudaErrorCheck( cudaGraphicsUnmapResources(1, &_frameTextureCUDA));
cudaStreamSynchronize(0);
}
__global__ void KernelFunction(cudaSurfaceObject_t frameCudaSurfaceObject){
const int maxIndex = RES_X * RES_Y;
int idx = threadIdx.x + blockDim.x * blockIdx.x;
if (idx > maxIndex) return;
surf2Dwrite(make_float4(1.0f, 0.0f, 0.0f, 1.0f), frameCudaSurfaceObject, 0, 0);
//surf2Dwrite(make_float4(1.0f, 0.0f, 0.0f, 1.0f), frameCudaSurfaceObject, (idx % RES_X) * 4, idx / RES_X);
}
The problem is that the surf2Dwrite on the kernel will cause other parts of my code to get an error.
With the code on it's current state my project runs but it doesn't show anything (which I suppose is normal since I'm not filling the surface object correctly).
But if I change my X & Y coordinates to anything other than (0,0) (by uncommenting the last line for example) then I get a "missaligned error" on the first line of the LaunchKernel function. (this error only shows on the second frame, not the first)
I've based my code on this other answer so I assume that part to be correct.
Surface uses coordinates in bytes, not in elements. For float4 the x coordinate should be x * 16 (or x * sizeof(float4)), not x * 4:
surf2Dwrite(make_float4(1.0f, 0.0f, 0.0f, 1.0f), frameCudaSurfaceObject,
(idx % RES_X) * sizeof(float4), idx / RES_X);
To make my maze type game faster I decided to put my drawed ball inside a texture, because i have to draw it otherwise once for every room and I'm drawing it like a concave polygon using the stencil buffer, it takes more time than using a texture. The problem is, that I'm getting it inside a texture correctly from the back buffer when I'm rendering the third frame since the start of the game and my question is, why is it like so?
When I'm using a texture from the thirst frame, I'm having texture with solid white color, so it has nothing inside. When I'm using textures from the second frame, then I have only the black background of the desired texture and when I take the texture from the third frame, then I have desired texture. For frame count I use the static variable "done" inside the "drawTexture" function.
Copying from the first frame:
Copying from the second frame:
Copying from the third frame (desired outcome):
void DrawBall::drawTexture(float imageD) {
static int done = 0;
if (done < 3) {
drawToTexture(imageD);
done++;
}
glEnable(GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture);
glColor3f(1, 1, 1);
glBegin (GL_QUADS);
glTexCoord2f (0.0, 0.0); glVertex3f (0.0, 0.0, -imageD);
glTexCoord2f (1.0, 0.0); glVertex3f (5.0, 0.0, -imageD);
glTexCoord2f (1.0, 1.0); glVertex3f (5.0, 5.0, -imageD);
glTexCoord2f (0.0, 1.0); glVertex3f (0.0, 5.0, -imageD);
glEnd ();
glDisable(GL_TEXTURE_2D);
}
void DrawBall::drawToTexture(float imageD) {
int viewport[4];
glGetIntegerv(GL_VIEWPORT, (int*) viewport);
int textureWidth = 64;
int textureHeight = 64;
texture = genEmptyTexture(textureWidth, textureHeight);
glViewport(0, 0, textureWidth, textureHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, 1, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/*
This function calculates the vertexes for the ball
inside a vector<vector<float>> variable "test"
*/
_calculateCircleVertexes(0.0f, 0.0f, -2.0f, 0.249f, &test, 20);
_displayBall(&test, 0.0f, 0.0f, 0.5f, -2.0f, &*smallBallColor);
glBindTexture(GL_TEXTURE_2D, texture);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, textureWidth, textureHeight, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)viewport[2] / (GLfloat)viewport[3], 1.0f, imageD + 10.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
GLuint DrawBall::genEmptyTexture(unsigned int width, unsigned int height) {
GLuint txtIndex;
glGenTextures(1, &txtIndex);
glBindTexture(GL_TEXTURE_2D, txtIndex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
return txtIndex;
}
void DrawBall::_displayBall(vector<vector<GLfloat>> *vertexes, GLfloat x, GLfloat y
, GLfloat imageW, GLfloat imageD, color *color) {
glTranslatef(x, y, imageD);
glClearStencil(0);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_NEVER, 0, 1);
glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);
glBegin(GL_POLYGON);
vector<vector<GLfloat>>::iterator it = vertexes->begin();
for (; it != vertexes->end(); it++) {
glVertex3f((*it)[0], (*it)[1], 0.0f);
}
glEnd();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, 1, 1);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
glColor3f(color->r, color->g, color->b);
glBegin(GL_QUADS);
glVertex3f(-(imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), -(imageW / 2.0f), 0.0f);
glVertex3f( (imageW / 2.0f), (imageW / 2.0f), 0.0f);
glVertex3f(-(imageW / 2.0f), (imageW / 2.0f), 0.0f);
glEnd();
glDisable(GL_STENCIL_TEST);
glTranslatef(x, y, -imageD);
}
You should not use the window framebuffer (which includes both back- and frontbuffer) for render to texture operations. It just breaks to easily (you've experienced it). Instead use a so called Framebuffer Object, with the texture as rendering target.
Well, Datenwolf, thank you for your suggestion, you are probably right but I just want to use the advanced stuff as less as possible and I found my mistakes. I didn't get the desired outcome before the second frame because I didn't have yet enabled stencil test. Before the first frame I didn't get the desired outcome because in the window creation Windows sends WM_SIZE message and I had the draw message inside it but at that time the OpenGL isn't set up properly yet.