gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-lib/examples/megaduck/laptop_printer/src/megaduck_printscreen.c
1 #include <gbdk/platform.h>
2 #include <stdint.h>
3 #include <stdbool.h>
4
5 #include <duck/laptop_io.h>
6
7 #include "megaduck_printer.h"
8 #include "megaduck_printscreen.h"
9
10 static void printscreen_prepare_tile_row(uint8_t row, uint8_t tile_bitplane_offset);
11
12
13 // Currently unknown:
14 // - Single pass printer probably does not support variable image width
15 // - Double pass printer might, since it has explicit Carriage Return and Line Feed commands, but it's not verified
16 //
17 // So for the time being require full screen image width
18 //
19 // The Duck Printer mechanical Carriage Return + Line Feed process takes about
20 // 500 msec for the print head to travel back to the start of the line.
21 //
22 // After that there is about a 600 msec period before the printer head
23 // starts moving. The ASIC between the CPU and the printer may be
24 // buffering printer data during that time so it can stream it out
25 // with the right timing.
26 //
27 // So giving the printer ~1000 msec between tile rows is needed
28 // to avoid printing glitches. The duration was determined through
29 // trial and error.
30 //
31 // The same ~1000 msec delay should be present after the last
32 // tile row is sent to allow the printer to finish processing
33 // that row before sending other commands. For example if this
34 // isn't done and a keyboard poll is sent immediately after
35 // the last tile row, then the peripheral controller seems to
36 // trigger a cpu reset.
37 //
38 bool duck_print_screen(void) {
39
40 bool return_status = true;
41
42 // Check for printer connectivity
43 uint8_t printer_type = duck_io_printer_query();
44 // Fix up printer status == 3 to be printer type 1, sort of a hack
45 if (printer_type == DUCK_IO_PRINTER_MAYBE_BUSY) printer_type = DUCK_IO_PRINTER_TYPE_1_PASS;
46 if (printer_type != DUCK_IO_PRINTER_TYPE_1_PASS) return false;
47
48 // Turn off VBlank interrupt during printing to avoid disruptions when
49 // streaming the tile row data
50 uint8_t int_enables_saved = IE_REG;
51 set_interrupts(IE_REG & ~VBL_IFLAG);
52
53 // Starting with a blank row (like system rom does) avoids a glitch where
54 // a tile is skipped somewhere in the very first row printed
55 duck_print_blank_row();
56
57 // Send the tile data row by row
58 for (uint8_t map_row = 0; map_row < DEVICE_SCREEN_HEIGHT; map_row++) {
59 printscreen_prepare_tile_row(map_row, BITPLANE_BOTH);
60 return_status = duck_printer_send_tile_row_1pass();
61 if (return_status == false) break;
62 }
63
64 // Print up to N blank rows to scroll the printed result up
65 // past the printer tear off position
66 if (return_status) {
67 for (uint8_t blank_row=0u; blank_row < PRINT_NUM_BLANK_ROWS_AT_END; blank_row++) {
68 duck_print_blank_row();
69 }
70 }
71
72 // Restore VBlank interrupt
73 set_interrupts(int_enables_saved);
74
75 return return_status;
76 }
77
78
79 // Prints a blank tile row by filling the pattern data with all zeros
80 // and then printing a row
81 bool duck_print_blank_row(void) {
82
83 // Fill print buffer with zero's
84 uint8_t * p_buf = tile_row_buffer;
85 for (uint8_t c = 0u; c < (DEVICE_SCREEN_WIDTH * BYTES_PER_PRINTER_TILE); c++) {
86 *p_buf++ = 0x00u;
87 }
88
89 return duck_printer_send_tile_row_1pass();
90 }
91
92
93 // Prepares a tile row from the contents of screen vram
94 static void printscreen_prepare_tile_row(uint8_t row, uint8_t tile_bitplane_offset) {
95
96 uint8_t tile_buffer[BYTES_PER_VRAM_TILE];
97 uint8_t * p_row_buffer = tile_row_buffer;
98
99 bool use_win_data = (((row * TILE_HEIGHT) >= WY_REG) && ( LCDC_REG & LCDCF_WINON));
100 uint8_t col = 0;
101
102 if (!use_win_data) {
103 // Add Scroll offset to closest tile (if rendering BG instead of Window)
104 row += (SCY_REG / TILE_HEIGHT);
105 col += (SCX_REG / TILE_WIDTH);
106 }
107
108 // Loop through tile columns for the current tile row
109 for (uint8_t tile = 0u; tile < DEVICE_SCREEN_WIDTH; tile++) {
110
111 uint8_t tile_id;
112 // Get the Tile ID from the map then copy it's tile pattern data into a buffer
113 if (use_win_data) {
114 // Read window data instead if it's enabled and visible
115 tile_id = get_win_tile_xy((col + tile) & (DEVICE_SCREEN_BUFFER_HEIGHT - 1),
116 (row - (WY_REG / TILE_HEIGHT)) & (DEVICE_SCREEN_BUFFER_HEIGHT - 1));
117 } else {
118 // Otherwise use the normal BG
119 tile_id = get_bkg_tile_xy((col + tile) & (DEVICE_SCREEN_BUFFER_HEIGHT - 1),
120 row & (DEVICE_SCREEN_BUFFER_HEIGHT - 1));
121 }
122 get_bkg_data(tile_id, 1u, tile_buffer);
123
124 // Mirror, Rotate -90 degrees and reduce tile to 1bpp
125 if (tile_bitplane_offset == BITPLANE_BOTH)
126 duck_printer_convert_tile_dithered(p_row_buffer, tile_buffer);
127 else
128 duck_printer_convert_tile(p_row_buffer, tile_buffer + tile_bitplane_offset);
129 p_row_buffer += BYTES_PER_PRINTER_TILE;
130 }
131 }
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.