int static possible_downward_moves(RenderBuffer &buffer, int x, int y) { int moves = 0; // no moves possible from bottom row if (y == 0) { return 0; } if (buffer.GetTempPixel(x-1 < 0 ? x-1+buffer.BufferWi : x-1, y-1) == xlBLACK) { moves += 1; } if (buffer.GetTempPixel(x, y-1) == xlBLACK) { moves += 2; } if (buffer.GetTempPixel(x+1 >= buffer.BufferWi ? x+1-buffer.BufferWi : x+1, y-1) == xlBLACK) { moves += 4; } return moves; }
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 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 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 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; } } } } } }