/* $Id: draw.cc,v 1.8 2000/01/13 20:11:22 mac Exp $ */ /* * glbiff -- A Mesa/OpenGL-based `xbiff' substitute * Copyright (C) 2000 Maciej Kalisiak * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include "draw.h" #include "glbiff.h" #include "astro.h" #include "rgb.h" #include "cfg.h" // some angles (in degrees) const int ANG_FLAG_UP = 90; const int ANG_FLAG_DOWN = 0; const int ANG_DOOR_OPEN = 90; const int ANG_DOOR_CLOSED = 0; const int ANG_CAM_INI = 0; // INIt = "tilted/corner" view const int ANG_CAM_FIN = 1; // FInal = head on box view // some step sizes const double STEP_FLAG = (ANG_FLAG_UP-ANG_FLAG_DOWN) /(double)flag_up_frames; const double STEP_DOOR = (ANG_DOOR_OPEN-ANG_DOOR_CLOSED) / (double)door_open_frames; const double STEP_CAM = (ANG_CAM_FIN-ANG_CAM_INI) / (double)cam_swing_frames; ////////// globals double flag_position=0; double door_position=0; double xform_factor=0; bool fDoorOpen = false; bool fLookHeadOn = false; /* * set_colour() * * generic routine to set current colour; uses some reasonable default * values. Requires that you pass in the RGB of the desired colour. */ void set_colour(float r, float g, float b) { float ambient = 0.2; float diffuse = 0.7; float specular = 0.4; GLfloat mat[4]; /**** set ambient lighting parameters ****/ mat[0] = ambient*r; mat[1] = ambient*g; mat[2] = ambient*b; mat[3] = 1.0; glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, mat); /**** set diffuse lighting parameters ******/ mat[0] = diffuse*r; mat[1] = diffuse*g; mat[2] = diffuse*b; mat[3] = 1.0; glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, mat); /**** set specular lighting parameters *****/ mat[0] = specular*r; mat[1] = specular*g; mat[2] = specular*b; mat[3] = 1.0; glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat); glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 0.5); } void draw_cube( double d ) { double v = 0.5 * d; // NOTE: the spurious braces are here so that XEmacs does nice indentation... glBegin(GL_QUAD_STRIP); { glVertex3f(-v,-v,v); glVertex3f(-v,-v,-v); glVertex3f(v,-v,v); glVertex3f(v,-v,-v); glVertex3f(v,v,v); glVertex3f(v,v,-v); glVertex3f(-v,v,v); glVertex3f(-v,v,-v); glVertex3f(-v,-v,v); glVertex3f(-v,-v,-v); } glEnd(); glBegin(GL_QUADS); { glVertex3f(-v,-v,v); // front face glVertex3f(v,-v,v); glVertex3f(v,v,v); glVertex3f(-v,v,v); glVertex3f(-v,v,-v); // back face glVertex3f(v,v,-v); glVertex3f(v,-v,-v); glVertex3f(-v,-v,-v); } glEnd(); } void outlined_cube( double d ) { draw_cube( d ); set_colour(0,0,0); double v = 0.5 * d; glBegin(GL_LINE_LOOP); { glVertex3f(-v,-v,-v); glVertex3f(v,-v,-v); glVertex3f(v,v,-v); glVertex3f(-v,v,-v); } glEnd(); glBegin(GL_LINE_LOOP); { glVertex3f(-v,-v,v); glVertex3f(v,-v,v); glVertex3f(v,v,v); glVertex3f(-v,v,v); } glEnd(); glBegin(GL_LINES); { glVertex3f(-v,-v,-v); glVertex3f(-v,-v,v); glVertex3f(-v,v,-v); glVertex3f(-v,v,v); glVertex3f(v,v,-v); glVertex3f(v,v,v); glVertex3f(v,-v,-v); glVertex3f(v,-v,v); } glEnd(); } /* * draw_mbox_top() * * draws the Bezier patch which makes the top of mailbox */ void draw_mbox_top() { glEnable(GL_MAP2_VERTEX_3); glEvalMesh2(GL_FILL, 0, DOME_SEGS, 0, DOME_SEGS); glDisable(GL_MAP2_VERTEX_3); } /* * draw_mbox_side() * * draw a single side of a mailbox; (nx,ny,nz) is the normal vector for * the side. */ void draw_mbox_side( float nx, float ny, float nz ) { glBegin(GL_POLYGON); glNormal3f(nx,ny,nz); glVertex3f(0,0,0); glVertex3f(0,0,SIDE_HEIGHT); glVertex3f(0,1,SIDE_HEIGHT); glVertex3f(0,1,0); glEnd(); } /* * draw_mbox_door() * * draws the door, using a Bezier curve, among other things. This is used * both for the front, and the back doors. */ void draw_mbox_door() { // glTranslatef(-0.5,-0.5*1.6,0); glEnable(GL_MAP1_VERTEX_3); glPushMatrix(); glTranslatef(0,0,SIDE_HEIGHT); glBegin(GL_POLYGON); glNormal3f(0,-1,0); glVertex3f(0,0,-SIDE_HEIGHT); for( int i=0; i<=DOME_SEGS; i++ ) glEvalCoord1f(((float)i)/((GLfloat)DOME_SEGS)); glVertex3f(1,0,-SIDE_HEIGHT); glEnd(); glPopMatrix(); glDisable(GL_MAP1_VERTEX_3); } /* * draw_mbox_flag() * * draws the flag, taking 'flag_position' into account. */ void draw_mbox_flag() { glPushMatrix(); glScalef(FLAG_SCALE,FLAG_SCALE,FLAG_SCALE*1.3); glRotatef(90-flag_position,0,1,0); glTranslatef(0.05,0,0.5); glPushMatrix(); glScalef(0.1,0.05,1); draw_cube(1.0); glPopMatrix(); glPushMatrix(); glTranslatef(0.2,0,0.35); glScalef(0.3,0.05,0.3); draw_cube(1.0); glPopMatrix(); glPopMatrix(); } /* * draw_env() * * draws a single small envelope: stands for 1 email */ void draw_env() { set_colour(1,1,1); glPushMatrix(); glRotatef(-10,0,1,0); glTranslatef(0.01,0.5+0.1,0.2); glScalef(0.02,1,0.4); outlined_cube(1.0); glPopMatrix(); } /* * draw_big_env() * * draws a bigger envelope: stands for 5 emails */ void draw_big_env() { set_colour(0.8,0.6,0); glPushMatrix(); glRotatef(-5,0,1,0); glTranslatef(0.01,0.5+0.1,0.25); glScalef(0.02,1,0.5); outlined_cube(1.0); glPopMatrix(); }; /* * draw_box() * * draws a small package: stands for 25 emails */ void draw_box() { set_colour(0.4,0.3,0.1); glPushMatrix(); glTranslatef(0.2,0.5+0.1,0.25); glScalef(0.4,1,0.5); outlined_cube(1.0); glPopMatrix(); }; /* * draw_big_box() * * draws a big package: stands for 50 emails */ void draw_big_box() { set_colour(0.5,0.5,0.1); glPushMatrix(); glTranslatef(0.2,0.5+0.1,0.37); glScalef(0.4,1,0.74); outlined_cube(1.0); glPopMatrix(); }; /* * draw_mail() * * draws the representation of 'mail_count' emails in the mailbox */ void draw_mail() { // determine number of each object int bbox, box, benv, env; if( mail_count>=MAX_MAIL_DRAWABLE ) { bbox=2; box=benv=env=0; } else { int mc=mail_count; bbox=mc/50; mc-=bbox*50; box=mc/25; mc-=box*25; benv=mc/5; mc-=benv*5; env=mc; } bool fLL, fLR, fUL, fUR; fLL=fLR=fUL=fUR=true; if( bbox ) { glPushMatrix(); glTranslatef(0.09,0,0); draw_big_box(); glPopMatrix(); fLL=fUL=false; if( bbox==2 ) { glPushMatrix(); glTranslatef(0.51,0,0); draw_big_box(); glPopMatrix(); fLR=fUR=false; } } if( box ) { glPushMatrix(); if( fLL ) { glTranslatef(0.02,0,0); fLL=false; } else { glTranslatef(0.52,0,0); fLR=false; } draw_box(); glPopMatrix(); } if( benv || env ) { glPushMatrix(); if( fLL ) { fLL=false; } else if( fLR ) { glTranslatef(0.5,0,0); fLR=false; } else if( fUR ) { glTranslatef(0.5,0,0.5); fUR=false; } for( int i=0; itm_year+1900,ptm->tm_mon+1,ptm->tm_mday); double hour = ptm->tm_hour + ptm->tm_min/60.0 + ptm->tm_sec/3600.0; // static double hour = 7; // hour += 0.05; // if( hour > 24 ) // hour -= 24; coord rs = sun_rise_set( today, my_long_lat ); // cerr << "rs == " << rs.a << ", " << rs.b << endl; // cerr << "time is " << ptm->tm_hour << ":" << ptm->tm_min << ":" // << ptm->tm_sec << " ; tm_isdst == " << ptm->tm_isdst << endl; // cerr << "hour is " << hour << endl; if( hour <= rs.a || hour >= rs.b ) glClearColor(0,0,0,1.0); // pitch dark else { double s = (hour - rs.a)/(rs.b-rs.a); list::iterator it = sky_keyframes.begin(); list::iterator it_after; while( (*it).s < s ) ++it; it_after = it; --it; double f = 1 - (s - (*it).s)/ ((*it_after).s-(*it).s); // cerr << "i == " << i << " : s == " << s << " : f == " << f << endl; glClearColor( (*it).rgb.r*f + (*it_after).rgb.r*(1-f), (*it).rgb.g*f + (*it_after).rgb.g*(1-f), (*it).rgb.b*f + (*it_after).rgb.b*(1-f), 1.0 ); } } /* * redraw() * * this is the callback that handles drawing of the OpenGL window */ void redraw( Display *dpy, Window w ) { if( !dpy || !w ) return; bool call_me_again = false; // "paint" the sky set_sky_colour(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // setup the viewing transformation (assume the models are already setup) glPushMatrix(); // --camera/viewing transformations // read these backwards using the camera local coordinate system // (or forwards using the "Grand, Fixed Coordinate System") glTranslatef( 0,0,-3.0+1.0*xform_factor ); // dolly out a bit glRotatef( -90+35-35.0*xform_factor,1,0,0 ); glRotatef( -45+45*xform_factor,0,0,1 ); // controls rot along z glTranslatef( 0,0,-0.25-0.25*xform_factor ); // move camera to the vertical center of box // glScalef(2,2,2); // paint the origin as a cube // draw_cube(0.1); /////// perform any motions necessary for this frame // check the flag, ... if( unreadmail && flag_positionANG_FLAG_DOWN ) { flag_position -= STEP_FLAG; call_me_again = true; } // door, ... if( fDoorOpen && door_positionANG_DOOR_CLOSED ) { door_position -= STEP_DOOR; call_me_again = true; } // and camera swing if( fLookHeadOn && xform_factorANG_CAM_INI ) { xform_factor -= STEP_CAM; call_me_again = true; } // render the land and mailbox draw_land(); draw_post(); draw_mbox(); // clean up and swap buffers glPopMatrix(); glFinish(); glXSwapBuffers(dpy, w); // setup a callback if any motions are not yet finished if(call_me_again) { timed_callback( refresh, refresh_period ); } } //////////////////////////////////////////////////////////// // texturing stuff GLubyte check_image[check_image_h][check_image_w][4]; GLuint texName; void make_check_image(void) { int i, j, c; for( i=0; i