AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Script/NesEmulator/VideoProvider.cs

178 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AxibugEmuOnline.Client.Common;
using System;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
using VirtualNes.Core;
using static UnityEngine.UI.CanvasScaler;
namespace AxibugEmuOnline.Client
{
public class VideoProvider : MonoBehaviour
{
#region UI_REF
public NesEmulator NesEmu;
public Canvas DrawCanvas;
public RawImage Image;
#endregion
#region GPU_TURBO
//图像数据字节数
private int TexBufferSize_gpu;
//图像数据指针
private IntPtr wrapTexBufferPointer_gpu;
//Unity 2D纹理对象,用于UI上绘制最终输出画面
private Texture2D wrapTex_gpu;
//nes调色板数据,已转换为unity纹理对象
private Texture2D pPal_gpu;
private Material GPUTurboMat_gpu;
#endregion
#region CPU
//图像数据字节数
private int TexBufferSize_cpu;
//图像数据指针
private GCHandle wrapTexBufferGH;
private IntPtr wrapTexBufferPointer_cpu;
//Unity 2D纹理对象,用于UI上绘制最终输出画面
private Texture2D wrapTex_cpu;
#endregion
public bool GPUTurbo = true;
private void Awake()
{
DrawCanvas.worldCamera = Camera.main;
GPUTurboMat_gpu = Image.material;
}
private void OnDestroy()
{
if (wrapTexBufferGH.IsAllocated)
wrapTexBufferGH.Free();
}
public unsafe void SetDrawData(uint* screenData)
{
PrepareUI(screenData);
if (GPUTurbo) PrepareForGPU(screenData);//判断使用GPU还是CPU
else PrepareForCPU(screenData);//使用CPU
if (GPUTurbo)
{
wrapTex_gpu.LoadRawTextureData(wrapTexBufferPointer_gpu, TexBufferSize_gpu);
wrapTex_gpu.Apply();
}
else
{
wrapTex_cpu.LoadRawTextureData(wrapTexBufferPointer_cpu, TexBufferSize_cpu);
wrapTex_cpu.Apply();
}
}
private unsafe void PrepareUI(uint* screenData)
{
if (GPUTurbo)
{
if (Image.material != GPUTurboMat_gpu) Image.material = GPUTurboMat_gpu;
if (wrapTex_gpu == null)
{
wrapTex_gpu = new Texture2D(PPU.SCREEN_WIDTH, PPU.SCREEN_HEIGHT, TextureFormat.RGBA32, false);
wrapTex_gpu.filterMode = FilterMode.Point;
wrapTexBufferPointer_gpu = (IntPtr)screenData;
TexBufferSize_gpu = wrapTex_gpu.width * wrapTex_gpu.height * 4;
}
if (Image.texture != wrapTex_gpu) Image.texture = wrapTex_gpu;
}
else
{
if (Image.material == GPUTurboMat_gpu) Image.material = null;
if (wrapTex_cpu == null)
{
wrapTex_cpu = new Texture2D(PPU.SCREEN_WIDTH - 16, PPU.SCREEN_HEIGHT, TextureFormat.RGBA32, false);
wrapTex_cpu.filterMode = FilterMode.Point;
uint[] cpuTexBuffer = new uint[wrapTex_cpu.width * wrapTex_cpu.height];
wrapTexBufferGH = GCHandle.Alloc(cpuTexBuffer, GCHandleType.Pinned);
wrapTexBufferPointer_cpu = wrapTexBufferGH.AddrOfPinnedObject();
TexBufferSize_cpu = cpuTexBuffer.Length * 4;
}
if (Image.texture != wrapTex_cpu) Image.texture = wrapTex_cpu;
}
}
private unsafe void PrepareForGPU(uint* screenData)
{
if (pPal_gpu == null)
{
var palRaw = PaletteDefine.m_cnPalette[0];
pPal_gpu = new Texture2D(palRaw.Length, 1, TextureFormat.RGBA32, false);
pPal_gpu.filterMode = FilterMode.Point;
for (int i = 0; i < palRaw.Length; i++)
{
uint colorRaw = palRaw[i];
var argbColor = BitConverter.GetBytes(colorRaw);
Color temp = Color.white;
temp.r = argbColor[2] / 255f;
temp.g = argbColor[1] / 255f;
temp.b = argbColor[0] / 255f;
temp.a = 1;
pPal_gpu.SetPixel(i, 0, temp);
}
pPal_gpu.Apply();
GPUTurboMat_gpu.SetTexture("_PalTex", pPal_gpu);
}
}
private unsafe void PrepareForCPU(uint* screenData)
{
int pScn = 0;
int width;
var Dst = (uint*)wrapTexBufferPointer_cpu;
var pDst = 0;
var palRaw = PaletteDefine.m_cnPalette[0];
for (int line = 0; line < PPU.SCREEN_HEIGHT; line++)
{
//PS如果是CPU计算宽度减少16的不必要部分才能对齐
width = PPU.SCREEN_WIDTH - 16;
while (width > 0)
{
var edx = screenData[pScn + 8];
uint index = edx & 0xFF;
//按下标颜色查找表中真实颜色
var colorData = palRaw[index];
//dst中颜色排列为abgr,而colorData排列为argb
uint r = (colorData & 0x00FF0000) >> 16; // 提取Red通道
uint g = (colorData & 0x0000FF00) >> 8; // 提取Green通道
uint b = (colorData & 0x000000FF); // 提取Blue通道
//用rgb构建颜色对象如果非unity 可以用这个rgb 构建System.Drawing.Color 单个颜色对象)
uint abgr = 0xFF000000 | (b << 16) | (g << 8) | (r << 0);
//放进颜色矩阵
Dst[pDst] = abgr;
pScn += 1;
pDst += 1;
width -= 1;
}
pScn += 16;
}
}
}
}