TEST_F(FrameBufferTest, instantiation) { FrameBuffer fbo; Texture colorTexture(GL_TEXTURE_2D); RenderBuffer depthRenderBuffer; GLfloat clearColor[] = { 0.0f, 0.0f, 0.5f }; colorTexture.setStorage2D(1, GL_RGB16F, _ctx.getWindowSize().x, _ctx.getWindowSize().y); colorTexture.set(GL_TEXTURE_MAG_FILTER, GL_NEAREST); colorTexture.set(GL_TEXTURE_MIN_FILTER, GL_NEAREST); colorTexture.set(GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); colorTexture.set(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); depthRenderBuffer.setStorage(GL_DEPTH_COMPONENT, _ctx.getWindowSize().x, _ctx.getWindowSize().y); colorTexture.bind(0); fbo.setTexture(GL_COLOR_ATTACHMENT0, colorTexture); fbo.setRenderBuffer(GL_DEPTH_ATTACHMENT, depthRenderBuffer); fbo.setDrawBuffer(GL_COLOR_ATTACHMENT0); if (!fbo.isComplete(GL_FRAMEBUFFER)) throw (std::runtime_error("bad framebuffer")); fbo.clear<GLfloat>(GL_COLOR, 0, clearColor); EXPECT_TRUE(fbo.isValid()); }
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 } } }
RenderBuffer* RenderBufferCache::get(GLenum format, const uint32_t width, const uint32_t height) { RenderBuffer* buffer = NULL; RenderBufferEntry entry(format, width, height); ssize_t index = mCache.indexOf(entry); if (index >= 0) { entry = mCache.itemAt(index); mCache.removeAt(index); buffer = entry.mBuffer; mSize -= buffer->getSize(); RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)", RenderBuffer::formatName(format), width, height); } else { buffer = new RenderBuffer(format, width, height); RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)", RenderBuffer::formatName(format), width, height); } buffer->bind(); buffer->allocate(); return buffer; }
void RenderBufferBase::onCreate(const RenderBuffer *source) { Inherited::onCreate(source); if(source != NULL) { RenderBuffer *pThis = static_cast<RenderBuffer *>(this); pThis->setImage(source->getImage()); } }
RenderTargetPtr MultiRenderTarget::CreateTexture(const TargetParam& tp) { if (tp.useAsTexture) { RenderTexture* rt = NEX_NEW(RenderTexture()); rt->Create(TextureBase::TEXTURE_2D, tp.format, dimensions.width, dimensions.height, 1); return Assign(rt); } else { RenderBuffer* rt = NEX_NEW(RenderBuffer()); rt->Create(tp.format, dimensions.width, dimensions.height); return Assign(rt); } }
void FrameBuffer::CreateTexturesAndBind() { // Create textures for each buffer. for (int i = 0; i < renderBuffers.Size(); ++i) { RenderBuffer * rb = renderBuffers[i]; // Actually create it. rb->CreateBuffer(); rb->CreateTexture(); // Bind them straight away too. rb->BindTextureToFrameBuffer(); } }
void RenderBufferBase::execSyncV( FieldContainer &oFrom, ConstFieldMaskArg whichField, AspectOffsetStore &oOffsets, ConstFieldMaskArg syncMode, const UInt32 uiSyncInfo) { RenderBuffer *pThis = static_cast<RenderBuffer *>(this); pThis->execSync(static_cast<RenderBuffer *>(&oFrom), whichField, oOffsets, syncMode, uiSyncInfo); }
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 FrameBuffer::setRenderBuffer(RenderBuffer& renderBuffer, Attachment attachment) { assert(_isBound); glFramebufferRenderbuffer( static_cast<GLuint>(_target), static_cast<GLuint>(attachment), GL_RENDERBUFFER, renderBuffer.handle() ); }
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; }
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"); } }
//all shapes are loaded from same image file to reduce file I/O and caching //thiss also allows animated images to be self-contained void PianoRenderCache::Piano_load_shapes(RenderBuffer &buffer, const wxString& filename) { debug_function(10); //Debug debug("load_shapes('%s')", (const char*)filename.c_str()); debug(1, "load shapes file '%s'", (const char*)filename.c_str()); //reload shapes even if file name hasn't changed; color map might be different now // if (!CachedShapeFilename.CmpNoCase(filename)) { debug_more(2, ", no change"); return; } //no change if (!wxFileExists(filename)) return; Piano_flush_shapes(); //invalidate cached data if (!Shapes.LoadFile(filename, wxBITMAP_TYPE_ANY, 0) || !Shapes.IsOk()) { //wxMessageBox("Error loading image file: "+NewPictureName); Shapes.Clear(); return; } if (buffer.GetColorCount() < 2) return; //use colors from shapes file if no user-selected colors // int imgwidth=image.GetWidth(); // int imght =image.GetHeight(); // std::hash_map<WXCOLORREF, int> palcounts; //TODO: use wxImage.GetData for better performance? //TODO: use multiple images within same file? for (int y = Shapes.GetHeight() - 1; y >= 0; --y) //bottom->top for (int x = 0; x < Shapes.GetWidth(); ++x) //left->right if (!Shapes.IsTransparent(x, y)) { xlColor color, mapped; color.Set(Shapes.GetRed(x, y), Shapes.GetGreen(x, y), Shapes.GetBlue(x, y)); if (ColorMap.find(color.GetRGB()) != ColorMap.end()) continue; //already saw this color buffer.palette.GetColor(ColorMap.size() % buffer.GetColorCount(), mapped); //assign user-selected colors to shape palette sequentially, loop if run out of colors debug(10, "shape color[%d] 0x%x => user-selected color [%d] 0x%x", ColorMap.size(), color.GetRGB(), ColorMap.size() % GetColorCount(), mapped.GetRGB()); ColorMap[color.GetRGB()] = mapped; //.GetRGB(); // ShapePalette.push_back(c.GetRGB()); //keep a list of unique colors in order of occurrence from origin L-R, B-T } debug(2, "w %d, h %d, #colors %d", Shapes.GetWidth(), Shapes.GetHeight(), ColorMap.size()); CachedShapeFilename = filename; //don't load same file again }
void 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); } }
bool GL3FrameBufferProvider::attach_object(GLenum opengl_attachment, const RenderBuffer &render_buffer) { int internal_attachment_offset = decode_internal_attachment_offset(opengl_attachment); // Check for object replacement bool is_replaced_object = false; if (!attached_renderbuffers[internal_attachment_offset].is_null()) { is_replaced_object = true; attached_renderbuffers[internal_attachment_offset] = RenderBuffer(); } if (!attached_textures[internal_attachment_offset].is_null()) { is_replaced_object = true; attached_textures[internal_attachment_offset] = Texture2D(); } // Store the renderbuffer attached_renderbuffers[internal_attachment_offset] = render_buffer; // Bind the renderbuffer GL3RenderBufferProvider *gl_render_buffer = static_cast<GL3RenderBufferProvider *>(render_buffer.get_provider()); if (!gl_render_buffer) throw Exception("Invalid render buffer"); FrameBufferStateTracker tracker_draw(bind_target, handle, gc_provider); GLenum target = GL_DRAW_FRAMEBUFFER; if (bind_target == framebuffer_read) target = GL_READ_FRAMEBUFFER; GLuint render_buffer_handle = gl_render_buffer->get_handle(); glFramebufferRenderbuffer(target, opengl_attachment, GL_RENDERBUFFER, render_buffer_handle); return is_replaced_object; }
void FrameBuffer::AttachDepthStencil(GraphicsRenderBufferInternalFormat depthFormat, GraphicsRenderBufferInternalFormat stencilFormat, const Size2U& size) { auto depthStencilFormat = GraphicsContext::CombineDepthStencilFormat(depthFormat, stencilFormat); if (depthStencilFormat != GraphicsRenderBufferInternalFormat::None) { RenderBuffer* renderBuffer = new RenderBuffer(depthStencilFormat, size); renderBuffer->Generate(); AttachRenderBuffer(GraphicsAttachment::DepthStencil, renderBuffer); } else { RenderBuffer* depthBuffer = new RenderBuffer(depthFormat, size); depthBuffer->Generate(); AttachRenderBuffer(GraphicsAttachment::Depth, depthBuffer); RenderBuffer* stencilBuffer = new RenderBuffer(stencilFormat, size); stencilBuffer->Generate(); AttachRenderBuffer(GraphicsAttachment::Stencil, stencilBuffer); } }
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 } } }
// Attempt to create an FBO with a certain configuration. If the FBO // is created with fewer bits in any of its parameters, the creation // is deemed to have failed. Even though the result is a valid FBO, // we're only interested in discrete, valid configurations. bool createFBO(GraphicsContext* gc, FboConfig &config, FboData &data) { bool result = true; bool multisample = config.depthSamples > 0; bool csaa = config.coverageSamples > config.depthSamples; data.fb = new FrameBufferObject; int texWidth = 512, texHeight = 512; data.tex = new Texture2D; data.tex->setTextureSize(texWidth, texHeight); data.tex->setInternalFormat(config.colorFormat); data.tex->setSourceFormat(GL_RGBA); data.tex->setSourceType(GL_FLOAT); data.tex->setFilter(Texture::MIN_FILTER, Texture::LINEAR_MIPMAP_LINEAR); data.tex->setFilter(Texture::MAG_FILTER, Texture::LINEAR); data.tex->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE); data.tex->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE); RenderBuffer* colorRB = 0; RenderBuffer* depthRB = 0; if (multisample) { data.resolveFB = new FrameBufferObject; data.resolveFB->setAttachment(Camera::COLOR_BUFFER, FrameBufferAttachment(data.tex.get())); colorRB = new RenderBuffer(texWidth, texHeight, config.colorFormat, config.coverageSamples, config.depthSamples); data.fb->setAttachment(Camera::COLOR_BUFFER, FrameBufferAttachment(colorRB)); depthRB = new RenderBuffer(texWidth, texHeight, config.depthFormat, config.coverageSamples, config.depthSamples); data.fb->setAttachment(Camera::DEPTH_BUFFER, FrameBufferAttachment(depthRB)); } else { data.depthTex = makeDepthTexture(texWidth, texHeight, config.depthFormat); data.fb->setAttachment(Camera::COLOR_BUFFER, FrameBufferAttachment(data.tex.get())); data.fb->setAttachment(Camera::DEPTH_BUFFER, FrameBufferAttachment(data.depthTex.get())); } State& state = *gc->getState(); unsigned int contextID = state.getContextID(); FBOExtensions* fboe = FBOExtensions::instance(contextID, true); data.fb->apply(state); result = checkFramebufferStatus(gc, true); if (!result) { fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); return false; } int query; if (multisample) { GLuint colorRBID = colorRB->getObjectID(contextID, fboe); fboe->glBindRenderbuffer(GL_RENDERBUFFER_EXT, colorRBID); if (csaa) { fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COVERAGE_SAMPLES_NV, &query); if (query < config.coverageSamples) result = false; else config.coverageSamples = query; fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_COLOR_SAMPLES_NV, &query); if ( query < config.depthSamples) result = false; else config.depthSamples = query; // report back the actual number } else { fboe->glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &query); if (query < config.depthSamples) result = false; else config.depthSamples = query; } } glGetIntegerv( GL_RED_BITS, &query); if (query != config.redbits) result = false; glGetIntegerv(GL_DEPTH_BITS, &query); if ( query != config.depthBits) result = false; if (result && multisample && data.resolveFB.valid()) { data.resolveFB->apply(state); result = checkFramebufferStatus(gc, true); if (result) { glGetIntegerv( GL_RED_BITS, &query); if (query != config.redbits) result = false; } } fboe->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); return result; }
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 MarqueeEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int BandSize = SettingsMap.GetInt("SLIDER_Marquee_Band_Size", 0); int SkipSize = SettingsMap.GetInt("SLIDER_Marquee_Skip_Size", 0); int Thickness = SettingsMap.GetInt("SLIDER_Marquee_Thickness", 0); int stagger = SettingsMap.GetInt("SLIDER_Marquee_Stagger", 0); int mSpeed = SettingsMap.GetInt("SLIDER_Marquee_Speed", 1); int mStart = SettingsMap.GetInt("SLIDER_Marquee_Start", 0); bool reverse_dir = SettingsMap.GetBool("CHECKBOX_Marquee_Reverse"); int x_scale = SettingsMap.GetInt("SLIDER_Marquee_ScaleX", 0); int y_scale = SettingsMap.GetInt("SLIDER_Marquee_ScaleY", 0); int xc_adj = SettingsMap.GetInt("SLIDER_MarqueeXC", 0); int yc_adj = SettingsMap.GetInt("SLIDER_MarqueeYC", 0); bool pixelOffsets = SettingsMap.GetBool("CHECKBOX_Marquee_PixelOffsets"); bool wrap_x = SettingsMap.GetBool("CHECKBOX_Marquee_WrapX"); int x = 0; xlColor color; size_t colorcnt = buffer.GetColorCount(); int color_size = BandSize + SkipSize; int repeat_size = color_size * colorcnt; int eff_pos = buffer.curPeriod - buffer.curEffStartPer; x = (mSpeed * eff_pos) / 5; int corner_x1 = 0; int corner_y1 = 0; int corner_x2 = (int)((double)buffer.BufferWi * (double)x_scale / 100.0) - 1; int corner_y2 = (int)((double)buffer.BufferHt * (double)y_scale / 100.0) - 1; int sign = 1; if( reverse_dir ) { sign = -1; } int xoffset_adj = xc_adj; int yoffset_adj = yc_adj; if (!pixelOffsets) { xoffset_adj = (xoffset_adj*buffer.BufferWi)/100.0; // xc_adj is from -100 to 100 yoffset_adj = (yoffset_adj*buffer.BufferHt)/100.0; // yc_adj is from -100 to 100 } for( int thick = 0; thick < Thickness; thick++ ) { int current_color = ((x + mStart) % repeat_size) / color_size; int current_pos = (((x + mStart) % repeat_size) % color_size); if( sign < 0 ) { current_color = colorcnt - current_color - 1; } // wxLogDebug(wxString::Format("Color: %d, Pos: %d", current_color, current_pos)); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*(stagger+1) * sign); for( int x_pos = corner_x1; x_pos <= corner_x2; x_pos++ ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(x_pos + xoffset_adj, corner_y2 + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*2*sign); for( int y_pos = corner_y2; y_pos >=corner_y1 ; y_pos-- ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(corner_x2 + xoffset_adj, y_pos + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*2*sign); for( int x_pos = corner_x2; x_pos >= corner_x1; x_pos-- ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(x_pos + xoffset_adj, corner_y1 + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, thick*2*sign); for( int y_pos = corner_y1; y_pos <= corner_y2-1; y_pos++ ) { color = xlBLACK; if( current_pos < BandSize ) { buffer.palette.GetColor(current_color, color); } buffer.ProcessPixel(corner_x1 + xoffset_adj, y_pos + yoffset_adj, color, wrap_x); UpdateMarqueeColor(current_pos, current_color, colorcnt, color_size, 1*sign); } corner_x1++; corner_y1++; corner_x2--; corner_y2--; } }
void 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 FrameBuffer::CreateRenderBuffers() { /// OpenGL specific data /// Frame buffer object for deferred shading //GLuint frameBufferObject; // Main frame buffer object to use //GLuint depthBuffer; // Depth buffer to act as Z-buffer for when parsing the input to the frame buffer //GLuint positionTexture; // World coordinate position texture //GLuint diffuseTexture; // Diffuse texture //GLuint depthTexture; // Depth texture //GLuint normalTexture; // Normal texture // GLuint error; /// Setup main Frame buffer object if (frameBufferObject == -1) frameBufferObject = GLFrameBuffers::New(); error = glGetError(); /// Bind it for manipulatoin. glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); AssertGLError("FrameBuffer::CreateRenderBuffers"); /// Establish some variables before we try tweaking properties.. Vector2i textureSize = size; /* /// Try oversampling o-o bool overSampling = false; if (overSampling){ glEnable( GL_MULTISAMPLE ); textureSize *= 2; } else glDisable(GL_MULTISAMPLE); */ /// Setup Render buffers AssertGLError("FrameBuffer::CreateRenderBuffers"); // Delete the old buffers as needed. for (int i = 0; i < renderBuffers.Size(); ++i) { RenderBuffer * rb = renderBuffers[i]; std::cout<<"\nDeallocating renderBuffer.."; delete rb; } renderBuffers.Clear(); // Create the buffers. RenderBuffer * depthBuf = new RenderBuffer("Depthbuf", BufferType::DEPTH_BUFFER, BufferStorageType::DEPTH_16F, textureSize), * diffBuf = new RenderBuffer("Diffuse", BufferType::COLOR_BUFFER_1, ColorStorageType(), textureSize)//, // * norBuf = new RenderBuffer(BufferType::COLOR_BUFFER_2, BufferStorageType::RGB_16F, textureSize), // * posBuf = new RenderBuffer(BufferType::COLOR_BUFFER_3, BufferStorageType::RGB_32F, textureSize) ; // Try adding the rest later on..? renderBuffers.Add(depthBuf); renderBuffers.Add(diffBuf); // renderBuffers.Add(norBuf); // renderBuffers.Add(posBuf); // Bind to 0 when done. glBindRenderbuffer(GL_RENDERBUFFER, 0); AssertGLError("FrameBuffer::CreateRenderBuffers"); // Create textures for each buffer. for (int i = 0; i < renderBuffers.Size(); ++i) { RenderBuffer * rb = renderBuffers[i]; // Actually create it. rb->CreateBuffer(); rb->CreateTexture(); // Bind them straight away too. rb->BindTextureToFrameBuffer(); } int frameBufferColorAttachmentsSet = 7; GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); // Check that status of our generated frame buffer AssertGLError("FrameBuffer::CreateRenderBuffers"); // Check that frame buffer is okay to work on. int result = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); switch(result) { case GL_FRAMEBUFFER_COMPLETE: // yay :3 break; case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: std::cout<<"\nINFO: Framebuffer incomplete attachment."; break; case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: std::cout<<"\nINFO: Framebuffer incomplete, missing attachment. Attach an image!"; break; case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: std::cout<<"\nINFO: Framebuffer incomplete draw buffer."; break; case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: std::cout<<"\nINFO: Framebuffer incomplete read buffer."; break; case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: std::cout<<"\nINFO: Framebuffer incomplete multisample."; break; case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: std::cout<<"\nINFO: Framebuffer incomplete layer targets."; break; case GL_FRAMEBUFFER_UNSUPPORTED: std::cout<<"\nINFO: Framebuffer unsupported."; break; default: std::cout<<"\nINFO: Unknown error in framebuffer ..."; break; } if (result != GL_FRAMEBUFFER_COMPLETE) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); std::cout<<"\nINFO: FrameBuffer not ready to be used."; SleepThread(10); return; } /// Only have frame buffer parameters in OpenGL 4.3 core and above... if (GL_VERSION_MAJOR >= 4 && GL_VERSION_MINOR >= 3){ /// Set frame buffer parameters // glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH, 512); // glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT, 512); // glFramebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES, 4); error = glGetError(); } // Unbind our frame buffer object, along with its attached render buffers glBindFramebuffer(GL_FRAMEBUFFER, 0); AssertGLError("FrameBuffer::CreateRenderBuffers"); // Ok! good = true; }
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); } } } } }
double P(const TaggedImage &img, RenderBuffer &rb, bool print_debug_info=false, Vector3d *last_color_dest=NULL) const { if(!obj) { RenderBuffer::RegionType fg_region = rb.new_region(); sphere_draw(rb, fg_region, pos, goal.sphere_radius); RenderBuffer::RegionType bg_region = rb.new_region(); sphere_draw(rb, bg_region, pos, 2*goal.sphere_radius); vector<ResultWithArea> results = rb.get_results(); Result inner_result = results[fg_region]; Result outer_result = results[bg_region]; Result far_result = img.total_result - inner_result; //- outer_result; if(inner_result.count < 100 || outer_result.count < 100 || far_result.count < 100) { if(print_debug_info) { cout << endl; cout << endl; cout << "NOT VISIBLE" << endl; } // not visible return 0.001; } if(last_color_dest) { *last_color_dest = inner_result.avg_color(); } Vector3d inner_color_guess = ColorRGBA_to_vec(goal.fg_color); Vector3d outer_color_guess = ColorRGBA_to_vec(goal.bg_color); Vector3d inner_color = inner_result.avg_color().normalized(); Vector3d outer_color = outer_result.avg_color().normalized(); Vector3d far_color = far_result.avg_color().normalized(); //double P2 = (inner_color - outer_color).norm(); //double P = P2* pow(far_color.dot(outer_color), 5); double P = 1; { if(results[fg_region].count < 100) { if(print_debug_info) { cout << "TOO SMALL FG" << endl; } P *= 0.5; } else { Vector3d this_color = results[fg_region].avg_color_assuming_unseen_is( outer_color).normalized(); if(outer_color_guess == inner_color_guess) { P *= exp(10*( (this_color - outer_color).norm() - ( far_color - outer_color).norm() - .05 )); } else { Vector3d dir = (inner_color_guess.normalized() - outer_color_guess.normalized()).normalized(); P *= exp(10*( (this_color - outer_color).dot(dir) - ( far_color - outer_color).norm() - .05 )); } } } { if(results[bg_region].count < 100) { if(print_debug_info) { cout << "TOO SMALL BG" << endl; } P *= 0.5; } else { Vector3d this_color = results[bg_region].avg_color_assuming_unseen_is( inner_color).normalized(); if(outer_color_guess == inner_color_guess) { P *= exp(10*( (inner_color - this_color).norm() - ( far_color - this_color).norm() - .05 )); } else { Vector3d dir = (inner_color_guess.normalized() - outer_color_guess.normalized()).normalized(); P *= exp(10*( (inner_color - this_color).dot(dir) - ( far_color - this_color).norm() - .05 )); } } } return P; } typedef std::pair<const Component *, RenderBuffer::RegionType> Pair; static std::vector<Pair> regions; regions.clear(); BOOST_FOREACH(const Component &component, obj->components) { if(component.name.find("marker ") == 0 || component.name.find("ignore ") == 0) continue; RenderBuffer::RegionType region = rb.new_region(); component.draw(rb, region, pos, q); regions.push_back(make_pair(&component, region)); } vector<ResultWithArea> results = rb.get_results(); double P = 1; BOOST_FOREACH(const Pair &p1, regions) { const ResultWithArea &p1_result = results[p1.second]; BOOST_FOREACH(const Pair &p2, regions) { if(&p2 >= &p1) continue; const ResultWithArea &p2_result = results[p2.second]; istringstream p1_ss(p1.first->name); string p1_prefix; p1_ss >> p1_prefix; string p1_op; p1_ss >> p1_op; Vector3d p1_dcolor; p1_ss >> p1_dcolor[0] >> p1_dcolor[1] >> p1_dcolor[2]; istringstream p2_ss(p2.first->name); string p2_prefix; p2_ss >> p2_prefix; string p2_op; p2_ss >> p2_op; Vector3d p2_dcolor; p2_ss >> p2_dcolor[0] >> p2_dcolor[1] >> p2_dcolor[2]; if(p2_dcolor == p1_dcolor) continue; Vector3d dir = (p2_dcolor - p1_dcolor).normalized(); if(p1_result.count < 10 || p2_result.count < 10) { P *= 0; continue; } P *= exp(30*(p2_result.avg_color_assuming_unseen_is(p1_result.avg_color()) - p1_result.avg_color_assuming_unseen_is(p2_result.avg_color())).dot(dir)); } } BOOST_FOREACH(const Pair &p1, regions) { const ResultWithArea &p1_result = results[p1.second]; istringstream p1_ss(p1.first->name); string p1_prefix; p1_ss >> p1_prefix; string p1_op; p1_ss >> p1_op; if(p1_op == "colornovar") { if(p1_result.count == 0) { P *= 1e-3; continue; } double var = 0; for(int i = 0; i < 3; i++) { var += p1_result.total_color2[i]/p1_result.count - pow(p1_result.total_color[i]/p1_result.count, 2); } P *= exp(-1e3*var); if(print_debug_info) { cout << "var " << var << " " << p1_result.total_color2.transpose() << " / " << p1_result.total_color.transpose() << " count " << p1_result.count << endl; } } } if(print_debug_info) { cout << "P " << P << endl; } /* RenderBuffer::RegionType fg_region = rb.new_region(); if(!obj) { sphere_draw(rb, fg_region, pos, goal.sphere_radius); } else { BOOST_FOREACH(const Component &component, obj->components) { if(component.name.find("solid_") == 0) { component.draw(rb, fg_region, pos, q); } } } RenderBuffer::RegionType bg_region = rb.new_region(); if(!obj) { sphere_draw(rb, bg_region, pos, 2*goal.sphere_radius); } else { BOOST_FOREACH(const Component &component, obj->components) { if(component.name.find("background_") == 0) { component.draw(rb, bg_region, pos, q); } } } Result inner_result = results[fg_region]; Result outer_result = results[bg_region]; Result far_result = img.total_result - inner_result; //- outer_result; if(inner_result.count < 100 || outer_result.count < 100 || far_result.count < 100) { if(print_debug_info) { cout << endl; cout << endl; cout << "NOT VISIBLE" << endl; } // not visible return 0.001; } if(last_color_dest) { *last_color_dest = inner_result.avg_color(); } Vector3d inner_color_guess = ColorRGBA_to_vec(goal.fg_color); Vector3d outer_color_guess = ColorRGBA_to_vec(goal.bg_color); Vector3d inner_color = inner_result.avg_color().normalized(); Vector3d outer_color = outer_result.avg_color().normalized(); Vector3d far_color = far_result.avg_color().normalized(); //double P2 = (inner_color - outer_color).norm(); //double P = P2* pow(far_color.dot(outer_color), 5); double P = 1; { if(results[fg_region].count < 100) { if(print_debug_info) { cout << "TOO SMALL FG" << endl; } P *= 0.5; } else { Vector3d this_color = results[fg_region].avg_color_assuming_unseen_is( outer_color).normalized(); if(outer_color_guess == inner_color_guess) { P *= exp(10*( (this_color - outer_color).norm() - ( far_color - outer_color).norm() - .05 )); } else { Vector3d dir = (inner_color_guess.normalized() - outer_color_guess.normalized()).normalized(); P *= exp(10*( (this_color - outer_color).dot(dir) - ( far_color - outer_color).norm() - .05 )); } } } { if(results[bg_region].count < 100) { if(print_debug_info) { cout << "TOO SMALL BG" << endl; } P *= 0.5; } else { Vector3d this_color = results[bg_region].avg_color_assuming_unseen_is( inner_color).normalized(); if(outer_color_guess == inner_color_guess) { P *= exp(10*( (inner_color - this_color).norm() - ( far_color - this_color).norm() - .05 )); } else { Vector3d dir = (inner_color_guess.normalized() - outer_color_guess.normalized()).normalized(); P *= exp(10*( (inner_color - this_color).dot(dir) - ( far_color - this_color).norm() - .05 )); } } } if(print_debug_info) { cout << endl; cout << endl; cout << "inner count" << inner_result.count << endl; cout << "inner avg " << inner_color << endl; cout << endl; cout << "outer count" << outer_result.count << endl; cout << "outer avg " << outer_color << endl; cout << endl; cout << "far count" << far_result.count << endl; cout << "far avg " << far_color << endl; cout << endl; cout << "P " << P << endl; } */ if(!(isfinite(P) && P >= 0)) { cout << "bad P: " << P << endl; assert(false); } return P; }
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 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 MusicEffect::CreateEvents(RenderBuffer& buffer, std::vector<std::list<MusicEvent*>*>& events, int startNote, int endNote, int bars, int scalenotes, int sensitivity) { // must have media if (buffer.GetMedia() == NULL) { return; } float notesperbar = ((float)endNote - (float)startNote + 1.0) / (float)bars; // use notes per bar // use multiple notes of data per output string using the maximum of these notes intensities std::map<int /*bar*/, std::map<int /*frame*/, float>> data; std::map<int /*bar*/, float> max; float overallmax = 0.0; for (int b = 0; b < bars; b++) { max[b] = 0.0; } // go through each frame and extract the data i need for (int f = buffer.curEffStartPer; f <= buffer.curEffEndPer; f++) { std::list<float>* pdata = buffer.GetMedia()->GetFrameData(f, FRAMEDATATYPE::FRAMEDATA_VU, ""); auto pn = pdata->begin(); // skip to start note for (int i = 0; i < startNote; i++) { ++pn; } for (int b = 0; b < bars && pn != pdata->end(); b++) { float val = 0.0; for (int n = 0; n < (int)notesperbar; n++) { val = std::max(val, *pn); ++pn; } data[b][f] = val; max[b] = std::max(max[b], val); overallmax = std::max(overallmax, val); } } for (int b = 0; b < bars; b++) { events.push_back(new std::list<MusicEvent*>()); float notesensitivity; if (scalenotes == 1) { notesensitivity = (float)sensitivity / 100.0; } else if (scalenotes == 2) { notesensitivity = (float)sensitivity / 100.0 * max[b]; } else { notesensitivity = (float)sensitivity / 100.0 * overallmax; } int startframe = -1; // extract the value for this note int frame = buffer.curEffStartPer; for (auto f = data[b].begin(); f != data[b].end(); ++f) { if (f->second > notesensitivity) { startframe = frame; while (f != data[b].end() && f->second > notesensitivity) { ++f; frame++; } --f; frame--; if (frame - startframe >= MINIMUMEVENTLENGTH) { events[b]->push_back(new MusicEvent(startframe, frame - startframe)); } } frame++; } } }
void MusicEffect::Render(RenderBuffer &buffer, int bars, const std::string& type, int sensitivity, bool scale, const std::string& scalenotes, int offsetx, int startnote, int endnote, const std::string& colourtreatment, bool fade) { // no point if we have no media if (buffer.GetMedia() == NULL) { return; } int nType = DecodeType(type); int nTreatment = DecodeColourTreatment(colourtreatment); int nScaleNotes = DecodeScaleNotes(scalenotes); // Grab our cache MusicRenderCache *cache = (MusicRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new MusicRenderCache(); buffer.infoCache[id] = cache; } int &_bars = cache->_bars; int &_startNote = cache->_startNote; int &_endNote = cache->_endNote; int &_type = cache->_type; int &_offsetx = cache->_offsetx; bool &_scale = cache->_scale; int &_sensitivity = cache->_sensitivity; int &_scalenotes = cache->_scalenotes; bool &_fade = cache->_fade; int& _colourTreatment = cache->_colourTreatment; std::vector<std::list<MusicEvent*>*>& _events = cache->_events; int actualbars = std::min(bars, std::min(endnote - startnote + 1, buffer.BufferWi - offsetx)); int notesperbar = (endnote - startnote + 1) / actualbars; int actualendnote = startnote + std::min(endnote, actualbars * notesperbar); int lightsperbar = 0.5 + (float)(buffer.BufferWi - offsetx) / (float)actualbars; // Check for config changes which require us to reset if (buffer.needToInit || _bars != bars || _type != nType || _startNote != startnote || _endNote != endnote || _offsetx != offsetx || _scale != scale || _scalenotes != nScaleNotes || _sensitivity != sensitivity || _colourTreatment != nTreatment || _fade != fade) { buffer.needToInit = false; _bars = bars; _fade = fade; _startNote = startnote; _endNote = endnote; _colourTreatment = nTreatment; _type = nType; _offsetx = offsetx; _scale = scale; _sensitivity = sensitivity; _scalenotes = nScaleNotes; cache->ClearEvents(); // We limit bars to the width of the model less the x offset CreateEvents(buffer, _events, _startNote, actualendnote, actualbars, _scalenotes, _sensitivity); } int per = 1; if (_scale) { per = lightsperbar; } try { for (int x = 0; x < _events.size(); x++) { for (int i = 0; i < per; i++) { switch (_type) { case 1: RenderMorph(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, *_events[x], _colourTreatment, false, fade); break; case 2: RenderMorph(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, *_events[x], _colourTreatment, true, fade); break; case 3: RenderCollide(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, true /* collide */, *_events[x], _colourTreatment, fade); break; case 4: RenderCollide(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, false /* uncollide */,* _events[x], _colourTreatment, fade); break; case 5: RenderOn(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, *_events[x], _colourTreatment, fade); break; } } } } catch (...) { // This is here to let me catch any exceptions and stop the exception causing the render thread to die //int a = 0; } }
void MorphEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int start_x1 = SettingsMap.GetInt("SLIDER_Morph_Start_X1", 0); int start_y1 = SettingsMap.GetInt("SLIDER_Morph_Start_Y1", 0); int start_x2 = SettingsMap.GetInt("SLIDER_Morph_Start_X2", 0); int start_y2 = SettingsMap.GetInt("SLIDER_Morph_Start_Y2", 0); int end_x1 = SettingsMap.GetInt("SLIDER_Morph_End_X1", 0); int end_y1 = SettingsMap.GetInt("SLIDER_Morph_End_Y1", 0); int end_x2 = SettingsMap.GetInt("SLIDER_Morph_End_X2", 0); int end_y2 = SettingsMap.GetInt("SLIDER_Morph_End_Y2", 0); int start_length = SettingsMap.GetInt("SLIDER_MorphStartLength", 0); int end_length = SettingsMap.GetInt("SLIDER_MorphEndLength", 0); bool start_linked = SettingsMap.GetBool("CHECKBOX_Morph_Start_Link"); bool end_linked = SettingsMap.GetBool("CHECKBOX_Morph_End_Link"); int duration = SettingsMap.GetInt("SLIDER_MorphDuration", 0); int acceleration = SettingsMap.GetInt("SLIDER_MorphAccel", 0); bool showEntireHeadAtStart = SettingsMap.GetBool("CHECKBOX_ShowHeadAtStart"); int repeat_count = SettingsMap.GetInt("SLIDER_Morph_Repeat_Count", 0); int repeat_skip = SettingsMap.GetInt("SLIDER_Morph_Repeat_Skip", 0); int stagger = SettingsMap.GetInt("SLIDER_Morph_Stagger", 0); double eff_pos = buffer.GetEffectTimeIntervalPosition(); double step_size = 0.1; int hcols = 0, hcole = 1; int tcols = 2, tcole = 3; int num_tail_colors = 2; switch (buffer.palette.Size()) { case 1: //one color selected, use it for all hcols = hcole = tcols = tcole = 0; break; case 2: //two colors, head/tail hcols = hcole = 0; tcols = tcole = 1; break; case 3: //three colors, head /tail start/end hcols = hcole = 0; tcols = 1; tcole = 2; break; case 4: break; case 5: num_tail_colors = 3; break; case 6: num_tail_colors = 4; break; } int x1a = calcPosition(start_x1, buffer.BufferWi); int y1a = calcPosition(start_y1, buffer.BufferHt); int x2a = calcPosition(end_x1, buffer.BufferWi); int y2a = calcPosition(end_y1, buffer.BufferHt); int x1b, x2b, y1b, y2b; if( start_linked ) { x1b = x1a; y1b = y1a; } else { x1b = calcPosition(start_x2, buffer.BufferWi); y1b = calcPosition(start_y2, buffer.BufferHt); } if( end_linked ) { x2b = x2a; y2b = y2a; } else { x2b = calcPosition(end_x2, buffer.BufferWi); y2b = calcPosition(end_y2, buffer.BufferHt); } xlColor head_color, tail_color, test_color; // compute direction int delta_xa = x2a - x1a; int delta_xb = x2b - x1b; int delta_ya = y2a - y1a; int delta_yb = y2b - y1b; int direction = delta_xa + delta_xb + delta_ya + delta_yb; int repeat_x = 0; int repeat_y = 0; double effect_pct = 1.0; double stagger_pct = 0.0; if( repeat_count > 0 ) { if( (std::abs((float)delta_xa) + std::abs((float)delta_xb)) < (std::abs((float)delta_ya) + std::abs((float)delta_yb)) ) { repeat_x = repeat_skip; } else { repeat_y = repeat_skip; } double stagger_val = (double)(std::abs((double)stagger))/200.0; effect_pct = 1.0 / (1 + stagger_val * repeat_count); stagger_pct = effect_pct * stagger_val; } std::vector<int> v_ax; std::vector<int> v_ay; std::vector<int> v_bx; std::vector<int> v_by; StoreLine(x1a, y1a, x2a, y2a, &v_ax, &v_ay); // store side a StoreLine(x1b, y1b, x2b, y2b, &v_bx, &v_by); // store side b int size_a = v_ax.size(); int size_b = v_bx.size(); std::vector<int> *v_lngx; // pointer to longest vector x std::vector<int> *v_lngy; // pointer to longest vector y std::vector<int> *v_shtx; // pointer to shorter vector x std::vector<int> *v_shty; // pointer to shorter vector y if( size_a > size_b ) { v_lngx = &v_ax; v_lngy = &v_ay; v_shtx = &v_bx; v_shty = &v_by; } else { v_lngx = &v_bx; v_lngy = &v_by; v_shtx = &v_ax; v_shty = &v_ay; } double pos_a, pos_b; double total_tail_length, alpha_pct; double total_length = v_lngx->size(); // total length of longest vector double head_duration = duration/100.0; // time the head is in the frame double head_end_of_head_pos = total_length + 1; double tail_end_of_head_pos = total_length + 1; double head_end_of_tail_pos = -1; double tail_end_of_tail_pos = -1; for( int repeat = 0; repeat <= repeat_count; repeat++ ) { double eff_pos_adj = buffer.calcAccel(eff_pos, acceleration); double eff_start_pct = (stagger >= 0) ? stagger_pct*repeat : stagger_pct*(repeat_count-repeat); double eff_end_pct = eff_start_pct + effect_pct; eff_pos_adj = (eff_pos_adj - eff_start_pct) / (eff_end_pct - eff_start_pct); if( eff_pos_adj < 0.0 ) { head_end_of_head_pos = -1; tail_end_of_head_pos = -1; head_end_of_tail_pos = -1; tail_end_of_tail_pos = -1; total_tail_length = 1.0; if( showEntireHeadAtStart ) { head_end_of_head_pos = start_length; } } else { if( head_duration > 0.0 ) { double head_loc_pct = eff_pos_adj / head_duration; head_end_of_head_pos = total_length * head_loc_pct; double current_total_head_length = end_length * head_loc_pct + start_length * (1.0 - head_loc_pct); // adjusted head length excluding clipping head_end_of_head_pos += current_total_head_length * head_loc_pct * head_duration; total_tail_length = total_length * ( 1 / head_duration - 1.0); if( showEntireHeadAtStart ) { head_end_of_head_pos += current_total_head_length * (1.0 - eff_pos_adj); } tail_end_of_head_pos = head_end_of_head_pos - current_total_head_length; head_end_of_tail_pos = tail_end_of_head_pos - step_size; tail_end_of_tail_pos = head_end_of_tail_pos - total_tail_length; buffer.Get2ColorBlend(hcols, hcole, std::min( head_loc_pct, 1.0), head_color); } else { total_tail_length = total_length; head_end_of_tail_pos = total_length * 2 * eff_pos_adj; tail_end_of_tail_pos = head_end_of_tail_pos - total_tail_length; } } // draw the tail for( double i = std::min(head_end_of_tail_pos, total_length-1); i >= tail_end_of_tail_pos && i >= 0.0; i -= step_size ) { double pct = ((total_length == 0) ? 0.0 : i / total_length); pos_a = i; pos_b = v_shtx->size() * pct; double tail_color_pct = (i-tail_end_of_tail_pos) / total_tail_length; if( num_tail_colors > 2 ) { double color_index = ((double)num_tail_colors - 1.0) * (1.0 - tail_color_pct); tail_color_pct = color_index - (double)((int)color_index); tcols = (int)color_index + 2; tcole = tcols + 1; if( tcole == num_tail_colors+1 ) { alpha_pct = (1.0 - tail_color_pct); } else { alpha_pct = 1.0; } buffer.Get2ColorBlend(tcols, tcole, tail_color_pct, tail_color); } else { if( tail_color_pct > 0.5 ) { alpha_pct = 1.0; } else { alpha_pct = tail_color_pct / 0.5; } buffer.Get2ColorBlend(tcole, tcols, tail_color_pct, tail_color); } if( buffer.allowAlpha ) { tail_color.alpha = 255 * alpha_pct; } buffer.DrawThickLine( (*v_lngx)[pos_a]+(repeat_x*repeat), (*v_lngy)[pos_a]+(repeat_y*repeat), (*v_shtx)[pos_b]+(repeat_x*repeat), (*v_shty)[pos_b]+(repeat_y*repeat), tail_color, direction >= 0); } // draw the head for( double i = std::max(tail_end_of_head_pos, 0.0); i <= head_end_of_head_pos && i < total_length; i += step_size ) { double pct = ((total_length == 0) ? 0.0 : i / total_length); pos_a = i; pos_b = v_shtx->size() * pct; buffer.DrawThickLine( (*v_lngx)[pos_a]+(repeat_x*repeat), (*v_lngy)[pos_a]+(repeat_y*repeat), (*v_shtx)[pos_b]+(repeat_x*repeat), (*v_shty)[pos_b]+(repeat_y*repeat), head_color, direction >= 0); } } }