diff --git a/toonz/sources/stdfx/particles.cpp b/toonz/sources/stdfx/particles.cpp index 925c036..8a494af 100644 --- a/toonz/sources/stdfx/particles.cpp +++ b/toonz/sources/stdfx/particles.cpp @@ -150,12 +150,14 @@ Particle::Particle(int g_lifetime, int seed, std::map porttiles, /*- Speed Angleの制御。RangeモードとGradientモードがある -*/ if (values.speeda_ctrl_val && - (porttiles.find(values.speeda_ctrl_val) != porttiles.end())) { + (porttiles.find(values.speeda_ctrl_val) != porttiles.end() || + porttiles.find(values.speeda_ctrl_val + Ctrl_64_Offset) != + porttiles.end())) { if (values.speeda_use_gradient_val) { /*- 参照画像のGradientを得る関数を利用して角度を得る -*/ float dir_x, dir_y; - get_image_gravity(porttiles[values.speeda_ctrl_val], values, dir_x, - dir_y); + get_image_gravity(porttiles[values.speeda_ctrl_val + Ctrl_64_Offset], + values, dir_x, dir_y); if (dir_x == 0.0f && dir_y == 0.0f) random_s_a_range = values.speed_val.first; else @@ -558,67 +560,41 @@ void Particle::get_image_reference(TTile *ctrl, const particles_values &values, /*-----------------------------------------------------------------*/ void Particle::get_image_gravity(TTile *ctrl1, const particles_values &values, float &gx, float &gy) { - TRaster32P raster32 = ctrl1->getRaster(); + TRaster64P raster64 = ctrl1->getRaster(); TPointD tmp(x, y); tmp -= ctrl1->m_pos; - int radius = 4; + int radius = 2; gx = 0; gy = 0; -//#define OLDSTUFF -#ifdef OLDSTUFF - int i; -#endif - raster32->lock(); -#ifdef OLDSTUFF - if (!values.gravity_radius_val) { - radius = 4; - if (raster32 && tmp.x >= radius && tmp.x < raster32->getLx() - radius && - tmp.y >= radius && tmp.y < raster32->getLy() - radius) { - TPixel32 *pix = &(raster32->pixels(troundp(tmp.y))[(int)tmp.x]); - double norm = 1 / ((double)TPixelGR8::maxChannelValue); - for (i = 1; i < radius; i++) { - gx += TPixelGR8::from(*(pix + i)).value; - gx -= TPixelGR8::from(*(pix - i)).value; - gy += TPixelGR8::from(*(pix + raster32->getWrap() * i)).value; - gy -= TPixelGR8::from(*(pix - raster32->getWrap() * i)).value; - } - gx = gx * norm; - gy = gy * norm; + raster64->lock(); + if (raster64 && tmp.x >= radius && tmp.x < raster64->getLx() - radius && + tmp.y >= radius && tmp.y < raster64->getLy() - radius) { + TPixel64 *pix = &(raster64->pixels(troundp(tmp.y))[(int)tmp.x]); + + gx += 2 * TPixelGR16::from(*(pix + 1)).value; + gx += TPixelGR16::from(*(pix + 1 + raster64->getWrap() * 1)).value; + gx += TPixelGR16::from(*(pix + 1 - raster64->getWrap() * 1)).value; + + gx -= 2 * TPixelGR16::from(*(pix - 1)).value; + gx -= TPixelGR16::from(*(pix - 1 + raster64->getWrap() * 1)).value; + gx -= TPixelGR16::from(*(pix - 1 - raster64->getWrap() * 1)).value; + + gy += 2 * TPixelGR16::from(*(pix + raster64->getWrap() * 1)).value; + gy += TPixelGR16::from(*(pix + raster64->getWrap() * 1 + 1)).value; + gy += TPixelGR16::from(*(pix + raster64->getWrap() * 1 - 1)).value; + + gy -= 2 * TPixelGR16::from(*(pix - raster64->getWrap() * 1)).value; + gy -= TPixelGR16::from(*(pix - raster64->getWrap() * 1 + 1)).value; + gy -= TPixelGR16::from(*(pix - raster64->getWrap() * 1 - 1)).value; + + double norm = std::sqrt(gx * gx + gy * gy); + if (norm) { + double inorm = 0.1 / norm; + gx = gx * inorm; + gy = gy * inorm; } - } else { -#endif - radius = 2; - if (raster32 && tmp.x >= radius && tmp.x < raster32->getLx() - radius && - tmp.y >= radius && tmp.y < raster32->getLy() - radius) { - TPixel32 *pix = &(raster32->pixels(troundp(tmp.y))[(int)tmp.x]); - - gx += 2 * TPixelGR8::from(*(pix + 1)).value; - gx += TPixelGR8::from(*(pix + 1 + raster32->getWrap() * 1)).value; - gx += TPixelGR8::from(*(pix + 1 - raster32->getWrap() * 1)).value; - - gx -= 2 * TPixelGR8::from(*(pix - 1)).value; - gx -= TPixelGR8::from(*(pix - 1 + raster32->getWrap() * 1)).value; - gx -= TPixelGR8::from(*(pix - 1 - raster32->getWrap() * 1)).value; - - gy += 2 * TPixelGR8::from(*(pix + raster32->getWrap() * 1)).value; - gy += TPixelGR8::from(*(pix + raster32->getWrap() * 1 + 1)).value; - gy += TPixelGR8::from(*(pix + raster32->getWrap() * 1 - 1)).value; - - gy -= 2 * TPixelGR8::from(*(pix - raster32->getWrap() * 1)).value; - gy -= TPixelGR8::from(*(pix - raster32->getWrap() * 1 + 1)).value; - gy -= TPixelGR8::from(*(pix - raster32->getWrap() * 1 - 1)).value; - - double norm = sqrt(gx * gx + gy * gy); - if (norm) { - double inorm = 0.1 / norm; - gx = gx * inorm; - gy = gy * inorm; - } - } -#ifdef OLDSTUFF } -#endif - raster32->unlock(); + raster64->unlock(); } /*-----------------------------------------------------------------*/ @@ -701,9 +677,10 @@ void Particle::move(std::map porttiles, // time=genlifetime-lifetime-1; // if(time<0) time=0; if (values.gravity_ctrl_val && - (porttiles.find(values.gravity_ctrl_val) != porttiles.end())) { - get_image_gravity(porttiles[values.gravity_ctrl_val], values, xgravity, - ygravity); + (porttiles.find(values.gravity_ctrl_val + Ctrl_64_Offset) != + porttiles.end())) { + get_image_gravity(porttiles[values.gravity_ctrl_val + Ctrl_64_Offset], + values, xgravity, ygravity); xgravity *= values.gravity_val; ygravity *= values.gravity_val; } diff --git a/toonz/sources/stdfx/particles.h b/toonz/sources/stdfx/particles.h index a27dfad..da353f4 100644 --- a/toonz/sources/stdfx/particles.h +++ b/toonz/sources/stdfx/particles.h @@ -7,6 +7,8 @@ #include "tspectrum.h" #include "trandom.h" +const int Ctrl_64_Offset = 1000; + //------------------------------------------------------------------------------ struct particles_values { diff --git a/toonz/sources/stdfx/particlesengine.cpp b/toonz/sources/stdfx/particlesengine.cpp index e766039..7ddcf98 100644 --- a/toonz/sources/stdfx/particlesengine.cpp +++ b/toonz/sources/stdfx/particlesengine.cpp @@ -160,15 +160,31 @@ void Particles_Engine::fill_range_struct(struct particles_values &values, } bool Particles_Engine::port_is_used(int i, struct particles_values &values) { + return port_is_used_for_value(i, values) || + port_is_used_for_gradient(i, values); +} + +// Returns true if the pixel value of control image is used. +// Such image will be computed in 8bpc. +bool Particles_Engine::port_is_used_for_value(int i, + struct particles_values &values) { return values.fincol_ctrl_val == i || values.foutcol_ctrl_val == i || values.friction_ctrl_val == i || values.gencol_ctrl_val == i || - values.gravity_ctrl_val == i || values.opacity_ctrl_val == i || - values.rot_ctrl_val == i || values.scale_ctrl_val == i || - values.scalestep_ctrl_val == i || values.source_ctrl_val == i || - values.speed_ctrl_val == i || values.speeda_ctrl_val == i || + values.opacity_ctrl_val == i || values.rot_ctrl_val == i || + values.scale_ctrl_val == i || values.scalestep_ctrl_val == i || + values.source_ctrl_val == i || values.speed_ctrl_val == i || + (values.speeda_ctrl_val == i && !values.speeda_use_gradient_val) || values.lifetime_ctrl_val == i || values.randomx_ctrl_val == i || values.randomy_ctrl_val == i; } + +// Returns true if the gradient of control image is used. +// Such image will be computed in 16bpc to get smooth result. +bool Particles_Engine::port_is_used_for_gradient( + int i, struct particles_values &values) { + return values.gravity_ctrl_val == i || + (values.speeda_ctrl_val == i && values.speeda_use_gradient_val); +} /*-----------------------------------------------------------------*/ /*-- Startフレームからカレントフレームまで順番に回す関数 --*/ void Particles_Engine::roll_particles( @@ -255,7 +271,7 @@ void Particles_Engine::roll_particles( { /*- 新たに作るパーティクルの数だけ繰り返す -*/ for (i = 0; i < newparticles; i++) { - int seed = (int)((std::numeric_limits::max)() * + int seed = (int)((std::numeric_limits::max)() * values.random_val->getFloat()); int level = (int)(values.random_val->getFloat() * level_n); @@ -291,7 +307,7 @@ void Particles_Engine::roll_particles( switch (values.toplayer_val) { case ParticlesFx::TOP_YOUNGER: for (i = 0; i < newparticles; i++) { - int seed = (int)((std::numeric_limits::max)() * + int seed = (int)((std::numeric_limits::max)() * values.random_val->getFloat()); int level = (int)(values.random_val->getFloat() * level_n); @@ -320,7 +336,7 @@ void Particles_Engine::roll_particles( for (int j = 0; j < tmp; j++, it++) ; { - int seed = (int)((std::numeric_limits::max)() * + int seed = (int)((std::numeric_limits::max)() * values.random_val->getFloat()); int level = (int)(values.random_val->getFloat() * level_n); int lifetime = 0; @@ -344,7 +360,7 @@ void Particles_Engine::roll_particles( default: for (i = 0; i < newparticles; i++) { - int seed = (int)((std::numeric_limits::max)() * + int seed = (int)((std::numeric_limits::max)() * values.random_val->getFloat()); int level = (int)(values.random_val->getFloat() * level_n); int lifetime = 0; @@ -402,9 +418,9 @@ void Particles_Engine::normalize_values(struct particles_values &values, (values.speeda_val.first) = (values.speeda_val.first) * M_PI_180; (values.speeda_val.second) = (values.speeda_val.second) * M_PI_180; if (values.step_val < 1) values.step_val = 1; - values.genfadecol_val = (values.genfadecol_val) * 0.01; - values.finfadecol_val = (values.finfadecol_val) * 0.01; - values.foutfadecol_val = (values.foutfadecol_val) * 0.01; + values.genfadecol_val = (values.genfadecol_val) * 0.01; + values.finfadecol_val = (values.finfadecol_val) * 0.01; + values.foutfadecol_val = (values.foutfadecol_val) * 0.01; } /*-----------------------------------------------------------------*/ @@ -492,6 +508,9 @@ void Particles_Engine::render_particles( TRenderSettings riAux(ri); riAux.m_affine = TAffine(); riAux.m_bpp = 32; + // control image using its gradient is computed in 64bpp + TRenderSettings riAux64(riAux); + riAux64.m_bpp = 64; int r_frame; // Useful in case of negative roll frames if (frame < 0) @@ -538,32 +557,74 @@ void Particles_Engine::render_particles( // dryComputed - so, declare the same here. (*it->second)->dryCompute(bbox, r_frame, riAux); } else { - tmp = new TTile; + // control image is used its gradient + if (port_is_used_for_gradient(it->first, values)) { + tmp = new TTile; - if (isPrecomputingEnabled) - (*it->second) - ->allocateAndCompute(*tmp, bbox.getP00(), - convert(bbox).getSize(), 0, r_frame, - riAux); - else { - std::string alias = - "CTRL: " + (*(it->second))->getAlias(r_frame, riAux); - TRasterImageP rimg = TImageCache::instance()->get(alias, false); + if (isPrecomputingEnabled) + (*it->second) + ->allocateAndCompute(*tmp, bbox.getP00(), + convert(bbox).getSize(), 0, r_frame, + riAux64); + else { + std::string alias = + "CTRL64: " + (*(it->second))->getAlias(r_frame, riAux64); + TRasterImageP rimg = TImageCache::instance()->get(alias, false); + + if (rimg) { + tmp->m_pos = bbox.getP00(); + tmp->setRaster(rimg->getRaster()); + } else { + (*it->second) + ->allocateAndCompute(*tmp, bbox.getP00(), + convert(bbox).getSize(), 0, r_frame, + riAux64); + + addRenderCache(alias, TRasterImageP(tmp->getRaster())); + } + } - if (rimg) { + porttiles[it->first + Ctrl_64_Offset] = tmp; + + // in case the control image is also used for non-gradient + if (port_is_used_for_value(it->first, values)) { + TRaster32P tileRas(tmp->getRaster()->getSize()); + TRop::convert(tileRas, tmp->getRaster()); + tmp = new TTile; tmp->m_pos = bbox.getP00(); - tmp->setRaster(rimg->getRaster()); - } else { + tmp->setRaster(tileRas); + porttiles[it->first] = tmp; + } + } + // control images used only for non-gradient + else { + tmp = new TTile; + + if (isPrecomputingEnabled) (*it->second) ->allocateAndCompute(*tmp, bbox.getP00(), convert(bbox).getSize(), 0, r_frame, riAux); - - addRenderCache(alias, TRasterImageP(tmp->getRaster())); + else { + std::string alias = + "CTRL: " + (*(it->second))->getAlias(r_frame, riAux); + TRasterImageP rimg = TImageCache::instance()->get(alias, false); + + if (rimg) { + tmp->m_pos = bbox.getP00(); + tmp->setRaster(rimg->getRaster()); + } else { + (*it->second) + ->allocateAndCompute(*tmp, bbox.getP00(), + convert(bbox).getSize(), 0, r_frame, + riAux); + + addRenderCache(alias, TRasterImageP(tmp->getRaster())); + } } - } - porttiles[it->first] = tmp; + porttiles[it->first] = tmp; + } } } } @@ -849,7 +910,7 @@ void Particles_Engine::fill_array(TTile *ctrl1, int ®ioncount, mask[1] = myarray[i - 1 + lx * (j - 1)]; } if (i != lx - 1) mask[3] = myarray[i + 1 + lx * (j - 1)]; - mask[2] = myarray[i + lx * (j - 1)]; + mask[2] = myarray[i + lx * (j - 1)]; if (!mask[0] && !mask[1] && !mask[2] && !mask[3]) { (regioncount)++; myarray[i + lx * j] = (regioncount); @@ -883,7 +944,7 @@ void Particles_Engine::fill_array(TTile *ctrl1, int ®ioncount, void Particles_Engine::normalize_array( std::vector> &myregions, TPointD pos, int lx, int ly, int regioncounter, std::vector &myarray, std::vector &lista, - std::vector &listb, std::vector & final) { + std::vector &listb, std::vector &final) { int i, j, k, l; std::vector tmp; @@ -896,13 +957,13 @@ void Particles_Engine::normalize_array( j = lista[l]; /*TMSG_INFO("j vale %d\n", j);*/ while (final[j] != j) j = final[j]; - k = listb[l]; + k = listb[l]; /*TMSG_INFO("k vale %d\n", k);*/ while (final[k] != k) k = final[k]; - if (j != k) final[j] = k; + if (j != k) final[j] = k; } // TMSG_INFO("esco dal for\n"); - for (j = 1; j <= regioncounter; j++) + for (j = 1; j <= regioncounter; j++) while (final[j] != final[final[j]]) final[j] = final[final[j]]; /*conto quante cavolo di regioni sono*/ diff --git a/toonz/sources/stdfx/particlesengine.h b/toonz/sources/stdfx/particlesengine.h index 3f783f7..645ae65 100644 --- a/toonz/sources/stdfx/particlesengine.h +++ b/toonz/sources/stdfx/particlesengine.h @@ -52,6 +52,8 @@ public: std::map, double> &partScales); bool port_is_used(int i, struct particles_values &values); + bool port_is_used_for_value(int i, struct particles_values &values); + bool port_is_used_for_gradient(int i, struct particles_values &values); /*- do_source_gradationがONのとき、入力画像のアルファ値に比例して発生濃度を変える。 @@ -81,7 +83,7 @@ public: void normalize_array(std::vector> &myregions, TPointD pos, int lx, int ly, int regioncounter, std::vector &myarray, std::vector &lista, - std::vector &listb, std::vector & final); + std::vector &listb, std::vector &final); void fill_array(TTile *ctrl1, int ®ioncount, std::vector &myarray, std::vector &lista, std::vector &listb, int thres);