From ebe6230f3e076926dcd3c591a860c30028bf83eb Mon Sep 17 00:00:00 2001 From: Wayne Venables Date: Tue, 7 Mar 2023 23:30:05 -0800 Subject: [PATCH] Additional documentation --- DoxygenLayout.xml | 4 +- Wiring.md | 1 + custom.css | 3 + doxygen-awesome.css | 145 +++++++++++++++++++++++++++++++++++++++----- doxygen.cfg | 4 +- src/picovga.h | 22 ++++++- src/vga_layer.h | 64 +++++++++++++++++++ 7 files changed, 223 insertions(+), 20 deletions(-) create mode 100644 custom.css diff --git a/DoxygenLayout.xml b/DoxygenLayout.xml index bb5e4c7..e85bb5c 100644 --- a/DoxygenLayout.xml +++ b/DoxygenLayout.xml @@ -4,7 +4,7 @@ - + @@ -167,7 +167,7 @@ - + diff --git a/Wiring.md b/Wiring.md index 6f39c39..738feac 100644 --- a/Wiring.md +++ b/Wiring.md @@ -1,3 +1,4 @@ + # Wiring diagram {#wiring} I don't present here the overall circuit I used, because the library was created as part of a retro gaming computer with Raspberry Pico and is still under development. Here is a simplified wiring diagram of the VGA monitor output (with added audio PWM output): diff --git a/custom.css b/custom.css new file mode 100644 index 0000000..e5626b3 --- /dev/null +++ b/custom.css @@ -0,0 +1,3 @@ +.image { + text-align: left; +} diff --git a/doxygen-awesome.css b/doxygen-awesome.css index abd2893..e8399cb 100644 --- a/doxygen-awesome.css +++ b/doxygen-awesome.css @@ -5,7 +5,7 @@ https://github.com/jothepro/doxygen-awesome-css MIT License -Copyright (c) 2021 - 2022 jothepro +Copyright (c) 2021 - 2023 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -160,7 +160,7 @@ html { --toc-background: var(--side-nav-background); --toc-foreground: var(--side-nav-foreground); - /* height of an item in any tree / collapsable table */ + /* height of an item in any tree / collapsible table */ --tree-item-height: 30px; --memname-font-size: var(--code-font-size); @@ -790,6 +790,7 @@ html.dark-mode iframe#MSearchResults { #nav-tree { background: transparent; + margin-right: 1px; } #nav-tree .label { @@ -956,8 +957,9 @@ div.contents div.dyncontent { html:not(.light-mode) div.contents > table img, html:not(.light-mode) div.contents div.dyncontent iframe, html:not(.light-mode) div.contents center iframe, - html:not(.light-mode) div.contents table iframe { - filter: hue-rotate(180deg) invert(); + html:not(.light-mode) div.contents table iframe, + html:not(.light-mode) div.contents .dotgraph iframe { + filter: brightness(89%) hue-rotate(180deg) invert(); } } @@ -966,8 +968,10 @@ html.dark-mode div.contents center img, html.dark-mode div.contents > table img, html.dark-mode div.contents div.dyncontent iframe, html.dark-mode div.contents center iframe, -html.dark-mode div.contents table iframe { - filter: hue-rotate(180deg) invert(); +html.dark-mode div.contents table iframe, +html.dark-mode div.contents .dotgraph iframe + { + filter: brightness(89%) hue-rotate(180deg) invert(); } h2.groupheader { @@ -1056,6 +1060,21 @@ h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { color: var(--page-foreground-color); } +.dotgraph { + max-width: 100%; + overflow-x: scroll; +} + +.dotgraph .caption { + position: sticky; + left: 0; +} + +/* Wrap Graphviz graphs with the `interactive_dotgraph` class if `INTERACTIVE_SVG = YES` */ +.interactive_dotgraph .dotgraph iframe { + max-width: 100%; +} + /* Table of Contents */ @@ -1322,7 +1341,7 @@ dl.bug dt a, dl.deprecated dt a, dl.todo dt a { font-weight: bold !important; } -dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.todo, dl.remark { +dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { padding: var(--spacing-medium); margin: var(--spacing-medium) 0; color: var(--page-background-color); @@ -1393,13 +1412,13 @@ dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { margin-inline-start: 0px; } -dl.invariant, dl.pre { +dl.invariant, dl.pre, dl.post { background: var(--invariant-color); border-left: 8px solid var(--invariant-color-dark); color: var(--invariant-color-darker); } -dl.invariant dt, dl.pre dt { +dl.invariant dt, dl.pre dt, dl.post dt { color: var(--invariant-color-dark); } @@ -1603,6 +1622,10 @@ table.doxtable tbody { border-radius: var(--border-radius-small); } +table.markdownTable, table.doxtable, table.fieldtable { + padding: 1px; +} + table.doxtable caption { display: block; } @@ -1693,6 +1716,15 @@ table.markdownTable tr:last-child, table.doxtable tr:last-child { border-bottom: none; } +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) { + display: block; +} + +.full_width_table table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { + display: table; + width: 100%; +} + table.fieldtable th { font-size: var(--page-font-size); font-weight: 600; @@ -2195,7 +2227,9 @@ div.memproto::-webkit-scrollbar, .contents center::-webkit-scrollbar, .contents .center::-webkit-scrollbar, .contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, -div.contents .toc::-webkit-scrollbar { +div.contents .toc::-webkit-scrollbar, +.contents .dotgraph::-webkit-scrollbar, +.contents .tabs-overview-container::-webkit-scrollbar { background: transparent; width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); @@ -2208,7 +2242,9 @@ div.memproto::-webkit-scrollbar-thumb, .contents center::-webkit-scrollbar-thumb, .contents .center::-webkit-scrollbar-thumb, .contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, -div.contents .toc::-webkit-scrollbar-thumb { +div.contents .toc::-webkit-scrollbar-thumb, +.contents .dotgraph::-webkit-scrollbar-thumb, +.contents .tabs-overview-container::-webkit-scrollbar-thumb { background-color: transparent; border: var(--webkit-scrollbar-padding) solid transparent; border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); @@ -2222,7 +2258,9 @@ div.memproto:hover::-webkit-scrollbar-thumb, .contents center:hover::-webkit-scrollbar-thumb, .contents .center:hover::-webkit-scrollbar-thumb, .contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, -div.contents .toc:hover::-webkit-scrollbar-thumb { +div.contents .toc:hover::-webkit-scrollbar-thumb, +.contents .dotgraph:hover::-webkit-scrollbar-thumb, +.contents .tabs-overview-container:hover::-webkit-scrollbar-thumb { background-color: var(--webkit-scrollbar-color); } @@ -2233,7 +2271,9 @@ div.memproto::-webkit-scrollbar-track, .contents center::-webkit-scrollbar-track, .contents .center::-webkit-scrollbar-track, .contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, -div.contents .toc::-webkit-scrollbar-track { +div.contents .toc::-webkit-scrollbar-track, +.contents .dotgraph::-webkit-scrollbar-track, +.contents .tabs-overview-container::-webkit-scrollbar-track { background: transparent; } @@ -2270,7 +2310,9 @@ div.memproto, .contents center, .contents .center, .contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, -div.contents .toc { +div.contents .toc, +.contents .dotgraph, +.contents .tabs-overview-container { scrollbar-width: thin; } @@ -2403,3 +2445,78 @@ a.anchorlink:hover { h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { display: inline-block; } + +/* + Optional tab feature +*/ + +.tabbed ul { + padding-inline-start: 0px; + margin: 0; + padding: var(--spacing-small) 0; + border-bottom: 1px solid var(--separator-color); +} + +.tabbed li { + display: none; +} + +.tabbed li.selected { + display: block; +} + +.tabs-overview-container { + overflow-x: auto; + display: block; + overflow-y: visible; +} + +.tabs-overview { + border-bottom: 1px solid var(--separator-color); + display: flex; + flex-direction: row; +} + +.tabs-overview button.tab-button { + color: var(--page-foreground-color); + margin: 0; + border: none; + background: transparent; + padding: var(--spacing-small) 0; + display: inline-block; + font-size: var(--page-font-size); + cursor: pointer; + box-shadow: 0 1px 0 0 var(--separator-color); +} + +.tabs-overview button.tab-button .tab-title { + float: left; + white-space: nowrap; + padding: var(--spacing-small) var(--spacing-large); + border-radius: var(--border-radius-medium); +} + +.tabs-overview button.tab-button:not(:last-child) .tab-title { + box-shadow: 8px 0 0 -7px var(--separator-color); +} + +.tabs-overview button.tab-button:hover .tab-title { + background: var(--primary-color); + color: var(--page-background-color); + box-shadow: none; +} + +.tabs-overview button.tab-button.active { + color: var(--primary-color); + box-shadow: 0 1px 0 0 var(--primary-color), inset 0 -1px 0 0 var(--primary-color); +} + +@media (prefers-color-scheme: dark) { + html:not(.light-mode) .tabs-overview button.tab-button:hover .tab-title { + color: var(--page-foreground-color); + } +} + +html.dark-mode .tabs-overview button.tab-button:hover .tab-title { + color: var(--page-foreground-color); +} \ No newline at end of file diff --git a/doxygen.cfg b/doxygen.cfg index 1213a64..c66e6c0 100644 --- a/doxygen.cfg +++ b/doxygen.cfg @@ -951,7 +951,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = . # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -1248,7 +1248,7 @@ HTML_STYLESHEET = # This tag requires that the tag GENERATE_HTML is set to YES. FULL_SIDEBAR = NO -HTML_EXTRA_STYLESHEET = doxygen-awesome.css +HTML_EXTRA_STYLESHEET = doxygen-awesome.css custom.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note diff --git a/src/picovga.h b/src/picovga.h index 61a4399..7f831c9 100644 --- a/src/picovga.h +++ b/src/picovga.h @@ -10,7 +10,8 @@ /// @defgroup VideoInitGroup Video/Library Initialization /// @defgroup VideoModeGroup Configurating Video Mode /// @defgroup ScreenGroup Screen Layout -/// @defgroup LayersGroup Overlay Layers and Sprites +/// @defgroup LayersGroup Overlay Layers +/// @defgroup SpriteGroup Sprites /// @defgroup ColorsGroup Colors and Palettes /// @defgroup CanvasGroup Canvas /// @defgroup OverclockGroup CPU Overclocking @@ -20,6 +21,7 @@ /// @defgroup Core1Group Second Core /// @defgroup UtilsGroup Utility Functions /// @defgroup TypesGroup Base types and Constants +/// @defgroup FontsGroup Fonts /** * @addtogroup TypesGroup @@ -119,7 +121,20 @@ typedef unsigned char Bool; // Includes // ---------------------------------------------------------------------------- -// fonts +/** + * @addtogroup FontsGroup + * @brief Included fonts + * @details The following fonts are ready to use in programs. The fonts in PicoVGA are in monochrome image format + * (i.e. 1 pixel is 1 bit) with 256 characters per line and a character width of 8 pixels. The total width of the + * image is therefore 2048 pixels (256 bytes). The height of the font can be arbitrary, but by default there are 8, + * 14 and 16 line fonts in the library. Fonts are exported by the RaspPicoImg utility to *.cpp source text format, + * and are added to the program as a byte array. + * + * Example of font font_bold_8x8: + * ![](www/img/font1.jpg) + * @{ +*/ + extern const ALIGNED u8 FontBold8x8[2048]; extern const ALIGNED u8 FontBold8x14[3584]; extern const ALIGNED u8 FontBold8x16[4096]; @@ -133,6 +148,9 @@ extern const ALIGNED u8 FontIbmTiny8x8[2048]; extern const ALIGNED u8 FontItalic8x8[2048]; extern const ALIGNED u8 FontThin8x8[2048]; +/// @} + + // PicoVGA includes #include "define.h" // common definitions of C and ASM #include "util/canvas.h" // canvas diff --git a/src/vga_layer.h b/src/vga_layer.h index 030c4f8..2fcdbd8 100644 --- a/src/vga_layer.h +++ b/src/vga_layer.h @@ -311,6 +311,69 @@ void LayerSetup(u8 inx, const u8* img, const sVmode* vmode, u16 w, u16 h, u8 col void LayerPerspSetup(u8 inx, const u8* img, const sVmode* vmode, u16 w, u16 h, u8 xbits, u8 ybits, s8 horiz, const int* mat, u8 col = 0); +/// @} + +/** + * @addtogroup SpriteGroup + * @details Sprites can be used in overlay planes with KEY, BLACK and WHITE programs. There are two ways to use the sprites: + * + * 1. Slow sprites, LAYERMODE_SPRITE* modes. Sprites are software generated. The line rendering function first clears the line + * buffer with a transparent color and then sequentially passes through the array of sprites. It looks for which sprites overlap + * a given Y address and, if so, renders the line into the buffer. Sprites in this mode have the advantage that they can overlap + * arbitrarily (the order of overlapping is based on the order of location in the address array) and can scroll subtly pixel by + * pixel. The main disadvantage is the high rendering overhead. Even a small number of sprites can cause a line rendering time + * overflow and thus an video dropout. However, it is important to note that the number of sprites (and their dimensions) on the + * same video line is involved. Sprites at distant Y-coordinates are not affected. To check if the rendering function will + * handle a given number of sprites, place the sprites horizontally next to each other. Conversely, if you want to ensure low + * rendering requirements, ensure that the sprites are not in the same vertical Y coordinates. Or reduce the width of the sprites. + * + * 2. Fast sprites, LAYERMODE_FASTSPRITE* modes. Sprites are not software rendered to the render buffer, but are sent directly to + * PIO via DMA transfer. This makes the rendering of sprites very fast and allows multiple sprites to be displayed side by side. + * Of course, this brings disadvantages on the other side. The X-coordinate of the sprites and their width must be a multiple of 4, + * and the sprites cannot be scrolled finely on the screen (does not apply to the Y-coordinate). But most importantly, the sprites + * cannot directly overlap. One sprite can continue rendering where the previous sprite left off. Thus, the previous sprite can cut + * off the beginning of the next sprite. There is a treatment that can slightly improve the situation. To improve overlays (and + * speed up rendering), the sprite includes a table that indicates how many pixels from the edge the opaque sprite line starts + * and how long it is. The SpritePrepLines() function can be used to generate the table. For fast sprites, this information must be + * a multiple of 4. Thus, if we ensure that the beginnings and ends of the image lines start and end at multiples of 4, the + * sprites will overlap almost correctly (unless they have internal transparency). Otherwise, transparent holes may appear at + * the point of overlap. One of the requirements for fast sprites is that the list of sprites must be sorted by the X coordinate. + * The SortSprite() support function is used for this purpose. + * + * When using sprites, the first step will be to specify the LAYERMODE_*SPRITE* layer mode for the VgaCfg() initialization + * function. + * + * The second step will be to build an array of sprite pattern line starts and lengths using the SpritePrepLines() function. + * The function will be passed a pointer to the image of each sprite (only 8-bit sprites are supported), the image dimensions, + * the pointers to the array of origin and line lengths (the array dimensions correspond to the height of the sprite), and the + * key transparency color. The function searches for line starts and line ends and writes them into the fields. The 'fast' + * parameter specifies whether the tables are generated for fast sprites, in which case the line starts and lengths are divided + * by 4. For slow sprites, the sprite width must be limited to 255 pixels. + * + * The third step is to build a list of sprites and initialize the sprites - especially the pointer to the image, the dimensions + * and coordinates of the sprites. The sprite list is an array of pointers to the sprite. Each sprite can only be in the list + * once, but multiple sprite can share the same sprite image and the same array of line starts and lengths. Slow sprites can have + * coordinates outside the allowed range (they will be cropped), but for fast sprites I recommend not to exceed the horizontal + * limits of the screen, the cropping of the image is not yet properly tuned and the program might crash. + * + * While the sprites don't have a parameter to turn them off, they can be turned off by setting the Y coordinate out off screen. + * During rendering, visible sprites are searched for by the Y coordinate, an invalid Y coordinate will ensure that the sprite + * is safely disabled. + * + * Fast sprites require sorting the list by the X coordinate. This is done by the SortSprite() function, which is passed a pointer + * to the list of sprites and the number of sprites in the list. This function should be called whenever you change the X + * coordinate of the sprite. Transient conditions (e.g. momentary mis-overlapping of sprites) do not matter, they are just + * short-term optical errors, they do not compromise the program. The function sorts using the bubble method, so it is quite + * slow, but so far it does not seem to harm anything (there are not many sprays). + * + * The last step is the initialization of the layer with the sprite. The function was described in the previous chapter. + * + * The next step is to turn on layer visibility with LayerOn() and control the sprites by changing their X and Y coordinates and + * changing their img images. + * + * @{ +*/ + /** * @brief Setup overlapped layer 1..3 for LAYERMODE_SPRITE* and LAYERMODE_FASTSPRITE* modes * @details It differs from the other setup functions by specifying the coordinate of the sprite area, the pointer to the @@ -324,6 +387,7 @@ void LayerPerspSetup(u8 inx, const u8* img, const sVmode* vmode, u16 w, u16 h, u * @param w Width of area with sprites (must be multiple of 4) * @param h Height of area with sprites * @param col Key color (needed for LAYERMODE_SPRITEKEY and LAYERMODE_FASTSPRITEKEY layer mode) + * @see LayersGroup */ void LayerSpriteSetup(u8 inx, sSprite** sprite, u16 spritenum, const sVmode* vmode, s16 x, s16 y, u16 w, u16 h, u8 col = 0);