Reputation: 87
I am working on a simple paint program using OpenGl. One of the requirements is for the user to be able to change the color of the line using the 1-7 keys, change the size of the stroke with the '+' or '-' keys, and a couple of other cases. I have most of this implemented, but here is where I am having trouble. Whenever I press any key to change the next stroke, it modifies everything that is already drawn on the screen. So if I drew a white squiggle, and then wanted to change the next line I am about to draw to red by pressing the '1' key, it will change the white squiggle I already drew to red. Same goes for size, and/or shape of the brush (triangle and line).
I am not expecting a walkthrough step by step, but some advice on how to proceed.
Here is my code for reference:
#include "stdafx.h"
#include <vector>
#include <gl/glut.h>
#include <gl/gl.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
std::vector<int>mouseX;
std::vector<int>mouseY;
int size=1;
int num = 0;
bool leftClick = false;
void drawShape(int num)
{
if (num == 0) // quad brush
{
for (unsigned int x = 0; x < mouseX.size(); x++)
{
glBegin(GL_POLYGON);
glVertex2f(mouseX[x] - size, mouseY[x] - size);
glVertex2f(mouseX[x] + size, mouseY[x] - size);
glVertex2f(mouseX[x] + size, mouseY[x] + size);
glVertex2f(mouseX[x] - size, mouseY[x] + size);
glEnd();
}
}
if (num == 1) //triangle brush
{
for (unsigned int x = 0; x < mouseX.size(); x++)
{
glBegin(GL_TRIANGLES);
glVertex2f(mouseX[x] - size, mouseY[x] - size);
glVertex2f(mouseX[x] + size, mouseY[x] - size);
glVertex2f(mouseX[x], mouseY[x] + size);
glEnd();
}
}
if (num == 2) //line brush
{
for (unsigned int x = 0; x < mouseX.size(); x++)
{
glBegin(GL_LINES);
glVertex2f(mouseX[x], mouseY[x] - size);
glVertex2f(mouseX[x], mouseY[x] + size);
glEnd();
}
}
if (num == 3) // circle brush
{
for (unsigned int x = 0; x < mouseX.size(); x++)
{
}
}
glFlush();
}
void display(void)
{
glClearColor(0, 0, 0, 0 );
glClear(GL_COLOR_BUFFER_BIT);
drawShape(num);
glFlush();
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case '1': //change the color to red
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 0, 0);
break;
case '2': //change the color to green
glColor3f(0, 1, 0);
break;
case '3': //change the color yellow
glColor3f(1, 1, 0);
break;
case '4': //change the color to blue
glColor3f(0, 0, 1);
break;
case '5': //change the color to magenta
glColor3f(1, 0, 1);
break;
case '6': //change the color to cyan
glColor3f(0, 1, 1);
break;
case '7': //change the color to white
glColor3f(1, 1, 1);
break;
case '=': //increase brush size by 2
if (size < 65)
size = size * 2;
break;
case '-': //decrease brush size by 2
if (size > 1 )
size = size / 2;
break;
case 'b': //cycle through brushes (0 - quad, 1 - triangle, 2 - line, 3 - circle)
num++;
if (num > 3)
num = 0;
break;
case 'c': //clear the screen back to black
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
break;
case 'r': //rotate the brush in 10 degree increments
break;
//EXTRA CREDIT ***case 'a':*** //a spray paint brush that has the edges blurred (transparent)
}
glutPostRedisplay();
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, WINDOW_WIDTH - 1, WINDOW_HEIGHT - 1, 0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
void mouse(int button, int action, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
if (action == GLUT_DOWN)
leftClick = true;
else
leftClick = false;
}
}
void mouseMove(int x, int y)
{
if (leftClick)
{
mouseX.push_back(x);
mouseY.push_back(y);
glutPostRedisplay();
}
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutInitWindowPosition(500, 300);
glutCreateWindow("Christopher Spear - Assignment 1");
init();
glutDisplayFunc(display);
glutMotionFunc(mouseMove);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
Upvotes: 1
Views: 2528
Reputation: 2874
Since OpenGL works as a state machine, it commands like glColor
will change the color until changed again. This is the reason why your other objects get drawn in the selected color as well. You need to keep the current color internally, set it when you draw your line, then reset it when you draw the next object.
ex:
float lineColor[3];
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case '1': //change the color to red
lineColor[0] = 1.0f;
lineColor[1] = 0.0f;
lineColor[2] = 0.0f;
break;
... and so on
}
}
void drawShape(int num)
{
if (num == 0) // quad brush
{
glColor3f(1.0f, 1.0f, 1.0f);
for (unsigned int x = 0; x < mouseX.size(); x++)
{
glBegin(GL_POLYGON);
glVertex2f(mouseX[x] - size, mouseY[x] - size);
glVertex2f(mouseX[x] + size, mouseY[x] - size);
glVertex2f(mouseX[x] + size, mouseY[x] + size);
glVertex2f(mouseX[x] - size, mouseY[x] + size);
glEnd();
}
}
...
if (num == 2) //line brush
{
glColor3fv(lineColor);
for (unsigned int x = 0; x < mouseX.size(); x++)
{
glBegin(GL_LINES);
glVertex2f(mouseX[x], mouseY[x] - size);
glVertex2f(mouseX[x], mouseY[x] + size);
glEnd();
}
}
...
}
So you basically set all relevant states before you draw. Alternatively you can set the color before the line and reset it directly afterwards, so you do not need to care about it in the other draw calls.
Upvotes: 2
Reputation: 7991
This is more of a tip to your homework assignment.
Create a class/struct Vertex that stores all the vertex information in it and you can easily add them together.
struct Vertex {
float x,y;
float r,g,b,a;
};
and create one list std::vector<Vertex> vertices;
, instead of multiple lists for each component. Its the same thing but it would be cleaner. And then you will just use
glVertex3f(vertices[i].x - size, vertices[i].y - size);
Upvotes: 1