| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Particles_Engine::Particles_Engine(ParticlesFx *parent, double frame) |
| : m_parent(parent), m_frame(frame) {} |
| |
| static void printTime(TStopWatch &sw, std::string name) { |
| std::stringstream ss; |
| ss << name << " : "; |
| sw.print(ss); |
| ss << '\n' << '\0'; |
| TSystem::outputDebug(ss.str()); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void Particles_Engine::fill_value_struct(struct particles_values &myvalues, |
| double frame) { |
| myvalues.source_ctrl_val = m_parent->source_ctrl_val->getValue(); |
| myvalues.bright_thres_val = m_parent->bright_thres_val->getValue(); |
| myvalues.multi_source_val = m_parent->multi_source_val->getValue(); |
| myvalues.x_pos_val = m_parent->center_val->getValue(frame).x; |
| myvalues.y_pos_val = m_parent->center_val->getValue(frame).y; |
| |
| myvalues.length_val = m_parent->length_val->getValue(frame); |
| myvalues.height_val = m_parent->height_val->getValue(frame); |
| myvalues.maxnum_val = m_parent->maxnum_val->getValue(frame); |
| myvalues.lifetime_val = m_parent->lifetime_val->getValue(frame); |
| myvalues.lifetime_ctrl_val = m_parent->lifetime_ctrl_val->getValue(); |
| myvalues.column_lifetime_val = m_parent->column_lifetime_val->getValue(); |
| myvalues.startpos_val = m_parent->startpos_val->getValue(); |
| myvalues.randseed_val = m_parent->randseed_val->getValue(); |
| myvalues.gravity_val = m_parent->gravity_val->getValue(frame); |
| myvalues.g_angle_val = m_parent->g_angle_val->getValue(frame); |
| myvalues.gravity_ctrl_val = m_parent->gravity_ctrl_val->getValue(); |
| myvalues.friction_val = m_parent->friction_val->getValue(frame); |
| myvalues.friction_ctrl_val = m_parent->friction_ctrl_val->getValue(); |
| myvalues.windint_val = m_parent->windint_val->getValue(frame); |
| myvalues.windangle_val = m_parent->windangle_val->getValue(frame); |
| myvalues.swingmode_val = m_parent->swingmode_val->getValue(); |
| myvalues.randomx_val = m_parent->randomx_val->getValue(frame); |
| myvalues.randomy_val = m_parent->randomy_val->getValue(frame); |
| myvalues.randomx_ctrl_val = m_parent->randomx_ctrl_val->getValue(); |
| myvalues.randomy_ctrl_val = m_parent->randomy_ctrl_val->getValue(); |
| myvalues.swing_val = m_parent->swing_val->getValue(frame); |
| myvalues.speed_val = m_parent->speed_val->getValue(frame); |
| myvalues.speed_ctrl_val = m_parent->speed_ctrl_val->getValue(); |
| myvalues.speeda_val = m_parent->speeda_val->getValue(frame); |
| myvalues.speeda_ctrl_val = m_parent->speeda_ctrl_val->getValue(); |
| myvalues.speeda_use_gradient_val = |
| m_parent->speeda_use_gradient_val->getValue(); |
| myvalues.speedscale_val = m_parent->speedscale_val->getValue(); |
| myvalues.toplayer_val = m_parent->toplayer_val->getValue(); |
| myvalues.mass_val = m_parent->mass_val->getValue(frame); |
| myvalues.scale_val = m_parent->scale_val->getValue(frame); |
| myvalues.scale_ctrl_val = m_parent->scale_ctrl_val->getValue(); |
| myvalues.scale_ctrl_all_val = m_parent->scale_ctrl_all_val->getValue(); |
| myvalues.rot_val = m_parent->rot_val->getValue(frame); |
| myvalues.rot_ctrl_val = m_parent->rot_ctrl_val->getValue(); |
| myvalues.trail_val = m_parent->trail_val->getValue(frame); |
| myvalues.trailstep_val = m_parent->trailstep_val->getValue(frame); |
| myvalues.rotswingmode_val = m_parent->rotswingmode_val->getValue(); |
| myvalues.rotspeed_val = m_parent->rotspeed_val->getValue(frame); |
| myvalues.rotsca_val = m_parent->rotsca_val->getValue(frame); |
| myvalues.rotswing_val = m_parent->rotswing_val->getValue(frame); |
| myvalues.pathaim_val = m_parent->pathaim_val->getValue(); |
| myvalues.opacity_val = m_parent->opacity_val->getValue(frame); |
| myvalues.opacity_ctrl_val = m_parent->opacity_ctrl_val->getValue(); |
| myvalues.trailopacity_val = m_parent->trailopacity_val->getValue(frame); |
| |
| myvalues.scalestep_val = m_parent->scalestep_val->getValue(frame); |
| myvalues.scalestep_ctrl_val = m_parent->scalestep_ctrl_val->getValue(); |
| myvalues.fadein_val = m_parent->fadein_val->getValue(frame); |
| myvalues.fadeout_val = m_parent->fadeout_val->getValue(frame); |
| myvalues.animation_val = m_parent->animation_val->getValue(); |
| myvalues.step_val = m_parent->step_val->getValue(); |
| |
| myvalues.gencol_val = m_parent->gencol_val->getValue(frame); |
| myvalues.gencol_ctrl_val = m_parent->gencol_ctrl_val->getValue(); |
| myvalues.gencol_spread_val = m_parent->gencol_spread_val->getValue(frame); |
| myvalues.genfadecol_val = m_parent->genfadecol_val->getValue(frame); |
| myvalues.fincol_val = m_parent->fincol_val->getValue(frame); |
| myvalues.fincol_ctrl_val = m_parent->fincol_ctrl_val->getValue(); |
| myvalues.fincol_spread_val = m_parent->fincol_spread_val->getValue(frame); |
| myvalues.finrangecol_val = m_parent->finrangecol_val->getValue(frame); |
| myvalues.finfadecol_val = m_parent->finfadecol_val->getValue(frame); |
| myvalues.foutcol_val = m_parent->foutcol_val->getValue(frame); |
| myvalues.foutcol_ctrl_val = m_parent->foutcol_ctrl_val->getValue(); |
| myvalues.foutcol_spread_val = m_parent->foutcol_spread_val->getValue(frame); |
| myvalues.foutrangecol_val = m_parent->foutrangecol_val->getValue(frame); |
| myvalues.foutfadecol_val = m_parent->foutfadecol_val->getValue(frame); |
| |
| myvalues.source_gradation_val = m_parent->source_gradation_val->getValue(); |
| myvalues.pick_color_for_every_frame_val = |
| m_parent->pick_color_for_every_frame_val->getValue(); |
| myvalues.perspective_distribution_val = |
| m_parent->perspective_distribution_val->getValue(); |
| } |
| |
| |
| |
| void Particles_Engine::fill_range_struct(struct particles_values &values, |
| struct particles_ranges &ranges) { |
| ranges.swing_range = values.swing_val.second - values.swing_val.first; |
| ranges.rotswing_range = |
| values.rotswing_val.second - values.rotswing_val.first; |
| ranges.randomx_range = values.randomx_val.second - values.randomx_val.first; |
| ranges.randomy_range = values.randomy_val.second - values.randomy_val.first; |
| ranges.rotsca_range = values.rotsca_val.second - values.rotsca_val.first; |
| ranges.rot_range = values.rot_val.second - values.rot_val.first; |
| ranges.speed_range = values.speed_val.second - values.speed_val.first; |
| ranges.speeda_range = values.speeda_val.second - values.speeda_val.first; |
| ranges.mass_range = values.mass_val.second - values.mass_val.first; |
| ranges.scale_range = values.scale_val.second - values.scale_val.first; |
| ranges.lifetime_range = |
| values.lifetime_val.second - values.lifetime_val.first; |
| ranges.scalestep_range = |
| values.scalestep_val.second - values.scalestep_val.first; |
| ranges.trail_range = (int)(values.trail_val.second - values.trail_val.first); |
| } |
| |
| bool Particles_Engine::port_is_used(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.lifetime_ctrl_val == i || values.randomx_ctrl_val == i || |
| values.randomy_ctrl_val == i; |
| } |
| |
| |
| void Particles_Engine::roll_particles( |
| TTile *tile, std::map<int, TTile *> porttiles, const TRenderSettings &ri, |
| std::list<Particle> &myParticles, struct particles_values &values, float cx, |
| float cy, int frame, int curr_frame, int level_n, bool *random_level, |
| float dpi, std::vector<int> lastframe, int &totalparticles) { |
| particles_ranges ranges; |
| int i, newparticles; |
| float xgravity, ygravity, windx, windy; |
| |
| windx = values.windint_val * sin(values.windangle_val); |
| windy = values.windint_val * cos(values.windangle_val); |
| xgravity = values.gravity_val * sin(values.g_angle_val); |
| ygravity = values.gravity_val * cos(values.g_angle_val); |
| |
| fill_range_struct(values, ranges); |
| |
| std::vector<std::vector<TPointD>> myregions; |
| |
| |
| |
| |
| std::vector<std::vector<int>> myHistogram; |
| |
| |
| |
| std::vector<float> myWeight; |
| |
| std::map<int, TTile *>::iterator it = porttiles.find(values.source_ctrl_val); |
| |
| |
| |
| std::map<int, TTile *>::iterator sizeIt = |
| porttiles.find(values.scale_ctrl_val); |
| if (values.perspective_distribution_val && (sizeIt != porttiles.end())) { |
| |
| |
| if (values.source_ctrl_val && (it != porttiles.end())) |
| fill_regions_with_size_map(myregions, myHistogram, sizeIt->second, |
| it->second, values.bright_thres_val); |
| else |
| fill_regions_with_size_map(myregions, myHistogram, sizeIt->second, 0, |
| values.bright_thres_val); |
| |
| if ((int)myHistogram.size() == 256) { |
| for (int m = 255; m >= 0; m--) { |
| |
| float scale = |
| values.scale_val.first + ranges.scale_range * (float)m / 255.0f; |
| float weight = 1.0f / (scale * scale); |
| |
| float tmpSum = weight * (float)myHistogram[m].size(); |
| int index = 255 - m; |
| if (index > 0) |
| tmpSum += myWeight[index - 1]; |
| myWeight.push_back(tmpSum); |
| } |
| } |
| } else { |
| |
| if (values.source_ctrl_val && (it != porttiles.end())) |
| |
| fill_regions(1, myregions, it->second, values.multi_source_val, |
| values.bright_thres_val, values.source_gradation_val, |
| myHistogram); |
| |
| |
| |
| |
| if ((int)myHistogram.size() == 256) { |
| for (int m = 255; m > 0; m--) { |
| float tmpSum = (float)(m * (int)myHistogram[m].size()); |
| int index = 255 - m; |
| if (index > 0) tmpSum += myWeight[index - 1]; |
| myWeight.push_back(tmpSum); |
| } |
| } |
| } |
| |
| |
| newparticles = (int)values.maxnum_val; |
| if (myParticles.empty() && newparticles) |
| { |
| |
| for (i = 0; i < newparticles; i++) { |
| int seed = (int)((std::numeric_limits<int>::max)() * |
| values.random_val->getFloat()); |
| int level = (int)(values.random_val->getFloat() * level_n); |
| |
| int lifetime = 0; |
| if (values.column_lifetime_val) |
| lifetime = lastframe[level]; |
| else |
| lifetime = (int)(values.lifetime_val.first + |
| ranges.lifetime_range * values.random_val->getFloat()); |
| if (lifetime > curr_frame - frame) |
| myParticles.push_back(Particle( |
| lifetime, seed, porttiles, values, ranges, myregions, |
| totalparticles, 0, level, lastframe[level], myHistogram, myWeight)); |
| |
| totalparticles++; |
| } |
| } else { |
| std::list<Particle>::iterator it; |
| for (it = myParticles.begin(); it != myParticles.end();) { |
| std::list<Particle>::iterator current = it; |
| ++it; |
| |
| Particle &part = (*current); |
| if (part.lifetime <= 0) |
| |
| myParticles.erase(current); |
| else |
| part.move(porttiles, values, ranges, windx, windy, xgravity, ygravity, |
| dpi, lastframe[part.level]); |
| } |
| |
| int oldparticles = myParticles.size(); |
| switch (values.toplayer_val) { |
| case ParticlesFx::TOP_YOUNGER: |
| for (i = 0; i < newparticles; i++) { |
| int seed = (int)((std::numeric_limits<int>::max)() * |
| values.random_val->getFloat()); |
| int level = (int)(values.random_val->getFloat() * level_n); |
| |
| int lifetime = 0; |
| if (values.column_lifetime_val) |
| lifetime = lastframe[level]; |
| else |
| lifetime = |
| (int)(values.lifetime_val.first + |
| ranges.lifetime_range * values.random_val->getFloat()); |
| |
| if (lifetime > curr_frame - frame) |
| myParticles.push_front(Particle(lifetime, seed, porttiles, values, |
| ranges, myregions, totalparticles, 0, |
| level, lastframe[level], myHistogram, |
| myWeight)); |
| |
| totalparticles++; |
| } |
| break; |
| |
| case ParticlesFx::TOP_RANDOM: |
| for (i = 0; i < newparticles; i++) { |
| double tmp = values.random_val->getFloat() * myParticles.size(); |
| std::list<Particle>::iterator it = myParticles.begin(); |
| for (int j = 0; j < tmp; j++, it++) |
| ; |
| { |
| int seed = (int)((std::numeric_limits<int>::max)() * |
| values.random_val->getFloat()); |
| int level = (int)(values.random_val->getFloat() * level_n); |
| int lifetime = 0; |
| |
| if (values.column_lifetime_val) |
| lifetime = lastframe[level]; |
| else |
| lifetime = |
| (int)(values.lifetime_val.first + |
| ranges.lifetime_range * values.random_val->getFloat()); |
| if (lifetime > curr_frame - frame) |
| myParticles.insert( |
| it, Particle(lifetime, seed, porttiles, values, ranges, |
| myregions, totalparticles, 0, level, |
| lastframe[level], myHistogram, myWeight)); |
| |
| totalparticles++; |
| } |
| } |
| break; |
| |
| default: |
| for (i = 0; i < newparticles; i++) { |
| int seed = (int)((std::numeric_limits<int>::max)() * |
| values.random_val->getFloat()); |
| int level = (int)(values.random_val->getFloat() * level_n); |
| int lifetime = 0; |
| |
| if (values.column_lifetime_val) |
| lifetime = lastframe[level]; |
| else |
| lifetime = |
| (int)(values.lifetime_val.first + |
| ranges.lifetime_range * values.random_val->getFloat()); |
| if (lifetime > curr_frame - frame) |
| myParticles.push_back(Particle(lifetime, seed, porttiles, values, |
| ranges, myregions, totalparticles, 0, |
| level, lastframe[level], myHistogram, |
| myWeight)); |
| |
| totalparticles++; |
| } |
| break; |
| } |
| } |
| } |
| |
| |
| |
| void Particles_Engine::normalize_values(struct particles_values &values, |
| const TRenderSettings &ri) { |
| double dpicorr = 1; |
| TPointD pos(values.x_pos_val, values.y_pos_val); |
| |
| (values.x_pos_val) = pos.x; |
| (values.y_pos_val) = pos.y; |
| (values.length_val) = (values.length_val) * dpicorr; |
| (values.height_val) = (values.height_val) * dpicorr; |
| (values.gravity_val) = (values.gravity_val) * dpicorr * 0.1; |
| (values.windint_val) = (values.windint_val) * dpicorr; |
| (values.speed_val.first) = (values.speed_val.first) * dpicorr; |
| (values.speed_val.second) = (values.speed_val.second) * dpicorr; |
| (values.randomx_val.first) = (values.randomx_val.first) * dpicorr; |
| (values.randomx_val.second) = (values.randomx_val.second) * dpicorr; |
| (values.randomy_val.first) = (values.randomy_val.first) * dpicorr; |
| (values.randomy_val.second) = (values.randomy_val.second) * dpicorr; |
| (values.scale_val.first) = (values.scale_val.first) * 0.01; |
| (values.scale_val.second) = (values.scale_val.second) * 0.01; |
| (values.scalestep_val.first) = (values.scalestep_val.first) * 0.01; |
| (values.scalestep_val.second) = (values.scalestep_val.second) * 0.01; |
| (values.opacity_val.first) = (values.opacity_val.first) * 0.01; |
| (values.opacity_val.second) = (values.opacity_val.second) * 0.01; |
| (values.trailopacity_val.first) = (values.trailopacity_val.first) * 0.01; |
| (values.trailopacity_val.second) = (values.trailopacity_val.second) * 0.01; |
| (values.mblur_val) = (values.mblur_val) * 0.01; |
| (values.friction_val) = -(values.friction_val) * 0.01; |
| (values.windangle_val) = (values.windangle_val) * M_PI_180; |
| (values.g_angle_val) = (values.g_angle_val + 180) * 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; |
| 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; |
| } |
| |
| |
| |
| void Particles_Engine::render_particles( |
| TFlash *flash, TTile *tile, std::vector<TRasterFxPort *> part_ports, |
| const TRenderSettings &ri, TDimension &p_size, TPointD &p_offset, |
| std::map<int, TRasterFxPort *> ctrl_ports, std::vector<TLevelP> partLevel, |
| float dpi, int curr_frame, int shrink, double startx, double starty, |
| double endx, double endy, std::vector<int> last_frame, unsigned long fxId) { |
| int frame, startframe, intpart = 0, level_n = 0; |
| struct particles_values values; |
| double dpicorr = dpi * 0.01, fractpart = 0, dpicorr_shrinked = 0, |
| opacity_range = 0; |
| bool random_level = false; |
| level_n = part_ports.size(); |
| |
| bool isPrecomputingEnabled = false; |
| { |
| TRenderer renderer(TRenderer::instance()); |
| isPrecomputingEnabled = |
| (renderer && renderer.isPrecomputingEnabled()) ? true : false; |
| } |
| |
| memset(&values, 0, sizeof(values)); |
| |
| fill_value_struct(values, m_frame); |
| |
| opacity_range = (values.opacity_val.second - values.opacity_val.first) * 0.01; |
| |
| startframe = (int)values.startpos_val; |
| if (values.unit_val == ParticlesFx::UNIT_SMALL_INCH) |
| dpicorr_shrinked = dpicorr / shrink; |
| else |
| dpicorr_shrinked = dpi / shrink; |
| |
| std::map<std::pair<int, int>, double> partScales; |
| curr_frame = curr_frame / values.step_val; |
| |
| ParticlesManager *pc = ParticlesManager::instance(); |
| |
| |
| ParticlesManager::FrameData *particlesData = pc->data(fxId); |
| |
| std::list<Particle> myParticles; |
| TRandom myRandom; |
| values.random_val = &myRandom; |
| myRandom = m_parent->randseed_val->getValue(); |
| int totalparticles = 0; |
| |
| int pcFrame = particlesData->m_frame; |
| if (pcFrame > curr_frame) { |
| |
| particlesData->clear(); |
| pcFrame = particlesData->m_frame; |
| } else if (pcFrame >= startframe - 1) { |
| myParticles = particlesData->m_particles; |
| myRandom = particlesData->m_random; |
| totalparticles = particlesData->m_totalParticles; |
| } |
| |
| for (frame = startframe - 1; frame <= curr_frame; ++frame) { |
| int dist_frame = curr_frame - frame; |
| |
| |
| |
| fill_value_struct(values, frame < 0 ? 0 : frame * values.step_val); |
| |
| normalize_values(values, ri); |
| |
| intpart = (int)values.maxnum_val; |
| |
| |
| |
| fractpart = fractpart + values.maxnum_val - intpart; |
| if ((int)fractpart) { |
| values.maxnum_val += (int)fractpart; |
| fractpart = fractpart - (int)fractpart; |
| } |
| |
| std::map<int, TTile *> porttiles; |
| |
| |
| |
| TRenderSettings riAux(ri); |
| riAux.m_affine = TAffine(); |
| riAux.m_bpp = 32; |
| |
| int r_frame; |
| if (frame < 0) |
| r_frame = 0; |
| else |
| r_frame = frame; |
| |
| TRectD outTileBBox(tile->m_pos, TDimensionD(tile->getRaster()->getLx(), |
| tile->getRaster()->getLy())); |
| |
| for (std::map<int, TRasterFxPort *>::iterator it = ctrl_ports.begin(); |
| it != ctrl_ports.end(); ++it) { |
| TTile *tmp; |
| |
| if ((it->second)->isConnected() && port_is_used(it->first, values)) { |
| TRectD bbox; |
| (*(it->second))->getBBox(r_frame, bbox, riAux); |
| |
| if (!bbox.isEmpty()) { |
| if (bbox == TConsts::infiniteRectD) |
| |
| bbox = ri.m_affine.inv() * outTileBBox; |
| |
| if (frame <= pcFrame) { |
| |
| |
| (*it->second)->dryCompute(bbox, r_frame, riAux); |
| } else { |
| 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 (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; |
| } |
| } |
| } |
| } |
| |
| if (frame > pcFrame) { |
| |
| roll_particles(tile, porttiles, riAux, myParticles, values, 0, 0, frame, |
| curr_frame, level_n, &random_level, 1, last_frame, |
| totalparticles); |
| |
| |
| if (!particlesData->m_calculated || |
| particlesData->m_frame + particlesData->m_maxTrail < frame) { |
| particlesData->m_frame = frame; |
| particlesData->m_particles = myParticles; |
| particlesData->m_random = myRandom; |
| particlesData->buildMaxTrail(); |
| particlesData->m_calculated = true; |
| particlesData->m_totalParticles = totalparticles; |
| } |
| } |
| |
| |
| |
| if (frame >= startframe - 1 && |
| !(dist_frame % |
| (values.trailstep_val > 1.0 ? (int)values.trailstep_val : 1))) { |
| |
| std::list<Particle>::iterator pt; |
| for (pt = myParticles.begin(); pt != myParticles.end(); ++pt) { |
| Particle &part = *pt; |
| int ndx = part.frame % last_frame[part.level]; |
| std::pair<int, int> ndxPair(part.level, ndx); |
| |
| std::map<std::pair<int, int>, double>::iterator it = |
| partScales.find(ndxPair); |
| |
| if (it != partScales.end()) |
| it->second = std::max(part.scale, it->second); |
| else |
| partScales[ndxPair] = part.scale; |
| } |
| |
| if (values.toplayer_val == ParticlesFx::TOP_SMALLER || |
| values.toplayer_val == ParticlesFx::TOP_BIGGER) |
| myParticles.sort(ComparebySize()); |
| |
| if (values.toplayer_val == ParticlesFx::TOP_SMALLER) { |
| std::list<Particle>::iterator pt; |
| for (pt = myParticles.begin(); pt != myParticles.end(); ++pt) { |
| Particle &part = *pt; |
| if (dist_frame <= part.trail && part.scale && part.lifetime > 0 && |
| part.lifetime <= |
| part.genlifetime) |
| { |
| do_render(flash, &part, tile, part_ports, porttiles, ri, p_size, |
| p_offset, last_frame[part.level], partLevel, values, |
| opacity_range, dist_frame, partScales); |
| } |
| } |
| } else { |
| std::list<Particle>::reverse_iterator pt; |
| for (pt = myParticles.rbegin(); pt != myParticles.rend(); ++pt) { |
| Particle &part = *pt; |
| if (dist_frame <= part.trail && part.scale && part.lifetime > 0 && |
| part.lifetime <= part.genlifetime) |
| { |
| do_render(flash, &part, tile, part_ports, porttiles, ri, p_size, |
| p_offset, last_frame[part.level], partLevel, values, |
| opacity_range, dist_frame, partScales); |
| } |
| } |
| } |
| } |
| |
| std::map<int, TTile *>::iterator it; |
| for (it = porttiles.begin(); it != porttiles.end(); ++it) delete it->second; |
| } |
| } |
| |
| |
| |
| void Particles_Engine::do_render( |
| TFlash *flash, Particle *part, TTile *tile, |
| std::vector<TRasterFxPort *> part_ports, std::map<int, TTile *> porttiles, |
| const TRenderSettings &ri, TDimension &p_size, TPointD &p_offset, |
| int lastframe, std::vector<TLevelP> partLevel, |
| struct particles_values &values, double opacity_range, int dist_frame, |
| std::map<std::pair<int, int>, double> &partScales) { |
| |
| |
| |
| int ndx = part->frame % lastframe; |
| |
| TRasterP tileRas(tile->getRaster()); |
| |
| std::string levelid; |
| double aim_angle = 0; |
| if (values.pathaim_val) { |
| double arctan = atan2(part->vy, part->vx); |
| aim_angle = arctan * M_180_PI; |
| } |
| |
| |
| |
| TRotation rotM(part->angle + aim_angle); |
| TScale scaleM(part->scale); |
| TAffine M(rotM * scaleM); |
| |
| |
| TAffine scaleAff(m_parent->handledAffine(ri, m_frame)); |
| double partScale = |
| scaleAff.a11 * partScales[std::pair<int, int>(part->level, ndx)]; |
| TDimensionD partResolution(0, 0); |
| TRenderSettings riNew(ri); |
| |
| |
| TRectD bbox(-5.0, -5.0, 5.0, 5.0), standardRefBBox; |
| if (part->level < |
| (int)part_ports.size() && |
| part_ports[part->level]->isConnected()) { |
| TRenderSettings riIdentity(ri); |
| riIdentity.m_affine = TAffine(); |
| |
| (*part_ports[part->level])->getBBox(ndx, bbox, riIdentity); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if (bbox.isEmpty() || bbox == TConsts::infiniteRectD) return; |
| } |
| |
| |
| bbox = bbox.enlarge(3); |
| standardRefBBox = bbox; |
| riNew.m_affine = TScale(partScale); |
| bbox = riNew.m_affine * bbox; |
| |
| partResolution = TDimensionD(tceil(bbox.getLx()), tceil(bbox.getLy())); |
| |
| if (flash) { |
| if (!partLevel[part->level]->frame(ndx)) { |
| if (part_ports[0]->isConnected()) { |
| TTile auxTile; |
| TRaster32P tmp; |
| tmp = TRaster32P(p_size); |
| (*part_ports[0]) |
| ->allocateAndCompute(auxTile, p_offset, p_size, tmp, ndx, ri); |
| partLevel[part->level]->setFrame(ndx, |
| TRasterImageP(auxTile.getRaster())); |
| } |
| } |
| |
| flash->pushMatrix(); |
| |
| const TAffine aff; |
| |
| flash->multMatrix(scaleM * aff.place(0, 0, part->x, part->y)); |
| |
| |
| |
| { |
| TColorFader cf(TPixel32::Red, .5); |
| flash->draw(partLevel[part->level]->frame(ndx), &cf); |
| } |
| |
| |
| flash->popMatrix(); |
| } else { |
| TRasterP ras; |
| |
| std::string alias; |
| TRasterImageP rimg; |
| if (rimg = partLevel[part->level]->frame(ndx)) { |
| ras = rimg->getRaster(); |
| } else { |
| alias = "PART: " + (*part_ports[part->level])->getAlias(ndx, riNew); |
| if (rimg = TImageCache::instance()->get(alias, false)) { |
| ras = rimg->getRaster(); |
| |
| |
| if (ras->getLx() < partResolution.lx || |
| ras->getLy() < partResolution.ly) |
| ras = 0; |
| else |
| partResolution = TDimensionD(ras->getLx(), ras->getLy()); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| partScale = partResolution.lx / standardRefBBox.getLx(); |
| riNew.m_affine = TScale(partScale); |
| bbox = riNew.m_affine * standardRefBBox; |
| |
| |
| |
| if (!ras) { |
| TTile auxTile; |
| (*part_ports[part->level]) |
| ->allocateAndCompute(auxTile, bbox.getP00(), |
| TDimension(partResolution.lx, partResolution.ly), |
| tile->getRaster(), ndx, riNew); |
| ras = auxTile.getRaster(); |
| |
| |
| TRaster32P rcachepart; |
| rcachepart = ras; |
| if (!rcachepart) { |
| rcachepart = TRaster32P(ras->getSize()); |
| TRop::convert(rcachepart, ras); |
| } |
| ras = rcachepart; |
| |
| |
| addRenderCache(alias, TRasterImageP(ras)); |
| } |
| |
| if (!ras) return; |
| |
| |
| TRaster32P rfinalpart; |
| double curr_opacity = |
| part->set_Opacity(porttiles, values, opacity_range, dist_frame); |
| if (curr_opacity != 1.0 || part->gencol.fadecol || part->fincol.fadecol || |
| part->foutcol.fadecol) { |
| |
| if (values.pick_color_for_every_frame_val && values.gencol_ctrl_val && |
| (porttiles.find(values.gencol_ctrl_val) != porttiles.end())) |
| part->get_image_reference(porttiles[values.gencol_ctrl_val], values, |
| part->gencol.col); |
| |
| rfinalpart = ras->clone(); |
| part->modify_colors_and_opacity(values, curr_opacity, dist_frame, |
| rfinalpart); |
| } else |
| rfinalpart = ras; |
| |
| |
| |
| |
| |
| |
| |
| M = ri.m_affine * M * TScale(1.0 / partScale); |
| |
| |
| TPointD pos(part->x, part->y); |
| pos = ri.m_affine * pos; |
| |
| |
| |
| |
| M = TTranslation(pos - tile->m_pos) * M * TTranslation(bbox.getP00()); |
| |
| if (TRaster32P myras32 = tile->getRaster()) |
| TRop::over(tileRas, rfinalpart, M); |
| else if (TRaster64P myras64 = tile->getRaster()) |
| TRop::over(tileRas, rfinalpart, M); |
| else |
| throw TException("ParticlesFx: unsupported Pixel Type"); |
| } |
| } |
| |
| |
| |
| void Particles_Engine::fill_array(TTile *ctrl1, int ®ioncount, |
| std::vector<int> &myarray, |
| std::vector<int> &lista, |
| std::vector<int> &listb, int threshold) { |
| int pr = 0; |
| int i, j; |
| int lx, ly; |
| lx = ctrl1->getRaster()->getLx(); |
| ly = ctrl1->getRaster()->getLy(); |
| |
| |
| TRaster32P raster32 = ctrl1->getRaster(); |
| raster32->lock(); |
| TPixel32 *pix = raster32->pixels(0); |
| for (i = 0; i < lx; i++) { |
| if (pix->m > threshold) { |
| pr++; |
| if (!i) { |
| (regioncount)++; |
| myarray[i] = (regioncount); |
| } else { |
| if (myarray[i - 1]) myarray[i] = myarray[i - 1]; |
| } |
| } |
| *pix++; |
| } |
| |
| for (j = 1; j < ly; j++) { |
| for (i = 0, pix = raster32->pixels(j); i < lx; i++, pix++) { |
| |
| if (pix->m > threshold) { |
| std::vector<int> mask(4); |
| pr++; |
| |
| if (i) { |
| mask[0] = myarray[i - 1 + lx * j]; |
| 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)]; |
| if (!mask[0] && !mask[1] && !mask[2] && !mask[3]) { |
| (regioncount)++; |
| myarray[i + lx * j] = (regioncount); |
| } else { |
| int mc, firsttime = 1; |
| for (mc = 0; mc < 4; mc++) { |
| if (mask[mc]) { |
| if (firsttime) { |
| myarray[i + lx * j] = mask[mc]; |
| firsttime = 0; |
| } else { |
| if (myarray[i + lx * j] != mask[mc]) { |
| lista.push_back(myarray[i + lx * j]); |
| listb.push_back(mask[mc]); |
| |
| |
| |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| raster32->unlock(); |
| } |
| |
| |
| |
| void Particles_Engine::normalize_array( |
| std::vector<std::vector<TPointD>> &myregions, TPointD pos, int lx, int ly, |
| int regioncounter, std::vector<int> &myarray, std::vector<int> &lista, |
| std::vector<int> &listb, std::vector<int> &final) { |
| int i, j, k, l; |
| |
| std::vector<int> tmp; |
| int maxregioncounter = 0; |
| int listsize = (int)lista.size(); |
| |
| for (k = 1; k <= regioncounter; k++) final[k] = k; |
| |
| for (l = 0; l < listsize; l++) { |
| j = lista[l]; |
| |
| while (final[j] != j) j = final[j]; |
| k = listb[l]; |
| |
| while (final[k] != k) k = final[k]; |
| if (j != k) final[j] = k; |
| } |
| |
| for (j = 1; j <= regioncounter; j++) |
| while (final[j] != final[final[j]]) final[j] = final[final[j]]; |
| |
| |
| |
| tmp.push_back(final[1]); |
| maxregioncounter = 1; |
| for (i = 2; i <= regioncounter; i++) { |
| int diff = 1; |
| for (j = 0; j < maxregioncounter; j++) { |
| if (tmp[j] == final[i]) { |
| diff = 0; |
| break; |
| } |
| } |
| if (diff) { |
| tmp.push_back(final[i]); |
| maxregioncounter++; |
| } |
| } |
| |
| myregions.resize(maxregioncounter); |
| for (j = 0; j < ly; j++) { |
| for (i = 0; i < lx; i++) { |
| int tmpindex; |
| if (myarray[i + lx * j]) { |
| tmpindex = final[myarray[i + lx * j]]; |
| |
| for (k = 0; k < maxregioncounter; k++) { |
| if (tmp[k] == tmpindex) break; |
| } |
| |
| TPointD tmppoint; |
| tmppoint.x = i; |
| tmppoint.y = j; |
| tmppoint += pos; |
| myregions[k].push_back(tmppoint); |
| } |
| } |
| } |
| } |
| |
| |
| |
| void Particles_Engine::fill_subregions( |
| int cont_index, std::vector<std::vector<TPointD>> &myregions, TTile *ctrl1, |
| int thres) { |
| int regioncounter = 0; |
| |
| int lx = ctrl1->getRaster()->getLx(); |
| int ly = ctrl1->getRaster()->getLy(); |
| |
| std::vector<int> myarray(lx * ly); |
| std::vector<int> lista; |
| std::vector<int> listb; |
| |
| fill_array(ctrl1, regioncounter, myarray, lista, listb, thres); |
| |
| if (regioncounter) { |
| std::vector<int> final(regioncounter + 1); |
| normalize_array(myregions, ctrl1->m_pos, lx, ly, regioncounter, myarray, |
| lista, listb, final); |
| } |
| } |
| |
| |
| |
| |
| void Particles_Engine::fill_single_region( |
| std::vector<std::vector<TPointD>> &myregions, TTile *ctrl1, int threshold, |
| bool do_source_gradation, std::vector<std::vector<int>> &myHistogram) { |
| TRaster32P raster32 = ctrl1->getRaster(); |
| assert(raster32); |
| |
| |
| int j; |
| myregions.resize(1); |
| myregions[0].clear(); |
| int cc = 0; |
| int icc = 0; |
| raster32->lock(); |
| |
| if (!do_source_gradation) |
| { |
| for (j = 0; j < raster32->getLy(); j++) { |
| TPixel32 *pix = raster32->pixels(j); |
| TPixel32 *endPix = pix + raster32->getLx(); |
| int i = 0; |
| while (pix < endPix) { |
| cc++; |
| if (pix->m > threshold) { |
| icc++; |
| TPointD tmp; |
| tmp.y = j; |
| tmp.x = i; |
| tmp += ctrl1->m_pos; |
| myregions[0].push_back(tmp); |
| |
| |
| } else { |
| |
| } |
| i++; |
| *pix++; |
| } |
| } |
| } else { |
| for (int i = 0; i < 256; i++) myHistogram.push_back(std::vector<int>()); |
| |
| TRandom rand = TRandom(1); |
| for (j = 0; j < raster32->getLy(); j++) { |
| TPixel32 *pix = raster32->pixels(j); |
| TPixel32 *endPix = pix + raster32->getLx(); |
| int i = 0; |
| while (pix < endPix) { |
| cc++; |
| |
| |
| |
| if (pix->m > 0) { |
| icc++; |
| TPointD tmp; |
| tmp.y = j; |
| tmp.x = i; |
| tmp += ctrl1->m_pos; |
| |
| |
| myHistogram[(int)pix->m].push_back((int)myregions[0].size()); |
| |
| myregions[0].push_back(tmp); |
| } else { |
| } |
| i++; |
| *pix++; |
| } |
| } |
| } |
| if (myregions[0].size() == 0) myregions.resize(0); |
| raster32->unlock(); |
| } |
| |
| |
| |
| |
| |
| void Particles_Engine::fill_regions( |
| int frame, std::vector<std::vector<TPointD>> &myregions, TTile *ctrl1, |
| bool multi, int thres, bool do_source_gradation, |
| std::vector<std::vector<int>> &myHistogram) { |
| TRaster32P ctrl1ras = ctrl1->getRaster(); |
| if (!ctrl1ras) return; |
| int i; |
| if (frame <= 0) |
| i = 0; |
| else |
| i = frame; |
| |
| if (multi) { |
| fill_subregions(i, myregions, ctrl1, thres); |
| } else { |
| fill_single_region(myregions, ctrl1, thres, do_source_gradation, |
| myHistogram); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| void Particles_Engine::fill_regions_with_size_map( |
| std::vector<std::vector<TPointD>> &myregions, |
| std::vector<std::vector<int>> &myHistogram, TTile *sizeTile, |
| TTile *sourceTile, int thres) { |
| TRaster32P sizeRas = sizeTile->getRaster(); |
| if (!sizeRas) return; |
| |
| TRaster32P sourceRas; |
| if (sourceTile) sourceRas = sourceTile->getRaster(); |
| |
| sizeRas->lock(); |
| if (sourceRas) sourceRas->lock(); |
| |
| myregions.resize(1); |
| myregions[0].clear(); |
| for (int i = 0; i < 256; i++) myHistogram.push_back(std::vector<int>()); |
| |
| for (int j = 0; j < sizeRas->getLy(); j++) { |
| TPixel32 *pix = sizeRas->pixels(j); |
| TPixel32 *endPix = pix + sizeRas->getLx(); |
| |
| TPixel32 *sourcePixHead = 0; |
| if (sourceRas) { |
| int sourceYPos = troundp(j + sizeTile->m_pos.y - sourceTile->m_pos.y); |
| if (sourceYPos >= 0 && sourceYPos < sourceRas->getLy()) |
| sourcePixHead = sourceRas->pixels(sourceYPos); |
| } |
| |
| int i = 0; |
| TPixel32 *sourcePix = 0; |
| while (pix < endPix) { |
| if (sourceRas) { |
| int sourceXPos = (int)(i + sizeTile->m_pos.x - sourceTile->m_pos.x); |
| if (sourcePixHead && sourceXPos >= 0 && sourceXPos < sourceRas->getLx()) |
| sourcePix = sourcePixHead + sourceXPos; |
| else |
| sourcePix = 0; |
| } else |
| sourcePix = 0; |
| |
| |
| |
| |
| if (sourceRas && (!sourcePix || sourcePix->m <= thres)) { |
| } |
| |
| |
| else { |
| TPointD tmp; |
| tmp.y = j; |
| tmp.x = i; |
| tmp += sizeTile->m_pos; |
| |
| int val = (int)TPixelGR8::from(*pix).value; |
| |
| |
| myHistogram[val].push_back((int)myregions[0].size()); |
| |
| |
| myregions[0].push_back(tmp); |
| } |
| |
| i++; |
| pix++; |
| } |
| } |
| |
| if (myregions[0].size() == 0) myregions.resize(0); |
| |
| sizeRas->unlock(); |
| if (sourceRas) sourceRas->unlock(); |
| } |
| |