示例#1
0
        //Queue<double> avr = new Queue<double>();
        // Step one cycle
        public void Step()
        {

            // If we change these, change vblank cycle count too
            LcdCycles++;
            FrameCycles++;

            switch (Mode)
            {
                case LcdMode.ScanlineRendering:
                    if (LcdCycles >= HDraw_Length)
                    {
#if THREADED_SCANLINE
                        if (scanlineThread.IsAlive == false)
                        {
                            throw new ArgumentException("Thread pop!");
                        }

                        // Wait for scanline rendering to finsih
                        while (drawScanline == true) 
                        {
                        }
#endif
                        LcdCycles -= HDraw_Length;
                        Mode = LcdMode.HBlank;


                        if (DispStatRegister.HBlankIrqEnabled)
                        {
                            gba.Interrupts.RequestInterrupt(Interrupts.InterruptType.HBlank);
                        }

                        // Start hblank DMA's (HDMA)
                        for(int i=0; i < 4; i++)
                        {
                            if(gba.Dma[i].DmaCnt.StartTiming == DmaControlRegister.DmaStartTiming.HBlank &&
                               gba.Dma[i].DmaCnt.ChannelEnabled == true)
                            {
                                gba.Dma[i].Started = true;
                            }
                        }
                    }
                    break;


                case LcdMode.HBlank:
                    if(LcdCycles >= HBlank_Length)
                    {
                        LcdCycles -= HBlank_Length;

                        CurrentScanline++;

                        if (DispStatRegister.VCounterIrqEnabled && 
                            CurrentScanline == gba.LcdController.DispStatRegister.VCountSetting)
                        {                           
                            gba.Interrupts.RequestInterrupt(Interrupts.InterruptType.VCounterMatch);
                        }
                        

                        if (CurrentScanline == 160)
                        {
                            Mode = LcdMode.VBlank;
                            VblankScanlineCycles = 0;

                            if (DispStatRegister.VBlankIrqEnabled)
                            {
                                gba.Interrupts.RequestInterrupt(Interrupts.InterruptType.VBlank);
                            }
                            

                            // We can set the renderer drawing the frame as soon as we enter vblank
                            lock (FrameBuffer)
                            {
                                // Flip frames 
                                if (FrameBuffer == frameBuffer0)
                                {
                                    FrameBuffer = frameBuffer1;
                                    drawBuffer = frameBuffer0;
                                }
                                else
                                {
                                    FrameBuffer = frameBuffer0;
                                    drawBuffer = frameBuffer1;
                                }

                                // Clear the draw buffer to the background color 
                                //using (var graphics = Graphics.FromImage(drawBuffer.Bitmap))
                                //{
                                //    graphics.Clear(Palettes.Palette0[0]);
                                //}
                            }

                            // lock to 60fps - 1000 / 60.0
                            double fps60 = 16.6666666;
                           /*
                            double frameTime = gba.EmulatorTimer.Elapsed.TotalMilliseconds - lastFrameTime;
                            avr.Enqueue(frameTime);
                            if (avr.Count == 11)
                            {
                                avr.Dequeue();
                                double frameAverage = avr.Average();
                                gba.LogMessage(String.Format("frame Ms {0:N2}", frameAverage));
                            }
                           */
                            while (gba.EmulatorTimer.Elapsed.TotalMilliseconds - lastFrameTime < fps60)
                            {
                            }

                            lastFrameTime = gba.EmulatorTimer.Elapsed.TotalMilliseconds;
                            

                            if (gba.OnFrame != null)
                            {
                                gba.OnFrame();
                            }
                        }
                        else
                        {
                            Mode = LcdMode.ScanlineRendering;
                            Render();
                        }
                    }
                    break;


                case LcdMode.VBlank:

                    VblankScanlineCycles++;
                    if (LcdCycles >= VBlank_Length)
                    {
                        // 160 + 68 lines per screen
                        if(CurrentScanline != 227 ||
                            FrameCycles != ScreenRefresh_Length)
                        {
                            throw new InvalidOperationException("LCD: Scanlines / cycles mismatch"); 
                        }

                        LcdCycles -= VBlank_Length;
                        FrameCycles = 0;

                        CurrentScanline = 0;
                        Mode = LcdMode.ScanlineRendering;
                        Render();

                        if (DispStatRegister.VCounterIrqEnabled &&
                            CurrentScanline == gba.LcdController.DispStatRegister.VCountSetting)
                        {
                           gba.Interrupts.RequestInterrupt(Interrupts.InterruptType.VCounterMatch);
                        }

                    }
                    else
                    {
                        // HBlanks IRQ's still fire durng vblank
                        if(VblankScanlineCycles == HDraw_Length)
                        {
                            if (DispStatRegister.HBlankIrqEnabled)
                            {
                                gba.Interrupts.RequestInterrupt(Interrupts.InterruptType.HBlank);
                            }
                        }

                        // We are within vblank
                        if(VblankScanlineCycles == ScanLine_Length)
                        {
                            VblankScanlineCycles = 0;
                            CurrentScanline++;

                            if (DispStatRegister.VCounterIrqEnabled &&
                            CurrentScanline == gba.LcdController.DispStatRegister.VCountSetting)
                            {
                                gba.Interrupts.RequestInterrupt(Interrupts.InterruptType.VCounterMatch);
                            }
                        }
                    }                
                    break;
          
            }
        }
示例#2
0
        public bool RenderSpritePixel(DirectBitmap drawBuffer, int screenX, int screenY, int priority, bool windowing, int windowRegion, ref int bgVisibleOverride)
        {
            int paletteIndex;

            foreach (var obj in priorityObjList[priority])
            {
                // Clip against the bounding box which can be DoubleSize. This is the only time doublesize is actually checked
                if (obj.BoundingBoxScreenSpace.ContainsPoint(screenX, screenY) == false)
                {
                    continue;
                }

                if (obj.Attributes.RotationAndScaling)
                {
                    int sourceWidth  = obj.Attributes.Dimensions.Width;
                    int sourceHeight = obj.Attributes.Dimensions.Height;

                    // The game will have set up the matrix to be the inverse texture mapping matrix. I.E it maps from screen space to texture space. Just what we need!
                    OamAffineMatrix rotScaleMatrix = obj.Attributes.AffineMatrix();

                    // NB: Order of operations counts here!
                    // Transform with the origin set to the centre of the sprite (that's what the - width/height /2 below is for)
                    int originX = screenX - obj.Attributes.XPositionAdjusted() - (sourceWidth / 2);
                    int originY = screenY - obj.Attributes.YPositionAdjusted() - (sourceHeight / 2);
                    // Not well documented anywhere but when double size is enabled we render offset by half the original source width / height
                    if (obj.Attributes.DoubleSize)
                    {
                        originX -= sourceWidth / 2;
                        originY -= sourceHeight / 2;
                    }

                    int transformedX, transformedY;
                    rotScaleMatrix.Multiply(originX, originY, out transformedX, out transformedY);

                    // Transform back from centre of sprite
                    transformedX += (sourceWidth / 2);
                    transformedY += (sourceHeight / 2);

                    paletteIndex = obj.PixelValue(transformedX, transformedY);
                }
                else
                {
                    //paletteIndex = obj.PixelScreenValue(x, scanline);
                    paletteIndex = obj.PixelValue(screenX - obj.Attributes.XPositionAdjusted(), screenY - obj.Attributes.YPositionAdjusted());
                }

                // Pal 0 == Transparent
                if (paletteIndex == 0)
                {
                    continue;
                }


                // TODO: I *think* this will render the Obj window correctly but i cannot test it yet
                // This pixel belongs to a sprite in the Obj Window and Win 0 & 1 are not enclosing this pixel
                if (windowing &&
                    gba.LcdController.DisplayControlRegister.DisplayObjWin &&
                    obj.Attributes.Mode == ObjAttributes.ObjMode.ObjWindow &&
                    ((windowRegion & (int)TileHelpers.WindowRegion.WindowIn) == 0))
                {
                    bgVisibleOverride = gba.LcdController.Windows[(int)Window.WindowName.WindowObj].DisplayBg0 |
                                        gba.LcdController.Windows[(int)Window.WindowName.WindowObj].DisplayBg1 |
                                        gba.LcdController.Windows[(int)Window.WindowName.WindowObj].DisplayBg2 |
                                        gba.LcdController.Windows[(int)Window.WindowName.WindowObj].DisplayBg3;

                    return(false);
                }

                drawBuffer.SetPixel(screenX, screenY, gba.LcdController.Palettes.Palette1[paletteIndex]);
                return(true);
            }
            return(false);
        }