pico9918-core 1.3.0
TMS9918A / F18A video display processor emulation in C99
Loading...
Searching...
No Matches
splash.c
Go to the documentation of this file.
1/**
2 * \file
3 * \brief pico9918-core - Splash overlay
4 *
5 * Copyright (c) 2024 Troy Schrapel
6 *
7 * This code is licensed under the MIT license
8 *
9 * https://github.com/visrealm/pico9918-core
10 *
11 */
12
13#include "splash.h"
14
15#include <stdbool.h>
16
17#if !PICO9918_NO_SPLASH
18
19/* Generated from PICO9918_SPLASH_IMAGE. The generator is told the symbol base
20 * name, so the board-conditional asset still yields splash* here and this TU
21 * carries no per-board #ifdef. */
22#include "overlay/bmp_splash.h"
23
24#if PICO9918_BUILD_RUNTIME_CHIP
25#include "overlay/bmp_splash_pro.h"
26
27/* Which artwork the personality wants. Set from pico9918_set_chip, where everything else
28 derived from the personality is worked out once. File scope like the animation state
29 above it, which is already shared. */
30static bool splashIsPro = false;
31
32/* The band is positioned from SPLASH_HEIGHT at compile time, so the two must agree. */
33PICO9918_STATIC_ASSERT(SPLASHPRO_HEIGHT == SPLASH_HEIGHT,
34 "the PRO splash is a different height - SPLASH_START_POS assumes one band");
35
37{
38 splashIsPro = pro;
39}
40#endif
41
42#define SPLASH_ENTER_FRAMES 60
43#define SPLASH_HOLD_FRAMES 180
44/* SPLASH_HEIGHT, not the splashHeight const int: this initialises a static, and
45 * reading a const object is not a constant expression in standard C (GCC allows
46 * it as an extension, MSVC rejects it). Same value, from the same generator. */
47#define SPLASH_START_POS (SPLASH_ENTER_FRAMES + SPLASH_HEIGHT + 2)
48
49static int logoOffset = SPLASH_START_POS;
50static bool canHideSplash = false;
51
52#endif
53
54/*
55 * reset the splash popup (after... reset)
56 */
58{
59#if !PICO9918_NO_SPLASH
60 logoOffset = SPLASH_START_POS;
61#endif
62}
63
65{
66#if !PICO9918_NO_SPLASH
67 canHideSplash = true;
68#endif
69}
70
71/*
72 * output the PICO9918 splash logo / firmware version at the bottom of the screen
73 */
74void pico9918_splash_render(uint16_t y, uint32_t frameCount, uint32_t vBorder, uint32_t vPixels,
75 uint32_t vVirtualPixels, PICO9918_PIXEL_T* pixels)
76{
77#if PICO9918_NO_SPLASH
78 (void)y;
79 (void)frameCount;
80 (void)vBorder;
81 (void)vPixels;
82 (void)vVirtualPixels;
83 (void)pixels;
84#else
85
86 if (y == 0)
87 {
88 if (frameCount < SPLASH_ENTER_FRAMES)
89 --logoOffset;
90 else if (canHideSplash && frameCount > (SPLASH_ENTER_FRAMES + SPLASH_HOLD_FRAMES))
91 ++logoOffset;
92 }
93
94 if (y <= vVirtualPixels)
95 {
96 /* WARNING: the 16-bit wraparound is the row gate, so do not "fix" the narrowing with a cast or a
97 * signed rewrite. logoOffset goes negative, so a row outside the logo band wraps to a large
98 * uint16 and fails the test below. MSVC C4244 may fire; the truncation is the mechanism. */
99 y -= vBorder + vPixels + logoOffset;
100 if (y < splashHeight)
101 {
102 const int leftBorderPx = 4;
103 const int splashBpp = 2;
104 const int splashPixPerByte = 8 / splashBpp;
105
106#if PICO9918_BUILD_RUNTIME_CHIP
107 uint8_t* const art = splashIsPro ? splashPro : splash;
108 const int artWidth = splashIsPro ? splashProWidth : splashWidth;
109 const PICO9918_PIXEL_T* pal = splashIsPro ? splashPro_pal : splash_pal;
110#else
111 uint8_t* const art = splash;
112 const int artWidth = splashWidth;
113 const PICO9918_PIXEL_T* pal = splash_pal;
114#endif
115
116 uint8_t* splashPtr = art + (y * artWidth / splashPixPerByte);
117
118 for (int x = leftBorderPx; x < leftBorderPx + artWidth; x += splashPixPerByte)
119 {
120 uint8_t c = *(splashPtr++);
121 uint8_t pixMask = 0xc0;
122 uint8_t offset = 6;
123
124 for (int px = 0; px < 4; ++px, offset -= 2, pixMask >>= 2)
125 {
126 uint8_t palIndex = (c & pixMask) >> offset;
127 if (palIndex) pixels[x + px] = pal[palIndex];
128 }
129 }
130 }
131 }
132#endif
133}
134
135#if PICO9918_BUILD_RUNTIME_CHIP
136
137#include "overlay/bmp_f18a_badge.h"
138
139_Static_assert(F18ABADGE_HEIGHT == PICO9918_F18A_BADGE_HEIGHT,
140 "the badge asset is not the height the renderer draws");
141_Static_assert(F18ABADGE_WIDTH == PICO9918_F18A_BADGE_WIDTH,
142 "the badge asset is not the width the renderer draws");
143/* img2carray.py emits a 1bpp byte only on every eighth pixel, so any other width
144 loses its last columns with no warning. */
145_Static_assert(F18ABADGE_WIDTH % 8 == 0, "the badge asset width must be a multiple of 8");
146
147bool pico9918_f18a_badge_render(uint16_t outputLine, uint32_t frameCount, PICO9918_PIXEL_T* pixels)
148{
149 if (frameCount >= PICO9918_F18A_BADGE_FRAMES || outputLine >= PICO9918_F18A_BADGE_HEIGHT)
150 {
151 return false;
152 }
153
154 const uint8_t* row = f18aBadge + outputLine * (F18ABADGE_WIDTH / 8);
155
156 /* Opaque, so unlike the splash above there is no index to treat as transparent. */
157 for (uint32_t x = 0; x < PICO9918_F18A_BADGE_WIDTH; ++x)
158 {
159 pixels[x] = f18aBadge_pal[(row[x >> 3] >> (7 - (x & 7))) & 1];
160 }
161
162 return true;
163}
164
165#endif // PICO9918_BUILD_RUNTIME_CHIP
void pico9918_splash_allow_hide(void)
allow the splash to animate back out - the host calls this once the display has been enabled
Definition splash.c:64
void pico9918_splash_select_pro(bool pro)
render the F18A's power-on badge into the scanline buffer
Definition splash.c:36
void pico9918_splash_render(uint16_t y, uint32_t frameCount, uint32_t vBorder, uint32_t vPixels, uint32_t vVirtualPixels, PICO9918_PIXEL_T *pixels)
render the splash logo into the scanline buffer, if row y falls in the logo band.
Definition splash.c:74
void pico9918_splash_reset(void)
restart the splash animation (after... reset)
Definition splash.c:57
pico9918-core - Splash overlay
#define PICO9918_F18A_BADGE_WIDTH
badge columns - must stay a multiple of 8, see splash.c
Definition splash.h:82
#define PICO9918_F18A_BADGE_HEIGHT
badge rows, each one OUTPUT line rather than one display line
Definition splash.h:84
#define PICO9918_F18A_BADGE_FRAMES
frames the badge is shown for, counting from reset
Definition splash.h:86