How to Zoom with Poppler - c

Language C, UI library: GTK, renderer: poppler
I'm newbie in GTK/Poppler programming and a bit stuck with understanding how to solve Zoom issue with poppler.
When I use the function below everything is ok, except zooming (hence - scrollbars).
I've tried to get the ideas from here, but it seems, I don't get how the screen/doc is rendered at all :(.
PopplerPage *ppage_P2 = NULL;
PopplerDocument *document_P2 = NULL;
cairo_surface_t *surface_P2 = NULL;
/* pdf_doc__view_page
* page - page number;
* zoom - floating nomber, 1.0 is 'no zoom'
*/
void pdf_doc__view_page (int page, float _zoom){
int err;
int w, h;
double width, height;
cairo_t *cr;
if(document_P2==NULL) /
return;
ppage_P2 = poppler_document_get_page (document_P2, page);
if(ppage_P2==NULL)
return;
poppler_page_get_size (ppage_P2, &width, &height);
w = (int) ceil(width);
h = (int) ceil(height);
if(surface_P2)
cairo_surface_destroy (surface_P2);
surface_P2 = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w*zoom_P2, h*zoom_P2);
cr = cairo_create (surface_P2);
poppler_page_render (ppage_P2, cr);
cairo_destroy (cr);
if(drawarea_P2==NULL)
return;
gtk_widget_set_size_request (drawarea_P2, w*zoom_P2, h*zoom_P2);
gtk_widget_queue_draw (drawarea_P2);
// self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u)
update_statusbar();
}

To have 'scrollers', you have to put the viewer in a GtkScrolledWindow, which I suspect you already did.
To have them actually working, once poppler rendered the page, you can ask poppler for the size of the render, then set the viewer to that size. Until then, the scrollbars don't know the size of drawing:
viewer_page = poppler_document_get_page(viewer_doc, 0);
// add a test to see if page was rendered correctly
poppler_page_get_size(viewer_page, &width, &height);
gtk_widget_set_size_request(viewer.drawingarea, (int)width, (int)height);

This is the answer. (but I still did not get how to create scrollers properly).
cr = cairo_create (surface_P2);
cairo_scale(cr, zoom_P1 , zoom_P1);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
poppler_page_render(ppage_P2, cairo);
cairo_destroy(cr);
cairo_surface_destroy(surface_P2);
g_object_unref(G_OBJECT(ppage_P2));
if(drawarea_P2==NULL)
return;
gtk_widget_set_size_request (drawarea_P2, w, h);
gtk_widget_queue_draw (drawarea_P2);
// self.SetScrollbars(u, u, (self.width*self.scale)/u, (self.height*self.scale)/u)
update_statusbar();
}

Related

How to fix freetype incorrectly loading characters

The FreeType library opens and loads a font without throwing errors, but when I try and use the character textures they're repeated and upsidedown.
I'm creating a graphics-based program using OpenGL, to deal with fonts and text I'm using FreeType. When I load the texture and set it up, the correct sizes and glyph attributes (width, advance etc...) are provided, but when I use the bitmap to create a texture and use that texture it's incorrect (as described earlier).
here is the initialisation code:
FT_Init_FreeType(&ft);
FT_New_Face(ft, "Roboto.ttf", 0, &face);
FT_Set_Pixel_Sizes(face, 0, 100);
getChars();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
FT_Done_Face(face);
FT_Done_FreeType(ft);
here is the code that then gets the character textures:
void getChars(){
int index = 0;
for (GLubyte c = 0; c < 128; c++){
if (FT_Load_Char(face, c, FT_LOAD_RENDER)){
printf("couldn't load character\n");
continue;
}
GLuint texture;
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,face->glyph->bitmap.width,face->glyph->bitmap.rows,0,GL_RGBA,GL_UNSIGNED_BYTE,face->glyph->bitmap.buffer);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
Character character = {texture, {face->glyph->bitmap.width, face->glyph->bitmap.rows}, {face->glyph->bitmap_left, face->glyph->bitmap_top}, face->glyph->advance.x};
chars[index++] = character;
}
printf("Got characters\n");
}
I've commented out the glTexParameteri s that didn't make any difference to the way the texture was displayed
Here are the structures used to store the textures:
typedef struct vec2 {
float x;
float y;
} vec2;
typedef struct Character {
GLuint Texture;
vec2 Size;
vec2 Bearing;
GLuint Advance;
} Character;
Character chars[128];
Finally here is the code that displays a string passed to it:
void drawText(char* inString, float x, float y, float scale, colour col) {
for (char* string = inString; *string != '\0'; string++){
Character ch = chars[(int) *string];
glBindTexture( GL_TEXTURE_2D, ch.Texture);
printf("character\n");
float xpos = x + ch.Bearing.x * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
float ypos = y - (ch.Size.y - ch.Bearing.y) * scale * 2 /glutGet(GLUT_WINDOW_HEIGHT);
float w = ch.Size.x * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
float h = ch.Size.y * scale * 2 /glutGet(GLUT_WINDOW_HEIGHT);
//draws the textured QUAD
glBegin(GL_QUADS);
//set the colour of the quad the texutre blends with to white with the appropriate opacity
glColor4f(col.R, col.G, col.B, col.A);
glTexCoord2f(0.0,0.0);
glVertex2f(xpos, ypos);
glTexCoord2f(0.0,1.0);
glVertex2f(xpos, ypos+h);
glTexCoord2f(1.0,1.0);
glVertex2f(xpos+w, ypos+h);
glTexCoord2f(1.0,0.0);
glVertex2f(xpos+w, ypos);
glEnd();
x += (ch.Advance >> 6) * scale * 2 /glutGet(GLUT_WINDOW_WIDTH);
printf("w %1.0f\n",w);
printf("h %1.0f\n",h);
printf("x %1.0f\n",xpos);
printf("y %1.0f\n",ypos);
}
}
I expect the normal text to be loaded, but as described earlier, each character looks like its own texture map
this is the way the text looks (ignore the image behind it)
The buffer which is returned by FT_Load_Char contains one byte for each pixel of the glyph.
If you would use modern OpenGL the you could use the format GL_RED for the bitmap format and the internal texture image format. the rest would do the Shader program.
Since you use Legacy OpenGL you've to use a format that converts the byte value to an RGB value. Use GL_LUMINANCE for that. GL_LUMINANCE converts "into an RGBA element by replicating the luminance value three times for red, green, and blue and attaching 1 for alpha".
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_LUMINANCE,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_LUMINANCE,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
Note that two-dimensional texturing has to be enabled, see glEnable:
glEnable(GL_TEXTURE_2D)
If you want to draw the text with an transparent background, then you can use GL_ALPHA:
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_ALPHA,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0,
GL_ALPHA,
GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
When you draw the text, then you've to enable Blending:
void drawText(char* inString, float x, float y, float scale, colour col) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
// [...]
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
Further glPixelStorei(GL_UNPACK_ALIGNMENT, 1); should be called before getChars();.

Font rendering (Freetype) with openGL ES 2.0 combined with other line drawing functions does not work

This thread is related to https: //stackoverflow.com/questions/50955558/render-fonts-with-sdl2-opengl-es-2-0-glsl-1-0-freetype
I have a problem combining font rendering and using this function as follows:
// Create VBO (Vertex Buffer Object) based on the vertices provided, render the vertices on the
// background buffer and eventually swap buffers to update the display.
// Return index of VBO buffer
GLuint drawVertices(SDL_Window *window, Vertex *vertices, GLsizei numVertices, int mode){
// Number of vertices elements must be provided as a param (see numVertices) because
// sizeof() cannot calculate the size of the type a pointer points to
//GLsizei vertSize = sizeof(vertices[0]);
//SDL_Log("Vertices size is %d, no of vertices is %d", vertSize, numVertices);
// Create a VBO (Vertex Buffer Object)
GLuint VBO = vboCreate(vertices, numVertices);
if (!VBO) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
// Set up for rendering the triangle (activate the VBO)
GLuint positionIdx = 0; // Position is vertex attribute 0
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(positionIdx, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
glEnableVertexAttribArray(positionIdx);
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
if (mode & RENDER){ glDrawArrays(GL_LINE_STRIP, 0, numVertices); }
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return VBO;
}
This function uses glDrawArrays() to draw a series of lines connecting the provided vertices. Flags CLEAR, RENDER & UPDATE are being used to let me do something like:
drawVertices(window, vertices, sizeOfVertices, CLEAR | RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
I did the same thing with the font rendering function thus enabling me to draw multiple strings in various x,y coordinates. The next two functions do the font rendering based on the code i submitted at the first place and off course your corrections.
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
void glRenderText(char *text, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
int w=0, h=0;
SDL_GetWindowSize(SDLmain.window, &w, &h);
float xMax = 2.0 / (float)w;
float yMax = 2.0 / (float)h;
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 }; // red and opaque
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){ glClearColor(0.0, 0.0, 0.0, 1); glClear(GL_COLOR_BUFFER_BIT); }
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
}
I therefore can do:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER | UPDATE);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER | UPDATE);
It turns out that i can either render fonts at various x,y coordinates or use the function drawVertices to render lines connecting those vertices BUT not both. That is, i cannot do this:
glRenderText(tmp, 0, 0, Olive, CLEAR | RENDER);
glRenderText(tmp, 0, 150, Yellow_Green, RENDER);
glRenderText(tmp, 0, 300, Light_Coral, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER);
drawVertices(window, vertices, sizeOfVertices, RENDER | UPDATE);
As you can tell the logic is that in either functions you have to just with a CLEAR | RENDER flag, then do only RENDER and on your last call to either functions use RENDER | UPDATE.
ISSUES:
(1) In my attempt to do the previous, that is, combinning glRenderText() + drawVertices() i failed because there is clearly something to be setup prior calling them one after the other.
(2) Another issue that i am facing is that running the code on my raspi3 resulted in drawVertices() working fine back when it comes to fonts i could only see the effect of glClearColor() & glClear(GL_COLOR_BUFFER_BIT) which means that the display was cleared with the color setup by glClearColor() but there was no font rendering to be seen. I tried both GL driver mode. There is one called FULL KMS GL driver and another called FAKE KMS GL driver.
Also, in order for the drawVertices() to work i had to comment the code provided below:
FT_Set_Pixel_Sizes(face, 0, 200);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLuint vbo;
GLuint attribute_coord=0;
glGenBuffers(1, &vbo);
glEnableVertexAttribArray(attribute_coord);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
I still had to keep the following code active:
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Activate the resulting shaders program
glUseProgram(shaderProg);
glUniform1i( tex_loc, 0 ); // 0, because the texture is bound to of texture unit 0
// Define RGB color + Alpha
float col[4] = { 0.0f, 1.0f, 1.0, 1.0f };
glUniform4fv( color_loc, 1, col);
i was able to resolve the issue by reseting pretty much everything that is not common to the two operations (glRenderText() & drawVertices())
The following code stays as is before calling any of the two functions ()glRenderText() & drawVertices()). These two functions have been updated so that a proper reset is done before reaching the point where glDrawArrays() is executed
// Load the shader program and set it for use
shaderProg = shaderProgLoad("shaderV1.vert", "shaderV1.frag");
// Activate the resulting shaders program
glUseProgram(shaderProg);
// After the shaders (vertex & fragment) have been compiled & linked into a program
// we can query the location index value of a uniform variable existing in the program.
// In this case we are querying uniform variables "tex" that exist in the fragment shader
GLuint tex_loc = glGetUniformLocation( shaderProg, "tex" );
// Set the value of the uniform variable "tex_loc" to 0, because the texture is bound to of texture unit 0
glUniform1i( tex_loc, 0 );
This is the updated function that resets some options so that we get the result we need. For example, glDisable(GL_BLEND); is used to disable blending when it comes to drawing lines. The most important off course is that i use glBindBuffer() to set the appropriate buffer for use by opengl every time drawVertices() is called. glGenBuffers() is used only once when the corresponding object name is 0 meaning that an used object name has not yet been assigned to the vbo.
GLuint drawVertices(SDL_Window *window, GLuint vbo, Vertex *vertices, GLsizei numVertices, SDL_Color rgb, int mode){
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1.0 };
// Get an available object name for glBindBuffer() when object name is ZERO
if (!vbo){ glGenBuffers(1, &vbo); }
// Check for problems
GLenum err = glGetError();
// Deal with errors
if (err != GL_NO_ERROR) {
// Failed
glDeleteBuffers(1, &vbo);
SDL_Log("Creating VBO failed, code %u\n", err);
vbo = 0;
}
else if (!vbo) {
// Failed. Error message has already been printed, so just quit
return (GLuint)NULL;
}
if (mode & CLEAR){
// Set color of the clear operation
glClearColor(0.0, 0.0, 0.0, 1.0);
// Clears the invisible buffer
glClear(GL_COLOR_BUFFER_BIT);
}
if (mode & RENDER){
// Dissable blending when drawing lines
glDisable(GL_BLEND);
// Set up for rendering the triangle (activate the vbo)
// Position is vertex attribute 0
GLuint attribute_coord = 0;
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
// Set the buffer to be used from now on
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*)0);
// Get the location of the uniform variable "color_loc"
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" to array "col"
glUniform4fv( color_loc, 1, col);
// Copy vertices into buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numVertices, vertices, GL_STATIC_DRAW);
// Now draw!
// GL_POINTS = Draw only the pixels that correspond to the vertices coordinates
// GL_LINE_STRIP = Draw line that connects the vertices coordinates
// GL_LINE_LOOP = Draw line that connects the vertices coordinates plus a line that re-connects the last coordinate with the first
// GL_TRIANGLE_FAN =
glDrawArrays(GL_LINE_STRIP, 0, numVertices);
}
// Don’t forget to flip the buffers as well, to display the final image:
// Update the window
if (mode & UPDATE){ SDL_GL_SwapWindow(window); }
return vbo;
}
Things work pretty much the same way for function glRenderText()
// render_text is called by glRenderText()
void render_text(const char *text, float x, float y, float sx, float sy) {
const char *p;
FT_GlyphSlot g = face->glyph;
//SDL_Log("Debug info: glyph w: %d, glyph rows: %d", g->bitmap.width, g->bitmap.rows);
for(p = text; *p; p++) {
// If FT_Load_Char() returns a non-zero value then the glyph in *p could not be loaded
if(FT_Load_Char(face, *p, FT_LOAD_RENDER)){ continue; }
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
g->bitmap.width,
g->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
g->bitmap.buffer
);
float x2 = x + g->bitmap_left * sx;
float y2 = -y - g->bitmap_top * sy;
float w = g->bitmap.width * sx;
float h = g->bitmap.rows * sy;
GLfloat box[4][4] = {
{x2, -y2 , 0, 0},
{x2 + w, -y2 , 1, 0},
{x2, -y2 - h, 0, 1},
{x2 + w, -y2 - h, 1, 1},
};
glBufferData(GL_ARRAY_BUFFER, sizeof box, box, GL_DYNAMIC_DRAW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
x += (g->advance.x>>6) * sx;
y += (g->advance.y>>6) * sy;
}
}
GLuint glRenderText(char *text, int fontSize, GLuint vbo, int _x, int _y, SDL_Color rgb, int mode) {
float x = _x;
float y = _y;
float xMax = 2.0 / (float)getWindowWidth();
float yMax = 2.0 / (float)getWindowHeight();
GLuint attribute_coord=0;
float col[4] = { (float)rgb.r/255, (float)rgb.g/255, (float)rgb.b/255, 1 };
// Enable blending when drawing fonts
glEnable(GL_BLEND);
// Set the W & H of the font loaded
FT_Set_Pixel_Sizes(face, 0, fontSize);
// If vbo is ZERO setup and get an object name
if (!vbo){
// Enables blending operations
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Specifies the alignment requirements for the start of each pixel row in memory
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Save into vbo one unused buffer name (index) for use with glBindBuffer
glGenBuffers(1, &vbo);
// Specifies the index of the generic vertex attribute and enables it
glEnableVertexAttribArray(attribute_coord);
}
// Set the buffer to be used from now on to the one indicated by vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Define an array of generic vertex attribute data
glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
GLuint color_loc = glGetUniformLocation( shaderProg, "color" );
// Set the value of the uniform variable "color_loc" from array "col"
glUniform4fv( color_loc, 1, col);
// Clear invisible buffer
if (mode & CLEAR){
glClearColor(0.0, 0.0, 0.0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
// If coordinate system required is:
// COORD_SYS_CONVENTIONAL = (1) left bottom corner is 0,0 and moving towards right and top sides we reach max screen size in pixels e.g 1024 * 768 pixels
// COORD_SYS_CARTECIAN = (2) left bottom corner is -1,-1 and moving towards right and top sides we reach +1,+1 . The center of the display is always 0,0
if (mode & ~COORD_SYS_CARTECIAN){
x = (_x * xMax)-1;
y = (_y * yMax)-1;
}
// Draw the text on the invisible buffer
if (mode & RENDER){ render_text(text, x, y, xMax, yMax); }
// Update display
if (mode & UPDATE){ SDL_GL_SwapWindow(SDLmain.window); }
return vbo;
}
The logic is that 2 vbos (one for drawing line through drawVertices and one for drawing fonts through glRenderText()) are defined in main() or in the global scope and are passed to glRenderText() & drawVertices() . These two functions update the values of their local copies and return the vbos so that the vbo in main or in the global scope get updated. That off course could be done by passing them entirely by reference instead of adopting my approach.
I have not yet tested the functionality in my raspi3 though. I will get back real soon with an update. Anyway, the functions given above are fully functional.
Thanks again for your time.

How can i add line breaks when rendering Text using X11,

I am making an application that renders texts according to style mentioned on screen using X Windows System and Xft. My code is working fine as shown below.
#include <X11/Xlib.h>
#include <X11/Xft/Xft.h>
char * nowShowing()
{
return strdup("This is a sample text This is rendered with new Driver installed This is a sample text his is rendered with new Driver installed");
}
int main()
{
XftFont *font;
XftDraw *draw;
XRenderColor render_color;
XftColor xft_color;
char *str;
str = nowShowing();
int x = 70;
int y = 150;
Display *dis = XOpenDisplay (0);
int screen = DefaultScreen (dis);
Window w = XCreateSimpleWindow (dis, RootWindow (dis, screen),
0, 0, 1200, 300, 1,
BlackPixel (dis, screen),
WhitePixel (dis, screen));
XEvent ev;
render_color.red = 0;
render_color.green =0;
render_color.blue = 0;
render_color.alpha = 0xffff;
XftColorAllocValue (dis,
DefaultVisual(dis, screen),
DefaultColormap(dis, screen),
&render_color,
&xft_color);
//font = XftFontOpen(dis, screen,
// XFT_FAMILY, XftTypeString, "charter",
// XFT_SIZE, XftTypeDouble, 20.0,
// NULL);
font = XftFontOpenName(dis,screen,"URW Palladio L:style=Bold Italic"); //it takes a Fontconfig pattern string
draw = XftDrawCreate(dis, w,
DefaultVisual(dis, screen),
DefaultColormap(dis, screen));
XSelectInput (dis, w, ExposureMask);
XMapWindow (dis, w);
for (;;)
{
XNextEvent (dis, &ev);
if (ev.type == Expose)
XftDrawString8(draw, &xft_color, font, x, y, (XftChar8 *) str,
strlen(str));
}
return 0;
}
But i am wondering that how can i add line breaks in the text entered. I tried using "/n" and also tried to make array and used loops but it didn't work.
New line "\n" will not be rendered by Xft. You need to render each line separately with proper offset, depending on font size and desired spacing.
I have modified the ending block of your code with sample text rendered two times on separate lines.
if (ev.type == Expose)
{
int fonth = font->ascent + font->descent;
XftDrawString8(draw, &xft_color, font, x, y, (XftChar8 *) str,
strlen(str));
XftDrawString8(draw, &xft_color, font, x, y+fonth, (XftChar8 *) str,
strlen(str));
}

OpenGL in Windows Forms (c++) - Buffer overflows?

I wrote a program in c++ using Windows forms. I use two Forms. The first form only contains a button. When it is pressed, a second form opens. This form contains a panel where a simple OpenGL simulation is played (rotated with the help of a timer provided by windows forms). The second form can be closed and opend again by pressing the botton in the first Form. The more often this is done, the slower the 3D-OpenGL-object rotates. After doing this for about 6 times the 3D-OpenGL-object starts to flicker totally crazy. I think it has to do with the fact, that the OpenGL-Object I construct is not destroyed properly and at a certain point the memory is full (in a more complicated version of the project it was flickering between the current 3D-object and a 3D object that should have been destroyed after the window was closed).
Here is a video of the Problem.
here is the code of OpenGL:
namespace OpenGLForm
{
public ref class COpenGL: public System::Windows::Forms::NativeWindow
{
public:
// Position/Orientation of 3D Mesh in Mesh-Viewer Window
float meshPos_x;
float meshPos_y;
float meshPos_z;
float meshOri_x;
float meshOri_y;
float meshOri_z;
COpenGL(System::Windows::Forms::Panel ^ parentForm, GLsizei iWidth, GLsizei iHeight)
{
// initialize all parameter / set pointers (for pointers of type MAT)
meshPos_x = 0.0;
meshPos_y = 0.0;
meshPos_z = -2.0;
meshOri_x = -63.0;
meshOri_y = 0.0;
meshOri_z = 0.0;
CreateParams^ cp = gcnew CreateParams;
m_hDC = GetDC((HWND)parentForm->Handle.ToPointer());
System::String^ filename = "C:/Advantech/Desktop/Const.txt";
System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
csvWriter->Write("Const");
csvWriter->Close();
if(m_hDC)
{
MySetPixelFormat(m_hDC);
ReSizeGLScene(iWidth, iHeight);
InitGL();
}
}
//custom function for transformations
System::Void Transform(float xTrans, float yTrans, float zTrans, float xRot, float yRot, float zRot)
{
//translate object
glTranslatef(xTrans, yTrans, zTrans);
//rotate along x-axis
glRotatef(xRot,1.0f,0.0f,0.0f);
//rotate along y-axis
glRotatef(yRot,0.0f,1.0f,0.0f);
//rotate along z-axis
glRotatef(zRot,0.0f,0.0f,1.0f);
}
System::Void Render(System::Void)
{
// Initial Settings
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear screen and depth buffer
glLoadIdentity();
meshOri_z = meshOri_z + 1;
// Set position and orientation of 3D mesh
Transform( meshPos_x,
meshPos_y,
meshPos_z,
meshOri_x,
meshOri_y,
meshOri_z );
glScalef( 0.05, 0.05, 0.05 );
int meshSize = 200;
// create 3D mesh Toplayer
for (int x = 1; x < meshSize; x++) {
for (int z = 1; z < meshSize; z++) {
glBegin(GL_QUADS);
int dm = 1;
glColor3f(dm,dm,dm);
glVertex3f( x, z, dm );
glVertex3f( (x+1), z, dm );
glVertex3f( (x+1), (z+1), dm );
glVertex3f( x, (z+1), dm );
glEnd();
}
}
}
System::Void SwapOpenGLBuffers(System::Void)
{
SwapBuffers(m_hDC) ;
}
private:
HDC m_hDC;
HGLRC m_hglrc;
protected:
~COpenGL(System::Void)
{
System::String^ filename = "C:/Advantech/Desktop/Dest.txt";
System::IO::StreamWriter^ csvWriter = gcnew System::IO::StreamWriter(filename, false, System::Text::Encoding::UTF8);
csvWriter->Write("Dest");
csvWriter->Close();
wglDeleteContext(m_hglrc);
DeleteDC(m_hDC);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
this->DestroyHandle();
}
GLint MySetPixelFormat(HDC hdc)
{
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
16, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
GLint iPixelFormat;
// get the device context's best, available pixel format match
if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0)
{
MessageBox::Show("ChoosePixelFormat Failed");
return 0;
}
// make that match the device context's current pixel format
if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE)
{
MessageBox::Show("SetPixelFormat Failed");
return 0;
}
if((m_hglrc = wglCreateContext(m_hDC)) == NULL)
{
MessageBox::Show("wglCreateContext Failed");
return 0;
}
if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL)
{
MessageBox::Show("wglMakeCurrent Failed");
return 0;
}
return 1;
}
bool InitGL(GLvoid) // All setup for opengl goes here
{
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
return TRUE; // Initialisation went ok
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize and initialise the gl window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
System::Void detectBlack(){
}
};
}
the first form only contains a button to open the second form
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {
Form1^ freaker = gcnew Form1();
freaker->ShowDialog();
}
and here is the code of the second form:
private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) {
}
void Form1_Closing( Object^ /*sender*/, System::ComponentModel::CancelEventArgs^ e )
{
this->OpenGL->~COpenGL();
}
//Time tick for play button option
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e){
UNREFERENCED_PARAMETER(sender);
UNREFERENCED_PARAMETER(e);
OpenGL->Render();
OpenGL->SwapOpenGLBuffers();
}
After one week of searching and trying around here the answer:
I found a class to destroy openGL objects in Windows (wgl). This class alone did not solve the problem. I had to call all the commands, then switch buffers by calling SwapBuffers(m_hDC); and call all the commands again. Later on I recognized that it is enough only to call the commands g_hDC=NULL; and g_hWnd=NULL;. So this is how my destructor looks like now:
~COpenGL(System::Void){
if (g_bFullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}
if (g_hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL,TEXT("Release Of DC And RC Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
if (!wglDeleteContext(g_hRC)) // Are We Able To Delete The RC?
{
MessageBox(NULL,TEXT("Release Rendering Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
}
g_hRC=NULL; // Set RC To NULL
}
if (g_hDC && !ReleaseDC(g_hWnd,g_hDC)) // Are We Able To Release The DC
{
MessageBox(NULL,TEXT("Release Device Context Failed."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hDC=NULL; // Set DC To NULL
}
if (g_hWnd && !DestroyWindow(g_hWnd)) // Are We Able To Destroy The Window?
{
MessageBox(NULL,TEXT("Could Not Release hWnd."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hWnd=NULL; // Set hWnd To NULL
}
if (!UnregisterClass(TEXT("OpenGL"),g_hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL,TEXT("Could Not Unregister Class."),TEXT("SHUTDOWN ERROR"),MB_OK | MB_ICONINFORMATION);
g_hInstance=NULL; // Set hInstance To NULL
}
SwapBuffers(g_hDC);
g_hDC=NULL;
g_hWnd=NULL;
}

Why is my openGL texture only covering half of my quad? Source included

Here is my code. I'm attempting to draw a simple quadrilateral, and place a checkerboard pattern on both sides of it. I want to allow the user to rotate around this piece with the mouse. Everything works fine, other than the texture - it is slanted, and only covers about half of the quad. Can anyone see something glaringly obvious that I am doing wrong? Thanks.
#include "glut-3.7.6-bin\glut.h"
// Constants for rotating camera
#define CAMERA_RELEASE 0
#define CAMERA_ROTATE 1
#define CAMERA_ZOOM 2
// Current camera control setting
int cameraSetting;
// Current viewing angle and scale of the scene
float viewAngleX, viewAngleY, scaleFactor = 1.0;
// Click coordinates
int clickX, clickY;
// Screen size
const int screenWidth = 600;
const int screenHeight = 600;
// Texture data
GLuint texture;
////////////////////////////////////////////////////////////////
// Function Prototypes
////////////////////////////////////////////////////////////////
GLuint loadTexture(const char * filename);
////////////////////////////////////////////////////////////////
// Callback and Initialization Functions
////////////////////////////////////////////////////////////////
void callbackMouse(int button, int state, int x, int y)
{
if (state == GLUT_DOWN)
{
// Store clicked coordinates
clickX = x;
clickY = y;
// Set camera mode to rotate
if (button == GLUT_LEFT_BUTTON)
{
cameraSetting = CAMERA_ROTATE;
}
// Set camera mode to zoom
else if (button == GLUT_RIGHT_BUTTON)
{
cameraSetting = CAMERA_ZOOM;
}
}
// Ignore camera commands if no button is clicked
else if (state == GLUT_UP)
{
cameraSetting = CAMERA_RELEASE;
}
}
void callbackKeyboard(unsigned char key, int x, int y)
{
if (key == 'q') {
exit(0);
}
}
void callbackMotion(int x, int y)
{
if (cameraSetting == CAMERA_ROTATE)
{
// Camera rotate setting - adjust the viewing angle by the direction of motion
viewAngleX += (x - clickX) / 5.0;
viewAngleX = viewAngleX > 180 ? (viewAngleX - 360) : (viewAngleX < - 180 ? (viewAngleX + 360) : viewAngleX);
clickX = x;
viewAngleY += (y - clickY) / 5.0;
viewAngleY = viewAngleY > 180 ? (viewAngleY - 360) : (viewAngleY < - 180 ? (viewAngleY + 360) : viewAngleY);
clickY = y;
}
else if (cameraSetting == CAMERA_ZOOM)
{
// Polygonal scale to simulate camera zoom
float currentScaleFactor = scaleFactor;
scaleFactor *= (1+ (y - clickY) / 60.0);
scaleFactor = scaleFactor < 0 ? currentScaleFactor : scaleFactor;
clickY = y;
}
glutPostRedisplay();
}
void callbackDisplay()
{
// Clear the screen
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// Set world window
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 1, 100);
// Setup 3D environment
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,5,
0,0,0,
0,1,0);
// Rotate and scale 3D environment to current user settings
glRotatef(viewAngleX, 0, 1, 0);
glRotatef(viewAngleY, 1, 0, 0);
glScalef(scaleFactor, scaleFactor, scaleFactor);
glBegin(GL_QUADS);
glTexCoord2d(0.0, 0.0); glVertex3f(-30, -5, -30);
glTexCoord2d(1.0, 0.0); glVertex3f(30, -5, -30);
glTexCoord2d(1.0, 1.0); glVertex3f(30, -5, 30);
glTexCoord2d(0.0, 1.0); glVertex3f(-30, -5, 30);
glEnd();
// Swap frame buffers
glutSwapBuffers();
}
void windowInitialization() {
// Enable textures by default
glEnable(GL_TEXTURE_2D);
// Load texture
texture = loadTexture("checkerboard.raw");
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
////////////////////////////////////////////////////////////////
// Main
////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
// GLUT Initialization
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(screenWidth,screenHeight);
// Create main window
glutCreateWindow("Test");
windowInitialization();
// Register callback functions
glutDisplayFunc(callbackDisplay);
glutMouseFunc(callbackMouse);
glutMotionFunc(callbackMotion);
glutKeyboardFunc(callbackKeyboard);
// Enter event processing loop
glutMainLoop();
}
////////////////////////////////////////////////////////////////
// Prototyped Functions
////////////////////////////////////////////////////////////////
GLuint loadTexture(const char * filename)
{
GLuint texture;
int width, height;
BYTE * data;
FILE * file;
// open texture data
file = fopen( filename, "rb" );
if ( file == NULL ) return 0;
// allocate buffer
width = 256;
height = 256;
data = (BYTE *) malloc( width * height * 3 );
// read texture data
fread( data, width * height * 3, 1, file );
fclose( file );
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 );
// texture wraps over at the edges
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 1 );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 1);
// build texture
gluBuild2DMipmaps( GL_TEXTURE_2D, 3, width, height,
GL_RGB, GL_UNSIGNED_BYTE, data );
// free buffer
free( data );
return texture;
}
Your code works fine for me; I suspect the problem is in the source image you're using for the texture. Double-check that the image is what you think it is. For example, using ImageMagick:
# Convert an image into raw RGB:
convert checkerboard.png checkerboard.rgb
# Convert raw RGB back to an image (assuming we know the size and color depth):
convert -size 256x256 -depth 8 checkerboard.rgb checkerboard.png

Resources