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);
Related
I'm attempting to to render a jpeg image (1024x1024 pixels) in the form of an FFmpeg AVFrame as a texture in OpenGL. What I get instead is something that appears as a 1024x1024 dark green quad:
The code to render the AVFrame data in OpenGL is shown below. I have convinced myself that the raw RGB data held within the FFmpeg AVFrame data is not solely dark green.
GLuint g_texture = {};
//////////////////////////////////////////////////////////////////////////
void display()
{
// Clear color and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); // Operate on model-view matrix
glEnable(GL_TEXTURE_2D);
GLuint texture = g_texture;
glBindTexture(GL_TEXTURE_2D, texture);
// Draw a quad
glBegin(GL_QUADS);
glVertex2i(0, 0); // top left
glVertex2i(1024, 0); // top right
glVertex2i(1024, 1024); // bottom right
glVertex2i(0, 1024); // bottom left
glEnd();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glFlush();
}
/* Initialize OpenGL Graphics */
void initGL(int w, int h)
{
glViewport(0, 0, w, h); // use a screen size of WIDTH x HEIGHT
glEnable(GL_TEXTURE_2D); // Enable 2D texturing
glMatrixMode(GL_PROJECTION); // Make a simple 2D projection on the entire window
glOrtho(0.0, w, h, 0.0, 0.0, 100.0);
glMatrixMode(GL_MODELVIEW); // Set the matrix mode to object modeling
//glTranslatef( 0, 0, -15 );
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the window
}
//////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
std::shared_ptr<AVFrame> apAVFrame;
if (!load_image_to_AVFrame(apAVFrame, "marble.jpg"))
{
assert(false);
return 1;
}
// From here on out, the AVFrame is RGB interleaved
// and is sized to 1,024 x 1,024 (power of 2).
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(1060, 1060);
glutInitWindowPosition(0, 0);
glutCreateWindow("OpenGL - Creating a texture");
glGenTextures(1, &g_texture);
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, g_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, apAVFrame->width,
apAVFrame->height, 0, GL_RGB, GL_UNSIGNED_BYTE,
apAVFrame->data[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* We will use linear interpolation for magnification filter */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); /* We will use linear interpolation for minifying filter */
initGL(1060, 1060);
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
Environment:
Ubuntu 18.04
GCC v8.2
EDIT: As per #immibis' suggestion below, it all works when I change the rendering of the quad to:
// Draw a quad
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2i(0, 0); // top left
glTexCoord2f(1, 0);
glVertex2i(1024, 0); // top right
glTexCoord2f(1, 1);
glVertex2i(1024, 1024); // bottom right
glTexCoord2f(0, 1);
glVertex2i(0, 1024); // bottom left
glEnd();
You forgot to give your vertices texture coordinates, so all the pixels on your screen are reading the same pixel from the texture. (The top-left, or wherever the default texture coordinates are)
Use glTexCoord2f before glVertex2i to set the texture coordinates for the vertex. They go from 0 on the top/left of the texture, to 1 on the bottom/right, so the corners of the texture are 0,0, 1,0, 1,1 and 0,1.
I'm developing a C++ application and I need to use an interface made in openGL. I have a grey background, some squared textures over the background and some text written next to the textures. The text is yellow but when I click with mouse on the window or I change the textures, the text turns grey (a different grey from the background) and I don't know why! Here is the code and screenshots:
int main(int argc, char** argv){
[...]
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
glEnable(GL_POINT_SMOOTH);
// Render the scene
glutDisplayFunc(display);
glutReshapeFunc(reshape);
// Turn the flow of control over to GLUT
glutMainLoop();
[...]
}
void display(void){
glClearColor(0.2f, 0.2f, 0.2f, 0.5f); //Background color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set up viewing transformation, looking down -Z axis
glLoadIdentity();
gluLookAt(posx, 0, -g_fViewDistance, 0, 0, -1, 0, 1, 0);
// Render the scene
glMatrixMode(GL_COLOR);
glColor3f(1.0f, 1.0f, 0.0f); // Textcolor
drawOnScreen(); // Draw text on screen
glMatrixMode(GL_MODELVIEW);
loadSquare(); // Load texture
glutSwapBuffers();
}
void reshape(GLint width, GLint height){
interface->setWindowWidth(width);
interface->setWindowHeight(height);
glViewport(0, 0, g_Width, g_Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(65.0, (float)g_Width / g_Height, g_nearPlane, g_farPlane);
glMatrixMode(GL_MODELVIEW);
}
void printStringOnVideo(void* font, char* s){
if (s && strlen(s)) {
while (*s) {
glutBitmapCharacter(font, *s);
s++;
}
}
}
void drawOnScreen(){
GLfloat x, y;
// Draw the strings, according to the current mode and font.
x = 2.90f;
y = 0.80f;
glRasterPos2f(x, y);
int len;
char s[] = { 'H', 'E', 'L', 'L', 'O', '\0' };
len = (int)strlen(s);
printStringOnVideo(GLUT_BITMAP_TIMES_ROMAN_24, s);
}
The loadSquare() function applies texture to squares. Its main feature is calling the class method for loading textures on squares:
void P300Square::setTexture(bool func){
// Se func = 0 allora carico la texture, viceversa il flash
string tmp = "";
if (func == false)
tmp = texturePath;
else
tmp = textureFlashPath;
GLuint texture = SOIL_load_OGL_texture
(
tmp.c_str(),
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT
);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glColor3ub(50, 50, 50);
glEnable(GL_BLEND);
glBegin(GL_QUADS);
glColor4f(0.5f, 0.0, 0.0f, 0.8f);
// Top Left
glTexCoord2f(0, 1);
glVertex2f(u, v);
// Top Right
glTexCoord2f(1, 1);
glVertex2f(u + size, v);
// Bottom Right
glTexCoord2f(1, 0);
glVertex2f(u + size, v + size);
// Bottom Left
glTexCoord2f(0, 0);
glVertex2f(u, v + size);
glEnd();
glDisable(GL_BLEND);
}
Can please someone help me? Thank you!
You should disable GL_TEXTURE_2D before you draw the bitmap font.
Internally, glutBitmapCharacter() uses glBitmap. This function maps the bitmap to a rectangle to the screen and generates a fragment for every framebuffer pixel in that rectangle where the bitmap is 1. Those fragments get the associated data from the values associated with the current raster position.
The generated fragments are processed like every other fragment (i.e. the ones generated by drawing primitives like lines or triangles). So stuff like texturing, lighting, fog, blending and so on will also affect everything drawn by glBitmap. Due to the fact that all fragments generated by a single bitmap get the same associated data, they all will get the same texture coordinate. Since you left texturing on, the GL textures all of these fragments with the very same sample from the texture, so that they all appear in the same color.
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);
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 making a particle fountain in openGL, I have the particles functioning properly. I decided to add a plane to make it look like they are bouncing off from it. What I'm trying to get is something like this
Unfortunately what I'm getting is this
the plain doesn't seem to be appearing at all. I tried messing with the co-ordinates and that doesn't seem to do anything. This is the image I'm using as the texture, it's a 256 X 256 24bit bmp.
I load the texture in the init function, then call it before I render the particles in the following function
void Load_Plane(){
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
glColor4f(0.0f, 0.2f, 0.2f, 0.5f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, txPlane);
glBegin(GL_QUADS);
glNormal3f(-10.0f, 0.0f, -10.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-10.0f, 0.0f, 10.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f( 10.0f, 0.0f, 10.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f( 10.0f, 0.0f, -10.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-10.0f, 0.0f, -10.0f);
glEnd();
}
full code
// particle_fountain.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<stdlib.h>
#include <stdio.h>
#include<Windows.h>
#include <time.h>
#include <GL\glut.h>
#include<GL\GLU.h>
#define MAX_PARTICLES 200 //max number of particles
#define MAX_BOUNCE_COUNT 5 //number of times a particle should bounce
#define MAX_PARTICLE_AGE 95
//Colours
float R = 0.8f;
float G = 0.2f;
float B = 0.0f;
float cR = 0.001f;
float cG = 0.002f;
float cB = 0.003f;
float Size = 0.02f; //size for points
GLuint txParticle;
GLuint txPlane;
struct PARTICLE {
float X,Y,Z; // Current position
float sX,sY,sZ; // Current Speed/Movement
float tX,tY,tZ; // Target Speed/Movement
float R,B,G; // Particle Colour
bool Active; // Is particle Active
int Age; // Age of the particle
int MaxAge; // Maximum Age before particle dies
int BounceCount;
} Particles[MAX_PARTICLES];
void Init_Particles();
void Activate_Particles();
void Adjust_Particles();
void Render_Particles();
bool LoadBitmapTexture(char * FileName, GLuint &texid);
void timer(int extra);
void Load_Plane();
void DrawGLscene();
void Reshape(GLsizei w, GLsizei h);
int main(int argc, char** argv){
glutInit(&argc,argv);
glutInitDisplayMode( GLUT_RGBA| GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow("Particle fountain");
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, -0.9, -3.0);
Init_Particles();
glutDisplayFunc(DrawGLscene);
glutTimerFunc(0, timer, 0);
glutMainLoop();
}
void timer(int extra)
{
glutPostRedisplay();
glutTimerFunc(20, timer, 0);
}
void Load_Plane(){
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
glColor4f(0.0f, 0.2f, 0.2f, 0.5f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, txPlane);
glBegin(GL_QUADS);
glNormal3f(-10.0f, 0.0f, -10.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-10.0f, 0.0f, 10.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f( 10.0f, 0.0f, 10.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f( 10.0f, 0.0f, -10.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-10.0f, 0.0f, -10.0f);
glEnd();
}
void DrawGLscene(){
Load_Plane();
glPushMatrix();
glScalef(1.0f, -1.0f, 1.0f);
Render_Particles();
glPopMatrix();
Render_Particles();
}
void Init_Particles(){
LoadBitmapTexture("./Particle.bmp", txParticle); //load the particle texture
LoadBitmapTexture("./Plain.bmp",txPlane); //load the plain texture
int p;
srand((int)time(NULL));
for(p=0; p<MAX_PARTICLES; p++){
Particles[p].Active = FALSE;
Particles[p].tX = 0.0f;
Particles[p].tY = -0.1f;
Particles[p].tZ = 0.0f;
}
}
void Activate_Particles(){
int p;
for(p=0; p<MAX_PARTICLES; p++){
if(!Particles[p].Active){
// Start the particle at 0,0,0 origin
Particles[p].X = 0.0f;
Particles[p].Y = 0.0f;
Particles[p].Z = 0.0f;
// The following lines set a random speed value
Particles[p].sX = (((float)((rand() % 100) + 1)) /
1000.0f) - 0.05f;
Particles[p].sY = (((float)((rand() % 100) + 50)) /
500.0f);
Particles[p].sZ = (((float)((rand() % 100) + 1)) /
1000.0f) - 0.05f;
// We also activate the particle
Particles[p].Active = true;
// Set it's Age to zero
Particles[p].Age = 0;
// We also assign a max age to the particles
Particles[p].MaxAge = MAX_PARTICLE_AGE;
// We Also reset the bouncecount to zero
Particles[p].BounceCount = 0;
//Adding the colours
Particles[p].R = R;
Particles[p].G = G;
Particles[p].B = B;
R+=cR;
G+=cG;
B+=cB;
if(R>1.0f){R=1.0f; cR=-cR;}
if(R<0.0f){R=0.0f; cR=-cR;}
if(G>1.0f){G=1.0f; cG=-cG;}
if(G<0.0f){G=0.0f; cG=-cG;}
if(B>1.0f){B=1.0f; cB=-cB;}
if(B<0.0f){B=0.0f; cB=-cB;}
return;
}
}
}
void Adjust_Particles(){
int p;
for(p=0; p<MAX_PARTICLES; p++){
// We move the speed towards the target speed by 1/20 (5%)
Particles[p].sX+= (Particles[p].tX - Particles[p].sX) / 20.0f;
Particles[p].sY+= (Particles[p].tY - Particles[p].sY) / 20.0f;
Particles[p].sZ+= (Particles[p].tZ - Particles[p].sZ) / 20.0f;
// Then we adjust the position of
// the particle by the new speed
Particles[p].X+= Particles[p].sX;
Particles[p].Y+= Particles[p].sY;
Particles[p].Z+= Particles[p].sZ;
// Now for the bounce code.
if(Particles[p].Y < 0.0f){
Particles[p].Y = 0.0f;
Particles[p].sY = -Particles[p].sY;
Particles[p].BounceCount++;
if(Particles[p].BounceCount > MAX_BOUNCE_COUNT){
Particles[p].Active = FALSE;
}
}
// And finally the age check
Particles[p].Age++;
if(Particles[p].Age > Particles[p].MaxAge){
Particles[p].Active = FALSE;
}
}
}
void Render_Particles(){
Activate_Particles();
Adjust_Particles();
glClear( GL_COLOR_BUFFER_BIT );
int p;
// Enable textures and bind our particle texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, txParticle);
// Disable Depth testing.
glDisable(GL_DEPTH_TEST);
// Enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR,GL_ONE);
for(p=0; p<MAX_PARTICLES; p++){
if(Particles[p].Active){
glColor4f(Particles[p].R,
Particles[p].G,
Particles[p].B, 1.0f);
glPushMatrix();
glTranslatef(Particles[p].X,
Particles[p].Y,
Particles[p].Z);
glBegin(GL_QUADS);
glNormal3f(0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(-Size, -Size, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(Size, -Size, 0.0f);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(Size, Size, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(-Size, Size, 0.0f);
glEnd();
glPopMatrix();
}
}
glEnable(GL_DEPTH_TEST);
glutSwapBuffers();
}
bool LoadBitmapTexture(char * FileName, GLuint &texid){
HBITMAP hBMP; // Handle Of The Bitmap
BITMAP BMP; // Bitmap Structure
glGenTextures(1, &texid); // Create The Texture
hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL),
FileName,
IMAGE_BITMAP, 0, 0,
LR_CREATEDIBSECTION | LR_LOADFROMFILE
);
if (!hBMP) // Does The Bitmap Exist?
return FALSE; // If Not Return False
GetObject(hBMP, sizeof(BMP), &BMP); // Get The Object
// hBMP: Handle To Graphics Object
// sizeof(BMP): Size Of Buffer For Object Information
// &BMP: Buffer For Object Information
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
// Pixel Storage Mode (Word Alignment / 4 Bytes)
// Typical Texture Generation Using Data From The Bitmap
glBindTexture(GL_TEXTURE_2D, texid);// Bind To The Texture ID
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR); // Linear Min Filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_LINEAR); // Linear Mag Filter
glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP.bmWidth, BMP.bmHeight,
0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
DeleteObject(hBMP); // Delete The Object
return TRUE; // Loading Was Successful
}
It could be that you're not clearing the depth buffer.
It doesn't affect any of the particles because you are disabling depth test when you render them, but when you render the plane, depth test is enabled, and since the depth buffer has not been cleared it has a spaz and doesn't render the plane.
Do
glClear(GL_DEPTH_BUFFER_BIT);
before you render the plane to clear the depth buffer.
EDIT:
This must be it-
You are calling
glClear(GL_COLOR_BUFFER_BIT);
after you render the plane. Look at your DrawGLScene function:
Load_Plane(); // you are drawing the plane here
glPushMatrix();
glScalef(1.0f, -1.0f, 1.0f);
Render_Particles(); // this function calls "glClear( GL_COLOR_BUFFER_BIT );"
// so anything that you rendered before is now removed.
glPopMatrix();
Render_Particles(); // same goes for here.
The solution would be to remove the call to glClear from your Render_Particles function,
and add it to the top of DrawGLScene:
(New DrawGLScene Code)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Load_Plane();
glPushMatrix();
glScalef(1.0f, -1.0f, 1.0f);
Render_Particles();
glPopMatrix();
Render_Particles();
EDIT #2:
You're calling glutSwapBuffers in the Render_Particles function.
Don't call it there. Call it at the end of DrawGLScene: