static float _bilinear_interpolate(float ll, float lr, float rl, float rr, float lambda1, float lambda2) { float il = _lerp(ll, rl, lambda1); float ir = _lerp(lr, rr, lambda1); return _lerp(il,ir,lambda2); }
static void _get_split_vertex(vertex &v_ret, const vertex &va, const vertex &vb, float y) { float ly = (y - va.y) / (vb.y - va.y); v_ret.x = _lerp(va.x, vb.x, ly); v_ret.y = y; v_ret.z = _lerp(va.z, vb.z, ly); v_ret.w = 1; v_ret.r = _lerp(va.r, vb.r, ly); v_ret.g = _lerp(va.g, vb.g, ly); v_ret.b = _lerp(va.b, vb.b, ly); v_ret.a = _lerp(va.a, vb.a, ly); v_ret.u = _lerp(va.u, vb.u, ly); v_ret.v = _lerp(va.v, vb.v, ly); }
//----------------------------------------------------------------------- double Noise3D::_noise(double x, double y, double z) { int X = (int)floor(x) & 255; int Y = (int)floor(y) & 255; int Z = (int)floor(z) & 255; x -= floor(x); y -= floor(y); z -= floor(z); double u = _fade(x); double v = _fade(y); double w = _fade(z); int A = p[X ]+Y, AA = p[A]+Z, AB = p[A+1]+Z; int B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z; double lrp = _lerp(w, _lerp(v, _lerp(u, _grad(p[AA], x, y, z), _grad(p[BA], x-1, y, z)), _lerp(u, _grad(p[AB], x, y-1, z), _grad(p[BB], x-1, y-1, z))), _lerp(v, _lerp(u, _grad(p[AA+1], x, y , z-1), _grad(p[BA+1], x-1, y, z-1)), _lerp(u, _grad(p[AB+1], x, y-1, z-1), _grad(p[BB+1], x-1, y-1, z-1)))); return Ogre::Math::Abs((Ogre::Real)lrp); // Use absolute value, because lrp in between [-1, 1] }
G_GNUC_PURE guint32 turbulencePixel(Geom::Point const &p) const { int wrapx = _wrapx, wrapy = _wrapy, wrapw = _wrapw, wraph = _wraph; double pixel[4]; double x = p[Geom::X] * _baseFreq[Geom::X]; double y = p[Geom::Y] * _baseFreq[Geom::Y]; double ratio = 1.0; for (int k = 0; k < 4; ++k) pixel[k] = 0.0; for(int octave = 0; octave < _octaves; ++octave) { double tx = x + PerlinOffset; double bx = floor(tx); double rx0 = tx - bx, rx1 = rx0 - 1.0; int bx0 = bx, bx1 = bx0 + 1; double ty = y + PerlinOffset; double by = floor(ty); double ry0 = ty - by, ry1 = ry0 - 1.0; int by0 = by, by1 = by0 + 1; if (_stitchTiles) { if (bx0 >= wrapx) bx0 -= wrapw; if (bx1 >= wrapx) bx1 -= wrapw; if (by0 >= wrapy) by0 -= wraph; if (by1 >= wrapy) by1 -= wraph; } bx0 &= BMask; bx1 &= BMask; by0 &= BMask; by1 &= BMask; int i = _latticeSelector[bx0]; int j = _latticeSelector[bx1]; int b00 = _latticeSelector[i + by0]; int b01 = _latticeSelector[i + by1]; int b10 = _latticeSelector[j + by0]; int b11 = _latticeSelector[j + by1]; double sx = _scurve(rx0); double sy = _scurve(ry0); double result[4]; // channel numbering: R=0, G=1, B=2, A=3 for (int k = 0; k < 4; ++k) { double const *qxa = _gradient[b00][k]; double const *qxb = _gradient[b10][k]; double a = _lerp(sx, rx0 * qxa[0] + ry0 * qxa[1], rx1 * qxb[0] + ry0 * qxb[1]); double const *qya = _gradient[b01][k]; double const *qyb = _gradient[b11][k]; double b = _lerp(sx, rx0 * qya[0] + ry1 * qya[1], rx1 * qyb[0] + ry1 * qyb[1]); result[k] = _lerp(sy, a, b); } if (_fractalnoise) { for (int k = 0; k < 4; ++k) pixel[k] += result[k] / ratio; } else { for (int k = 0; k < 4; ++k) pixel[k] += fabs(result[k]) / ratio; } x *= 2; y *= 2; ratio *= 2; if(_stitchTiles) { // Update stitch values. Subtracting PerlinOffset before the multiplication and // adding it afterward simplifies to subtracting it once. wrapw *= 2; wraph *= 2; wrapx = wrapx*2 - PerlinOffset; wrapy = wrapy*2 - PerlinOffset; } } if (_fractalnoise) { guint32 r = CLAMP_D_TO_U8((pixel[0]*255.0 + 255.0) / 2); guint32 g = CLAMP_D_TO_U8((pixel[1]*255.0 + 255.0) / 2); guint32 b = CLAMP_D_TO_U8((pixel[2]*255.0 + 255.0) / 2); guint32 a = CLAMP_D_TO_U8((pixel[3]*255.0 + 255.0) / 2); r = premul_alpha(r, a); g = premul_alpha(g, a); b = premul_alpha(b, a); ASSEMBLE_ARGB32(pxout, a,r,g,b); return pxout; } else { guint32 r = CLAMP_D_TO_U8(pixel[0]*255.0); guint32 g = CLAMP_D_TO_U8(pixel[1]*255.0); guint32 b = CLAMP_D_TO_U8(pixel[2]*255.0); guint32 a = CLAMP_D_TO_U8(pixel[3]*255.0); r = premul_alpha(r, a); g = premul_alpha(g, a); b = premul_alpha(b, a); ASSEMBLE_ARGB32(pxout, a,r,g,b); return pxout; } }
int wind_file_get_wind(wind_file_t* file, float lat, float lon, float height, float* windu, float *windv, float *uvar, float *vvar) { // we use static variables to 'cache' the last left and right lat/longs // and heights so that we can avoid searching the axes if necessary static int have_valid_latlon_cache = 0; static int have_valid_pressure_cache = 0; static unsigned int left_lat_idx, right_lat_idx; static unsigned int left_lon_idx, right_lon_idx; static unsigned int left_pr_idx, right_pr_idx; static float left_lat, right_lat; static float left_lon, right_lon; int i; float left_height, right_height; float lat_lambda, lon_lambda, pr_lambda; assert(file); assert(windu && windv); // canonicalise the longitude lon = _canonicalise_longitude(lon); // by default, return nothing in case of error. *windu = *windv = 0.f; // see if the cache is indeed valid if(have_valid_latlon_cache) { if((left_lat > lat) || (right_lat < lat) || !_longitude_is_left_of(left_lon, lon) || !_longitude_is_left_of(lon, right_lon)) { have_valid_latlon_cache = 0; } } // if we have no cached grid locations, look for them. if(!have_valid_latlon_cache) { // look for latitude along second axis if(!_wind_file_axis_find_value(file->axes[1], lat, _float_is_left_of, &left_lat_idx, &right_lat_idx)) { fprintf(stderr, "ERROR: Latitude %f is not covered by file.\n", lat); return 0; } left_lat = file->axes[1]->values[left_lat_idx]; right_lat = file->axes[1]->values[right_lat_idx]; // look for longitude along third axis if(!_wind_file_axis_find_value(file->axes[2], lon, _longitude_is_left_of, &left_lon_idx, &right_lon_idx)) { fprintf(stderr, "ERROR: Longitude %f is not covered by file.\n", lon); return 0; } left_lon = file->axes[2]->values[left_lon_idx]; right_lon = file->axes[2]->values[right_lon_idx]; if(verbosity > 1) fprintf(stderr, "INFO: Moved to latitude/longitude " "cell (%f,%f)-(%f,%f)\n", left_lat, left_lon, right_lat, right_lon); have_valid_latlon_cache = 1; } // compute the normalised lat/lon co-ordinate within the cell we're in. if(left_lat_idx != right_lat_idx) lat_lambda = (lat - left_lat) / (right_lat - left_lat); else lat_lambda = 0.5f; if(left_lon_idx != right_lon_idx) lon_lambda = _longitude_distance(lon, left_lon) / _longitude_distance(right_lon, left_lon); else lon_lambda = 0.5f; // munge the lambdas into the right range. Numerical approximations can nudge them // ~1e-08 either side sometimes. lat_lambda = (lat_lambda < 0.f) ? 0.f : lat_lambda; lat_lambda = (lat_lambda > 1.f) ? 1.f : lat_lambda; lon_lambda = (lon_lambda < 0.f) ? 0.f : lon_lambda; lon_lambda = (lon_lambda > 1.f) ? 1.f : lon_lambda; // use this normalised co-ordinate to check the left and right heights if(have_valid_pressure_cache) { float ll_height, lr_height, rl_height, rr_height; // left ll_height = _wind_file_get_height(file, left_lat_idx, left_lon_idx, left_pr_idx); lr_height = _wind_file_get_height(file, left_lat_idx, right_lon_idx, left_pr_idx); rl_height = _wind_file_get_height(file, right_lat_idx, left_lon_idx, left_pr_idx); rr_height = _wind_file_get_height(file, right_lat_idx, right_lon_idx, left_pr_idx); left_height = _bilinear_interpolate(ll_height, lr_height, rl_height, rr_height, lat_lambda, lon_lambda); // if the leftmost height is too small and we can go lower... if((left_height > height) && (left_pr_idx > 0)) have_valid_pressure_cache = 0; // right ll_height = _wind_file_get_height(file, left_lat_idx, left_lon_idx, right_pr_idx); lr_height = _wind_file_get_height(file, left_lat_idx, right_lon_idx, right_pr_idx); rl_height = _wind_file_get_height(file, right_lat_idx, left_lon_idx, right_pr_idx); rr_height = _wind_file_get_height(file, right_lat_idx, right_lon_idx, right_pr_idx); right_height = _bilinear_interpolate(ll_height, lr_height, rl_height, rr_height, lat_lambda, lon_lambda); // if the rightmost height is too small and we can go higher... if((right_height < height) && (right_pr_idx < file->axes[0]->n_values-1)) have_valid_pressure_cache = 0; } // if our height cache is out of whack, find a better cell. if(!have_valid_pressure_cache) { // search along all heights to find what pressure level we're at left_pr_idx = right_pr_idx = file->axes[0]->n_values; left_height = right_height = -1.f; for(i=0; i<file->axes[0]->n_values; ++i) { // get heights for each corner of our lat/lon cell. float ll_height = _wind_file_get_height(file, left_lat_idx, left_lon_idx, i); float lr_height = _wind_file_get_height(file, left_lat_idx, right_lon_idx, i); float rl_height = _wind_file_get_height(file, right_lat_idx, left_lon_idx, i); float rr_height = _wind_file_get_height(file, right_lat_idx, right_lon_idx, i); // interpolate within our cell. float interp_height = _bilinear_interpolate( ll_height, lr_height, rl_height, rr_height, lat_lambda, lon_lambda); if((interp_height <= height) && ((interp_height >= left_height) || (left_pr_idx == file->axes[0]->n_values))) { left_pr_idx = i; left_height = interp_height; } if((interp_height >= height) && ((interp_height <= right_height) || (right_pr_idx == file->axes[0]->n_values))) { right_pr_idx = i; right_height = interp_height; } } if(left_pr_idx == file->axes[0]->n_values) { left_pr_idx = right_pr_idx; if(verbosity > 0) fprintf(stderr, "WARN: Moved to %.2fm, below height where we " "have data. " "Assuming we're at %.fmb or approx. %.2fm.\n", height, file->axes[0]->values[left_pr_idx], _wind_file_get_height(file, left_lat_idx, left_lon_idx, left_pr_idx)); } if(right_pr_idx == file->axes[0]->n_values) { right_pr_idx = left_pr_idx; if(verbosity > 0) fprintf(stderr, "WARN: Moved to %.2fm, above height where we " "have data. " "Assuming we're at %.fmb or approx. %.2fm.\n", height, file->axes[0]->values[right_pr_idx], _wind_file_get_height(file, left_lat_idx, left_lon_idx, right_pr_idx)); } if((left_pr_idx == file->axes[0]->n_values) || (right_pr_idx == file->axes[0]->n_values)) { fprintf(stderr, "ERROR: Moved to a totally stupid height (%f). " "Giving up!\n", height); return 0; } if(verbosity > 1) fprintf(stderr, "INFO: Moved to pressure cell (%.fmb, %.fmb)\n", file->axes[0]->values[left_pr_idx], file->axes[0]->values[right_pr_idx]); have_valid_pressure_cache = 1; } // compute the normalised pressure co-ordinate within the cell we're in. if(left_pr_idx != right_pr_idx) pr_lambda = (height - left_height) / (right_height - left_height); else pr_lambda = 0.5f; // pr_lambda might be outside of the range [0,1] depending on if we went // above or below our data, munge it appropriately. pr_lambda = (pr_lambda < 0.f) ? 0.f : pr_lambda; pr_lambda = (pr_lambda > 1.f) ? 1.f : pr_lambda; assert(lat_lambda >= 0.f); assert(lon_lambda >= 0.f); assert(pr_lambda >= 0.f); assert(lat_lambda <= 1.f); assert(lon_lambda <= 1.f); assert(pr_lambda <= 1.f); // By this point we have left/right co-ordinates which describe the // latitude, longitude and pressure boundaries of our data cell along // with normalised co-ordinates within it. We can now actually find // some data... // // We compute the lerped u and v along with the neighbourhood mean and // square mean to calculate the neighbourhood variance. { float llu, lru, rlu, rru; float llv, lrv, rlv, rrv; float lowu, lowv, highu, highv; float umean = 0.f; float usqmean = 0.f; float vmean = 0.f; float vsqmean = 0.f; // let's get the wind u and v for the lower lat/lon cell _wind_file_get_wind_raw(file, left_lat_idx, left_lon_idx, left_pr_idx, &llu, &llv); _wind_file_get_wind_raw(file, left_lat_idx, right_lon_idx, left_pr_idx, &lru, &lrv); _wind_file_get_wind_raw(file, right_lat_idx, left_lon_idx, left_pr_idx, &rlu, &rlv); _wind_file_get_wind_raw(file, right_lat_idx, right_lon_idx, left_pr_idx, &rru, &rrv); lowu = _bilinear_interpolate(llu, lru, rlu, rru, lat_lambda, lon_lambda); lowv = _bilinear_interpolate(llv, lrv, rlv, rrv, lat_lambda, lon_lambda); umean = llu + lru + rlu + rru; vmean = llv + lrv + rlv + rrv; usqmean = llu*llu + lru*lru + rlu*rlu + rru*rru; vsqmean = llv*llv + lrv*lrv + rlv*rlv + rrv*rrv; /* lowusq = _bilinear_interpolate(llu*llu, lru*lru, rlu*rlu, rru*rru, lat_lambda, lon_lambda); lowvsq = _bilinear_interpolate(llv*llv, lrv*lrv, rlv*rlv, rrv*rrv, lat_lambda, lon_lambda); */ // let's get the wind u and v for the upper lat/lon cell _wind_file_get_wind_raw(file, left_lat_idx, left_lon_idx, right_pr_idx, &llu, &llv); _wind_file_get_wind_raw(file, left_lat_idx, right_lon_idx, right_pr_idx, &lru, &lrv); _wind_file_get_wind_raw(file, right_lat_idx, left_lon_idx, right_pr_idx, &rlu, &rlv); _wind_file_get_wind_raw(file, right_lat_idx, right_lon_idx, right_pr_idx, &rru, &rrv); highu = _bilinear_interpolate(llu, lru, rlu, rru, lat_lambda, lon_lambda); highv = _bilinear_interpolate(llv, lrv, rlv, rrv, lat_lambda, lon_lambda); umean += llu + lru + rlu + rru; vmean += llv + lrv + rlv + rrv; usqmean += llu*llu + lru*lru + rlu*rlu + rru*rru; vsqmean += llv*llv + lrv*lrv + rlv*rlv + rrv*rrv; /* highusq = _bilinear_interpolate(llu*llu, lru*lru, rlu*rlu, rru*rru, lat_lambda, lon_lambda); highvsq = _bilinear_interpolate(llv*llv, lrv*lrv, rlv*rlv, rrv*rrv, lat_lambda, lon_lambda); */ *windu = _lerp(lowu, highu, pr_lambda); *windv = _lerp(lowv, highv, pr_lambda); // We will calculate the variance by making use of the fact // that the lerping is effectively a weighted mean or // expectation and that // var = E[X^2] - E[X]^2. // // In effect this calculates the instantaneous variance by considering the // contributions from the cube surrounding the point in question. // This is highly cunning and, on the face of it, not entirely wrong. umean *= 0.125f; usqmean *= 0.125f; vmean *= 0.125f; vsqmean *= 0.125f; *uvar = usqmean - umean * umean; *vvar = vsqmean - vmean * vmean; } return 1; }
static void _smooth_draw_triangle_flat_bottom(vertex &v0, vertex &v1, vertex &v2) { if (v0.y == v1.y) { _swap_vertex(v0, v2); } else if (v0.y == v2.y) { _swap_vertex(v0, v1); } if (v1.x > v2.x) { _swap_vertex(v1, v2); } int x0 = v0.x; int y0 = v0.y; int x1 = v1.x; int y1 = v1.y; int x2 = v2.x; int y2 = v2.y; float xs = x0; float xe = x0; int y_end = (y1 > y2) ? y1 : y2; float y_dis = y_end - y0; float crs = v0.r; float cre = v0.r; float cgs = v0.g; float cge = v0.g; float cbs = v0.b; float cbe = v0.b; float cas = v0.a; float cae = v0.a; float tus = v0.u; float tue = v0.u; float tvs = v0.v; float tve = v0.v; float ds = v0.z; float de = v0.z; bool texturing = (tus != -1 && tvs != -1); color c; for (int y = y0; y < y_end; y++) { float ly = ((float)y - y0) / y_dis; xs = _lerp(x0, x1, ly); xe = _lerp(x0, x2, ly); crs = _lerp(v0.r, v1.r, ly); cre = _lerp(v0.r, v2.r, ly); cgs = _lerp(v0.g, v1.g, ly); cge = _lerp(v0.g, v2.g, ly); cbs = _lerp(v0.b, v1.b, ly); cbe = _lerp(v0.b, v2.b, ly); cas = _lerp(v0.a, v1.a, ly); cae = _lerp(v0.a, v2.a, ly); if (texturing) { tus = _lerp(v0.u, v1.u, ly); tue = _lerp(v0.u, v2.u, ly); tvs = _lerp(v0.v, v1.v, ly); tve = _lerp(v0.v, v2.v, ly); } ds = _lerp(v0.z, v1.z, ly); de = _lerp(v0.z, v2.z, ly); float x_dis = xe - xs; for (int x = xs; x < xe; x++) { float lx = ((float)x - xs) / x_dis; float d = _lerp(ds, de, lx); if (!depth_buffer::get_instance()->d_test(x, y, d)) { continue; } if (!texturing) { c.r = _lerp(crs, cre, lx); c.g = _lerp(cgs, cge, lx); c.b = _lerp(cbs, cbe, lx); c.a = _lerp(cas, cae, lx); } else { float u = _lerp(tus, tue, lx); float v = _lerp(tvs, tve, lx); c = texture::get_instance()->sampling(u, v); } color_buffer::get_intance()->write_color(x, y, c); } } }