//private void Tick() => myChip8.Tick(); private void Tick60Hz() { if (!pause) { myChip8.EmulateCycle(); clockRateStatusLabel.Text = $"{myChip8.ClockRate.ToString("F1")} Hz (avg: {(myChip8.ProcessingTime / 10.0).ToString("#,##0.00", NumberFormatInfo.CurrentInfo)} ns)"; frameRateStatusLabel.Text = $"{myChip8.FrameRate.ToString("F1")} FPS (avg: {(myChip8.RenderingTime / 10.0).ToString("#,##0.00", NumberFormatInfo.CurrentInfo)} ns)"; } }
static int Main(string[] args) { if (!driver.Init(WIDTH, HEIGHT)) { Debug.Print("Failed to initialize!"); return(-1); } // Setup the graphics (window size, display mode, etc) if (!driver.SetupGraphics($"assets{Path.DirectorySeparatorChar.ToString(CultureInfo.CurrentCulture)}CHIP-8.logo.bmp")) { Debug.Print("Failed to setup graphics!"); return(-2); } // Setup the input system (register input callbacks) if (!driver.SetupInput()) { Debug.Print("Failed to setup input!"); return(-3); } if (!LoadMedia()) { Debug.Print("Failed to load media!"); return(-4); } //Main loop flag var quit = false; //Event handler SDL.SDL_Event evt; //Set default current surface currentTexture = textures[(int)KeyPressSurface.Default]; Debug.Print("Loaded..."); var pixelColor = appleIIcGreen; var backgroundColor = gray; // Initialize the CHIP-8 system (Clear the memory, registers and screen) myChip8 = new CPU((uint)((pixelColor.a << 24) | (pixelColor.r << 16) | (pixelColor.g << 8) | pixelColor.b), (uint)((backgroundColor.a << 24) | (backgroundColor.r << 16) | (backgroundColor.g << 8) | backgroundColor.b)); myChip8.OnDraw += DrawGraphics; myChip8.OnStartSound += OnStartSound; myChip8.OnEndSound += OnEndSound; // Load (copy) the game into the memory myChip8.LoadGame($"progs{Path.DirectorySeparatorChar.ToString(CultureInfo.CurrentCulture)}demo.ch8"); //Rotation variables double angle = 0; screenCenter = new SDL.SDL_Point { x = WIDTH / 2, y = HEIGHT / 2 }; //Start counting frames per second countedFrames = 0; fpsTimer.Start(); //While application is running while (!quit) { if (!debugKeys && !debugPixels) { // Emulate one cycle of the system myChip8.EmulateCycle(); } //Handle events on queue while (SDL.SDL_PollEvent(out evt) != 0) { //User requests quit switch (evt.type) { case SDL.SDL_EventType.SDL_QUIT: Debug.Print("Quitting..."); quit = true; break; case SDL.SDL_EventType.SDL_KEYDOWN: //Select surfaces based on key press switch (evt.key.keysym.sym) { case SDL.SDL_Keycode.SDLK_ESCAPE: Debug.Print("ESCAPE"); Debug.Print("Quitting..."); quit = true; break; case SDL.SDL_Keycode.SDLK_UP: currentTexture = textures[(int)KeyPressSurface.Up]; Debug.Print("UP"); break; case SDL.SDL_Keycode.SDLK_DOWN: currentTexture = textures[(int)KeyPressSurface.Down]; Debug.Print("DOWN"); break; case SDL.SDL_Keycode.SDLK_LEFT: currentTexture = textures[(int)KeyPressSurface.Left]; Debug.Print("LEFT"); break; case SDL.SDL_Keycode.SDLK_RIGHT: currentTexture = textures[(int)KeyPressSurface.Right]; Debug.Print("RIGHT"); break; case SDL.SDL_Keycode.SDLK_1: keys[0x0] = 1; Debug.Print("1"); break; case SDL.SDL_Keycode.SDLK_2: keys[0x1] = 1; Debug.Print("2"); break; case SDL.SDL_Keycode.SDLK_3: keys[0x2] = 1; Debug.Print("3"); break; case SDL.SDL_Keycode.SDLK_4: keys[0x3] = 1; Debug.Print("4"); break; case SDL.SDL_Keycode.SDLK_q: keys[0x4] = 1; Debug.Print("q"); break; case SDL.SDL_Keycode.SDLK_w: keys[0x5] = 1; Debug.Print("w"); break; case SDL.SDL_Keycode.SDLK_e: keys[0x6] = 1; Debug.Print("e"); break; case SDL.SDL_Keycode.SDLK_r: keys[0x7] = 1; Debug.Print("r"); break; case SDL.SDL_Keycode.SDLK_a: keys[0x8] = 1; Debug.Print("a"); break; case SDL.SDL_Keycode.SDLK_s: keys[0x9] = 1; Debug.Print("s"); break; case SDL.SDL_Keycode.SDLK_d: keys[0xA] = 1; Debug.Print("d"); break; case SDL.SDL_Keycode.SDLK_f: keys[0xA] = 1; Debug.Print("f"); break; case SDL.SDL_Keycode.SDLK_z: keys[0xB] = 1; Debug.Print("z"); break; case SDL.SDL_Keycode.SDLK_y: keys[0xB] = 1; Debug.Print("y"); break; case SDL.SDL_Keycode.SDLK_x: keys[0xC] = 1; Debug.Print("x"); break; case SDL.SDL_Keycode.SDLK_c: keys[0xD] = 1; Debug.Print("c"); break; case SDL.SDL_Keycode.SDLK_v: keys[0xE] = 1; Debug.Print("v"); break; case SDL.SDL_Keycode.SDLK_BACKSPACE: debugKeys = false; debugPixels = !debugPixels; if (debugPixels) { Debug.Print("Entering debug pixel mode"); } else { Debug.Print("Leaving debug pixel mode"); } break; case SDL.SDL_Keycode.SDLK_RETURN: debugKeys = !debugKeys; debugPixels = false; if (debugKeys) { Debug.Print("Entering debug keys mode"); } else { Debug.Print("Leaving debug keys mode"); } break; case SDL.SDL_Keycode.SDLK_PLUS: zoom += 0.5f; Debug.Print($"Zoom level: {zoom.ToString(NumberFormatInfo.CurrentInfo)}x"); break; case SDL.SDL_Keycode.SDLK_MINUS: zoom -= 0.5f; Debug.Print($"Zoom level: {zoom.ToString(NumberFormatInfo.CurrentInfo)}x"); break; case SDL.SDL_Keycode.SDLK_0: zoom = 1.0f; Debug.Print($"Zoom level: {zoom.ToString(NumberFormatInfo.CurrentInfo)}x"); break; default: currentTexture = textures[(int)KeyPressSurface.Default]; Debug.Print("Default Key Press"); break; } break; case SDL.SDL_EventType.SDL_KEYUP: //Select surfaces based on key press switch (evt.key.keysym.sym) { case SDL.SDL_Keycode.SDLK_UP: currentTexture = textures[(int)KeyPressSurface.Default]; break; case SDL.SDL_Keycode.SDLK_DOWN: currentTexture = textures[(int)KeyPressSurface.Default]; break; case SDL.SDL_Keycode.SDLK_LEFT: currentTexture = textures[(int)KeyPressSurface.Default]; break; case SDL.SDL_Keycode.SDLK_RIGHT: currentTexture = textures[(int)KeyPressSurface.Default]; break; case SDL.SDL_Keycode.SDLK_1: keys[0x0] = 0; Debug.Print("1"); break; case SDL.SDL_Keycode.SDLK_2: keys[0x1] = 0; Debug.Print("2"); break; case SDL.SDL_Keycode.SDLK_3: keys[0x2] = 0; Debug.Print("3"); break; case SDL.SDL_Keycode.SDLK_4: keys[0x3] = 0; Debug.Print("4"); break; case SDL.SDL_Keycode.SDLK_q: keys[0x4] = 0; Debug.Print("q"); break; case SDL.SDL_Keycode.SDLK_w: keys[0x5] = 0; Debug.Print("w"); break; case SDL.SDL_Keycode.SDLK_e: keys[0x6] = 0; Debug.Print("e"); break; case SDL.SDL_Keycode.SDLK_r: keys[0x7] = 0; Debug.Print("r"); break; case SDL.SDL_Keycode.SDLK_a: keys[0x8] = 0; Debug.Print("a"); break; case SDL.SDL_Keycode.SDLK_s: keys[0x9] = 0; Debug.Print("s"); break; case SDL.SDL_Keycode.SDLK_d: keys[0xA] = 0; Debug.Print("d"); break; case SDL.SDL_Keycode.SDLK_f: keys[0xA] = 0; Debug.Print("f"); break; case SDL.SDL_Keycode.SDLK_z: keys[0xB] = 0; break; case SDL.SDL_Keycode.SDLK_y: keys[0xB] = 0; break; case SDL.SDL_Keycode.SDLK_x: keys[0xC] = 0; break; case SDL.SDL_Keycode.SDLK_c: keys[0xD] = 0; break; case SDL.SDL_Keycode.SDLK_v: keys[0xE] = 0; break; default: currentTexture = textures[(int)KeyPressSurface.Default]; break; } break; } } if (debugKeys) { if (!SDLDriver.Render(currentTexture)) { Debug.Print("Failed to render texture!"); } } if (debugPixels) { angle = RotateRectangle(angle); } // Store key press state (Press and Release) // If we press or release a key, we should store this state in the part that emulates the keypad myChip8.SetKeys(keys); // 60 Hz = 1000 ms /60 = 16.666 ms => approx. 17 ms (17 ms * 60 = 1020 ms) //SDL.SDL_Delay(17); //Calculate and correct fps var avgFPS = countedFrames / (fpsTimer.Ticks / 1000.0); // It is possible for there to be a very small amount of time passed // for the first frame and have it give us a really high fps. // This is why we correct the value if it is really high. if (avgFPS > 2000000) { avgFPS = 0; } //Set text to be rendered timerText = $"Average {avgFPS.ToString("F2", NumberFormatInfo.CurrentInfo)} Frames Per Second"; var color = white; if (debugKeys) { color = black; } if (debugPixels) { color = green1; } //Render text if (!fpsTextTexture.LoadFromRenderedText(timerText, color)) { Debug.Print("Unable to render FPS texture!"); } //Clear screen //SDL.SDL_SetRenderDrawColor(driver.rendererPtr, 0xFF, 0xFF, 0xFF, 0xFF); //SDL.SDL_RenderClear(driver.rendererPtr); //Render textures fpsTextTexture.Render((WIDTH - fpsTextTexture.Width) / 2, (HEIGHT - (int)(fpsTextTexture.Height * 1.75))); //Update screen if (!driver.Present()) { Debug.Print("Failed to present render!"); } ++countedFrames; } return(0); }