world_of_cow/mmn_17.c

315 lines
9.3 KiB
C
Raw Normal View History

2023-07-03 15:40:28 +00:00
#include <GL/freeglut.h>
#include <GL/freeglut_std.h>
#include <GL/gl.h>
2023-07-05 11:51:36 +00:00
#include <GL/glext.h>
2023-07-05 08:37:27 +00:00
#include <GL/glu.h>
2023-07-03 15:40:28 +00:00
#include <stdio.h>
#include <math.h>
2023-07-05 08:37:27 +00:00
#include "ui.h"
#include "grass_texture_color.h"
#include "help.h"
2023-07-06 10:11:08 +00:00
// close enough
#define PI 3.14
2023-07-05 11:51:36 +00:00
2023-07-06 10:11:08 +00:00
// 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 };
2023-07-11 17:43:01 +00:00
struct {
unsigned char lockYMovement: 1;
unsigned char showHelp: 1;
2023-07-11 17:43:01 +00:00
GLenum textureFilter;
} settings = {
0, 0, GL_NEAREST,
2023-07-11 17:43:01 +00:00
};
struct {
int main;
int cowControl;
int filters;
} menus; // to simply hold the menues in a labed manner
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;
}
2023-07-05 11:51:36 +00:00
2023-07-05 08:37:27 +00:00
// Ui stuff
2023-07-06 10:11:08 +00:00
int lastMouseButton = GLUT_LEFT_BUTTON;
int lastMouseX = 0, lastMouseY = 0;
ui_slider* draggedSlider = NULL;
ui_button buttons[] = {}; // TODO: maybe delete? the menu thing is easier to work with
ui_slider sliders[] = {
{
2023-07-11 17:43:01 +00:00
/* pos */ { { 0.9, 0.7, 0.0 }, { -50.0, -5.0, 0.0 } },
/* size */ { 100.0, 10.0, 10.0 },
0.1
}
};
2023-07-05 11:51:36 +00:00
void drawUi(void) {
glDisable(GL_LIGHTING);
2023-07-11 17:43:01 +00:00
glDisable(GL_DEPTH_TEST);
2023-07-05 11:51:36 +00:00
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);
2023-07-05 08:37:27 +00:00
// 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);
}
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();
}
2023-07-05 08:37:27 +00:00
int err = glGetError();
if(err != 0) {
printf("opengl error %d: %s\n", err, gluErrorString(err));
}
2023-07-05 11:51:36 +00:00
}
void drawWorld(void) {
2023-07-11 17:43:01 +00:00
glEnable(GL_DEPTH_TEST);
2023-07-05 11:51:36 +00:00
// set perspective camera
GLdouble wWidth = (GLdouble) glutGet(GLUT_WINDOW_WIDTH);
GLdouble wHeight = (GLdouble) glutGet(GLUT_WINDOW_HEIGHT);
2023-07-06 10:11:08 +00:00
// Calculate current camera position from rotation
vec3 cp = vec3_new(0.0, 0.0, camRadius);
cp = rotateByCameraRotation(cp);
2023-07-06 10:11:08 +00:00
cp = vec3_add(cp, camCenter);
vec3 up = rotateByCameraRotation(vec3_new(0.0, 1.0, 0.0));
2023-07-06 10:11:08 +00:00
2023-07-05 11:51:36 +00:00
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(cp.x, cp.y, cp.z, camCenter.x, camCenter.y, camCenter.z, up.x, up.y, up.z);
2023-07-05 11:51:36 +00:00
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90, wWidth / wHeight , 1.0, 500.0);
2023-07-05 11:51:36 +00:00
// Lights
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
2023-07-06 10:11:08 +00:00
// Directional light - aka light
2023-07-05 11:51:36 +00:00
GLfloat light1[] = { 0.0, 1.0, 0.0, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light1);
// World
// Ground
2023-07-11 17:43:01 +00:00
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);
2023-07-05 11:51:36 +00:00
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);
2023-07-11 17:43:01 +00:00
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);
2023-07-05 11:51:36 +00:00
glEnd();
glDisable(GL_TEXTURE_2D);
2023-07-11 17:43:01 +00:00
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();
2023-07-05 11:51:36 +00:00
}
void display(void) {
// Clear screen
glClearColor(0.0, 0.0, 0.0, 1.0); // Dark theme :)
glClear(GL_COLOR_BUFFER_BIT);
2023-07-11 17:43:01 +00:00
glClear(GL_DEPTH_BUFFER_BIT);
2023-07-05 11:51:36 +00:00
drawWorld();
drawUi();
2023-07-05 08:37:27 +00:00
glutSwapBuffers();
2023-07-03 15:40:28 +00:00
glFlush();
}
void mouseEvent(int button, int state, int x, int y) {
2023-07-06 10:11:08 +00:00
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 {
// 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));
}
}
2023-07-06 10:11:08 +00:00
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));
2023-07-11 17:43:01 +00:00
if(settings.lockYMovement) {
moveX.y = 0;
moveY.y = 0;
}
2023-07-06 10:11:08 +00:00
camCenter = vec3_add(camCenter, vec3_mult(moveX, (lastMouseX - x)));
camCenter = vec3_add(camCenter, vec3_mult(moveY, (y - lastMouseY)));
2023-07-06 10:11:08 +00:00
}
lastMouseX = x; lastMouseY = y;
glutPostRedisplay();
}
void mouseWheelEvent(int wheel, int dir, int x, int y) {
2023-07-06 10:11:08 +00:00
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;
2023-07-06 10:11:08 +00:00
slided = 1;
}
}
2023-07-06 10:11:08 +00:00
if(!slided) {
camRadius *= 1.0 - (dir * 0.1);
2023-07-06 10:11:08 +00:00
}
glutPostRedisplay();
}
void keyboardEvent(unsigned char c, int x, int y) {
if(c == '\e') {
if(settings.showHelp) {
settings.showHelp = 0;
glutPostRedisplay();
}
else {
glutLeaveMainLoop();
exit(0);
}
}
if(c == 'a') {
glutPostRedisplay();
}
2023-07-03 15:40:28 +00:00
}
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 2: // Show help
settings.showHelp ^= 1;
glutPostRedisplay();
break;
}
}
void onControlCowMenu(int item) {
lastMouseButton = GLUT_RIGHT_BUTTON;
printf("Control cow: %d\n", item);
}
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", 0);
glutAddMenuEntry("Head", 1);
glutAddMenuEntry("Tail", 2);
// 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("Help", 2);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
2023-07-03 15:40:28 +00:00
int main(int argc, char** argv) {
/* initialize glut and window */
glutInit(&argc, argv);
2023-07-11 17:43:01 +00:00
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
2023-07-03 15:40:28 +00:00
glutInitWindowSize(800, 500);
glutInitWindowPosition(450, 450);
/* create window and set callbacks */
2023-07-05 08:37:27 +00:00
glutCreateWindow("World of Cow");
2023-07-03 15:40:28 +00:00
glutDisplayFunc(display);
glutMouseFunc(mouseEvent);
glutKeyboardFunc(keyboardEvent);
glutMouseWheelFunc(mouseWheelEvent);
glutMotionFunc(mouseMotionEvent);
menuSetup();
2023-07-11 17:43:01 +00:00
// set up some rendering related stuff
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
2023-07-03 15:40:28 +00:00
glutMainLoop();
2023-07-03 15:40:28 +00:00
return 0;
}