private void CopyTexture( NvGpuVmm Vmm, TextureInfo Texture, byte[] Buffer, int Width, int Height) { TextureWriter.Write(Vmm, Texture, Buffer, Width, Height); }
static void Main(string[] args) { if (args.Length < 1) { Usage(); return; } void WithIO(Action <Stream, Stream> action) { using (var fi = File.OpenRead(args[1])) using (var fo = File.OpenWrite(args[2])) action(fi, fo); } var makepkg = true; switch (args[0]) { case "rbmid2mid": WithIO((fi, fo) => { var rbmid = RBMidReader.ReadStream(fi); var midi = RBMidConverter.ToMid(rbmid); MidiCS.MidiFileWriter.WriteSMF(midi, fo); }); break; case "mid2rbmid": WithIO((fi, fo) => { var mid = MidiCS.MidiFileReader.FromStream(fi); var rbmid = RBMidConverter.ToRBMid(mid); RBMidWriter.WriteStream(rbmid, fo); }); break; case "reprocess": WithIO((fi, fo) => { var rbmid = RBMidReader.ReadStream(fi); var processed = RBMidConverter.ToRBMid(RBMidConverter.ToMid(rbmid), rbmid.HopoThreshold); RBMidWriter.WriteStream(processed, fo); }); break; case "tex2png": WithIO((fi, fo) => { var tex = TextureReader.ReadStream(fi); var bitmap = TextureConverter.ToBitmap(tex, 0); bitmap.Save(fo, System.Drawing.Imaging.ImageFormat.Png); }); break; case "png2tex": WithIO((fi, fo) => { var img = System.Drawing.Image.FromStream(fi); var tex = TextureConverter.ToTexture(img); TextureWriter.WriteStream(tex, fo); }); break; case "milopng2tex": WithIO((fi, fo) => { var tex = TextureConverter.MiloPngToTexture(fi); TextureWriter.WriteStream(tex, fo); }); break; case "mesh2obj": { var input = args[1]; var output = args[2]; using (var fi = File.OpenRead(input)) { var mesh = HxMeshReader.ReadStream(fi); var obj = HxMeshConverter.ToObj(mesh); File.WriteAllText(output, obj); } break; } case "milo2lip": case "milo2lips": case "milo2lipsync": WithIO((fi, fo) => { var milo = MiloFile.ReadFromStream(fi); var lipsync = LipsyncConverter.FromMilo(milo); new LipsyncWriter(fo).WriteStream(lipsync); }); break; case "version": var assembly = System.Reflection.Assembly.GetExecutingAssembly(); var version = FileVersionInfo.GetVersionInfo(assembly.Location).FileVersion; var libAssembly = System.Reflection.Assembly.GetAssembly(typeof(RBMid)); var libVersion = FileVersionInfo.GetVersionInfo(libAssembly.Location).FileVersion; Console.WriteLine($"ForgeTool v{version}"); Console.WriteLine($"LibForge v{libVersion}"); break; case "test": { var dir = args[1]; int succ = 0, warn = 0, fail = 0; var files = dir.EndsWith(".rbmid_ps4") || dir.EndsWith(".rbmid_pc") ? new[] { dir } : Directory.EnumerateFiles(dir, "*.rbmid_*"); foreach (var f in files) { var info = new FileInfo(f); var name = info.Name; using (var fi = File.OpenRead(f)) { try { var rbmid = RBMidReader.ReadStream(fi); var midi = RBMidConverter.ToMid(rbmid); var rbmid2 = RBMidConverter.ToRBMid(midi, rbmid.HopoThreshold); using (var ms = new MemoryStream((int)fi.Length)) { // TODO: Switch this to rbmid2 once we are generating all events // (regardless of whether the event data are all correct) RBMidWriter.WriteStream(rbmid, ms); ms.Position = 0; if (ms.Length == fi.Length) { var comparison = rbmid.Compare(rbmid2); if (comparison != null) { throw new CompareException("File comparison failed at field: " + comparison); } Console.WriteLine($"[OK] {name}"); succ++; } else { Console.Write($"[WARN] {name}:"); Console.WriteLine($" Processed file had different length ({fi.Length} orig, {ms.Length} processed)"); warn++; } } } catch (CompareException e) { Console.WriteLine($"[WARN] {name}: {e.Message}"); warn++; } catch (Exception e) { Console.WriteLine($"[ERROR] {name}: {e.Message}"); Console.WriteLine(e.StackTrace); fail++; } } } Console.WriteLine($"Summary: {succ} OK, {warn} WARN, {fail} ERROR"); if (warn > 0) { Console.WriteLine("(a = converted file, b = original)"); } } break; case "simpletest": { var dir = args[1]; int succ = 0, warn = 0, fail = 0; foreach (var f in Directory.EnumerateFiles(dir, "*.rbmid_*")) { var info = new FileInfo(f); var name = info.Name; using (var fi = File.OpenRead(f)) { try { var rbmid = RBMidReader.ReadStream(fi); using (var ms = new MemoryStream((int)fi.Length)) { RBMidWriter.WriteStream(rbmid, ms); ms.Position = 0; if (ms.Length == fi.Length) { succ++; } else { Console.WriteLine($"[WARN] {name}:"); Console.WriteLine($" Processed file had different length ({fi.Length} orig, {ms.Length} processed)"); warn++; } } } catch (Exception e) { Console.WriteLine($"[ERROR] {name}:"); Console.WriteLine(" " + e.Message); fail++; } } } Console.WriteLine($"Summary: {succ} OK, {warn} WARN, {fail} ERROR"); } break; case "testrbsong": { var dir = args[1]; int succ = 0, warn = 0, fail = 0; var files = dir.EndsWith(".rbsong") ? new[] { dir } : Directory.EnumerateFiles(dir, "*.rbsong"); foreach (var f in files) { var info = new FileInfo(f); var name = info.Name; using (var fi = File.OpenRead(f)) { try { var rbsong = new RBSongReader(fi).Read(); using (var ms = new MemoryStream((int)fi.Length)) { new RBSongWriter(ms).WriteStream(rbsong); ms.Position = 0; if (ms.Length == fi.Length) { succ++; } else { Console.WriteLine($"[WARN] {name}:"); Console.WriteLine($" Processed file had different length ({fi.Length} orig, {ms.Length} processed)"); warn++; } } } catch (Exception e) { Console.WriteLine($"[ERROR] {name}:"); Console.WriteLine(" " + e.Message); fail++; } } } Console.WriteLine($"Summary: {succ} OK, {warn} WARN, {fail} ERROR"); if (fail > 0) { Console.WriteLine("(a = converted file, b = original)"); } } break; case "rbsong2rbsong": WithIO((i, o) => new RBSongWriter(o).WriteStream(new RBSongReader(i).Read())); break; case "con2gp4": makepkg = false; goto case "con2pkg"; case "con2pkg": { var i = 0; bool eu = false; string pkgId = null, pkgDesc = null; while (++i < args.Length - 4) { switch (args[i]) { case "--scee": eu = true; continue; case "--id": pkgId = args[++i]; continue; case "--desc": pkgDesc = args[++i]; continue; } break; } if (makepkg) { var cmd = args[i++]; var con = args[i++]; var dest = args[i++]; var tmpDir = Path.Combine(Path.GetTempPath(), "forgetool_tmp_build"); if (!Directory.Exists(con)) { var conFilename = Path.GetFileName(con); PkgCreator.ConToGp4(con, tmpDir, eu, pkgId, pkgDesc); } else { PkgCreator.ConsToGp4(con, tmpDir, eu, pkgId, pkgDesc); } PkgCreator.BuildPkg(cmd, Path.Combine(tmpDir, "project.gp4"), dest); Directory.Delete(tmpDir, true); } else { var con = args[i++]; var dest = args[i++]; PkgCreator.ConToGp4(con, dest, eu, pkgId, pkgDesc); } } break; default: Usage(); break; } }
public void Flush() { if (m_mesh == null) { Debug.LogWarning("AlembicPointsRenderer: mesh is not assigned"); return; } if (m_materials == null || m_materials.Length == 0 || (m_materials.Length == 1 && m_materials[0] == null)) { Debug.LogWarning("AlembicPointsRenderer: material is not assigned"); return; } var pointsCloud = GetComponent <AlembicPointsCloud>(); int max_instances = pointsCloud.m_peakVertexCount; int instance_count = pointsCloud.m_count; m_bounds.center = mul(pointsCloud.m_boundsCenter, m_trans_scale); m_bounds.extents = mul(pointsCloud.m_boundsExtents, m_trans_scale); if (instance_count == 0) { return; } // nothing to draw // update data texture if (m_texPositions == null || !m_texPositions.IsCreated()) { int height = ceildiv(max_instances, TextureWidth); m_texPositions = CreateDataTexture(TextureWidth, height, RenderTextureFormat.ARGBFloat); m_texVelocities = CreateDataTexture(TextureWidth, height, RenderTextureFormat.ARGBFloat); m_texIDs = CreateDataTexture(TextureWidth, height, RenderTextureFormat.RFloat); } var ps = Marshal.UnsafeAddrOfPinnedArrayElement(pointsCloud.m_abcPositions, 0); var ids = Marshal.UnsafeAddrOfPinnedArrayElement(pointsCloud.m_abcIDs, 0); TextureWriter.Write(m_texPositions, ps, pointsCloud.m_count, TextureWriter.tDataFormat.Float3); TextureWriter.Write(m_texIDs, ids, pointsCloud.m_count, TextureWriter.tDataFormat.LInt); // update expanded mesh if (m_expanded_mesh != null) { // destroy existing expanded mesh if mesh is replaced if (m_expanded_mesh.name != m_mesh.name + "_expanded") { m_expanded_mesh = null; } } if (m_expanded_mesh == null) { m_expanded_mesh = CreateExpandedMesh(m_mesh, max_instances, out m_instances_par_batch); m_expanded_mesh.UploadMeshData(true); m_expanded_mesh.name = m_mesh.name + "_expanded"; } if (m_actual_materials == null) { m_actual_materials = new List <List <Material> >(); while (m_actual_materials.Count < m_materials.Length) { m_actual_materials.Add(new List <Material>()); } } var trans = GetComponent <Transform>(); m_expanded_mesh.bounds = m_bounds; m_count_rate = Mathf.Max(m_count_rate, 0.0f); instance_count = Mathf.Min((int)(instance_count * m_count_rate), (int)(max_instances * m_count_rate)); int batch_count = ceildiv(instance_count, m_instances_par_batch); // clone materials if needed for (int i = 0; i < m_actual_materials.Count; ++i) { var materials = m_actual_materials[i]; while (materials.Count < batch_count) { Material m = CloneMaterial(m_materials[i], materials.Count); materials.Add(m); } } // update materials var worldToLocalMatrix = trans.localToWorldMatrix; for (int i = 0; i < m_actual_materials.Count; ++i) { var materials = m_actual_materials[i]; for (int j = 0; j < materials.Count; ++j) { var m = materials[j]; m.SetInt("_BatchBegin", j * m_instances_par_batch); m.SetTexture("_PositionBuffer", m_texPositions); m.SetTexture("_VelocityBuffer", m_texVelocities); m.SetTexture("_IDBuffer", m_texIDs); m.SetInt("_NumInstances", instance_count); m.SetVector("_CountRate", new Vector4(m_count_rate, 1.0f / m_count_rate, 0.0f, 0.0f)); m.SetVector("_ModelScale", m_model_scale); m.SetVector("_TransScale", m_trans_scale); m.SetMatrix("_Transform", worldToLocalMatrix); } } var childRenderers = transform.GetComponentsInChildren <MeshRenderer>(); if (m_makeChildRenderers) { // create child renderers if needed int missing = m_materials.Length; if (childRenderers != null) { missing -= childRenderers.Length; } if (missing > 0) { for (int i = 0; i < missing; i++) { MakeChildRenderer(childRenderers.Length + i); } childRenderers = transform.GetComponentsInChildren <MeshRenderer>(); } // assign materials to child renderers for (int i = 0; i < m_actual_materials.Count; ++i) { var materials = m_actual_materials[i]; materials.RemoveRange(batch_count, materials.Count - batch_count); childRenderers[i].sharedMaterials = materials.ToArray(); } // update mesh in child renderers if m_mesh is replaced for (int i = 0; i < childRenderers.Length; ++i) { var mesh_filter = childRenderers[i].GetComponent <MeshFilter>(); if (mesh_filter.sharedMesh != m_expanded_mesh) { mesh_filter.sharedMesh = m_expanded_mesh; } } } else { // clear child renderers if (childRenderers != null) { foreach (var child in childRenderers) { if (child != null) { DestroyImmediate(child.gameObject); } } childRenderers = null; } // issue draw calls int layer = gameObject.layer; Matrix4x4 matrix = Matrix4x4.identity; m_actual_materials.ForEach(a => { for (int i = 0; i < batch_count; ++i) { Graphics.DrawMesh(m_expanded_mesh, matrix, a[i], layer, null, 0, null, m_cast_shadow, m_receive_shadow); } }); } }
static void Main(string[] args) { if (args.Length < 1) { Usage(); return; } void WithIO(Action <Stream, Stream> action) { using (var fi = File.OpenRead(args[1])) using (var fo = File.OpenWrite(args[2])) action(fi, fo); } var makepkg = true; switch (args[0]) { case "rbmid2mid": WithIO((fi, fo) => { var rbmid = RBMidReader.ReadStream(fi); var midi = RBMidConverter.ToMid(rbmid); MidiCS.MidiFileWriter.WriteSMF(midi, fo); }); break; case "mid2rbmid": WithIO((fi, fo) => { var mid = MidiCS.MidiFileReader.FromStream(fi); var rbmid = RBMidConverter.ToRBMid(mid); RBMidWriter.WriteStream(rbmid, fo); }); break; case "reprocess": WithIO((fi, fo) => { var rbmid = RBMidReader.ReadStream(fi); var processed = RBMidConverter.ToRBMid(RBMidConverter.ToMid(rbmid), rbmid.HopoThreshold); RBMidWriter.WriteStream(processed, fo); }); break; case "tex2png": WithIO((fi, fo) => { var tex = TextureReader.ReadStream(fi); var bitmap = TextureConverter.ToBitmap(tex, 0); bitmap.Save(fo, System.Drawing.Imaging.ImageFormat.Png); }); break; case "png2tex": WithIO((fi, fo) => { var img = System.Drawing.Image.FromStream(fi); var tex = TextureConverter.ToTexture(img); TextureWriter.WriteStream(tex, fo); }); break; case "milopng2tex": WithIO((fi, fo) => { var tex = TextureConverter.MiloPngToTexture(fi); TextureWriter.WriteStream(tex, fo); }); break; case "mesh2obj": { var input = args[1]; var output = args[2]; using (var fi = File.OpenRead(input)) { var mesh = HxMeshReader.ReadStream(fi); var obj = HxMeshConverter.ToObj(mesh); File.WriteAllText(output, obj); } break; } case "milo2lip": case "milo2lips": case "milo2lipsync": WithIO((fi, fo) => { var milo = MiloFile.ReadFromStream(fi); var lipsync = LipsyncConverter.FromMilo(milo); new LipsyncWriter(fo).WriteStream(lipsync); }); break; case "version": var assembly = System.Reflection.Assembly.GetExecutingAssembly(); var version = FileVersionInfo.GetVersionInfo(assembly.Location).FileVersion; var libAssembly = System.Reflection.Assembly.GetAssembly(typeof(RBMid)); var libVersion = FileVersionInfo.GetVersionInfo(libAssembly.Location).FileVersion; Console.WriteLine($"ForgeTool v{version}"); Console.WriteLine($"LibForge v{libVersion}"); break; case "test": { var dir = args[1]; int succ = 0, warn = 0, fail = 0; var files = dir.EndsWith(".rbmid_ps4") || dir.EndsWith(".rbmid_pc") ? new[] { dir } : Directory.EnumerateFiles(dir, "*.rbmid_*"); foreach (var f in files) { var info = new FileInfo(f); var name = info.Name; using (var fi = File.OpenRead(f)) { try { var rbmid = RBMidReader.ReadStream(fi); var midi = RBMidConverter.ToMid(rbmid); var rbmid2 = RBMidConverter.ToRBMid(midi, rbmid.HopoThreshold); using (var ms = new MemoryStream((int)fi.Length)) { // TODO: Switch this to rbmid2 once we are generating all events // (regardless of whether the event data are all correct) RBMidWriter.WriteStream(rbmid, ms); ms.Position = 0; if (ms.Length == fi.Length) { var comparison = rbmid.Compare(rbmid2); if (comparison != null) { throw new CompareException("File comparison failed at field: " + comparison); } Console.WriteLine($"[OK] {name}"); succ++; } else { Console.Write($"[WARN] {name}:"); Console.WriteLine($" Processed file had different length ({fi.Length} orig, {ms.Length} processed)"); warn++; } } } catch (CompareException e) { Console.WriteLine($"[WARN] {name}: {e.Message}"); warn++; } catch (Exception e) { Console.WriteLine($"[ERROR] {name}: {e.Message}"); Console.WriteLine(e.StackTrace); fail++; } } } Console.WriteLine($"Summary: {succ} OK, {warn} WARN, {fail} ERROR"); if (warn > 0) { Console.WriteLine("(a = converted file, b = original)"); } if (warn > 0 || fail > 0) { Environment.Exit(1); } } break; case "simpletest": { var dir = args[1]; int succ = 0, warn = 0, fail = 0; foreach (var f in Directory.EnumerateFiles(dir, "*.rbmid_*")) { var info = new FileInfo(f); var name = info.Name; using (var fi = File.OpenRead(f)) { try { var rbmid = RBMidReader.ReadStream(fi); using (var ms = new MemoryStream((int)fi.Length)) { RBMidWriter.WriteStream(rbmid, ms); ms.Position = 0; if (ms.Length == fi.Length) { succ++; } else { Console.WriteLine($"[WARN] {name}:"); Console.WriteLine($" Processed file had different length ({fi.Length} orig, {ms.Length} processed)"); warn++; } } } catch (Exception e) { Console.WriteLine($"[ERROR] {name}:"); Console.WriteLine(" " + e.Message); fail++; } } } Console.WriteLine($"Summary: {succ} OK, {warn} WARN, {fail} ERROR"); } break; case "testrbsong": { var dir = args[1]; int succ = 0, warn = 0, fail = 0; var files = dir.EndsWith(".rbsong") ? new[] { dir } : Directory.EnumerateFiles(dir, "*.rbsong"); foreach (var f in files) { var info = new FileInfo(f); var name = info.Name; using (var fi = File.OpenRead(f)) { try { var rbsong = new RBSongResource(); rbsong.Load(fi); using (var ms = new MemoryStream((int)fi.Length)) { new RBSongResourceWriter(ms).WriteStream(rbsong); ms.Position = 0; if (ms.Length == fi.Length) { succ++; } else { Console.WriteLine($"[WARN] {name}:"); Console.WriteLine($" Processed file had different length ({fi.Length} orig, {ms.Length} processed)"); warn++; } } } catch (Exception e) { Console.WriteLine($"[ERROR] {name}:"); Console.WriteLine(" " + e.Message); fail++; } } } Console.WriteLine($"Summary: {succ} OK, {warn} WARN, {fail} ERROR"); if (fail > 0) { Console.WriteLine("(a = converted file, b = original)"); } } break; case "rbsong2rbsong": WithIO((i, o) => { var rbsong = new RBSongResource(); rbsong.Load(i); new RBSongResourceWriter(o).WriteStream(rbsong); }); break; case "con2gp4": makepkg = false; goto case "con2pkg"; case "con2pkg": { var i = 0; bool eu = false; string pkgId = null, pkgDesc = null; while (++i < args.Length - 3) { switch (args[i]) { case "--scee": eu = true; continue; case "--id": pkgId = args[++i]; continue; case "--desc": pkgDesc = args[++i]; continue; } break; } if (makepkg) { var con = args[i++]; var dest = args[i++]; var tmpDir = Path.Combine(Path.GetTempPath(), "forgetool_tmp_build"); if (!Directory.Exists(con)) { var conFilename = Path.GetFileName(con); PkgCreator.ConToGp4(con, tmpDir, eu, pkgId, pkgDesc); } else { PkgCreator.ConsToGp4(con, tmpDir, eu, pkgId, pkgDesc); } PkgCreator.BuildPkg(Path.Combine(tmpDir, "project.gp4"), dest); Directory.Delete(tmpDir, true); } else { var con = args[i++]; var dest = args[i++]; PkgCreator.ConToGp4(con, dest, eu, pkgId, pkgDesc); } } break; case "csv2txt": { var input = args[1]; var output = args[2]; using (var fi = File.OpenRead(input)) { var csv = CsvData.LoadFile(fi); File.WriteAllText(output, csv.ToString()); } } break; case "arkorder": { var input = args[1]; var output = args[2]; var sb = new StringBuilder(); var archive = new Archive(input); using (var o = File.OpenWrite(output)) using (var sw = new StreamWriter(o)) { archive.WriteArkorder(sw); } } break; case "arkbuild": { var filedir = args[1]; var arkorder = args[2]; var outdir = args[3]; var name = args[4]; if (!Directory.Exists(filedir)) { Console.WriteLine($"Error: {filedir} does not exist."); return; } if (!Directory.Exists(outdir)) { Console.WriteLine($"Error: {outdir} does not exist."); return; } if (!File.Exists(arkorder)) { Console.WriteLine($"Error: {arkorder} not found."); return; } var arks = new List <List <Tuple <string, IFile> > >(); DataArray arkOrder; using (var order = File.OpenRead(arkorder)) using (var reader = new StreamReader(order)) { arkOrder = DtxCS.DTX.FromDtaStream(order); } int arkIndex = 0; arks.Add(new List <Tuple <string, IFile> >()); foreach (var x in arkOrder.Children) { if (x is DataSymbol s) { var fullPath = Path.Combine(filedir, s.Name.Replace('/', Path.DirectorySeparatorChar)); if (!File.Exists(fullPath)) { Console.WriteLine($"Error: {fullPath} could not be found."); return; } IFile f = Util.LocalFile(fullPath); arks[arkIndex].Add(Tuple.Create(s.Name, f)); } else if (x is DataCommand c && c.Symbol(0).Name == "split_ark") { arkIndex++; arks[arkIndex] = new List <Tuple <string, IFile> >(); } } var builder = new ArkBuilder(name, arks); Console.Write($"Writing {name}.hdr and ark files to {outdir}..."); builder.Save(outdir); } break; default: Usage(); break; } }
private void TextureCopy(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) { CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0; int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth); int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight); int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch); int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions); bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0; int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth); int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight); int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch); int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions); TextureSwizzle SrcSwizzle = SrcLinear ? TextureSwizzle.Pitch : TextureSwizzle.BlockLinear; TextureSwizzle DstSwizzle = DstLinear ? TextureSwizzle.Pitch : TextureSwizzle.BlockLinear; int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); long SrcKey = Vmm.GetPhysicalAddress(SrcAddress); long DstKey = Vmm.GetPhysicalAddress(DstAddress); bool IsSrcFb = Gpu.Engine3d.IsFrameBufferPosition(SrcKey); bool IsDstFb = Gpu.Engine3d.IsFrameBufferPosition(DstKey); TextureInfo SrcTexture() { return(new TextureInfo( SrcAddress, SrcWidth, SrcHeight, SrcPitch, SrcBlockHeight, 1, SrcSwizzle, GalTextureFormat.A8B8G8R8)); } TextureInfo DstTexture() { return(new TextureInfo( DstAddress, DstWidth, DstHeight, DstPitch, DstBlockHeight, 1, DstSwizzle, GalTextureFormat.A8B8G8R8)); } //TODO: fb -> fb copies, tex -> fb copies, formats other than RGBA8, //make it throw for unimpl stuff (like the copy mode)... if (IsSrcFb && IsDstFb) { //Frame Buffer -> Frame Buffer copy. Gpu.Renderer.FrameBuffer.Copy( SrcKey, DstKey, 0, 0, SrcWidth, SrcHeight, 0, 0, DstWidth, DstHeight); } if (IsSrcFb) { //Frame Buffer -> Texture copy. Gpu.Renderer.FrameBuffer.GetBufferData(SrcKey, (byte[] Buffer) => { TextureInfo Src = SrcTexture(); TextureInfo Dst = DstTexture(); if (Src.Width != Dst.Width || Src.Height != Dst.Height) { throw new NotImplementedException("Texture resizing is not supported"); } TextureWriter.Write(Vmm, Dst, Buffer); }); } else if (IsDstFb) { //Texture -> Frame Buffer copy. const GalTextureFormat Format = GalTextureFormat.A8B8G8R8; byte[] Buffer = TextureReader.Read(Vmm, SrcTexture()); Gpu.Renderer.FrameBuffer.SetBufferData( DstKey, DstWidth, DstHeight, Format, Buffer); } else { //Texture -> Texture copy. TextureInfo Src = SrcTexture(); TextureInfo Dst = DstTexture(); if (Src.Width != Dst.Width || Src.Height != Dst.Height) { throw new NotImplementedException("Texture resizing is not supported"); } TextureWriter.Write(Vmm, Dst, TextureReader.Read(Vmm, Src)); } }