bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) { bool done; BurnTime += ticks; ticks *= 2; // Make the fire burn done = false; while (!done && ticks--) { Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); done = (Density < 0); } if (BurnTexture != NULL) delete BurnTexture; BurnTexture = new GLTexture(WIDTH, HEIGHT, false, false); // Update the burn texture with the new burn data BYTE rgb_buffer[WIDTH*HEIGHT*4]; const BYTE *src = BurnArray; DWORD *dest = (DWORD *)rgb_buffer; for (int y = HEIGHT; y != 0; --y) { for (int x = WIDTH; x != 0; --x) { BYTE s = clamp<int>((*src++)*2, 0, 255); *dest++ = MAKEARGB(s,255,255,255); } } // Put the initial screen back to the buffer. gl_SetTextureMode(TM_OPAQUE); gl.Disable(GL_ALPHA_TEST); fb->wipestartscreen->Bind(0, CM_DEFAULT); gl.Color4f(1.f, 1.f, 1.f, 1.f); gl.Begin(GL_TRIANGLE_STRIP); gl.TexCoord2f(0, fb->wipestartscreen->GetVB()); gl.Vertex2i(0, 0); gl.TexCoord2f(0, 0); gl.Vertex2i(0, fb->Height); gl.TexCoord2f(fb->wipestartscreen->GetUR(), fb->wipestartscreen->GetVB()); gl.Vertex2i(fb->Width, 0); gl.TexCoord2f(fb->wipestartscreen->GetUR(), 0); gl.Vertex2i(fb->Width, fb->Height); gl.End(); gl_SetTextureMode(TM_MODULATE); gl.ActiveTexture(GL_TEXTURE1); gl.Enable(GL_TEXTURE_2D); // mask out the alpha channel of the wipeendscreen. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); gl.ActiveTexture(GL_TEXTURE0); // Burn the new screen on top of it. gl.Color4f(1.f, 1.f, 1.f, 1.f); fb->wipeendscreen->Bind(1, CM_DEFAULT); //BurnTexture->Bind(0, CM_DEFAULT); BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, false, 0, CM_DEFAULT); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); gl.Begin(GL_TRIANGLE_STRIP); gl.MultiTexCoord2f(GL_TEXTURE0, 0, 0); gl.MultiTexCoord2f(GL_TEXTURE1, 0, fb->wipestartscreen->GetVB()); gl.Vertex2i(0, 0); gl.MultiTexCoord2f(GL_TEXTURE0, 0, BurnTexture->GetVB()); gl.MultiTexCoord2f(GL_TEXTURE1, 0, 0); gl.Vertex2i(0, fb->Height); gl.MultiTexCoord2f(GL_TEXTURE0, BurnTexture->GetUR(), 0); gl.MultiTexCoord2f(GL_TEXTURE1, fb->wipestartscreen->GetUR(), fb->wipestartscreen->GetVB()); gl.Vertex2i(fb->Width, 0); gl.MultiTexCoord2f(GL_TEXTURE0, BurnTexture->GetUR(), BurnTexture->GetVB()); gl.MultiTexCoord2f(GL_TEXTURE1, fb->wipestartscreen->GetUR(), 0); gl.Vertex2i(fb->Width, fb->Height); gl.End(); gl.ActiveTexture(GL_TEXTURE1); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); gl.Disable(GL_TEXTURE_2D); gl.ActiveTexture(GL_TEXTURE0); // The fire may not always stabilize, so the wipe is forced to end // after an arbitrary maximum time. return done || (BurnTime > 40); }
bool OpenGLSWFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLSWFrameBuffer *fb) { bool done; BurnTime += ticks; ticks *= 2; // Make the fire burn done = false; while (!done && ticks--) { Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); done = (Density < 0); } // Update the burn texture with the new burn data if (BurnTexture->Buffers[0] == 0) { glGenBuffers(2, (GLuint*)BurnTexture->Buffers); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[0]); glBufferData(GL_PIXEL_UNPACK_BUFFER, WIDTH * HEIGHT, nullptr, GL_STREAM_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[1]); glBufferData(GL_PIXEL_UNPACK_BUFFER, WIDTH * HEIGHT, nullptr, GL_STREAM_DRAW); } else { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, BurnTexture->Buffers[BurnTexture->CurrentBuffer]); BurnTexture->CurrentBuffer = (BurnTexture->CurrentBuffer + 1) & 1; } uint8_t *dest = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, WIDTH * HEIGHT, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); if (dest) { memcpy(dest, BurnArray, WIDTH * HEIGHT); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); GLint oldBinding = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldBinding); glBindTexture(GL_TEXTURE_2D, BurnTexture->Texture); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_RED, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, oldBinding); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } // Put the initial screen back to the buffer. DrawScreen(fb, fb->InitialWipeScreen); // Burn the new screen on top of it. float right = float(fb->Width); float bot = float(fb->Height); BURNVERTEX verts[4] = { { 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0, 0 }, { right, 0.f, 0.f, 1.f, 1.f, 0.f, 1, 0 }, { right, bot, 0.f, 1.f, 1.f, 1.f, 1, 1 }, { 0.f, bot, 0.f, 1.f, 0.f, 1.f, 0, 1 } }; fb->SetTexture(0, fb->FinalWipeScreen); fb->SetTexture(1, BurnTexture); fb->SetAlphaBlend(GL_FUNC_ADD, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); fb->SetPixelShader(fb->Shaders[SHADER_BurnWipe]); glActiveTexture(GL_TEXTURE1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); fb->DrawTriangleFans(2, verts); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glActiveTexture(GL_TEXTURE0); // The fire may not always stabilize, so the wipe is forced to end // after an arbitrary maximum time. return done || (BurnTime > 40); }
bool OpenGLFrameBuffer::Wiper_Burn::Run(int ticks, OpenGLFrameBuffer *fb) { bool done; BurnTime += ticks; ticks *= 2; // Make the fire burn done = false; while (!done && ticks--) { Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); done = (Density < 0); } if (BurnTexture != NULL) delete BurnTexture; BurnTexture = new FHardwareTexture(WIDTH, HEIGHT, true); // Update the burn texture with the new burn data BYTE rgb_buffer[WIDTH*HEIGHT*4]; const BYTE *src = BurnArray; DWORD *dest = (DWORD *)rgb_buffer; for (int y = HEIGHT; y != 0; --y) { for (int x = WIDTH; x != 0; --x) { BYTE s = clamp<int>((*src++)*2, 0, 255); *dest++ = MAKEARGB(s,255,255,255); } } float ur = fb->GetWidth() / FHardwareTexture::GetTexDimension(fb->GetWidth()); float vb = fb->GetHeight() / FHardwareTexture::GetTexDimension(fb->GetHeight()); // Put the initial screen back to the buffer. gl_RenderState.SetTextureMode(TM_OPAQUE); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); gl_RenderState.ResetColor(); gl_RenderState.Apply(); fb->wipestartscreen->Bind(0, 0, false); FFlatVertex *ptr; unsigned int offset, count; ptr = GLRenderer->mVBO->GetBuffer(); ptr->Set(0, 0, 0, 0, vb); ptr++; ptr->Set(0, fb->Height, 0, 0, 0); ptr++; ptr->Set(fb->Width, 0, 0, ur, vb); ptr++; ptr->Set(fb->Width, fb->Height, 0, ur, 0); ptr++; GLRenderer->mVBO->RenderCurrent(ptr, GL_TRIANGLE_STRIP, &offset, &count); gl_RenderState.SetTextureMode(TM_MODULATE); gl_RenderState.SetEffect(EFF_BURN); gl_RenderState.ResetColor(); gl_RenderState.Apply(); // Burn the new screen on top of it. fb->wipeendscreen->Bind(0, 0, false); BurnTexture->CreateTexture(rgb_buffer, WIDTH, HEIGHT, 1, true, 0); GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, offset, count); gl_RenderState.SetEffect(EFF_NONE); // The fire may not always stabilize, so the wipe is forced to end // after an arbitrary maximum time. return done || (BurnTime > 40); }
bool D3DFB::Wiper_Burn::Run(int ticks, D3DFB *fb) { bool done; BurnTime += ticks; ticks *= 2; // Make the fire burn done = false; while (!done && ticks--) { Density = wipe_CalcBurn(BurnArray, WIDTH, HEIGHT, Density); done = (Density < 0); } // Update the burn texture with the new burn data D3DLOCKED_RECT lrect; if (SUCCEEDED(BurnTexture->LockRect(0, &lrect, NULL, D3DLOCK_DISCARD))) { const BYTE *src = BurnArray; BYTE *dest = (BYTE *)lrect.pBits; for (int y = HEIGHT; y != 0; --y) { for (int x = WIDTH; x != 0; --x) { *dest++ = *src++; } dest += lrect.Pitch - WIDTH; } BurnTexture->UnlockRect(0); } // Put the initial screen back to the buffer. IDirect3DSurface9 *source = NULL, *target; if (SUCCEEDED(fb->InitialWipeScreen->GetSurfaceLevel(0, &source)) && SUCCEEDED(fb->D3DDevice->GetRenderTarget(0, &target))) { fb->D3DDevice->UpdateSurface(source, NULL, target, NULL); target->Release(); } if (source != NULL) { source->Release(); } // Burn the new screen on top of it. float top = fb->LBOffset - 0.5f; float right = float(fb->Width) - 0.5f; float bot = float(fb->Height) + top; float texright = float(fb->Width) / float(fb->FBWidth); float texbot = float(fb->Height) / float(fb->FBHeight); BURNVERTEX verts[4] = { { -0.5f, top, 0.5f, 1.f, 0.f, 0.f, 0, 0 }, { right, top, 0.5f, 1.f, texright, 0.f, 1, 0 }, { right, bot, 0.5f, 1.f, texright, texbot, 1, 1 }, { -0.5f, bot, 0.5f, 1.f, 0.f, texbot, 0, 1 } }; fb->D3DDevice->SetFVF(D3DFVF_BURNVERTEX); fb->SetTexture(0, fb->FinalWipeScreen); fb->SetTexture(1, BurnTexture); fb->SetAlphaBlend(D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA); fb->SetPixelShader(fb->BurnShader); fb->D3DDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); if (fb->SM14) { fb->D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); fb->D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); } fb->D3DDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, sizeof(BURNVERTEX)); fb->D3DDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT); if (fb->SM14) { fb->D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER); fb->D3DDevice->SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); } fb->D3DDevice->SetFVF(D3DFVF_FBVERTEX); // The fire may not always stabilize, so the wipe is forced to end // after an arbitrary maximum time. return done || (BurnTime > 40); }