void MusicEffect::RenderMorph(RenderBuffer &buffer, int x, int bars, int startNote, int endNote, std::list<MusicEvent*>& events, int colourTreatment, bool bounce, bool fade) { bool up = true; int event = -1; for (auto it = events.begin(); it != events.end(); ++it) { event++; up = !up; if ((*it)->IsEventActive(buffer.curPeriod)) { float progress = (*it)->OffsetInDuration(buffer.curPeriod); int length = buffer.BufferHt; int start = -1 * length + progress * 2 * length + 1; int end = start + length; for (int y = std::max(0, start); y < std::min(end, buffer.BufferHt); y++) { xlColor c = xlWHITE; float proportion = ((float)end - (float)y) / (float)length; if (colourTreatment == 1) { // distinct float percolour = 1.0 / (float)buffer.GetColorCount(); for (int i = 0; i < buffer.GetColorCount(); i++) { if (proportion <= ((float)i + 1.0)*percolour) { buffer.palette.GetColor(i, c); break; } } } else if (colourTreatment == 2) { // blend buffer.GetMultiColorBlend(proportion, false, c); } else if (colourTreatment == 3) { buffer.palette.GetColor(event % buffer.GetColorCount(), c); } if (fade) { c.alpha = (1.0 -proportion) * 255; } if (up || !bounce) { buffer.SetPixel(x, y, c); } else { buffer.SetPixel(x, buffer.BufferHt - y - 1, c); } } } } }
void MusicEffect::RenderOn(RenderBuffer &buffer, int x, int bars, int startNote, int endNote, std::list<MusicEvent*>& events, int colourTreatment, bool fade) { int event = -1; for (auto it = events.begin(); it != events.end(); ++it) { event++; if ((*it)->IsEventActive(buffer.curPeriod)) { float progress = (*it)->OffsetInDuration(buffer.curPeriod); for (int y = 0; y < buffer.BufferHt; y++) { xlColor c = xlWHITE; float proportion = (float)y / (float)buffer.BufferHt; if (colourTreatment == 1) { // distinct float percolour = 1.0 / (float)buffer.GetColorCount(); for (int i = 0; i < buffer.GetColorCount(); i++) { if (proportion <= ((float)i + 1.0)*percolour) { buffer.palette.GetColor(i, c); break; } } } else if (colourTreatment == 2) { // blend buffer.GetMultiColorBlend(proportion, false, c); } else if (colourTreatment == 3) { buffer.palette.GetColor(event % buffer.GetColorCount(), c); } if (fade) { c.alpha = (1.0 - progress) * 255; } buffer.SetPixel(x, y, c); } } } }
void ShimmerEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { float oset = buffer.GetEffectTimeIntervalPosition(); int Duty_Factor = GetValueCurveInt("Shimmer_Duty_Factor", 50, SettingsMap, oset); bool Use_All_Colors = SettingsMap.GetBool("CHECKBOX_Shimmer_Use_All_Colors", false); float cycles = GetValueCurveDouble("Shimmer_Cycles", 1.0, SettingsMap, oset); int colorcnt=buffer.GetColorCount(); double position = buffer.GetEffectTimeIntervalPosition(cycles); double ColorIdx = round(position * 0.999 * (double)colorcnt); double pos2 = position * colorcnt; while (pos2 > 1.0) { pos2 -= 1.0; } if (pos2 * 100 > Duty_Factor) { return; } xlColor color; buffer.palette.GetColor(ColorIdx, color); for (int y=0; y<buffer.BufferHt; y++) { for (int x=0; x<buffer.BufferWi; x++) { if(Use_All_Colors) { // Should we randomly assign colors from palette or cycle thru sequentially? ColorIdx=rand() % colorcnt; // Select random numbers from 0 up to number of colors the user has checked. 0-5 if 6 boxes checked buffer.palette.GetColor(ColorIdx, color); // Now go and get the hsv value for this ColorIdx } buffer.SetPixel(x,y,color); // Turn pixel } } }
//all shapes are loaded from same image file to reduce file I/O and caching //thiss also allows animated images to be self-contained void PianoRenderCache::Piano_load_shapes(RenderBuffer &buffer, const wxString& filename) { debug_function(10); //Debug debug("load_shapes('%s')", (const char*)filename.c_str()); debug(1, "load shapes file '%s'", (const char*)filename.c_str()); //reload shapes even if file name hasn't changed; color map might be different now // if (!CachedShapeFilename.CmpNoCase(filename)) { debug_more(2, ", no change"); return; } //no change if (!wxFileExists(filename)) return; Piano_flush_shapes(); //invalidate cached data if (!Shapes.LoadFile(filename, wxBITMAP_TYPE_ANY, 0) || !Shapes.IsOk()) { //wxMessageBox("Error loading image file: "+NewPictureName); Shapes.Clear(); return; } if (buffer.GetColorCount() < 2) return; //use colors from shapes file if no user-selected colors // int imgwidth=image.GetWidth(); // int imght =image.GetHeight(); // std::hash_map<WXCOLORREF, int> palcounts; //TODO: use wxImage.GetData for better performance? //TODO: use multiple images within same file? for (int y = Shapes.GetHeight() - 1; y >= 0; --y) //bottom->top for (int x = 0; x < Shapes.GetWidth(); ++x) //left->right if (!Shapes.IsTransparent(x, y)) { xlColor color, mapped; color.Set(Shapes.GetRed(x, y), Shapes.GetGreen(x, y), Shapes.GetBlue(x, y)); if (ColorMap.find(color.GetRGB()) != ColorMap.end()) continue; //already saw this color buffer.palette.GetColor(ColorMap.size() % buffer.GetColorCount(), mapped); //assign user-selected colors to shape palette sequentially, loop if run out of colors debug(10, "shape color[%d] 0x%x => user-selected color [%d] 0x%x", ColorMap.size(), color.GetRGB(), ColorMap.size() % GetColorCount(), mapped.GetRGB()); ColorMap[color.GetRGB()] = mapped; //.GetRGB(); // ShapePalette.push_back(c.GetRGB()); //keep a list of unique colors in order of occurrence from origin L-R, B-T } debug(2, "w %d, h %d, #colors %d", Shapes.GetWidth(), Shapes.GetHeight(), ColorMap.size()); CachedShapeFilename = filename; //don't load same file again }
void MusicEffect::RenderCollide(RenderBuffer &buffer, int x, int bars, int startNote, int endNote, bool in, std::list<MusicEvent*>& events, int colourTreatment, bool fade) { int event = -1; for (auto it = events.begin(); it != events.end(); ++it) { event++; if ((*it)->IsEventActive(buffer.curPeriod)) { float progress = (*it)->OffsetInDuration(buffer.curPeriod); int mid = buffer.BufferHt / 2; int length = buffer.BufferHt; int leftstart, leftend; if (!in) { progress = 1.0 - progress; } leftstart = 0 - mid - 1 + progress * length; leftend = leftstart + mid; if (leftend > mid) { leftend = mid; } int loopstart = leftstart; if (loopstart < 0) { loopstart = 0; } for (int y = loopstart; y < leftend; y++) { xlColor c = xlWHITE; float proportion = ((float)y - (float)leftstart) / (float)mid; if (colourTreatment == 1) { // distinct float percolour = 1.0 / (float)buffer.GetColorCount(); for (int i = 0; i < buffer.GetColorCount(); i++) { if (proportion <= ((float)i + 1.0)*percolour) { buffer.palette.GetColor(i, c); break; } } } else if (colourTreatment == 2) { // blend buffer.GetMultiColorBlend(proportion, false, c); } else if (colourTreatment == 3) { buffer.palette.GetColor(event % buffer.GetColorCount(), c); } if (fade) { c.alpha = progress * 255; } buffer.SetPixel(x, y, c); buffer.SetPixel(x, mid - y + mid - 1, c); } } } }
void MarqueeEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int BandSize = SettingsMap.GetInt("SLIDER_Marquee_Band_Size", 0); int SkipSize = SettingsMap.GetInt("SLIDER_Marquee_Skip_Size", 0); int Thickness = SettingsMap.GetInt("SLIDER_Marquee_Thickness", 0); int stagger = SettingsMap.GetInt("SLIDER_Marquee_Stagger", 0); int mSpeed = SettingsMap.GetInt("SLIDER_Marquee_Speed", 1); int mStart = SettingsMap.GetInt("SLIDER_Marquee_Start", 0); bool reverse_dir = SettingsMap.GetBool("CHECKBOX_Marquee_Reverse"); int x_scale = SettingsMap.GetInt("SLIDER_Marquee_ScaleX", 0); int y_scale = SettingsMap.GetInt("SLIDER_Marquee_ScaleY", 0); int xc_adj = SettingsMap.GetInt("SLIDER_MarqueeXC", 0); int yc_adj = SettingsMap.GetInt("SLIDER_MarqueeYC", 0); bool pixelOffsets = SettingsMap.GetBool("CHECKBOX_Marquee_PixelOffsets"); bool wrap_x = SettingsMap.GetBool("CHECKBOX_Marquee_WrapX"); int x = 0; xlColor color; size_t colorcnt = buffer.GetColorCount(); int color_size = BandSize + SkipSize; int repeat_size = color_size * colorcnt; int eff_pos = buffer.curPeriod - buffer.curEffStartPer; x = (mSpeed * eff_pos) / 5; int corner_x1 = 0; int corner_y1 = 0; int corner_x2 = (int)((double)buffer.BufferWi * (double)x_scale / 100.0) - 1; int corner_y2 = (int)((double)buffer.BufferHt * (double)y_scale / 100.0) - 1; int sign = 1; if( reverse_dir ) { sign = -1; } int xoffset_adj = xc_adj; int yoffset_adj = yc_adj; if (!pixelOffsets) { xoffset_adj = (xoffset_adj*buffer.BufferWi)/100.0; // xc_adj is from -100 to 100 yoffset_adj = (yoffset_adj*buffer.BufferHt)/100.0; // yc_adj is from -100 to 100 } for( int thick = 0; thick < Thickness; thick++ ) { int current_color = ((x + mStart) % repeat_size) / color_size; int current_pos = (((x + mStart) % repeat_size) % color_size); if( sign < 0 ) { current_color = colorcnt - current_color - 1; } // wxLogDebug(wxString::Format("Color: %d, Pos: %d", current_color, current_pos)); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*(stagger+1) * sign); for( int x_pos = corner_x1; x_pos <= corner_x2; x_pos++ ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(x_pos + xoffset_adj, corner_y2 + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*2*sign); for( int y_pos = corner_y2; y_pos >=corner_y1 ; y_pos-- ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(corner_x2 + xoffset_adj, y_pos + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*2*sign); for( int x_pos = corner_x2; x_pos >= corner_x1; x_pos-- ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(x_pos + xoffset_adj, corner_y1 + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*2*sign); for( int y_pos = corner_y1; y_pos <= corner_y2-1; y_pos++ ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(corner_x1 + xoffset_adj, y_pos + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } corner_x1++; corner_y1++; corner_x2--; corner_y2--; } }
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); } } } } } } } }
void TwinkleEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int Count = SettingsMap.GetInt("SLIDER_Twinkle_Count", 3); int Steps = SettingsMap.GetInt("SLIDER_Twinkle_Steps", 30); bool Strobe = SettingsMap.GetBool("CHECKBOX_Twinkle_Strobe", false); bool reRandomize = SettingsMap.GetBool("CHECKBOX_Twinkle_ReRandom", false); int lights = (buffer.BufferHt*buffer.BufferWi)*(Count / 100.0); // Count is in range of 1-100 from slider bar int step = 1; if (lights > 0) { step = buffer.BufferHt*buffer.BufferWi / lights; } int max_modulo = Steps; if (max_modulo<2) max_modulo = 2; // scm could we be getting 0 passed in? int max_modulo2 = max_modulo / 2; if (max_modulo2<1) max_modulo2 = 1; if(step<1) step=1; TwinkleRenderCache *cache = (TwinkleRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new TwinkleRenderCache(); buffer.infoCache[id] = cache; } std::vector<StrobeClass> &strobe = cache->strobe; size_t colorcnt=buffer.GetColorCount(); int i = 0; if (buffer.needToInit) { buffer.needToInit = false; strobe.clear(); for (int y=0; y < buffer.BufferHt; y++) { for (int x=0; x < buffer.BufferWi; x++) { i++; if (i%step==1 || step==1) { int s = strobe.size(); strobe.resize(s + 1); strobe[s].duration = rand() % max_modulo; strobe[s].x = x; strobe[s].y = y; strobe[s].colorindex = rand() % colorcnt; } } } } for (size_t x = 0; x < strobe.size(); x++) { strobe[x].duration++; if (strobe[x].duration < 0) { continue; } if (strobe[x].duration == max_modulo) { strobe[x].duration = 0; if (reRandomize) { strobe[x].duration -= rand() % max_modulo2; strobe[x].colorindex = rand() % colorcnt; } } int i7 = strobe[x].duration; HSVValue hsv; buffer.palette.GetHSV(strobe[x].colorindex, hsv); double v = hsv.value; if(i7<=max_modulo2) { if(max_modulo2>0) v = (1.0*i7)/max_modulo2; else v =0; } else { if(max_modulo2>0)v = (max_modulo-i7)*1.0/(max_modulo2); else v = 0; } if(v<0.0) v=0.0; if(Strobe) { if(i7==max_modulo2) v = 1.0; else v = 0.0; } if (buffer.allowAlpha) { xlColor color; buffer.palette.GetColor(strobe[x].colorindex, color); color.alpha = 255.0 * v; buffer.SetPixel(strobe[x].x,strobe[x].y,color); // Turn pixel on } else { buffer.palette.GetHSV(strobe[x].colorindex, hsv); // we left the Hue and Saturation alone, we are just modifiying the Brightness Value hsv.value = v; buffer.SetPixel(strobe[x].x,strobe[x].y,hsv); // Turn pixel on } } }
void PinwheelEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { float oset = buffer.GetEffectTimeIntervalPosition(); int pinwheel_arms = SettingsMap.GetInt("SLIDER_Pinwheel_Arms", 3); int pinwheel_twist = GetValueCurveInt("Pinwheel_Twist", 0, SettingsMap, oset); int pinwheel_thickness = GetValueCurveInt("Pinwheel_Thickness", 0, SettingsMap, oset); bool pinwheel_rotation = SettingsMap.GetBool("CHECKBOX_Pinwheel_Rotation"); const std::string &pinwheel_3d = SettingsMap["CHOICE_Pinwheel_3D"]; int xc_adj = GetValueCurveInt("PinwheelXC", 0, SettingsMap, oset); int yc_adj = GetValueCurveInt("PinwheelYC", 0, SettingsMap, oset); int pinwheel_armsize = GetValueCurveInt("Pinwheel_ArmSize", 100, SettingsMap, oset); int pspeed = GetValueCurveInt("Pinwheel_Speed", 10, SettingsMap, oset); const std::string &pinwheel_style = SettingsMap["CHOICE_Pinwheel_Style"]; int xc; float tmax; HSVValue hsv, hsv1; double pos = (buffer.curPeriod - buffer.curEffStartPer) * pspeed * buffer.frameTimeInMs / 50; int degrees_per_arm = 1; if (pinwheel_arms > 0) degrees_per_arm = 360 / pinwheel_arms; float armsize = (pinwheel_armsize / 100.0); if (pinwheel_style == "New Render Method") { std::vector<size_t> colorarray; colorarray.resize(pinwheel_arms); for (int i = 0; i < pinwheel_arms; i++) { colorarray[i] = i%buffer.GetColorCount(); } xc = (int)(ceil(std::hypot(buffer.BufferWi, buffer.BufferHt) / 2)); xc_adj = xc_adj*buffer.BufferWi / 200; yc_adj = yc_adj*buffer.BufferHt / 200; int max_radius = xc * armsize; if (pinwheel_thickness == 0) pinwheel_thickness = 1; tmax = (pinwheel_thickness / 100.0)*degrees_per_arm; // Force single visible line in case width is narrower than visible float pi_180 = M_PI/180; for(int a=0; a<pinwheel_arms; a++) { int ColorIdx = a%pinwheel_arms; xlColor color; buffer.palette.GetHSV(colorarray[ColorIdx], hsv); color = xlColor(hsv); int angle = (a*degrees_per_arm); if (pinwheel_rotation == 1) // do we have CW rotation { angle = (270 - angle) + pos; } else { angle = angle - 90 - pos; } int x,y, degrees_twist; for (float r=0; r<=max_radius; r+=0.5) { degrees_twist = (r/max_radius) * pinwheel_twist; int t2 = (int)angle%degrees_per_arm; double round = (float)t2 / (float)tmax; x = floor((int)(r * buffer.cos((angle + degrees_twist) * pi_180)) + xc_adj + buffer.BufferWi / 2); y = floor((int)(r * buffer.sin((angle + degrees_twist) * pi_180)) + yc_adj + buffer.BufferHt / 2); if (buffer.palette.IsSpatial(colorarray[ColorIdx])) { buffer.palette.GetSpatialColor(colorarray[ColorIdx], xc_adj + buffer.BufferWi / 2, yc_adj + buffer.BufferHt / 2, x, y, round, max_radius, color); } buffer.SetPixel(x,y,color); } } // Draw actual pinwheel arms for (int x = 0; x < buffer.BufferWi; x++) { int x1 = x - xc_adj - (buffer.BufferWi / 2); for (int y = 0; y < buffer.BufferHt; y++) { int y1 = y - yc_adj - (buffer.BufferHt / 2); double r = std::hypot(x1, y1); if (r <= max_radius) { double degrees_twist = (r / max_radius)*pinwheel_twist; double theta = (std::atan2(x1, y1) * 180 / 3.14159) + degrees_twist; if (pinwheel_rotation == 1) // do we have CW rotation { theta = pos + theta + (tmax/2); } else { theta = pos - theta + (tmax/2); } theta = theta + 540.0; int t2 = (int)theta%degrees_per_arm; if (t2 <= tmax) { double round = (float)t2 / (float)tmax; t2 = std::abs(t2 - (tmax/2)) * 2; xlColor color; int ColorIdx2 = ((int)((theta/degrees_per_arm)))%pinwheel_arms; if (buffer.palette.IsSpatial(colorarray[ColorIdx2])) { buffer.palette.GetSpatialColor(colorarray[ColorIdx2], xc_adj + buffer.BufferWi / 2, yc_adj + buffer.BufferHt / 2, x, y, round, max_radius, color); hsv = color.asHSV(); } else { buffer.palette.GetHSV(colorarray[ColorIdx2], hsv); } hsv1=hsv; color = xlColor(hsv1); if(pinwheel_3d=="3D") { if (buffer.allowAlpha) { color.alpha = 255.0 * ((tmax - t2) / tmax); } else { hsv1.value = hsv.value * ((tmax - t2) / tmax); color = hsv1; } } else if (pinwheel_3d == "3D Inverted") { if (buffer.allowAlpha) { color.alpha = 255.0 * ((t2) / tmax); } else { hsv1.value = hsv.value * ((t2) / tmax); color = hsv1; } } buffer.SetPixel(x, y, color); } } } } } else { // Old Render Method int a,xc,ColorIdx,base_degrees; float t,tmax; float radius; HSVValue hsv,hsv0,hsv1; size_t colorcnt=buffer.GetColorCount(); xc= (int)(std::max(buffer.BufferWi, buffer.BufferHt)/2); radius = xc/100.0; for(a=1; a<=pinwheel_arms; a++) { ColorIdx=a%colorcnt; buffer.palette.GetHSV(ColorIdx, hsv); // Now go and get the hsv value for this ColorIdx if(pinwheel_rotation==1) // do we have CW rotation { base_degrees = (a-1)*degrees_per_arm + pos; // yes } else { base_degrees = (a-1)*degrees_per_arm - pos; // no, we are CCW } Draw_arm(buffer, base_degrees, xc*armsize, pinwheel_twist,hsv,xc_adj,yc_adj); if(pinwheel_thickness>0) { tmax= (pinwheel_thickness/100.0)*degrees_per_arm/2.0; hsv1=hsv; xlColor color(hsv1); for (t=1; t<=tmax; t++) { if(pinwheel_3d=="3D") { if (buffer.allowAlpha) { color.alpha = 255.0 * ((tmax-t)/tmax); } else { hsv1.value = hsv.value * ((tmax-t)/tmax); color = hsv1; } } else if(pinwheel_3d=="3D Inverted") { if (buffer.allowAlpha) { color.alpha = 255.0 * ((t)/tmax); } else { hsv1.value = hsv.value * ((t)/tmax); color = hsv1; } } Draw_arm(buffer, base_degrees-t, xc*armsize, pinwheel_twist,color,xc_adj,yc_adj); Draw_arm(buffer, base_degrees+t, xc*armsize, pinwheel_twist,color,xc_adj,yc_adj); } } } } }
void StrobeEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int Number_Strobes = SettingsMap.GetInt("SLIDER_Number_Strobes", 1); int StrobeDuration = SettingsMap.GetInt("SLIDER_Strobe_Duration", 1); int Strobe_Type = SettingsMap.GetInt("SLIDER_Strobe_Type", 0); StrobeRenderCache *cache = (StrobeRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new StrobeRenderCache(); buffer.infoCache[id] = cache; } std::vector<StrobeClass> &strobe = cache->strobe; if (StrobeDuration == 0) { StrobeDuration = 1; } if (buffer.needToInit) { buffer.needToInit = false; strobe.resize(StrobeDuration * Number_Strobes); for (int x = 0; x < strobe.size(); x++) { strobe[x].duration = -1; } } int offset = ((buffer.curPeriod-buffer.curEffStartPer) % StrobeDuration) * Number_Strobes; int ColorIdx; StrobeClass m; HSVValue hsv; size_t colorcnt=buffer.GetColorCount(); // create new strobe, randomly place a strobe for(int i = 0; i < Number_Strobes; i++) { strobe[offset + i].x =rand() % buffer.BufferWi; // randomly pick a x,y location for strobe to fire strobe[offset + i].y =rand() % buffer.BufferHt; strobe[offset + i].duration = StrobeDuration; ColorIdx=rand()%colorcnt; buffer.palette.GetHSV(ColorIdx, strobe[offset + i].hsv); // take first checked color as color of flash buffer.palette.GetColor(ColorIdx, strobe[offset + i].color); // take first checked color as color of flash } // render strobe, we go through all storbes and decide if they should be turned on int x,y,n=0; for (std::vector<StrobeClass>::iterator it=strobe.begin(); it!=strobe.end(); ++it) { n++; hsv=it->hsv; xlColor color(it->color); x=it->x; y=it->y; if(it->duration > 0) { buffer.SetPixel(x,y,color); } double v = 1.0; if(it->duration==1) { v = 0.5; } else if(it->duration==2) { v = 0.75; } if (buffer.allowAlpha) { color.alpha = 255.0 * v; } else { hsv.value *= v; color = hsv; } if(Strobe_Type==2) { int r = rand()%2; if(r==0) { buffer.SetPixel(x,y-1,color); buffer.SetPixel(x,y+1,color); } else { buffer.SetPixel(x-1,y,color); buffer.SetPixel(x+1,y,color); } } if(Strobe_Type==3) { buffer.SetPixel(x,y-1,color); buffer.SetPixel(x,y+1,color); buffer.SetPixel(x-1,y,color); buffer.SetPixel(x+1,y,color); } if(Strobe_Type==4) { int r = rand()%2; if(r==0) { buffer.SetPixel(x,y-1,color); buffer.SetPixel(x,y+1,color); buffer.SetPixel(x-1,y,color); buffer.SetPixel(x+1,y,color); } else { buffer.SetPixel(x+1,y-1,color); buffer.SetPixel(x+1,y+1,color); buffer.SetPixel(x-1,y-1,color); buffer.SetPixel(x-1,y+1,color); } } it->duration--; // decrease the frame counter on this strobe, when it gets to zero we no longer will turn it on } }
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); } } } }