Skip to content

Commit 146868c

Browse files
committed
Add OpenGL support.
1 parent b633a82 commit 146868c

File tree

6 files changed

+353
-80
lines changed

6 files changed

+353
-80
lines changed

build.gradle

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,95 @@ repositories {
2929
dependencies {
3030
implementation 'com.beust:jcommander:1.82'
3131
implementation 'commons-io:commons-io:2.21.0'
32+
33+
implementation platform("org.lwjgl:lwjgl-bom:3.3.6")
34+
35+
implementation "org.lwjgl:lwjgl"
36+
implementation "org.lwjgl:lwjgl-assimp"
37+
implementation "org.lwjgl:lwjgl-bgfx"
38+
implementation "org.lwjgl:lwjgl-cuda"
39+
implementation "org.lwjgl:lwjgl-egl"
40+
implementation "org.lwjgl:lwjgl-fmod"
41+
implementation "org.lwjgl:lwjgl-freetype"
42+
implementation "org.lwjgl:lwjgl-glfw"
43+
implementation "org.lwjgl:lwjgl-harfbuzz"
44+
implementation "org.lwjgl:lwjgl-hwloc"
45+
implementation "org.lwjgl:lwjgl-jawt"
46+
implementation "org.lwjgl:lwjgl-jemalloc"
47+
implementation "org.lwjgl:lwjgl-ktx"
48+
implementation "org.lwjgl:lwjgl-libdivide"
49+
implementation "org.lwjgl:lwjgl-llvm"
50+
implementation "org.lwjgl:lwjgl-lmdb"
51+
implementation "org.lwjgl:lwjgl-lz4"
52+
implementation "org.lwjgl:lwjgl-meow"
53+
implementation "org.lwjgl:lwjgl-meshoptimizer"
54+
implementation "org.lwjgl:lwjgl-msdfgen"
55+
implementation "org.lwjgl:lwjgl-nanovg"
56+
implementation "org.lwjgl:lwjgl-nfd"
57+
implementation "org.lwjgl:lwjgl-nuklear"
58+
implementation "org.lwjgl:lwjgl-odbc"
59+
implementation "org.lwjgl:lwjgl-openal"
60+
implementation "org.lwjgl:lwjgl-opencl"
61+
implementation "org.lwjgl:lwjgl-opengl"
62+
implementation "org.lwjgl:lwjgl-opengles"
63+
implementation "org.lwjgl:lwjgl-openvr"
64+
implementation "org.lwjgl:lwjgl-openxr"
65+
implementation "org.lwjgl:lwjgl-opus"
66+
implementation "org.lwjgl:lwjgl-par"
67+
implementation "org.lwjgl:lwjgl-remotery"
68+
implementation "org.lwjgl:lwjgl-rpmalloc"
69+
implementation "org.lwjgl:lwjgl-shaderc"
70+
implementation "org.lwjgl:lwjgl-spvc"
71+
implementation "org.lwjgl:lwjgl-sse"
72+
implementation "org.lwjgl:lwjgl-stb"
73+
implementation "org.lwjgl:lwjgl-tinyexr"
74+
implementation "org.lwjgl:lwjgl-tinyfd"
75+
implementation "org.lwjgl:lwjgl-tootle"
76+
implementation "org.lwjgl:lwjgl-vma"
77+
implementation "org.lwjgl:lwjgl-vulkan"
78+
implementation "org.lwjgl:lwjgl-xxhash"
79+
implementation "org.lwjgl:lwjgl-yoga"
80+
implementation "org.lwjgl:lwjgl-zstd"
81+
implementation "org.lwjgl:lwjgl::natives-linux"
82+
implementation "org.lwjgl:lwjgl-assimp::natives-linux"
83+
implementation "org.lwjgl:lwjgl-bgfx::natives-linux"
84+
implementation "org.lwjgl:lwjgl-freetype::natives-linux"
85+
implementation "org.lwjgl:lwjgl-glfw::natives-linux"
86+
implementation "org.lwjgl:lwjgl-harfbuzz::natives-linux"
87+
implementation "org.lwjgl:lwjgl-hwloc::natives-linux"
88+
implementation "org.lwjgl:lwjgl-jemalloc::natives-linux"
89+
implementation "org.lwjgl:lwjgl-ktx::natives-linux"
90+
implementation "org.lwjgl:lwjgl-libdivide::natives-linux"
91+
implementation "org.lwjgl:lwjgl-llvm::natives-linux"
92+
implementation "org.lwjgl:lwjgl-lmdb::natives-linux"
93+
implementation "org.lwjgl:lwjgl-lz4::natives-linux"
94+
implementation "org.lwjgl:lwjgl-meow::natives-linux"
95+
implementation "org.lwjgl:lwjgl-meshoptimizer::natives-linux"
96+
implementation "org.lwjgl:lwjgl-msdfgen::natives-linux"
97+
implementation "org.lwjgl:lwjgl-nanovg::natives-linux"
98+
implementation "org.lwjgl:lwjgl-nfd::natives-linux"
99+
implementation "org.lwjgl:lwjgl-nuklear::natives-linux"
100+
implementation "org.lwjgl:lwjgl-openal::natives-linux"
101+
implementation "org.lwjgl:lwjgl-opengl::natives-linux"
102+
implementation "org.lwjgl:lwjgl-opengles::natives-linux"
103+
implementation "org.lwjgl:lwjgl-openvr::natives-linux"
104+
implementation "org.lwjgl:lwjgl-openxr::natives-linux"
105+
implementation "org.lwjgl:lwjgl-opus::natives-linux"
106+
implementation "org.lwjgl:lwjgl-par::natives-linux"
107+
implementation "org.lwjgl:lwjgl-remotery::natives-linux"
108+
implementation "org.lwjgl:lwjgl-rpmalloc::natives-linux"
109+
implementation "org.lwjgl:lwjgl-shaderc::natives-linux"
110+
implementation "org.lwjgl:lwjgl-spvc::natives-linux"
111+
implementation "org.lwjgl:lwjgl-sse::natives-linux"
112+
implementation "org.lwjgl:lwjgl-stb::natives-linux"
113+
implementation "org.lwjgl:lwjgl-tinyexr::natives-linux"
114+
implementation "org.lwjgl:lwjgl-tinyfd::natives-linux"
115+
implementation "org.lwjgl:lwjgl-tootle::natives-linux"
116+
implementation "org.lwjgl:lwjgl-vma::natives-linux"
117+
implementation "org.lwjgl:lwjgl-xxhash::natives-linux"
118+
implementation "org.lwjgl:lwjgl-yoga::natives-linux"
119+
implementation "org.lwjgl:lwjgl-zstd::natives-linux"
120+
32121
testImplementation 'org.mockito:mockito-core:5.20.0'
33122
testImplementation 'junit:junit:4.13.2'
34123
}

src/main/java/ca/craigthomas/chip8java/emulator/components/CentralProcessingUnit.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1250,7 +1250,7 @@ public void reset() {
12501250
playbackRate = 4000.0;
12511251
bitplane = 1;
12521252
if (screen != null) {
1253-
screen.clearScreen(bitplane);
1253+
// screen.clearScreen(bitplane);
12541254
}
12551255
awaitingKeypress = false;
12561256
audioPatternBuffer = new int[16];

src/main/java/ca/craigthomas/chip8java/emulator/components/Emulator.java

Lines changed: 117 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@
1515
import java.util.Timer;
1616
import java.util.logging.Logger;
1717

18+
import org.lwjgl.*;
19+
import org.lwjgl.glfw.*;
20+
import org.lwjgl.opengl.*;
21+
import org.lwjgl.system.*;
22+
23+
import java.nio.*;
24+
25+
import static org.lwjgl.glfw.Callbacks.*;
26+
import static org.lwjgl.glfw.GLFW.*;
27+
import static org.lwjgl.opengl.GL11.*;
28+
import static org.lwjgl.system.MemoryStack.*;
29+
import static org.lwjgl.system.MemoryUtil.*;
30+
1831
/**
1932
* The main Emulator class.
2033
*/
@@ -49,6 +62,8 @@ public class Emulator
4962
private Timer timer;
5063
private TimerTask timerTask;
5164

65+
private long window;
66+
5267
/**
5368
* Convenience constructor that sets the emulator running with a 1x
5469
* screen scale, a cycle time of 0, a null rom, and trace mode off.
@@ -108,33 +123,33 @@ public Emulator(
108123
System.exit(1);
109124
}
110125

111-
Color converted_color0 = null;
126+
PixelColor converted_color0 = null;
112127
try {
113-
converted_color0 = Color.decode("#" + color0);
128+
converted_color0 = new PixelColor(Color.decode("#" + color0));
114129
} catch (NumberFormatException e) {
115130
System.out.println("color_0 parameter could not be decoded (" + e.getMessage() +")");
116131
System.exit(1);
117132
}
118133

119-
Color converted_color1 = null;
134+
PixelColor converted_color1 = null;
120135
try {
121-
converted_color1 = Color.decode("#" + color1);
136+
converted_color1 = new PixelColor(Color.decode("#" + color1));
122137
} catch (NumberFormatException e) {
123138
System.out.println("color_1 parameter could not be decoded (" + e.getMessage() +")");
124139
System.exit(1);
125140
}
126141

127-
Color converted_color2 = null;
142+
PixelColor converted_color2 = null;
128143
try {
129-
converted_color2 = Color.decode("#" + color2);
144+
converted_color2 = new PixelColor(Color.decode("#" + color2));
130145
} catch (NumberFormatException e) {
131146
System.out.println("color_2 parameter could not be decoded (" + e.getMessage() +")");
132147
System.exit(1);
133148
}
134149

135-
Color converted_color3 = null;
150+
PixelColor converted_color3 = null;
136151
try {
137-
converted_color3 = Color.decode("#" + color3);
152+
converted_color3 = new PixelColor(Color.decode("#" + color3));
138153
} catch (NumberFormatException e) {
139154
System.out.println("color_3 parameter could not be decoded (" + e.getMessage() +")");
140155
System.exit(1);
@@ -172,9 +187,7 @@ public Emulator(
172187
IO.closeStream(romFileStream);
173188
}
174189

175-
// Initialize the screen
176-
initEmulatorJFrame();
177-
start();
190+
init();
178191
}
179192

180193
/**
@@ -190,23 +203,97 @@ public void run() {
190203
};
191204
timer.scheduleAtFixedRate(timerTask, 0L, 17L);
192205

193-
while (state != EmulatorState.KILLED) {
194-
if (state != EmulatorState.PAUSED) {
195-
if (!cpu.isAwaitingKeypress()) {
196-
cpu.fetchIncrementExecute();
197-
} else {
198-
cpu.decodeKeypressAndContinue();
199-
}
200-
}
201-
202-
if (keyboard.getRawKeyPressed() == Keyboard.CHIP8_QUIT) {
203-
break;
204-
}
206+
while (!glfwWindowShouldClose(window)) {
207+
// if (state != EmulatorState.PAUSED) {
208+
// if (!cpu.isAwaitingKeypress()) {
209+
// cpu.fetchIncrementExecute();
210+
// } else {
211+
// cpu.decodeKeypressAndContinue();
212+
// }
213+
214+
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
215+
glClear(GL_COLOR_BUFFER_BIT);
216+
glfwSwapBuffers(window);
217+
// glReadPixels();
218+
glfwPollEvents();
219+
// }
205220
}
221+
206222
kill();
207223
System.exit(0);
208224
}
209225

226+
void init() {
227+
int scaleFactor = screen.getScale();
228+
int scaledWidth = Screen.WIDTH * scaleFactor;
229+
int scaledHeight = Screen.HEIGHT * scaleFactor;
230+
231+
if (!glfwInit()) {
232+
throw new IllegalStateException("Unable to initialize GLFW");
233+
}
234+
235+
glfwDefaultWindowHints();
236+
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
237+
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
238+
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
239+
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
240+
241+
window = glfwCreateWindow(scaledWidth, scaledHeight, DEFAULT_TITLE, NULL, NULL);
242+
if (window == NULL) {
243+
glfwTerminate();
244+
throw new RuntimeException("Failed to create the GLFW window");
245+
}
246+
247+
GLFWErrorCallback errorCallback = new GLFWErrorCallback() {
248+
@Override
249+
public void invoke(int error, long description) {
250+
System.out.println("Error: " + error + ", " + description);
251+
}
252+
};
253+
glfwSetErrorCallback(errorCallback);
254+
255+
// The main emulator keyboard callback function
256+
GLFWKeyCallback keyCallback = new GLFWKeyCallback() {
257+
@Override
258+
public void invoke(long window, int key, int scancode, int action, int mods) {
259+
if (action == GLFW_PRESS) {
260+
keyboard.keyPressed(key);
261+
}
262+
263+
if (action == GLFW_RELEASE) {
264+
keyboard.keyReleased(key);
265+
}
266+
267+
if (key == Keyboard.CHIP8_QUIT && action == GLFW_RELEASE) {
268+
glfwSetWindowShouldClose(window, true);
269+
}
270+
}
271+
};
272+
glfwSetKeyCallback(window, keyCallback);
273+
274+
// Get the thread stack and push a new frame
275+
// try ( MemoryStack stack = stackPush() ) {
276+
// IntBuffer pWidth = stack.mallocInt(1); // int*
277+
// IntBuffer pHeight = stack.mallocInt(1); // int*
278+
// glfwGetWindowSize(window, pWidth, pHeight);
279+
// GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
280+
// glfwSetWindowPos(window, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
281+
// }
282+
283+
glfwMakeContextCurrent(window);
284+
// glfwSwapInterval(1);
285+
// glfwShowWindow(window);
286+
287+
// This line is critical for LWJGL's interoperation with GLFW's
288+
// OpenGL context, or any context that is managed externally.
289+
// LWJGL detects the context that is current in the current thread,
290+
// creates the GLCapabilities instance and makes the OpenGL
291+
// bindings available for use.
292+
GL.createCapabilities();
293+
294+
// glViewport(0, 0, scaledWidth, scaledHeight);
295+
}
296+
210297
/**
211298
* Returns the main frame for the emulator.
212299
*
@@ -290,18 +377,14 @@ private void attachCanvas() {
290377
canvas.setFocusable(true);
291378
canvas.requestFocus();
292379

293-
canvas.addKeyListener(keyboard);
380+
// canvas.addKeyListener(keyboard);
294381
}
295382

296383
/**
297-
* Will redraw the contents of the screen to the emulator window. Optionally, if
298-
* isInTraceMode is True, will also draw the contents of the overlayScreen to the screen.
384+
* Will redraw the contents of the screen to the emulator window.
299385
*/
300386
private void refreshScreen() {
301-
Graphics2D graphics = (Graphics2D) canvas.getBufferStrategy().getDrawGraphics();
302-
graphics.drawImage(screen.getBuffer(), null, 0, 0);
303-
graphics.dispose();
304-
canvas.getBufferStrategy().show();
387+
glfwSwapBuffers(window);
305388
}
306389

307390
/**
@@ -313,8 +396,11 @@ public void kill() {
313396
timer.cancel();
314397
timer.purge();
315398
timerTask.cancel();
316-
dispose();
399+
// dispose();
317400
state = EmulatorState.KILLED;
401+
glfwFreeCallbacks(window);
402+
glfwDestroyWindow(window);
403+
glfwTerminate();
318404
}
319405

320406
/**

0 commit comments

Comments
 (0)