void MusicEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { Render(buffer, SettingsMap.GetInt("TEXTCTRL_Music_Bars", 6), SettingsMap.Get("CHOICE_Music_Type", "Collide"), SettingsMap.GetInt("TEXTCTRL_Music_Sensitivity", 50), SettingsMap.GetBool("CHECKBOX_Music_Scale", false), std::string(SettingsMap.Get("CHOICE_Music_Scaling", "All Notes")), SettingsMap.GetInt("TEXTCTRL_Music_Offset", 0), SettingsMap.GetInt("TEXTCTRL_Music_StartNote", 0), SettingsMap.GetInt("TEXTCTRL_Music_EndNote", 127), SettingsMap.Get("CHOICE_Music_Colour", "Distinct"), SettingsMap.GetBool("CHECKBOX_Music_Fade", false) ); }
void VideoEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { Render(buffer, SettingsMap["FILEPICKERCTRL_Video_Filename"], SettingsMap.GetDouble("TEXTCTRL_Video_Starttime", 0.0), SettingsMap.GetBool("CHECKBOX_Video_AspectRatio", false), SettingsMap.Get("CHOICE_Video_DurationTreatment", "Normal") ); }
void StateEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { RenderState(buffer, effect->GetParentEffectLayer()->GetParentElement()->GetSequenceElements(), SettingsMap.Get("CHOICE_State_StateDefinition", ""), SettingsMap["CHOICE_State_State"], SettingsMap["CHOICE_State_TimingTrack"], SettingsMap["CHOICE_State_Mode"], SettingsMap["CHOICE_State_Color"] ); }
void PixelBufferClass::SetLayerSettings(int layer, const SettingsMap &settingsMap) { LayerInfo *inf = layers[layer]; inf->persistent = settingsMap.GetBool(CHECKBOX_OverlayBkg); inf->mask.clear(); inf->fadeInSteps = (int)(settingsMap.GetDouble(TEXTCTRL_Fadein, 0.0)*1000)/frameTimeInMs; inf->fadeOutSteps = (int)(settingsMap.GetDouble(TEXTCTRL_Fadeout, 0.0)*1000)/frameTimeInMs; inf->inTransitionType = settingsMap.Get(CHOICE_In_Transition_Type, STR_FADE); inf->outTransitionType = settingsMap.Get(CHOICE_Out_Transition_Type, STR_FADE); inf->inTransitionAdjust = settingsMap.GetInt(SLIDER_In_Transition_Adjust, 0); inf->outTransitionAdjust = settingsMap.GetInt(SLIDER_Out_Transition_Adjust, 0); inf->inTransitionReverse = settingsMap.GetBool(CHECKBOX_In_Transition_Reverse); inf->outTransitionReverse = settingsMap.GetBool(CHECKBOX_Out_Transition_Reverse); inf->blur = settingsMap.GetInt(SLIDER_EffectBlur, 1); inf->sparkle_count = settingsMap.GetInt(SLIDER_SparkleFrequency, 0); inf->RotoZoom = settingsMap.GetInt(CHECKBOX_RotoZoom, 0) ; inf->ZoomCycles = settingsMap.GetInt(SLIDER_ZoomCycles, 1); inf->ZoomRotation = settingsMap.GetInt(SLIDER_ZoomRotation, 0); inf->ZoomInOut = settingsMap.GetInt(SLIDER_ZoomInOut, 0); inf->brightness = settingsMap.GetInt(SLIDER_Brightness, 100); inf->contrast=settingsMap.GetInt(SLIDER_Contrast, 0); SetMixType(layer, settingsMap.Get(CHOICE_LayerMethod, STR_NORMAL)); inf->effectMixThreshold = (float)settingsMap.GetInt(SLIDER_EffectLayerMix, 0)/100.0; inf->effectMixVaries = settingsMap.GetBool(CHECKBOX_LayerMorph); const std::string &type = settingsMap.Get(CHOICE_BufferStyle, STR_DEFAULT); const std::string &transform = settingsMap.Get(CHOICE_BufferTransform, STR_NONE); if (inf->bufferType != type || inf->bufferTransform != transform) { inf->Nodes.clear(); model->InitRenderBufferNodes(type, transform, inf->Nodes, inf->BufferWi, inf->BufferHt); inf->bufferType = type; inf->bufferTransform = transform; inf->buffer.InitBuffer(inf->BufferHt, inf->BufferWi); } }
std::list<std::string> StateEffect::CheckEffectSettings(const SettingsMap& settings, AudioManager* media, Model* model, Effect* eff) { std::list<std::string> res; // -Buffer not rotated wxString bufferTransform = settings.Get("B_CHOICE_BufferTransform", "None"); if (bufferTransform != "None") { res.push_back(wxString::Format(" WARN: State effect with transformed buffer '%s' may not render correctly. Model '%s', Start %s", model->GetName(), bufferTransform, FORMATTIME(eff->GetStartTimeMS())).ToStdString()); } wxString timing = settings.Get("E_CHOICE_State_TimingTrack", ""); wxString state = settings.Get("E_CHOICE_State_State", ""); // - Face chosen or specific phoneme if (state == "" && timing == "") { res.push_back(wxString::Format(" ERR: State effect with no timing selected. Model '%s', Start %s", model->GetName(), FORMATTIME(eff->GetStartTimeMS())).ToStdString()); } return res; }
double RenderableEffect::GetValueCurveDouble(wxString name, double def, const SettingsMap &SettingsMap, float offset) { double res = SettingsMap.GetDouble("TEXTCTRL_" + name, def); wxString vc = SettingsMap.Get("VALUECURVE_" + name, ""); if (vc != "") { ValueCurve valc(vc.ToStdString()); if (valc.IsActive()) { res = valc.GetOutputValueAt(offset); } } return res; }
int RenderableEffect::GetValueCurveInt(wxString name, int def, const SettingsMap &SettingsMap, float offset) { int res = def; if (SettingsMap.Contains("SLIDER_" + name)) { res = SettingsMap.GetInt("SLIDER_" + name, def); } else if (SettingsMap.Contains("TEXTCTRL_" + name)) { res = SettingsMap.GetInt("TEXTCTRL_" + name, def); } if (SettingsMap.Contains("VALUECURVE_" + name)) { wxString vc = SettingsMap.Get("VALUECURVE_" + name, ""); ValueCurve valc(vc.ToStdString()); if (valc.IsActive()) { res = valc.GetOutputValueAt(offset); } } return res; }
std::list<std::string> MorphEffect::CheckEffectSettings(const SettingsMap& settings, AudioManager* media, Model* model, Effect* eff) { std::list<std::string> res; if (settings.Get("E_VALUECURVE_Morph_Start_X1", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_Morph_Start_X2", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_Morph_Start_Y1", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_Morph_Start_Y2", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_Morph_End_X1", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_Morph_End_X2", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_Morph_End_Y1", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_Morph_End_Y2", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_MorphRepeat_Count", "").find("Active=TRUE") != std::string::npos || settings.Get("E_VALUECURVE_MorphRepeat_Skip", "").find("Active=TRUE") != std::string::npos ) { // we cant validate a value curve } else { int startx = std::max(1,std::abs(settings.GetInt("E_SLIDER_Morph_Start_X1", 0) - settings.GetInt("E_SLIDER_Morph_Start_X2", 0)) * model->GetDefaultBufferWi() / 80); int endx = std::max(1, std::abs(settings.GetInt("E_SLIDER_Morph_End_X1", 0) - settings.GetInt("E_SLIDER_Morph_End_X2", 0)) * model->GetDefaultBufferWi() / 80); int starty = std::max(1, std::abs(settings.GetInt("E_SLIDER_Morph_Start_Y1", 0) - settings.GetInt("E_SLIDER_Morph_Start_Y2", 0)) * model->GetDefaultBufferWi() / 80); int endy = std::max(1, std::abs(settings.GetInt("E_SLIDER_Morph_End_Y1", 0) - settings.GetInt("E_SLIDER_Morph_End_Y2", 0)) * model->GetDefaultBufferWi() / 80); int minmorph = std::min(startx, std::min(starty, std::min(endx, endy))); int repeat_count = settings.GetInt("E_SLIDER_Morph_Repeat_Count", 0); int repeat_skip = settings.GetInt("E_SLIDER_Morph_Repeat_Skip", 0); int maxmodel = std::max(model->GetDefaultBufferWi(), model->GetDefaultBufferHt()); if ((minmorph + repeat_skip) * repeat_count > 2 * maxmodel) { res.push_back(wxString::Format(" WARN: Morph effect with repeat count and skip which are larger than necessary. This may lead to slow render times. Model '%s', Start %s", model->GetName(), FORMATTIME(eff->GetStartTimeMS())).ToStdString()); } } return res; }
void GarlandsEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int GarlandType = SettingsMap.GetInt("SLIDER_Garlands_Type", 0); int Spacing = SettingsMap.GetInt("SLIDER_Garlands_Spacing", 0); float cycles = SettingsMap.GetDouble("TEXTCTRL_Garlands_Cycles", 1.0); if (Spacing < 1) { Spacing = 1; } int x,y,yadj,ylimit,ring; double ratio; xlColor color; int dir = GetDirection(SettingsMap.Get("CHOICE_Garlands_Direction", "Up")); double position = buffer.GetEffectTimeIntervalPosition(cycles); if (dir > 3) { dir -= 4; if (position > 0.5) { position = (1.0 - position) * 2.0; } else { position *= 2.0; } } int buffMax = buffer.BufferHt; int garlandWid = buffer.BufferWi; if (dir > 1) { buffMax = buffer.BufferWi; garlandWid = buffer.BufferHt; } double PixelSpacing=Spacing*buffMax/100.0; if (PixelSpacing < 2.0) PixelSpacing=2.0; double total = buffMax * PixelSpacing - buffMax + 1; double positionOffset = total * position; for (ring = 0; ring < buffMax; ring++) { ratio=double(buffMax-ring-1)/double(buffMax); buffer.GetMultiColorBlend(ratio, false, color); y = 1.0 + ring*PixelSpacing - positionOffset; ylimit=ring; for (x=0; x<garlandWid; x++) { yadj=y; switch (GarlandType) { case 1: switch (x%5) { case 2: yadj-=2; break; case 1: case 3: yadj-=1; break; } break; case 2: switch (x%5) { case 2: yadj-=4; break; case 1: case 3: yadj-=2; break; } break; case 3: switch (x%6) { case 3: yadj-=6; break; case 2: case 4: yadj-=4; break; case 1: case 5: yadj-=2; break; } break; case 4: switch (x%5) { case 1: case 3: yadj-=2; break; } break; } if (yadj < ylimit) yadj=ylimit; if (yadj < buffMax) { if (dir == 1 || dir == 2) { yadj = buffMax - yadj - 1; } if (dir > 1) { buffer.SetPixel(yadj,x,color); } else { buffer.SetPixel(x,yadj,color); } } } } }
void RenderableEffect::AdjustSettingsToBeFitToTime(int effectIdx, SettingsMap &settings, int startMS, int endMS, xlColorVector &colors) { if (effectIdx == EffectManager::eff_FACES && settings.Get("E_CHOICE_Faces_FaceDefinition", "") == "" && settings.Get("E_CHOICE_Faces_TimingTrack", "") == "") { settings["E_CHOICE_Faces_FaceDefinition"] = "xlights_papagayo.xml"; } int ftt = wxAtoi(settings.Get("T_CHECKBOX_FitToTime", "1")); switch (effectIdx) { //these effects have never used the FitToTime or speed settings, nothing to do case EffectManager::eff_OFF: case EffectManager::eff_GALAXY: case EffectManager::eff_FAN: case EffectManager::eff_MARQUEE: case EffectManager::eff_MORPH: case EffectManager::eff_SHOCKWAVE: case EffectManager::eff_GLEDIATOR: case EffectManager::eff_FACES: break; case EffectManager::eff_STROBE: case EffectManager::eff_TWINKLE: break; //these effects have been updated to have a dedicated repeat or speed or other control //and now ignore the FitToTime and Speed sliders, but the settings need adjusting case EffectManager::eff_ON: if (settings.Get("E_TEXTCTRL_On_Cycles", "") == "") { float cycles = 1.0; if (!ftt) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; cycles = maxState / 200; } settings["E_TEXTCTRL_On_Cycles"] = wxString::Format("%0.2f", cycles); } break; case EffectManager::eff_SNOWSTORM: if (settings.Get("E_SLIDER_Snowstorm_Speed", "") == "") { settings["E_SLIDER_Snowstorm_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_SNOWFLAKES: if (settings.Get("E_SLIDER_Snowflakes_Speed", "") == "") { settings["E_SLIDER_Snowflakes_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_BUTTERFLY: if (settings.Get("E_SLIDER_Butterfly_Speed", "") == "") { settings["E_SLIDER_Butterfly_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_CIRCLES: if (settings.Get("E_SLIDER_Circles_Speed", "") == "") { settings["E_SLIDER_Circles_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_LIFE: if (settings.Get("E_SLIDER_Life_Speed", "") == "") { settings["E_SLIDER_Life_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_METEORS: if (settings.Get("E_SLIDER_Meteors_Speed", "") == "") { settings["E_SLIDER_Meteors_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_TREE: if (settings.Get("E_SLIDER_Tree_Speed", "") == "") { settings["E_SLIDER_Tree_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_PINWHEEL: if (settings.Get("E_TEXTCTRL_Pinwheel_Speed", "") == "") { settings["E_TEXTCTRL_Pinwheel_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_PLASMA: if (settings.Get("E_TEXTCTRL_Plasma_Speed", "") == "") { settings["E_TEXTCTRL_Plasma_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_TEXT: if (settings.Get("E_TEXTCTRL_Text_Speed1", "") == "") { settings["E_TEXTCTRL_Text_Speed1"] = settings.Get("T_SLIDER_Speed", "10"); } if (settings.Get("E_TEXTCTRL_Text_Speed2", "") == "") { settings["E_TEXTCTRL_Text_Speed2"] = settings.Get("T_SLIDER_Speed", "10"); } if (settings.Get("E_TEXTCTRL_Text_Speed3", "") == "") { settings["E_TEXTCTRL_Text_Speed3"] = settings.Get("T_SLIDER_Speed", "10"); } if (settings.Get("E_TEXTCTRL_Text_Speed4", "") == "") { settings["E_TEXTCTRL_Text_Speed4"] = settings.Get("T_SLIDER_Speed", "10"); } if (settings.Get("E_SLIDER_Text_Position1", "") != "") { int pos = wxAtoi(settings.Get("E_SLIDER_Text_Position1", "50")) * 2 - 100; settings.erase("E_SLIDER_Text_Position1"); settings["E_SLIDER_Text_YStart1"] = wxString::Format("%d", pos); settings["E_SLIDER_Text_XStart1"] = wxString::Format("%d", pos); settings["E_SLIDER_Text_XEnd1"] = wxString::Format("%d", pos); settings["E_SLIDER_Text_YEnd1"] = wxString::Format("%d", pos); } break; case EffectManager::eff_WAVE: if (settings.Get("E_TEXTCTRL_Wave_Speed", "") == "") { settings["E_TEXTCTRL_Wave_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } break; case EffectManager::eff_SPIROGRAPH: if (settings.Get("E_TEXTCTRL_Spirograph_Speed", "") == "") { settings["E_TEXTCTRL_Spirograph_Speed"] = settings.Get("T_SLIDER_Speed", "10"); } if (settings.Get("E_CHECKBOX_Spirograph_Animate", "") != "") { int i = wxAtoi(settings.Get("E_CHECKBOX_Spirograph_Animate", "0")); settings["E_TEXTCTRL_Spirograph_Animate"] = (i == 0 ? "0" : "10"); settings.erase("E_CHECKBOX_Spirograph_Animate"); } break; case EffectManager::eff_COLORWASH: if (settings.Get("E_TEXTCTRL_ColorWash_Cycles", "") == "") { double count = wxAtoi(settings.Get("E_SLIDER_ColorWash_Count", "1")); settings.erase("E_SLIDER_ColorWash_Count"); if (settings["T_CHECKBOX_FitToTime"] == "1") { count = 1.0; settings["E_CHECKBOX_ColorWash_CircularPalette"] = "0"; } else { settings["E_CHECKBOX_ColorWash_CircularPalette"] = "1"; } settings["E_TEXTCTRL_ColorWash_Cycles"] = wxString::Format("%0.2f", count); } break; case EffectManager::eff_FIRE: if (settings.Get("E_TEXTCTRL_Fire_GrowthCycles", "") == "") { bool grow = settings["E_CHECKBOX_Fire_GrowFire"] == "1"; settings.erase("E_CHECKBOX_Fire_GrowFire"); if (grow) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; double maxState = totalTime * speed / 50; double cycles = maxState / 500.0; settings["E_TEXTCTRL_Fire_GrowthCycles"] = wxString::Format("%0.2f", cycles); } else { settings["E_TEXTCTRL_Fire_GrowthCycles"] = "0.0"; } } break; case EffectManager::eff_FIREWORKS: if (settings.Get("E_SLIDER_Fireworks_Number_Explosions", "") != "") { int cnt = wxAtoi(settings.Get("E_SLIDER_Fireworks_Number_Explosions", "10")); settings.erase("E_SLIDER_Fireworks_Number_Explosions"); int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int total = (speed * cnt) / 50; if (total > 50) { total = 50; } if (total < 1) { total = 1; } settings["E_SLIDER_Fireworks_Explosions"] = wxString::Format("%d", total); } break; case EffectManager::eff_RIPPLE: if (settings.Get("E_TEXTCTRL_Ripple_Cycles", "") == "") { float cycles = 1.0; if (!ftt) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; cycles = maxState / 200; } settings["E_TEXTCTRL_Ripple_Cycles"] = wxString::Format("%0.2f", cycles); } break; case EffectManager::eff_BARS: if (settings.Get("E_TEXTCTRL_Bars_Cycles", "") == "") { float cycles = 1.0; wxString dir = settings["E_CHOICE_Bars_Direction"]; if (!ftt) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; if (dir.Contains("Altern")) { cycles = maxState * 2; } else { cycles = maxState / 200; } } settings["E_TEXTCTRL_Bars_Cycles"] = wxString::Format("%0.2f", cycles); } break; case EffectManager::eff_SPIRALS: if (settings.Get("E_TEXTCTRL_Spirals_Movement", "") == "") { float cycles = 1.0; int dir = wxAtoi(settings.Get("E_SLIDER_Spirals_Direction", "1")); settings.erase("E_SLIDER_Spirals_Direction"); if (!ftt) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; cycles = maxState / 600; } settings["E_TEXTCTRL_Spirals_Movement"] = wxString::Format("%0.2f", dir * cycles); } break; case EffectManager::eff_CURTAIN: if (settings.Get("E_TEXTCTRL_Curtain_Speed", "") == "") { float cycles = 1.0; if (!ftt) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; cycles = maxState / 200; } settings["E_TEXTCTRL_Curtain_Speed"] = wxString::Format("%0.2f", cycles); } break; case EffectManager::eff_SINGLESTRAND: if ("Skips" == settings["E_NOTEBOOK_SSEFFECT_TYPE"]) { if (settings.Get("E_SLIDER_Skips_Advance", "") == "") { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); settings["E_SLIDER_Skips_Advance"] = wxString::Format("%d", speed - 1); } } else { wxString type = settings.Get("E_CHOICE_Chase_Type1", "Left-Right"); if (type == "Auto reverse") { type = "Bounce from Left"; settings["E_CHOICE_Chase_Type1"] = type; } else if (type == "Bounce" || type == "Pacman") { type = "Dual Bounce"; settings["E_CHOICE_Chase_Type1"] = type; } if (settings.Get("E_TEXTCTRL_Chase_Rotations", "") == "") { float cycles = 1.0; if (!ftt) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; cycles = maxState / 250.0; } settings["E_TEXTCTRL_Chase_Rotations"] = wxString::Format("%0.2f", cycles); } } break; case EffectManager::eff_SHIMMER: if (settings.Get("E_TEXTCTRL_Shimmer_Cycles", "") == "") { float cycles = 1.0; int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; cycles = maxState / (100.0 * colors.size()); settings["E_TEXTCTRL_Shimmer_Cycles"] = wxString::Format("%0.2f", cycles); } break; case EffectManager::eff_PICTURES: if (settings.Get("E_TEXTCTRL_Pictures_FrameRateAdj", "") == "") { if (settings.Get("E_CHECKBOX_MovieIs20FPS", "") == "1") { settings["E_TEXTCTRL_Pictures_FrameRateAdj"] = "1.0"; } else if (settings.Get("E_SLIDER_Pictures_GifSpeed", "") == "0") { settings["E_TEXTCTRL_Pictures_FrameRateAdj"] = "0.0"; } else if (!ftt) { int speed = wxAtoi(settings.Get("T_SLIDER_Speed", "10")); int totalTime = endMS - startMS; int maxState = totalTime * speed / 50; double cycles = maxState / 300.0; settings["E_TEXTCTRL_Pictures_Speed"] = wxString::Format("%0.2f", cycles); } settings.erase("E_CHECKBOX_MovieIs20FPS"); settings.erase("E_SLIDER_Pictures_GifSpeed"); } break; case EffectManager::eff_GARLANDS: //Don't attempt to map the Garlands speed settings. In v3, the Garland speed depended on the Speed setting, the //Spacing setting as well as the height of the model. We don't have the height of the model here so really //no way to figure out the speed or an appropriate mapping break; //these all need code updated and new sliders and such before we can map them //these all have state/speed requirements case EffectManager::eff_PIANO: break; } settings.erase("T_CHECKBOX_FitToTime"); settings.erase("T_SLIDER_Speed"); }
void SnowflakesEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int Count = SettingsMap.GetInt("SLIDER_Snowflakes_Count", 5); int SnowflakeType = SettingsMap.GetInt("SLIDER_Snowflakes_Type", 1); int sSpeed = SettingsMap.GetInt("SLIDER_Snowflakes_Speed", 10); std::string falling = SettingsMap.Get("CHOICE_Falling", "Driving"); int i,n,x,x0,y0,y,check,delta_y; xlColor color1,color2, color3; bool wrapx = false; // set to true if you want snowflakes to draw wrapped around when near edges in the accumulate effect. SnowflakesRenderCache *cache = (SnowflakesRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new SnowflakesRenderCache(); buffer.infoCache[id] = cache; } int &LastSnowflakeCount = cache->LastSnowflakeCount; int &LastSnowflakeType = cache->LastSnowflakeType; int &effectState = cache->effectState; std::string& LastFalling = cache->LastFalling; buffer.palette.GetColor(0, color1); buffer.palette.GetColor(1, color2); if (buffer.needToInit || Count != LastSnowflakeCount || SnowflakeType != LastSnowflakeType || falling != LastFalling) { // initialize buffer.needToInit = false; LastSnowflakeCount=Count; LastSnowflakeType=SnowflakeType; LastFalling = falling; buffer.ClearTempBuf(); effectState = 0; // place Count snowflakes for (n=0; n < Count; n++) { delta_y=buffer.BufferHt/4; y0=(n % 4)*delta_y; if (y0+delta_y > buffer.BufferHt) delta_y = buffer.BufferHt-y0; if (delta_y<1) delta_y=1; // find unused space for (check=0; check < 20; check++) { x=rand() % buffer.BufferWi; y=y0 + (rand() % delta_y); if (buffer.GetTempPixel(x,y) == xlBLACK) { effectState++; break; } } // draw flake, SnowflakeType=0 is random type switch (SnowflakeType == 0 ? rand() % 5 : SnowflakeType-1) { case 0: // single node if(falling != "Driving") { buffer.SetTempPixel(x, y, color1, 0); } else { buffer.SetTempPixel(x, y, color1); } break; case 1: // 5 nodes if (x < 1) x+=1; if (y < 1) y+=1; if (x > buffer.BufferWi-2) x-=1; if (y > buffer.BufferHt-2) y-=1; if(falling != "Driving") { buffer.SetTempPixel(x,y,color1, 1); } else { buffer.SetTempPixel(x,y,color1); buffer.SetTempPixel(x-1,y,color2); buffer.SetTempPixel(x+1,y,color2); buffer.SetTempPixel(x,y-1,color2); buffer.SetTempPixel(x,y+1,color2); } break; case 2: // 3 nodes if (x < 1) x+=1; if (y < 1) y+=1; if (x > buffer.BufferWi-2) x-=1; if (y > buffer.BufferHt-2) y-=1; if(falling != "Driving") { buffer.SetTempPixel(x,y,color1, 2); } else { buffer.SetTempPixel(x,y,color1); if (rand() % 100 > 50) // % 2 was not so random { buffer.SetTempPixel(x-1,y,color2); buffer.SetTempPixel(x+1,y,color2); } else { buffer.SetTempPixel(x,y-1,color2); buffer.SetTempPixel(x,y+1,color2); } } break; case 3: // 9 nodes if (x < 2) x+=2; if (y < 2) y+=2; if (x > buffer.BufferWi-3) x-=2; if (y > buffer.BufferHt-3) y-=2; if(falling != "Driving") { buffer.SetTempPixel(x, y, color1, 3); } else { buffer.SetTempPixel(x, y, color1); for (i=1; i<=2; i++) { buffer.SetTempPixel(x-i,y,color2); buffer.SetTempPixel(x+i,y,color2); buffer.SetTempPixel(x,y-i,color2); buffer.SetTempPixel(x,y+i,color2); } } break; case 4: // 13 nodes if (x < 2) x+=2; if (y < 2) y+=2; if (x > buffer.BufferWi-3) x-=2; if (y > buffer.BufferHt-3) y-=2; if(falling != "Driving") { buffer.SetTempPixel(x, y, color1, 4); } else { buffer.SetTempPixel(x, y, color1); buffer.SetTempPixel(x-1,y,color2); buffer.SetTempPixel(x+1,y,color2); buffer.SetTempPixel(x,y-1,color2); buffer.SetTempPixel(x,y+1,color2); buffer.SetTempPixel(x-1,y+2,color2); buffer.SetTempPixel(x+1,y+2,color2); buffer.SetTempPixel(x-1,y-2,color2); buffer.SetTempPixel(x+1,y-2,color2); buffer.SetTempPixel(x+2,y-1,color2); buffer.SetTempPixel(x+2,y+1,color2); buffer.SetTempPixel(x-2,y-1,color2); buffer.SetTempPixel(x-2,y+1,color2); } break; case 5: // 45 nodes (not enabled) break; } } } // move snowflakes int movement = (buffer.curPeriod - buffer.curEffStartPer) * sSpeed * buffer.frameTimeInMs / 50; int new_x,new_y,new_x2,new_y2; int starty = 0; if (falling == "Falling & Accumulating") { starty = 1; } bool driving = falling == "Driving"; for (x=0; x<buffer.BufferWi; x++) { new_x = (x+movement/20) % buffer.BufferWi; // CW new_x2 = (x-movement/20) % buffer.BufferWi; // CCW if (new_x2 < 0) new_x2 += buffer.BufferWi; for (y=starty; y<buffer.BufferHt; y++) { if (!driving) { // this controls the speed by skipping movement when slow if (((buffer.curPeriod-buffer.curEffStartPer) * (sSpeed+1)) / 30 != ((buffer.curPeriod-buffer.curEffStartPer-1) * (sSpeed + 1)) / 30) { // if there is a flake to move buffer.GetTempPixel(x, y, color3); if (color3 != xlBLACK) { // check where we can move to? int moves = possible_downward_moves(buffer, x, y); x0 = x; //we have something to move // randomly move the flake left or right if (moves > 0 || (falling == "Falling" && y == 0)) { switch(rand() % 5) { case 0: if (moves & 1) { x0 = x - 1; } else { if (moves & 2) { x0 = x; } else { x0 = x + 1; } } break; case 1: if (moves & 4) { x0 = x + 1; } else { if (moves & 2) { x0 = x; } else { x0 = x - 1; } } break; default: //down more often then left/right to look less "jittery" if (moves & 2) { x0 = x; } else if ((moves & 5) == 4) { x0 = x + 1; } else if ((moves & 5) == 1) { x0 = x - 1; } else { switch(rand() % 2) { case 0: x0 = x+1; break; default: x0 = x-1; break; } } break; } // handle wrap around if (x0 < 0) { x0 += buffer.BufferWi; } else if (x0 >= buffer.BufferWi) { x0 -= buffer.BufferWi; } // and move it down y0 = y - 1; buffer.SetTempPixel(x, y, xlBLACK); if (y0 >= 0) { // move the flake down buffer.SetTempPixel(x0, y0, color3); if (falling == "Falling & Accumulating") { int nextmoves = possible_downward_moves(buffer, x0, y0); if (nextmoves == 0) { // we cant move any further so we can add one at the top effectState--; } } } else { // falling should always be just falling ... never accumulate effectState--; } } } } } else { new_y = (y+movement/10) % buffer.BufferHt; new_y2 = (new_y+buffer.BufferHt/2) % buffer.BufferHt; buffer.GetTempPixel(new_x,new_y,color1); if (color1 == xlBLACK) buffer.GetTempPixel(new_x2,new_y2,color1); // strip off the alpha channel buffer.SetPixel(x, y, color1); } } } if (!driving) { // add new flakes to the top check = 0; int placedFullCount = 0; while (effectState < Count && check < 20) { // find unused space x=rand() % buffer.BufferWi; if (buffer.GetTempPixel(x, buffer.BufferHt-1) == xlBLACK) { effectState++; buffer.SetTempPixel(x, buffer.BufferHt-1, color1, SnowflakeType == 0 ? rand() % 5 : SnowflakeType-1); int nextmoves = possible_downward_moves(buffer, x, buffer.BufferHt-1); if (nextmoves == 0) { //the placed pixel fills the column, make sure we note that so we can place //another snowflake placedFullCount++; } } check++; } effectState -= placedFullCount; // paint my current state for (int y=0; y < buffer.BufferHt; y++) { for (int x=0; x < buffer.BufferWi; x++) { buffer.GetTempPixel(x, y, color3); if (color3 != xlBLACK) { // draw flake, SnowflakeType=0 is random type switch (color3.Alpha()) { case 0: // single node buffer.SetPixel(x, y, color1); break; case 1: // 5 nodes buffer.SetPixel(x,y,color1); set_pixel_if_not_color(buffer, x-1, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+1, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x, y-1, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x, y+1, color2, color1, wrapx, false); break; case 2: { // 3 nodes buffer.SetPixel(x,y,color1); bool isAtBottom = true; for (int yt = 0; yt < y - 1; yt++) { if (buffer.GetTempPixel(x, yt) == xlBLACK) { isAtBottom = false; break; } } // when flake has settled always paint it horizontally if (isAtBottom) { set_pixel_if_not_color(buffer, x-1, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+1, y, color2, color1, wrapx, false); } else { if (rand() % 100 > 50) // % 2 was not so random { set_pixel_if_not_color(buffer, x-1, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+1, y, color2, color1, wrapx, false); } else { set_pixel_if_not_color(buffer, x, y-1, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x, y+1, color2, color1, wrapx, false); } } } break; case 3: // 9 nodes buffer.SetPixel(x,y,color1); for (i=1; i<=2; i++) { set_pixel_if_not_color(buffer, x-i, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+i, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x, y-i, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x, y+i, color2, color1, wrapx, false); } break; case 4: // 13 nodes buffer.SetPixel(x,y,color1); set_pixel_if_not_color(buffer, x-1, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+1, y, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x, y+1, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x, y-1, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x-1, y+2, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+1, y+2, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x-1, y-2, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+1, y-2, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+2, y-1, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x+2, y+1, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x-2, y-1, color2, color1, wrapx, false); set_pixel_if_not_color(buffer, x-2, y+1, color2, color1, wrapx, false); break; case 5: // 45 nodes (not enabled) break; } } } } } }
void FireworksEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int Number_Explosions = SettingsMap.GetInt("SLIDER_Fireworks_Explosions", 16); int Count = SettingsMap.GetInt("SLIDER_Fireworks_Count", 50); float Velocity = SettingsMap.GetDouble("SLIDER_Fireworks_Velocity", 2.0f); int Fade = SettingsMap.GetInt("SLIDER_Fireworks_Fade", 50); float f = 0.0; bool useMusic = SettingsMap.GetBool("CHECKBOX_Fireworks_UseMusic", false); float sensitivity = (float)SettingsMap.GetInt("SLIDER_Fireworks_Sensitivity", 50) / 100.0; bool useTiming = SettingsMap.GetBool("CHECKBOX_FIRETIMING", false); wxString timing = SettingsMap.Get("CHOICE_FIRETIMINGTRACK", ""); if (timing == "") useTiming = false; if (useMusic) { if (buffer.GetMedia() != nullptr) { std::list<float>* pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, FRAMEDATA_HIGH, ""); if (pf != nullptr) { f = *pf->begin(); } } } FireworksRenderCache *cache = (FireworksRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new FireworksRenderCache(); buffer.infoCache[id] = cache; } int& next = cache->next; int& sincelasttriggered = cache->sincelasttriggered; int x25,x75,y25,y75; //float velocity = 3.5; int ColorIdx; float v; HSVValue hsv; size_t colorcnt = buffer.GetColorCount(); if (buffer.needToInit) { SetPanelTimingTracks(); cache->sincelasttriggered = 0; cache->next = 0; buffer.needToInit = false; for(int i=0; i<maxFlakes; i++) { cache->fireworkBursts[i]._bActive = false; } for (int x = 0; x < Number_Explosions; x++) { double start = -1; if (!useMusic) { start = buffer.curEffStartPer + buffer.rand01() * (buffer.curEffEndPer - buffer.curEffStartPer); } x25=(int)buffer.BufferWi*0.25; x75=(int)buffer.BufferWi*0.75; y25=(int)buffer.BufferHt*0.25; y75=(int)buffer.BufferHt*0.75; int startX; int startY; if((x75-x25)>0) startX = x25 + rand()%(x75-x25); else startX=0; if((y75-y25)>0) startY = y25 + rand()%(y75-y25); else startY=0; // Create a new burst ColorIdx=rand() % colorcnt; // Select random numbers from 0 up to number of colors the user has checked. 0-5 if 6 boxes checked for(int i=0; i<Count; i++) { cache->fireworkBursts[x * Count + i].Reset(startX, startY, false, Velocity, ColorIdx, start); } } if (timing != "") { effect->GetParentEffectLayer()->GetParentElement()->GetSequenceElements()->AddRenderDependency(timing.ToStdString(), buffer.cur_model); } } if (useMusic) { // only trigger a firework if music is greater than the sensitivity if (f > sensitivity) { // trigger if it was not previously triggered or has been triggered for REPEATTRIGGER frames if (sincelasttriggered == 0 || sincelasttriggered > REPEATTRIGGER) { // activate all the particles in the next firework for (int j = 0; j < Count; j++) { cache->fireworkBursts[Count*next + j]._bActive = true; buffer.palette.GetHSV(cache->fireworkBursts[Count*next + j]._colorindex, hsv); // Now go and get the hsv value for this ColorIdx cache->fireworkBursts[Count*next + j]._hsv = hsv; } // use the next firework next time next++; if (next == Number_Explosions) { next = 0; } } // if music is over the trigger level for REPEATTRIGGER frames then we will trigger another firework sincelasttriggered++; if (sincelasttriggered > REPEATTRIGGER) { sincelasttriggered = 0; } } else { // not triggered so clear last triggered counter sincelasttriggered = 0; } } if (useTiming) { if (mSequenceElements == nullptr) { // no timing tracks ... this shouldnt happen } else { // Load the names of the timing tracks Element* t = nullptr; for (size_t l = 0; l < mSequenceElements->GetElementCount(); l++) { Element* e = mSequenceElements->GetElement(l); if (e->GetEffectLayerCount() == 1 && e->GetType() == ELEMENT_TYPE_TIMING) { if (e->GetName() == timing) { t = e; break; } } } if (t == nullptr) { // timing track not found ... this shouldnt happen } else { sincelasttriggered = 0; EffectLayer* el = t->GetEffectLayer(0); for (int j = 0; j < el->GetEffectCount(); j++) { if (buffer.curPeriod == el->GetEffect(j)->GetStartTimeMS() / buffer.frameTimeInMs || buffer.curPeriod == el->GetEffect(j)->GetEndTimeMS() / buffer.frameTimeInMs) { // activate all the particles in the next firework for (int k = 0; k < Count; k++) { cache->fireworkBursts[Count*next + k]._bActive = true; buffer.palette.GetHSV(cache->fireworkBursts[Count*next + k]._colorindex, hsv); // Now go and get the hsv value for this ColorIdx cache->fireworkBursts[Count*next + k]._hsv = hsv; } // use the next firework next time next++; if (next == Number_Explosions) { next = 0; } break; } } } } } for (int i=0; i<(Count*Number_Explosions); i++) { if (!useMusic && !useTiming) { if (cache->fireworkBursts[i].startPeriod == buffer.curPeriod) { cache->fireworkBursts[i]._bActive = true; buffer.palette.GetHSV(cache->fireworkBursts[i]._colorindex, hsv); // Now go and get the hsv value for this ColorIdx cache->fireworkBursts[i]._hsv = hsv; } } // ... active flakes: if (cache->fireworkBursts[i]._bActive) { // Update position cache->fireworkBursts[i]._x += cache->fireworkBursts[i]._dx; cache->fireworkBursts[i]._y += (-cache->fireworkBursts[i]._dy - cache->fireworkBursts[i]._cycles*cache->fireworkBursts[i]._cycles/10000000.0); // If this flake run for more than maxCycle or this flake is out of bounds, time to switch it off cache->fireworkBursts[i]._cycles+=20; if (cache->fireworkBursts[i]._cycles >= 10000 || cache->fireworkBursts[i]._y >= buffer.BufferHt || cache->fireworkBursts[i]._y < 0 || cache->fireworkBursts[i]._x < 0. || cache->fireworkBursts[i]._x >= buffer.BufferWi) { cache->fireworkBursts[i]._bActive = false; if (useMusic) { cache->fireworkBursts[i].Reset(); } continue; } } if(cache->fireworkBursts[i]._bActive == true) { v = ((Fade*10.0)-cache->fireworkBursts[i]._cycles)/(Fade*10.0); if (v<0) v=0.0; if (buffer.allowAlpha) { xlColor c(cache->fireworkBursts[i]._hsv); c.alpha = 255.0 * v; buffer.SetPixel(cache->fireworkBursts[i]._x, cache->fireworkBursts[i]._y, c); } else { hsv=cache->fireworkBursts[i]._hsv; hsv.value=v; buffer.SetPixel(cache->fireworkBursts[i]._x, cache->fireworkBursts[i]._y, hsv); } } } }