Related
I have this weird problem in which the object that I'm trying to rotate just suddenly disappears. The way I am looking to rotate the object is with a keypress, which turns a global variable rotateAnimation to true. When the variable rotateAnimation is false, the object is visible, but once it's true the object disappears.
Here is the code:
bool rotateAnimation = false;
bool moveAnimation = false;
int moveDirX = 1, moveDirY = 1;
void DrawSpiral(int x, int y)
{
float tx, ty;
float i;
float a = 0, b = 0;
glPointSize(3);
glBegin(GL_LINE_STRIP);
for (i = 0; i < 20; i = i + 0.025)
{
a = a + .05;
b = b + .05;
tx = x + b * cos(i);
ty = y + a * sin(i);
glVertex2f(tx, ty);
}
glEnd();
}
void DrawSquare(int x, int y, int size)
{
glBegin(GL_POLYGON);
glVertex2f(x, y);
glVertex2f(x - size, y);
glVertex2f(x - size, y - size);
glVertex2f(x, y - size);
glEnd();
}
void DrawPolygon(int x, int y)
{
glBegin(GL_POLYGON);
glVertex2f(x, y);
glVertex2f(x - 25, y - 25);
glVertex2f(x - 15, y - 53);
glVertex2f(x + 15, y - 53);
glVertex2f(x + 25, y - 25);
glEnd();
}
void init()
{
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glMatrixMode(GL_PROJECTION); // Since I want to do rotation in 2D
glLoadIdentity();
glClearColor(1.0, 1.0, 1.0, 0);
glColor3f(0.0f, 0.0f, 0.0f);
gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT);
}
void Keypress(int key, int x, int y)
{
switch (key)
{
case 'm':
moveAnimation = !moveAnimation;
break;
case 'o':
rotateAnimation = !rotateAnimation;
break;
}
}
void Display()
{
glClear(GL_COLOR_BUFFER_BIT);
staticScene(); // Some other drawings that should always be there on the screen
glPushMatrix();
if (rotateAnimation)
{
glRotatef(60, 1.0, 0.0, 0.0);
}
glColor3f(0.0f, 0.0f, 0.0f);
glPointSize(2);
if (shape == "square")
DrawSquare(X, Y, 40);
else if (shape == "polygon")
DrawPolygon(X, Y);
else if (shape == "spiral")
DrawSpiral(X, Y);
glPopMatrix();
glutSwapBuffers();
}
void timer(int value)
{
glutPostRedisplay();
glutTimerFunc(1000 / 60, timer, 0);
if (moveAnimation)
{
int dx = 2, dy = 2;
if (X - dx < 0) // Add from X
X += dx, moveDirX = 1;
else if (X + dx > drawingWindow[0].first) // Subtract to X
X -= dx, moveDirX = -1;
else
X += (dx * moveDirX);
if (Y - dy < drawingWindow[2].second) // Add from Y
Y += dy, moveDirY = 1;
else if (Y + dy > drawingWindow[0].second) // Subtract to Y
Y -= dy, moveDirY = -1;
else
Y += (dy * moveDirY);
}
}
When rotateAnimation is false:
When rotateAnimation is true:
EDIT: I tried to scale the object too, but the same thing happens, when the toggle is on the object disappears, and when off it appears. One thing I noted is that when I comment out the TimerFunc then nothing happens. Neither does the object scale or rotate depending on what is toggled on.
Edited: You didn't switch the matrix mode to GL_MODELVIEW.
void init()
{
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
glMatrixMode(GL_PROJECTION); // Since I want to do rotation in 2D
glLoadIdentity();
glClearColor(1.0, 1.0, 1.0, 0);
glColor3f(0.0f, 0.0f, 0.0f);
gluOrtho2D(0, WINDOW_WIDTH, 0, WINDOW_HEIGHT);
glMatrixMode(GL_MODELVIEW); //<--here
}
I have a problem regarding the gluOrtho2D function. I want to resize the window size and calibrate its coordinates, but i have problems with the function. I think that the coordinates calculated
The problem is that if i click somewhere on the window, the point isn't on the cursor, but somewhere near it ( ~20 pixels). If i resize the window, i want the window points to be converted to the new window size, that's why the gluOrtho2D function had those parameters. Maybe i didn't figure it out the good way.
GLdouble mouseX = ( double )(2* widthValue * x / windowWidthSize) - widthSize ;
GLdouble mouseY = -( double )(2 * heightValue * y / windowHeightSize) + heightValue;
are good as i want them to take values from -30 to +30 (both x and y), but the
gluOrtho2D( -width / widthValue , width / widthValue , -height / heightValue , height / heightValue);
function doesn't convert them as i want. Any ideas to fix it?
#include<windows.h>
#include<GL/Glut.h> //includes the opengl, glu, and glut header files
#include<stdlib.h> //includes the standard library header file
#include<iostream>
#include<fstream>
#include<vector>
using namespace std;
vector<pair<GLdouble,GLdouble>>v;
GLdouble heightValue = 30.0; // the points X and Y coordinates would be [-30,30]
GLdouble widthValue = 30.0; // the points X and Y coordinates would be [-30,30]
void initGL()
{
glClearColor(1,1,1,0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5.0);
glBegin(GL_POINTS);
glColor3f(1.0f, 1.0f, 0.0f);
// prints the points
for(auto i : v)
glVertex2d(i.first, i.second);
glEnd();
glFlush();
}
void reshape(GLsizei width, GLsizei height) {
// Set the viewport to cover the new window
glViewport(0, 0, width, height);
// Set the aspect ratio of the clipping area to match the viewport
glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity(); // Reset the projection matrix
// here is the problem with the coordinates. Any help??
gluOrtho2D(-width/ widthValue, width/ widthValue,-height / heightValue ,height / heightValue);
}
void mouseClick(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) // left button is pressed
{
double windowHeightSize = glutGet(GLUT_WINDOW_HEIGHT); // gets window's size
double windowWidthSize = glutGet(GLUT_WINDOW_WIDTH); // gets window's size
// converts the click coordinate on the screen to the coordinate on the window
GLdouble mouseX = (double)(60.0 * x / windowWidthSize) - 30.0;
GLdouble mouseY = -(double)(60.0 * y / windowHeightSize) + 30.0;
v.push_back(make_pair(mouseX,mouseY) ); // insert the point's coordinates in the vector
display();
}
}
int main(int argc,char** argv)
{
glutInit(&argc,argv);
glutInitWindowSize(800, 600);
glutInitWindowPosition(50, 50);//sets the position of the window in pixels from top left corner
glutCreateWindow("Program Find Convex Hull");
glutDisplayFunc(display);
glutReshapeFunc(reshape); // functia este apelata cand redimensionam fereastra
glutMouseFunc(mouseClick);
// initGL();
glutMainLoop();//loops the current event
return 0;
}
If the Orthographic projection is set by:
gluOrtho2D(-ortho_x, ortho_x, -ortho_y, ortho_y);
then the transformation of the moue position (window coordinates) to view coordinates is:
GLdouble mouseX = (double)(x/windowWidthSize * 2*ortho_x) - ortho_x;
GLdouble mouseY = ortho_y - (double)(y/windowHeightSize * 2*ortho_y);
Apply that to your example:
GLdouble ortho_x = 30.0;
GLdouble ortho_y = -30.0;
void reshape(GLsizei width, GLsizei height) {
// Set the viewport to cover the new window
glViewport(0, 0, width, height);
// Set the aspect ratio of the clipping area to match the viewport
glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity(); // Reset the projection matrix
ortho_x = width / widthValue;
ortho_y = height / heightValue;
gluOrtho2D(-ortho_x, ortho_x, -ortho_y, ortho_y);
}
void mouseClick(int button, int state, int x, int y)
{
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) // left button is pressed
{
double windowHeightSize = glutGet(GLUT_WINDOW_HEIGHT); // gets window's size
double windowWidthSize = glutGet(GLUT_WINDOW_WIDTH); // gets window's size
// converts the click coordinate on the screen to the coordinate on the window
GLdouble mouseX = (double)(x/windowWidthSize * 2*ortho_x) - ortho_x;
GLdouble mouseY = ortho_y - (double)(y/windowHeightSize * 2*ortho_y);
v.push_back(make_pair(mouseX,mouseY) ); // insert the point's coordinates in the vector
glutPostRedisplay();
}
}
Note, it is not necessary to change (ortho_x, ortho_y) in reshape. Since you mentioned in your question "i want them to take values from -30 to +30", it is even possible to keep (30.0, 30.0).
I created Lines and when I'm rotate the line. Line will be stretch. How can I stop stretch at rotation time. When I change height in Ortho it will be not displaying properly. When Line is going left or right it will be start strtching but when it will be reach in main point it will come in real position.
#include<fstream>
#include<iostream>
#include<stdlib.h>
#include<glut.h>
using namespace std;
float yr = 0;
void introscreen();
void screen();
void screen1();
void PitchLadder();
int width = 1268;
int height = 720;
float translate = 0.0f;
GLfloat angle = 0.0f;
void display(void) {
glClearColor(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-300, 300, -10, 25, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
static int center_x = 0;
static int center_y = 0;
}
void specialKey(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP:
translate += 1.0f;
break;
case GLUT_KEY_DOWN:
translate -= 1.0f;
break;
case GLUT_KEY_LEFT:
angle += 1.0f;
break;
case GLUT_KEY_RIGHT:
angle -= 1.0f;
break;
}
glutPostRedisplay();
}
void Rolling(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0, 1, 0);
glPushMatrix();
glRotatef(-angle, 0, 0, 1);
glTranslatef(-10, translate,0);
PitchLadder();
glPopMatrix();
glFlush();
}
void PitchLadder() {
GLfloat y;
GLfloat y2;
GLfloat fSize[5];
GLfloat fCurrSize;
fCurrSize = fSize[2];
for (y2 = -90.0f ; y2 <= 90.0f ; y2 += 10.0f) {
glLineWidth(fCurrSize);
glBegin(GL_LINES);
glVertex3f(-50.0f , y2 , 0);
glVertex3f(50.0f , y2 , 0);
glEnd();
fCurrSize += 1.0f;
screen();
screen1();
}
}
void renderbitmap1(float x3, float y3, void *font1, char *string1) {
char *c1;
glRasterPos2f(x3, y3);
for (c1=string1; *c1 != '\0'; c1++) {
glutBitmapCharacter(font1, *c1);
}
}
void screen(void) {
glColor3f(0, 1, 0);
char buf1[20] = { '\0' };
for (int row1 = -90.0f; row1 <= 90 + yr; row1 +=10.0f) {
sprintf_s(buf1,"%i", row1);
renderbitmap1(70 , (yr+row1), GLUT_BITMAP_TIMES_ROMAN_24, buf1);
}
}
void renderbitmap2(float x4, float y4, void *font2, char *string2) {
char *c1;
glRasterPos2f(x4, y4);
for (c1=string2; *c1 != '\0'; c1++) {
glutBitmapCharacter(font2, *c1);
}
}
void screen1(void) {
glColor3f(0, 1, 0);
char buf1[20] = { '\0' };
for (int row1 = -90.0f; row1 <= 90 + yr; row1 +=10.0f) {
sprintf_s(buf1,"%i", row1);
renderbitmap2(-70 , (yr+row1), GLUT_BITMAP_TIMES_ROMAN_24, buf1);
}
}
int main(int arg, char** argv) {
glutInit(&arg, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(width, height);
glutInitWindowPosition(50, 100);
glutCreateWindow("HUD Lines");
display();
glutDisplayFunc(Rolling);
glutSpecialFunc(specialKey);
glutMainLoop();
return 0;
}
At Orthographic Projection, the view space coordinates are linearly mapped to the clip space coordinates respectively normalized device coordinates. The normlaized device space is a cube with a minimum of (-1, -1, -1) and a maximum of (1, 1, 1).
Finally the coordinates in normalized device space are mapped to the rectangular viewport.
If the viewport is rectangular then the aspect ratio has to be considered, when the view space coordinates are transformed to clip space.
The mapping of the normalized device coordinates to the viewport distorted the geometry by the reciprocal aspect ration of the viewport. This distortion has to be compensated by the orthographic projection.
When the orthographic projection is set by glOrtho(left, right, bottom, top, near, far), then the cuboid volume is defined, which maps (left, bottom, near) to (-1, -1, -1) and (right, top, far) to (1, 1, 1).
It is not necessary that the x and y range of the orthographic projection is equal the view port rectangle, bit the ration (left-right)/(top-bottom)hast to be equal the ration of the viewport rectangle else the geometry will be distored.
double size = 200.0f;
double aspect = (double)width / (double)height;
glOrtho(-aspect*size/2.0, aspect*size/2.0, -size/2.0, size/2.0, -1.0, 1.0);
Your window size and orthographic "view" do not have the same aspect ratio:
// This creates a window that's 1268 x 720 (a wide rectangle)
int width = 1268;
int height = 720;
glutInitWindowSize(width, height);
// This creates a "view" that's 300 x 300 (a square)
glOrtho(-300, 300, -10, 25, 0, 1);
The "view" will be stretched to fill the viewport (window). You are seeing a 300 x 300 image being stretched to 1268x720, which definitely makes horizontal lines appear longer than vertical lines even though they're the same length in the code.
You should call glOrtho using the width and height variables of your window:
glOrtho(0, width, 0, height, 0, 1);
Notice that I have changed the arguments to (left = 0, right = width, bottom = 0, top = height, ...). This allows you to work with a screen coordinate space that is similar to 2D rendering but the bottom-left corner is (0,0) and the top-right is (width,height).
I'm trying to implement the flood fill algorithm in OpenGL, but I'm encountering an error doing so. The error is that the algorithm does not stop at the boundary, and simply keeps going until the edge of the window, and eventually crashes with a bad memory access error. I'm working on MacOS Mojave 10.14.4.
I think my implementation's logic is correct, however, I've printed out the color of each pixel from getPixel, and it is always white (the background color), even when getting the color of boundary pixels.
The code below draws a circle using Bresenham's Line algorithm (midpoint algorithm), and then flood fills it (unsuccessfully).
#include <GLUT/GLUT.h>
#include <iostream>
struct Color {
GLubyte r;
GLubyte g;
GLubyte b;
};
Color getPixelColor(GLint x, GLint y) {
Color color;
glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, &color);
return color;
}
void setPixel (GLint x, GLint y) {
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
Color color = getPixelColor(x, y);
}
void setPixelColor(GLint x, GLint y, Color color) {
glColor3ub(color.r, color.g, color.b);
setPixel(x, y);
glEnd();
glFlush();
}
void floodFill4 (GLint x, GLint y, Color fillColor, Color interiorColor) {
Color color = getPixelColor(x, y);
if (color.r == interiorColor.r && color.g == interiorColor.g &&
color.b == interiorColor.b) {
setPixelColor(x, y, fillColor);
floodFill4 (x + 1, y, fillColor, interiorColor);
floodFill4 (x - 1, y, fillColor, interiorColor);
floodFill4 (x, y + 1, fillColor, interiorColor);
floodFill4 (x, y - 1, fillColor, interiorColor);
}
}
void drawCirclePoint(GLint x, GLint y, GLint cx, GLint cy) {
setPixel(cx+x, cy+y);
setPixel(cx+y, cy+x);
setPixel(cx-y, cy+x);
setPixel(cx-x, cy+y);
setPixel(cx-x, cy-y);
setPixel(cx-y, cy-x);
setPixel(cx+y, cy-x);
setPixel(cx+x, cy-y);
}
void drawCircle(GLint cx, GLint cy, GLint radius) {
int p = 1 - radius;
GLint x = 0;
GLint y = radius;
while (x < y) {
drawCirclePoint(x, y, cx, cy);
if (p < 0) {
x++;
p += (2 * x) + 1;
} else {
x++;
y--;
p += (2 * x) + 1 - (2 * y);
}
}
}
void displayMe(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3ub(0, 0, 0);
GLint cx = 0;
GLint cy = 0;
GLint radius = 200;
// Draw head
glColor3ub(0, 0, 0);
drawCircle(cx, cy, radius);
glEnd();
glFlush();
Color interiorColor = {255, 255, 255};
Color fillColor = {0, 0, 255};
// floodFill4(100, 100, fillColor, interiorColor);
}
void init (void) {
glClearColor(1.0, 1.0, 1.0, 0.0); // Set display-window color to white.
glMatrixMode(GL_PROJECTION); // Set projection parameters.
glLoadIdentity();
gluOrtho2D(-1000.0, 1000.0, -1000.0, 1000.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(1000, 1000);
glutInitWindowPosition(100, 100);
glutCreateWindow("My Drawing");
init();
glutDisplayFunc(displayMe);
glutMainLoop();
return 0;
}
I've looked at this post, which seems similar, but wasn't able to find a solution.
If you're going to persist with glVertex() for point plotting make sure you set up your matrix stack transforms (GL_PROJECTION/GL_MODELVIEW) so they match the glReadPixels() coordinate system:
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0, glutGet(GLUT_WINDOW_WIDTH), 0, glutGet(GLUT_WINDOW_HEIGHT) );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
Or switch to glRasterPos() + glDrawPixels() for setPixel*().
Better yet, do the flood-fill logic host-side & upload the results to a GL texture for display.
Either way you're going to run into a stack overflow with that recursive solution on even fairly reasonably sized inputs so you'll probably want to switch to an explicit stack/queue:
void floodFill4( GLint aX, GLint aY, Color fillColor, Color interiorColor )
{
typedef std::pair< GLint, GLint > Location;
std::queue< Location > locations;
locations.push( Location( aX, aY ) );
while( !locations.empty() )
{
const Location loc = locations.front();
locations.pop();
GLint x = loc.first;
GLint y = loc.second;
Color color = getPixelColor( x, y );
if( color.r == interiorColor.r &&
color.g == interiorColor.g &&
color.b == interiorColor.b )
{
setPixelColor( x, y, fillColor );
locations.push( Location( x, y - 1 ) );
locations.push( Location( x, y + 1 ) );
locations.push( Location( x - 1, y ) );
locations.push( Location( x + 1, y ) );
}
}
}
I've got code for flood fill algorithm.
void floodFill() {
float target[3] = { 1.0, 1.0, 0.0 };
float border[3] = { 1.0, 1.0, 1.0 };
float clearp[3] = { 0.0, 0.0, 0.0 };
std::stack<pixel*> colored;
if (!stack.empty()) // stack contains first pixel
colored.push(stack.top());
while(!colored.empty()) {
pixel *p = colored.top();
drawPixel(p->x, p->y, target);
colored.pop();
//up
float pix[3];
glReadPixels(p->x, p->y + KOEF, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x;
pn->y = p->y + KOEF;
colored.push(pn);
}
//down
glReadPixels(p->x, p->y - KOEF, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x;
pn->y = p->y - KOEF;
colored.push(pn);
}
//left
glReadPixels(p->x - KOEF, p->y, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x - KOEF;
pn->y = p->y;
colored.push(pn);
}
//right
glReadPixels(p->x + KOEF, p->y, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x + KOEF;
pn->y = p->y;
colored.push(pn);
}
}
}
I draw pixel using this method
void drawPixel(float x, float y, float *t) {
glRasterPos2i(x, y);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
for(int i = 0; i < KOEF; i++) {
glRasterPos2i(x, y + i);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
glRasterPos2i(x + i, y);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
glRasterPos2i(x + i, y + i);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
}
};
To fill some area I choose first pixel with mouse click and then call method floodFill.
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
pixel *p = new pixel();
p->x = x;
p->y = HEIGHT - y;
if (!stack.empty())
stack.pop();
stack.push(p); // first pixel
floodFill();
}
};
The result is (for example)
But it works very slow(several seconds. area on the picture - it was drawing it for 11 seconds. area around letter - 43 seconds). And I thought it slowly will draw pixel after pixel but it is waiting for several seconds and then I see the result.
my pc is
intel core 2 duo p8600 2.4 GHz
nvidia 9600m gt 512 mb
windows x86
ram 4 GB(3)`
Should it work so slow or there is a problem?
That's a terrible way to use OpenGL.
Do your flood-fill in host memory, upload the resulting bitmap to an OpenGL texture, and then render a quad with that texture.
Should it work so slow or there is a problem?
No, it should not. Because Photoshop can make it faster :-)
It looks like there are some efficiency-related issues.
You should not use OpenGL calls for single pixel operations. You should better make a buffered copy of the image, process (floodfill) it, then copy back.
Why are you using these strange float coordinates instead of normal integer pixel indices?
And what about not using floats for colors too? Floating point operations are slower than integer ones and float values needs further convesion to internal image format.
Your program seems to be too OOP-ish for its purpose. It is not good idea to use new and stack in the innermost loop of the image processing routine.