void AssistPanel::SetEffectInfo(Effect* effect_, xLightsFrame* xlights_parent) { if( mGridCanvas != nullptr ) { mEffect = effect_; EffectLayer* layer = mEffect->GetParentEffectLayer(); if (layer == nullptr) { static log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); logger_base.error("No layer found for effect %s", (const char *)mEffect->GetEffectName().c_str()); } Element* elem = layer->GetParentElement(); if (elem == nullptr) { static log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); logger_base.error("No element found for effect %s", (const char *)mEffect->GetEffectName().c_str()); } std::string model_name = elem->GetModelName(); mModel = xlights_parent->GetModel(model_name); if (mModel != nullptr && dynamic_cast<SubModelElement*>(elem) != nullptr) { Model *scls = mModel->GetSubModel(dynamic_cast<SubModelElement*>(elem)->GetName()); if (scls != nullptr) { mModel = scls; } } if (mModel == nullptr) { static log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); logger_base.error("No model found for effect %s for model %s", (const char *)mEffect->GetEffectName().c_str(), (const char *)model_name.c_str()); } RefreshEffect(); } }
void MainSequencer::GetSelectedEffectsData(wxString& copy_data) { int start_column = PanelEffectGrid->GetStartColumn(); int column_start_time = -1000; EffectLayer* tel = mSequenceElements->GetVisibleEffectLayer(mSequenceElements->GetSelectedTimingRow()); if( tel != nullptr && start_column != -1) { Effect* eff = tel->GetEffect(start_column); if( eff != nullptr ) { column_start_time = eff->GetStartTimeMS(); } } for(int i=0;i<mSequenceElements->GetRowInformationSize();i++) { int row_number = mSequenceElements->GetRowInformation(i)->Index-mSequenceElements->GetFirstVisibleModelRow(); EffectLayer* el = mSequenceElements->GetEffectLayer(i); for (int x = 0; x < el->GetEffectCount(); x++) { Effect *ef = el->GetEffect(x); if (ef->GetSelected() != EFFECT_NOT_SELECTED) { wxString start_time = wxString::Format("%d",ef->GetStartTimeMS()); wxString end_time = wxString::Format("%d",ef->GetEndTimeMS()); wxString row = wxString::Format("%d",row_number); wxString column_start = wxString::Format("%d",column_start_time); copy_data += ef->GetEffectName() + "\t" + ef->GetSettingsAsString() + "\t" + ef->GetPaletteAsString() + "\t" + start_time + "\t" + end_time + "\t" + row + "\t" + column_start + "\n"; } } } }
void SequenceElements::UnSelectAllEffects() { for(int i=0;i<mRowInformation.size();i++) { EffectLayer* effectLayer = GetEffectLayer(&mRowInformation[i]); effectLayer->UnSelectAllEffects(); } }
void AssistPanel::SetEffectInfo(Effect* effect_, xLightsFrame* xlights_parent) { if( mGridCanvas != nullptr ) { mEffect = effect_; EffectLayer* layer = mEffect->GetParentEffectLayer(); Element* elem = layer->GetParentElement(); std::string model_name = elem->GetName(); Model *cls = xlights_parent->GetModel(model_name); mGridCanvas->SetModel(cls); mGridCanvas->SetNumColumns(cls->BufferWi); mGridCanvas->SetNumRows(cls->BufferHt); mGridCanvas->SetEffect(mEffect); } }
int SequenceElements::SelectEffectsInRowAndColumnRange(int startRow, int endRow, int startCol,int endCol) { int num_selected = 0; EffectLayer* tel = GetVisibleEffectLayer(GetSelectedTimingRow()); if( tel != nullptr ) { Effect* eff1 = tel->GetEffect(startCol); Effect* eff2 = tel->GetEffect(endCol); if( eff1 != nullptr && eff2 != nullptr ) { int startMS = eff1->GetStartTimeMS(); int endMS = eff2->GetEndTimeMS(); num_selected = SelectEffectsInRowAndTimeRange(startRow, endRow, startMS, endMS); } } return num_selected; }
int SequenceElements::SelectEffectsInRowAndTimeRange(int startRow, int endRow, int startMS,int endMS) { int num_selected = 0; if(startRow<mVisibleRowInformation.size()) { if(endRow>=mVisibleRowInformation.size()) { endRow = mVisibleRowInformation.size()-1; } for(int i=startRow;i<=endRow;i++) { EffectLayer* effectLayer = GetEffectLayer(&mVisibleRowInformation[i]); num_selected += effectLayer->SelectEffectsInTimeRange(startMS,endMS); } } return num_selected; }
void SequenceElements::RenameTimingTrack(std::string oldname, std::string newname) { // actual timing track name already updated ... we just need to update any effects that care about the timing track name // faces, state, piano, vumeter std::vector<RenderableEffect*> effects(GetEffectManager().size()); int count = 0; for (int x = 0; x < GetEffectManager().size(); x++) { RenderableEffect *eff = GetEffectManager()[x]; effects[x] = eff; } for (size_t i = 0; i < GetElementCount(); i++) { Element* elem = GetElement(i); if (elem->GetType() == "model") { for (int j = 0; j < elem->GetEffectLayerCount(); j++) { EffectLayer* layer = elem->GetEffectLayer(j); for (int k = 0; k < layer->GetEffectCount(); k++) { Effect* eff = layer->GetEffect(k); if (effects[eff->GetEffectIndex()] != nullptr) { effects[eff->GetEffectIndex()]->RenameTimingTrack(oldname, newname, eff); } } } for (int j = 0; j < elem->getStrandLayerCount(); j++) { StrandLayer* layer = elem->GetStrandLayer(j); for (int k = 0; k < layer->GetEffectCount(); k++) { Effect* eff = layer->GetEffect(k); if (effects[eff->GetEffectIndex()] != nullptr) { effects[eff->GetEffectIndex()]->RenameTimingTrack(oldname, newname, eff); } } for (int k = 0; k < layer->GetNodeLayerCount(); k++) { NodeLayer* nlayer = layer->GetNodeLayer(k); for (int l = 0; l < nlayer->GetEffectCount(); l++) { Effect* eff = nlayer->GetEffect(l); if (effects[eff->GetEffectIndex()] != nullptr) { effects[eff->GetEffectIndex()]->RenameTimingTrack(oldname, newname, eff); } } } } } } }
void MainSequencer::SplitTimingMark() { int x1; int x2; if( mPlayType == PLAY_TYPE_MODEL ) { x1 = PanelTimeLine->GetPlayMarker(); x2 = x1; } else { x1 = PanelTimeLine->GetSelectedPositionStart(); x2 = PanelTimeLine->GetSelectedPositionEnd(); } if( x2 == -1 ) x2 = x1; int selectedTiming = mSequenceElements->GetSelectedTimingRow(); if(selectedTiming >= 0) { Element* e = mSequenceElements->GetVisibleRowInformation(selectedTiming)->element; EffectLayer* el = e->GetEffectLayer(mSequenceElements->GetVisibleRowInformation(selectedTiming)->layerIndex); int index1,index2; int t1 = PanelTimeLine->GetAbsoluteTimeMSfromPosition(x1); int t2 = PanelTimeLine->GetAbsoluteTimeMSfromPosition(x2); if(el->HitTestEffectByTime(t1,index1) && el->HitTestEffectByTime(t2,index2)) { if( index1 == index2 ) { Effect* eff1 = el->GetEffect(index1); int old_end_time = eff1->GetEndTimeMS(); if( t1 != t2 || ((t1 == t2) && t1 != eff1->GetStartTimeMS() && t1 != eff1->GetEndTimeMS()) ) { eff1->SetEndTimeMS(t1); std::string name,settings; el->AddEffect(0,name,settings,"",t2,old_end_time,false,false); PanelEffectGrid->ForceRefresh(); } } else { wxMessageBox("Timing cannot be split across timing marks.","Timing placement error"); } } } }
void RowHeading::BreakdownTimingPhrases(Element* element) { element->SetFixedTiming(0); EffectLayer* layer = element->GetEffectLayer(0); if( element->GetEffectLayerCount() > 1 ) { for( int k = element->GetEffectLayerCount()-1; k > 0; k--) { element->RemoveEffectLayer(k); } } EffectLayer* word_layer = element->AddEffectLayer(); for( int i = 0; i < layer->GetEffectCount(); i++ ) { Effect* effect = layer->GetEffect(i); std::string phrase = effect->GetEffectName(); mSequenceElements->BreakdownPhrase(word_layer, effect->GetStartTimeMS(), effect->GetEndTimeMS(), phrase); } wxCommandEvent eventRowHeaderChanged(EVT_ROW_HEADINGS_CHANGED); wxPostEvent(GetParent(), eventRowHeaderChanged); }
void MainSequencer::InsertTimingMarkFromRange() { bool is_range = true; int x1; int x2; if( mPlayType == PLAY_TYPE_MODEL ) { x1 = PanelTimeLine->GetPlayMarker(); x2 = x1; } else { x1 = PanelTimeLine->GetSelectedPositionStart(); x2 = PanelTimeLine->GetSelectedPositionEnd(); } if( x2 == -1 ) x2 = x1; if( x1 == x2) is_range = false; int selectedTiming = mSequenceElements->GetSelectedTimingRow(); if(selectedTiming >= 0) { int t1 = PanelTimeLine->GetAbsoluteTimeMSfromPosition(x1); int t2 = PanelTimeLine->GetAbsoluteTimeMSfromPosition(x2); if(is_range) { Element* e = mSequenceElements->GetVisibleRowInformation(selectedTiming)->element; EffectLayer* el = e->GetEffectLayer(mSequenceElements->GetVisibleRowInformation(selectedTiming)->layerIndex); int index; if(!el->HitTestEffectByTime(t1,index) && !el->HitTestEffectByTime(t2,index)) { std::string name,settings; el->AddEffect(0,name,settings,"",t1,t2,false,false); PanelEffectGrid->ForceRefresh(); } else { wxMessageBox("Timing exist already in the selected region","Timing placement error"); } } else { // x1 and x2 are the same. Insert from end time of timing to the left to x2 Element* e = mSequenceElements->GetVisibleRowInformation(selectedTiming)->element; EffectLayer* el = e->GetEffectLayer(mSequenceElements->GetVisibleRowInformation(selectedTiming)->layerIndex); int index; if(!el->HitTestEffectByTime(t2,index)) { // if there is an effect to left std::string name,settings; Effect * effect = nullptr; for (int x = 0; x < el->GetEffectCount(); x++) { Effect * e = el->GetEffect(x); if (e->GetStartTimeMS() > t2 && x > 0) { effect = el->GetEffect(x - 1); break; } } if(effect!=nullptr) { int t1 = effect->GetEndTimeMS(); el->AddEffect(0,name,settings,"",t1,t2,false,false); } // No effect to left start at time = 0 else { int t1 = 0; if (el->GetEffectCount() > 0) { Effect *e = el->GetEffect(el->GetEffectCount() - 1); t1 = e->GetEndTimeMS(); } el->AddEffect(0,name,settings,"",t1,t2,false,false); } PanelEffectGrid->ForceRefresh(); } else { SplitTimingMark(); // inserting a timing mark inside a timing mark same as a split } } } }
void StateEffect::RenderState(RenderBuffer &buffer, SequenceElements *elements, const std::string &faceDefinition, const std::string& Phoneme, const std::string &trackName, const std::string& mode, const std::string& colourmode) { if (buffer.needToInit) { buffer.needToInit = false; elements->AddRenderDependency(trackName, buffer.cur_model); if (buffer.isTransformed) { log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); logger_base.warn("State effect starting at %dms until %dms on model %s has a transformed buffer. This may not work as expected.", buffer.curEffStartPer * buffer.frameTimeInMs, buffer.curEffEndPer * buffer.frameTimeInMs, (const char *)buffer.cur_model.c_str()); } } Element *track = elements->GetElement(trackName); std::recursive_mutex tmpLock; std::recursive_mutex *lock = &tmpLock; if (track != nullptr) { lock = &track->GetChangeLock(); } std::unique_lock<std::recursive_mutex> locker(*lock); if (buffer.cur_model == "") { return; } Model* model_info = buffer.frame->AllModels[buffer.cur_model]; if (model_info == nullptr) { return; } std::string definition = faceDefinition; bool found = true; std::map<std::string, std::map<std::string, std::string> >::iterator it = model_info->stateInfo.find(definition); if (it == model_info->stateInfo.end()) { //not found found = false; } if (!found) { if ("Coro" == definition && model_info->stateInfo.find("SingleNode") != model_info->stateInfo.end()) { definition = "SingleNode"; found = true; } else if ("SingleNode" == definition && model_info->stateInfo.find("Coro") != model_info->stateInfo.end()) { definition = "Coro"; found = true; } } if (definition == "") { return; } std::string modelType = found ? model_info->stateInfo[definition]["Type"] : definition; if (modelType == "") { modelType = definition; } int type = 1; if ("SingleNode" == modelType) { type = 0; } else if ("NodeRange" == modelType) { type = 1; } std::string tstates = Phoneme; int intervalnumber = 0; //GET label from timing track int startms = -1; int endms = -1; int posms = -1; if (tstates == "") { // if we dont have a track then exit if (track == NULL) { return; } EffectLayer *layer = track->GetEffectLayer(0); std::unique_lock<std::recursive_mutex> locker(layer->GetLock()); int time = buffer.curPeriod * buffer.frameTimeInMs + 1; posms = buffer.curPeriod * buffer.frameTimeInMs; Effect *ef = layer->GetEffectByTime(time); if (ef == nullptr) { tstates = ""; } else { startms = ef->GetStartTimeMS(); endms = ef->GetEndTimeMS(); tstates = ef->GetEffectName(); } ef = layer->GetEffectByTime(buffer.curEffStartPer * buffer.frameTimeInMs + 1); while (ef != NULL && ef->GetStartTimeMS() <= time) { intervalnumber++; int endtime = ef->GetEndTimeMS(); ef = layer->GetEffectByTime(endtime + 1); if (ef == NULL) { ef = layer->GetEffectAfterTime(endtime + 1); } } } std::vector<std::string> sstates; if (mode == "Default" || startms == -1) { wxString ss = wxString(tstates); wxStringTokenizer tkz(ss, wxT(" ,;:")); while (tkz.HasMoreTokens()) { wxString token = tkz.GetNextToken(); sstates.push_back(token.Lower().ToStdString()); } } else if (mode == "Countdown") { // tstates should contain the starting number int val = wxAtoi(tstates); val = val * 1000; int subtracttime = (posms - startms); val = val - subtracttime; val = val / 1000; int v = val; bool force = false; if ((v / 1000) * 1000 > 0) { sstates.push_back(wxString::Format("%d", (v / 1000) * 1000).ToStdString()); force = true; } v = v - (v / 1000) * 1000; if ((v / 100) * 100 > 0) { sstates.push_back(wxString::Format("%d", (v / 100) * 100).ToStdString()); force = true; } else { if (force) { sstates.push_back("000"); } } v = v - (v / 100) * 100; if ((v / 10) * 10 > 0) { sstates.push_back(wxString::Format("%d", (v / 10) * 10).ToStdString()); } else { if (force) { sstates.push_back("00"); } } v = v - (v / 10) * 10; sstates.push_back(wxString::Format("%d", v).ToStdString()); } else if (mode == "Time Countdown") { wxDateTime dt; dt.ParseFormat(tstates.c_str(), "%H:%M:%S"); if (!dt.IsValid()) { dt.ParseFormat(tstates.c_str(), "%M:%S"); } if (dt.IsValid()) { dt.Subtract(wxTimeSpan(0, 0, 0, (buffer.curPeriod - buffer.curEffStartPer) * buffer.frameTimeInMs)); int m = dt.GetMinute(); if ((m / 10) * 1000 > 0) { sstates.push_back(wxString::Format("%d", (m / 10) * 1000).ToStdString()); } else { sstates.push_back("0000"); } m = m - (m / 10) * 10; if (m * 100 > 0) { sstates.push_back(wxString::Format("%d", m * 100).ToStdString()); } else { sstates.push_back("000"); } int s = dt.GetSecond(); if ((s / 10) * 10 > 0) { sstates.push_back(wxString::Format("%d", (s / 10) * 10).ToStdString()); } else { sstates.push_back("00"); } s = s - (s / 10) * 10; sstates.push_back(wxString::Format("%d", s).ToStdString()); } sstates.push_back("colon"); } else if (mode == "Number") // used for FM frequencies { double f = wxAtof(tstates); sstates.push_back("dot"); double f2 = f - int(f); f2 = (int)(f2 * 10 + 0.5); sstates.push_back(wxString::Format("%d", (int)f2).ToStdString()); int v = f; bool force = false; if ((v / 100) * 1000 > 0) { sstates.push_back(wxString::Format("%d", (v / 100) * 1000).ToStdString()); force = true; } v = v - (v / 100) * 100; if ((v / 10) * 100 > 0) { sstates.push_back(wxString::Format("%d", (v / 10) * 100).ToStdString()); } else { if (force) { sstates.push_back("000"); } } v = v - (v / 10) * 10; if (v * 10 > 0) { sstates.push_back(wxString::Format("%d", v * 10).ToStdString()); } else { sstates.push_back("00"); } } else if (mode == "Iterate") { float progressthroughtimeinterval = ((float)posms - (float)startms) / ((float)endms - (float)startms); std::vector<std::string> tmpstates; wxString ss = wxString(tstates); wxStringTokenizer tkz(ss, wxT(" ,;:")); while (tkz.HasMoreTokens()) { wxString token = tkz.GetNextToken(); tmpstates.push_back(token.Lower().ToStdString()); } int which = tmpstates.size() * progressthroughtimeinterval; if (which < sstates.size()) { sstates.push_back(tmpstates[which]); } } bool customColor = found ? model_info->stateInfo[definition]["CustomColors"] == "1" : false; // process each token for (size_t i = 0; i < sstates.size(); i++) { // get the channels std::string statename = FindState(model_info->stateInfo[definition], sstates[i]); std::string channels = model_info->stateInfo[definition][statename]; if (statename != "" && channels != "") { xlColor color; if (colourmode == "Graduate") { buffer.GetMultiColorBlend(buffer.GetEffectTimeIntervalPosition(), false, color); } else if (colourmode == "Cycle") { buffer.palette.GetColor((intervalnumber - 1) % buffer.GetColorCount(), color); } else { // allocate int statenum = wxAtoi(statename.substr(1)); buffer.palette.GetColor((statenum - 1) % buffer.GetColorCount(), color); } if (customColor) { std::string cname = model_info->stateInfo[definition][statename + "-Color"]; if (cname == "") { color = xlWHITE; } else { color = xlColor(cname); } } wxStringTokenizer wtkz(channels, ","); while (wtkz.HasMoreTokens()) { wxString valstr = wtkz.GetNextToken(); if (type == 0) { for (size_t n = 0; n < model_info->GetNodeCount(); n++) { wxString nn = model_info->GetNodeName(n, true); if (nn == valstr) { for (auto a = buffer.Nodes[n]->Coords.begin() ; a != buffer.Nodes[n]->Coords.end(); a++) { buffer.SetPixel(a->bufX, a->bufY, color); } } } } else if (type == 1) { int start, end; if (valstr.Contains("-")) { int idx = valstr.Index('-'); start = wxAtoi(valstr.Left(idx)); end = wxAtoi(valstr.Right(valstr.size() - idx - 1)); } else { start = end = wxAtoi(valstr); } if (start > end) { start = end; } start--; end--; for (int n = start; n <= end; n++) { if (n < buffer.Nodes.size()) { for (auto a = buffer.Nodes[n]->Coords.begin() ; a != buffer.Nodes[n]->Coords.end(); a++) { buffer.SetPixel(a->bufX, a->bufY, color); } } } } } } } }
bool SequenceElements::LoadSequencerFile(xLightsXmlFile& xml_file) { mFilename = xml_file; wxXmlDocument& seqDocument = xml_file.GetXmlDocument(); wxXmlNode* root=seqDocument.GetRoot(); std::vector<std::string> effectStrings; std::vector<std::string> colorPalettes; Clear(); for(wxXmlNode* e=root->GetChildren(); e!=NULL; e=e->GetNext() ) { if (e->GetName() == "DisplayElements") { for(wxXmlNode* element=e->GetChildren(); element!=NULL; element=element->GetNext() ) { bool active=false; bool selected=false; bool collapsed=false; std::string name = element->GetAttribute(STR_NAME).ToStdString(); std::string type = element->GetAttribute(STR_TYPE).ToStdString(); bool visible = element->GetAttribute("visible")=='1'?true:false; if (type==STR_TIMING) { active = element->GetAttribute("active")=='1'?true:false; } else { collapsed = element->GetAttribute("collapsed")=='1'?true:false; } Element* elem = AddElement(name,type,visible,collapsed,active,selected); if (type==STR_TIMING) { std::string views = element->GetAttribute("views", "").ToStdString(); elem->SetViews(views); } } } else if (e->GetName() == "EffectDB") { effectStrings.clear(); for(wxXmlNode* elementNode=e->GetChildren(); elementNode!=NULL; elementNode=elementNode->GetNext() ) { if(elementNode->GetName()==STR_EFFECT) { effectStrings.push_back(elementNode->GetNodeContent().ToStdString()); } } } else if (e->GetName() == "ColorPalettes") { colorPalettes.clear(); for(wxXmlNode* elementNode=e->GetChildren(); elementNode!=NULL; elementNode=elementNode->GetNext() ) { if(elementNode->GetName() == STR_COLORPALETTE) { colorPalettes.push_back(elementNode->GetNodeContent().ToStdString()); } } } else if (e->GetName() == "ElementEffects") { for(wxXmlNode* elementNode=e->GetChildren(); elementNode!=NULL; elementNode=elementNode->GetNext() ) { if(elementNode->GetName()==STR_ELEMENT) { Element* element = GetElement(elementNode->GetAttribute(STR_NAME).ToStdString()); if (element !=NULL) { // check for fixed timing interval int interval = 0; if( elementNode->GetAttribute(STR_TYPE) == STR_TIMING ) { interval = wxAtoi(elementNode->GetAttribute("fixed")); } if( interval > 0 ) { element->SetFixedTiming(interval); EffectLayer* effectLayer = element->AddEffectLayer(); int time = 0; int end_time = xml_file.GetSequenceDurationMS(); int startTime, endTime, next_time; while( time <= end_time ) { next_time = (time + interval <= end_time) ? time + interval : end_time; startTime = TimeLine::RoundToMultipleOfPeriod(time,mFrequency); endTime = TimeLine::RoundToMultipleOfPeriod(next_time,mFrequency); effectLayer->AddEffect(0,"","","",startTime,endTime,EFFECT_NOT_SELECTED,false); time += interval; } } else { for(wxXmlNode* effectLayerNode=elementNode->GetChildren(); effectLayerNode!=NULL; effectLayerNode=effectLayerNode->GetNext()) { if (effectLayerNode->GetName() == STR_EFFECTLAYER || effectLayerNode->GetName() == STR_STRAND) { EffectLayer* effectLayer = NULL; if (effectLayerNode->GetName() == STR_EFFECTLAYER) { effectLayer = element->AddEffectLayer(); } else { effectLayer = element->GetStrandLayer(wxAtoi(effectLayerNode->GetAttribute(STR_INDEX)), true); if (effectLayerNode->GetAttribute(STR_NAME, STR_EMPTY) != STR_EMPTY) { ((StrandLayer*)effectLayer)->SetName(effectLayerNode->GetAttribute(STR_NAME).ToStdString()); } } LoadEffects(effectLayer, elementNode->GetAttribute(STR_TYPE).ToStdString(), effectLayerNode, effectStrings, colorPalettes); } } } } } } } } // Select view and set current view models as visible int last_view = xml_file.GetLastView(); for(wxXmlNode* view=mViewsNode->GetChildren(); view!=NULL; view=view->GetNext() ) { std::string viewName = view->GetAttribute(STR_NAME).ToStdString(); std::string models = view->GetAttribute("models").ToStdString(); std::vector <Element*> new_view; mAllViews.push_back(new_view); int view_index = mAllViews.size()-1; if( view_index == last_view ) { AddMissingModelsToSequence(models); PopulateView(models, view_index); SetCurrentView(view_index); } } if (mModelsNode != nullptr) { PopulateRowInformation(); } // Set to the first model/view mFirstVisibleModelRow = 0; return true; }
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); } } } }