X-Git-Url: http://git.mutantstargoat.com?p=faros-demo;a=blobdiff_plain;f=src%2Fmain.cc;h=b889a0f082de5d719b9783deb93366a3a586ab5a;hp=64ce2fc2e3a7bfac01dce7f27f276cfc79f87fde;hb=HEAD;hpb=08dfe45a9c75333375791380ed5ed44ceda1e904 diff --git a/src/main.cc b/src/main.cc index 64ce2fc..b889a0f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -4,76 +4,82 @@ #include #include #include +#include #include "sdr.h" - -#define CURVE_VS "sdr/curve_top.v.glsl" -#define CURVE_FS "sdr/curve_top.f.glsl" -#define BEAM_VS "sdr/beam.v.glsl" -#define BEAM_FS "sdr/beam.f.glsl" +#include "geom.h" +#include "seq.h" +#include "ui.h" #define BEAM_SHELLS 40 #define BEAM_RMIN 0.01 #define BEAM_RMAX 0.125 -#define BEAM_ENERGY 0.02 +#define BEAM_ENERGY 0.01 #define BEAM_LEN 16.0 +#define BEAM_DEF_SPEED 0.1 +#define BEAM_HEIGHT 4.65 + +#define XLOGO_RAD 0.5 -#define BEAM_START_ANGLE 180 -#define BEAM_STOP_ANGLE 359 +#define LERP(a, b, t) ((a) + ((b) - (a)) * (t)) -enum State { - ST_DEFAULT, - ST_CAM_WAIT, - ST_CAM_STOP, - ST_XLOGO +struct Camera { + float x, y, z; + float theta, phi; + float dist; }; static bool init(); static void cleanup(); -static void faros(); +static void display(); static void light(); -static void ground(); -static void backdrop(); -static void xlogo(); +static void paper_light(); +static void backdrop(float alpha); +static void help(); -static void update_anim(); - -static void display(); static void idle(); static void reshape(int x, int y); static void keyboard(unsigned char c, int x, int y); +static void keyb_special(int key, int x, int y); static void mbutton(int bn, int state, int x, int y); static void mmotion(int x, int y); -static inline float smoothstep(float a, float b, float x); +int win_width, win_height; +static bool freecam = true; -static float cam_theta = 45, cam_phi, cam_dist = 10; -static unsigned int sdr_curve_top, sdr_beam, sdr_sky; +static Camera cam = {0, 0, 0, 0, 0, 10}; +static unsigned int sdr_beam, sdr_sky; static long start_time; -static float anim_speed = 1.0; static long anim_stop_time; -static long tmsec; -static float beam_speed = 0.1; -static float beam_angle; -static float prev_beam_angle; -static State state; +long tmsec, prev_tmsec, anim_time; +bool anim_stopped; static const float sil_color[] = {0.05, 0.02, 0.1, 1.0}; +static const float ink_color[] = {0.05, 0.15, 0.3, 1.0}; static const float beam_color[] = {0.5, 0.4, 0.2, 1.0}; +static const float paper_color[] = {0.9, 0.8, 0.8, 1.0}; + +static float beam_angle, beam_speed; +static float beam_len; +static float xlogo_alpha, xcircle; +static float paper; + +static bool show_help, show_ui = true; int main(int argc, char **argv) { - glutInit(&argc, argv); glutInitWindowSize(800, 600); + glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE); - glutCreateWindow("Faros"); + glutCreateWindow("Faros (press F1 for controls help)"); glutDisplayFunc(display); glutIdleFunc(idle); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); + glutSpecialFunc(keyb_special); glutMouseFunc(mbutton); glutMotionFunc(mmotion); @@ -100,131 +106,159 @@ static bool init() glEnable(GL_NORMALIZE); - if(!(sdr_curve_top = create_program_load(CURVE_VS, CURVE_FS))) + if(!init_geom()) { return false; - - if(!(sdr_beam = create_program_load(BEAM_VS, BEAM_FS))) + } + if(!(sdr_beam = create_program_load("sdr/beam.v.glsl", "sdr/beam.f.glsl"))) return false; if(!(sdr_sky = create_program_load("sdr/sky.v.glsl", "sdr/sky.f.glsl"))) { return false; } + if(!init_seq()) { + return false; + } + add_seq_track("beam-speed", INTERP_SIGMOID, EXTRAP_CLAMP, BEAM_DEF_SPEED); + add_seq_track("beam-len", INTERP_SIGMOID, EXTRAP_CLAMP, BEAM_LEN); + add_seq_track("cam-dist", INTERP_SIGMOID, EXTRAP_CLAMP, 10); + add_seq_track("cam-phi", INTERP_SIGMOID, EXTRAP_CLAMP, 0); + add_seq_track("cam-theta", INTERP_SIGMOID, EXTRAP_CLAMP, 0); + add_seq_track("cam-x", INTERP_SIGMOID, EXTRAP_CLAMP, 0); + add_seq_track("cam-y", INTERP_SIGMOID, EXTRAP_CLAMP, 0); + add_seq_track("cam-z", INTERP_SIGMOID, EXTRAP_CLAMP, 0); + add_seq_track("xlogo", INTERP_SIGMOID, EXTRAP_CLAMP, 0); + add_seq_track("xcircle", INTERP_SIGMOID, EXTRAP_CLAMP, 1); + add_seq_track("paper", INTERP_SIGMOID, EXTRAP_CLAMP, 0); + load_seq("seq"); + + freecam = seq_track_empty("cam-theta"); + + glClearColor(paper_color[0], paper_color[1], paper_color[2], 1); + start_time = glutGet(GLUT_ELAPSED_TIME); + prev_tmsec = start_time; return true; } static void cleanup() { + destroy_seq(); + destroy_geom(); + free_program(sdr_beam); + free_program(sdr_sky); } -static void faros() +static void display() { - glColor3fv(sil_color); + tmsec = (long)glutGet(GLUT_ELAPSED_TIME) - start_time; + float dt = (tmsec - prev_tmsec) / 1000.0f; + prev_tmsec = tmsec; + + anim_time = tmsec; + if(anim_stopped) { + dt = 0.0f; + anim_time = anim_stop_time - start_time; + } - // kormos - glPushMatrix(); - glScalef(1.1, 3, 1.1); - glTranslatef(0, 0.5, 0); - glutSolidCube(1.0); - glPopMatrix(); + paper = get_seq_value("paper", anim_time); - glShadeModel(GL_FLAT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + backdrop(1.0f - paper); - // base - glPushMatrix(); - glRotatef(90, 1, 0, 0); - glTranslatef(0, -0.15, 0); - glutSolidCylinder(2, 0.3, 16, 1); - glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); - // middle cylinder - glPushMatrix(); - glTranslatef(0, 3, 0); - glRotatef(22.5, 0, 1, 0); - glRotatef(-90, 1, 0, 0); - glutSolidCylinder(0.5, 1.0, 8, 1); - glPopMatrix(); + if(!freecam) { + cam.dist = get_seq_value("cam-dist", anim_time); + cam.phi = get_seq_value("cam-phi", anim_time); + cam.theta = get_seq_value("cam-theta", anim_time); + cam.x = get_seq_value("cam-x", anim_time); + cam.y = get_seq_value("cam-y", anim_time); + cam.z = get_seq_value("cam-z", anim_time); + } - // trim middle cylinder (mporntoura) - glPushMatrix(); - glTranslatef(0, 3.9, 0); - glRotatef(22.5, 0, 1, 0); - glRotatef(-90, 1, 0, 0); - glutSolidCylinder(0.55, 0.02, 8, 1); - glPopMatrix(); + glTranslatef(0, -2, -cam.dist); + glRotatef(cam.phi, 1, 0, 0); + glRotatef(cam.theta, 0, 1, 0); + glTranslatef(-cam.x, -cam.y, -cam.z); - // top smaller cylinder - glPushMatrix(); - glTranslatef(0, 4, 0); - glRotatef(22.5, 0, 1, 0); - glRotatef(-90, 1, 0, 0); - glutSolidCylinder(0.28, 0.5, 8, 1); - glPopMatrix(); + float color[3]; + color[0] = LERP(sil_color[0], ink_color[0], paper); + color[1] = LERP(sil_color[1], ink_color[1], paper); + color[2] = LERP(sil_color[2], ink_color[2], paper); - // top wire even smaller cylinder - glPushMatrix(); - glTranslatef(0, 4.5, 0); - glRotatef(22.5, 0, 1, 0); - glRotatef(-90, 1, 0, 0); - glutWireCylinder(0.18, 0.3, 9, 3); - glPopMatrix(); + glColor3fv(color); + ground(); + faros(); - glShadeModel(GL_SMOOTH); + beam_len = get_seq_value("beam-len", anim_time); + beam_speed = get_seq_value("beam-speed", anim_time); + beam_angle += beam_speed * 360.0f * dt; + + xlogo_alpha = get_seq_value("xlogo", anim_time); + xcircle = get_seq_value("xcircle", anim_time); + + if(xlogo_alpha > 0.0) { + glPushMatrix(); + float beam_angle_rad = beam_angle / 180.0 * M_PI; + float xlogo_dist = beam_len; + float xlogo_pos[3] = {sin(beam_angle_rad), 0, cos(beam_angle_rad)}; + glTranslatef(xlogo_pos[0] * xlogo_dist, xlogo_pos[1] * xlogo_dist + BEAM_HEIGHT, xlogo_pos[2] * xlogo_dist); + xlogo(XLOGO_RAD, color, paper_color, xlogo_alpha, xcircle); + glPopMatrix(); + } - // top troulos glPushMatrix(); - glTranslatef(0, 4.8, 0); - glRotatef(22.5, 0, 1, 0); - glRotatef(-90, 1, 0, 0); - glutSolidCone(0.18, 0.2, 9, 1); + glRotatef(beam_angle, 0, 1, 0); + light(); glPopMatrix(); - // tsamploukano - glPushMatrix(); - glTranslatef(-0.28, 4, 0); - glScalef(1, 13, 1); - glutSolidSphere(0.1, 16, 16); - glPopMatrix(); + paper_light(); - //pyramid on top of kormos - bind_program(sdr_curve_top); + if(show_ui) { + ui(); + } - glPushMatrix(); - glTranslatef(0, 3, 0); - glRotatef(45, 0, 1, 0); - glRotatef(-90, 1, 0, 0); - glScalef(1, 1, 0.45); - glutSolidCylinder(1, 1, 4, 16); - glPopMatrix(); + if(show_help) { + help(); + } - bind_program(0); + glutSwapBuffers(); } static void light() { + float beam_alpha = 1.0 - paper; + if(beam_alpha <= 0.0f) return; + glPushAttrib(GL_ENABLE_BIT); glDisable(GL_CULL_FACE); glPushMatrix(); - glTranslatef(0, 4.65, 0.2); + glTranslatef(0, BEAM_HEIGHT, 0.2); bind_program(sdr_beam); - set_uniform_float(sdr_beam, "beam_len", BEAM_LEN); + set_uniform_float(sdr_beam, "beam_len", beam_len); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glDepthMask(0); for(int i=0; i= BEAM_START_ANGLE && prev_beam_angle < BEAM_START_ANGLE) { - state = ST_CAM_STOP; - printf("func: %s\n", __func__); - printf("state from wait to stop (ba: %f)\n", beam_angle); - beam_start_time = tmsec; - beam_stop_interval = beam_angle / beam_speed; // 400 / beam_speed; - printf(" stop interval: %f\n", beam_stop_interval); - } - } - if(state == ST_CAM_STOP) { - float t = smoothstep(beam_start_time, beam_start_time + beam_stop_interval, tmsec); - prev_beam_angle = beam_angle; - beam_angle = BEAM_START_ANGLE + (BEAM_STOP_ANGLE - BEAM_START_ANGLE) * t; - - if(t >= 1) { - printf("state from stop to xlogo\n"); - state = ST_XLOGO; - } - } else if(state == ST_XLOGO) { - - } else { - prev_beam_angle = beam_angle; - beam_angle = fmod(tanim * beam_speed * 360, 360.0); - } + glPopAttrib(); } -static void display() +static void help() { - if(anim_stop_time > 0) { - tmsec = anim_stop_time - start_time; - } else { - tmsec = (long)glutGet(GLUT_ELAPSED_TIME) - start_time; - } - - update_anim(tmsec); + static const char *help_lines[] = { + "Camera control", + " LMB drag ....... rotate", + " MMB drag ....... pan", + " RMB drag/wheel . zoom", + " c .............. toggle free/animated camera", + " v .............. print current view parameters", + "Animation control", + " ........ pause time", + " .... restart time", + " +/- ............ change beam rotation speed and set keyframe", + " 0 .............. clear beam rotation keyframes", + " [/] ............ change beam length and set keyframe", + " \\ .............. clear beam length keyframes", + " ........ record automatic beam stop transition", + " K .............. set camera keyframe", + " -L ...... clear all camera keyframes", + " X/Z ............ toggle X logo/circle and set keyframe", + " -X/Z .... clear logo/circle keyframes", + " P .............. toggle paper", + " -P ...... clear paper keyframes", + " ~ .............. dump all animation keyframes to seq_dump", + "Other", + " F5 ............. toggle UI", + 0 + }; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - backdrop(); + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); + glPushMatrix(); glLoadIdentity(); - - glTranslatef(0, -2, -cam_dist); - glRotatef(cam_phi, 1, 0, 0); - glRotatef(cam_theta, 0, 1, 0); - - ground(); - faros(); - + glMatrixMode(GL_PROJECTION); glPushMatrix(); + glLoadIdentity(); + glOrtho(0, win_width, win_height, 0, -1, 1); - glRotatef(beam_angle, 0, 1, 0); - light(); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBegin(GL_QUADS); + glColor4f(0, 0, 0, 0.5); + glVertex2f(0, 0); + glVertex2f(0, win_height); + glVertex2f(win_width, win_height); + glVertex2f(win_width, 0); + glEnd(); + glDisable(GL_BLEND); + + int xpos = 20; + int ypos = 30; + for(int i=0; help_lines[i]; i++) { + glColor3f(0.05, 0.05, 0.05); + glRasterPos2i(xpos + 1, ypos + 2); + const char *s = help_lines[i]; + while(*s) { + glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *s++); + } + glColor3f(0.7, 1, 0.6); + glRasterPos2i(xpos, ypos); + s = help_lines[i]; + while(*s) { + glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *s++); + } + ypos += 22; + } + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); - glutSwapBuffers(); + glPopAttrib(); } static void idle() @@ -336,6 +396,8 @@ static void idle() static void reshape(int x, int y) { + win_width = x; + win_height = y; glViewport(0, 0, x, y); glMatrixMode(GL_PROJECTION); @@ -344,61 +406,162 @@ static void reshape(int x, int y) gluPerspective(50, (float)x / (float)y, 0.5, 500); } -static long calc_timeshift(float prev_speed, float speed) -{ - long delta = tmsec * speed - tmsec * prev_speed; - return delta / speed; -} - -#define ANIM_DELTA 0.5 - static void keyboard(unsigned char c, int x, int y) { - float prev_anim_speed; + int idx; + static Camera orig_cam; + long anim_time = anim_stopped ? anim_stop_time - start_time : tmsec; switch(c) { case 27: exit(0); + case '\b': + start_time = glutGet(GLUT_ELAPSED_TIME); + prev_tmsec = 0; + anim_stop_time = anim_stopped ? start_time : 0; + beam_angle = 0; + break; + case ' ': - if(anim_stop_time > 0) { - start_time += glutGet(GLUT_ELAPSED_TIME) - anim_stop_time; + if(anim_stopped) { + long msec = glutGet(GLUT_ELAPSED_TIME); + start_time += msec - anim_stop_time; + prev_tmsec = msec - start_time; anim_stop_time = 0; + anim_stopped = false; } else { anim_stop_time = glutGet(GLUT_ELAPSED_TIME); + anim_stopped = true; } break; case '=': - start_time += calc_timeshift(anim_speed, anim_speed + ANIM_DELTA); - anim_speed += ANIM_DELTA; + beam_speed = get_seq_value("beam-speed", anim_time); + set_seq_value("beam-speed", anim_time, beam_speed + 0.1); break; case '-': - prev_anim_speed = anim_speed; - anim_speed -= ANIM_DELTA; - if(anim_speed < 0) - anim_speed = 0; - start_time += calc_timeshift(prev_anim_speed, anim_speed); + beam_speed = get_seq_value("beam-speed", anim_time) - 0.1; + if(beam_speed < 0) beam_speed = 0; + set_seq_value("beam-speed", anim_time, beam_speed); + break; + + case '0': + clear_seq_track("beam-speed"); + break; + + case '[': + beam_len = get_seq_value("beam-len", anim_time) - 0.5; + if(beam_len < 0) beam_len = 0; + set_seq_value("beam-len", anim_time, beam_len); + break; + + case ']': + beam_len = get_seq_value("beam-len", anim_time); + set_seq_value("beam-len", anim_time, beam_len + 0.5); + break; + + case '\\': + clear_seq_track("beam-len"); break; - case '\n': case '\r': - switch(state) { - case ST_DEFAULT: - state = ST_CAM_WAIT; - prev_beam_angle = beam_angle; - printf("from default to cam_wait\n"); - break; - case ST_XLOGO: - printf("from xlogo to default\n"); - state = ST_DEFAULT; - start_time = tmsec; - break; - default: - break; + case '\n': + idx = find_seq_track("beam-speed"); + assert(idx >= 0); + set_seq_value(idx, anim_time, beam_speed); + set_seq_value(idx, anim_time + 2000, 0); + break; + + case 'c': + freecam = !freecam; + printf("camera mode: %s\n", freecam ? "free" : "animated"); + if(!freecam) { + orig_cam = cam; + } else { + cam = orig_cam; } break; + + case 'v': + printf("current view\n"); + printf(" pos: %f %f %f\n", cam.x, cam.y, cam.z); + printf(" theta: %f, phi: %f\n", cam.theta, cam.phi); + printf(" dist: %f\n", cam.dist); + break; + + case 'L': + printf("clearing camera keyframes\n"); + clear_seq_track("cam-x"); + clear_seq_track("cam-y"); + clear_seq_track("cam-z"); + clear_seq_track("cam-theta"); + clear_seq_track("cam-phi"); + clear_seq_track("cam-dist"); + break; + + case 'k': + printf("setting camera keyframe for time: %ld\n", anim_time); + set_seq_value("cam-x", anim_time, cam.x); + set_seq_value("cam-y", anim_time, cam.y); + set_seq_value("cam-z", anim_time, cam.z); + set_seq_value("cam-theta", anim_time, cam.theta); + set_seq_value("cam-phi", anim_time, cam.phi); + set_seq_value("cam-dist", anim_time, cam.dist); + break; + + case 'x': + set_seq_value("xlogo", anim_time, xlogo_alpha < 0.5 ? 1.0 : 0.0); + break; + + case 'X': + printf("clearing logo keyframes\n"); + clear_seq_track("xlogo"); + break; + + case 'z': + set_seq_value("xcircle", anim_time, xcircle < 0.5 ? 1.0 : 0.0); + break; + + case 'Z': + printf("clearing circle keyframes\n"); + clear_seq_track("xcircle"); + break; + + + case 'p': + set_seq_value("paper", anim_time, paper < 0.5 ? 1.0 : 0.0); + break; + + case 'P': + printf("clearing paper keyframes\n"); + clear_seq_track("paper"); + break; + + case '`': + printf("dumping animation data to: seq_dump\n"); + if(!dump_seq("seq_dump")) { + fprintf(stderr, "dump failed\n"); + } + break; + + default: + break; + } +} + +static void keyb_special(int key, int x, int y) +{ + switch(key) { + case GLUT_KEY_F1: + show_help = !show_help; + break; + + case GLUT_KEY_F5: + show_ui = !show_ui; + break; + default: break; } @@ -409,10 +572,27 @@ static bool bst[8]; static void mbutton(int bn, int state, int x, int y) { int button = bn - GLUT_LEFT_BUTTON; - bst[button] = state == GLUT_DOWN; + bool pressed = state == GLUT_DOWN; + bst[button] = pressed; prev_x = x; prev_y = y; + + if(pressed) { + switch(bn) { + case 3: + cam.dist -= 0.5; + if(cam.dist < 0) cam.dist = 0; + break; + + case 4: + cam.dist += 0.5; + break; + + default: + break; + } + } } static void mmotion(int x, int y) @@ -427,29 +607,42 @@ static void mmotion(int x, int y) return; if (bst[0]) { - cam_theta += dx * 0.5; - cam_phi += dy * 0.5; + cam.theta += dx * 0.5; + cam.phi += dy * 0.5; - if (cam_phi < -90) - cam_phi = -90; + if (cam.phi < -90) + cam.phi = -90; - if (cam_phi > 90) - cam_phi = 90; + if (cam.phi > 90) + cam.phi = 90; } if (bst[2]) { - cam_dist += dy * 0.1; + cam.dist += dy * 0.1; - if (cam_dist < 0) - cam_dist = 0; + if (cam.dist < 0) + cam.dist = 0; } -} -static inline float smoothstep(float a, float b, float x) -{ - if(x < a) return 0.0f; - if(x >= b) return 1.0f; + if(bst[1]) { + float theta = cam.theta / 180.0f * M_PI; + float phi = cam.phi / 180.0f * M_PI; - x = (x - a) / (b - a); - return x * x * (3.0f - 2.0f * x); + float pan_u[3], pan_v[3]; + + pan_u[0] = cos(theta); + pan_u[1] = 0; + pan_u[2] = sin(theta); + + pan_v[0] = sin(phi) * sin(theta); + pan_v[1] = cos(phi); + pan_v[2] = -sin(phi) * cos(theta); + + float pan_x = -dx * 0.002 * cam.dist; + float pan_y = dy * 0.002 * cam.dist; + + cam.x += pan_u[0] * pan_x + pan_v[0] * pan_y; + cam.y += pan_u[1] * pan_x + pan_v[1] * pan_y; + cam.z += pan_u[2] * pan_x + pan_v[2] * pan_y; + } }