1
+ package uno.awt
2
+
3
+ import glm_.vec2.Vec2i
4
+ import org.lwjgl.glfw.GLFWErrorCallback
5
+ import org.lwjgl.opengl.GLUtil
6
+ import org.lwjgl.system.Callback
7
+ import org.lwjgl.system.jawt.JAWTDrawingSurface
8
+ import org.lwjgl.system.jawt.JAWTFunctions
9
+ import uno.glfw.GlfwWindow
10
+ import uno.glfw.HWND
11
+ import uno.glfw.VSync
12
+ import uno.glfw.glfw
13
+ import java.awt.Canvas
14
+ import java.awt.Graphics
15
+ import java.awt.event.ComponentAdapter
16
+ import java.awt.event.ComponentEvent
17
+ import javax.swing.SwingUtilities
18
+
19
+ /* *
20
+ * A Canvas component that uses OpenGL for rendering.
21
+ *
22
+ * Spasi: GLFW saves the AWT window proc somewhere and replaces it with its own on `glfwAttachWin32Window`.
23
+ * It restores it back when the GLFW window is destroyed.
24
+ * The difference between key and mouse events is that for key events the GLFW window proc returns `DefWindowProcW(...)`,
25
+ * but for mouse events it returns 0, so the events do not propagate to AWT
26
+ *
27
+ * This implementation supports Windows only.
28
+ */
29
+ abstract class LwjglCanvas (val glDebug : Boolean = false ) : Canvas() {
30
+
31
+ val awt = JAWT ()
32
+
33
+ lateinit var glfwWindow: GlfwWindow
34
+
35
+ var swapBuffers = true
36
+ var fps = true
37
+
38
+ var debugProc: Callback ? = null
39
+
40
+ var awtDebug = false
41
+
42
+ lateinit var glfwErrorCallback: GLFWErrorCallback
43
+
44
+ private fun initInternal (hwnd : HWND ) {
45
+ // println("LwjglCanvas.initInternal ${Date().toInstant()}")
46
+
47
+ initialized = true
48
+
49
+ glfwErrorCallback = GLFWErrorCallback .createPrint().set()
50
+
51
+ glfw {
52
+ init ()
53
+ windowHint { debug = glDebug }
54
+ }
55
+
56
+ // glfwWindowHint can be used here to configure the GL context
57
+ glfwWindow = GlfwWindow .fromWin32Window(hwnd).apply {
58
+ makeContextCurrent()
59
+ createCapabilities(forwardCompatible = false )
60
+ }
61
+
62
+ glfwWindow.cursorPosCallback = { it.toString() }
63
+
64
+ if (glDebug)
65
+ debugProc = GLUtil .setupDebugMessageCallback()
66
+
67
+ glfw.swapInterval = VSync .OFF
68
+
69
+ init ()
70
+
71
+ glfwWindow.unmakeContextCurrent()
72
+
73
+ // println("/LwjglCanvas.initInternal ${Date().toInstant()}")
74
+ }
75
+
76
+ var initialized = false
77
+ var resized = false
78
+ var animated = true
79
+
80
+ // lateinit var caps: Caps
81
+
82
+ // According to jawt.h > This value may be cached
83
+ lateinit var surface: JAWTDrawingSurface
84
+
85
+ init {
86
+
87
+ if (! awt.get())
88
+ throw IllegalStateException (" GetAWT failed" )
89
+
90
+ // this avoids to calling the super method
91
+ this .addComponentListener(object : ComponentAdapter () {
92
+ override fun componentResized (e : ComponentEvent ? ) {
93
+ // println("resized")
94
+ resized = true
95
+ }
96
+ // Not working
97
+ // override fun componentHidden(e: ComponentEvent?) {
98
+ // println("hidden")
99
+ // }
100
+ //
101
+ // override fun componentMoved(e: ComponentEvent?) {
102
+ // println("moved")
103
+ // }
104
+ //
105
+ // override fun componentShown(e: ComponentEvent?) {
106
+ // println("shown")
107
+ // }
108
+ })
109
+
110
+ SwingUtilities .invokeAndWait {
111
+ surface = awt.getDrawingSurface(this )!!
112
+ }
113
+ }
114
+
115
+ /* * critical, call paint without default g.clearRect, because it causes flickering */
116
+ override fun update (g : Graphics ) = paint(g)// .also { println("update") }
117
+
118
+ var last = 0L
119
+ var time = 0L
120
+ var frames = 0
121
+
122
+ override fun paint (g : Graphics ) {
123
+
124
+ if (awtDebug)
125
+ println (" paint start " + Thread .currentThread().name)
126
+
127
+ // Lock the drawing surface
128
+ if (surface.lock() == JawtLock .ERROR )
129
+ throw IllegalStateException (" ds->Lock() failed" )
130
+
131
+ wrapped { hwnd ->
132
+
133
+ if (! initialized)
134
+ initInternal(hwnd)
135
+
136
+ glfwWindow.inContext {
137
+
138
+ if (resized) {
139
+ // println("LwjglCanvas.reshape ${Date().toInstant()}")
140
+ val newSize = Vec2i (width, height)
141
+ glfwWindow.size = newSize
142
+ reshape(newSize)
143
+ resized = false
144
+ // println("/LwjglCanvas.reshape ${Date().toInstant()}")
145
+ }
146
+
147
+ // println("LwjglCanvas.render ${Date().toInstant()}")
148
+ if (awtDebug)
149
+ println (" paint before render " )
150
+
151
+ render()
152
+
153
+ // println("/LwjglCanvas.render ${Date().toInstant()}")
154
+ if (awtDebug)
155
+ println (" paint end" )
156
+
157
+ if (swapBuffers)
158
+ glfwWindow.swapBuffers()
159
+
160
+ if (fps) {
161
+ val now = System .currentTimeMillis()
162
+ time + = now - last
163
+ last = now
164
+ frames++
165
+ if (time > 1000 ) {
166
+ time % = 1000
167
+ println (" fps = $frames " )
168
+ frames = 0
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ if (animated)
175
+ repaint()
176
+ }
177
+
178
+ /* override fun paint(g: Graphics) {
179
+ if (awtDebug) {
180
+ println("paint start " + Thread.currentThread().name)
181
+ }
182
+
183
+ // Lock the drawing surface
184
+ val lock = JAWT_DrawingSurface_Lock(surface, surface.Lock())
185
+ if (lock has JAWT_LOCK_ERROR)
186
+ throw IllegalStateException("ds->Lock() failed")
187
+
188
+ try {
189
+ // Get the drawing surface info
190
+ val dsi = JAWT_DrawingSurface_GetDrawingSurfaceInfo(surface, surface.GetDrawingSurfaceInfo())
191
+ ?: throw IllegalStateException("ds->GetDrawingSurfaceInfo() failed")
192
+
193
+ try {
194
+ // Get the window platform drawing info
195
+ val surfaceInfo = JAWTWin32DrawingSurfaceInfo.create(dsi.platformInfo())
196
+
197
+ val hdc = surfaceInfo.hdc()
198
+ assert(hdc != NULL)
199
+
200
+ if (!initialized)
201
+ initInternal(HWND(surfaceInfo.hwnd()))
202
+
203
+ glfwWindow.makeContextCurrent()
204
+
205
+ if (resized) {
206
+ // println("LwjglCanvas.reshape ${Date().toInstant()}")
207
+ val newSize = Vec2i(width, height)
208
+ glfwWindow.size = newSize
209
+ reshape(newSize)
210
+ resized = false
211
+ // println("/LwjglCanvas.reshape ${Date().toInstant()}")
212
+ }
213
+
214
+ // println("LwjglCanvas.render ${Date().toInstant()}")
215
+ if (awtDebug) {
216
+ println("paint before render ")
217
+ }
218
+ render()
219
+ // println("/LwjglCanvas.render ${Date().toInstant()}")
220
+
221
+ if (swapBuffers)
222
+ glfwWindow.swapBuffers()
223
+
224
+ if (fps) {
225
+ val now = System.currentTimeMillis()
226
+ time += now - last
227
+ last = now
228
+ frames++
229
+ if (time > 1000) {
230
+ time %= 1000
231
+ println("fps = $frames")
232
+ frames = 0
233
+ }
234
+ }
235
+
236
+ glfwWindow.unmakeContextCurrent()
237
+
238
+ } finally {
239
+ // Free the drawing surface info
240
+ JAWT_DrawingSurface_FreeDrawingSurfaceInfo(dsi, surface.FreeDrawingSurfaceInfo())
241
+ }
242
+ } finally {
243
+ // Unlock the drawing surface
244
+ JAWT_DrawingSurface_Unlock(surface, surface.Unlock())
245
+ }
246
+
247
+ if (awtDebug) {
248
+ println("paint end")
249
+ }
250
+
251
+ if (animated)
252
+ repaint()
253
+ }*/
254
+
255
+ inline fun wrapped (block : (HWND ) -> Unit ) {
256
+
257
+ try {
258
+ // Get the drawing surface info
259
+ val dsi = surface.info ? : throw IllegalStateException (" ds->GetDrawingSurfaceInfo() failed" )
260
+
261
+ try {
262
+ // Get the window platform drawing info
263
+ val surfaceInfo = JAWTWin32DrawingSurfaceInfo (dsi)
264
+
265
+ val hdc = surfaceInfo.hdc
266
+ assert (hdc.isValid)
267
+
268
+ block(surfaceInfo.hwnd)
269
+
270
+ } finally {
271
+ // Free the drawing surface info
272
+ surface free dsi
273
+ }
274
+ } finally {
275
+ // Unlock the drawing surface
276
+ surface.unlock()
277
+ }
278
+ }
279
+
280
+ fun destroyInternal () {
281
+ println (" destroyInternal" )
282
+
283
+ glfwWindow.makeContextCurrent()
284
+
285
+ destroy()
286
+
287
+ debugProc?.free()
288
+
289
+ glfwWindow.unmakeContextCurrent()
290
+
291
+ JAWTFunctions .JAWT_FreeDrawingSurface (surface, awt.FreeDrawingSurface ())
292
+ awt.free()
293
+
294
+ glfwWindow.destroy()
295
+ glfw.terminate()
296
+ }
297
+
298
+ fun toggleAnimation () {
299
+ if (animated)
300
+ animated = false
301
+ else {
302
+ animated = true
303
+ repaint()
304
+ }
305
+ }
306
+
307
+ // public methods to overwrite in application
308
+
309
+ abstract fun init ()
310
+ abstract fun reshape (size : Vec2i )
311
+ abstract fun render ()
312
+ abstract fun destroy ()
313
+ }
0 commit comments