每当我尝试用鼠标输入两个顶点时,我都会崩溃。我最近改变了我组织每个形状的方式,以确保新形状与旧形状重叠。
这个项目的想法是制作各种各样的交互式画布。用户可以选择直线,三角形和矩形,然后选择颜色和更多功能。
我知道线条和三角形的代码工作,矩形应该工作但我不能测试它由于崩溃。
我认为我的问题出现在鼠标左键释放区域。特别是将形状id添加到" StructArray"中的每个结构。阵列。我确定它只是一种可以忽视的东西。
另外一个补充说明,我的班级正在使用旧的openGL,所以程序中已经存在的任何openGL代码都需要保留,我不能使用新的东西或基于着色器的东西。
如果您需要任何澄清,请告诉我。
我已经包含了C文件以及头文件(UPDATE V2):
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <OpenGL/glu.h>
#include "lineseg.h"
#include "triseg.h"
#include "rectseg.h"
#include "colors.h"
#define MAXLINES 100
typedef struct shapes{
int id;
} shapes;
enum {LINE, TRIANGLE, RECTANGLE};
shapes *ShapeArray[MAXLINES];
int currentcolor = BLACK;
GLfloat drawingcolor[][3] = {{0.0, 0.0, 0.0},
{1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}};
char *colorword[] = {"black", "red", "green", "blue"};
int shapenum = 0; // Number of shapes drawn
int linenum = 0;
Ln *LineSegments[MAXLINES]; // LineSegments is an array of pointers to Ln
Tri *TriangleSegments[MAXLINES]; // TriangleSegments is an array of pointers to Tri
Rect *RectangleSegments[MAXLINES]; // RectangelSegments is an array of pointers to Rect
int NumVertex = 2;
GLint currentx, currenty; // Used to store cursor coordinates
GLdouble dx, dy; // Passed to GetCursorPos, which needs pointers to doubles
GLint winwidth = 700, winheight = 700; // Window width and height
V2d *firstvert = NULL, *secondvert = NULL, *thirdvert = NULL, *fourthvert = NULL; // Pointers to vertices currently being drawn
V2d *make_vertex(int x, int y) {
V2d *tmp;
tmp = (V2d *) malloc(sizeof(V2d));
if (tmp == NULL) {
printf("Out of memory\n");
exit(0);
}
tmp->x = x;
tmp->y = y;
return tmp;
}
Ln *make_line(V2d v1, V2d v2) {
Ln *tmp;
tmp = (Ln *) malloc(sizeof(Ln));
if (tmp == NULL) {
printf("Out of memory\n");
exit(0);
}
tmp->v1 = v1;
tmp->v2 = v2;
return tmp;
}
Tri *make_triangle(V2d v1, V2d v2, V2d v3){
Tri *tmp;
tmp = (Tri *) malloc(sizeof(Tri));
if (tmp == NULL) {
printf("Out of memory\n");
exit(0);
}
tmp->v1 = v1;
tmp->v2 = v2;
tmp->v3 = v3;
return tmp;
}
Rect *make_rectangle(V2d v1, V2d v2){
Rect *tmp;
tmp = (Rect *) malloc(sizeof(Rect));
if (tmp == NULL) {
printf("Out of memory\n");
exit(0);
}
tmp->v1 = v1;
tmp->v2 = v2;
return tmp;
}
void myInit(void)
{
glViewport(0, 0, winwidth, winheight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, winwidth, 0.0, winheight);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(1.0, 1.0, 1.0, 1.0);
glPointSize(5.0); // size used when rendering points
glLineWidth(2.0); // width used when rendering lines
glLineStipple(2, 0xAAAA); // stippling pattern used when drawing a dotted line
printf("Drawing in %s\n", colorword[currentcolor]);
}
void draw(void){
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (int i = 0; i < shapenum; i++){
if (ShapeArray[i]->id == LINE) {
// Draw all lines that are already drawn and stored in the array LineSegments
glColor3fv(drawingcolor[LineSegments[i]->color]);
glBegin(GL_LINES);
glVertex2i(LineSegments[i]->v1.x, LineSegments[i]->v1.y);
glVertex2i(LineSegments[i]->v2.x, LineSegments[i]->v2.y);
glEnd();
// Draw the segment that is currently being drawn
if (firstvert != NULL) {
glColor3fv(drawingcolor[currentcolor]);
glBegin(GL_POINTS);
glVertex2i(firstvert->x, firstvert->y);
glEnd();
}
if (secondvert != NULL) {
glColor3fv(drawingcolor[currentcolor]);
glBegin(GL_POINTS);
glVertex2i(secondvert->x, secondvert->y);
glEnd();
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex2i(firstvert->x, firstvert->y);
glVertex2i(secondvert->x, secondvert->y);
glEnd();
glDisable(GL_LINE_STIPPLE);
}
}
else if (ShapeArray[i]->id == TRIANGLE){
glColor3fv(drawingcolor[TriangleSegments[i]->color]);
glBegin(GL_LINE_LOOP);
glVertex2i(TriangleSegments[i]->v1.x, TriangleSegments[i]->v1.y);
glVertex2i(TriangleSegments[i]->v2.x, TriangleSegments[i]->v2.y);
glVertex2i(TriangleSegments[i]->v3.x, TriangleSegments[i]->v3.y);
glEnd();
if (firstvert != NULL) {
glColor3fv(drawingcolor[currentcolor]);
glBegin(GL_POINTS);
glVertex2i(firstvert->x, firstvert->y);
glEnd();
}
if (secondvert != NULL) {
glColor3fv(drawingcolor[currentcolor]);
glBegin(GL_POINTS);
glVertex2i(secondvert->x, secondvert->y);
glEnd();
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINE_LOOP);
glVertex2i(firstvert->x, firstvert->y);
glVertex2i(secondvert->x, secondvert->y);
glVertex2i(thirdvert->x, thirdvert->y);
glEnd();
glDisable(GL_LINE_STIPPLE);
}
}
else if (ShapeArray[i]->id == RECTANGLE){
glColor3fv(drawingcolor[RectangleSegments[i]->color]);
glBegin(GL_LINE_LOOP);
glVertex2i(RectangleSegments[i]->v1.x, RectangleSegments[i]->v1.y);
glVertex2i(RectangleSegments[i]->v2.x, RectangleSegments[i]->v1.y);
glVertex2i(RectangleSegments[i]->v2.x, RectangleSegments[i]->v2.y);
glVertex2i(RectangleSegments[i]->v1.x, RectangleSegments[i]->v2.y);
glEnd();
if (firstvert != NULL) {
glColor3fv(drawingcolor[currentcolor]);
glBegin(GL_POINTS);
glVertex2i(firstvert->x, firstvert->y);
glEnd();
}
if (secondvert != NULL) {
glColor3fv(drawingcolor[currentcolor]);
glBegin(GL_POINTS);
glVertex2i(secondvert->x, secondvert->y);
glEnd();
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINE_LOOP);
glVertex2i(firstvert->x, firstvert->y);
glVertex2i(secondvert->x, secondvert->y);
glEnd();
glDisable(GL_LINE_STIPPLE);
}
}
}
}
void keyboard(GLFWwindow *w, int key, int scancode, int action, int mods) {
if (action == GLFW_PRESS)
switch (key) {
case GLFW_KEY_R:
currentcolor = (currentcolor != RED)?RED:BLACK;
printf("Now drawing in %s\n", colorword[currentcolor]);
break;
case GLFW_KEY_G:
currentcolor = (currentcolor != GREEN)?GREEN:BLACK;
printf("Now drawing in %s\n", colorword[currentcolor]);
break;
case GLFW_KEY_B:
currentcolor = (currentcolor != BLUE)?BLUE:BLACK;
printf("Now drawing in %s\n", colorword[currentcolor]);
break;
case GLFW_KEY_ESCAPE:
case GLFW_KEY_Q:
printf("Exiting Program!\n");
glfwSetWindowShouldClose(w, GL_TRUE);
break;
case GLFW_KEY_C:
printf("Now clearing window!\n");
shapenum = 0; //clear shapes
for (int i = 0; i < MAXLINES; i++){
free(ShapeArray[i]);
}
break;
case GLFW_KEY_F:
printf("Fill mode selected\n");
break;
case GLFW_KEY_F1:
printf("Line mode selected\n");
NumVertex = 2; //Line mode
break;
case GLFW_KEY_F2:
printf("Triangle mode selected\n");
NumVertex = 3; //Triangle mode
break;
case GLFW_KEY_F3:
printf("Rectangle mode selected\n");
NumVertex = 4; //rectangle mode
break;
}
}
// Cursor motion callback. Used only when mousebutton is pressed
// for first vertex and not released
void cursor(GLFWwindow *w, GLdouble cursorx, GLdouble cursory) {
/* As the mouse moves, the second vertex is updated constantly. */
/* Free old copies of secondvert before updating */
currentx = (GLint)cursorx;
currenty = (GLint)cursory;
free(secondvert);
secondvert = make_vertex(currentx, winheight - currenty);
}
// Mouse button callback
void mouse(GLFWwindow *w, int button, int action, int mods) {
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if (action == GLFW_PRESS) {
printf("%d\n",shapenum);
glfwGetCursorPos(w, &dx, &dy);
currentx = (GLint)dx;
currenty = (GLint)dy;
if (NumVertex == 2){
if (firstvert == NULL) {/* save first vertex and register cursor motion callback for rubberbanding effect */
firstvert = make_vertex(currentx, winheight - currenty);
glfwSetCursorPosCallback(w, cursor); // Set cursor motion callback
}
else /* save second vertex of segment */
secondvert = make_vertex(currentx, winheight - currenty);
}
else if (NumVertex == 3){
if (firstvert == NULL) {/* save first vertex and register cursor motion callback for rubberbanding effect */
firstvert = make_vertex(currentx, winheight - currenty);
//glfwSetCursorPosCallback(w, cursor); // Set cursor motion callback
}
else if (secondvert == NULL){/* save second vertex of segment */
secondvert = make_vertex(currentx, winheight - currenty);
//glfwSetCursorPosCallback(w, cursor);
}
else if (thirdvert == NULL){
thirdvert = make_vertex(currentx, winheight - currenty);
//glfwSetCursorPosCallback(w, cursor);
}
}
else if (NumVertex == 4){
if (firstvert == NULL) {/* save first vertex and register cursor motion callback for rubberbanding effect */
firstvert = make_vertex(currentx, winheight - currenty);
glfwSetCursorPosCallback(w, cursor); // Set cursor motion callback
}
else{/* save second vertex of segment */
secondvert = make_vertex(currentx, winheight - currenty);
}
}
} /* end mouse press action */
else { // -----------------------------------------------NEED TO WORK OUT-----------------
if (action == GLFW_RELEASE) {
glfwSetCursorPosCallback(w, NULL); /* When button is released, disable cursor motion callback */
if (NumVertex == 2){
if (secondvert != NULL) {
/* create a new line and put it in array (if size not exceeded). Set its color and id */
if (shapenum < MAXLINES) {
LineSegments[shapenum] = make_line(*firstvert, *secondvert);
LineSegments[shapenum]->color = currentcolor;
LineSegments[shapenum]->id = shapenum;
ShapeArray[shapenum]->id = LINE;
shapenum++;
firstvert = NULL;
secondvert = NULL;
}
else
printf("Maximum of %d reached. Cannot draw any more lines.\n", MAXLINES);
}
}
else if (NumVertex == 3){
if (thirdvert != NULL) {
if (shapenum < MAXLINES) {
TriangleSegments[shapenum] = make_triangle(*firstvert, *secondvert, *thirdvert);
TriangleSegments[shapenum]->color = currentcolor;
TriangleSegments[shapenum]->id = shapenum;
ShapeArray[shapenum]->id = TRIANGLE;
shapenum++;
firstvert = NULL;
secondvert = NULL;
thirdvert = NULL;
}
else
printf("Maximum of %d reached. Cannot draw any more lines.\n", MAXLINES);
}
}
else if (NumVertex == 4){
if (secondvert != NULL) {
if (shapenum < MAXLINES) {
RectangleSegments[shapenum] = make_rectangle(*firstvert, *secondvert);
RectangleSegments[shapenum]->color = currentcolor;
RectangleSegments[shapenum]->id = shapenum;
ShapeArray[shapenum]->id = RECTANGLE;
shapenum++;
firstvert = NULL;
secondvert = NULL;
}
else
printf("Maximum of %d reached. Cannot draw any more lines.\n", MAXLINES);
}
}
}
} /* end mouse release action */
} /* end left mouse click action */
}
int main(int argc, char** argv) {
GLFWwindow* window;
const GLubyte* renderer;
const GLubyte* version;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(winwidth, winheight, "HW_1", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
for (int i = 0; i < MAXLINES; i++){
ShapeArray[i] = malloc(sizeof *ShapeArray[i]);
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
/* get version info */
renderer = glGetString (GL_RENDERER); /* get renderer string */
version = glGetString (GL_VERSION); /* version as a string */
printf ("Renderer: %s\n", renderer);
printf ("OpenGL version supported %s\n", version);
myInit();
glfwSetKeyCallback(window, keyboard); /* Callback functions */
glfwSetMouseButtonCallback(window, mouse);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
draw();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
return 0;
}
triseg.h
// struct for triangle segments
typedef struct triangle {
V2d v1;
V2d v2;
V2d v3;
int color;
int id;
} Tri;
Tri *make_triangle(V2d v1, V2d v2, V2d v3);
colors.h
enum {BLACK, RED, GREEN, BLUE};
rectseg.h
// struct for rectangle segments
typedef struct rectangle {
V2d v1;
V2d v2;
V2d v3;
V2d v4;
int color;
int id;
} Rect;
Rect *make_rectangle(V2d v1, V2d v2, V2d v3, V2d v4);
lineseg.h
// struct for two dimensional vertex
typedef struct vertex2d {
int x;
int y;
} V2d;
// struct for line segments
typedef struct line {
V2d v1;
V2d v2;
int color;
int id;
} Ln;
V2d *make_vertex(int x, int y);
Ln *make_line(V2d v1, V2d v2);
答案 0 :(得分:2)
您将ShapeArray
创建为指针数组
shapes *ShapeArray[MAXLINES];
但我没有看到任何代码,你实际上在数组中为shapes
内存了malloc内存。所以当你这样做时:
ShapeArray[shapenum]->id = LINE;
我怀疑你是通过NULL
指针访问的。
也许你应该像这样声明ShapeArray
:
shapes ShapeArray[MAXLINES];
然后像这样访问:
ShapeArray[shapenum].id = LINE;
或者只是某处shapes
的malloc空间。
我还注意到你的draw
函数似乎有点困惑。您目前在两个嵌套循环中使用i
作为循环迭代器,这不会按预期执行。
我认为内部循环不是必需的,所以如果我们只看一下函数的头部,你应该做更多的事情:
void draw(void){
// Clear screen ahead of drawing all shapes
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Loop over each shape.
for (int i = 0; i < shapenum; i++){
// Is THIS shape a LINE?
if (ShapeArray[i]->id == LINE) {
// It is! Lets draw ONE line shape.
glColor3fv(drawingcolor[LineSegments[i]->color]);
glBegin(GL_LINES);
glVertex2i(LineSegments[i]->v1.x, LineSegments[i]->v1.y);
glVertex2i(LineSegments[i]->v2.x, LineSegments[i]->v2.y);
glEnd();
}
// .... rest of function also needs fixing ...