aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/gui/WindowContainer.kt
blob: 60dc1e454009aa182beb9f0fe4439898a87b81bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package gui

import GameBoy
import cpu.Cpu
import gli_.Texture
import gli_.gli
import glm_.vec2.Vec2i
import glm_.vec4.Vec4
import gln.checkError
import gln.texture.glDeleteTexture
import gln.texture.initTexture2d
import gpu.TestPatternGpu
import imgui.Context
import imgui.ImGui
import imgui.TextureID
import imgui.destroy
import imgui.impl.LwjglGL3
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL30
import uno.glfw.GlfwWindow
import uno.glfw.glfw
import java.awt.image.BufferedImage
import java.io.File

class WindowContainer {

  val gameBoy: GameBoy

  init {
    glfw.init("3.2")

    gameBoy = GameBoy(Cpu(), TestPatternGpu())
    gameBoy.loadRom(File("src/main/resources/roms/boot-rom.gb"))
  }

  val window = GlfwWindow(1280, 720, "KGB - KotlinGameBoy").apply {
    init()
  }


  fun run() {

    // Enable vsync
    glfw.swapInterval = 1

    val ctx = Context()
    LwjglGL3.init(window)
    ImGui.styleColorsDark()

    window.loop(::mainLoop)

    LwjglGL3.shutdown()
    ctx.destroy()

    window.destroy()
    glfw.terminate()

  }

  private fun mainLoop() {

    LwjglGL3.newFrame()

    val (texture, textureId) = createAndRegisterTexture(gameBoy.gpu.getFrame())

    with(ImGui) {
      paintDebugWindow()
      paintCpuRegisterWindow(gameBoy.cpu.registers)
      paintRunControlWindow(gameBoy.cpu)
      paintRamDumpWindow(gameBoy.cpu.ram)
      paintEmulationOutputWindow(textureId)
    }

    gln.glViewport(window.framebufferSize)
    gln.glClearColor(Vec4(0.45f, 0.55f, 0.6f, 1f))
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT)

    ImGui.render()
    LwjglGL3.renderDrawData(ImGui.drawData!!)

    // TODO - render direct to framebuffer rather than creating and destroying texture each frame
    disposeTexture(texture, textureId)

    checkError("mainLoop")
  }

  private fun createAndRegisterTexture(frame: BufferedImage): Pair<Texture, TextureID> {
    val texture = gli.createTexture(frame)
    val textureId = initTexture2d {
      minFilter = linear
      magFilter = linear
      GL30.glPixelStorei(GL30.GL_UNPACK_ROW_LENGTH, 0)
      image(GL30.GL_RGB, Vec2i(640,576), GL30.GL_RGB, GL30.GL_UNSIGNED_BYTE, texture.data())
    }

    return Pair(texture, textureId)
  }

  private fun disposeTexture(texture: Texture, textureID: TextureID) {
    glDeleteTexture(textureID)
    texture.dispose()
  }

}