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
- 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 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/glut.h>
#include <GL/gl.h>
@ -163,10 +164,32 @@ void drawCow(char cowsPOV) {
glScalef(0.2, 1.0, 0.2);
glutSolidSphere(1.0, 8, 8);
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
glColor3f(1.0, 1.0, 1.0);
glDisable(GL_COLOR_MATERIAL);
}
void onCowKeyboardInput(char key) {
switch(control) {
case COW_CONTROL_MOVE:
@ -199,6 +222,6 @@ void setCameraToCowPOV() {
glRotatef(-headRot.y, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, -5.0);
// body
glTranslatef(-cowPos.x, -cowPos.y, -cowPos.z);
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
#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 };
@ -21,10 +24,10 @@ struct {
unsigned char lockYMovement: 1;
unsigned char showHelp: 1;
unsigned char cowsPOV: 1;
unsigned char controlLight: 1;
GLenum textureFilter;
} settings = {
0, 0, 0, GL_NEAREST,
0, 0, 0, 0, GL_NEAREST,
};
struct {
int main;
@ -40,22 +43,21 @@ struct {
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[] = {
{ // ambient red
/* pos */ { { 0.9, 0.9, 0.0 }, { -50.0, -10.0, 0.0 } },
/* size */ { 100.0, 10.0, 10.0 },
0.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.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.3
0.1
},
{ // drag speed
/* 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 } },
/* 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
};
void generateGrassVertexList() {
@ -153,10 +208,6 @@ void drawUi(void) {
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);
}
@ -173,7 +224,14 @@ void drawUi(void) {
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);
if(settings.showHelp) {
glColor3f(0.3, 0.3, 0.3);
glBegin(GL_QUADS);
@ -219,16 +277,32 @@ void drawWorld(void) {
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
// 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);
glEnable(GL_LIGHT0);
// Directional light - aka light
GLfloat light1[] = { 0.0, 1.0, 0.0, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light1);
GLfloat lightColor[] = {0.5, 0.4, 0.1, 1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, lightColor);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightColor);
// 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
@ -291,11 +365,7 @@ 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);
@ -305,12 +375,6 @@ void mouseEvent(int button, int state, int x, int y) {
}
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();
}
@ -324,7 +388,7 @@ void mouseMotionEvent(int x, int y) {
}
else {
// 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;
if(camRot.y > 2 * PI) 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;
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(moveY, (y - lastMouseY) * speed));
}
@ -377,6 +441,16 @@ void keyboardEvent(unsigned char c, int x, int y) {
}
}
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) {
@ -403,11 +477,16 @@ void onMenuItem(int item) {
case 4: // quit
glutLeaveMainLoop();
exit(0);
case 5: // control light source
updateCowControl(COW_CONTROL_NONE);
settings.controlLight = 1;
}
}
void onControlCowMenu(int item) {
lastMouseButton = GLUT_RIGHT_BUTTON;
settings.controlLight = 0;
updateCowControl(item);
}
@ -434,6 +513,7 @@ void menuSetup() {
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);
@ -443,7 +523,7 @@ int main(int argc, char** argv) {
/* initialize glut and window */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 500);
glutInitWindowSize(1280, 720);
glutInitWindowPosition(450, 450);
/* create window and set callbacks */
glutCreateWindow("World of Cow - Aviv Romem");

47
ui.c
View file

@ -7,53 +7,6 @@
#include <stdio.h>
#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) {
int wWidth = glutGet(GLUT_WINDOW_WIDTH);

12
ui.h
View file

@ -7,15 +7,6 @@ typedef struct _ui_position {
vec3 absolute;
} 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 {
ui_pos position;
/* 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
} 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);
char ui_slider_mouse_over(ui_slider* s, int mouseX, int mouseY);
void ui_slider_onclick(ui_slider* s, int mouseX, int mouseY);