Get OpenGL point size in pixels on Windows? - c++

I am using OpenGL in WinAPI to create a 2D line graph. My points are plotted in point size 8, and I want to adjust the height of the plotted points (and the line connecting them) so that the bottom of the point is at the proper y-position (i.e., so that a point at 0 isn't split by the x-axis).
I had an adjustment hard-coded, but I would rather have it scale with the plotted point size, so that when it's plotted in a different size window, it works the same.
Here is my method for plotting the points and the line connecting them:
void plotScores() {
if (samples > 1) { //if this is at least the second score, connect the scores with a line
glLineWidth(12.0);
GLdouble lineXPos = 0, lineYPos = 0;
glColor3d(0.3, 0.3, 0.3);
glBegin(GL_LINE_STRIP);
for (int i = 0; i < scores.size(); i++) {
lineXPos = (i * 0.05) - 0.88;
lineYPos = ((scores[i] - 0.5) * 1.6); //need to adjust this for line y-position...
glVertex2d(lineXPos, lineYPos);
}
glEnd();
}
for (int i = 0; i < scores.size(); i++) {
GLdouble pointXPos = (i * 0.05) - 0.88;
GLdouble pointYPos = ((scores[i] - 0.5) * 1.6); //...and this for point y-position
if (scores[i] >= threshold) {
glColor3d(0.0, 1.0, 0.2);
}
else {
glColor3d(1.0, 0.2, 0.0);
}
glBegin(GL_POINTS);
glVertex2d(pointXPos, pointYPos);
glEnd();
}
}

You set the point size with glPointSize, so you should know that value. If you want to query it afterwards for some reason, it can be done with glGet and GL_POINT_SIZE enum.

Related

Calculate grid width given a set of points

I am drawing a grid in opengl using this -
void draw_grid()
{
glColor3f(0.32, 0.32, 0.32);
int iterations = int(WIDTH / grid_width) + 1;
glBegin(GL_LINES);
for (int i = 0; i < iterations; i++)
{
int x = i * grid_width;
glVertex2f(x, 0);
glVertex2f(x, HEIGHT);
}
for (int i = 0; i < iterations; i++)
{
int y = i * grid_width;
glVertex2f(0, y);
glVertex2f(WIDTH, y);
}
glEnd();
}
And, then I plot points at the intersections of this grid.
I am implementing simple dda method for drawing lines.
For endpoints (2,3) and (15, 8) I get this as output -
But, for endpoints (2,3) and (35, 8) I get this -
You can see that for the second case some points get plotted outside the window and thus are not visible.
This happens because I have hardcoded the grid_width.
I understand that more the difference between the endpoints the smaller the grid_width is supposed to be.
But I can't figure out how exactly to calculate the grid_width so that no matter what endpoints are given they are drawn in the bounds of the window.
You have to determine the grid_width depending on the maximum coordinate. The maximum width of the grid is WIDTH / maxC where maxC is the maximum coordinate. e.g.:
grid_width = int(WIDTH / maxC);

gluLookAt seems to be producting wrong view, OpenGL

I am working on an nbody simulator and I want to display it with OpenGL. I want to always be looking at the centre of mass reference frame. I have the following code. I calculate the COM and I set the center coordinate in the gluLookAt function to be the center of mass. I then subtract the "zoom" from the z coordinate to get the eye position. By logic this should ensure that I am always looking at whatever value the center of mass is. The only issue is that I marked where the center of mass should be on the screen with a red dot and it is moving. Shouldn't it never move if I am always looking at it from the same relative position? Here is my code. Focus on the display function since I assume that is where the error will be. I had similar code working in another project and I can't really find any differences.
#include "Universe.cuh"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "timer.hpp"
#include <GL/glut.h>
Universe u;
float* vbuf;
double angle = 0.0, zoom = 1000;
void display()
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
float3 c = u.getCenterOfMass();
gluLookAt(c.x, c.y, c.z - zoom, c.x, c.y, c.z, 0, 1, 0);
glScalef(0.1, 0.1, 0.1);
glRotated(angle, 1, 0, 0);
glColor4f(1, 1, 1, 0.25);
glBegin(GL_POINTS);
{
glColor3f(1.0, 0.0, 0.0);
glVertex3d(c.x, c.y, c.z);
}
glEnd();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (double)w / (double)h, 1.0, zoom * 1e9);
glMatrixMode(GL_MODELVIEW);
}
void copy_to_vbuf()
{
for(int i = 0; i < u.size(); i++)
{
vbuf[3 * i + 0] = u.getObjects()[i].p.x;
vbuf[3 * i + 1] = u.getObjects()[i].p.y;
vbuf[3 * i + 2] = u.getObjects()[i].p.z;
}
}
void keyboard(unsigned char c, int x, int y)
{
if(c == 'w')
angle += 1;
else if(c == 's')
angle -= 1;
else if(c == '=')
zoom /= 1.2;
else if(c == '-')
zoom *= 1.2;
glutPostRedisplay();
}
void idle()
{
u.timeStep();
copy_to_vbuf();
glutPostRedisplay();
}
int main(int argc, char** argv)
{
cudaSetDevice(0);
srand(time(0));
u.getConfiguration().max_velocity = 10;
u.getConfiguration().softening_factor = 0.01;
u.getConfiguration().threshold_angle = 35;
u.getConfiguration().time_step = 0.1;
const int N = 5;
vbuf = new float[3 * N];
for(int i = 0; i < N; i++)
{
Object o;
o.m = rand() % 100 + 1;
o.p.x = 500.0 * rand() / RAND_MAX - 250.0;
o.p.y = 500.0 * rand() / RAND_MAX - 250.0;
o.p.z = 500.0 * rand() / RAND_MAX - 250.0;
u.addObject(o);
}
copy_to_vbuf();
glutInit(&argc, argv);
glutInitDisplayMode(GL_DOUBLE);
glutInitWindowSize(1000, 1000);
glutCreateWindow("N-Body");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutIdleFunc(idle);
glutKeyboardFunc(keyboard);
glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPointSize(1.0);
glutMainLoop();
return 0;
}
Two points regarding:
glScalef(0.1, 0.1, 0.1);
glRotated(angle, 1, 0, 0);
Since your axis is not centered on the 'COM', when you apply rotation the COM point will not stay in place and logically would move around the screen.
AFIK the normal order is scale,rotate,translate for transformations. This will apply the rotation and then scale.
EDIT:
To expand on that: Currently you take an arbitrary point rotate it, scale it and then focus on the point where it used to be. If you want to rotate your model (e.g. point marking the 'COM') around itself, it needs to be centered at (0,0,0).

Picking in OpenGL using glRenderMode(GL_SELECT) and glReadPixels

I'm trying to do selection in opengl but it is not working.
I draw objects I receive from a .obj file (v, vn, f, o and such indices). Each object consists from "groups" and each group is a group of GL_POLYGON.
Here is the draw function:
void draw(GLenum mode) {
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(100.0, 0.0, 0.0);
glColor3f(0, 0, 1);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 100.0, 0.0);
glColor3f(0, 1, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 100.0);
glEnd();
glColor4f(1.0, 1.0, 1.0, 1.0);
if (changeFOV) {
fovAngle += fovScale;
changeFOV = false;
setTransformations();
}
for (unsigned int i = 0; i < objects.size(); i++) {
objectItem currObject = objects[i];
for (unsigned int j = 0; j < currObject.getGroups().size(); j++) {
group currGroup = currObject.getGroups().at(j);
for (unsigned int k = 0; k < currGroup.getFs().size(); k++) {
if (mode == GL_SELECT)
glPushName(currGroup.getName());
glPushMatrix();
vector<pair<int, int> > currF = currGroup.getFs()[k];
glBegin(GL_POLYGON);
for (unsigned int kk = 0; kk < currF.size(); kk++) {
Vector3f currVertex = vertexes.at(
(currF.at(kk).first - 1 >= 0) ?
currF.at(kk).first - 1 : 0);
Vector3f currNormal = vertexesNormal.at(
(currF.at(kk).second - 1 >= 0) ?
currF.at(kk).second - 1 : 0);
glNormal3f(currNormal.x, currNormal.y, currNormal.z);
glVertex3f(currVertex.x / 1, currVertex.y / 1,
currVertex.z / 1);
}
glEnd();
glPopMatrix();
}
}
}
}
The drawing works ok and I see the object on the screen.
This is all the picking procedure
/* PICKING */
void processHits(GLint hits, GLuint *buffer) {
float z1, z2;
for (int i = 0; buffer[i] > 0; i += 5) {
z1 = buffer[i + 1] / 4294967295.0;
z2 = buffer[i + 2] / 4294967295.0;
printf("z1 = %f ,z2 = %f zValue = %f\n", z1, z2, zValue[0]);
if ((zValue[0] <= z1 + 0.0001 && zValue[0] >= z2 - 0.0001)
|| (zValue[0] >= z1 - 0.0001 && zValue[0] <= z2 + 0.0001)) { //try to locate which name is correlated with the pressed pixel according to z value
ii = buffer[i + 3];
jj = buffer[i + 4];
}
}
}
void startPicking(GLuint *selectionBuf) {
glSelectBuffer(bufSize, selectionBuf); //declare buffer for input in selection mode
glRenderMode(GL_SELECT); //change to selecting mode
glInitNames(); //initialize names stack
glPushName(-1); //push name
}
void pick(int button, int x, int y) {
//use selection mode to pick
glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_FLOAT, pix);
//printf("depth = %f, x = %d, y = %d\n",pixels[(viewport[3]-y)*512+x],x,viewport[3]-y);
glMatrixMode(GL_PROJECTION);
glReadPixels((GLdouble) x, (GLdouble) viewport[3] - y, 2, 2,
GL_DEPTH_COMPONENT, GL_FLOAT, zValue);
glPushMatrix(); //saves current projection matrix
startPicking(selectionBuf); //preper selection mode
glLoadIdentity();
gluPickMatrix((GLdouble) x, (GLdouble) viewport[3] - y, 1, 1, viewport); //change matrices so only the area of the picking pixel can be seen.
gluPerspective(fovAngle, 1, near, far); //return to perspective state
glMatrixMode(GL_MODELVIEW);
draw(GL_SELECT); //draws board on background
hits = glRenderMode(GL_RENDER); //gets hits number
glMatrixMode(GL_PROJECTION);
glPopMatrix(); //restores projection matrix
glMatrixMode(GL_MODELVIEW);
processHits(hits, selectionBuf); //check hits
if(hits > 0)
printf("touched: %d\n",selectionBuf[3]);
//printf("depth %f hits: %d\n\n",pixels[(viewport[3]-y)*512+x], hits);
if (zValue[0] < 1.0) {
isPick = true;
xx = x;
yy = y;
if (button == GLUT_RIGHT_BUTTON)
zMove = true;
else
zMove = false;
}
}
the pick function is called when the mouse is clicked (using opengl mouse function).
The error I'm receiving is that no objects appears to be hit when clicking on an object.
I'm using Ubuntu 14.04 LTS with Opengl 3.0
I don't know how to ask or what specifically ask, I would appreciate some inputs on the code if you see something wrong..
You seemed to have missed using glPopName()
GLNames used in the selection buffer are pushed on a stack. So unless you call glPopName() the stack would never unwind. The working of this is similar to the calls glPushMatrix() and glPopMatrix().
Typically this is what the code flow looks like.
//Push the name of the primitives on top of selection stack
glPushName(...)
//Set Transformations / Draw the primitives
..
..
//Pop the name (Clear the stack for pushing another name)
glPopName();

drawing figures with opengl

I have an array that contains 0's and 1's and based on the value of the array I want to draw a square and fill it with a color. I have the follow code below, but it only makes 1 square in the middle of the screen. I feel like there is something I need to do with glVertex2f() but I'm kind of stumped.
The end result is something like this
but my code is just one square colored.
for (int i = 0; i < Width; i++) {
for (int j = 0; j < Height; i++) {
if (myArray[i][j] == 0) {
glColor(1.1, 1.1, 1.1);
} else {
glColor(2.2, 2.2, 2.2);
}
glBegin(GL_QUADS);
glVertex2f(-0.2, 0.2);
glVertex2f(0.2, 0.2);
glVertex2f(0.2, 0.2);
glVertex2f(-0.2, 0.2);
glEnd;
}
}
You are drawing all of your squares in the same spot - you need to space them out.
Try adding a translate in front of each draw. Something like:
glPushMatrix();
glTranslatef(2. * i, 2. * j, 0.0) ;
glBegin(GL_QUADS) ;
...
glPopMatrix() ;

create a 3d playing surface/game board in opengl- c++

I am trying to create a 3D box, that would play the role of a playing board/surface/room for a 3D game in C++, using OpenGl. As a starting point I found some code that does that for a 2D surface. My question would be how to modify the following code to serve my purpose:
for (float i = -width; i + 0.1 <= width; i += 0.1) {
for (float j = -height; j + 0.1 <= height; j+= 0.1) {
glBegin(GL_QUADS);
glNormal3f(0, 1, 0);
glVertex3f(i, 0, j);
glVertex3f(i, 0, j + 0.1);
glVertex3f(i + 0.1, 0, j + 0.1);
glVertex3f(i + 0.1, 0, j);
glEnd();
}
}
Thanks a lot.
You can either use above code 6 times but each time apply different rotation/translation matrix, or you can do it the right way and generate correct geometry for missing 5 walls of your box. There are lots of samples for drawing cubes, ie.:
http://www.opengl.org/resources/code/samples/glut_examples/examples/examples.html