/*     WMGlobe 1.3  -  All the Earth on a WMaker Icon
 *     copyright (C) 1998,99,2000,01 Jerome Dumonteil <jerome.dumonteil@linuxfr.org>
 *
 *     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., 675 Mass Ave, Cambridge, MA 02139, USA.
 ***************************************************************************/
/* this code was based on XGlobe :
   renderer.cpp
   *
   * This file is part of XGlobe. See README for details.
   *
   * Copyright (C) 1998 Thorsten Scheuermann
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public Licenses as published by
   * the Free Software Foundation.
   ************************************************************************/
/*
   Some parts of this files should be rewritten to not depend on
   WindowMaker version
*/

#include "wmglobe.h"

static RColor mygetMapColorLinear
    (double longitude, double latitude, double angle);

/*
 * static RColor getMapColor(double longitude, double latitude, double angle);
 */

static void randomPosition();
void setViewPos(double lat, double lon);
static void myRPutPixel(int x, int y, RColor * color);
#ifdef WITH_MARKERS
#if (WITH_MARKERS == 1)
static void invertPixel(int x, int y);
static void put_cross(int x, int y);
static void put_dot_cross(int x, int y, RColor * color);
#endif
#endif
static void getquarter(RImage * image, int x, int y, MPO * m[4], int dx,
		       int dy);
static void updateTime(int force);
static struct timeval timeaccel(struct timeval t);






struct timeval timeaccel(struct timeval t)
{
    struct timeval at;
    double rr;

    t = diftimev(t, tini);
    rr = floor((double) t.tv_sec * time_multi +
	       (double) t.tv_usec * time_multi / 1000000.);
/*** something bad may appen if time_multi=max after 41 minutes (overflow) ***/
    while (rr > (double) LONG_MAX)
	rr -= (2.0 * (double) LONG_MAX + 1.0);
    at.tv_sec = (int) rr;
    at.tv_usec = (int) (t.tv_usec * time_multi) % 1000000;
    return addtimev(at, tbase);
}






static void myRPutPixel(int x, int y, RColor * color)
{
    int ofs;
    unsigned char *sr, *sg, *sb;

    ofs = (y * DIAMETRE + x) * 3;
    sr = small->data + (ofs++);
    sg = small->data + (ofs++);
    sb = small->data + (ofs);

    *sr = color->red;
    *sg = color->green;
    *sb = color->blue;
    return;
}






#if WITH_MARKERS
static void invertPixel(int x, int y)
{
    int ofs;
    unsigned char *sr, *sg, *sb;

    ofs = (y * DIAMETRE + x) * 3;
    sr = small->data + (ofs++);
    sg = small->data + (ofs++);
    sb = small->data + (ofs);

#if ( CROSS_INVERT == 1 )
    *sr = 255 - *sr;
    *sg = 255 - *sg;
    *sb = 255 - *sb;
#else
    if (*sb > 127 || *sg > 127 || *sr > 127)
	*sr = *sg = *sb = 0;
    else
	*sr = *sg = *sb = 255;
#endif
    return;
}

#define T_CADRE(x,y) ((x) < DIAMETRE && (x) >= 0 \
&& (y) < DIAMETRE && (y) >= 0 && tabsolu[(x)][(y)])





static void put_cross(int x, int y)
{
    int i, x_cross, y_cross;

    if (T_CADRE(x, y)) {
	if (!fun && sens != 1) {
	    x = DIAMETRE - 1 - x;
	    y = DIAMETRE - 1 - y;
	}
	for (i = 2; i <= CROSS_LENGTH; i++) {
	    x_cross = x + i;
	    y_cross = y;
	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);
	    x_cross = x - i;

	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);
	    x_cross = x;
	    y_cross = y - i;
	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);

	    y_cross = y + i;
	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);
	}
    }
}








static void put_dot_cross(int x, int y, RColor * color)
{
    int i, x_cross, y_cross;

    if (T_CADRE(x, y)) {
	if (!fun && sens != 1) {
	    x = DIAMETRE - 1 - x;
	    y = DIAMETRE - 1 - y;
	}
	for (i = 2; i <= CROSS_LENGTH; i += 2) {
	    x_cross = x + i;
	    y_cross = y;
	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);
	    x_cross = x - i;

	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);
	    x_cross = x;
	    y_cross = y - i;
	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);

	    y_cross = y + i;
	    if (T_CADRE(x_cross, y_cross))
		invertPixel(x_cross, y_cross);

	    x_cross = x + i + 1;
	    y_cross = y;
	    if (T_CADRE(x_cross, y_cross))
		myRPutPixel(x_cross, y_cross, color);
	    x_cross = x - i - 1;

	    if (T_CADRE(x_cross, y_cross))
		myRPutPixel(x_cross, y_cross, color);
	    x_cross = x;
	    y_cross = y - i - 1;
	    if (T_CADRE(x_cross, y_cross))
		myRPutPixel(x_cross, y_cross, color);

	    y_cross = y + i + 1;
	    if (T_CADRE(x_cross, y_cross))
		myRPutPixel(x_cross, y_cross, color);
	}
    }
}
#endif








static void getquarter(RImage * image, int x, int y, MPO * m[4], int dx,
		       int dy)
{
    int xx;
    register int ofs;

/*** hope this is faster than calculation with floats .... ****/

    x %= image->width;
    xx = x;
    y %= image->height;
    ofs = (y * image->width + x) * 3;
    m[0]->r = image->data[ofs++];
    m[0]->g = image->data[ofs++];
    m[0]->b = image->data[ofs];

    xx++;
    xx %= image->width;
    ofs = (y * image->width + xx) * 3;
    m[1]->r = image->data[ofs++];
    m[1]->g = image->data[ofs++];
    m[1]->b = image->data[ofs];

    y++;
    y %= image->height;
    ofs = (y * image->width + x) * 3;
    m[2]->r = image->data[ofs++];
    m[2]->g = image->data[ofs++];
    m[2]->b = image->data[ofs];

    ofs = (y * image->width + xx) * 3;
    m[3]->r = image->data[ofs++];
    m[3]->g = image->data[ofs++];
    m[3]->b = image->data[ofs];


/*
 * m[0]->r=((m[0]->r*(256-dx)*(256-dy))+
 *      (m[1]->r*dx*(256-dy))+
 *      (m[2]->r*(256-dx)*dy)+
 *      (m[3]->r*dx*dy))>>16;
 * m[0]->g=((m[0]->g*(256-dx)*(256-dy))+
 *      (m[1]->g*dx*(256-dy))+
 *      (m[2]->g*(256-dx)*dy)+
 *      (m[3]->g*dx*dy))>>16;
 * m[0]->b=((m[0]->b*(256-dx)*(256-dy))+
 *      (m[1]->b*dx*(256-dy))+
 *      (m[2]->b*(256-dx)*dy)+
 *      (m[3]->b*dx*dy))>>16;
 */

    if ((ofs = m[1]->r - m[0]->r) != 0)
	m[0]->r += (ofs * dx) >> 8;
    if ((ofs = m[1]->g - m[0]->g) != 0)
	m[0]->g += (ofs * dx) >> 8;
    if ((ofs = m[1]->b - m[0]->b) != 0)
	m[0]->b += (ofs * dx) >> 8;

    if ((ofs = m[3]->r - m[2]->r) != 0)
	m[2]->r += (ofs * dx) >> 8;
    if ((ofs = m[3]->g - m[2]->g) != 0)
	m[2]->g += (ofs * dx) >> 8;
    if ((ofs = m[3]->b - m[2]->b) != 0)
	m[2]->b += (ofs * dx) >> 8;

    if ((ofs = m[2]->r - m[0]->r) != 0)
	m[0]->r += (ofs * dy) >> 8;
    if ((ofs = m[2]->g - m[0]->g) != 0)
	m[0]->g += (ofs * dy) >> 8;
    if ((ofs = m[2]->b - m[0]->b) != 0)
	m[0]->b += (ofs * dy) >> 8;

    return;
}









void calcDistance()
{
    double tan_a;

    tan_a = (zoom * DIAMETRE / 2.0) / proj_dist;
/*
 *     distance of camera to center of earth ( = coordinate origin)
 */
    center_dist = radius / sin(atan(tan_a));
    c_coef = center_dist * center_dist - radius * radius;
    solution = FALSE;
    return;
}









void renderFrame()
{
    int py, px;
    RColor teinte;

    double dir_x, dir_y, dir_z;	/* direction of cast ray */

    double hit_x, hit_y, hit_z;	/* hit position on earth surface */

    double hit2_x, hit2_y, hit2_z;	/* mirrored hit position on earth surface */

    double sp_x, sp_y, sp_z;	/* intersection point of globe and ray */

    double a;			/*  coeff. of quardatic equation */

    double udroot;		/*  racine */
    double wurzel;
    double r;			/* r' */

    double s1, s2, s;		/*distance between intersections and
				   camera position */

    double longitude, latitude;	/* coordinates of hit position */

    double light_angle;		/* cosine of angle between sunlight and
				   surface normal */

    int startx, endx;		/* the region to be painted */

    int starty, endy;

    double m11;
    double m12;
    double m13;
    double m21;
    double m22;
    double m23;
    double m31;
    double m32;
    double m33;

    a = dir_x = dir_y = 0;
    dir_z = -proj_dist;

#ifdef DEBUG
    fprintf(stdout, "solution : %d\n", solution);
#endif
    /*
     * clear image
     */
    if (solution == FALSE)
	RClearImage(small, &noir);
    /*
     *  rotation matrix
     */

    m11 = cos(v_long);
    m22 = cos(v_lat);
    m23 = sin(v_lat);
    m31 = -sin(v_long);
    m12 = m23 * m31;
    m13 = -m22 * m31;
    m21 = 0.;
    m32 = -m23 * m11;
    m33 = m22 * m11;

    /*
     *  calc. radius of projected sphere
     */
    if (solution == FALSE) {
	b_coef = 2 * center_dist * dir_z;
	radius_proj =
	    (int) sqrt(b_coef * b_coef / (4 * c_coef) - dir_z * dir_z) + 1;
    }

    if (fun) {
	starty = DIAMETRE / 2 - radius_proj - 3;
	endy = DIAMETRE - starty - 1;
	if ((double) starty < (double) (-funy))
	    starty = -funy;
	if ((double) starty > (double) (DIAMETRE - 1 - funy))
	    starty = DIAMETRE - 1 - funy;
	if ((double) endy < (double) (-funy))
	    endy = -funy;
	if ((double) endy > (double) (DIAMETRE - 1 - funy))
	    endy = DIAMETRE - 1 - funy;

	if (solution == FALSE) {
	    int i, j;
	    if (starty + funy > 0)
		for (j = 0; j < starty + funy; j++)
		    for (i = 0; i < DIAMETRE; i++)
			tabsolu[i][j] = 0;
	    if (endy + 1 + funy <= DIAMETRE - 1)
		for (j = endy + funy + 1; j < DIAMETRE; j++)
		    for (i = 0; i < DIAMETRE; i++)
			tabsolu[i][j] = 0;
	}

	for (py = starty; py <= endy; py++) {

	    startx = DIAMETRE / 2 - 6 -
		(int) sqrt(MAX((radius_proj * radius_proj -
				(py - DIAMETRE / 2) *
				(py - DIAMETRE / 2)), 0.0));

	    endx = DIAMETRE - startx - 1;
	    if ((double) startx < (double) (-funx))
		startx = -funx;

	    if ((double) startx > (double) (DIAMETRE - 1 - funx))
		startx = DIAMETRE - 1 - funx;

	    if ((double) endx < (double) (-funx))
		endx = -funx;
	    if ((double) endx > (double) (DIAMETRE - 1 - funx))
		endx = DIAMETRE - 1 - funx;

	    if (solution == FALSE) {
		int i;
		if (startx + funx > 0)
		    for (i = 0; i < startx + funx; i++)
			tabsolu[i][py + funy] = 0;
		if (endx + 1 + funx <= DIAMETRE - 1)
		    for (i = endx + 1 + funx; i < DIAMETRE; i++)
			tabsolu[i][py + funy] = 0;
	    }


	    /*
	     *  calculate offset into image data
	     */

	    for (px = startx; px <= endx; px++) {
		if (solution == FALSE) {
		    dir_x = (double) px - DIAMETRE / 2 + 0.5;
		    dir_y = -(double) py + DIAMETRE / 2 - 0.5;

		    a = dir_x * dir_x + dir_y * dir_y + dir_z * dir_z;

		    udroot = b_coef * b_coef - 4 * a * c_coef;	/*what's under the
								   sq.root when solving the                                                                        quadratic equation */
		    if (udroot >= 0) {
			tabsolu[px + funx][py + funy] = 1;
			wurzel = sqrt(udroot);
			s1 = (-b_coef + wurzel) / (2. * a);
			s2 = (-b_coef - wurzel) / (2. * a);
			s = (s1 < s2) ? s1 : s2;	/* smaller solution belongs
							   to nearer intersection */
			solu[px + funx][py + funy][0] = s * dir_x;
			solu[px + funx][py + funy][1] = s * dir_y;
			solu[px + funx][py + funy][2] =
			    center_dist + s * dir_z;
		    } else {
			tabsolu[px + funx][py + funy] = 0;
		    }
		}

		if (tabsolu[px + funx][py + funy]) {	/*  solution exists <=>
							   intersection exists */
		    sp_x = solu[px + funx][py + funy][0];	/* sp = camera pos + s*dir */
		    sp_y = solu[px + funx][py + funy][1];
		    sp_z = solu[px + funx][py + funy][2];

		    hit_x = m11 * sp_x + m12 * sp_y + m13 * sp_z;
		    hit_y = m22 * sp_y + m23 * sp_z;
		    hit_z = m31 * sp_x + m32 * sp_y + m33 * sp_z;

		    hit2_x = -m11 * sp_x + m12 * sp_y + m13 * sp_z;
		    hit2_y = m22 * sp_y + m23 * sp_z;
		    hit2_z = -m31 * sp_x + m32 * sp_y + m33 * sp_z;
/*** hope hit_z wont get too close to zero *******/
		    if (ABS(hit_z) < 0.001) {
			if (hit_x * hit_z > 0.)
			    longitude = PI / 2.;
			else
			    longitude = -PI / 2.;
			if (hit_z > 0.)
			    hit_z = 0.001;
			else
			    hit_z = -0.001;
		    } else {
			longitude = atan(hit_x / hit_z);
		    }

		    if (hit_z < 0.)
			longitude += PI;

		    r = (double) sqrt(hit_x * hit_x + hit_z * hit_z);

		    latitude = atan(-hit_y / r);

		    light_angle =
			(light_x * hit_x + light_y * hit_y +
			 light_z * hit_z) / radius;

		    /*
		     *  Set pixel in image
		     */

		    teinte =
			mygetMapColorLinear(longitude, latitude,
					    light_angle);
			/* here dont use myRPutPixel since we prefer some
			error detection about limits */
		    RPutPixel(small, px + funx, py + funy, &teinte);
		}
	    }			/*px */
	}			/*py */

    }


/*** not fun : ***/
    else {
	starty = DIAMETRE / 2 - radius_proj - 3;
	starty = (starty < 0) ? 0 : starty;
	endy = DIAMETRE - starty - 1;
/*
 * py  0 to 63 max
 */
	if (solution == FALSE) {
	    int i, j;
	    if (starty > 0)
		for (j = 0; j < starty; j++)
		    for (i = 0; i < DIAMETRE; i++)
			tabsolu[i][j] = 0;
	    if (endy + 1 <= DIAMETRE - 1)
		for (j = endy + 1; j < DIAMETRE; j++)
		    for (i = 0; i < DIAMETRE; i++)
			tabsolu[i][j] = 0;
	}


	for (py = starty; py <= endy; py++) {
	    startx = DIAMETRE / 2 - 6 -
		(int) sqrt(MAX((radius_proj * radius_proj -
				(py - DIAMETRE / 2) *
				(py - DIAMETRE / 2)), 0.0));
	    startx = (startx < 0) ? 0 : startx;
/*
 *   0<= startx <=31
 */
	    if (solution == FALSE) {
		int i;
		if (startx > 0)
		    for (i = 0; i < startx; i++) {
			tabsolu[i][py] = 0;
			tabsolu[DIAMETRE - 1 - i][py] = 0;
		    }
	    }

	    for (px = startx; px < DIAMETRE / 2; px++) {
		if (solution == FALSE) {
		    dir_x = (double) px - DIAMETRE / 2 + 0.5;

		    dir_y = -(double) py + DIAMETRE / 2 - 0.5;

		    a = dir_x * dir_x + dir_y * dir_y + dir_z * dir_z;

		    /*what's under the sq.root when solving the
		       quadratic equation */
		    udroot = b_coef * b_coef - 4 * a * c_coef;
		    if (udroot >= 0) {
			tabsolu[px][py] = 1;
			tabsolu[DIAMETRE - 1 - px][py] = 1;
			wurzel = sqrt(udroot);
			s1 = (-b_coef + wurzel) / (2. * a);
			s2 = (-b_coef - wurzel) / (2. * a);
			s = (s1 < s2) ? s1 : s2;	/* smaller solution
							   belongs to nearer
							   intersection */
			/* sp = camera pos + s*dir */
			solu[px][py][0] = s * dir_x;
			solu[px][py][1] = s * dir_y;
			solu[px][py][2] = center_dist + s * dir_z;
		    } else {
			tabsolu[px][py] = 0;
			tabsolu[DIAMETRE - 1 - px][py] = 0;
		    }
		}
		if (tabsolu[px][py]) {	/*  solution exists <=>
					   intersection exists */
		    sp_x = solu[px][py][0];
		    sp_y = solu[px][py][1];
		    sp_z = solu[px][py][2];
		    hit_x = m11 * sp_x + m12 * sp_y + m13 * sp_z;
		    hit_y = m22 * sp_y + m23 * sp_z;
		    hit_z = m31 * sp_x + m32 * sp_y + m33 * sp_z;

		    hit2_x = -m11 * sp_x + m12 * sp_y + m13 * sp_z;
		    hit2_y = m22 * sp_y + m23 * sp_z;
		    hit2_z = -m31 * sp_x + m32 * sp_y + m33 * sp_z;

/*** hope hit_z wont get too close to zero *******/
#ifdef DEBUG
		    if (ABS(hit_z) < ABS(minhz)) {
			minhz = hit_z;
			fprintf(stdout, "should >>0 : hit_z %f\n", hit_z);
			fprintf(stdout, "             hit_x %f\n", hit_x);
			fprintf(stdout, "             ratio %f\n",
				hit_x / hit_z);
			fprintf(stdout, "             long  %f\n",
				atan(hit_x / hit_z));

			sleep(1);
		    }
#endif
		    if (ABS(hit_z) < 0.001) {
			if (hit_x * hit_z > 0.)
			    longitude = PI / 2.;
			else
			    longitude = -PI / 2.;
			if (hit_z > 0.)
			    hit_z = 0.001;
			else
			    hit_z = -0.001;
		    } else {
			longitude = atan(hit_x / hit_z);
		    }

		    if (hit_z < 0.)
			longitude += PI;

		    r = (double) sqrt(hit_x * hit_x + hit_z * hit_z);

		    latitude = atan(-hit_y / r);

		    light_angle =
			(light_x * hit_x + light_y * hit_y +
			 light_z * hit_z) / radius;
		    if (sens == 1) {

			/*
			 *  Set pixel in image
			 */

			teinte =
			    mygetMapColorLinear(longitude, latitude,
						light_angle);
			myRPutPixel(px, py, &teinte);

			/*
			 * mirror the left half-circle of the globe:
			 * we need a new position and have to recalc. the
			 * light intensity
			 */

			light_angle =
			    (light_x * hit2_x + light_y * hit2_y +
			     light_z * hit2_z) / radius;
			teinte =
			    mygetMapColorLinear(2 * v_long - longitude,
						latitude, light_angle);
			myRPutPixel(DIAMETRE - px - 1, py, &teinte);
		    } else {
			/* sens==-1 */
			/*
			 *  Set pixel in image
			 */

			teinte =
			    mygetMapColorLinear(longitude, latitude,
						light_angle);
			myRPutPixel(DIAMETRE - px - 1, DIAMETRE - py - 1,
				    &teinte);

			/*
			 * mirror the left half-circle of the globe:
			 * we need a new position and have
			 * to recalc. the light intensity
			 */

			light_angle =
			    (light_x * hit2_x + light_y * hit2_y +
			     light_z * hit2_z) / radius;
			teinte =
			    mygetMapColorLinear(2 * v_long - longitude,
						latitude, light_angle);
			myRPutPixel(px, DIAMETRE - py - 1, &teinte);
		    }
		}
	    }			/*px */
	}			/*py */


    }				/*else fun */
#if WITH_MARKERS
/* markers */
    if (nb_marker) {
	int i;
	double mx, my, mz;

	for (i = 0; i < nb_marker; i++) {

	    mx = m11 * marker[i][0] + m31 * marker[i][2];
	    mz = -m31 * marker[i][0] + m11 * marker[i][2];
	    my = m22 * marker[i][1] - m23 * mz;
	    mz = m23 * marker[i][1] + m22 * mz;

	    if (mz > 0) {
		if (i == sun_marker) {
		    put_dot_cross((int)
				  (mx * radius_proj + DIAMETRE / 2 + funx),
				  (int) (-my * radius_proj + DIAMETRE / 2 +
					 funy), &sun_col);
		} else if (i == moon_marker) {
		    put_dot_cross((int)
				  (mx * radius_proj + DIAMETRE / 2 + funx),
				  (int) (-my * radius_proj + DIAMETRE / 2 +
					 funy), &moon_col);
		} else {
		    put_cross((int)
			      (mx * radius_proj + DIAMETRE / 2 + funx),
			      (int) (-my * radius_proj + DIAMETRE / 2 +
				     funy));
		}
	    }
	}
    }
#endif
    solution = TRUE;
    return;
}













static RColor
mygetMapColorLinear(double longitude, double latitude, double angle)
{
    RColor point;
    int x, y, xl, yl, dx, dy, ang;

    if (longitude < 0.)
	longitude += 2 * PI;

    latitude += PI / 2;

    longitude += PI;
    if (longitude >= 2 * PI)
	longitude -= 2 * PI;

    if (angle > 0)
	ang = (int) floor((1 - ((1 - angle) * dawn)) * 256);
    else
	ang = angle * 256;

    xl = (int) (longitude * mratiox);
    yl = (int) (latitude * mratioy);

    x = xl >> 8;
    y = yl >> 8;
    dx = xl - (x << 8);
    dy = yl - (y << 8);

    if (use_nightmap) {
	if (ang > 0) {
	    getquarter(map, x, y, md, dx, dy);
	    getquarter(mapnight, x, y, mn, dx, dy);

	    md[0]->r = ((mn[0]->r * (256 - ang) + md[0]->r * ang)) >> 8;
	    md[0]->g = ((mn[0]->g * (256 - ang) + md[0]->g * ang)) >> 8;
	    md[0]->b = ((mn[0]->b * (256 - ang) + md[0]->b * ang)) >> 8;
	} else {
	    getquarter(mapnight, x, y, md, dx, dy);
	}
    } else {
	getquarter(map, x, y, md, dx, dy);
	if (ang > 0) {
	    md[0]->r =
		((md[0]->r * aml +
		  md[0]->r * ang / 256 * (256 - aml))) >> 8;
	    md[0]->g =
		((md[0]->g * aml +
		  md[0]->g * ang / 256 * (256 - aml))) >> 8;
	    md[0]->b =
		((md[0]->b * aml +
		  md[0]->b * ang / 256 * (256 - aml))) >> 8;
	} else {
	    md[0]->r = (md[0]->r * aml) >> 8;
	    md[0]->g = (md[0]->g * aml) >> 8;
	    md[0]->b = (md[0]->b * aml) >> 8;
	}
    }

    point.red = (unsigned char) md[0]->r;
    point.green = (unsigned char) md[0]->g;
    point.blue = (unsigned char) md[0]->b;
    point.alpha = 255; /* in fun mode, we use original Rputpixel that need alpha?*/
    return point;
}







static void randomPosition()
{
    addlat = ((rand() % 30001) / 30000.) * 180. - 90.;
    addlong = ((rand() % 30001) / 30000.) * 360. - 180.;
    return;
}









static void updateTime(int force)
{
/* calcul of sun position every minute */
    if ((trend.tv_sec - tsunpos) >= 60 || force) {
	tsunpos = trend.tv_sec;
	sun_position(tsunpos, &sun_lat, &sun_long);
	light_x = cos(sun_lat) * sin(sun_long);
	light_y = sin(sun_lat);
	light_z = cos(sun_lat) * cos(sun_long);
	do_something = TRUE;
#if WITH_MARKERS
	if (sun_marker >= 0) {
	    marker[sun_marker][0] = light_x;
	    marker[sun_marker][1] = light_y;
	    marker[sun_marker][2] = light_z;
	}
/* ... and the moon position */
	if (moon_marker >= 0 || p_type == PTMOON || force == STRONG) {
	    moon_position(tsunpos, &moon_lat, &moon_long);
	    if (moon_marker >= 0) {
		marker[moon_marker][1] = moon_lat;
		marker[moon_marker][0] = moon_long;
		transform_marker(moon_marker);
	    }
	}
#endif
    }
    return;
}









void transform_marker(int m)
{
    /* long/lat => rotation matrix */
    double dtmp1, dtmp2;

    dtmp1 = sin(marker[m][0]) * cos(marker[m][1]);
    dtmp2 = sin(marker[m][1]);
    marker[m][2] = cos(marker[m][0]) * cos(marker[m][1]);
    marker[m][0] = dtmp1;
    marker[m][1] = dtmp2;
}








void setViewPos(double lat, double lon)
{
    double dif;
    while (lat >= 360.)
	lat -= 360.;
    while (lat <= -360.)
	lat += 360.;
    while (addlat >= 360.)
	addlat -= 360.;
    while (addlat <= -360.)
	addlat += 360.;

    if (lat >= 90.) {
	dif = lat;
	lat = 180. - lat;
	addlat += (lat - dif);
	dlat *= -1;
	if (!fun && !stable) {
	    lon += 180.;
	    addlong += 180.;
	}
	if (!stable)
	    sens *= -1;
    }
    if (lat <= -90.) {
	dif = lat;
	lat = -180. - lat;
	addlat += (lat - dif);
	dlat *= -1;
	if (!fun && !stable) {
	    lon += 180.;
	    addlong += 180.;
	}
	if (!stable)
	    sens *= -1;
    }
    if (lat >= 90.) {
	dif = lat;
	lat = 180. - lat;
	addlat += (lat - dif);
	dlat *= -1;
	if (!fun && !stable) {
	    lon += 180.;
	    addlong += 180.;
	}
	if (!stable)
	    sens *= -1;
    }
    if (lat <= -90.) {
	dif = lat;
	lat = -180. - lat;
	addlat += (lat - dif);
	dlat *= -1;
	if (!fun && !stable) {
	    lon += 180.;
	    addlong += 180.;
	}
	if (!stable)
	    sens *= -1;
    }
    while (lon >= 180.) {
	lon -= 360.;
	addlong -= 360.;
    }
    while (lon <= -180.) {
	lon += 360.;
	addlong += 360.;
    }

    v_lat = lat * PI / 180.;
    v_long = lon * PI / 180.;
    dv_lat = lat;
    dv_long = lon;

    return;
}








void recalc(int force)
{
    double coeff, va, vo;
    struct timeval tv, tnow;

    tnow = getimev();
    trend = timeaccel(tnow);
    tv = diftimev(tnow, tlast);

    if (firstTime) {
	firstTime = FALSE;
	updateTime(STRONG);
    } else {
	coeff = (double) tv.tv_sec + tv.tv_usec / 1000000.;

	if (!force) {
/** while !clic button rotate earth **/
	    addlat += dlat * coeff;
	    addlong += dlong * coeff;
	}
    }

    if (addlong != old_dvlong || addlat != old_dvlat || p_type == PTRANDOM) {
	old_dvlong = addlong;
	old_dvlat = addlat;
	do_something = TRUE;
    }
#if WITH_MARKERS
    if (force) {
	if (p_type == PTSUN) {
	    va = sun_lat * 180. / PI;
	    vo = sun_long * 180. / PI;
	    updateTime(TRUE);
	    addlat -= sun_lat * 180. / PI - va;
	    addlong -= sun_long * 180. / PI - vo;
	} else if (p_type == PTMOON) {
	    va = moon_lat * 180. / PI;
	    vo = moon_long * 180. / PI;
	    updateTime(TRUE);
	    addlat -= moon_lat * 180. / PI - va;
	    addlong -= moon_long * 180. / PI - vo;
	}
#else
    if (force && p_type == PTSUN) {
	va = sun_lat * 180. / PI;
	vo = sun_long * 180. / PI;
	updateTime(TRUE);
	addlat -= sun_lat * 180. / PI - va;
	addlong -= sun_long * 180. / PI - vo;
#endif
    } else {
	updateTime(FALSE);
    }

    if (do_something) {
	switch (p_type) {
	case PTSUN:
	    setViewPos(sun_lat * 180. / PI + addlat,
		       sun_long * 180. / PI + addlong);
	    break;

#if WITH_MARKERS
	case PTMOON:
	    setViewPos(moon_lat * 180. / PI + addlat,
		       moon_long * 180. / PI + addlong);
	    break;
#endif
	case PTFIXED:
	    setViewPos(addlat, addlong);
	    break;

	case PTRANDOM:
	    if (stoprand == FALSE)
		randomPosition();
	    else
		stoprand--;
	    setViewPos(addlat, addlong);
	    break;

	default:
	    break;
	}
#ifdef DEBUG
	fprintf(stdout, "%s  render\n", ctime(&trend.tv_sec));
#endif
	renderFrame();
    }
    tlast = tnow;
    tnext = addtimev(tnow, tdelay);

    return;
}






/* convert a 4 layers RGBA image to a 3 layer one */
int ripalpha(RImage * image)
{
    int x, y;
    unsigned char *d, *s, *old;

    if (image == NULL)
	return 0;
    if (image->format == RRGBFormat)
	return 1;

    d = malloc(image->width * image->height * 3 + 4);
    if (!d) {
	RErrorCode = RERR_NOMEMORY;
	puts("error in ripalpha");
	return 0;
    }

    s = image->data;
    old = image->data;
    image->data = d;
    image->format = RRGBFormat;
    for (y = 0; y < image->height; y++) {
	for (x = 0; x < image->width; x++) {
	    *d++ = *s++;
	    *d++ = *s++;
	    *d++ = *s++;
	    s++;
	}
    }
    free(old);
    return 1;
}
