Compare commits

..

3 commits

Author SHA1 Message Date
a1292ce40f
added text to sliders 2023-08-08 20:25:07 +03:00
790fee53b5
cow got a flashlight yay 2023-08-08 20:12:58 +03:00
2fe1b677b7
user controlled light 2023-08-08 19:37:02 +03:00
5 changed files with 141 additions and 100 deletions

View file

@ -6,9 +6,6 @@ Code here is published under the [AGPL-v3](https://www.gnu.org/licenses/agpl-3.0
# TODO # TODO
- User controlled light source
- Add light source
- move the light
- change intensity
- Add popping-floating text of funny cow thoughts when in cow view - Add popping-floating text of funny cow thoughts when in cow view
- Add Textures and stuff :)(optional) - Construct the required pdf with explanations and screenshots
- Properly comment the code :/

25
cow.c
View file

@ -1,3 +1,4 @@
#include <GL/freeglut.h>
#include <GL/freeglut_std.h> #include <GL/freeglut_std.h>
#include <GL/glut.h> #include <GL/glut.h>
#include <GL/gl.h> #include <GL/gl.h>
@ -163,10 +164,32 @@ void drawCow(char cowsPOV) {
glScalef(0.2, 1.0, 0.2); glScalef(0.2, 1.0, 0.2);
glutSolidSphere(1.0, 8, 8); glutSolidSphere(1.0, 8, 8);
glPopMatrix(); // Tails(from sonic the hedgehog) glPopMatrix(); // Tails(from sonic the hedgehog)
// Give the cow a little flashlight because its dark outside
glPushMatrix(); // fl
glTranslatef(0.5, -1.2, 1.4);
glColor3f(0.3, 0.3 ,0.3);
glutSolidCylinder(0.3, 2.0, 8, 1);
glTranslatef(0.0, 0.0, 2.0);
glRotatef(180.0, 0.0, 1.0, 0.0);
glutSolidCone(0.6, 0.6, 8, 2);
glEnable(GL_LIGHT0);
// Directional light - aka light
GLfloat light1[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat lightColor[] = {0.9, 0.9, 0.1, 1.0};
GLfloat dir[] = { 0.0, 0.0, -1.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light1);
glLightfv(GL_LIGHT0, GL_AMBIENT, lightColor);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightColor);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir);
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 30.0);
glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 2.0);
glPopMatrix(); // fl
glPopMatrix(); // cow pos glPopMatrix(); // cow pos
glColor3f(1.0, 1.0, 1.0); glColor3f(1.0, 1.0, 1.0);
glDisable(GL_COLOR_MATERIAL); glDisable(GL_COLOR_MATERIAL);
} }
void onCowKeyboardInput(char key) { void onCowKeyboardInput(char key) {
switch(control) { switch(control) {
case COW_CONTROL_MOVE: case COW_CONTROL_MOVE:
@ -199,6 +222,6 @@ void setCameraToCowPOV() {
glRotatef(-headRot.y, 0.0, 1.0, 0.0); glRotatef(-headRot.y, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, -5.0); glTranslatef(0.0, 0.0, -5.0);
// body // body
glTranslatef(-cowPos.x, -cowPos.y, -cowPos.z);
glRotatef(-cowRot, 0.0, 1.0, 0.0); glRotatef(-cowRot, 0.0, 1.0, 0.0);
glTranslatef(-cowPos.x, -cowPos.y, -cowPos.z);
} }

150
mmn_17.c
View file

@ -13,6 +13,9 @@
// close enough // close enough
#define PI 3.14 #define PI 3.14
// user controlled light thing
vec3 lightPos = { 0.0, 10, 25.0 };
// Camera rotation and stuff // Camera rotation and stuff
float camRadius = 40.0; float camRadius = 40.0;
vec3 camCenter = { 0.0, 0.0, 0.0 }; vec3 camCenter = { 0.0, 0.0, 0.0 };
@ -21,10 +24,10 @@ struct {
unsigned char lockYMovement: 1; unsigned char lockYMovement: 1;
unsigned char showHelp: 1; unsigned char showHelp: 1;
unsigned char cowsPOV: 1; unsigned char cowsPOV: 1;
unsigned char controlLight: 1;
GLenum textureFilter; GLenum textureFilter;
} settings = { } settings = {
0, 0, 0, GL_NEAREST, 0, 0, 0, 0, GL_NEAREST,
}; };
struct { struct {
int main; int main;
@ -40,22 +43,21 @@ struct {
int lastMouseButton = GLUT_LEFT_BUTTON; int lastMouseButton = GLUT_LEFT_BUTTON;
int lastMouseX = 0, lastMouseY = 0; int lastMouseX = 0, lastMouseY = 0;
ui_slider* draggedSlider = NULL; ui_slider* draggedSlider = NULL;
ui_button buttons[] = {}; // TODO: maybe delete? the menu thing is easier to work with
ui_slider sliders[] = { ui_slider sliders[] = {
{ // ambient red { // ambient red
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -10.0, 0.0 } }, /* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -10.0, 0.0 } },
/* size */ { 100.0, 10.0, 10.0 }, /* size */ { 100.0, 10.0, 10.0 },
0.0 0.1
}, },
{ // ambient green { // ambient green
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -40.0, 0.0 } }, /* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -40.0, 0.0 } },
/* size */ { 100.0, 10.0, 10.0 }, /* size */ { 100.0, 10.0, 10.0 },
0.0 0.1
}, },
{ // ambient blue { // ambient blue
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -70.0, 0.0 } }, /* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -70.0, 0.0 } },
/* size */ { 100.0, 10.0, 10.0 }, /* size */ { 100.0, 10.0, 10.0 },
0.3 0.1
}, },
{ // drag speed { // drag speed
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -120.0, 0.0 } }, /* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -120.0, 0.0 } },
@ -66,7 +68,60 @@ ui_slider sliders[] = {
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -170.0, 0.0 } }, /* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -170.0, 0.0 } },
/* size */ { 100.0, 10.0, 10.0 }, /* size */ { 100.0, 10.0, 10.0 },
0.3 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
}; };
void generateGrassVertexList() { void generateGrassVertexList() {
@ -153,10 +208,6 @@ void drawUi(void) {
glLoadIdentity(); glLoadIdentity();
gluOrtho2D(0.0, wWidth, 0.0, wHeight); 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) { for(ui_slider* s = sliders; s < sliders + sizeof sliders / sizeof(ui_slider); s += 1) {
ui_slider_draw(s); ui_slider_draw(s);
} }
@ -173,7 +224,14 @@ void drawUi(void) {
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, td); 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); 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); 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);
if(settings.showHelp) { if(settings.showHelp) {
glColor3f(0.3, 0.3, 0.3); glColor3f(0.3, 0.3, 0.3);
glBegin(GL_QUADS); glBegin(GL_QUADS);
@ -219,16 +277,32 @@ void drawWorld(void) {
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
// Ambient light // Ambient light
GLfloat ambient[] = { sliders[0].value, sliders[1].value, sliders[2].value, 1.0 }; GLfloat ambient[] = { slidersN.ambientRed->value, slidersN.ambientGreen->value, slidersN.ambientBlue->value, 1.0 };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
glEnable(GL_LIGHT0); // GL_LIGHT0 is reserved for the cow's flashlight
// Directional light - aka light // user light
GLfloat light1[] = { 0.0, 1.0, 0.0, 0.0 }; glEnable(GL_LIGHT1);
glLightfv(GL_LIGHT0, GL_POSITION, light1); GLfloat ulPos[] = { lightPos.x, lightPos.y, lightPos.z, 1.0 };
GLfloat lightColor[] = {0.5, 0.4, 0.1, 1.0}; GLfloat ulColor[] = { slidersN.lightRed->value, slidersN.lightGreen->value, slidersN.lightBlue->value, 1.0 };
glLightfv(GL_LIGHT0, GL_AMBIENT, lightColor); glLightfv(GL_LIGHT1, GL_POSITION, ulPos);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); glLightfv(GL_LIGHT1, GL_AMBIENT, ulColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightColor); 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 // World
drawCow(settings.cowsPOV); drawCow(settings.cowsPOV);
// Ground // Ground
@ -291,11 +365,7 @@ void mouseEvent(int button, int state, int x, int y) {
lastMouseX = x; lastMouseY = y; lastMouseX = x; lastMouseY = y;
if(state == 0) lastMouseButton = button; if(state == 0) lastMouseButton = button;
if(state == 0 && button == GLUT_LEFT_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) { for(ui_slider* s = sliders; s < sliders + sizeof sliders / sizeof(ui_slider); s += 1) {
if(ui_slider_mouse_over(s, x, y)) { if(ui_slider_mouse_over(s, x, y)) {
ui_slider_onclick(s, x, y); ui_slider_onclick(s, x, y);
@ -305,12 +375,6 @@ void mouseEvent(int button, int state, int x, int y) {
} }
else if(state == 1 && button == GLUT_LEFT_BUTTON) { else if(state == 1 && button == GLUT_LEFT_BUTTON) {
draggedSlider = NULL; 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(); glutPostRedisplay();
} }
@ -324,7 +388,7 @@ void mouseMotionEvent(int x, int y) {
} }
else { else {
// rotate the camera // rotate the camera
float speed = sliders[4].value * 0.095 + 0.005; float speed = slidersN.rotSpeed->value * 0.095 + 0.005;
camRot.y -= (x - lastMouseX) * speed; camRot.y -= (x - lastMouseX) * speed;
if(camRot.y > 2 * PI) camRot.y -= 2 * PI; if(camRot.y > 2 * PI) camRot.y -= 2 * PI;
else if(camRot.y < 0.0) camRot.y += 2 * PI; else if(camRot.y < 0.0) camRot.y += 2 * PI;
@ -341,7 +405,7 @@ void mouseMotionEvent(int x, int y) {
moveX.y = 0; moveX.y = 0;
moveY.y = 0; moveY.y = 0;
} }
float speed = sliders[3].value * 0.9 + 0.1; 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(moveX, (lastMouseX - x) * speed));
camCenter = vec3_add(camCenter, vec3_mult(moveY, (y - lastMouseY) * speed)); camCenter = vec3_add(camCenter, vec3_mult(moveY, (y - lastMouseY) * speed));
} }
@ -377,6 +441,16 @@ void keyboardEvent(unsigned char c, int x, int y) {
} }
} }
onCowKeyboardInput(c); 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();
}
} }
void onMenuItem(int item) { void onMenuItem(int item) {
@ -403,11 +477,16 @@ void onMenuItem(int item) {
case 4: // quit case 4: // quit
glutLeaveMainLoop(); glutLeaveMainLoop();
exit(0); exit(0);
case 5: // control light source
updateCowControl(COW_CONTROL_NONE);
settings.controlLight = 1;
} }
} }
void onControlCowMenu(int item) { void onControlCowMenu(int item) {
lastMouseButton = GLUT_RIGHT_BUTTON; lastMouseButton = GLUT_RIGHT_BUTTON;
settings.controlLight = 0;
updateCowControl(item); updateCowControl(item);
} }
@ -434,6 +513,7 @@ void menuSetup() {
glutAddMenuEntry("Lock Y position", 0); glutAddMenuEntry("Lock Y position", 0);
glutAddMenuEntry("Change to Cow POV", 1); glutAddMenuEntry("Change to Cow POV", 1);
glutAddMenuEntry("Reset view", 3); glutAddMenuEntry("Reset view", 3);
glutAddMenuEntry("Control point light", 5);
glutAddMenuEntry("Help", 2); glutAddMenuEntry("Help", 2);
glutAddMenuEntry("Quit", 4); glutAddMenuEntry("Quit", 4);
glutAttachMenu(GLUT_RIGHT_BUTTON); glutAttachMenu(GLUT_RIGHT_BUTTON);
@ -443,7 +523,7 @@ int main(int argc, char** argv) {
/* initialize glut and window */ /* initialize glut and window */
glutInit(&argc, argv); glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 500); glutInitWindowSize(1280, 720);
glutInitWindowPosition(450, 450); glutInitWindowPosition(450, 450);
/* create window and set callbacks */ /* create window and set callbacks */
glutCreateWindow("World of Cow - Aviv Romem"); glutCreateWindow("World of Cow - Aviv Romem");

47
ui.c
View file

@ -7,53 +7,6 @@
#include <stdio.h> #include <stdio.h>
#define BACK_COLOR 0.3, 0.35, 0.35 #define BACK_COLOR 0.3, 0.35, 0.35
#define BACK_CLICKED_COLOR 0.25, 0.3, 0.3
void ui_button_draw(ui_button* b) {
int wWidth = glutGet(GLUT_WINDOW_WIDTH);
int wHeight = glutGet(GLUT_WINDOW_HEIGHT);
vec3 pos = vec3_add(b->position.absolute, vec3_new(b->position.relative.x * wWidth, b->position.relative.y * wHeight, 0.0));
vec3 ext = b->size;
glColorVec(b->clicked ? vec3_new(BACK_CLICKED_COLOR) : vec3_new(BACK_COLOR));
glBegin(GL_QUADS);
glVertexVec(pos);
glVertex3f(pos.x + ext.x, pos.y, pos.z);
glVertexVec(vec3_add(pos, ext));
glVertex3f(pos.x, pos.y + ext.y, pos.z);
glEnd();
glColor3f(0.7, 0.7, 0.8);
glLineWidth(2.0);
glBegin(GL_LINE_LOOP);
glVertexVec(pos);
glVertex3f(pos.x + ext.x, pos.y, pos.z);
glVertexVec(vec3_add(pos, ext));
glVertex3f(pos.x, pos.y + ext.y, pos.z);
glEnd();
// Draw text if needed
if(b->text != NULL) {
glColor3f(1.0, 1.0, 1.0);
// Get text size
int textWidth = glutBitmapLength(GLUT_BITMAP_TIMES_ROMAN_24, (unsigned char*)b->text);
int textHeight = glutBitmapHeight(GLUT_BITMAP_TIMES_ROMAN_24);
// set raster position - not gonna take into account multiple line text buttons
vec3 rPos = vec3_add(pos, vec3_mult(ext, 0.5));
rPos.x -= textWidth * 0.5;
rPos.y -= textHeight * 0.25;
glRasterPos3f(rPos.x, rPos.y, rPos.z);
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, (unsigned char*)b->text);
}
}
char ui_button_mouse_over(ui_button* b, int mouseX, int mouseY) {
int wWidth = glutGet(GLUT_WINDOW_WIDTH);
int wHeight = glutGet(GLUT_WINDOW_HEIGHT);
vec3 pos = vec3_add(b->position.absolute, vec3_new(b->position.relative.x * wWidth, b->position.relative.y * wHeight, 0.0));
vec3 ext = b->size;
vec3 m = vec3_sub(vec3_new(mouseX, wHeight - mouseY, 0.0), pos);
return m.x > 0.0 && m.x < ext.x && m.y > 0.0 && m.y < ext.y;
}
void ui_slider_draw(ui_slider* s) { void ui_slider_draw(ui_slider* s) {
int wWidth = glutGet(GLUT_WINDOW_WIDTH); int wWidth = glutGet(GLUT_WINDOW_WIDTH);

12
ui.h
View file

@ -7,15 +7,6 @@ typedef struct _ui_position {
vec3 absolute; vec3 absolute;
} ui_pos; } ui_pos;
typedef struct _ui_button {
ui_pos position;
/* x,y - width,height, z - unused */
vec3 size; // size in pixels - if screen is too small i am not sure if it is a smart idea to make everything smaller
void (*onClick)(); // instead of passing stuff in, im just gonna put every state variable in global scope to ensure everything lives...
char* text;
char clicked;
} ui_button;
typedef struct _ui_slider { typedef struct _ui_slider {
ui_pos position; ui_pos position;
/* x - width, y - height, z - middle circle radius */ /* x - width, y - height, z - middle circle radius */
@ -23,9 +14,6 @@ typedef struct _ui_slider {
float value; // Value will always range between 0 and 1 float value; // Value will always range between 0 and 1
} ui_slider; } ui_slider;
void ui_button_draw(ui_button* b);
char ui_button_mouse_over(ui_button* b, int mouseX, int mouseY);
void ui_slider_draw(ui_slider* s); void ui_slider_draw(ui_slider* s);
char ui_slider_mouse_over(ui_slider* s, int mouseX, int mouseY); char ui_slider_mouse_over(ui_slider* s, int mouseX, int mouseY);
void ui_slider_onclick(ui_slider* s, int mouseX, int mouseY); void ui_slider_onclick(ui_slider* s, int mouseX, int mouseY);