diff --git a/mmn_17.c b/mmn_17.c index 6b29ace..8ed6871 100644 --- a/mmn_17.c +++ b/mmn_17.c @@ -13,6 +13,9 @@ // close enough #define PI 3.14 +// user controlled light thing +vec3 lightPos = { 0.0, 0.0, 0.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.1, 0.9, 0.0 }, { 0.0, -10.0, 0.0 } }, + /* size */ { 100.0, 10.0, 10.0 }, + 0.0 + }, + { // user light - green + /* pos */ { { 0.1, 0.9, 0.0 }, { 0.0, -40.0, 0.0 } }, + /* size */ { 100.0, 10.0, 10.0 }, + 0.0 + }, + { // user light - blue + /* pos */ { { 0.1, 0.9, 0.0 }, { 0.0, -70.0, 0.0 } }, + /* size */ { 100.0, 10.0, 10.0 }, + 0.0 + }, + { // user light - movement step + /* pos */ { { 0.1, 0.9, 0.0 }, { 0.0, -100.0, 0.0 } }, + /* size */ { 100.0, 10.0, 10.0 }, + 0.2 + }, + { // user light - constant attenuation + /* pos */ { { 0.1, 0.9, 0.0 }, { 0.0, -130.0, 0.0 } }, + /* size */ { 100.0, 10.0, 10.0 }, + 0.0 + }, + { // user light - linear attenuation + /* pos */ { { 0.1, 0.9, 0.0 }, { 0.0, -160.0, 0.0 } }, + /* size */ { 100.0, 10.0, 10.0 }, + 0.0 + }, + { // user light - cubic attenuation + /* pos */ { { 0.1, 0.9, 0.0 }, { 0.0, -190.0, 0.0 } }, + /* size */ { 100.0, 10.0, 10.0 }, + 0.0 + }, +}; +// 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); } @@ -219,16 +270,39 @@ 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); + // 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); + // 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 * 10.0 + 0.01); + glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, slidersN.lightLinAtten->value * 0.5); + glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, slidersN.lightQuadAtten->value * 0.5); + // 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); diff --git a/ui.c b/ui.c index 5204707..140e6b0 100644 --- a/ui.c +++ b/ui.c @@ -7,53 +7,6 @@ #include #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); diff --git a/ui.h b/ui.h index 5e2a26b..703dc2b 100644 --- a/ui.h +++ b/ui.h @@ -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);