Skip to content

Commit

Permalink
Handle SDL_QUIT on the SdlLoopRunner
Browse files Browse the repository at this point in the history
  • Loading branch information
JD557 committed Apr 6, 2024
1 parent 0936e71 commit fcaf489
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,41 +25,46 @@ object SdlAsyncLoopRunner extends LoopRunner[Future] {
cleanup: () => Unit,
frequency: LoopFrequency
): Future[S] = {
val event: Ptr[SDL_Event] = malloc(sizeof[SDL_Event]).asInstanceOf[Ptr[SDL_Event]]
val fullCleanup = () => {
cleanup()
free(event.asInstanceOf[Ptr[Byte]])
SDL_Quit()
}
val fullTerminateWhen = (state: S) => {
SDL_PumpEvents()
val quit = SDL_PeepEvents(event, 1, SDL_eventaction.SDL_GETEVENT, SDL_QUIT.uint, SDL_QUIT.uint) >= 1
quit || terminateWhen(state)
}
frequency match {
case LoopFrequency.Never =>
new NeverLoop(operation, fullCleanup).run(initialState)
new NeverLoop(operation, event, fullCleanup).run(initialState)
case LoopFrequency.Uncapped =>
new UncappedLoop(operation, terminateWhen, fullCleanup).run(initialState)
new UncappedLoop(operation, fullTerminateWhen, fullCleanup).run(initialState)
case freq @ LoopFrequency.LoopDuration(_) =>
new CappedLoop(operation, terminateWhen, freq.millis, fullCleanup).run(initialState)
new CappedLoop(operation, fullTerminateWhen, freq.millis, fullCleanup).run(initialState)
}
}

final class NeverLoop[S](operation: S => S, cleanup: () => Unit) {
def checkQuit(event: Ptr[SDL_Event]) =
final class NeverLoop[S](operation: S => S, event: Ptr[SDL_Event], cleanup: () => Unit) {
def checkQuit() =
SDL_WaitEvent(event) == 1 && SDL_EventType.define((!event).`type`) == SDL_QUIT

@tailrec
private def finiteLoopAux(event: Ptr[SDL_Event]): Unit = {
val quit = checkQuit(event)
private def finiteLoopAux(): Unit = {
val quit = checkQuit()
Thread.`yield`()
if (quit) ()
else finiteLoopAux(event)
else finiteLoopAux()
}

def run(initialState: S): Future[S] = {
val event: Ptr[SDL_Event] = malloc(sizeof[SDL_Event]).asInstanceOf[Ptr[SDL_Event]]
Future(operation(initialState))
.map { res =>
finiteLoopAux(event)
finiteLoopAux()
res
}
.map { res =>
free(event.asInstanceOf[Ptr[Byte]])
cleanup()
res
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import eu.joaocosta.minart.graphics.*
import eu.joaocosta.minart.input.*

/** A low level Canvas implementation that shows the image in a SDL Window.
*
* @param handleQuit if true, the canvas should handle quit events. Otherwise, it is expected that those are handled in the application code.
*/
final class SdlCanvas() extends SurfaceBackedCanvas {
final class SdlCanvas(handleQuit: Boolean = false) extends SurfaceBackedCanvas {

// Rendering resources

Expand All @@ -40,7 +42,17 @@ final class SdlCanvas() extends SurfaceBackedCanvas {
private[this] def handleEvents(): Boolean = {
val event = stackalloc[SDL_Event]()
var keepGoing: Boolean = isCreated()
while (keepGoing && SDL_PollEvent(event) != 0) {
def nextEvent(): Int = {
if (isCreated()) {
if (handleQuit) SDL_PollEvent(event)
else {
SDL_PumpEvents()
SDL_PeepEvents(event, 1, SDL_eventaction.SDL_GETEVENT, SDL_KEYDOWN.uint, SDL_LASTEVENT.uint)
}
} else 0
}
if (isCreated()) SDL_PumpEvents()
while (keepGoing && nextEvent() > 0) {
SDL_EventType.define((!event).`type`) match {
case SDL_KEYDOWN =>
SdlKeyMapping
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,38 @@ object SdlSyncLoopRunner extends LoopRunner[Try] {
cleanup: () => Unit,
frequency: LoopFrequency
): Try[S] = {
val event: Ptr[SDL_Event] = malloc(sizeof[SDL_Event]).asInstanceOf[Ptr[SDL_Event]]
val fullCleanup = () => {
cleanup()
free(event.asInstanceOf[Ptr[Byte]])
SDL_Quit()
}
val fullTerminateWhen = (state: S) => {
SDL_PumpEvents()
val quit = SDL_PeepEvents(event, 1, SDL_eventaction.SDL_GETEVENT, SDL_QUIT.uint, SDL_QUIT.uint) >= 1
quit || terminateWhen(state)
}
frequency match {
case LoopFrequency.Never =>
new NeverLoop(operation, fullCleanup).run(initialState)
new NeverLoop(operation, event, fullCleanup).run(initialState)
case LoopFrequency.Uncapped =>
new UncappedLoop(operation, terminateWhen, fullCleanup).run(initialState)
new UncappedLoop(operation, fullTerminateWhen, fullCleanup).run(initialState)
case freq @ LoopFrequency.LoopDuration(_) =>
new CappedLoop(operation, terminateWhen, freq.millis, fullCleanup).run(initialState)
new CappedLoop(operation, fullTerminateWhen, freq.millis, fullCleanup).run(initialState)
}
}

final class NeverLoop[S](operation: S => S, cleanup: () => Unit) {
def finiteLoopAux(event: Ptr[SDL_Event]): Unit = {
final class NeverLoop[S](operation: S => S, event: Ptr[SDL_Event], cleanup: () => Unit) {
def finiteLoopAux(): Unit = {
def checkQuit() = SDL_WaitEvent(event) == 1 && SDL_EventType.define((!event).`type`) == SDL_QUIT
while (!checkQuit()) {}
()
}

def run(initialState: S): Try[S] = {
val event: Ptr[SDL_Event] = malloc(sizeof[SDL_Event]).asInstanceOf[Ptr[SDL_Event]]
val res = operation(initialState)
val res = operation(initialState)
Try {
finiteLoopAux(event)
free(event.asInstanceOf[Ptr[Byte]])
finiteLoopAux()
cleanup()
res
}
Expand All @@ -68,8 +73,10 @@ object SdlSyncLoopRunner extends LoopRunner[Try] {
}

def run(initialState: S): Try[S] =
val event: Ptr[SDL_Event] = malloc(sizeof[SDL_Event]).asInstanceOf[Ptr[SDL_Event]]
Try {
val res = finiteLoopAux(initialState)
free(event.asInstanceOf[Ptr[Byte]])
cleanup()
res
}
Expand Down
1 change: 1 addition & 0 deletions backend/native/src/main/scala/sdl2/SDL.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ object predef:
given Tag[T] = Tag.Int.asInstanceOf[Tag[T]]
extension (inline t: T)
inline def int: CInt = eq.apply(t)
inline def uint: UInt = eq.apply(t).toUInt
inline def value: CInt = eq.apply(t)

object enumerations:
Expand Down

0 comments on commit fcaf489

Please sign in to comment.