坚持使用交互式openGL程序

时间:2016-09-29 04:06:05

标签: c opengl shapes

每当我尝试用鼠标输入两个顶点时,我都会崩溃。我最近改变了我组织每个形状的方式,以确保新形状与旧形状重叠。

这个项目的想法是制作各种各样的交互式画布。用户可以选择直线,三角形和矩形,然后选择颜色和更多功能。

我知道线条和三角形的代码工作,矩形应该工作但我不能测试它由于崩溃。

我认为我的问题出现在鼠标左键释放区域。特别是将形状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);

1 个答案:

答案 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 ...