552 lines
19 KiB
C
552 lines
19 KiB
C
#include <GL/freeglut.h>
|
|
#include <GL/freeglut_std.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glext.h>
|
|
#include <GL/glu.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include "ui.h"
|
|
#include "grass_texture_color.h"
|
|
#include "help.h"
|
|
#include "cow.h"
|
|
// close enough
|
|
#define PI 3.14
|
|
|
|
// user controlled light thing
|
|
vec3 lightPos = { 0.0, 10, 25.0 };
|
|
|
|
// Camera rotation and stuff
|
|
float camRadius = 40.0;
|
|
vec3 camCenter = { 0.0, 0.0, 0.0 };
|
|
vec3 camRot = { -PI * 0.25, PI, 0.0 };
|
|
// some stuff to remember
|
|
struct {
|
|
unsigned char lockYMovement: 1;
|
|
unsigned char showHelp: 1;
|
|
unsigned char cowsPOV: 1;
|
|
unsigned char controlLight: 1;
|
|
GLenum textureFilter;
|
|
} settings = {
|
|
0, 0, 0, 0, GL_NEAREST,
|
|
};
|
|
struct {
|
|
int main;
|
|
int cowControl;
|
|
int filters;
|
|
} menus; // to simply hold the menues in a labed manner
|
|
// holding the lists, although only 1 was used
|
|
struct {
|
|
GLuint grass;
|
|
} lists;
|
|
|
|
// Ui stuff
|
|
int lastMouseButton = GLUT_LEFT_BUTTON; // for camera movement/rotation, also used with the sliders
|
|
int lastMouseX = 0, lastMouseY = 0; // for camera movement/rotation
|
|
ui_slider* draggedSlider = NULL; // helps when dragging a slider
|
|
ui_slider sliders[] = {
|
|
{ // ambient red
|
|
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -10.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.1
|
|
},
|
|
{ // ambient green
|
|
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -40.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.1
|
|
},
|
|
{ // ambient blue
|
|
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -70.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.1
|
|
},
|
|
{ // drag speed
|
|
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -120.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.5
|
|
},
|
|
{ // rotation speed
|
|
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -170.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.3
|
|
},
|
|
{ // user light - red
|
|
/* pos */ { { 0., 0.9, 0.0 }, { 20.0, -10.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.0
|
|
},
|
|
{ // user light - green
|
|
/* pos */ { { 0.0, 0.9, 0.0 }, { 20.0, -40.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.0
|
|
},
|
|
{ // user light - blue
|
|
/* pos */ { { 0.0, 0.9, 0.0 }, { 20.0, -70.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
1.0
|
|
},
|
|
{ // user light - movement step
|
|
/* pos */ { { 0.0, 0.9, 0.0 }, { 20.0, -100.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.2
|
|
},
|
|
{ // user light - constant attenuation
|
|
/* pos */ { { 0.0, 0.9, 0.0 }, { 20.0, -130.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.0
|
|
},
|
|
{ // user light - linear attenuation
|
|
/* pos */ { { 0.0, 0.9, 0.0 }, { 20.0, -160.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.0
|
|
},
|
|
{ // user light - cubic attenuation
|
|
/* pos */ { { 0.0, 0.9, 0.0 }, { 20.0, -190.0, 0.0 } },
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
|
0.5
|
|
},
|
|
};
|
|
// sliders named, struct to give sliders a name, they are stored in an array to ease handling them
|
|
struct {
|
|
ui_slider* ambientRed;
|
|
ui_slider* ambientGreen;
|
|
ui_slider* ambientBlue;
|
|
ui_slider* dragSpeed;
|
|
ui_slider* rotSpeed;
|
|
ui_slider* lightRed;
|
|
ui_slider* lightGreen;
|
|
ui_slider* lightBlue;
|
|
ui_slider* lightMove;
|
|
ui_slider* lightConAtten;
|
|
ui_slider* lightLinAtten;
|
|
ui_slider* lightQuadAtten;
|
|
} slidersN = {
|
|
sliders, sliders + 1, sliders + 2, sliders + 3, sliders + 4, sliders + 5, sliders + 6,
|
|
sliders + 7, sliders + 8, sliders + 9, sliders + 10, sliders + 11
|
|
};
|
|
// generate a list for the grass, using a list makes it much faster
|
|
// and the correct way to make them wiggle a bit(wind) is using a vertex shader
|
|
// but that was not in the scope of the course
|
|
void generateGrassVertexList() {
|
|
lists.grass = glGenLists(1);
|
|
glNewList(lists.grass, GL_COMPILE);
|
|
glDisable(GL_CULL_FACE); // disable culling so we could see the grass from both directions
|
|
for(float x = -50.0; x < 50.0; x += 1.0) {
|
|
for(float z = -50.0; z < 50.0; z += 1.0) {
|
|
float tx = -0.03 * (rand() % 21), tz = -0.03 * (rand() % 21); // give the grass a bit of randomness in their looks
|
|
glPushMatrix();
|
|
glTranslatef(x, 0.0, z); // move the grass to the locaiton on grid
|
|
glRotatef(rand() % 360, 0.0, 1.0, 0.0); // rotate by a random amount
|
|
glBegin(GL_TRIANGLES);
|
|
glColor3f(0.0, 0.3, 0.0);
|
|
glVertex3f(0.0, 0.0, 0.0);
|
|
glColor3f(0.0, 0.5, 0.0);
|
|
glVertex3f(0.5, 0.0, 0.0);
|
|
glVertex3f(tx, 1.5, tz);
|
|
glColor3f(0.0, 0.2, 0.0);
|
|
glVertex3f(0.0, 0.0, 0.0);
|
|
glVertex3f(0.0, 0.0, 0.5);
|
|
glColor3f(0.0, 0.5, 0.0);
|
|
glVertex3f(tx, 1.5, tz);
|
|
glEnd();
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
glEnable(GL_CULL_FACE);
|
|
glEndList();
|
|
}
|
|
// draws a tree based on the radius and the height in a location based on the matrix stack
|
|
void drawTree(float rad, float height) {
|
|
// Bark
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
glColor3f(0.3, 0.1, 0.3);
|
|
glPushMatrix();
|
|
glTranslatef(0.0, height, 0.0);
|
|
glRotatef(90.0, 1.0, 0.0, 0.0);
|
|
glutSolidCylinder(rad, height, 16, 3);
|
|
glPopMatrix();
|
|
glColor3f(0.0, 1.0, 0.0);
|
|
glPushMatrix();
|
|
glTranslatef(0.0, height, 0.0);
|
|
// leaves, 5 green balls
|
|
vec3 ts[] = {
|
|
vec3_new(1.0, 0.0, 0.0), vec3_new(-1.0, 0.0, 0.0),
|
|
vec3_new(0.0, 0.0, -1.0), vec3_new(0.0, 0.0, 1.0),
|
|
vec3_new(0.0, 1.0, 0.0),
|
|
};
|
|
for(int i = 0; i < 5; i += 1) {
|
|
vec3 t = ts[i];
|
|
glPushMatrix();
|
|
glTranslatef(t.x * rad, t.y * rad, t.z * rad);
|
|
glutSolidSphere(rad * 1.5, 8, 8);
|
|
glPopMatrix();
|
|
}
|
|
glPopMatrix();
|
|
glColor3f(1.0, 1.0, 1.0);
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
}
|
|
// rotates a vector by the camera rotation
|
|
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;
|
|
}
|
|
|
|
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 sliders
|
|
for(ui_slider* s = sliders; s < sliders + sizeof sliders / sizeof(ui_slider); s += 1) {
|
|
ui_slider_draw(s);
|
|
}
|
|
// sliders labels
|
|
glColor3f(1.0, 1.0, 1.0);
|
|
unsigned char t[] = "Ambient light";
|
|
glRasterPos2f(wWidth * 0.9 - glutBitmapLength(GLUT_BITMAP_TIMES_ROMAN_24, t) * 0.5, wHeight * 0.90 + 20.0);
|
|
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, t);
|
|
glRasterPos2f(wWidth * 0.9 - 75.0, wHeight * 0.9 - 10.0);
|
|
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, (unsigned char*)"r\ng\nb");
|
|
unsigned char td[] = "Drag speed";
|
|
unsigned char tr[] = "Rotate speed";
|
|
glRasterPos2f(wWidth * 0.9 - glutBitmapLength(GLUT_BITMAP_TIMES_ROMAN_24, td) * 0.5, wHeight * 0.9 - 100.0);
|
|
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, td);
|
|
glRasterPos2f(wWidth * 0.9 - glutBitmapLength(GLUT_BITMAP_TIMES_ROMAN_24, tr) * 0.5, wHeight * 0.9 - 150.0);
|
|
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, tr);
|
|
// light sliders
|
|
unsigned char t2[] = "Light orb";
|
|
unsigned char side[] = "r\ng\nb\nSpeed\nConstant Atten\nLinear Atten\nQuadraic Atten";
|
|
glRasterPos2f(10.0, wHeight * 0.9 + 20.0);
|
|
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, t2);
|
|
glRasterPos2f(140.0, wHeight * 0.9 - 10.0);
|
|
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, side);
|
|
// show help if needed
|
|
if(settings.showHelp) {
|
|
glColor3f(0.3, 0.3, 0.3);
|
|
glBegin(GL_QUADS);
|
|
glVertex3f(wWidth * 0.1, wHeight * 0.1, 0.0);
|
|
glVertex3f(wWidth * 0.9, wHeight * 0.1, 0.0);
|
|
glVertex3f(wWidth * 0.9, wHeight * 0.9, 0.0);
|
|
glVertex3f(wWidth * 0.1, wHeight * 0.9, 0.0);
|
|
glEnd();
|
|
glColor3f(1.0,1.0,1.0);
|
|
glRasterPos2f(wWidth * 0.12, wHeight * 0.8);
|
|
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, helpString);
|
|
}
|
|
// check for errors
|
|
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);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
if(settings.cowsPOV) {
|
|
setCameraToCowPOV();
|
|
}
|
|
else {
|
|
// 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));
|
|
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 , 0.5, 500.0);
|
|
// Lights
|
|
glEnable(GL_LIGHTING);
|
|
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
|
|
// Ambient light
|
|
GLfloat ambient[] = { slidersN.ambientRed->value, slidersN.ambientGreen->value, slidersN.ambientBlue->value, 1.0 };
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
|
|
// GL_LIGHT0 is reserved for the cow's flashlight
|
|
// user light
|
|
glEnable(GL_LIGHT1);
|
|
GLfloat ulPos[] = { lightPos.x, lightPos.y, lightPos.z, 1.0 };
|
|
GLfloat ulColor[] = { slidersN.lightRed->value, slidersN.lightGreen->value, slidersN.lightBlue->value, 1.0 };
|
|
glLightfv(GL_LIGHT1, GL_POSITION, ulPos);
|
|
glLightfv(GL_LIGHT1, GL_AMBIENT, ulColor);
|
|
glLightfv(GL_LIGHT1, GL_DIFFUSE, ulColor);
|
|
glLightfv(GL_LIGHT1, GL_SPECULAR, ulColor);
|
|
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, slidersN.lightConAtten->value * 5.0 + 0.01);
|
|
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, slidersN.lightLinAtten->value * 0.3);
|
|
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, slidersN.lightQuadAtten->value * 0.01);
|
|
// draw a little glowing orb where it stands
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glTranslatef(lightPos.x, lightPos.y, lightPos.z);
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
glColor3f(1.0, 1.0, 1.0);
|
|
glMaterialfv(GL_FRONT, GL_EMISSION, ulColor);
|
|
glutSolidSphere(1.0, 8, 8);
|
|
GLfloat reset[] = { 0.0, 0.0, 0.0, 1.0 };
|
|
glMaterialfv(GL_FRONT, GL_EMISSION, reset);
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
glPopMatrix();
|
|
// World
|
|
drawCow(settings.cowsPOV);
|
|
// Ground - with a low res grass texture
|
|
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);
|
|
// draw some trees
|
|
glPushMatrix();
|
|
glTranslatef(25.0, 0.0, 25.0);
|
|
drawTree(3.0, 20.0);
|
|
glTranslatef(-50.0, 0.0, 0.0);
|
|
drawTree(2.0, 19.0);
|
|
glPopMatrix();
|
|
// Scary shady cube
|
|
glPushMatrix();
|
|
glTranslatef(0.0, 10.0, 50.0);
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
glColor3f(0.05, 0.05, 0.1);
|
|
GLfloat mat[] = { 0.25, 0.25, 0.25, 0.4, 0.4, 0.4, 0.774597, 0.774597, 0.774597, 0.6 };
|
|
glMaterialf(GL_FRONT, GL_SHININESS, mat[9] * 128.0);
|
|
glMaterialfv(GL_FRONT, GL_AMBIENT, mat);
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat + 3);
|
|
glMaterialfv(GL_FRONT, GL_SPECULAR, mat + 6);
|
|
glutSolidCube(20.0);
|
|
GLfloat matReset[] = {0.0, 0.0, 0.0};
|
|
glMaterialf(GL_FRONT, GL_SHININESS, 0.0);
|
|
glMaterialfv(GL_FRONT, GL_AMBIENT, matReset);
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, matReset);
|
|
glMaterialfv(GL_FRONT, GL_SPECULAR, matReset);
|
|
glPopMatrix();
|
|
glColor3f(0.1, 0.3, 0.0);
|
|
glCallList(lists.grass);
|
|
glColor3f(1.0, 1.0, 1.0);
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
}
|
|
|
|
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) {
|
|
// save the last mouse position
|
|
lastMouseX = x; lastMouseY = y;
|
|
if(state == 0) lastMouseButton = button;
|
|
if(state == 0 && button == GLUT_LEFT_BUTTON) {
|
|
// check if a slider needs to be dragged
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
// release the dragged slider(if there was one)
|
|
else if(state == 1 && button == GLUT_LEFT_BUTTON) {
|
|
draggedSlider = NULL;
|
|
}
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
void mouseMotionEvent(int x, int y) {
|
|
if(lastMouseButton == GLUT_LEFT_BUTTON) {
|
|
if(draggedSlider != NULL) { // drag a slider if needed
|
|
if(ui_slider_mouse_over(draggedSlider, x, y)) {
|
|
ui_slider_onclick(draggedSlider, x, y);
|
|
}
|
|
}
|
|
else {
|
|
// rotate the camera
|
|
float speed = slidersN.rotSpeed->value * 0.095 + 0.005;
|
|
camRot.y -= (x - lastMouseX) * speed;
|
|
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) * speed));
|
|
}
|
|
|
|
}
|
|
else if(lastMouseButton == GLUT_MIDDLE_BUTTON) {
|
|
// drag the camera
|
|
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;
|
|
}
|
|
float speed = slidersN.dragSpeed->value * 0.9 + 0.1;
|
|
camCenter = vec3_add(camCenter, vec3_mult(moveX, (lastMouseX - x) * speed));
|
|
camCenter = vec3_add(camCenter, vec3_mult(moveY, (y - lastMouseY) * speed));
|
|
}
|
|
lastMouseX = x; lastMouseY = y;
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
void mouseWheelEvent(int wheel, int dir, int x, int y) {
|
|
// slide a slider, if no sliders slided the zoom the camera
|
|
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') { // exit help, or program
|
|
if(settings.showHelp) {
|
|
settings.showHelp = 0;
|
|
glutPostRedisplay();
|
|
}
|
|
else {
|
|
glutLeaveMainLoop();
|
|
exit(0);
|
|
}
|
|
}
|
|
onCowKeyboardInput(c);
|
|
// Move light source if applicable
|
|
if(settings.controlLight) {
|
|
// Controls: wasd - movement over xz plane, qe movement over y axle
|
|
// color and such shall be controlled using the sliders
|
|
float step = slidersN.lightMove->value * 9.0 + 1.0; // go from 1 to 10;
|
|
lightPos.x += ((c == 'd') - (c == 'a')) * step;
|
|
lightPos.y += ((c == 'q') - (c == 'e')) * step;
|
|
lightPos.z += ((c == 'w') - (c == 's')) * step;
|
|
glutPostRedisplay();
|
|
}
|
|
}
|
|
// main right click menu
|
|
void onMenuItem(int item) {
|
|
lastMouseButton = -1; // to prevent jumps in view position/rotation
|
|
switch(item) {
|
|
case 0: // Lock y
|
|
settings.lockYMovement ^= 1;
|
|
glutChangeToMenuEntry(3, settings.lockYMovement ? "Unlock Y position" : "Lock Y position", 0);
|
|
break;
|
|
case 1: // cow pov
|
|
settings.cowsPOV ^= 1;
|
|
glutPostRedisplay();
|
|
break;
|
|
case 2: // Show help
|
|
settings.showHelp ^= 1;
|
|
glutPostRedisplay();
|
|
break;
|
|
case 3: // reste view
|
|
camRadius = 40.0;
|
|
camCenter = vec3_new(0.0, 0.0, 0.0);
|
|
camRot = vec3_new(-PI * 0.125, 0.0, 0.0);
|
|
glutPostRedisplay();
|
|
break;
|
|
case 4: // quit
|
|
glutLeaveMainLoop();
|
|
exit(0);
|
|
case 5: // control light source
|
|
updateCowControl(COW_CONTROL_NONE);
|
|
settings.controlLight = 1;
|
|
|
|
}
|
|
}
|
|
// cow control sub menu
|
|
void onControlCowMenu(int item) {
|
|
lastMouseButton = GLUT_RIGHT_BUTTON;
|
|
settings.controlLight = 0;
|
|
updateCowControl(item);
|
|
}
|
|
// filter sub menu
|
|
void onFilterMenu(int item) {
|
|
lastMouseButton = GLUT_RIGHT_BUTTON;
|
|
GLenum filters[] = { GL_LINEAR, GL_NEAREST };
|
|
settings.textureFilter = filters[item];
|
|
}
|
|
|
|
void menuSetup() {
|
|
// control cow sub-menu
|
|
menus.cowControl = glutCreateMenu(onControlCowMenu);
|
|
glutAddMenuEntry("Movement", COW_CONTROL_MOVE);
|
|
glutAddMenuEntry("Head", COW_CONTROL_HEAD);
|
|
glutAddMenuEntry("Tail", COW_CONTROL_TAIL);
|
|
// filters
|
|
menus.filters = glutCreateMenu(onFilterMenu);
|
|
glutAddMenuEntry("Linear", 0);
|
|
glutAddMenuEntry("Nearest", 1);
|
|
|
|
menus.main = glutCreateMenu(onMenuItem);
|
|
glutAddSubMenu("Control Cow", menus.cowControl);
|
|
glutAddSubMenu("Texture filters", menus.filters);
|
|
glutAddMenuEntry("Lock Y position", 0);
|
|
glutAddMenuEntry("Change to Cow POV", 1);
|
|
glutAddMenuEntry("Reset view", 3);
|
|
glutAddMenuEntry("Control point light", 5);
|
|
glutAddMenuEntry("Help", 2);
|
|
glutAddMenuEntry("Quit", 4);
|
|
glutAttachMenu(GLUT_RIGHT_BUTTON);
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
/* initialize glut and window */
|
|
glutInit(&argc, argv);
|
|
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
|
|
glutInitWindowSize(1280, 720);
|
|
glutInitWindowPosition(450, 450);
|
|
/* create window and set callbacks */
|
|
glutCreateWindow("World of Cow - Aviv Romem");
|
|
glutDisplayFunc(display);
|
|
glutMouseFunc(mouseEvent);
|
|
glutKeyboardFunc(keyboardEvent);
|
|
glutMouseWheelFunc(mouseWheelEvent);
|
|
glutMotionFunc(mouseMotionEvent);
|
|
menuSetup();
|
|
// set up some rendering related stuff
|
|
glEnable(GL_CULL_FACE);
|
|
glCullFace(GL_BACK);
|
|
|
|
generateGrassVertexList();
|
|
glutMainLoop();
|
|
|
|
return 0;
|
|
} |