2023/09/25

Absolute devices vs Relative devices


GLUT event types
- window
→ resize, expose , iconify
- mouse
- motion
- keyboard
- idle
→ define what should be done if there is no event in the queue

We have to register callback functions to define these events
- When an event occurs, the appropriate callbackfunction executes
- last line in main.c for GLUT must be glutMainLoop(); which puts the program in an infinite event loop
→ in each cycle thru the loop, glut looks at events in the queue and picks the appropriate callback based on the type
→ glutDisplayFunc
⇒ window first opened
⇒ window is exposed
⇒ user program decides it needs to redraw the scene - animation
⇒ we can force it to update display with glutPostRedisplay. can call this in any callback function except the display on
→ glutMouseFunc
→ glutMotionFunc
→ glutPassiveMotionFunc
→ glutReshapeFunc
→ glutKeyFunc
→ glutIdleFunc
⇒ useful for animation
⇒ can call glutPostRedisplay
⇒ dont draw in this function, but change some animation variables, and then call the redraw function
• this has to be a global because myIdle() doesnt take parameters
⇒ will call as often as it can based on ur hardware (frame rate)

First Animation
#include <math.h>
#define PI 3.14159265
#define DEG_TO_RAD PI/180.0

//updated in myIdle, used in myDisplay
GLFloat theta = 0.0;

void myIdle(){
    theta += 0.002;
    if(theta >= 360){
        theta -= 360;
    }
}

void myDisplay(){
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POLYGON);
        glVertex2f(cos(DEG_TO_RAD * theta), sin(DEG_TO_RAD*theta));
        glVertex2f(cos(DEG_TO_RAD * theta + 90), sin(DEG_TO_RAD*theta + 90));
        glVertex2f(cos(DEG_TO_RAD * theta + 180), sin(DEG_TO_RAD*theta + 180));
        glVertex2f(cos(DEG_TO_RAD * theta + 270), sin(DEG_TO_RAD*theta + 270));
    glEnd();
    glFlush();
}



Partially drawn scenes
- we can't always draw the scne fast enough before the hardware refreshes memory
- partially drawn scene happen when u get a video memory dump to the screen before we've finished drawing
- double buffering solves this problem
→ we don't draw directly to video memory, we're going to draw into an unseen back buffer
→ front buffer is displayed but not written to
→ when openGL has finished drawing, it will send a signal to that it can be sent to the screen
→ transfer from back to front buffer is a fixed time operation. it doesnt matter how long it took the draw the pixels, when they're done theyre just an area of memory. it is a fixed time operation to switch the memory to the other buffer. no longer a function of the scene complexity, its just a fixed time operation
→ call glutSwapBuffers instead of glFlush
→ start off by calling glutInitDisplayMode(GL_RGBA | GL_DOUBLE | GL_DEPTH)
⇒ bitwise OR

typedef GLFloat point2[2];

point2 pointA = {-0.5, -0.2}
point2 pointB = {0.90.7}

GLFloat interp = 0.0;
void myIdle(){
    interp += 0.005;
    if(interp >= 1){
        interp = 0;
    }
    glPostRedisplay()
}

void myDisplay(){
    glClear()
    glBegin(GL_POINTS)
        glColor3f(1,0,0)
        glVertex2fv(pointA)
        glColor3f(0,0,1)
        glVertex2fv(pointB)
        glColor(1,1,1)
        glVertex2f((1-interp)*pointA[0] + interp*pointB[0], (1-interp)*pointA[1] + interp*pointB[1])
    glEnd()
    glutSwapBuffers()

}


2023/09/27 - 12:43
Callbacks

- can exit the program with a simple mouse callback
- must invert the y coordinate returned by the mouse callback
→ openGL drawing coordinates have an origin in the bottom left
→ mouse coordinates start from the top of the screen for some reason
- typically openGL drawing corrdinates are independent from window size

GLint mousePressed = 0;
GLFloat mouseX, mouseY;
GLint windowHeight = 400;
GLint windowWidth = 500;
void myDisplay(){
    glColor(GL_COLOR_BUFFER_BIT)
    if(mousePressed){
        glBegin(GL_POINTS);
            glVertex(mouseX,mouseY);
        gnEnd();
    }
    glFlush()
}

void myMouseButton(int button, int state, int x, int y){
    if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN){
        mousePressed = 1;
        mouseX = (GLFloat) x/ (GLFloat)windowWidth
        mouseY = (GLFloat)windowHeight - (GLFloat)y;
        mouseY = mouseY / (GLFloat)windowHeight;
        glPostRedisplay();
    }

}



Changes to the window size
- have to decide whether you want to react to window size change or not
- if we don't react, object will get distorted
- in addition to changing openGL drawing parameters we also have to fix the viewport
- viewport: subset of the application window
- when we have a reshape event we have to adjust the viewport to the new available size

void myReshape(int newWidth, int newHeight){
    glViewport(0,0,newWidth,newHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity(); //"dont worry about it yet"
    gluOrtho2D(0, (GLFloat)newWidth / (GLFloat)originalWidth, 0, (GLFloat) newHeight/ (GLFloat) originalHeight)

}


Using the keyboard
- define a callback
→ glutKeyboardFunc(myKey)
→ myKey(unsigned char key, int x, int y)
- key release doesnt count as an event


- can also create:
→ menus
→ dynamic windows
→ sub-windows
→ multiple windows
→ changing callbacks during execution

Index