GLColorBuffer GLLensDustFilter::Filter(GLColorBuffer input) { SPADES_MARK_FUNCTION(); UpdateNoise(); std::vector<Level> levels; IGLDevice *dev = renderer->GetGLDevice(); GLQuadRenderer qr(dev); static GLProgramAttribute thruPosition("positionAttribute"); static GLProgramUniform thruColor("colorUniform"); static GLProgramUniform thruTexture("mainTexture"); static GLProgramUniform thruTexCoordRange("texCoordRange"); thruPosition(thru); thruColor(thru); thruTexture(thru); thruTexCoordRange(thru); GLColorBuffer downSampled = DownSample(input, r_hdr ? false : true); downSampled = GaussianBlur(downSampled, false); downSampled = GaussianBlur(downSampled, true); thru->Use(); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexture.SetValue(0); dev->Enable(IGLDevice::Blend, false); levels.reserve(10); // create downsample levels for(int i = 0; i < 10; i++){ GLColorBuffer prevLevel; if(i == 0){ prevLevel = downSampled; }else{ prevLevel = levels.back().buffer; } int prevW = prevLevel.GetWidth(); int prevH = prevLevel.GetHeight(); int newW = (prevW + 1) / 2; int newH = (prevH + 1) / 2; if(newW <= 1 || newH <= 1) break; GLColorBuffer newLevel = DownSample(prevLevel); newLevel = GaussianBlur(newLevel, false); newLevel = GaussianBlur(newLevel, true); Level lv; lv.w = newW; lv.h = newH; lv.buffer = newLevel; levels.push_back(lv); } dev->Enable(IGLDevice::Blend, true); dev->BlendFunc(IGLDevice::SrcAlpha, IGLDevice::OneMinusSrcAlpha); // composite levels in the opposite direction thru->Use(); qr.SetCoordAttributeIndex(thruPosition()); for(int i = (int)levels.size() - 1; i >= 1; i--){ int cnt = (int)levels.size() - i; float alpha = (float)cnt / (float)(cnt + 1); alpha = alpha; GLColorBuffer curLevel = levels[i].buffer; float sx = .25f / curLevel.GetWidth(); float sy = .25f / curLevel.GetHeight(); for(int j = 0; j < 4; j++) { if(i < (int)levels.size() - 1) { curLevel = levels[i].retBuf[j]; } GLColorBuffer targLevel = levels[i - 1].buffer; GLColorBuffer targRet = input.GetManager()->CreateBufferHandle(targLevel.GetWidth(), targLevel.GetHeight(), false); levels[i - 1].retBuf[j] = targRet; dev->BindFramebuffer(IGLDevice::Framebuffer, targRet.GetFramebuffer()); dev->Viewport(0, 0, targRet.GetWidth(), targRet.GetHeight()); dev->BindTexture(IGLDevice::Texture2D, targLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, 1.f); thruTexCoordRange.SetValue(0.f, 0.f, 1.f, 1.f); dev->Enable(IGLDevice::Blend, false); qr.Draw(); float cx = 0.f, cy = 0.f; switch(j){ case 0: cx = sx; break; case 1: cx = -sx; break; case 2: cy = sy; break; case 3: cy = -sy; break; } dev->BindTexture(IGLDevice::Texture2D, curLevel.GetTexture()); thruColor.SetValue(1.f, 1.f, 1.f, alpha); thruTexCoordRange.SetValue(cx, cy, 1.f, 1.f); dev->Enable(IGLDevice::Blend, true); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); } } static GLProgramAttribute dustPosition("positionAttribute"); static GLProgramUniform dustDustTexture("dustTexture"); static GLProgramUniform dustBlurTexture1("blurTexture1"); static GLProgramUniform dustBlurTexture2("blurTexture2"); static GLProgramUniform dustBlurTexture3("blurTexture3"); static GLProgramUniform dustBlurTexture4("blurTexture4"); static GLProgramUniform dustInputTexture("inputTexture"); static GLProgramUniform dustNoiseTexture("noiseTexture"); static GLProgramUniform dustNoiseTexCoordFactor("noiseTexCoordFactor"); dustPosition(dust); dustDustTexture(dust); dustBlurTexture1(dust); dustBlurTexture2(dust); dustBlurTexture3(dust); dustBlurTexture4(dust); dustInputTexture(dust); dustNoiseTexture(dust); dustNoiseTexCoordFactor(dust); dust->Use(); float facX = renderer->ScreenWidth() / 128.f; float facY = renderer->ScreenHeight() / 128.f; dustNoiseTexCoordFactor.SetValue(facX, facY, facX / 128.f, facY / 128.f); // composite to the final image GLColorBuffer output = input.GetManager()->CreateBufferHandle(); GLColorBuffer topLevel1 = levels[0].retBuf[0]; GLColorBuffer topLevel2 = levels[0].retBuf[1]; GLColorBuffer topLevel3 = levels[0].retBuf[2]; GLColorBuffer topLevel4 = levels[0].retBuf[3]; qr.SetCoordAttributeIndex(dustPosition()); dev->ActiveTexture(0); dev->BindTexture(IGLDevice::Texture2D, input.GetTexture()); dev->ActiveTexture(1); dev->BindTexture(IGLDevice::Texture2D, topLevel1.GetTexture()); dev->ActiveTexture(2); dev->BindTexture(IGLDevice::Texture2D, topLevel2.GetTexture()); dev->ActiveTexture(3); dev->BindTexture(IGLDevice::Texture2D, topLevel3.GetTexture()); dev->ActiveTexture(4); dev->BindTexture(IGLDevice::Texture2D, topLevel4.GetTexture()); dev->ActiveTexture(5); dustImg->Bind(IGLDevice::Texture2D); dev->ActiveTexture(6); dev->BindTexture(IGLDevice::Texture2D, noiseTex); dev->BindFramebuffer(IGLDevice::Framebuffer, output.GetFramebuffer()); dev->Viewport(0, 0, output.GetWidth(), output.GetHeight()); dustBlurTexture1.SetValue(2); dustBlurTexture2.SetValue(1); dustBlurTexture3.SetValue(3); dustBlurTexture4.SetValue(4); dustDustTexture.SetValue(5); dustNoiseTexture.SetValue(6); dustInputTexture.SetValue(0); qr.Draw(); dev->BindTexture(IGLDevice::Texture2D, 0); dev->ActiveTexture(0); return output; }
void APU_INTERNAL::Write( WORD addr, BYTE data ) { switch( addr ) { // CH0,1 rectangle case 0x4000: case 0x4001: case 0x4002: case 0x4003: case 0x4004: case 0x4005: case 0x4006: case 0x4007: WriteRectangle( (addr<0x4004)?0:1, addr, data ); break; // CH2 triangle case 0x4008: case 0x4009: case 0x400A: case 0x400B: WriteTriangle( addr, data ); break; // CH3 noise case 0x400C: case 0x400D: case 0x400E: case 0x400F: WriteNoise( addr, data ); break; // CH4 DPCM case 0x4010: case 0x4011: case 0x4012: case 0x4013: WriteDPCM( addr, data ); break; case 0x4015: reg4015 = data; if( !(data&(1<<0)) ) { ch0.enable = 0; ch0.len_count = 0; } if( !(data&(1<<1)) ) { ch1.enable = 0; ch1.len_count = 0; } if( !(data&(1<<2)) ) { ch2.enable = 0; ch2.len_count = 0; ch2.lin_count = 0; ch2.counter_start = 0; } if( !(data&(1<<3)) ) { ch3.enable = 0; ch3.len_count = 0; } if( !(data&(1<<4)) ) { ch4.enable = 0; ch4.dmalength = 0; } else { ch4.enable = 0xFF; if( !ch4.dmalength ) { ch4.address = ch4.cache_addr; ch4.dmalength = ch4.cache_dmalength; ch4.phaseacc = 0; } } break; case 0x4017: break; // VirtuaNES固有ポート case 0x4018: UpdateRectangle( ch0, (INT)data ); UpdateRectangle( ch1, (INT)data ); UpdateTriangle ( (INT)data ); UpdateNoise ( (INT)data ); break; default: break; } }