498 lines
9.5 KiB
C++
498 lines
9.5 KiB
C++
#ifdef X11
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/keysym.h>
|
|
#include <Xm/Xm.h>
|
|
|
|
#include <GL/glx.h>
|
|
#include <GLwMDrawA.h>
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
#include <GL/glu.h>
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#ifdef X11
|
|
#include <sys/time.h>
|
|
#else
|
|
#include <time.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include "stonehen.h"
|
|
#endif
|
|
|
|
#include "atmosphe.h"
|
|
#include "scene.h"
|
|
|
|
#include "callback.h"
|
|
|
|
int cb_demo_mode = 0;
|
|
float demo_time;
|
|
|
|
#ifdef X11
|
|
extern Widget glw;
|
|
extern XtAppContext app_context;
|
|
GLXContext glx_context;
|
|
#endif
|
|
|
|
static int needs_wp = 0;
|
|
#ifdef X11
|
|
static XtWorkProcId workproc = NULL;
|
|
#else
|
|
static int workproc = 0;
|
|
#endif
|
|
|
|
static int winx, winy;
|
|
|
|
static int button_down = 0;
|
|
int mousex, mousey;
|
|
/* What's moving */
|
|
GLint target;
|
|
|
|
/* Location of the telescope */
|
|
GLfloat tx, ty;
|
|
|
|
/* Movements of the camera position to be applied at the next redraw */
|
|
float rot_pendx = 0, rot_pendz = 0, trans_pend = 0;
|
|
|
|
/* How fast the camera is moving */
|
|
float trans_speed = 0;
|
|
|
|
/* This is how fast demo time moves relative to real time */
|
|
GLfloat time_scale = 0;
|
|
|
|
TimeDate last_update;
|
|
|
|
float last_time = 0;
|
|
const float time_fudge = 1000;
|
|
inline unsigned long current_time()
|
|
{
|
|
#ifdef X11
|
|
struct timeval time;
|
|
gettimeofday(&time, NULL);
|
|
return (time.tv_sec * 1000000 + time.tv_usec);
|
|
#else
|
|
return (GetTickCount() * 1000);
|
|
#endif
|
|
}
|
|
|
|
inline float clamp(float x, float min, float max)
|
|
{
|
|
if (x < min) return min;
|
|
else if (x > max) return max;
|
|
else return x;
|
|
}
|
|
|
|
static void add_workproc(Widget w)
|
|
{
|
|
needs_wp++;
|
|
#ifdef X11
|
|
if (workproc == NULL)
|
|
workproc = XtAppAddWorkProc(app_context, drawWP, NULL);
|
|
#else
|
|
workproc = SetTimer(w, 1, 1000, NULL);
|
|
#endif
|
|
}
|
|
|
|
static void remove_workproc(Widget w)
|
|
{
|
|
needs_wp--;
|
|
if (needs_wp == 0) {
|
|
#ifdef X11
|
|
XtRemoveWorkProc(workproc);
|
|
workproc = NULL;
|
|
#else
|
|
KillTimer(w, 1);
|
|
workproc = 0;
|
|
#endif
|
|
} else if (needs_wp < 0) {
|
|
fprintf(stderr, "Internal Error: No workproc to remove!\n");
|
|
needs_wp = 0;
|
|
workproc = NULL;
|
|
}
|
|
}
|
|
|
|
static void reset_viewer()
|
|
{
|
|
scene_viewer_center();
|
|
}
|
|
|
|
#ifdef X11
|
|
void intToggleCB(Widget w, XtPointer client_data, XtPointer call_data)
|
|
{
|
|
int *data;
|
|
XmToggleButtonCallbackStruct *ptr;
|
|
ptr = (XmToggleButtonCallbackStruct *)call_data;
|
|
data = (int *)client_data;
|
|
*data = ptr->set;
|
|
// This redraw may or may not be needed - do it to be safe
|
|
drawWP(NULL);
|
|
}
|
|
|
|
|
|
void initCB(Widget w)
|
|
{
|
|
Arg args[1];
|
|
XVisualInfo *vi;
|
|
|
|
glw = w;
|
|
|
|
XtSetArg(args[0], GLwNvisualInfo, &vi);
|
|
XtGetValues(w, args, 1);
|
|
|
|
glx_context = glXCreateContext(XtDisplay(w), vi, 0, GL_FALSE);
|
|
GLwDrawingAreaMakeCurrent(w, glx_context);
|
|
|
|
scene_init();
|
|
|
|
last_update.read_time();
|
|
|
|
resetViewerCB(NULL, NULL, NULL);
|
|
}
|
|
|
|
void exposeCB(Widget w)
|
|
{
|
|
drawWP(NULL);
|
|
}
|
|
#endif
|
|
|
|
void resizeCB(Widget w, XtPointer client_data, XtPointer call)
|
|
{
|
|
#ifdef X11
|
|
GLwDrawingAreaCallbackStruct *call_data;
|
|
|
|
GLwDrawingAreaMakeCurrent(w, glx_context);
|
|
|
|
call_data = (GLwDrawingAreaCallbackStruct *)call;
|
|
|
|
winx = call_data->width;
|
|
winy = call_data->height;
|
|
#else
|
|
RECT rect;
|
|
GetClientRect(w, &rect);
|
|
|
|
winx = WINDSIZEX(rect);
|
|
winy = WINDSIZEY(rect);
|
|
#endif
|
|
|
|
glViewport(0, 0, winx, winy);
|
|
|
|
aspect = (GLfloat)winx / (GLfloat)winy;
|
|
}
|
|
|
|
void inputCB(Widget w, XtPointer client_data, XtPointer call_data)
|
|
{
|
|
GLwDrawingAreaCallbackStruct *call;
|
|
|
|
int bufsize = 5;
|
|
#ifdef X11
|
|
char buffer[5];
|
|
KeySym key;
|
|
XComposeStatus compose;
|
|
#endif
|
|
|
|
float dx, dy, r1, r2;
|
|
|
|
#ifdef X11
|
|
GLwDrawingAreaMakeCurrent(w, glx_context);
|
|
#endif
|
|
|
|
call = (GLwDrawingAreaCallbackStruct *)call_data;
|
|
|
|
switch(call->event->type) {
|
|
case ButtonPress:
|
|
last_time = current_time();
|
|
button_down = call->event->xbutton.button;
|
|
mousex = call->event->xbutton.x;
|
|
mousey = call->event->xbutton.y;
|
|
/* Determine if the target should be the camera position
|
|
* or the telescope */
|
|
if (use_telescope) {
|
|
scene_get_position_telescope(&tx, &ty);
|
|
scene_get_radius_telescope(&r1);
|
|
dx = (tx + .5) - ((GLfloat)(winx - mousex)/(GLfloat)winx);
|
|
dy = (ty + .5) - ((GLfloat)(winy - mousey)/(GLfloat)winy);
|
|
r2 = sqrt(dx*dx + dy*dy);
|
|
if (r2 < r1) target = name_telescope;
|
|
else target = name_background;
|
|
} else target = name_background;
|
|
add_workproc(w);
|
|
break;
|
|
case ButtonRelease:
|
|
#ifdef X11
|
|
if (call->event->xbutton.button == Button3) {
|
|
/* Use Button3 to stop */
|
|
if (trans_speed) remove_workproc(w);
|
|
trans_speed = 0;
|
|
}
|
|
#endif
|
|
remove_workproc(w);
|
|
button_down = 0;
|
|
break;
|
|
case MotionNotify:
|
|
switch(button_down) {
|
|
case Button1:
|
|
/* Use Button1 to control the way in which the viewer is looking
|
|
* or to move the telescope around */
|
|
if (target == name_background) {
|
|
dx = (float)(call->event->xmotion.x - mousex) / (float)winx;
|
|
dy = (float)(call->event->xmotion.y - mousey) / (float)winy;
|
|
rot_pendx -= dy * fov;
|
|
rot_pendz -= dx * fov;
|
|
} else {
|
|
dx = (float)(mousex - call->event->xmotion.x) / (float)winx;
|
|
dy = (float)(mousey - call->event->xmotion.y) / (float)winy;
|
|
tx += dx;
|
|
ty += dy;
|
|
tx = clamp(tx, -.5, .5);
|
|
ty = clamp(ty, -.5, .5);
|
|
scene_position_telescope(tx, ty);
|
|
}
|
|
break;
|
|
case Button2:
|
|
/* Use Button2 to change speed */
|
|
dx = (float)(mousex - call->event->xmotion.x) /
|
|
(float)winx;
|
|
if (dx && !trans_speed) add_workproc(w);
|
|
#ifdef WIN32
|
|
else if (!dx && trans_speed) remove_workproc(w);
|
|
#endif
|
|
trans_speed += dx;
|
|
break;
|
|
}
|
|
mousex = call->event->xmotion.x;
|
|
mousey = call->event->xmotion.y;
|
|
break;
|
|
|
|
#ifdef X11 // We can handle our own keys...
|
|
case KeyPress:
|
|
XLookupString(&(call->event->xkey), buffer, bufsize, &key, &compose);
|
|
if (key == XK_Escape) exit(0);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
const float speed_t = .5;
|
|
const float speed_r = 15.;
|
|
const float speed_rx = 10.;
|
|
void demo_mode_update(float dt)
|
|
{
|
|
float t;
|
|
|
|
if (!cb_demo_mode) return;
|
|
|
|
dt /= 1000000;
|
|
demo_time += dt;
|
|
|
|
t = demo_time;
|
|
|
|
if (t < 10.5) {
|
|
trans_speed = speed_t;
|
|
return;
|
|
} else t -= 10.5;
|
|
|
|
if (t < 1) {
|
|
trans_speed = 0;
|
|
rot_pendz = 0;
|
|
return;
|
|
} else t -= 1;
|
|
|
|
if (t < 3.) {
|
|
trans_speed = 0.;
|
|
rot_pendz = dt * speed_r;
|
|
return;
|
|
} else t -= 3.;
|
|
|
|
if (t < 2.) {
|
|
rot_pendx = -dt * speed_rx;
|
|
return;
|
|
} else t -= 2.;
|
|
|
|
if (t < 2.) {
|
|
return;
|
|
} else t -= 2.;
|
|
|
|
if (t < 2.) {
|
|
rot_pendx = dt * speed_rx;
|
|
return;
|
|
} else t -= 2.;
|
|
|
|
|
|
if (t < 3.) {
|
|
trans_speed = 0.;
|
|
rot_pendz = dt * speed_r;
|
|
return;
|
|
} else t -= 3.;
|
|
|
|
if (t < 30.) {
|
|
trans_speed = speed_t;
|
|
rot_pendz = 0;
|
|
return;
|
|
} else t -= 30.;
|
|
|
|
if (t < 1.) {
|
|
trans_speed = 0;
|
|
return;
|
|
} else t -= 1.;
|
|
|
|
if (t < 1.3) {
|
|
rot_pendz = -dt * speed_r;
|
|
return;
|
|
} else t -= 1.3;
|
|
|
|
// Pan back to see entire thing
|
|
if (t < 23) {
|
|
trans_speed = speed_t;
|
|
return;
|
|
} else t -= 23;
|
|
|
|
// Hold before starting over
|
|
if (t < 20) {
|
|
trans_speed = 0;
|
|
return;
|
|
}
|
|
else t -= 20;
|
|
|
|
demo_time = 0.;
|
|
reset_viewer();
|
|
}
|
|
|
|
Boolean drawWP(Widget w)
|
|
{
|
|
/* Right now, there's two completely independent time measurements:
|
|
* one for the time of day in the demo and one for changing the camera
|
|
* position */
|
|
TimeDate t, dt;
|
|
float elapsed_time, time;
|
|
#ifdef WIN32
|
|
HDC hDC;
|
|
#endif
|
|
|
|
if (time_scale != 0.0) {
|
|
t.read_time();
|
|
dt = (t - last_update) * time_scale;
|
|
scene_inc_time(dt);
|
|
last_update = t;
|
|
}
|
|
|
|
time = current_time();
|
|
if (time - last_time > time_fudge) {
|
|
elapsed_time = time - last_time;
|
|
demo_mode_update(elapsed_time);
|
|
trans_pend = trans_speed * (elapsed_time / 1000000);
|
|
last_time = time;
|
|
}
|
|
|
|
scene_viewer_rotatex(rot_pendx);
|
|
scene_viewer_rotatez(rot_pendz);
|
|
scene_viewer_translate(trans_pend);
|
|
rot_pendx = 0;
|
|
rot_pendz = 0;
|
|
trans_pend = 0;
|
|
|
|
#ifdef X11
|
|
GLwDrawingAreaMakeCurrent(glw, glx_context);
|
|
scene_render();
|
|
/* This is a total hack */
|
|
// if (!use_antialias)
|
|
GLwDrawingAreaSwapBuffers(glw);
|
|
#else
|
|
hDC = GetDC(w);
|
|
scene_render();
|
|
SwapBuffers(hDC);
|
|
ReleaseDC(w, hDC);
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef X11
|
|
void weatherCB(Widget w, XtPointer client_data, XtPointer call_data)
|
|
{
|
|
Weather *data;
|
|
XmToggleButtonCallbackStruct *ptr;
|
|
ptr = (XmToggleButtonCallbackStruct *)call_data;
|
|
if (ptr->set) scene_set_weather(*((Weather *)client_data));
|
|
drawWP(NULL);
|
|
}
|
|
#endif
|
|
|
|
void currentTimeCB(Widget w)
|
|
{
|
|
scene_set_time(TimeDate().read_time());
|
|
drawWP(w);
|
|
}
|
|
|
|
void time10amCB(Widget w)
|
|
{
|
|
scene_set_time(TimeDate(10, 0));
|
|
drawWP(w);
|
|
}
|
|
|
|
void time12pmCB(Widget w)
|
|
{
|
|
scene_set_time(TimeDate(12, 0));
|
|
drawWP(w);
|
|
}
|
|
|
|
void time4pmCB(Widget w)
|
|
{
|
|
scene_set_time(TimeDate(16, 0));
|
|
drawWP(w);
|
|
}
|
|
|
|
void timeSpeedCB(Widget w, XtPointer client_data, XtPointer call_data)
|
|
{
|
|
|
|
#ifdef X11
|
|
if (!((XmToggleButtonCallbackStruct *)call_data)->set) return;
|
|
time_scale = (int)client_data;
|
|
#endif
|
|
if (time_scale == 0.0) remove_workproc(w);
|
|
else add_workproc(w);
|
|
last_update.read_time();
|
|
}
|
|
|
|
void demo_modeCB(Widget w, XtPointer client_data, XtPointer call_data)
|
|
{
|
|
#ifdef X11
|
|
int val = ((XmToggleButtonCallbackStruct *)call_data)->set;
|
|
#else
|
|
int val = cb_demo_mode;
|
|
#endif
|
|
if (!val) {
|
|
remove_workproc(w);
|
|
resetViewerCB(w, NULL, NULL);
|
|
last_time = current_time();
|
|
} else {
|
|
reset_viewer();
|
|
add_workproc(w);
|
|
trans_speed = 0;
|
|
demo_time = 0;
|
|
rot_pendx = -5;
|
|
}
|
|
drawWP(w);
|
|
}
|
|
|
|
void resetViewerCB(Widget w, XtPointer client_data, XtPointer call_data)
|
|
{
|
|
trans_speed = 0;
|
|
rot_pendx = rot_pendz = trans_pend = 0;
|
|
rot_pendx = -5;
|
|
reset_viewer();
|
|
return;
|
|
}
|
|
|
|
|
|
void exitCB(Widget w, XtPointer client_data, XtPointer call_data)
|
|
{
|
|
exit(0);
|
|
}
|