particlesfx : use 16bpc control image for gradient

This commit is contained in:
shun-iwasawa 2021-04-20 16:39:28 +09:00 committed by manongjohn
parent 5d866328ea
commit 3b3c1b2fa1
4 changed files with 136 additions and 94 deletions

View file

@ -150,12 +150,14 @@ Particle::Particle(int g_lifetime, int seed, std::map<int, TTile *> porttiles,
/*- Speed Angleの制御。RangeモードとGradientモードがある -*/ /*- Speed Angleの制御。RangeモードとGradientモードがある -*/
if (values.speeda_ctrl_val && 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) { if (values.speeda_use_gradient_val) {
/*- 参照画像のGradientを得る関数を利用して角度を得る -*/ /*- 参照画像のGradientを得る関数を利用して角度を得る -*/
float dir_x, dir_y; float dir_x, dir_y;
get_image_gravity(porttiles[values.speeda_ctrl_val], values, dir_x, get_image_gravity(porttiles[values.speeda_ctrl_val + Ctrl_64_Offset],
dir_y); values, dir_x, dir_y);
if (dir_x == 0.0f && dir_y == 0.0f) if (dir_x == 0.0f && dir_y == 0.0f)
random_s_a_range = values.speed_val.first; random_s_a_range = values.speed_val.first;
else 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, void Particle::get_image_gravity(TTile *ctrl1, const particles_values &values,
float &gx, float &gy) { float &gx, float &gy) {
TRaster32P raster32 = ctrl1->getRaster(); TRaster64P raster64 = ctrl1->getRaster();
TPointD tmp(x, y); TPointD tmp(x, y);
tmp -= ctrl1->m_pos; tmp -= ctrl1->m_pos;
int radius = 4; int radius = 2;
gx = 0; gx = 0;
gy = 0; gy = 0;
//#define OLDSTUFF raster64->lock();
#ifdef OLDSTUFF if (raster64 && tmp.x >= radius && tmp.x < raster64->getLx() - radius &&
int i; tmp.y >= radius && tmp.y < raster64->getLy() - radius) {
#endif TPixel64 *pix = &(raster64->pixels(troundp(tmp.y))[(int)tmp.x]);
raster32->lock();
#ifdef OLDSTUFF gx += 2 * TPixelGR16::from(*(pix + 1)).value;
if (!values.gravity_radius_val) { gx += TPixelGR16::from(*(pix + 1 + raster64->getWrap() * 1)).value;
radius = 4; gx += TPixelGR16::from(*(pix + 1 - raster64->getWrap() * 1)).value;
if (raster32 && tmp.x >= radius && tmp.x < raster32->getLx() - radius &&
tmp.y >= radius && tmp.y < raster32->getLy() - radius) { gx -= 2 * TPixelGR16::from(*(pix - 1)).value;
TPixel32 *pix = &(raster32->pixels(troundp(tmp.y))[(int)tmp.x]); gx -= TPixelGR16::from(*(pix - 1 + raster64->getWrap() * 1)).value;
double norm = 1 / ((double)TPixelGR8::maxChannelValue); gx -= TPixelGR16::from(*(pix - 1 - raster64->getWrap() * 1)).value;
for (i = 1; i < radius; i++) {
gx += TPixelGR8::from(*(pix + i)).value; gy += 2 * TPixelGR16::from(*(pix + raster64->getWrap() * 1)).value;
gx -= TPixelGR8::from(*(pix - i)).value; gy += TPixelGR16::from(*(pix + raster64->getWrap() * 1 + 1)).value;
gy += TPixelGR8::from(*(pix + raster32->getWrap() * i)).value; gy += TPixelGR16::from(*(pix + raster64->getWrap() * 1 - 1)).value;
gy -= TPixelGR8::from(*(pix - raster32->getWrap() * i)).value;
} gy -= 2 * TPixelGR16::from(*(pix - raster64->getWrap() * 1)).value;
gx = gx * norm; gy -= TPixelGR16::from(*(pix - raster64->getWrap() * 1 + 1)).value;
gy = gy * norm; 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 raster64->unlock();
raster32->unlock();
} }
/*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/
@ -701,9 +677,10 @@ void Particle::move(std::map<int, TTile *> porttiles,
// time=genlifetime-lifetime-1; // time=genlifetime-lifetime-1;
// if(time<0) time=0; // if(time<0) time=0;
if (values.gravity_ctrl_val && if (values.gravity_ctrl_val &&
(porttiles.find(values.gravity_ctrl_val) != porttiles.end())) { (porttiles.find(values.gravity_ctrl_val + Ctrl_64_Offset) !=
get_image_gravity(porttiles[values.gravity_ctrl_val], values, xgravity, porttiles.end())) {
ygravity); get_image_gravity(porttiles[values.gravity_ctrl_val + Ctrl_64_Offset],
values, xgravity, ygravity);
xgravity *= values.gravity_val; xgravity *= values.gravity_val;
ygravity *= values.gravity_val; ygravity *= values.gravity_val;
} }

View file

@ -7,6 +7,8 @@
#include "tspectrum.h" #include "tspectrum.h"
#include "trandom.h" #include "trandom.h"
const int Ctrl_64_Offset = 1000;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
struct particles_values { struct particles_values {

View file

@ -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) { 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 || return values.fincol_ctrl_val == i || values.foutcol_ctrl_val == i ||
values.friction_ctrl_val == i || values.gencol_ctrl_val == i || values.friction_ctrl_val == i || values.gencol_ctrl_val == i ||
values.gravity_ctrl_val == i || values.opacity_ctrl_val == i || values.opacity_ctrl_val == i || values.rot_ctrl_val == i ||
values.rot_ctrl_val == i || values.scale_ctrl_val == i || values.scale_ctrl_val == i || values.scalestep_ctrl_val == i ||
values.scalestep_ctrl_val == i || values.source_ctrl_val == i || values.source_ctrl_val == i || values.speed_ctrl_val == i ||
values.speed_ctrl_val == i || values.speeda_ctrl_val == i || (values.speeda_ctrl_val == i && !values.speeda_use_gradient_val) ||
values.lifetime_ctrl_val == i || values.randomx_ctrl_val == i || values.lifetime_ctrl_val == i || values.randomx_ctrl_val == i ||
values.randomy_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フレームからカレントフレームまで順番に回す関数 --*/ /*-- Startフレームからカレントフレームまで順番に回す関数 --*/
void Particles_Engine::roll_particles( void Particles_Engine::roll_particles(
@ -255,7 +271,7 @@ void Particles_Engine::roll_particles(
{ {
/*- 新たに作るパーティクルの数だけ繰り返す -*/ /*- 新たに作るパーティクルの数だけ繰り返す -*/
for (i = 0; i < newparticles; i++) { for (i = 0; i < newparticles; i++) {
int seed = (int)((std::numeric_limits<int>::max)() * int seed = (int)((std::numeric_limits<int>::max)() *
values.random_val->getFloat()); values.random_val->getFloat());
int level = (int)(values.random_val->getFloat() * level_n); int level = (int)(values.random_val->getFloat() * level_n);
@ -291,7 +307,7 @@ void Particles_Engine::roll_particles(
switch (values.toplayer_val) { switch (values.toplayer_val) {
case ParticlesFx::TOP_YOUNGER: case ParticlesFx::TOP_YOUNGER:
for (i = 0; i < newparticles; i++) { for (i = 0; i < newparticles; i++) {
int seed = (int)((std::numeric_limits<int>::max)() * int seed = (int)((std::numeric_limits<int>::max)() *
values.random_val->getFloat()); values.random_val->getFloat());
int level = (int)(values.random_val->getFloat() * level_n); 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++) for (int j = 0; j < tmp; j++, it++)
; ;
{ {
int seed = (int)((std::numeric_limits<int>::max)() * int seed = (int)((std::numeric_limits<int>::max)() *
values.random_val->getFloat()); values.random_val->getFloat());
int level = (int)(values.random_val->getFloat() * level_n); int level = (int)(values.random_val->getFloat() * level_n);
int lifetime = 0; int lifetime = 0;
@ -344,7 +360,7 @@ void Particles_Engine::roll_particles(
default: default:
for (i = 0; i < newparticles; i++) { for (i = 0; i < newparticles; i++) {
int seed = (int)((std::numeric_limits<int>::max)() * int seed = (int)((std::numeric_limits<int>::max)() *
values.random_val->getFloat()); values.random_val->getFloat());
int level = (int)(values.random_val->getFloat() * level_n); int level = (int)(values.random_val->getFloat() * level_n);
int lifetime = 0; 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.first) = (values.speeda_val.first) * M_PI_180;
(values.speeda_val.second) = (values.speeda_val.second) * M_PI_180; (values.speeda_val.second) = (values.speeda_val.second) * M_PI_180;
if (values.step_val < 1) values.step_val = 1; if (values.step_val < 1) values.step_val = 1;
values.genfadecol_val = (values.genfadecol_val) * 0.01; values.genfadecol_val = (values.genfadecol_val) * 0.01;
values.finfadecol_val = (values.finfadecol_val) * 0.01; values.finfadecol_val = (values.finfadecol_val) * 0.01;
values.foutfadecol_val = (values.foutfadecol_val) * 0.01; values.foutfadecol_val = (values.foutfadecol_val) * 0.01;
} }
/*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/
@ -492,6 +508,9 @@ void Particles_Engine::render_particles(
TRenderSettings riAux(ri); TRenderSettings riAux(ri);
riAux.m_affine = TAffine(); riAux.m_affine = TAffine();
riAux.m_bpp = 32; 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 int r_frame; // Useful in case of negative roll frames
if (frame < 0) if (frame < 0)
@ -538,32 +557,74 @@ void Particles_Engine::render_particles(
// dryComputed - so, declare the same here. // dryComputed - so, declare the same here.
(*it->second)->dryCompute(bbox, r_frame, riAux); (*it->second)->dryCompute(bbox, r_frame, riAux);
} else { } else {
tmp = new TTile; // control image is used its gradient
if (port_is_used_for_gradient(it->first, values)) {
tmp = new TTile;
if (isPrecomputingEnabled) if (isPrecomputingEnabled)
(*it->second) (*it->second)
->allocateAndCompute(*tmp, bbox.getP00(), ->allocateAndCompute(*tmp, bbox.getP00(),
convert(bbox).getSize(), 0, r_frame, convert(bbox).getSize(), 0, r_frame,
riAux); riAux64);
else { else {
std::string alias = std::string alias =
"CTRL: " + (*(it->second))->getAlias(r_frame, riAux); "CTRL64: " + (*(it->second))->getAlias(r_frame, riAux64);
TRasterImageP rimg = TImageCache::instance()->get(alias, false); TRasterImageP rimg = TImageCache::instance()->get(alias, false);
if (rimg) { 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()));
}
}
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->m_pos = bbox.getP00();
tmp->setRaster(rimg->getRaster()); tmp->setRaster(tileRas);
} else { porttiles[it->first] = tmp;
}
}
// control images used only for non-gradient
else {
tmp = new TTile;
if (isPrecomputingEnabled)
(*it->second) (*it->second)
->allocateAndCompute(*tmp, bbox.getP00(), ->allocateAndCompute(*tmp, bbox.getP00(),
convert(bbox).getSize(), 0, r_frame, convert(bbox).getSize(), 0, r_frame,
riAux); riAux);
else {
std::string alias =
"CTRL: " + (*(it->second))->getAlias(r_frame, riAux);
TRasterImageP rimg = TImageCache::instance()->get(alias, false);
addRenderCache(alias, TRasterImageP(tmp->getRaster())); 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 &regioncount,
mask[1] = myarray[i - 1 + lx * (j - 1)]; mask[1] = myarray[i - 1 + lx * (j - 1)];
} }
if (i != lx - 1) mask[3] = 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]) { if (!mask[0] && !mask[1] && !mask[2] && !mask[3]) {
(regioncount)++; (regioncount)++;
myarray[i + lx * j] = (regioncount); myarray[i + lx * j] = (regioncount);
@ -883,7 +944,7 @@ void Particles_Engine::fill_array(TTile *ctrl1, int &regioncount,
void Particles_Engine::normalize_array( void Particles_Engine::normalize_array(
std::vector<std::vector<TPointD>> &myregions, TPointD pos, int lx, int ly, std::vector<std::vector<TPointD>> &myregions, TPointD pos, int lx, int ly,
int regioncounter, std::vector<int> &myarray, std::vector<int> &lista, int regioncounter, std::vector<int> &myarray, std::vector<int> &lista,
std::vector<int> &listb, std::vector<int> & final) { std::vector<int> &listb, std::vector<int> &final) {
int i, j, k, l; int i, j, k, l;
std::vector<int> tmp; std::vector<int> tmp;
@ -896,13 +957,13 @@ void Particles_Engine::normalize_array(
j = lista[l]; j = lista[l];
/*TMSG_INFO("j vale %d\n", j);*/ /*TMSG_INFO("j vale %d\n", j);*/
while (final[j] != j) j = final[j]; while (final[j] != j) j = final[j];
k = listb[l]; k = listb[l];
/*TMSG_INFO("k vale %d\n", k);*/ /*TMSG_INFO("k vale %d\n", k);*/
while (final[k] != k) k = final[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"); // 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]]; while (final[j] != final[final[j]]) final[j] = final[final[j]];
/*conto quante cavolo di regioni sono*/ /*conto quante cavolo di regioni sono*/

View file

@ -52,6 +52,8 @@ public:
std::map<std::pair<int, int>, double> &partScales); std::map<std::pair<int, int>, double> &partScales);
bool port_is_used(int i, struct particles_values &values); 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のとき do_source_gradationがONのとき
@ -81,7 +83,7 @@ public:
void normalize_array(std::vector<std::vector<TPointD>> &myregions, void normalize_array(std::vector<std::vector<TPointD>> &myregions,
TPointD pos, int lx, int ly, int regioncounter, TPointD pos, int lx, int ly, int regioncounter,
std::vector<int> &myarray, std::vector<int> &lista, std::vector<int> &myarray, std::vector<int> &lista,
std::vector<int> &listb, std::vector<int> & final); std::vector<int> &listb, std::vector<int> &final);
void fill_array(TTile *ctrl1, int &regioncount, std::vector<int> &myarray, void fill_array(TTile *ctrl1, int &regioncount, std::vector<int> &myarray,
std::vector<int> &lista, std::vector<int> &listb, int thres); std::vector<int> &lista, std::vector<int> &listb, int thres);