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"
|
2023-07-11 10:20:38 +00:00
|
|
|
#include "grass_texture_color.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 };
|
2023-07-11 10:20:38 +00:00
|
|
|
vec3 camRot = { -PI * 0.125, 0.0, 0.0 };
|
2023-07-11 17:43:01 +00:00
|
|
|
struct {
|
|
|
|
unsigned char lockYMovement: 1;
|
|
|
|
GLenum textureFilter;
|
|
|
|
} settings = {
|
|
|
|
0, GL_NEAREST,
|
|
|
|
};
|
2023-07-11 10:20:38 +00:00
|
|
|
|
|
|
|
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;
|
2023-07-11 17:43:01 +00:00
|
|
|
void changeFilterButton();
|
|
|
|
void lockYButton();
|
2023-07-05 08:37:27 +00:00
|
|
|
ui_button buttons[] = {
|
|
|
|
{
|
2023-07-11 10:20:38 +00:00
|
|
|
/* pos */ { { 0.9, 0.5, 0.0 }, { -65.0, -20.0, 0.0 } },
|
|
|
|
/* size */ { 130.0, 40.0, 0.0 },
|
2023-07-11 17:43:01 +00:00
|
|
|
/* onclick */ changeFilterButton,
|
|
|
|
/* text */ "Cycle filter",
|
2023-07-06 08:24:46 +00:00
|
|
|
0
|
2023-07-11 17:43:01 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
{ { 0.9, 0.5, 0.0 }, { -50.0, 25.0, 0.0 } },
|
|
|
|
{ 100.0, 40.0, 0.0 },
|
|
|
|
lockYButton,
|
|
|
|
"Lock Y"
|
2023-07-05 08:37:27 +00:00
|
|
|
}
|
|
|
|
};
|
2023-07-05 09:24:14 +00:00
|
|
|
ui_slider sliders[] = {
|
|
|
|
{
|
2023-07-11 17:43:01 +00:00
|
|
|
/* pos */ { { 0.9, 0.7, 0.0 }, { -50.0, -5.0, 0.0 } },
|
2023-07-11 10:20:38 +00:00
|
|
|
/* size */ { 100.0, 10.0, 10.0 },
|
2023-07-05 09:24:14 +00:00
|
|
|
0.1
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-07-11 17:43:01 +00:00
|
|
|
void changeFilterButton() {
|
|
|
|
static int current = 0;
|
|
|
|
GLenum filters[] = { GL_NEAREST, GL_LINEAR };
|
|
|
|
current = (current + 1) % (sizeof(filters) / sizeof(GLenum));
|
|
|
|
settings.textureFilter = filters[current];
|
2023-07-05 11:51:36 +00:00
|
|
|
glutPostRedisplay();
|
|
|
|
}
|
2023-07-11 17:43:01 +00:00
|
|
|
void lockYButton() {
|
|
|
|
settings.lockYMovement ^= 1;
|
|
|
|
buttons[1].text = settings.lockYMovement ? "Unlock Y" : "Lock Y";
|
|
|
|
}
|
2023-07-03 15:40:28 +00:00
|
|
|
|
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);
|
|
|
|
}
|
2023-07-05 09:24:14 +00:00
|
|
|
for(ui_slider* s = sliders; s < sliders + sizeof sliders / sizeof(ui_slider); s += 1) {
|
|
|
|
ui_slider_draw(s);
|
|
|
|
}
|
|
|
|
|
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
|
2023-07-11 10:20:38 +00:00
|
|
|
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);
|
2023-07-11 10:20:38 +00:00
|
|
|
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();
|
2023-07-11 10:20:38 +00:00
|
|
|
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();
|
2023-07-11 10:20:38 +00:00
|
|
|
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
|
2023-07-11 10:20:38 +00:00
|
|
|
// 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);
|
2023-07-11 10:20:38 +00:00
|
|
|
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);
|
2023-07-11 10:20:38 +00:00
|
|
|
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();
|
2023-07-11 10:20:38 +00:00
|
|
|
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;
|
2023-07-06 08:24:46 +00:00
|
|
|
if(state == 0) lastMouseButton = button;
|
|
|
|
if(state == 0 && button == GLUT_LEFT_BUTTON) {
|
2023-07-05 09:24:14 +00:00
|
|
|
for(ui_button* b = buttons; b < buttons + sizeof buttons / sizeof(ui_button); b += 1) {
|
2023-07-06 08:24:46 +00:00
|
|
|
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;
|
2023-07-05 09:24:14 +00:00
|
|
|
if(ui_button_mouse_over(b, x, y) && b->onClick != NULL) {
|
|
|
|
b->onClick();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-06 08:24:46 +00:00
|
|
|
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);
|
|
|
|
}
|
2023-07-05 09:24:14 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-06 10:11:08 +00:00
|
|
|
else if(lastMouseButton == GLUT_MIDDLE_BUTTON) {
|
2023-07-11 10:20:38 +00:00
|
|
|
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
|
|
|
|
2023-07-11 10:20:38 +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
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2023-07-11 10:20:38 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
lastMouseX = x; lastMouseY = y;
|
2023-07-06 08:24:46 +00:00
|
|
|
glutPostRedisplay();
|
2023-07-05 09:24:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mouseWheelEvent(int wheel, int dir, int x, int y) {
|
2023-07-06 10:11:08 +00:00
|
|
|
char slided = 0;
|
2023-07-05 09:24:14 +00:00
|
|
|
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-05 09:24:14 +00:00
|
|
|
}
|
|
|
|
}
|
2023-07-06 10:11:08 +00:00
|
|
|
if(!slided) {
|
2023-07-11 10:20:38 +00:00
|
|
|
camRadius *= 1.0 - (dir * 0.1);
|
2023-07-06 10:11:08 +00:00
|
|
|
}
|
2023-07-05 09:24:14 +00:00
|
|
|
glutPostRedisplay();
|
|
|
|
}
|
|
|
|
|
|
|
|
void keyboardEvent(unsigned char c, int x, int y) {
|
|
|
|
if(c == '\e') {
|
|
|
|
glutLeaveMainLoop();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
if(c == 'a') {
|
|
|
|
glutPostRedisplay();
|
|
|
|
}
|
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);
|
2023-07-05 09:24:14 +00:00
|
|
|
glutKeyboardFunc(keyboardEvent);
|
|
|
|
glutMouseWheelFunc(mouseWheelEvent);
|
2023-07-06 08:24:46 +00:00
|
|
|
glutMotionFunc(mouseMotionEvent);
|
2023-07-11 17:43:01 +00:00
|
|
|
// set up some rendering related stuff
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
glCullFace(GL_BACK);
|
2023-07-11 10:20:38 +00:00
|
|
|
|
2023-07-03 15:40:28 +00:00
|
|
|
glutMainLoop();
|
2023-07-11 10:20:38 +00:00
|
|
|
|
2023-07-03 15:40:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|