#include "stdafx.h"
#include "VideoProc.h"
#include "Config.h"
#include "Platform.h"
#include "BK001001.h"

CVideoProc::CVideoProc()
	: m_pScreen(nullptr)
{
}


CVideoProc::~CVideoProc()
{}

void CVideoProc::init()
{
	m_sOSCV.init();
	m_sOSCV.clear();
	fMemory_Mod = 0.0;
	fMemoryTicks = 0.0;
}

void CVideoProc::clear()
{
	m_sOSCV.clear();
	fMemoryTicks = 0.0;
}

void CVideoProc::uninit()
{
}

void CVideoProc::InitEmulator()
{
	//параметры экрана
	m_pScreen->SetColorMode(g_Config.m_bColorMode);
	m_pScreen->SetAdaptMode(g_Config.m_bAdaptBWMode);
	m_pScreen->SetLuminoforeEmuMode(g_Config.m_bLuminoforeEmulMode);
	g_Config.m_bFullscreenMode ? m_pScreen->SetFullScreenMode() : m_pScreen->SetWindowMode();
}

void CVideoProc::clock()
{
	if (--fMemoryTicks <= 0.0)
	{
		do
		{
			Make_One_Screen_Cycle(); //тут выполняются циклы экрана
			fMemoryTicks += fMemory_Mod;
		}
		while (fMemoryTicks < 1.0);
	}
}

//это вариант точного алгоритма из VP1-037
void CVideoProc::Make_One_Screen_Cycle()
{
	register uint16_t dww = m_sOSCV.nVideoAddress & 076; // счётчик слов внутри строки
	register uint16_t dwa = m_sOSCV.nVideoAddress & 037700; //адрес строки
	register auto pBoard = g_Platform.GetBoardPtr();

	if (!(m_sOSCV.bVgate || m_sOSCV.bHgate))
	{
		m_pScreen->SetExtendedMode(!(pBoard->m_reg177664 & 01000));
		register DWORD_PTR nScrAddr = ((DWORD_PTR)pBoard->GetScreenPage()) << 14;
		register uint8_t *nScr = pBoard->GetMainMemory() + nScrAddr + m_sOSCV.nVideoAddress;
		m_pScreen->PrepareScreenLineWordRGB32(m_sOSCV.nLineCounter, dww, *(uint16_t *)nScr);
	}

	dww += 2; //переходим к следующему слову

	if (m_sOSCV.bHgate) //считаем служебное поле в строке
	{
		if (dww == 040) //отсчитали 16. служебных слов
		{
			dww = 0;
			m_sOSCV.bHgate = false;
		}
	}
	else if (dww == 0100)
	{
		//если отсчитали 32. слова, нужно теперь считать служебные
		dww = 0;
		m_sOSCV.bHgate = true;
		register int dwl = (m_sOSCV.nLineCounter + 1) & 0377; // Счётчик строк

		if (m_sOSCV.bVgate) //считаем служебные
		{
			if (--m_sOSCV.nVGateCounter <= 0) //отсчитали 64 служебные строки
			{
				dwl = 0;  //снова начнём считать информационные
				m_sOSCV.bVgate = false;
			}

			//когда считаем служебные строки, выбираем из них 353..350
			if ((m_sOSCV.nVGateCounter & 0374) == 050)    //if (050 <= m_sOSCV.nVGateCounter && m_sOSCV.nVGateCounter <= 053)
			{
				//если строки 351, 350
				if (!(m_sOSCV.nVGateCounter & 2))         //if (050 == m_sOSCV.nVGateCounter || m_sOSCV.nVGateCounter == 051)
				{
					//применяем новое смещение
					dwa = (pBoard->m_reg177664 & 0377) << 6; //VA[13:6] <= RA[7:0];
				}

				//при этом на новую строку не переходим. в одной крутимся.
			}
			else
			{
				//переход на следующую строку
				dwa += 0100; //VA[13:6] <= VA[13:6] + 8'b00000001;
			}
		}
		else
		{
			if (dwl == 0)
			{
				//если отсчитали 256 информационных строк, нужно теперь считать служебные.
				m_sOSCV.bVgate = true;
				m_sOSCV.nVGateCounter = 64;

				if ((pBoard->m_reg177662out & 040000) == 0) //если бит 14 установлен, таймер не работает.
				{
					g_Platform.GetCPUPtr()->TickIRQ2();
					//для лога дампа регистров AY
					g_Platform.GetAY8910Ptr()->log_timerTick();
				}

				g_Platform.GetMainPtr()->PostMessage(WM_SCR_DRAW);
			}

			//переход на следующую строку
			dwa += 0100; //VA[13:6] <= VA[13:6] + 8'b00000001;
		}

		m_sOSCV.nLineCounter = dwl;
	}

	m_sOSCV.nVideoAddress = (dwa | dww) & 037776;
}

