In this post the rectangle moved via mouse. I want to add a triangle and move like rectangle via mouse.
The triangle function like this:
void drawTriangle(float x,float y,float size){
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
Rectangle and triangle moved together. But I want to move it different. So what is my wrong?
You'll have to maintain an array of Shape objects and test each one for mouse collisions, as well as keep track of which Shape you're dragging:
#include <GL/glut.h>
#include <vector>
using namespace std;
struct Shape
{
float mX, mY;
float mSize;
bool mIsRectangle;
bool PointInside( const float x, const float y ) const
{
return
mX - mSize <= x && x <= mX + mSize
&&
mY - mSize <= y && y <= mY + mSize;
}
};
vector< Shape > objects;
Shape* dragging = NULL;
void mouse( int button, int state, int x, int y )
{
if( GLUT_DOWN == state )
{
dragging = NULL;
for( Shape& obj : objects )
{
if( obj.PointInside( x, y ) )
{
dragging = &obj;
glutPostRedisplay();
break;
}
}
}
else
{
dragging = NULL;
}
}
void motion( int x, int y )
{
if( dragging )
{
dragging->mX = x;
dragging->mY = y;
glutPostRedisplay();
}
}
void drawRect( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_QUADS );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, -1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glVertex2f( -1, 1 );
glEnd();
glPopMatrix();
}
void drawTriangle( float x, float y, float size )
{
glPushMatrix();
glTranslatef( x, y, 0.0f );
glScalef( size, size, 1.0f );
glBegin( GL_TRIANGLES );
glColor3ub( 255, 255, 255 );
glVertex2f( -1, 1 );
glVertex2f( 1, -1 );
glVertex2f( 1, 1 );
glEnd();
glPopMatrix();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH );
const double h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
for( const Shape& obj : objects )
{
if( obj.mIsRectangle )
drawRect( obj.mX, obj.mY, obj.mSize );
else
drawTriangle( obj.mX, obj.mY, obj.mSize );
}
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
Shape temp;
temp.mSize = 50;
temp.mX = temp.mY = 100;
temp.mIsRectangle = true;
objects.push_back( temp );
temp.mX = temp.mY = 200;
temp.mIsRectangle = false;
objects.push_back( temp );
glutMainLoop();
return 0;
}
Related
I am not able to plot the vertex glVertex2f( 10.0, 0.0 ) in the window, but when I use points like 0.8 it shows up.
Height = 640
Width = 480
So, I might be able to plot points in this range I guess. Can anyone point out the mistake and correct it?
Code:
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <cstdlib>
//defining constants
#define MAX_WIDTH 640
#define MAX_HEIGHT 480
//display callback function
void display(){
glClear( GL_COLOR_BUFFER_BIT );
glPointSize( 5 );
glLoadIdentity();
gluLookAt( 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 1.0, 0.0 );
glBegin( GL_POINTS );
//setting the pointer color
glColor3f( 1.0, 1.0, 1.0 );
glVertex2f( 0.0, 0.0 );
glVertex2f( 10.0, 0.0 );
glEnd();
glFlush();
}
//catching keyboard events
void keyboardEvent( unsigned char c, int x, int y ){
if( c == 27 ){
exit(0);
}
}
//catching mouse click events
void mouseEvent( int button, int state, int x, int y ){
//checking if the mouse button is clicked or not using state para.
if( state == GLUT_DOWN ){
if( button == GLUT_LEFT_BUTTON ){
}
else if( button == GLUT_RIGHT_BUTTON ){
}
}
}
//adjusting window when it is moved or resized
void reshape( int w, int h ){
glViewport( 0, 0, w, h );
}
//initialising the window at startup
void initialise(){
glClearColor( 0.0, 0.0, 0.0, 1.0 );
gluOrtho2D( 0, MAX_WIDTH, 0, MAX_HEIGHT );
}
int main( int argc, char **argv ){
//initialising the glut library
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB );
glutInitWindowSize( MAX_WIDTH, MAX_HEIGHT );
glutInitWindowPosition( 100, 100 );
glutCreateWindow("DDA Assignment");
//calling normal functions
initialise();
//registering callback functions
glutDisplayFunc( display );
glutKeyboardFunc( keyboardEvent );
glutMouseFunc( mouseEvent );
glutReshapeFunc( reshape );
glutMainLoop();
return 0;
}
The glLoadIdentity() in display() is wiping out the matrix set by gluOrtho2D() in initialise().
Today I finally figured out what I needed to do to animate my GIF but now that I have it animated the FPS on my program lowered dramatically. I have my GIF in a serperate function so it doesn't have to reload every texture whenever I try to update the frames of the GIF. I also plan on loading more GIFs if there is a way to fix my FPS drop issue so I need a way to reduce lag on all of them. Is there any easy way to fix this?
My code:
LUtil.cpp:
#include "LUtil.h"
#include <IL/il.h>
#include <IL/ilu.h>
#include "LSpriteSheet.h"
int add = 0;
int zoom = 0;
double leftzoom = -SCREEN_WIDTH;
double topzoom = -SCREEN_HEIGHT;
double rightzoom = SCREEN_WIDTH;
double bottomzoom = SCREEN_HEIGHT;
float sy = 0.f;
int scroll = 0;
GLfloat gCameraX = 0.f, gCameraY = 0.f, gCameraZ = 0.f;
//Sprite texture
LSpriteSheet gArrowSprites;
LSpriteSheet gSamusSprites;
LSpriteSheet jSamusSprites;
bool initGL()
{
//Initialize GLEW
GLenum glewError = glewInit();
if( glewError != GLEW_OK )
{
printf( "Error initializing GLEW! %s\n", glewGetErrorString( glewError ) );
return false;
}
//Make sure OpenGL 2.1 is supported
if( !GLEW_VERSION_2_1 )
{
printf( "OpenGL 2.1 not supported!\n" );
return false;
}
//Set the viewport
glViewport( 0.f, -0.f, SCREEN_WIDTH, SCREEN_HEIGHT );
//Initialize Projection Matrix
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( leftzoom, rightzoom, bottomzoom, topzoom, 1.0, -1.0 );
//Initialize Modelview Matrix
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glPushMatrix();
//Initialize clear color
glClearColor( 0.f, 0.f, 0.f, 1.f );
//Enable texturing
glEnable( GL_TEXTURE_2D );
glEnable( GL_BLEND );
glDisable( GL_DEPTH_TEST );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
//Check for error
GLenum error = glGetError();
if( error != GL_NO_ERROR )
{
printf( "Error initializing OpenGL! %s\n", gluErrorString(error));
return false;
}
//Initialize DevIL
ilInit();
ilClearColour( 255, 255, 255, 000 );
//Check for error
ILenum ilError = ilGetError();
if( ilError != IL_NO_ERROR )
{
printf( "Error initializing DevIL! %s\n", iluErrorString(ilError) );
return false;
}
return true;
}
LFRect clip;
bool loadMedia()
{
//Load texture
if( !gArrowSprites.loadTextureFromFile( "Textures/SamusM.png" ) )
{
printf( "Unable to load texture!\n" );
return false;
}
clip = { 0.f, 0.f, 330.f, 355.f };
//Top left
clip.x = 0.f;
clip.y = 0.f;
gArrowSprites.addClipSprite( clip );
//Top right
clip = {0.f, 0.f, 310.f, 480.f};
clip.x = 331.f;
clip.y = 0.f;
gArrowSprites.addClipSprite( clip );
clip = {0.f, 0.f, 330.f, 125.f};
//Bottom left
clip.x = 0.f;
clip.y = 355.f;
gArrowSprites.addClipSprite( clip );
clip = { 0.f, 0.f, 330.f, 355.f };
//Top left
clip.x = 0.f;
clip.y = 480.f;
gArrowSprites.addClipSprite( clip );
//Top right
clip = {0.f, 0.f, 310.f, 480.f};
clip.x = 331.f;
clip.y = 480.f;
gArrowSprites.addClipSprite( clip );
clip = {0.f, 0.f, 330.f, 125.f};
//Bottom left
clip.x = 0.f;
clip.y = 835.f;
gArrowSprites.addClipSprite( clip );
//Generate VBO
if( !gArrowSprites.generateDataBuffer() )
{
printf( "Unable to clip sprite sheet!\n" );
return false;
}
if( !jSamusSprites.loadTextureFromFile( "Textures/SamusAran.png" ) )
{
printf( "Unable to load texture!\n" );
return false;
}
clip = { 0.f, 0.f, 375.f, 562.f };
//Top left
clip.x = 0.f;
clip.y = 0.f;
jSamusSprites.addClipSprite( clip );
if( !jSamusSprites.generateDataBuffer() )
{
printf( "Unable to clip sprite sheet!\n" );
return false;
}
return true;
}
bool textureLoaded = false;
bool loadGif(){
if(textureLoaded == false){
if( !gSamusSprites.loadTextureFromFile( "Textures/SamusG.png" ) )
{
printf( "Unable to load texture!\n" );
return false;
}
textureLoaded = true;
}
sy += 214.f;
if(sy == 8988.f){
sy = 0.f;
}
clip = {0.f, 0.f, 213.f, 214.f};
clip.x = 0.f;
clip.y = sy;
gSamusSprites.addClipSprite( clip );
if( !gSamusSprites.generateDataBuffer() )
{
printf( "Unable to clip sprite sheet!\n" );
return false;
}
return true;
}
void update()
{
}
void render()
{
//Clear color buffer
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glPushMatrix();
if(add == 0){
if(zoom < 100){
double const f_zoom = 1.0 - 0.01 * zoom;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(leftzoom * f_zoom, rightzoom * f_zoom, bottomzoom * f_zoom, topzoom * f_zoom, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
if(zoom < -102){
double const f_zoom = 1.0 + 0.01 * zoom;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(leftzoom * f_zoom, rightzoom * f_zoom, bottomzoom * f_zoom, topzoom * f_zoom, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
glTranslatef( -1080.f, -782.f, 0.f );
gArrowSprites.renderSprite( 0 );
//Render top right arrow
glTranslatef( +1080.f, +782.f, 0.f );
glTranslatef( 1085.f, -120.f, 0.f );
gArrowSprites.renderSprite( 1 );
//Render bottom left arrow
glTranslatef( -1085.f, +120.f, 0.f );
glTranslatef( 0.f, 885.f ,0.f );
gArrowSprites.renderSprite( 2 );
glTranslatef(0.f, -885.f, 0.f);
jSamusSprites.renderSprite( 0 );
glTranslatef( -620.f, -855.f, 0.f );
glTranslatef( 620.f, 0.f , 0.f );
gSamusSprites.renderSprite( 0 );
}
if(add == 1){
if(zoom < 100){
double const f_zoom = 1.0 - 0.01 * zoom;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(leftzoom * f_zoom, rightzoom * f_zoom, bottomzoom * f_zoom, topzoom * f_zoom, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
if(zoom < -102){
double const f_zoom = 1.0 + 0.01 * zoom;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(leftzoom * f_zoom, rightzoom * f_zoom, bottomzoom * f_zoom, topzoom * f_zoom, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
glTranslatef( -1080.f, -782.f, 0.f );
gArrowSprites.renderSprite( 3 );
glTranslatef( +1080.f, +782.f, 0.f );
glTranslatef( 1085.f, -120.f, 0.f );
gArrowSprites.renderSprite( 4 );
glTranslatef( -1085.f, +120.f, 0.f );
glTranslatef( 0.f, 885.f ,0.f );
gArrowSprites.renderSprite( 5 );
glTranslatef(0.f, -885.f, 0.f);
jSamusSprites.renderSprite( 0 );
glTranslatef( -620.f, -855.f, 0.f );
glTranslatef( 620.f, 0.f , 0.f );
gSamusSprites.renderSprite( 0 );
}
glLoadIdentity();
glutSwapBuffers();
}
void handleKeys( unsigned char key, int x, int y )
{
//If the user presses q
if( key == 'q' && add == 0 )
{
add++;
}
else if( key == 'q' && add == 1)
{
add--;
}
//Update the sprite rectangles so the texture change takes effect
if( key == 27 ) {
exit(0);
}
if(key == 'a') {
gCameraX += 8.f;
}
else if (key == 'd') {
gCameraX -= 8.f;
}
else if (key == 'w') {
gCameraY += 8.f;
}
else if (key == 's') {
gCameraY -= 8.f;
}
else if (key == '+' && zoom != 99) {
zoom += 1;
}
else if (key == '-' && zoom != -101) {
zoom -= 1;
}
//Take saved matrix off the stack and reset it
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
glLoadIdentity();
//Move camera to position
glTranslatef( gCameraX, gCameraY, gCameraZ );
//Save default matrix again with camera translation
glPushMatrix();
}
Main.cpp:
#include "LUtil.h"
void runMainLoop( int val );
void runGifLoop( int val2 );
int main( int argc, char* args[] )
{
glutInit( &argc, args );
glutInitContextVersion( 2, 1 );
glutInitDisplayMode( GLUT_DOUBLE );
glutInitWindowSize( SCREEN_WIDTH, SCREEN_HEIGHT );
glutCreateWindow( "Samus" );
if( !initGL() )
{
printf( "Unable to initialize graphics library!\n" );
return 1;
}
if( !loadMedia() )
{
printf( "Unable to load media!\n" );
return 2;
}
glutKeyboardFunc( handleKeys );
glutDisplayFunc( render );
glutTimerFunc( 1000 / SCREEN_FPS, runMainLoop, 0 );
glutTimerFunc( 1000 / SCREEN_FPS, runGifLoop, 0 );
glutMainLoop();
return 0;
}
void runMainLoop( int val )
{
update();
render();
glutTimerFunc( 1000 / SCREEN_FPS, runMainLoop, val );
}
void runGifLoop( int val2 )
{
loadGif();
glutTimerFunc( 1000 / SCREEN_FPS, runGifLoop, val2 );
}
I am trying to implement a 2D camera in OpenGL that behaves like the Google maps camera. Specifically the "zoom to mouse point" functionality.
So far I have been able to implement pan and zoom OK - but only if the zoom is locked to the center of the window/widget. If I try to zoom on the mouse location the view seems to "jump" and after the zoom level increases the item I zoomed in on is no longer under the mouse cursor.
My camera class is below - quite a lot of code but I couldn't make it any smaller sorry!
I call Apply() on the start of each frame, and I call SetX/YPos when the scene is panned, finally I call SetScale with the previous scale +/- 0.1f with the mouse position when the mouse wheel is scrolled.
camera.h
class Camera
{
public:
Camera();
void Apply();
void SetXPos(float xpos);
void SetYPos(float ypos);
void SetScale(float scaleFactor, float mx, float my);
float XPos() const { return m_XPos; }
float YPos() const { return m_YPos; }
float Scale() const { return m_ScaleFactor; }
void SetWindowSize(int w, int h);
void DrawTestItems();
private:
void init_matrix();
float m_XPos;
float m_YPos;
float m_ScaleFactor;
float m_Width;
float m_Height;
float m_ZoomX;
float m_ZoomY;
};
camera.cpp
Camera::Camera()
: m_XPos(0.0f),
m_YPos(0.0f),
m_ScaleFactor(1.0f),
m_ZoomX(0.0f),
m_ZoomY(0.0f),
m_Width(0.0f),
m_Height(0.0f)
{
}
// Called when window is created and when window is resized
void Camera::SetWindowSize(int w, int h)
{
m_Width = (float)w;
m_Height = (float)h;
}
void Camera::init_matrix()
{
glViewport(0, 0, m_Width, m_Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float new_W = m_Width * m_ScaleFactor;
float new_H = m_Height * m_ScaleFactor;
// Point to zoom on
float new_x = m_ZoomX;
float new_y = m_ZoomY;
glOrtho( -new_W/2+new_x,
new_W/2+new_x,
new_H/2+new_y,
-new_H/2+new_y,
-1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Camera::Apply()
{
// Zoom
init_matrix();
// Pan
glTranslatef( m_XPos, m_YPos, 1.0f );
DrawTestItems();
}
void Camera::SetXPos(float xpos)
{
m_XPos = xpos;
}
void Camera::SetYPos(float ypos)
{
m_YPos = ypos;
}
// mx,my = window coords of mouse pos when wheel was scrolled
// scale factor goes up or down by 0.1f
void Camera::SetScale(float scaleFactor, float mx, float my)
{
m_ZoomX = (float)mx;
m_ZoomY = (float)my;
m_ScaleFactor = scaleFactor;
}
void Camera::DrawTestItems()
{
}
Update: I seem to have noticed 2 issues:
The mouse position in SetScale is incorrect - I don't know why.
No matter what I try glOrtho causes the centre of the screen to be the zoom point,I confirmed this setting the zoom point manually/hard coding it. In Google maps the screen won't "stick" to the centre like this.
Update again:
I'm also using Qt if this makes any difference, I just have a basic QGLWidget and I am using the mouse wheel event to perform the zoom. I take the delta of the wheel event and then either add or subtract 0.1f to the scale passing in the mouse position from the wheel event.
Get the world-space coordinates of the mouse cursor using the current zoom factor and model/proj/view matrices.
Adjust zoom factor
Get the world-space mouse coordinates again using the new zoom factor
Shift the camera position by the difference in world-space mouse coordinates
Redraw scene using new camera position and zoom factor
Something like this (in the wheel() callback):
#include <GL/freeglut.h>
#include <iostream>
using namespace std;
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
glm::dvec3 Unproject( const glm::dvec3& win )
{
glm::ivec4 view;
glm::dmat4 proj, model;
glGetDoublev( GL_MODELVIEW_MATRIX, &model[0][0] );
glGetDoublev( GL_PROJECTION_MATRIX, &proj[0][0] );
glGetIntegerv( GL_VIEWPORT, &view[0] );
glm::dvec3 world = glm::unProject( win, model, proj, view );
return world;
}
// unprojects the given window point
// and finds the ray intersection with the Z=0 plane
glm::dvec2 PlaneUnproject( const glm::dvec2& win )
{
glm::dvec3 world1 = Unproject( glm::dvec3( win, 0.01 ) );
glm::dvec3 world2 = Unproject( glm::dvec3( win, 0.99 ) );
// u is a value such that:
// 0 = world1.z + u * ( world2.z - world1.z )
double u = -world1.z / ( world2.z - world1.z );
// clamp u to reasonable values
if( u < 0 ) u = 0;
if( u > 1 ) u = 1;
return glm::dvec2( world1 + u * ( world2 - world1 ) );
}
// pixels per unit
const double ppu = 1.0;
glm::dvec2 center( 0 );
double scale = 1.0;
void ApplyCamera()
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
const double w = glutGet( GLUT_WINDOW_WIDTH ) / ppu;
const double h = glutGet( GLUT_WINDOW_HEIGHT ) / ppu;
glOrtho( -w/2, w/2, -h/2, h/2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glScaled( scale, scale, 1.0 );
glTranslated( -center[0], -center[1], 0 );
}
glm::dvec2 mPos;
glm::dvec2 centerStart( 0 );
int btn = -1;
void mouse( int button, int state, int x, int y )
{
ApplyCamera();
y = glutGet( GLUT_WINDOW_HEIGHT ) - y;
mPos = glm::ivec2( x, y );
btn = button;
if( GLUT_LEFT_BUTTON == btn && GLUT_DOWN == state )
{
centerStart = PlaneUnproject( glm::dvec2( x, y ) );
}
if( GLUT_LEFT_BUTTON == btn && GLUT_UP == state )
{
btn = -1;
}
glutPostRedisplay();
}
void motion( int x, int y )
{
y = glutGet( GLUT_WINDOW_HEIGHT ) - y;
mPos = glm::ivec2( x, y );
if( GLUT_LEFT_BUTTON == btn )
{
ApplyCamera();
glm::dvec2 cur = PlaneUnproject( glm::dvec2( x, y ) );
center += ( centerStart - cur );
}
glutPostRedisplay();
}
void passiveMotion( int x, int y )
{
y = glutGet( GLUT_WINDOW_HEIGHT ) - y;
mPos = glm::ivec2( x, y );
glutPostRedisplay();
}
void wheel( int wheel, int direction, int x, int y )
{
y = glutGet( GLUT_WINDOW_HEIGHT ) - y;
mPos = glm::ivec2( x, y );
ApplyCamera();
glm::dvec2 beforeZoom = PlaneUnproject( glm::dvec2( x, y ) );
const double scaleFactor = 0.90;
if( direction == -1 ) scale *= scaleFactor;
if( direction == 1 ) scale /= scaleFactor;
ApplyCamera();
glm::dvec2 afterZoom = PlaneUnproject( glm::dvec2( x, y ) );
center += ( beforeZoom - afterZoom );
glutPostRedisplay();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
ApplyCamera();
glm::dvec2 cur = PlaneUnproject( mPos );
cout << cur.x << " " << cur.y << " " << scale << endl;
glPushMatrix();
glScalef( 50, 50, 1 );
glBegin( GL_QUADS );
glColor3ub( 255, 255, 255 );
glVertex2i( -1, -1 );
glVertex2i( 1, -1 );
glVertex2i( 1, 1 );
glVertex2i( -1, 1 );
glEnd();
glPopMatrix();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
glutMouseFunc( mouse );
glutMotionFunc( motion );
glutMouseWheelFunc( wheel );
glutDisplayFunc( display );
glutPassiveMotionFunc( passiveMotion );
glutMainLoop();
return 0;
}
I am trying to draw the shape shown below (in black) in OpenGL (for desktops, not mobile). I'd prefer it in 3D, but 2D would suffice as well. I will be mapping a texture to it as well. I've used triangle fans/strips for other things in the past and I imagine that's what I'd need to use here but I'm just not sure where to start on it. I've drawn the WHITE part before, but never the inverse (the black part). Any thoughts or guidance on what to use (triangle fan, triangle strip, some other odd OpenGL shape I probably didn't know existed, etc...)
Final Solution:
void draw_arch(GLfloat width, GLfloat height, GLint slices)
{
glPushMatrix();
GLfloat offset = 0.5f;
glScalef(width/2,height/(1+offset),1.0f);
glBegin(GL_QUADS);
for( unsigned int i = 0; i < slices; ++i ) {
float curAngle = ( ( i + 0 ) / (float)slices ) * 3.14159;
float nxtAngle = ( ( i + 1 ) / (float)slices ) * 3.14159;
glVertex2f( cos( curAngle ), sin( curAngle ) );
glVertex2f( cos( curAngle ), 1.0f + offset );
glVertex2f( cos( nxtAngle ), 1.0f + offset );
glVertex2f( cos( nxtAngle ), sin( nxtAngle ) );
}
glEnd();
glPopMatrix();
}
I can adjust the "offset" variable to make different looking arches, however in this application, I choose 0.5 to make it look the way I wanted it to!
Generate the top half of a circle and an offset above it and link the two with quads/triangles:
#include <GL/glut.h>
#include <cmath>
void glShape( const float height, unsigned int segs )
{
glBegin( GL_QUADS );
for( unsigned int i = 0; i < segs; ++i )
{
float curAngle = ( ( i + 0 ) / (float)segs ) * 3.14159;
float nxtAngle = ( ( i + 1 ) / (float)segs ) * 3.14159;
glVertex2f( cos( curAngle ), sin( curAngle ) );
glVertex2f( cos( curAngle ), 1 + height );
glVertex2f( cos( nxtAngle ), 1 + height );
glVertex2f( cos( nxtAngle ), sin( nxtAngle ) );
}
glEnd();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3ub( 255, 0, 0 );
glShape( 0.1f, 20 );
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
Probably not the minimal number of quads/triangles but it's quick and easy :)
I'm trying to draw a selection box over an image drawn using glDrawPixels, but I cannot get it to show. In order to represent the coordinates of the box, I have 4 global integers that I update on mouse actions (the first 2 on click, the others when the mouse is dragged), which I then use in the drawing function. I'm sure that the drawing function is called when the mouse gets dragged, and that the four values at least get updated, since I tried printing them every time the drawing function gets called.
The OpenGL calls I have in the main are:
glutInit(&argc, argv);
glutInitWindowSize(WINDOW_DIM, WINDOW_DIM);
glutInitWindowPosition(0, 0);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutCreateWindow("Window");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glClearColor(0.0, 0.0, 0.0, 1.0);
glDisable(GL_DEPTH_TEST);
glutMainLoop();
and my display function:
void display()
{
printf("calling display\n");
for(unsigned int i=0; i<WINDOW_DIM*WINDOW_DIM; ++i)
{
pixels[i]=colors[img[i]];
}
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(WINDOW_DIM, WINDOW_DIM, GL_RGB, GL_FLOAT, (float*)pixels);
glutSwapBuffers();
if(upd_xmin!=0 || upd_ymin!=0 || upd_xmax!=0 || upd_ymax!=0)
{
glDrawBuffer(GL_FRONT);
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
printf("drawing selection\n");
printf("coords %d %d %d %d\n", upd_xmin, upd_ymin, upd_xmax, upd_ymax);
glColor3f(1.0, 1.0, 1.0);
glLineWidth(3.0);
glBegin(GL_LINE_LOOP);
glVertex2i(upd_xmin, upd_ymin);
glVertex2i(upd_xmin, upd_ymax);
glVertex2i(upd_xmax, upd_ymax);
glVertex2i(upd_xmax, upd_ymin);
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
glDrawBuffer(GL_BACK);
}
}
As I said, I don't think the problem is with the mouse and motion function, seeing how the coordinates of the box (the upd_x and upd_y variables in the code above) get updated when there's a mouse event, but if needed I can post those as well.
Don't swap the buffers in the middle. Just draw the selection box on the back-buffer like everything else:
#include <GL/glut.h>
int StartX = -1;
int StartY = -1;
int EndX = -1;
int EndY = -1;
void mouse( int button, int state, int x, int y )
{
if( button == GLUT_LEFT && state == GLUT_DOWN )
{
StartX = x;
StartY = y;
}
if( button == GLUT_LEFT && state == GLUT_UP )
{
StartX = -1;
StartY = -1;
EndX = -1;
EndY = -1;
}
}
void motion( int x, int y )
{
EndX = x;
EndY = y;
glutPostRedisplay();
}
void display()
{
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glBegin( GL_TRIANGLES );
glColor3ub( 255, 0, 0 );
glVertex2i( -1, -1 );
glColor3ub( 0, 255, 0 );
glVertex2i( 1, -1 );
glColor3ub( 0, 0, 255 );
glVertex2i( 0, 1 );
glEnd();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
if( StartX > 0 && StartY > 0 && EndX > 0 && EndY > 0 )
{
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
glColor3f(1.0, 1.0, 1.0);
glLineWidth(3.0);
glBegin(GL_LINE_LOOP);
glVertex2i(StartX, StartY);
glVertex2i(EndX, StartY);
glVertex2i(EndX, EndY);
glVertex2i(StartX, EndY);
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
}
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
glutMainLoop();
return 0;
}
Since you weren't specifying them I added projection and modelview matrices.
I believe the problem lies here:
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(WINDOW_DIM, WINDOW_DIM, GL_RGB, GL_FLOAT, (float*)pixels);
glutSwapBuffers();
rest of drawing
Your render call should look like:
clear
render
swap buffers
Where render is all of your draw calls (including glDrawPixels).
Also, glDrawPixels was removed in OpenGL 3.2. Unless you absolutely need to use that particular method, why not use an orthographic projection to draw GUI elements (which the selection box can be though of as)?
Edit: Also, be aware that if you make draw calls after glDrawPixels, those may overwrite what you drew with glDrawPixels.