void update(bool _force) override
	{
		FrameBuffer * pCurrentBuffer = frameBufferList().getCurrent();
		const float scaleX = pCurrentBuffer != nullptr ? 1.0f / pCurrentBuffer->m_width : VI.rwidth;
		const float scaleY = pCurrentBuffer != nullptr ? 1.0f / pCurrentBuffer->m_height : VI.rheight;
		uScreenCoordsScale.set(2.0f*scaleX, -2.0f*scaleY, _force);
	}
void DepthBufferList::saveBuffer(uint32_t _address)
{
	if (!config.frameBufferEmulation.enable)
		return;

	FrameBuffer * pFrameBuffer = frameBufferList().findBuffer(_address);
	if (pFrameBuffer != NULL)
		pFrameBuffer->m_isDepthBuffer = true;

	if (m_pCurrent == NULL || m_pCurrent->m_address != _address)
		m_pCurrent = findBuffer(_address);

	if (m_pCurrent != NULL && pFrameBuffer != NULL && m_pCurrent->m_width != pFrameBuffer->m_width) {
		removeBuffer(_address);
		m_pCurrent = NULL;
	}

	if (m_pCurrent == NULL) {
		m_list.emplace_front();
		DepthBuffer & buffer = m_list.front();

		buffer.m_address = _address;
		buffer.m_width = pFrameBuffer != NULL ? pFrameBuffer->m_width : VI.width;

		buffer.initDepthBufferTexture(pFrameBuffer);

		m_pCurrent = &buffer;
	}

	frameBufferList().attachDepthBuffer();

#ifdef DEBUG
		DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "DepthBuffer_SetBuffer( 0x%08X ); color buffer is 0x%08X\n",
			address, ( pFrameBuffer != NULL &&  pFrameBuffer->m_FBO > 0) ?  pFrameBuffer->m_startAddress : 0
		);
#endif

}
void DepthBufferList::clearBuffer(uint32_t _uly, uint32_t _lry)
{
	if (m_pCurrent == NULL)
		return;
	m_pCurrent->m_cleared = true;
	m_pCurrent->m_uly = _uly;
	m_pCurrent->m_lry = _lry;
#ifdef GL_IMAGE_TEXTURES_SUPPORT
	if (m_pCurrent->m_FBO == 0 || !video().getRender().isImageTexturesSupported() || config.frameBufferEmulation.N64DepthCompare == 0)
		return;
	float color[4] = {1.0f, 1.0f, 0.0f, 1.0f};
	glBindImageTexture(depthImageUnit, 0, 0, GL_FALSE, 0, GL_READ_WRITE, fboFormats.depthImageInternalFormat);
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_pCurrent->m_FBO);
	const uint32_t cycleType = gDP.otherMode.cycleType;
	gDP.otherMode.cycleType = G_CYC_FILL;
	video().getRender().drawRect(0,0,VI.width, VI.height, color);
	gDP.otherMode.cycleType = cycleType;
	glBindImageTexture(depthImageUnit, m_pCurrent->m_pDepthImageTexture->glName, 0, GL_FALSE, 0, GL_READ_WRITE, fboFormats.depthImageInternalFormat);
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferList().getCurrent()->m_FBO);
#endif // GL_IMAGE_TEXTURES_SUPPORT
}
	void update(bool _force) override
	{
		FrameBuffer * pBuffer = frameBufferList().getCurrent();
		if (pBuffer == nullptr || pBuffer->m_pDepthBuffer == nullptr)
			return;

		const int nDepthEnabled = (gSP.geometryMode & G_ZBUFFER) > 0 ? 1 : 0;
		uEnableDepth.set(nDepthEnabled, _force);
		if (nDepthEnabled == 0) {
			uEnableDepthCompare.set(0, _force);
			uEnableDepthUpdate.set(0, _force);
		}
		else {
			uEnableDepthCompare.set(gDP.otherMode.depthCompare, _force);
			uEnableDepthUpdate.set(gDP.otherMode.depthUpdate, _force);
		}
		uDepthMode.set(gDP.otherMode.depthMode, _force);
		uDepthSource.set(gDP.otherMode.depthSource, _force);
		if (gDP.otherMode.depthSource == G_ZS_PRIM)
			uDeltaZ.set(gDP.primDepth.deltaZ, _force);
	}
void displayLoadProgress(const wchar_t *format, ...)
{
	va_list args;
	wchar_t wbuf[INFO_BUF];
	char buf[INFO_BUF];

	// process input
#ifdef OS_ANDROID
	const u32 bufSize = 2048;
	char cbuf[bufSize];
	char fmt[bufSize];
	wcstombs(fmt, format, bufSize);
	va_start(args, format);
	vsprintf(cbuf, fmt, args);
	va_end(args);
	mbstowcs(wbuf, cbuf, INFO_BUF);
#else
	va_start(args, format);
	vswprintf(wbuf, INFO_BUF, format, args);
	va_end(args);
#endif

	// XXX: convert to multibyte
	wcstombs(buf, wbuf, INFO_BUF);

	FrameBuffer* pBuffer = frameBufferList().getCurrent();
	if (pBuffer != nullptr)
		gfxContext.bindFramebuffer(graphics::bufferTarget::DRAW_FRAMEBUFFER, graphics::ObjectHandle::null);

	GraphicsDrawer & drawer = dwnd().getDrawer();
	drawer.clearColorBuffer(nullptr);
	drawer.drawText(buf, -0.9f, 0);
	dwnd().swapBuffers();

	if (pBuffer != nullptr)
		gfxContext.bindFramebuffer(graphics::bufferTarget::DRAW_FRAMEBUFFER, pBuffer->m_FBO);
}