How to display unicode text in OpenGL? - windows

Is there a good way for displaying unicode text in opengl under Windows? For example, when you have to deal with different languages. The most common approach like
#define FONTLISTRANGE 128
GLuint list;
list = glGenLists(FONTLISTRANGE);
wglUseFontBitmapsW(hDC, 0, FONTLISTRANGE, list);
just won't do because you can't create enough lists for all unicode characters.

You should also check out the FTGL library.
FTGL is a free cross-platform Open
Source C++ library that uses Freetype2
to simplify rendering fonts in OpenGL
applications. FTGL supports bitmaps,
pixmaps, texture maps, outlines,
polygon mesh, and extruded polygon
rendering modes.
This project was dormant for awhile, but is recently back under development. I haven't updated my project to use the latest version, but you should check it out.
It allows for using any True Type Font via the FreeType font library.

I recommend reading this OpenGL font tutorial. It's for the D programming language but it's a nice introduction to various issues involved in implementing a glyph caching system for rendering text with OpenGL. The tutorial covers Unicode compliance, antialiasing, and kerning techniques.
D is pretty comprehensible to anyone who knows C++ and most of the article is about the general techniques, not the implementation language.

Id recommend FTGL as already recommended above, however I have implemented a freetype/OpenGL renderer myself and thought you might find the code handy if you want reinvent this wheel yourself. I'd really recommend FTGL though, its a lot less hassle to use. :)
* glTextRender class by Semi Essessi
*
* FreeType2 empowered text renderer
*
*/
#include "glTextRender.h"
#include "jEngine.h"
#include "glSystem.h"
#include "jMath.h"
#include "jProfiler.h"
#include "log.h"
#include <windows.h>
FT_Library glTextRender::ftLib = 0;
//TODO::maybe fix this so it use wchar_t for the filename
glTextRender::glTextRender(jEngine* j, const char* fontName, int size = 12)
{
#ifdef _DEBUG
jProfiler profiler = jProfiler(L"glTextRender::glTextRender");
#endif
char fontName2[1024];
memset(fontName2,0,sizeof(char)*1024);
sprintf(fontName2,"fonts\\%s",fontName);
if(!ftLib)
{
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Font: %s was requested before FreeType was initialised", fn);
#endif
return;
}
// constructor code for glTextRender
e=j;
gl = j->gl;
red=green=blue=alpha=1.0f;
face = 0;
// remember that for some weird reason below font size 7 everything gets scrambled up
height = max(6,(int)floorf((float)size*((float)gl->getHeight())*0.001666667f));
aHeight = ((float)height)/((float)gl->getHeight());
setPosition(0.0f,0.0f);
// look in base fonts dir
if(FT_New_Face(ftLib, fontName2, 0, &face ))
{
// if we dont have it look in windows fonts dir
char buf[1024];
GetWindowsDirectoryA(buf,1024);
strcat(buf, "\\fonts\\");
strcat(buf, fontName);
if(FT_New_Face(ftLib, buf, 0, &face ))
{
//TODO::check in mod fonts directory
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Request for font: %s has failed", fn);
#endif
face = 0;
return;
}
}
// FreeType uses 64x size and 72dpi for default
// doubling size for ms
FT_Set_Char_Size(face, mulPow2(height,7), mulPow2(height,7), 96, 96);
// set up cache table and then generate the first 256 chars and the console prompt character
for(int i=0;i<65536;i++)
{
cached[i]=false;
width[i]=0.0f;
}
for(unsigned short i = 0; i < 256; i++) getChar((wchar_t)i);
getChar(CHAR_PROMPT);
#ifdef _DEBUG
wchar_t fn[128];
mbstowcs(fn,fontName,strlen(fontName)+1);
LogWriteLine(L"\x25CB\x25CB\x25CF Font: %s loaded OK", fn);
#endif
}
glTextRender::~glTextRender()
{
// destructor code for glTextRender
for(int i=0;i<65536;i++)
{
if(cached[i])
{
glDeleteLists(listID[i],1);
glDeleteTextures(1,&(texID[i]));
}
}
// TODO:: work out stupid freetype crashz0rs
try
{
static int foo = 0;
if(face && foo < 1)
{
foo++;
FT_Done_Face(face);
face = 0;
}
}
catch(...)
{
face = 0;
}
}
// return true if init works, or if already initialised
bool glTextRender::initFreeType()
{
if(!ftLib)
{
if(!FT_Init_FreeType(&ftLib)) return true;
else return false;
} else return true;
}
void glTextRender::shutdownFreeType()
{
if(ftLib)
{
FT_Done_FreeType(ftLib);
ftLib = 0;
}
}
void glTextRender::print(const wchar_t* str)
{
// store old stuff to set start position
glPushAttrib(GL_TRANSFORM_BIT);
// get viewport size
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
glPopAttrib();
float color[4];
glGetFloatv(GL_CURRENT_COLOR, color);
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
//glDisable(GL_DEPTH_TEST);
// set blending for AA
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTranslatef(xPos,yPos,0.0f);
glColor4f(red,green,blue,alpha);
// call display lists to render text
glListBase(0u);
for(unsigned int i=0;i<wcslen(str);i++) glCallList(getChar(str[i]));
// restore old states
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPopAttrib();
glColor4fv(color);
glPushAttrib(GL_TRANSFORM_BIT);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
}
void glTextRender::printf(const wchar_t* str, ...)
{
if(!str) return;
wchar_t* buf = 0;
va_list parg;
va_start(parg, str);
// allocate buffer
int len = (_vscwprintf(str, parg)+1);
buf = new wchar_t[len];
if(!buf) return;
vswprintf(buf, str, parg);
va_end(parg);
print(buf);
delete[] buf;
}
GLuint glTextRender::getChar(const wchar_t c)
{
int i = (int)c;
if(cached[i]) return listID[i];
// load glyph and get bitmap
if(FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT )) return 0;
FT_Glyph glyph;
if(FT_Get_Glyph(face->glyph, &glyph)) return 0;
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
FT_Bitmap& bitmap = bitmapGlyph->bitmap;
int w = roundPow2(bitmap.width);
int h = roundPow2(bitmap.rows);
// convert to texture in memory
GLubyte* texture = new GLubyte[2*w*h];
for(int j=0;j<h;j++)
{
bool cond = j>=bitmap.rows;
for(int k=0;k<w;k++)
{
texture[2*(k+j*w)] = 0xFFu;
texture[2*(k+j*w)+1] = ((k>=bitmap.width)||cond) ? 0x0u : bitmap.buffer[k+bitmap.width*j];
}
}
// store char width and adjust max height
// note .5f
float ih = 1.0f/((float)gl->getHeight());
width[i] = ((float)divPow2(face->glyph->advance.x, 7))*ih;
aHeight = max(aHeight,(.5f*(float)bitmap.rows)*ih);
glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
// create gl texture
glGenTextures(1, &(texID[i]));
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texID[i]);
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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, texture);
glPopAttrib();
delete[] texture;
// create display list
listID[i] = glGenLists(1);
glNewList(listID[i], GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, texID[i]);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// adjust position to account for texture padding
glTranslatef(.5f*(float)bitmapGlyph->left, 0.0f, 0.0f);
glTranslatef(0.0f, .5f*(float)(bitmapGlyph->top-bitmap.rows), 0.0f);
// work out texcoords
float tx=((float)bitmap.width)/((float)w);
float ty=((float)bitmap.rows)/((float)h);
// render
// note .5f
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, .5f*(float)bitmap.rows);
glTexCoord2f(0.0f, ty);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(tx, ty);
glVertex2f(.5f*(float)bitmap.width, 0.0f);
glTexCoord2f(tx, 0.0f);
glVertex2f(.5f*(float)bitmap.width, .5f*(float)bitmap.rows);
glEnd();
glPopMatrix();
// move position for the next character
// note extra div 2
glTranslatef((float)divPow2(face->glyph->advance.x, 7), 0.0f, 0.0f);
glEndList();
// char is succesfully cached for next time
cached[i] = true;
return listID[i];
}
void glTextRender::setPosition(float x, float y)
{
float fac = ((float)gl->getHeight());
xPos = fac*x+FONT_BORDER_PIXELS; yPos = fac*(1-y)-(float)height-FONT_BORDER_PIXELS;
}
float glTextRender::getAdjustedWidth(const wchar_t* str)
{
float w = 0.0f;
for(unsigned int i=0;i<wcslen(str);i++)
{
if(cached[str[i]]) w+=width[str[i]];
else
{
getChar(str[i]);
w+=width[str[i]];
}
}
return w;
}

You may have to generate you own "glyph cache" in texture memory as you go, potentially with some sort of LRU policy to avoid destroying all of the texture memory. Not nearly as easy as your current method, but may be the only way given the number of unicode chars

You should consider using an Unicode rendering library (eg. Pango) to render the stuff into a bitmap and put that bitmap on the screen or into a texture.
Rendering unicode text is not simple. So you cannot simply load 64K rectangular glyphs and use it.
Characters may overlap. Eg in this smiley:
( ͡° ͜ʖ ͡°)
Some code points stack accents on the previous character. Consider this excerpt from this notable post:
...he com̡e̶s, ̕h̵i​s un̨ho͞ly radiańcé destro҉ying all
enli̍̈́̂̈́ghtenment, HTML tags lea͠ki̧n͘g fr̶ǫm ̡yo​͟ur eye͢s̸ ̛l̕ik͏e
liq​uid pain, the song of re̸gular exp​ression parsing will
exti​nguish the voices of mor​tal man from the sp​here I can see it
can you see ̲͚̖͔̙î̩́t̲͎̩̱͔́̋̀ it is beautiful t​he final snuffing of
the lie​s of Man ALL IS LOŚ͖̩͇̗̪̏̈́T ALL I​S LOST the pon̷y he comes
he c̶̮omes he comes the ich​or permeates all MY FACE MY FACE ᵒh god no
NO NOO̼O​O NΘ stop the an​*̶͑̾̾​̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨe̠̅s
͎a̧͈͖r̽̾̈́͒͑e n​ot rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ ZA̡͊͠͝LGΌ ISͮ̂҉̯͈͕̹̘̱ TO͇̹̺ͅƝ̴ȳ̳
TH̘Ë͖́̉ ͠P̯͍̭O̚​N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘
̶̧̨̱̹̭̯ͧ̾ͬC̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ
If you truly want to render Unicode correctly you should be able to render this one correctly too.
UPDATE: Looked at this Pango engine, and it's the case of banana, the gorilla, and the entire jungle. First it depends on the Glib because it used GObjects, second it cannot render directly into a byte buffer. It has Cario and FreeType backends, so you must use one of them to render the text and export it into bitmaps eventually. That's doesn't look good so far.
In addition to that, if you want to store the result in a texture, use pango_layout_get_pixel_extents after setting the text to get the sizes of rectangles to render the text to. Ink rectangle is the rectangle to contain the entire text, it's left-top position is the position relative to the left-top of the logical rectangle. (The bottom line of the logical rectangle is the baseline). Hope this helps.

Queso GLC is great for this, I've used it to render Chinese and Cyrillic characters in 3D.
http://quesoglc.sourceforge.net/
The Unicode text sample it comes with should get you started.

You could also group the characters by language. Load each language table as needed, and when you need to switch languages, unload the previous language table and load the new one.

Unicode is supported in the title bar. I have just tried this on a Mac, and it ought to work elsewhere too. If you have (say) some imported data including text labels, and some of the labels just might contain unicode, you could add a tool that echoes the label in the title bar.
It's not a great solution, but it is very easy to do.

Related

GTK++/Cairo: load png, rotate, and copy rectangle to surface

I am in the process of developing an artificial horizon, as used in planes. This horizon has a background containing ground (brown) and sky (blue). Depending on the roll-angle/pitch of the plane, this background is rotated.
In order to keep it simple and keep CPU usage low, instead of drawing everything every pass, I wish to use an oversized static background image, which I will rotate as needed, and from which I will then copy/paste a square section to the screen.
The problem I'm having, is that I can't get cairo to rotate the surface FIRST and THEN copy/paste a section. It does copy/paste correctly, only rotates AFTER this has been done.
The code I have so far:
#define WINDOW_WIDTH 320
#define WINDOW_HEIGHT 240
double deg2rad( double degrees )
{
return((double)((double)degrees * ( (double)M_PI/(double)180.0 )));
}
static gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
cairo_surface_t *source;
cairo_t *bck;
cairo_pattern_t *source_pattern;
gint s_width, s_height, d_width, d_height,source_x, source_y;
// load the image from disk
source = cairo_image_surface_create_from_png ("/home/henri/dev/art_horiz_bck.png");
bck = cairo_create(source);
cairo_set_source_surface (bck, source,0,0);
s_width = cairo_image_surface_get_width(source);
s_height = cairo_image_surface_get_height(source);
// rotate around center of image
cairo_translate(bck, s_width/2, s_height/2);
cairo_rotate(cr, deg2rad(30));
cairo_paint(bck);
// after rotation, the image size should have been changed (increased)
s_width = cairo_image_surface_get_width(cairo_get_target (bck));
s_height = cairo_image_surface_get_height(cairo_get_target (bck));
d_width = gtk_widget_get_allocated_width (widget);
d_height = gtk_widget_get_allocated_height (widget);
// get the center 'viewport'
source_x = (s_width/2)-(d_width/2);
source_y = (s_height/2)-(d_height/2);
// copy this rectangle to the destination surface
cairo_set_source_surface (cr, source, -source_x, -source_y);
cairo_rectangle (cr, 0, 0, 320, 200);
cairo_fill (cr);
return FALSE;
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *topbar;
GtkWidget *bottombar;
GtkWidget *da;
gtk_init (&argc, &argv);
topbar = gtk_image_new_from_file ("/home/henri/dev/topbar.png");
bottombar = gtk_image_new_from_file ("/home/henri/dev/bottombar.png");
da = gtk_drawing_area_new();
gtk_widget_set_size_request (da, WINDOW_WIDTH, WINDOW_HEIGHT);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_decorated(GTK_WINDOW (window), 0);
gtk_window_set_default_size (GTK_WINDOW (window), WINDOW_WIDTH, WINDOW_HEIGHT);
g_signal_connect (da, "draw", G_CALLBACK(draw_cb), NULL);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
grid = gtk_grid_new ();
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_grid_attach (GTK_GRID (grid), topbar, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), da, 0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), bottombar, 0, 2, 1, 1);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
As stated, this almost does what I want, besides the rotation not getting applied at cairo_paint(bck). So i FIRST want cairo to rotate the image and THEN get a square horizontal rectangle from it. Now it first gets the rectangle, and then rotates this.
//edit
to make this more clear. The app will run on an embedded device with a 320x240 tft screen. It will be fullscreen. Above and below the horizon windows there wil be small static bars. This question only handles the drawing area in between.
I have this background image:
http://s10.postimg.org/3xuvr2dyh/art_horiz_bck.png
This is sufficiently oversized to cover all possible roll and pitch angles of the airplane in question. Now suppose the plane is flying in a 10 degree nose up attitude (so it's climbing) and is rolling with 5 degrees roll-angle.
Now what I want to do is to rotate the above background by 5 degrees, and then take a rectangular section out of it, above the horizon, so that the 10 degree nose up attitude is also displayed. So from the above image, I want to distill this image:
http://s9.postimg.org/a4u8m4oan/Naamloos.png
Note that this second image is cropped to 320x240, the size of the drawing area it will be drawn on.
//edit 2
the below posted code by Uli Schlachter does seem to do what I want, however, goes wrong at this point:
cairo_matrix_translate (&matrix, -(s_width-d_width)/2.0, -(s_height - d_height)/2.0)
This is because it uses the dimensions of the original, unrotated image. I need it to use the dimensions of the already rotated image there.
No idea if this works the way you want, but hopefully it helps you to figure out how to do what you want:
static gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
cairo_surface_t *source;
cairo_t *bck;
cairo_pattern_t *source_pattern;
gint s_width, s_height, d_width, d_height,source_x, source_y;
cairo_matrix_t matrix;
// load the image from disk
source = cairo_image_surface_create_from_png ("/home/henri/dev/art_horiz_bck.png");
source_pattern = cairo_pattern_create_for_surface (source);
s_width = cairo_image_surface_get_width(source);
s_height = cairo_image_surface_get_height(source);
d_width = gtk_widget_get_allocated_width (widget);
d_height = gtk_widget_get_allocated_height (widget);
cairo_surface_destroy (source);
// rotate around center of image
cairo_matrix_init_identity (&matrix)
cairo_matrix_translate (&matrix, s_width/2.0, s_height/2.0)
cairo_matrix_rotate (&matrix, deg2rad(30));
cairo_matrix_translate (&matrix, -(s_width-d_width)/2.0, -(s_height-d_height)/2.0)
cairo_pattern_set_matrix (source_pattern, &matrix);
// copy this rectangle to the destination surface
cairo_set_source (cr, source_pattern);
cairo_pattern_destroy (source_pattern);
cairo_rectangle (cr, 0, 0, 320, 200);
cairo_fill (cr);
return FALSE;
}

accumulatedweight throws cv:Exception error

I am new to OpenCV and trying to find contours and draw rectangle on them, here's my code but its throwing cv::Exception when it comes to accumulatedweighted().
i tried to make both src(Original Image) and dst(background) by converting to CV_32FC3 and then finding avg using accumulatedweighted.
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/imgproc_c.h"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>
using namespace cv;
using namespace std;
static void help()
{
cout << "\nThis is a Example to implement CAMSHIFT to detect multiple motion objects.\n";
}
Rect rect;
VideoCapture capture;
Mat currentFrame, currentFrame_grey, differenceImg, oldFrame_grey,background;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
bool first = true;
int main(int argc, char* argv[])
{
//Create a new movie capture object.
capture.open(0);
if(!capture.isOpened())
{
//error in opening the video input
cerr << "Unable to open video file: " /*<< videoFilename*/ << endl;
exit(EXIT_FAILURE);
}
//capture current frame from webcam
capture >> currentFrame;
//Size of the image.
CvSize imgSize;
imgSize.width = currentFrame.size().width; //img.size().width
imgSize.height = currentFrame.size().height; ////img.size().height
//Images to use in the program.
currentFrame_grey.create( imgSize, IPL_DEPTH_8U);//image.create().
while(1)
{
capture >> currentFrame;//VideoCapture& VideoCapture::operator>>(Mat& image)
//Convert the image to grayscale.
cvtColor(currentFrame,currentFrame_grey,CV_RGB2GRAY);//cvtColor()
currentFrame.convertTo(currentFrame,CV_32FC3);
background = Mat::zeros(currentFrame.size(), CV_32FC3);
accumulateWeighted(currentFrame,background,1.0,NULL);
imshow("Background",background);
if(first) //Capturing Background for the first time
{
differenceImg = currentFrame_grey.clone();//img1 = img.clone()
oldFrame_grey = currentFrame_grey.clone();//img2 = img.clone()
convertScaleAbs(currentFrame_grey, oldFrame_grey, 1.0, 0.0);//convertscaleabs()
first = false;
continue;
}
//Minus the current frame from the moving average.
absdiff(oldFrame_grey,currentFrame_grey,differenceImg);//absDiff()
//bluring the differnece image
blur(differenceImg, differenceImg, imgSize);//blur()
//apply threshold to discard small unwanted movements
threshold(differenceImg, differenceImg, 25, 255, CV_THRESH_BINARY);//threshold()
//find contours
findContours(differenceImg,contours,hierarchy,CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); //findcontours()
//draw bounding box around each contour
//for(; contours! = 0; contours = contours->h_next)
for(int i = 0; i < contours.size(); i++)
{
rect = boundingRect(contours[i]); //extract bounding box for current contour
//drawing rectangle
rectangle(currentFrame, cvPoint(rect.x, rect.y), cvPoint(rect.x+rect.width, rect.y+rect.height), cvScalar(0, 0, 255, 0), 2, 8, 0);
}
//New Background
convertScaleAbs(currentFrame_grey, oldFrame_grey, 1.0, 0.0);
//display colour image with bounding box
imshow("Output Image", currentFrame);//imshow()
//display threshold image
imshow("Difference image", differenceImg);//imshow()
//clear memory and contours
//cvClearMemStorage( storage );
//contours = 0;
contours.clear();
//background = currentFrame;
//press Esc to exit
char c = cvWaitKey(33);
if( c == 27 ) break;
}
// Destroy All Windows.
destroyAllWindows();
return 0;
}
Please Help to solve this.
you might want to RTFM before asking here.
so, you missed the alpha param as well as the dst Mat in your call to addWeighted
Mat dst;
accumulateWeighted(currentFrame, 0.5 background, 0.5, 0, dst);
also, no idea, what the whole thing should achieve. adding up the current frame before diffing it does not make any sense to me.
if you planned to do background separation, throw it all away, and use one of the builtin backgroundsubtractors instead

GLFW simple triangle is lost?

I modified the "Simple example" example in GLFW3.0.4 in Mac OSX 10.8 as an XCode 4.6 project (runs fine when unchanged). I am having a (2D) rectangle drawn with an external library (which draws via shaders). I can see the rectangle but If I draw the sample triangle (immediate drawn) before it, the triangle is seen in the first splash (frame) and then it is lost. If I try to draw it after, the triangle is never seen. I can only see the rectangle and I don't know what settings/states the library is changing!
I tried to inspect the application with OpenGL Profiler. Stopped before CGLFlushDrawable and could not find the triangle in any of the buffers (front, back, depth, stencil).
Am I doing something (prominently) wrong? The profiler allows only gl-function breakpoints. How can I debug this (more efficiently) and find the problem.
Here is (much of the changed parts of) the code:
void glfw2DViewport(GLFWwindow * window) {
float ratio;
int width, height;
glfwGetFramebufferSize(window, &width, &height);
ratio = width / (float) height;
glViewport(0, 0, width, height);
glClearColor(0.8, 0.8, 0.8, 1.0); // Lets see if something black is drawn!!
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// eye is at 0,0,0 looking to positive Z, -1(behind) to 1 are clipping planes:
// https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml
glOrtho(ratio, -ratio, -1.f, 1.f, 1.0f, -1.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// ----- 2D settings -----
glfwSwapInterval(1);
glEnable(GL_SMOOTH);
glDisable(GL_DEPTH_TEST);
//glDisable(GL_STENCIL_TEST); // Disabling changed nothing!!
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(5.0f);
glEnable(GL_LINE_SMOOTH);
glPointSize(5.0f);
glEnable(GL_POINT_SMOOTH);
}
int main(void) {
GLFWwindow* window;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window) {
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glfw2DViewport(window);
//...
while (!glfwWindowShouldClose(window)) {
glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
//drawUnitTriangle(); // can be seen just in the first frame!
glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); // A vain attempt?
glPushAttrib(GL_ALL_ATTRIB_BITS); // Another vain attempt??
external_library_identity_matrix();
external_library_rectangle(POS,RED);
external_library_flush();
glPopAttrib();
glPopClientAttrib();
// Other vain attempts:
glfwMakeContextCurrent(window);
glMatrixMode(GL_MODELVIEW_MATRIX);
glLoadIdentity();
drawUnitTriangle(); // Nothing is Drawn!!
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
Are you sure the posted code is exactly what you are building with? If that's true, please check the argument of glMatrixMode() it should be GL_MODELVIEW, not GL_MODELVIEW_MATRIX. There are two places where you set it like this.
Since you already have glfw2DViewport(), why don't you put it in the while loop and delete other model view setting codes?

Use arrow keys to rotate refrence system in openGL

This is the code written in the book openGL SuperBible to create a Spring-Shaped Path of Points on the screen:
#include "stdafx.h"
#include <Windows.h>
#include <gl\glut.h>
#include <gl\GLU.h>
#include <gl\GL.h>
#include <math.h>
// Define a constant for the value of PI
#define GL_PI 3.1415f
void ChangeSize(GLsizei , GLsizei );
void SetupRC();
void RenderScene(void);
int main(int argc, CHAR* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutCreateWindow("Points Example");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
SetupRC();
glutMainLoop();
return 0;
}
// Change viewing volume and viewport. Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
{
GLfloat nRange = 100.0f;
// Prevent a divide by zero
if(h == 0)
h = 1;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
// Reset projection matrix stack
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Establish clipping volume (left, right, bottom, top, near, far)
if (w <= h)
glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
else
glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);
// Reset Model view matrix stack
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// This function does any needed initialization on the rendering context
void SetupRC()
{
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
// Set drawing color to green
glColor3f(0.0f, 1.0f, 0.0f);
}
// Called to draw scene
void RenderScene(void)
{
GLfloat x,y,z,angle;
int xRot,yRot; // Storage for coordinates and angles
xRot = 45;
yRot = 45;
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT);
// Save matrix state and do the rotation
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// Call only once for all remaining points
glBegin(GL_POINTS);
z = -50.0f;
for(angle = 0.0f; angle <= (2.0f*GL_PI)*3.0f; angle += 0.1f)
{
x = 50.0f*sin(angle);
y = 50.0f*cos(angle);
// Specify the point and move the Z value up a little
glVertex3f(x, y, z);
z += 0.5f;
}
// Done drawing points
glEnd();
// Restore transformations
glPopMatrix();
// Flush drawing commands
glutSwapBuffers();
}
In fact by setting xRot=yRot=45 degrees, I have reached this shape.
But in the book it is told:
When this program is run, all you see is a circle
of points because you are initially looking directly down the z-axis. To see the effect, use
the arrow keys to spin the drawing around the x- and y-axes.
This means that we should have some code using arrow keys to increase and decrease the value of xRot and yRot. I have made some effort to do that.
1-Writing a function:
void _cdecl keyboard(int key ,int xRot,int yRot)
{
switch (key)
{
case GLUT_KEY_PAGE_UP:
yRot++;
case GLUT_KEY_PAGE_DOWN:
yRot--;
case GLUT_KEY_HOME:
xRot--;
case GLUT_KEY_END:
xRot++;
}
}
2-Its prototype at top of the code:
void _cdecl keyboard(int,int,int);
3-adding these two lines of code to the body of the function RenderScene:
GLint key = GLUT_KEY_PAGE_UP;
glutSpecialFunc(keyboard(key,xRot,yRot));
But I'm not sure it will work. The code gets the error:
error C2664: 'glutSpecialFunc' : cannot convert parameter 1 from 'void' to 'void (__cdecl *)(int,int,int)'
and I don't know how to return the changed value of xRot and yRot to the caller function because the compiler doesn't let me to define Pass by referrence parameters and the argument of glutSpecialFunc is a pointer to a void function!
Edited section of my question
as jblocksom suggested I changed the code to something like this:
1-defining and initializing global variables just before the main starts:
int xRot = 0;
int yRot = 0;
2- calling glutSpecialFunc somewhere in main
glutSpecialFunc(keyboard);
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
3- altering the code in keyboard function
void keyboard(int keyParam ,int mx,int my)
{
switch (keyParam)
{
case GLUT_KEY_PAGE_UP:
my++;
case GLUT_KEY_PAGE_DOWN:
my--;
case GLUT_KEY_HOME:
mx--;
case GLUT_KEY_END:
mx++;
}
glutPostRedisplay();
}
No compile and run-time error. But it does not work. I think this is because when I call glutSpecialFunc(keyboard), the function uses coordinates of mouse and keypress as the input argument so any increment or decrement is applied on the mouse coordinates not xRot or yRot which will be used in glRotatef(xRot, 1.0f, 0.0f, 0.0f) or glRotatef(yRot, 0.0f, 1.0f, 0.0f) so when calling the two latter the xRot and yRot is still equal to zero and there will be no rotation.I need to pass xRot and yRot to the function keyboard but how???
Even writing the function as:
void keyboard(int keyParam ,int mx,int my)
{
switch (keyParam)
{
case GLUT_KEY_PAGE_UP:
yRot++;
case GLUT_KEY_PAGE_DOWN:
yRot--;
case GLUT_KEY_HOME:
xRot--;
case GLUT_KEY_END:
xRot++;
}
glutPostRedisplay();
}
and calling it in the form glutSpecialFunc(keyboard) will not any difference!!!
glutSpecialFunc registers a callback with GLUT to be called when the user hits one of the arrow keys; the function you give it, keyboard, is not something you would call yourself. This is why you can't return anything from it. To get data out of the callback you'll need to set a global variable.
You'll want to call glutSpecialFunc somewhere in main where the other GLUT callbacks are set (eg glutRenderFunc). To get past the compile error, you'll call it like this:
glutSpecialFunc(keyboard);
which tells GLUT to call keyboard() with the key and mouse position.
Make the xRot and yRot variables referred to in RenderScene global.
Change the function signature of keyboard to not use xRot and yRot as variable names so that it will refer to the global ones:
void _cdecl keyboard(int key, int mx, int my)
You'll also probably need a call to glutPostRedisplay() at the end of keyboard, this will tell GLUT to redraw the scene.
Hopefully after that it should work, good luck!

Image flips, OpenGL output to JPEG using libjpeg

The below code helps me to convert OpenGL output to JPEG image using libjpg but the resultant image is flipped vertical...
The code works perfect but the final image is flipped I dont know why ?!
unsigned char *pdata = new unsigned char[width*height*3];
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pdata);
FILE *outfile;
if ((outfile = fopen("sample.jpeg", "wb")) == NULL) {
printf("can't open %s");
exit(1);
}
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
/*set the quality [0..100] */
jpeg_set_quality (&cinfo, 100, true);
jpeg_start_compress(&cinfo, true);
JSAMPROW row_pointer;
int row_stride = width * 3;
while (cinfo.next_scanline < cinfo.image_height) {
row_pointer = (JSAMPROW) &pdata[cinfo.next_scanline*row_stride];
jpeg_write_scanlines(&cinfo, &row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
OpenGL's coordinate system has the origin in the lower left corner of the image. LIBJPEG assumes that the origin of the image is in the upper left corner of the image. Make the following change to fix your code:
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer = (JSAMPROW) &pdata[(cinfo.image_height-1-cinfo.next_scanline)*row_stride];
jpeg_write_scanlines(&cinfo, &row_pointer, 1);
}

Resources