#include #include #include #include #include #include #include #include "ui.h" #include "grass_texture_color.h" // close enough #define PI 3.14 // Camera rotation and stuff float camRadius = 10.0; vec3 camCenter = { 0.0, 0.0, 0.0 }; vec3 camRot = { -PI * 0.125, 0.0, 0.0 }; struct { unsigned char lockYMovement: 1; GLenum textureFilter; } settings = { 0, GL_NEAREST, }; vec3 rotateByCameraRotation(vec3 v) { vec3 r; // rotate along the x axis(yz plane) r.z = cosf(camRot.x) * v.z + sinf(camRot.x) * v.y; r.y = -sinf(camRot.x) * v.z + cosf(camRot.x) * v.y; v = r; // rotate along the y axis(xy plane) r.z = cosf(camRot.y) * v.z + sinf(camRot.y) * v.x; r.x = -sinf(camRot.y) * v.z + cosf(camRot.y) * v.x; return r; } // Ui stuff int lastMouseButton = GLUT_LEFT_BUTTON; int lastMouseX = 0, lastMouseY = 0; ui_slider* draggedSlider = NULL; void changeFilterButton(); void lockYButton(); ui_button buttons[] = { { /* pos */ { { 0.9, 0.5, 0.0 }, { -65.0, -20.0, 0.0 } }, /* size */ { 130.0, 40.0, 0.0 }, /* onclick */ changeFilterButton, /* text */ "Cycle filter", 0 }, { { { 0.9, 0.5, 0.0 }, { -50.0, 25.0, 0.0 } }, { 100.0, 40.0, 0.0 }, lockYButton, "Lock Y" } }; ui_slider sliders[] = { { /* pos */ { { 0.9, 0.7, 0.0 }, { -50.0, -5.0, 0.0 } }, /* size */ { 100.0, 10.0, 10.0 }, 0.1 } }; void changeFilterButton() { static int current = 0; GLenum filters[] = { GL_NEAREST, GL_LINEAR }; current = (current + 1) % (sizeof(filters) / sizeof(GLenum)); settings.textureFilter = filters[current]; glutPostRedisplay(); } void lockYButton() { settings.lockYMovement ^= 1; buttons[1].text = settings.lockYMovement ? "Unlock Y" : "Lock Y"; } void drawUi(void) { glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // set ui camera int wWidth = glutGet(GLUT_WINDOW_WIDTH); int wHeight = glutGet(GLUT_WINDOW_HEIGHT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, wWidth, 0.0, wHeight); // Draw buttons for(ui_button* b = buttons; b < buttons + sizeof buttons / sizeof(ui_button); b += 1) { ui_button_draw(b); } for(ui_slider* s = sliders; s < sliders + sizeof sliders / sizeof(ui_slider); s += 1) { ui_slider_draw(s); } int err = glGetError(); if(err != 0) { printf("opengl error %d: %s\n", err, gluErrorString(err)); } } void drawWorld(void) { glEnable(GL_DEPTH_TEST); // set perspective camera GLdouble wWidth = (GLdouble) glutGet(GLUT_WINDOW_WIDTH); GLdouble wHeight = (GLdouble) glutGet(GLUT_WINDOW_HEIGHT); // Calculate current camera position from rotation vec3 cp = vec3_new(0.0, 0.0, camRadius); cp = rotateByCameraRotation(cp); cp = vec3_add(cp, camCenter); vec3 up = rotateByCameraRotation(vec3_new(0.0, 1.0, 0.0)); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(cp.x, cp.y, cp.z, camCenter.x, camCenter.y, camCenter.z, up.x, up.y, up.z); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(90, wWidth / wHeight , 1.0, 500.0); // Lights glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // Directional light - aka light GLfloat light1[] = { 0.0, 1.0, 0.0, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light1); // World // Ground glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, settings.textureFilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, settings.textureFilter); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, grass_color_128); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glColor3f(1.0, 1.0, 0.0); glNormal3f(0.0, 5.0, 0.0); glTexCoord2f(0.0, 0.0); glVertex3f(-50.0, 0.0, -50.0); glTexCoord2f(0.0, 1.0); glVertex3f(-50.0, 0.0, 50.0); glTexCoord2f(1.0, 1.0); glVertex3f(50.0, 0.0, 50.0); glTexCoord2f(1.0, 0.0); glVertex3f(50.0, 0.0, -50.0); glEnd(); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glTranslatef(0.0, 5.0, 0.0); glScalef(3.0, 3.0, 3.0); glColor3f(1.0, 1.0, 1.0); glutSolidDodecahedron(); glPopMatrix(); } void display(void) { // Clear screen glClearColor(0.0, 0.0, 0.0, 1.0); // Dark theme :) glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT); drawWorld(); drawUi(); glutSwapBuffers(); glFlush(); } void mouseEvent(int button, int state, int x, int y) { lastMouseX = x; lastMouseY = y; if(state == 0) lastMouseButton = button; if(state == 0 && button == GLUT_LEFT_BUTTON) { for(ui_button* b = buttons; b < buttons + sizeof buttons / sizeof(ui_button); b += 1) { if(ui_button_mouse_over(b, x, y) && b->onClick != NULL) { b->clicked = 1; } } for(ui_slider* s = sliders; s < sliders + sizeof sliders / sizeof(ui_slider); s += 1) { if(ui_slider_mouse_over(s, x, y)) { ui_slider_onclick(s, x, y); draggedSlider = s; } } } else if(state == 1 && button == GLUT_LEFT_BUTTON) { draggedSlider = NULL; for(ui_button* b = buttons; b < buttons + sizeof buttons / sizeof(ui_button); b += 1) { b->clicked = 0; if(ui_button_mouse_over(b, x, y) && b->onClick != NULL) { b->onClick(); } } } glutPostRedisplay(); } void mouseMotionEvent(int x, int y) { if(lastMouseButton == GLUT_LEFT_BUTTON) { if(draggedSlider != NULL) { if(ui_slider_mouse_over(draggedSlider, x, y)) { ui_slider_onclick(draggedSlider, x, y); } } } else if(lastMouseButton == GLUT_MIDDLE_BUTTON) { vec3 moveX = rotateByCameraRotation(vec3_new(1.0, 0.0, 0.0)); vec3 moveY = rotateByCameraRotation(vec3_new(0.0, 1.0, 0.0)); if(settings.lockYMovement) { moveX.y = 0; moveY.y = 0; } camCenter = vec3_add(camCenter, vec3_mult(moveX, (lastMouseX - x))); camCenter = vec3_add(camCenter, vec3_mult(moveY, (y - lastMouseY))); } else if(lastMouseButton == GLUT_RIGHT_BUTTON) { // rotate the camera camRot.y -= (x - lastMouseX) * PI * 0.01; if(camRot.y > 2 * PI) camRot.y -= 2 * PI; else if(camRot.y < 0.0) camRot.y += 2 * PI; camRot.x = fmin(PI * 0.5, fmax(-PI * 0.5, camRot.x - (y - lastMouseY) * 0.01 * PI)); } lastMouseX = x; lastMouseY = y; glutPostRedisplay(); } void mouseWheelEvent(int wheel, int dir, int x, int y) { char slided = 0; for(ui_slider* s = sliders; s < sliders + sizeof sliders / sizeof(ui_slider); s += 1) { if(ui_slider_mouse_over(s, x, y)) { s->value += dir * 0.05; if(s->value < 0.0) s->value = 0.0; if(s->value > 1.0) s->value = 1.0; slided = 1; } } if(!slided) { camRadius *= 1.0 - (dir * 0.1); } glutPostRedisplay(); } void keyboardEvent(unsigned char c, int x, int y) { if(c == '\e') { glutLeaveMainLoop(); exit(0); } if(c == 'a') { glutPostRedisplay(); } } int main(int argc, char** argv) { /* initialize glut and window */ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(800, 500); glutInitWindowPosition(450, 450); /* create window and set callbacks */ glutCreateWindow("World of Cow"); glutDisplayFunc(display); glutMouseFunc(mouseEvent); glutKeyboardFunc(keyboardEvent); glutMouseWheelFunc(mouseWheelEvent); glutMotionFunc(mouseMotionEvent); // set up some rendering related stuff glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glutMainLoop(); return 0; }