public LcdController(GameboyAdvance gba) { this.gba = gba; frameBuffer0 = new DirectBitmap(Screen_X_Resolution, Screen_Y_Resolution); frameBuffer1 = new DirectBitmap(Screen_X_Resolution, Screen_Y_Resolution); FrameBuffer = frameBuffer0; drawBuffer = frameBuffer1; this.Palettes = new Palettes(); DisplayControlRegister = new DisplayControlRegister(this); DispStatRegister = new DisplayStatusRegister(this); BgControlRegisters = new BgControlRegister[4]; Bg = new Background[4]; for (int i = 0; i < 4; i++) { BgControlRegisters[i] = new BgControlRegister(this, i); Bg[i] = new Background(gba, i, BgControlRegisters[i]); priorityObjList[i] = new List<Obj>(); } Obj = new Obj[Max_Sprites]; for (int i = 0; i < Max_Sprites; i++) { Obj[i] = new Obj(gba, new ObjAttributes(gba, i * 8, gba.Memory.OamRam)); } OamAffineMatrices = new OamAffineMatrix[Max_OAM_Matrices]; UInt32 address = 0x00000006; for (int i = 0; i < 32; i++) { OamAffineMatrices[i] = new OamAffineMatrix(gba.Memory.OamRam, address); address += 0x20; } Windows = new Window[4]; for (int i = 0; i < 4; i++) { Windows[i] = new Window(gba); } #if THREADED_SCANLINE drawScanline = false; exitThread = false; scanlineThread = new Thread(new ThreadStart(ScanlineThread)); scanlineThread.Start(); #endif }
public LcdController(GameboyAdvance gba) { this.gba = gba; frameBuffer0 = new DirectBitmap(Screen_X_Resolution, Screen_Y_Resolution); frameBuffer1 = new DirectBitmap(Screen_X_Resolution, Screen_Y_Resolution); FrameBuffer = frameBuffer0; drawBuffer = frameBuffer1; this.Palettes = new Palettes(); DisplayControlRegister = new DisplayControlRegister(gba, this); DispStatRegister = new DisplayStatusRegister(gba, this); Bg = new Background[4]; UInt32 scrollBaseAddress = 0x4000010; for (int i = 0; i < 4; i++) { BgControlRegister cntReg = new BgControlRegister(gba, this, i, (UInt32) (0x4000008 + (i * 2))); MemoryRegister16 scrollXReg = new MemoryRegister16(gba.Memory, scrollBaseAddress, false, true, 0x01); MemoryRegister16 scrollYReg = new MemoryRegister16(gba.Memory, scrollBaseAddress + 2, false, true, 0x01); Bg[i] = new Background(gba, i, cntReg, scrollXReg, scrollYReg); scrollBaseAddress += 4; } VCount = new MemoryRegister8(gba.Memory, 0x04000006, true, false); this.ObjController = new ObjController(gba); Windows = new Window[4]; Windows[0] = new Window(gba, 0x4000040, 0x4000048); Windows[1] = new Window(gba, 0x4000042, 0x4000049); Windows[2] = new Window(gba, 0, 0x400004A); Windows[3] = new Window(gba, 0, 0x400004B); this.BlendControlRegister = new BlendControlRegister(this, gba); BlendingCoefficientRegister = new PixelCoefficientRegister(this, gba, 0x4000052); BrightnessCoefficientRegister = new PixelCoefficientRegister(this, gba, 0x4000054); #if THREADED_SCANLINE //Interlocked.Exchange(ref drawScanline, 0); drawScanline = 0; exitThread = false; scanlineThread = new Thread(new ThreadStart(ScanlineThread)); scanlineThread.Priority = ThreadPriority.Highest; scanlineThread.Start(); #endif }
private void RenderScanlineTextMode() { ObjPrioritySort(); int scanline = CurrentScanline; bool windowing = (DisplayControlRegister.DisplayWin0 || DisplayControlRegister.DisplayWin1 || DisplayControlRegister.DisplayWin1 || DisplayControlRegister.DisplayObjWin); // We render front to back. Once a pixel is drawn we stop going through the layers. // TODO: In order to do blending we may need to go through all the layers for each pixel #if ParallelizeScanline var paritioner = Partitioner.Create(0, LcdController.Screen_X_Resolution, 80); var result = Parallel.ForEach(paritioner, (range) => { for (int x = range.Item1; x < range.Item2; x++) #else for (int x = 0; x < Screen_X_Resolution; x++) #endif { int paletteIndex; bool pixelDrawn = false; // Windowing can disable obj's and bg's bool objVisibleOverride = false; int windowRegion = 0; int bgVisibleOverride = 0; // bitmask for bg visible (from window) if (windowing) { windowRegion = TileHelpers.PixelWindowRegion(x, CurrentScanline, gba); // 0 is outside of all windows if (windowRegion == 0) { objVisibleOverride = Windows[(int) Window.WindowName.WindowOut].DisplayObjs; bgVisibleOverride = Windows[(int)Window.WindowName.WindowOut].DisplayBg0 | Windows[(int)Window.WindowName.WindowOut].DisplayBg1 | Windows[(int)Window.WindowName.WindowOut].DisplayBg2 | Windows[(int)Window.WindowName.WindowOut].DisplayBg3; } // Window 0 takes priority over window 1. We don't need to check if the point is within both areas as it is done in the function call above else if((windowRegion & (int)TileHelpers.WindowRegion.Window0) != 0) { objVisibleOverride = Windows[(int)Window.WindowName.Window0].DisplayObjs; bgVisibleOverride = Windows[(int)Window.WindowName.Window0].DisplayBg0 | Windows[(int)Window.WindowName.Window0].DisplayBg1 | Windows[(int)Window.WindowName.Window0].DisplayBg2 | Windows[(int)Window.WindowName.Window0].DisplayBg3; } else if ((windowRegion & (int)TileHelpers.WindowRegion.Window1) != 0) { objVisibleOverride = Windows[(int)Window.WindowName.Window1].DisplayObjs; bgVisibleOverride = Windows[(int)Window.WindowName.Window1].DisplayBg0 | Windows[(int)Window.WindowName.Window1].DisplayBg1 | Windows[(int)Window.WindowName.Window1].DisplayBg2 | Windows[(int)Window.WindowName.Window1].DisplayBg3; } } else { objVisibleOverride = true; bgVisibleOverride = 0; } // Start at the top priority, if something draws to the pixel, we can early out and stop processing this pixel for (int priority = 0; priority < 4; priority++) { // Sprite rendering if (DisplayControlRegister.DisplayObj && (!windowing || (windowing && objVisibleOverride))) { pixelDrawn = RenderSpritePixel(x, scanline, priority, windowing, windowRegion, ref bgVisibleOverride); if (pixelDrawn) { break; } } // No Sprite occupied this pixel, move on to backgrounds // Bg Rendering // Find the background with this priority for (int bgSelect = 0; bgSelect < 4; bgSelect++) { if (Bg[bgSelect].CntRegister.Priority != priority || DisplayControlRegister.BgVisible(Bg[bgSelect].BgNumber) == false || (windowing && ((bgVisibleOverride & (1 << bgSelect)) == 0))) { continue; } if (Bg[bgSelect].AffineMode) { paletteIndex = Bg[bgSelect].PixelValueAffine(x, scanline); } else { paletteIndex = Bg[bgSelect].PixelValue(x, scanline); } // Pal 0 == Transparent if (paletteIndex == 0) { continue; } drawBuffer.SetPixel(x, scanline, Palettes.Palette0[paletteIndex]); pixelDrawn = true; // Once a pixel has been drawn, no need to check other BG's break; } if(pixelDrawn) { break; } } // If nothing is drawn then default to backdrop colour if (pixelDrawn == false) { drawBuffer.SetPixel(x, scanline, Palettes.Palette0[0]); } } #if ParallelizeScanline }); // Parallel.For //while (result.IsCompleted == false) ; #endif }