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); } } } } }
//update previous bkg: //if it's a scrolling piano, scroll previous notes up one row //for eqbars, shorten them void PianoRenderCache::Piano_update_bkg(RenderBuffer &buffer, int Style, wxSize& canvas, int rowh) { debug_function(10); debug(1, "style %d", Style); xlColor c; //TODO: should use GDI+ functions on Windows //TODO: use GetData for better performance; probably doesn't matter since grid is fairly small (as compared to normal images or screen canvas) //TODO: speed switch (Style) { case -1: //initialize debug_more(5, ", init canvas %d x %d", canvas.x, canvas.y); // PrevRender.clear(); //start with blank canvas // PrevRender.resize(canvas.x * cnavas.y); //set all pixels off for (int x = 0; x < canvas.x; ++x) for (int y = 0; y < canvas.y; ++y) buffer.SetPixel(x, y, c); //clear all (background canvas is persistent while piano effect is active) return; case PIANO_STYLE_SCROLLING: //scroll up one row debug_more(5, ", scroll %d x %d up by %d", canvas.x, canvas.y, rowh); for (int x = 0; x < canvas.x; ++x) for (int y = 0; y < canvas.y; ++y) if (y < canvas.y - rowh) { debug_more(30, ", (%d,%d)->(%d,%d)", x, canvas.y - y - rowh - 1, x, canvas.y - y - 1); buffer.CopyPixel(x, canvas.y - y - rowh - 1, x, canvas.y - y - 1); } else { debug_more(30, ", (%d,%d)<-0", x, canvas.y - y - 1); buffer.SetPixel(x, canvas.y - y - 1, c); //clear bottom row, scroll others } return; case PIANO_STYLE_EQBARS: //scroll down one row (decaying bars) debug_more(5, ", scroll %d x %d down by %d", canvas.x, canvas.y, rowh); // c.Set(255, 255, 255); //debug for (int x = 0; x < canvas.x; ++x) for (int y = 0; y < canvas.y; ++y) if (y < canvas.y - rowh) { debug_more(30, ", (%d,%d)->(%d,%d)", x, y + rowh, x, y); buffer.CopyPixel(x, y + rowh, x, y); } else { debug_more(30, ", (%d,%d)<-0", x, y); buffer.SetPixel(x, y, c); //clear top row, scroll other rows } return; case PIANO_STYLE_ICICLES: //scroll down one pixel (drip) debug_more(5, ", scroll %d x %d", canvas.x, canvas.y); for (int x = 0; x < canvas.x; ++x) for (int y = 0; y < canvas.y; ++y) if (y < canvas.y - 1) { debug_more(30, ", (%d,%d)->(%d,%d)", x, y + 1, x, y); buffer.CopyPixel(x, y + 1, x, y); } // else { debug_more(30, ", (%d,%d)<-0", x, y); buffer.SetPixel(x, y, c); } //clear top pixel, scroll other pixels return; default: debug_more(5, ", no scrolling"); } }
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 } } }
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); } } } }
static void set_pixel_if_not_color(RenderBuffer &buffer, int x, int y, xlColor toColor, xlColor notColor, bool wrapx, bool wrapy) { int adjx = x; int adjy = y; if (x < 0) { if (wrapx) { adjx += buffer.BufferWi; } else { return; } } else if (x >= buffer.BufferWi) { if (wrapx) { adjx -= buffer.BufferWi; } else { return; } } if (y < 0) { if (wrapy) { adjy += buffer.BufferHt; } else { return; } } else if (y >= buffer.BufferHt) { if (wrapy) { adjy -= buffer.BufferHt; } else { return; } } // strip off alpha when comparing if (buffer.GetTempPixel(adjx, adjy).GetRGB() != notColor.GetRGB()) { buffer.SetPixel(adjx, adjy, toColor); } }
void PinwheelEffect::Draw_arm(RenderBuffer &buffer, int base_degrees,int max_radius,int pinwheel_twist, const xlColor &rgb,int xc_adj,int yc_adj) { float r,phi; int x,y,xc,yc; float pi_180 = M_PI/180; int degrees_twist,degrees; xc= (int)(buffer.BufferWi/2); yc= (int)(buffer.BufferHt/2); xc = xc + (xc_adj/100.0)*xc; // xc_adj is from -100 to 100 yc = yc + (yc_adj/100.0)*yc; for(r=0.0; r<=max_radius; r+=0.5) { degrees_twist=(r/max_radius)*pinwheel_twist; degrees = base_degrees + degrees_twist; phi = degrees * pi_180; x = r * buffer.cos (phi) + xc; y = r * buffer.sin (phi) + yc; buffer.SetPixel(x, y, rgb); } }
void TendrilEffect::Render(RenderBuffer &buffer, int movement, int tunemovement, int movementSpeed, int thickness, float friction, float dampening, float tension, int trails, int length) { buffer.drawingContext->Clear(); if (friction < 0.4) { friction = 0.4; } if (friction > 0.6) { friction = 0.6; } if (dampening < 0) { dampening = 0; } if (dampening > 0.5) { dampening = 0.5; } if (tension < 0.96) { tension = 0.96; } if (tension > 0.999) { tension = 0.999; } TendrilRenderCache *cache = (TendrilRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new TendrilRenderCache(); buffer.infoCache[id] = cache; } int &_movement = cache->_movement; int &_tunemovement = cache->_tunemovement; int &_mv1 = cache->_mv1; int &_mv2 = cache->_mv2; int &_mv3 = cache->_mv3; int &_mv4 = cache->_mv4; int &_thickness = cache->_thickness; int &_trails = cache->_trails; int &_length = cache->_length; float &_friction = cache->_friction; float &_dampening = cache->_dampening; float &_tension = cache->_tension; xlColor &_colour = cache->_colour; Tendril* &_tendril = cache->_tendril; xlColor color1; buffer.palette.GetColor(0, color1); if (_tendril == NULL || _movement != movement || _tunemovement != tunemovement || _thickness != thickness || _friction != friction || _dampening != dampening || _tension != tension || _trails != trails || _length != length || _colour != color1) { if (_tendril != NULL) { delete _tendril; } _thickness = thickness; _friction = friction; _dampening = dampening; _tension = tension; _trails = trails; _length = length; _colour = color1; wxPoint start(buffer.BufferWi/2, buffer.BufferHt/2); _tendril = new Tendril(_friction, _trails, _length, _dampening, _tension, -1, -1, &start, _colour, _thickness, buffer.BufferWi, buffer.BufferHt); if (_movement != movement || _tunemovement != tunemovement) { switch(movement) { case 1: // random // no initialisation break; case 2: // corners _mv1 = 0; // current x _mv2 = 0; // current y _mv3 = 0; // corner _mv4 = tunemovement; // movement amount if (_mv4 == 0) { _mv4 = 1; } break; case 3: // circles _mv1 = 0; // radians _mv2 = std::min(buffer.BufferWi, buffer.BufferHt) / 2; // radius _mv3 = tunemovement * 3; if (_mv3 == 0) { _mv3 = 1; } break; case 4: // horizontal zig zag _mv1 = 0; // current y _mv2 = (double)tunemovement * 1.5; if (_mv2 == 0) { _mv2 = 1; } _mv3 = 1; // direction break; case 5: // vertical zig zag _mv1 = 0; // current x _mv2 = (double)tunemovement * 1.5; _mv3 = 1; // direction break; } } _movement = movement; _tunemovement = tunemovement; } const double PI = 3.141592653589793238463; int speed = 10 - movementSpeed; if (speed <= 0 || buffer.curPeriod % speed == 0) { switch(_movement) { case 1: _tendril->UpdateRandomMove(_tunemovement); break; case 2: switch(_mv3) { case 0: _mv1+=std::max(buffer.BufferWi/_mv4,1); if (_mv1 >= buffer.BufferWi - buffer.BufferWi / _mv4) { _mv3++; } break; case 1: _mv2+=std::max(buffer.BufferHt/_mv4,1); if (_mv2 >= buffer.BufferHt - buffer.BufferHt / _mv4) { _mv3++; } break; case 2: _mv1-=std::max(buffer.BufferWi/_mv4,1); if (_mv1 <= buffer.BufferWi / _mv4) { _mv3++; } break; case 3: _mv2-=std::max(buffer.BufferHt/_mv4,1); if (_mv2 <= buffer.BufferHt / _mv4) { _mv3 = 0; } break; } _tendril->Update(_mv1, _mv2); break; case 3: _mv1++; if (_mv1 > _mv3) { _mv1 = 0; } { int x = (double)_mv2 * cos((double)_mv1 * 2.0 * PI / (double)_mv3) + (double)buffer.BufferWi / 2.0; int y = (double)_mv2 * sin((double)_mv1 * 2.0 * PI / (double)_mv3) + (double)buffer.BufferHt / 2.0; _tendril->Update(x, y); } break; case 4: { _mv1 = _mv1 + _mv3; int x = sin(std::max((double)buffer.BufferHt / (double)_mv2, 0.5) * PI * (double)_mv1 / (double)buffer.BufferHt) * (double)buffer.BufferWi / 2.0 + (double)buffer.BufferWi / 2.0; if (_mv1 >= buffer.BufferHt || _mv1 <= 0) { _mv3 = _mv3 * -1; } if (_mv3 < 0) { x = buffer.BufferWi - x; } _tendril->Update(x, _mv1); } break; case 5: { _mv1 = _mv1 + _mv3; int y = sin(std::max((double)buffer.BufferWi / (double)_mv2, 0.5) * PI * (double)_mv1 / (double)buffer.BufferWi) * (double)buffer.BufferHt / 2.0 + (double)buffer.BufferHt / 2.0; if (_mv1 >= buffer.BufferWi || _mv1 <= 0) { _mv3 = _mv3 * -1; } if (_mv3 < 0) { y = buffer.BufferHt - y; } _tendril->Update(_mv1, y); } break; } } _tendril->Draw(buffer.drawingContext); wxImage * image = buffer.drawingContext->FlushAndGetImage(); bool hasAlpha = image->HasAlpha(); xlColor c; for(int y=0; y<buffer.BufferHt; y++) { for(int x=0; x< buffer.BufferWi; x++) { if (hasAlpha) { c.Set(image->GetRed(x,y),image->GetGreen(x,y),image->GetBlue(x,y),image->GetAlpha(x,y)); } else { c.Set(image->GetRed(x,y),image->GetGreen(x,y),image->GetBlue(x,y), 255); } buffer.SetPixel(x, y, c); } } }
void GalaxyEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int center_x = SettingsMap.GetInt("SLIDER_Galaxy_CenterX"); int center_y = SettingsMap.GetInt("SLIDER_Galaxy_CenterY"); int start_radius = SettingsMap.GetInt("SLIDER_Galaxy_Start_Radius"); int end_radius = SettingsMap.GetInt("SLIDER_Galaxy_End_Radius"); int start_angle = SettingsMap.GetInt("SLIDER_Galaxy_Start_Angle"); int revolutions = SettingsMap.GetInt("SLIDER_Galaxy_Revolutions"); int start_width = SettingsMap.GetInt("SLIDER_Galaxy_Start_Width"); int end_width = SettingsMap.GetInt("SLIDER_Galaxy_End_Width"); int duration = SettingsMap.GetInt("SLIDER_Galaxy_Duration"); int acceleration = SettingsMap.GetInt("SLIDER_Galaxy_Accel"); bool reverse_dir = SettingsMap.GetBool("CHECKBOX_Galaxy_Reverse"); bool blend_edges = SettingsMap.GetBool("CHECKBOX_Galaxy_Blend_Edges"); bool inward = SettingsMap.GetBool("CHECKBOX_Galaxy_Inward"); if( revolutions == 0 ) return; std::vector< std::vector<double> > temp_colors_pct(buffer.BufferWi, std::vector<double>(buffer.BufferHt)); std::vector< std::vector<double> > pixel_age(buffer.BufferWi, std::vector<double>(buffer.BufferHt)); double eff_pos = buffer.GetEffectTimeIntervalPosition(); int num_colors = buffer.palette.Size(); xlColor color, c_old, c_new; HSVValue hsv1; double eff_pos_adj = buffer.calcAccel(eff_pos, acceleration); double revs = (double)revolutions; double pos_x = buffer.BufferWi * center_x/100.0; double pos_y = buffer.BufferHt * center_y/100.0; double head_duration = duration/100.0; // time the head is in the frame double tail_length = revs * (1.0 - head_duration); double color_length = tail_length / num_colors; if(color_length < 1.0) color_length = 1.0; double tail_end_of_tail = ((revs + tail_length) * eff_pos_adj) - tail_length; double head_end_of_tail = tail_end_of_tail + tail_length; double radius1 = start_radius; double radius2 = end_radius; double width1 = start_width; double width2 = end_width; double step = buffer.GetStepAngle(radius1, radius2); for( int x = 0; x < buffer.BufferWi; x++ ) { for( int y = 0; y < buffer.BufferHt; y++ ) { temp_colors_pct[x][y] = 0.0; pixel_age[x][y] = 0.0; } } buffer.ClearTempBuf(); double last_check = (inward ? std::min(head_end_of_tail,revs) : std::max(0.0, tail_end_of_tail) ) + (double)start_angle; for( double i = (inward ? std::min(head_end_of_tail,revs) : std::max(0.0, tail_end_of_tail)); (inward ? i >= std::max(0.0, tail_end_of_tail) : i <= std::min(head_end_of_tail,revs)); (inward ? i -= step : i += step) ) { double adj_angle = i + (double)start_angle; if( reverse_dir ) { adj_angle *= -1.0; } double color_val = (head_end_of_tail-i) / color_length; int color_int = (int)color_val; double color_pct = color_val - (double)color_int; int color2 = std::min(color_int+1, num_colors-1); if( color_int < color2 ) { buffer.Get2ColorBlend(color_int, color2, std::min( color_pct, 1.0), color); } else { buffer.palette.GetColor(color2, color); } HSVValue hsv(color); double full_brightness = hsv.value; double pct = i/revs; double current_radius = radius2 * pct + radius1 * (1.0 - pct); double current_width = width2 * pct + width1 * (1.0 - pct); double half_width = current_width / 2.0; double inside_radius = current_radius - half_width; for( double r = inside_radius; ; r += 0.5 ) { if( r > current_radius ) r = current_radius; double x1 = buffer.sin(ToRadians(adj_angle)) * r + (double)pos_x; double y1 = buffer.cos(ToRadians(adj_angle)) * r + (double)pos_y; double outside_radius = current_radius + (current_radius - r); double x2 = buffer.sin(ToRadians(adj_angle)) * outside_radius + (double)pos_x; double y2 = buffer.cos(ToRadians(adj_angle)) * outside_radius + (double)pos_y; double color_pct2 = (r-inside_radius)/(current_radius-inside_radius); if( blend_edges ) { if( hsv.value > 0.0 ) { if ((int)x1 >= 0 && (int)x1 < buffer.BufferWi && (int)y1 >= 0 && (int)y1 < buffer.BufferHt) { buffer.SetTempPixel((int)x1,(int)y1,color); temp_colors_pct[(int)x1][(int)y1] = color_pct2; pixel_age[(int)x1][(int)y1] = adj_angle; } if ((int)x2 >= 0 && (int)x2 < buffer.BufferWi && (int)y2 >= 0 && (int)y2 < buffer.BufferHt) { buffer.SetTempPixel((int)x2,(int)y2,color); temp_colors_pct[(int)x2][(int)y2] = color_pct2; pixel_age[(int)x2][(int)y2] = adj_angle; } } } else { hsv.value = full_brightness * color_pct2; if( hsv.value > 0.0 ) { buffer.SetPixel(x1,y1,hsv); buffer.SetPixel(x2,y2,hsv); } } if( r >= current_radius ) break; } // blend old data down into final buffer if( blend_edges && ( (inward ? (last_check-adj_angle) : (adj_angle-last_check)) >= 90.0) ) { for( int x = 0; x < buffer.BufferWi; x++ ) { for( int y = 0; y < buffer.BufferHt; y++ ) { if( temp_colors_pct[x][y] > 0.0 && ((inward ? (pixel_age[x][y]-adj_angle) : (adj_angle-pixel_age[x][y])) >= 180.0) ) { buffer.GetTempPixel(x,y,c_new); buffer.GetPixel(x,y,c_old); buffer.Get2ColorAlphaBlend(c_old, c_new, temp_colors_pct[x][y], color); buffer.SetPixel(x,y,color); temp_colors_pct[x][y] = 0.0; pixel_age[x][y] = 0.0; } } } last_check = adj_angle; } } // blend remaining data down into final buffer if( blend_edges ) { for( int x = 0; x < buffer.BufferWi; x++ ) { for( int y = 0; y < buffer.BufferHt; y++ ) { if( temp_colors_pct[x][y] > 0.0 ) { buffer.GetTempPixel(x,y,c_new); buffer.GetPixel(x,y,c_old); buffer.Get2ColorAlphaBlend(c_old, c_new, temp_colors_pct[x][y], color); buffer.SetPixel(x,y,color); } } } } }
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 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 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); } } } }
bool PianoRenderCache::Piano_RenderKey(RenderBuffer &buffer, Sprite* sprite, std::hash_map<wxPoint_, int>& drawn, int style, wxSize& canvas, wxSize& keywh, const wxString &placement, bool clip) //bool RgbEffects::Sprite::render(wxSize& keywh, wxSize& BufferWH_int, int yscroll, bool Clipping) { debug_function(9); //hash_map<pair<wxPoint, wxSize>, int>& drawn) //PIANO_STYLE_KEYS sprites have 2 states: on (down) and off (up); draw all sprites; top view or edge view int drawstate = sprite->ani_state++; //bump to next active (animation) state if (!drawstate) sprite->ani_state = 0; //stay in inactive state else // if ((xy.size() == 1) && (drawstate == -1)) return false; //inactive on/off sprite; don't need tp draw anything if (drawstate >= sprite->xy.size()) //end of animation // if (it->repeat > 0) drawstate = 0; //loop immediately // else if (it->repeat < 0) drawstate = -rnd(); //loop with delay /*else*/ drawstate = sprite->xy.size() - 1; //stay at last state; don't loop // wxPoint realxy = sprite->destxy; // realxy.y += yscroll; //scrolling debug_more(30, ", dest (%d => %d, %d), #drawn %d", sprite->destxy.x, (clip? sprite->destxy.x: sprite->destxy.x % canvas.x), sprite->destxy.y, drawn.size()); if (clip) if ((sprite->destxy.x >= buffer.BufferWi) || (sprite->destxy.y >= buffer.BufferHt) || (sprite->destxy.x + keywh.x < 0) || (sprite->destxy.y + keywh.y < 0)) return false; //outside of visible rect // debug_more(30, ", here1"); wxPoint_ where = sprite->destxy.y * 65536 + (clip? sprite->destxy.x: sprite->destxy.x % canvas.x); //wrap on even key boundary // debug_more(30, ", here2"); if ((style != PIANO_STYLE_ANIMAGE) && (drawn.find(where) != drawn.end()) && (drawstate <= drawn[where])) { debug_more(30, ", already drawn[0x%x]=%d vs %d", where, drawn[where], drawstate); return false; } //do not redraw older states in same location drawn[where] = drawstate; //remember highest state drawn in this location //don't draw overlapping regions more than once // SetPixel(x-xoffset,(state % ((imght+BufferHt)*speedfactor)) / speedfactor-y,c); //moving up // SetPixel(x-xoffset,BufferHt+imght-y-(state % ((imght+BufferHt)*speedfactor)) / speedfactor,c); //moving down //copy sprite image to pixel buffer, scale up/down: //iterate thru target pixels and pull from sprite in case sizes don't match (need to set all target pixels, but okay to skip some source pixels) float xscale = (float)sprite->wh.x / keywh.x, yscale = (float)sprite->wh.y / keywh.y; //src -> dest scale factor // debug_more(30, ", here3"); //TODO: use wxImage.GetData for better performance? int xofs = !clip? (buffer.BufferWi % (7 * keywh.x)) / 2: 0; //center keys if not clipped if (WantHistory(style)) debug(20, "draw sprite '%s': set x/y %d/%d + %d/%d to 0x%x", (const char*)sprite->name.ToStdString().c_str(), sprite->destxy.x, sprite->destxy.y, keywh.x, keywh.y, drawstate? sprite->on.GetRGB(): sprite->off.GetRGB()); //.Flush(true); else debug(20, "draw sprite '%s': copy from x/y[%d/%d] %d/%d + %d/%d => x/y %d/%d + %d/%d, x/y scale = %f/%f", (const char*)sprite->name.ToStdString().c_str(), drawstate, sprite->xy.size(), sprite->xy[drawstate].x, sprite->xy[drawstate].y, sprite->wh.x, sprite->wh.y, sprite->destxy.x, sprite->destxy.y, keywh.x, keywh.y, 1.0 / xscale, 1.0 / yscale); //.Flush(true); for (int x = 0; x < keywh.x; ++x) //copying to it->w columns in dest for (int y = 0; y < keywh.y; ++y) //copying to it->h rows in dest; vert scaling is more likely, so make Y the inner loop for better pixel caching { // static xlColor cached_rgb; //cached mapped pixel color // static wxPoint cached_xy(-1, -1); wxPoint src_xy(sprite->xy[drawstate].x + x * xscale, sprite->xy[drawstate].y + y * yscale); //TODO: scale doesn't make sense for all cases src_xy.y = Shapes.GetHeight() - src_xy.y - 1; //whoops, origin is top left but wanted bottom left bool transparent = 0; if (WantHistory(style)) cached_rgb = drawstate? sprite->on: sprite->off; //kludge: fill rect with same color to avoid losing pixels due to scaling else if ((src_xy.x != cached_xy.x) || (src_xy.y != cached_xy.y)) //update cached pixel info { cached_xy = src_xy; //prev_xy.x = src_xy.x; prev_y = srcy; //not sure how expensive wx pixel functions are, so cache current pixel info just in case; aliasing/averaging and color mapping also makes thiss more expensive if (Shapes.IsTransparent(src_xy.x, src_xy.y)) transparent = 1; //-1; //-1 matches white, so use + instead else { // xlColor c; //TODO: tile, center, anti-aliasing cached_rgb.Set(Shapes.GetRed(src_xy.x, src_xy.y), Shapes.GetGreen(src_xy.x, src_xy.y), Shapes.GetBlue(src_xy.x, src_xy.y)); //NOTE: need to do pixel merging if scale is not 1:1 if (!ColorMap.empty()) cached_rgb = ColorMap[cached_rgb.GetRGB()]; //map to user-selected colors } debug_more(20, ", LK(%d,%d)", cached_xy.x, cached_xy.y); } if (transparent == 1 /*-1*/) continue; //don't need to draw pixel int wrapx = sprite->destxy.x + x, scrolly = sprite->destxy.y; // if (style == PIANO_STYLE_ANIMAGE) { wrapx *= xscale; scrolly *= yscale; } if (!clip) wrapx %= canvas.x; //wrap on even key boundary // if ((style == PIANO_STYLE_ICICLES) || (style == PIANO_STYLE_EQBARS)) scrolly += canvas.y - keywh.y; //draw at top instead of bottom if (style == PIANO_STYLE_ICICLES) scrolly += canvas.y - keywh.y; //draw at top instead of bottom // debug_more(20, ", %d+%d vs. %d-%d? %d", xofs, wrapx, BufferWi, xofs, xofs + wrapx < BufferWi - xofs); // if (!clip) wrapx = (wrapx + 2 * xofs) % BufferWi - 2 * xofs; //wrap within reduced area, not expanded area debug_more(20, ", (%d,%d)<-0x%x", wrapx, sprite->destxy.y + y, cached_rgb.GetRGB()); if (xofs + wrapx < buffer.BufferWi - xofs) buffer.SetPixel(xofs + wrapx, sprite->destxy.y + y, cached_rgb); //no vertical wrap, only horizontal wrap } // debug.Flush(true); return true; }
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 OnEffect::Render(Effect *eff, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int start = SettingsMap.GetInt(TEXTCTRL_Eff_On_Start, 100); int end = SettingsMap.GetInt(TEXTCTRL_Eff_On_End, 100); bool shimmer = SettingsMap.GetInt(CHECKBOX_On_Shimmer, 0) > 0; float cycles = SettingsMap.GetDouble(TEXTCTRL_On_Cycles, 1.0); int x,y; int cidx = 0; if (shimmer) { int tot = buffer.curPeriod - buffer.curEffStartPer; if (tot % 2) { if (buffer.palette.Size() <= 1) { return; } cidx = 1; } } bool spatialcolour = buffer.palette.IsSpatial(cidx); double adjust = buffer.GetEffectTimeIntervalPosition(cycles); xlColor color; if (start == 100 && end == 100) { buffer.palette.GetColor(cidx, color); } else { HSVValue hsv; buffer.palette.GetHSV(cidx,hsv); double d = adjust; d = start + (end - start) * d; d = d / 100.0; hsv.value = hsv.value * d; color = hsv; } int transparency = GetValueCurveInt("On_Transparency", 0, SettingsMap, adjust); if (transparency) { transparency *= 255; transparency /= 100; color.alpha = 255 - transparency; } ///////////////////////// DMX Support //////////////////////// // if the model is a DMX model this will write the color into // the proper red, green, and blue channels. ////////////////////////////////////////////////////////////// if (buffer.cur_model != "") { Model* model_info = buffer.frame->AllModels[buffer.cur_model]; if (model_info != nullptr) { if( model_info->GetDisplayAs() == "DMX" ) { xlColor c; DmxModel* dmx = (DmxModel*)model_info; int red_channel = dmx->GetRedChannel(); int grn_channel = dmx->GetGreenChannel(); int blu_channel = dmx->GetBlueChannel(); if( red_channel != 0 ) { c.red = color.red; c.green = color.red; c.blue = color.red; buffer.SetPixel(red_channel-1, 0, c); } if( grn_channel != 0 ) { c.red = color.green; c.green = color.green; c.blue = color.green; buffer.SetPixel(grn_channel-1, 0, c); } if( blu_channel != 0 ) { c.red = color.blue; c.green = color.blue; c.blue = color.blue; buffer.SetPixel(blu_channel-1, 0, c); } return; } } } ////////////////////////////////////////////////////////////// ///////////////////// End DMX Support //////////////////////// ////////////////////////////////////////////////////////////// //Every Node set to selected color for (x=0; x<buffer.BufferWi; x++) { for (y=0; y<buffer.BufferHt; y++) { if (spatialcolour) { buffer.palette.GetSpatialColor(cidx, (float)x / (float)buffer.BufferWi, (float)y / (float)buffer.BufferHt, color); if (start == 100 && end == 100) { } else { HSVValue hsv = color.asHSV(); double d = adjust; d = start + (end - start) * d; d = d / 100.0; hsv.value = hsv.value * d; color = hsv; } if (transparency) { color.alpha = 255 - transparency; } } buffer.SetPixel(x,y,color); } } if (shimmer || cycles != 1.0) { std::lock_guard<std::recursive_mutex> lock(eff->GetBackgroundDisplayList().lock); eff->GetBackgroundDisplayList().resize((buffer.curEffEndPer - buffer.curEffStartPer + 1) * 6); buffer.CopyPixelsToDisplayListX(eff, 0, 0, 0); } else if (buffer.needToInit) { std::lock_guard<std::recursive_mutex> lock(eff->GetBackgroundDisplayList().lock); eff->GetBackgroundDisplayList().resize(6); if (start == 100 && end == 100) { buffer.palette.GetColor(0, color); buffer.SetDisplayListHRect(eff, 0, 0.0, 0.0, 1.0, 1.0, color, color); } else { HSVValue hsv; buffer.palette.GetHSV(cidx,hsv); hsv.value = hsv.value * start / 100.0; color = hsv; buffer.palette.GetHSV(cidx,hsv); hsv.value = hsv.value * end / 100.0; buffer.SetDisplayListHRect(eff, 0, 0.0, 0.0, 1.0, 1.0, color, xlColor(hsv)); } buffer.needToInit = false; } }
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 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 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 ShockwaveEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int center_x = SettingsMap.GetInt("SLIDER_Shockwave_CenterX", 0); int center_y = SettingsMap.GetInt("SLIDER_Shockwave_CenterY", 0); int start_radius = SettingsMap.GetInt("SLIDER_Shockwave_Start_Radius", 0); int end_radius = SettingsMap.GetInt("SLIDER_Shockwave_End_Radius", 0); int start_width = SettingsMap.GetInt("SLIDER_Shockwave_Start_Width", 0); int end_width = SettingsMap.GetInt("SLIDER_Shockwave_End_Width", 0); int acceleration = SettingsMap.GetInt("SLIDER_Shockwave_Accel", 0); bool blend_edges = SettingsMap.GetBool("CHECKBOX_Shockwave_Blend_Edges"); std::vector< std::vector<double> > temp_colors_pct(buffer.BufferWi, std::vector<double>(buffer.BufferHt)); double eff_pos = buffer.GetEffectTimeIntervalPosition(); int num_colors = buffer.palette.Size(); if( num_colors == 0 ) num_colors = 1; xlColor color, c_old, c_new; double eff_pos_adj = buffer.calcAccel(eff_pos, acceleration); double blend_pct = 1.0 / (num_colors-1); double color_pct1 = eff_pos_adj / blend_pct; int color_index = (int)color_pct1; blend_pct = color_pct1 - (double)color_index; buffer.Get2ColorBlend(color_index, std::min(color_index+1,num_colors-1), std::min( blend_pct, 1.0), color); double pos_x = buffer.BufferWi * center_x/100.0; double pos_y = buffer.BufferHt * center_y/100.0; double radius1 = start_radius; double radius2 = end_radius; double radius_center = radius1 + (radius2 - radius1) * eff_pos_adj; double half_width = (start_width + (end_width - start_width) * eff_pos_adj) / 2.0; radius1 = radius_center - half_width; radius2 = radius_center + half_width; double step = buffer.GetStepAngle(radius1, radius2); for( int x = 0; x < buffer.BufferWi; x++ ) { for( int y = 0; y < buffer.BufferHt; y++ ) { temp_colors_pct[x][y] = 0.0; } } buffer.ClearTempBuf(); for( double current_angle = 0.0; current_angle <= 360.0; current_angle += step ) { for( double r = std::max(0.0, radius1); r <= radius2; r += 0.5 ) { double x1 = buffer.sin(ToRadians(current_angle)) * r + (double)pos_x; double y1 = buffer.cos(ToRadians(current_angle)) * r + (double)pos_y; if( blend_edges ) { double color_pct = 1.0 - std::abs(r-radius_center)/half_width; if( color_pct > 0.0 ) { if (x1 >= 0 && x1 < buffer.BufferWi && y1 >= 0 && y1 < buffer.BufferHt) { if (buffer.allowAlpha) { color.alpha = 255.0 * color_pct; buffer.SetPixel((int)x1,(int)y1,color); } else { temp_colors_pct[(int)x1][(int)y1] = color_pct; buffer.SetTempPixel((int)x1,(int)y1,color); } } } } else { buffer.SetPixel((int)x1,(int)y1,color); } } } // blend element data into final buffer if( blend_edges && !buffer.allowAlpha ) { for( int x = 0; x < buffer.BufferWi; x++ ) { for( int y = 0; y < buffer.BufferHt; y++ ) { if( temp_colors_pct[x][y] > 0.0 ) { buffer.GetTempPixel(x,y,c_new); buffer.GetPixel(x,y,c_old); buffer.Get2ColorAlphaBlend(c_old, c_new, temp_colors_pct[x][y], color); buffer.SetPixel(x,y,color); temp_colors_pct[x][y] = 0.0; } } } } }
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 ColorWashEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { bool HorizFade = SettingsMap.GetBool(CHECKBOX_ColorWash_HFade); bool VertFade = SettingsMap.GetBool(CHECKBOX_ColorWash_VFade); float cycles = SettingsMap.GetDouble(TEXTCTRL_ColorWash_Cycles, 1.0); bool EntireModel = SettingsMap.GetInt(CHECKBOX_ColorWash_EntireModel, 1); int x1 = SettingsMap.GetInt(SLIDER_ColorWash_X1, -50); int y1 = SettingsMap.GetInt(SLIDER_ColorWash_Y1, -50); int x2 = SettingsMap.GetInt(SLIDER_ColorWash_X2, 50); int y2 = SettingsMap.GetInt(SLIDER_ColorWash_Y2, 50); bool shimmer = SettingsMap.GetInt(CHECKBOX_ColorWash_Shimmer, 0); bool circularPalette = SettingsMap.GetInt(CHECKBOX_ColorWash_CircularPalette, 0); int x,y; xlColor color, orig; double position = buffer.GetEffectTimeIntervalPosition(cycles); buffer.GetMultiColorBlend(position, circularPalette, color); int startX = 0; int startY = 0; int endX = buffer.BufferWi - 1; int endY = buffer.BufferHt - 1; if (!EntireModel) { startX = std::min(x1, x2); endX = std::max(x1, x2); startY = std::min(y1, y2); endY = std::max(y1, y2); startX = std::round(double(buffer.BufferWi - 0.5) * (double)startX / 100.0); endX = std::round(double(buffer.BufferWi - 0.5) * (double)endX / 100.0); startY = std::round(double(buffer.BufferHt - 0.5) * (double)startY / 100.0); endY = std::round(double(buffer.BufferHt - 0.5) * (double)endY / 100.0); startX = std::max(startX, 0); endX = std::min(endX, buffer.BufferWi - 1); startY = std::max(startY, 0); endY = std::min(endY, buffer.BufferHt - 1); } int tot = buffer.curPeriod - buffer.curEffStartPer; if (!shimmer || (tot % 2) == 0) { double HalfHt=double(endY - startY)/2.0; double HalfWi=double(endX - startX)/2.0; orig = color; HSVValue hsvOrig = color.asHSV(); xlColor color2 = color; for (x=startX; x <= endX; x++) { HSVValue hsv = hsvOrig; if (HorizFade) { if (buffer.allowAlpha) { color.alpha = (double)orig.alpha*(1.0-std::abs(HalfWi-x-startX)/HalfWi); } else { hsv.value*=1.0-std::abs(HalfWi-x-startX)/HalfWi; color = hsv; } } color2.alpha = color.alpha; for (y=startY; y<=endY; y++) { if (VertFade) { if (buffer.allowAlpha) { color.alpha = (double)color2.alpha*(1.0-std::abs(HalfHt-(y-startY))/HalfHt); } else { HSVValue hsv2 = hsv; hsv2.value*=1.0-std::abs(HalfHt-(y-startY))/HalfHt; color = hsv2; } } buffer.SetPixel(x, y, color); } } } else { orig = xlBLACK; } wxMutexLocker lock(effect->GetBackgroundDisplayList().lock); if (VertFade || HorizFade) { effect->GetBackgroundDisplayList().resize((buffer.curEffEndPer - buffer.curEffStartPer + 1) * 4 * 2); int total = buffer.curEffEndPer - buffer.curEffStartPer + 1; double x1 = double(buffer.curPeriod - buffer.curEffStartPer) / double(total); double x2 = (buffer.curPeriod - buffer.curEffStartPer + 1.0) / double(total); int idx = (buffer.curPeriod - buffer.curEffStartPer) * 8; buffer.SetDisplayListVRect(effect, idx, x1, 0.0, x2, 0.5, xlBLACK, orig); buffer.SetDisplayListVRect(effect, idx + 4, x1, 0.5, x2, 1.0, orig, xlBLACK); } else { effect->GetBackgroundDisplayList().resize((buffer.curEffEndPer - buffer.curEffStartPer + 1) * 4); int midX = (startX + endX) / 2; int midY = (startY + endY) / 2; buffer.CopyPixelsToDisplayListX(effect, midY, midX, midX); } }
void TreeEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int Branches = SettingsMap.GetInt("SLIDER_Tree_Branches", 1); int tspeed = SettingsMap.GetInt("SLIDER_Tree_Speed", 10); int effectState = (buffer.curPeriod - buffer.curEffStartPer) * tspeed * buffer.frameTimeInMs / 50; int x,y,i,r,ColorIdx,pixels_per_branch; int maxFrame,mod,branch,row,b,f_mod,m,frame; int number_garlands,f_mod_odd,s_odd_row,odd_even; float V,H; number_garlands=1; xlColor color; if(Branches<1) Branches=1; pixels_per_branch=(int)(0.5+buffer.BufferHt/Branches); if(pixels_per_branch<1) pixels_per_branch=1; maxFrame=(Branches+1) * buffer.BufferWi; if(effectState>0 && maxFrame>0) frame = (effectState/4)%maxFrame; else frame=1; i=0; for (y=0; y<buffer.BufferHt; y++) // For my 20x120 megatree, BufferHt=120 { for (x=0; x<buffer.BufferWi; x++) // BufferWi=20 in the above example { if(pixels_per_branch>0) mod=y%pixels_per_branch; else mod=0; if(mod==0) mod=pixels_per_branch; V=1-(1.0*mod/pixels_per_branch)*0.70; i++; ColorIdx=0; buffer.palette.GetColor(ColorIdx, color); // Now go and get the hsv value for this ColorIdx if (buffer.allowAlpha) { color.alpha = 255.0 * V; } else { HSVValue hsv = color.asHSV(); hsv.value = V; // we have now set the color for the background tree color = hsv; } // $orig_rgbval=$rgb_val; branch = (int)((y-1)/pixels_per_branch); row = pixels_per_branch-mod; // now row=0 is bottom of branch, row=1 is one above bottom // mod = which pixel we are in the branch // mod=1,row=pixels_per_branch-1 top picrl in branch // mod=2, second pixel down into branch // mod=pixels_per_branch,row=0 last pixel in branch // // row = 0, the $p is in the bottom row of tree // row =1, the $p is in second row from bottom b = (int) ((effectState)/buffer.BufferWi)%Branches; // what branch we are on based on frame # // // b = 0, we are on bottomow row of tree during frames 1 to BufferWi // b = 1, we are on second row from bottom, frames = BufferWi+1 to 2*BufferWi // b = 2, we are on third row from bottome, frames - 2*BufferWi+1 to 3*BufferWi f_mod = (effectState/4)%buffer.BufferWi; // if(f_mod==0) f_mod=BufferWi; // f_mod is to BufferWi-1 on each row // f_mod == 0, left strand of this row // f_mod==BufferWi, right strand of this row // m=(x%6); if(m==0) m=6; // use $m to indicate where we are in horizontal pattern // m=1, 1sr strand // m=2, 2nd strand // m=6, last strand in 6 strand pattern r=branch%5; H = r/4.0; odd_even=b%2; s_odd_row = buffer.BufferWi-x+1; f_mod_odd = buffer.BufferWi-f_mod+1; if(branch<=b && x<=frame && // for branches below or equal to current row (((row==3 || (number_garlands==2 && row==6)) && (m==1 || m==6)) || ((row==2 || (number_garlands==2 && row==5)) && (m==2 || m==5)) || ((row==1 || (number_garlands==2 && row==4)) && (m==3 || m==4)) )) if((odd_even ==0 && x<=f_mod) || (odd_even ==1 && s_odd_row<=f_mod)) { HSVValue hsv; hsv.hue = H; hsv.saturation=1.0; hsv.value=1.0; color = hsv; } // if(branch>b) // { // return $rgb_val; // for branches below current, dont dont balnk anything out // } // else if(branch==b) // { // if(odd_even ==0 && x>f_mod) // { // $rgb_val=$orig_rgbval;// we are even row ,counting from bottom as zero // } // if(odd_even ==1 && s_odd_row>f_mod) // { // $rgb_val=$orig_rgbval;// we are even row ,counting from bottom as zero // } // } //if($branch>$b) $rgb_val=$orig_rgbval; // erase rows above our current row. // Yes, so now decide on what color it should be // we left the Hue and Saturation alone, we are just modifiying the Brightness Value buffer.SetPixel(x,y,color); // Turn pixel on } } }
void VideoEffect::Render(RenderBuffer &buffer, const std::string& filename, double starttime, bool aspectratio, std::string durationTreatment) { VideoRenderCache *cache = (VideoRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new VideoRenderCache(); buffer.infoCache[id] = cache; } std::string &_filename = cache->_filename; int &_starttime = cache->_starttime; bool &_aspectratio = cache->_aspectratio; std::string &_durationTreatment = cache->_durationTreatment; int &_loops = cache->_loops; int &_frameMS = cache->_frameMS; VideoReader* &_videoreader = cache->_videoreader; if (_starttime != starttime) { _starttime = starttime; } // we always reopen video on first frame or if it is not open or if the filename has changed if (buffer.needToInit) { buffer.needToInit = false; _filename = filename; _aspectratio = aspectratio; _durationTreatment = durationTreatment; _loops = 0; _frameMS = buffer.frameTimeInMs; if (_videoreader != NULL) { delete _videoreader; _videoreader = NULL; } if (buffer.BufferHt == 1) { log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); logger_base.warn("VideoEffect::Cannot render video onto a 1 pixel high model. Have you set it to single line?"); } else if (wxFileExists(_filename)) { // have to open the file _videoreader = new VideoReader(_filename, buffer.BufferWi, buffer.BufferHt, _aspectratio); if (_videoreader == NULL) { log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); logger_base.warn("VideoEffect: Failed to load video file %s.", (const char *)_filename.c_str()); } else { // extract the video length int videolen = _videoreader->GetLengthMS(); VideoPanel *fp = (VideoPanel*)panel; if (fp != nullptr) { fp->addVideoTime(filename, videolen); } if (_starttime != 0) { _videoreader->Seek(_starttime * 1000); } if (_durationTreatment == "Slow/Accelerate") { int effectFrames = buffer.curEffEndPer - buffer.curEffStartPer + 1; int videoFrames = (videolen - _starttime) / buffer.frameTimeInMs; float speedFactor = (float)videoFrames / (float)effectFrames; _frameMS = (int)((float)buffer.frameTimeInMs * speedFactor); } } } else { log4cpp::Category &logger_base = log4cpp::Category::getInstance(std::string("log_base")); logger_base.warn("VideoEffect: Video file %s not found.", (const char *)_filename.c_str()); } } if (_videoreader != NULL) { // get the image for the current frame AVFrame* image = _videoreader->GetNextFrame(_starttime * 1000 + (buffer.curPeriod - buffer.curEffStartPer) * _frameMS - _loops * _videoreader->GetLengthMS()); // if we have reached the end and we are to loop if (_videoreader->AtEnd() && _durationTreatment == "Loop") { _loops++; // jump back to start and try to read frame again _videoreader->Seek(0); image = _videoreader->GetNextFrame(_starttime * 1000 + (buffer.curPeriod - buffer.curEffStartPer) * _frameMS - _loops * _videoreader->GetLengthMS()); } int startx = (buffer.BufferWi - _videoreader->GetWidth()) / 2; int starty = (buffer.BufferHt - _videoreader->GetHeight()) / 2; // check it looks valid if (image != NULL) { // draw the image xlColor c; for (int y = 0; y < _videoreader->GetHeight(); y++) { for (int x = 0; x < _videoreader->GetWidth(); x++) { try { c.Set(*(image->data[0] + (_videoreader->GetHeight() - 1 - y) * _videoreader->GetWidth() * 3 + x * 3), *(image->data[0] + (_videoreader->GetHeight() - 1 - y) * _videoreader->GetWidth() * 3 + x * 3 + 1), *(image->data[0] + (_videoreader->GetHeight() - 1 - y) * _videoreader->GetWidth() * 3 + x * 3 + 2), 255); } catch (...) { // this shouldnt happen so make it stand out c = xlRED; } buffer.SetPixel(x + startx, y+starty, c); } } } else { // display a blue background to show we have gone past end of video for (int y = 0; y < buffer.BufferHt; y++) { for (int x = 0; x < buffer.BufferWi; x++) { buffer.SetPixel(x, y, xlBLUE); } } } } else { // display a red background to show we have a problem for (int y = 0; y < buffer.BufferHt; y++) { for (int x = 0; x < buffer.BufferWi; x++) { buffer.SetPixel(x, y, xlRED); } } } }