• Docs
  • Install
  • Follow @cosplayengine
  • v.0.9.5
  • GitHub
  • Watch
  • Examples
  1. Home
  2. Video

Video

  • Introduction
  • Install
  • ASCII Games
  • Demos
  • Examples
  • Macarena
  • Pong
  • Snake
  • Bird
  • Developer Guide
  • Quick Game 🏃
  • Key Concepts
  • Game Structure
  • Scenes & Objects
  • Log & Debugging
  • Pixels & Colors
  • Images
  • Keyboard Input
  • Sprite Animation
  • Shaders
  • Particle Effects
  • Fonts
  • Canvas Drawing
  • Text Input
  • Camera Tracking
  • Tile Mapping
  • Audio
  • Video
  • UI Toolkit
  • Build & Run

Video

Video rendered in ASCII character is rather an acquired taste... However, when used carefully and tastefully it can provide striking visuals for ASCII game. Typical workflow of creating ASCII video includes:

  • Converting an existing video clip (like MP4) into a series of individual per-frame images (JPEGs).
  • Converting each individual image into ASCII image.
  • Displaying a sequence of ASCII images.

There are plenty of existing tooling available that can help you to convert a standard video like MP4 into a set of JPEG images and then convert these images into ASCII art images. Once you have ASCII art images you can use CosPlay video support to play back that video.

CosPlay video support consists of:

  • CPVideo - video descriptor.
  • CPVideoSprite - video playback sprite.
  • CPVideoSpriteListener - video playback synchronization listener.

Video is defined as a sequence of same-sized frames where each frame is an image. CPVideoSprite provides rendering of that video while CPVideoSpriteListener allows the video playback to synchronize with other action in the game like sound or animation.

Video Is An Asset

Just like other assets such as CPFont, CPImage, CPParticleEmitter, CPAnimation or CPSound they are not managed or governed by the CosPlay game engine unlike scenes and scene object, that are managed and governed by the game engine. Assets are typically created outside the game loop and managed by the developer, they can be freely shared between scenes or scene objects as any other standard Scala objects.

Creating Video Clip

Vide clip is defined by CPVideo class.

Let's see the usage of video support on a quick video clip that we'll call "Psychedelic Tunnel". Here's the source code for the video clip definition (which is also available in the built-in video example). Now, this code snippet does more than a usual video clip definition would: it not only loads the raw footage from prefab/video/tunnel.txt file but also skins every frame adding programmatic contrast and applying "psychedelic" effect to it:

            import org.cosplay.*
            import CPPixel.*
            import CPColor.*

            import scala.io.Source
            import scala.util.Using

            // 40 frames from https://ascii.co.uk/animated-art/3d-tunnel-animated-ascii-art.html.
            object VideoClip extends CPVideo("vid", "https://ascii.co.uk/animated-art/3d-tunnel-animated-ascii-art.html"):
                private final val RAW_FOOTAGE = "prefab/video/tunnel.txt" // Under 'resources' folder...
                private final val FRAME_CNT = 40
                private val frames: Seq[CPImage] = {
                    val rsrc = getClass.getClassLoader.getResourceAsStream(RAW_FOOTAGE)
                    if rsrc != null then
                        Using.resource(Source.fromInputStream(rsrc, "UTF-8")) { rs =>
                            // Load all lines and skip empty ones.
                            val lines = rs.getLines().toSeq.filter(_.trim.nonEmpty)
                            lines.grouped(lines.size / FRAME_CNT).toSeq.map { frameLines =>
                                // Psychedelic mode :-)
                                val c = CPRand.rand(CS_X11_ALL)
                                new CPArrayImage(frameLines, (ch, _, _) => {
                                    ch match
                                        // Color it for more contrast.
                                        case '.' => ch&c.darker(0.4)
                                        case ',' => ch&c.darker(0.3)
                                        case ':' => ch&c.darker(0.25)
                                        case ';' => ch&c.darker(0.2)
                                        case 'i' => ch&c.darker(0.15)
                                        case '1' => ch&c.darker(0.05)
                                        case ' ' => XRAY
                                        case _ => ch&c
                                })
                            }
                        }
                    else
                        throw Exception(s"Unable to find or load: $RAW_FOOTAGE")
                }

                override val getFrameCount: Int = frames.size
                override val getFrameDim: CPDim = frames.head.getDim
                override def getFrame(idx: Int): CPImage = frames(idx)
        

NOTES:

  • Note that we know upfront that there are 40 frames in the prefab/video/tunnel.txt raw footage file.
  • The only methods that you need to implement are those on the lines 39, 40 and 41.

Playing Video Clip

Video playback is based on CPVideoSprite class.

Once we have a video clip, let's develop a simple playback interface that would allow pausing, resuming and rewinding the playback. Here's the full source code for this fully functional video player:

            import org.cosplay.*
            import CPColor.*
            import CPPixel.*
            import CPKeyboardKey.*
            import CPStyledString.styleStr
            import prefabs.shaders.*

            object VideoPlayer:
                def main(args: Array[String]): Unit =
                    val c1 = C_LIGHT_GREEN
                    val c2 = C_ORANGE1
                    val ctrlImg = new CPArrayImage(
                        styleStr("[Space]", c1) ++ styleStr(" Play|Pause    ", c2) ++
                        styleStr("[R]", c1) ++ styleStr(" Rewind    ", c2) ++
                        styleStr("[Q]", c1) ++ styleStr(" Quit    ", c2) ++
                        styleStr("[Ctrl-L]", c1) ++ styleStr(" Log    ", c2) ++
                        styleStr("[Ctrl-Q]", c1) ++ styleStr(" FPS Overlay", c2)
                    ).trimBg()
                    val vidDim = VideoClip.getFrameDim
                    val ctrlDim = ctrlImg.getDim
                    val dim = CPDim((vidDim.w + 8).max(ctrlDim.w + 4), vidDim.h + 8)
                    val vidSpr = new CPVideoSprite(vid = VideoClip, 4, 2, 0, 30, true, false, true)
                    val bgPx = '.'&&(C_GRAY2, C_GRAY1)
                    // Create the scene.
                    val sc = new CPScene("scene", Option(dim), bgPx,
                        vidSpr,
                        new CPKeyboardSprite((_, key) => key match
                            case KEY_LO_R => vidSpr.rewind()
                            case KEY_SPACE => vidSpr.toggle()
                            case _ => ()
                        ),
                        new CPStaticImageSprite((dim.w - ctrlDim.w) / 2, dim.h - 4, 0, ctrlImg),
                        CPKeyboardSprite(_.exitGame(), KEY_LO_Q) // Exit the game on 'q' press.
                    )

                    // Initialize the engine.
                    CPEngine.init(
                        CPGameInfo(name = "Video Player", initDim = Option(dim)),
                        System.console() == null || args.contains("emuterm")
                    )

                    // Start the game & wait for exit.
                    try CPEngine.startGame(sc)
                    finally CPEngine.dispose()

                    sys.exit(0)
        

NOTES:

  • Most of the code in this example has to do with setting up the video player interface.
  • Video playback sprite is created on the line 22 and controlled on the line 28 and 29 by the keyboard keys.

Run this example to get this video playback:

Useful Links

Here's some useful links for ASCII videos:

  • Use https://www.ffmpeg.org/ or similar tool to convert video into separate still images.
  • Use https://github.com/cslarsen/jp2a or similar tool to convert individual JPGs into ASCII.
  • https://john.dev/b?id=2019-02-23-ascii-face provides full example of ASCII video.
  • On This Page
  • Video
  • Create Clip
  • Play Clip
  • Useful Links
  • Example
  • Video Example
  • Quick Links
  • Discord
  • Stack Overflow
  • GitHub
  • @cosplayengine
  • YouTube
  • API
Copyright © 2023 Rowan Games, Inc. Privacy • Docs release: 0.9.5 Latest: