/** * @(#) $RCSfile: MouseEngineLoop.as,v $ $Revision: 1.4 $ $Date: 2003/01/29 16:40:19 $ * * Copyright 2003 Orgdot AS. All Rights Reserved. * http://dev.swfit.com * * 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. */ /** * Generates several mouse xy values with delays and bounce. See MouseEngineInit * for further information. * * @author Olaf Havnes * @version $Revision: 1.4 $ $Date: 2003/01/29 16:40:19 $ * @since SWFIT1.0 */ // NB Split this file in two - we don't need the camera all the time? // The old mouse position old_x = x; // The real mouse x position x = _x; // The change since last frame c_x = x - old_x; // The delayed mouse x position dl_x = (dl_x * dl + x) / (dl + 1); // The undelayed but clipped mouse x position cl_x = x; if (x < x_min) cl_x = x_min; else if (x > x_max) cl_x = x_max; // The delayed and clipped mouse x position dc_x = (dc_x * dl + cl_x) / (dl + 1); // The rubber mouse x uses the clipped and undelayed x vx += ac * (cl_x - rb_x) - fr * vx; rb_x += vx; // Store in _level0. /:mouse_x = x; /:mouse_int_x = int (x); /:change_mouse_x = c_x; /:change_mouse_int_x = int (c_x); /:delay_mouse_x = dl_x; /:delay_mouse_int_x = int (dl_x); /:clip_mouse_x = cl_x; /:clip_mouse_int_x = int (cl_x); /:delay_clip_mouse_x = dc_x; /:delay_clip_mouse_int_x = int (dc_x); /:rubber_mouse_x = rb_x; /:rubber_mouse_int_x = int (rb_x); /** * Repeat for y. */ // The old mouse position old_y = y; // The real mouse y position y = _y; // The change since last frame c_y = y - old_y; // The delayed mouse y position dl_y = (dl_y * dl + y) / (dl + 1); // The undelayed but clipped mouse y position cl_y = y; if (y < y_min) cl_y = y_min; else if (y > y_max) cl_y = y_max; // The delayed and clipped mouse y position dc_y = (dc_y * dl + cl_y) / (dl + 1); // The rubber mouse y uses the clipped and undelayed y vy += ac * (cl_y - rb_y) - fr * vy; rb_y += vy; // Store in _level0. /:mouse_y = y; /:mouse_int_y = int (y); /:change_mouse_y = c_y; /:change_mouse_int_y = int (c_y); /:delay_mouse_y = dl_y; /:delay_mouse_int_y = int (dl_y); /:clip_mouse_y = cl_y; /:clip_mouse_int_y = int (cl_y); /:delay_clip_mouse_y = dc_y; /:delay_clip_mouse_int_y = int (dc_y); /:rubber_mouse_y = rb_y; /:rubber_mouse_int_y = int (rb_y); /** * The camera model uses the delayed-clipped mouse values, producing values between * - 1 and 1 for camera-position, reversing the sign for the y-values (+ is now up). */ cam_x = dc_x / cw_2 + xwa; cam_y = - dc_y / ch_2 + ywa; // pre-compute cam_x2 = cam_x * cam_x; cam_y2 = cam_y * cam_y; cam_z2 = cam_len_sq - cam_x2 - cam_y2; // Iterate just once through Newton's method. I doubt anybody is able to move the // mouse quick enough to produce a significant error on this value, especially since // the camera uses the delayed mouse values. cam_z = (cam_z + cam_z2 / cam_z) / 2; // Store in _level0. /:camera_x = cam_x; /:camera_y = cam_y; /:camera_z = cam_z; // When we move the camera back plane, we might think of it as // a) rotate the "horizon unit line HUV" in the XZ plane around the Y-axis // b) rotate the "verizon unit line VUV " around the horizon line, so that // VUV is perpendicular to both HUV and the camera back plane // We look at HUV first. Rotating HUV in the XZ-plane: // HUV = (xh, 0, zh) and |HUV| = 1 gives us: zh * zh + xh * xh = 1 // C.HUV = 0 gives us: xh * cam_x + zh * cam_z = 0 // ==> zh = - xh * cam_x / cam_z , and // ==> xh * xh * (1 + cam_x * cam_x / cam_z * cam_z ) = 1 xh = (xh + cam_z2 / ((cam_z2 + cam_x2) * xh)) / 2; zh = - xh * cam_x / cam_z; yh = 0; // Then we look at VUV, remembering that: // VUV.HUV = 0, C.VUV = 0 and |VUV| = 1 // See EOF for notes. eq_0 = xh * cam_z - zh * cam_x; eq_1 = yh * cam_z - zh * cam_y; eq_2 = xh * cam_y - yh * cam_x; eq_02 = eq_0 * eq_0; // One Newton iteration will do for the square root: yv = ( yv + eq_02 / ((eq_02 + eq_1 * eq_1 + eq_2 * eq_2) * yv) ) / 2; zv = - yv * eq_2 / eq_0; xv = - yv * eq_1 / eq_0; // We get values for the camera roll from the mouse position on the screen. // The further out the mouse is, the more roll, the closer to one centered axis, // the less roll. We use the sign to adjust for quadrant. cr = cr_2 * (cam_x2 + cam_y2) * cam_x * cam_y; // Store in _level0. /:camera_roll = cr; // Look up a trig value: cr_mult = int (cr * /:DEG_MULT); if (cr_mult < 0) cr_mult += /:NUM_DEG; cr_mult_cos = eval ("/:COS_" add cr_mult); cr_mult_sin = eval ("/:SIN_" add cr_mult); // Then we return to the two vectors HUV and VUV from above. The two vectors in // the rotated crosshair can be represented as a sum of HUV and VUV: // huv_r = cos (R) * HUV + sin (R) * VUV, and // vuv_r = cos (R) * VUV - sin (R) * VUV: // Store in _level0. /:huv_x = xh * cr_mult_cos + xv * cr_mult_sin; /:huv_y = yh * cr_mult_cos + yv * cr_mult_sin; /:huv_z = zh * cr_mult_cos + zv * cr_mult_sin; /:vuv_x = xv * cr_mult_cos - xh * cr_mult_sin; /:vuv_y = yv * cr_mult_cos - yh * cr_mult_sin; /:vuv_z = zv * cr_mult_cos - zh * cr_mult_sin; /* Notes for the "verizon" unit vector: a) cam_x * xv + cam_y * yv + cam_z * zv = 0 ==> zv = - xv * cam_x / cam_z - yv * cam_y / cam_z b) xh * xv + yh * yv + zh * zv = 0 ==> xv = - yv * ( yh / xh ) - zv * ( zh / xh ) Do substitution on both: a) cam_x * (- yv * ( yh / xh ) - zv * ( zh / xh )) + cam_y * yv + cam_z * zv = 0 cam_y * yv - cam_x * yv * yh / xh = - cam_x * zv * zh / xh + cam_z * zv zv = - yv * (cam_y * xh - cam_x * yh ) / (cam_z * xh - cam_x * zh) zv^2 = yv^2 * (cam_y * xh - cam_x * yh )^2 / (cam_z * xh - cam_x * zh)^2 b) xh * xv + yh * yv + zh * (- xv * cam_x / cam_z - yv * cam_y / cam_z) = 0 xv * (xh - zh * cam_x / cam_z) + yv * (yh - zh * cam_y / cam_z) = 0 xv = - yv * (yh * cam_z - zh * cam_y) / (xh * cam_z - zh * cam_x) xv^2 = yv^2 * (yh * cam_z - zh * cam_y)^2 / (xh * cam_z - zh * cam_x) ^2 We know that the length of VUV is 1: 1 = xv^2 + yv^2 + zv^2 = yv^2 * ( (xh * cam_z - zh * cam_x)^2 + (yh * cam_z - zh * cam_y)^2 + (xh * cam_y - yh * cam_x)^2 ) / (xh * cam_z - zh * cam_x)^2 etc. */