diff --git a/.gitignore b/.gitignore index f25df931..006a1228 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .vscode .DS_Store video/build +video.ino.cpp diff --git a/platformio.ini b/platformio.ini index dc7c957a..e0e72a90 100644 --- a/platformio.ini +++ b/platformio.ini @@ -30,3 +30,4 @@ build_flags = monitor_filters = esp32_exception_decoder monitor_speed = 115200 upload_speed = 600000 +build_type = debug diff --git a/video/agon.h b/video/agon.h index dbdb196b..42081a48 100644 --- a/video/agon.h +++ b/video/agon.h @@ -60,6 +60,7 @@ #define VDP_CONTROLKEYS 0x98 // Control keys on/off #define VDP_BUFFERED 0xA0 // Buffered commands #define VDP_UPDATER 0xA1 // Update VDP +#define VDP_BDPP 0xA2 // Enable BDPP #define VDP_LOGICALCOORDS 0xC0 // Switch BBC Micro style logical coords on and off #define VDP_LEGACYMODES 0xC1 // Switch VDP 1.03 compatible modes on and off #define VDP_SWITCHBUFFER 0xC3 // Double buffering control @@ -212,6 +213,9 @@ enum AudioState : uint8_t { // Audio channel state #define BUFFERED_REVERSE 0x18 // Reverse the order of data in a buffer #define BUFFERED_COPY_REF 0x19 // Copy references to blocks from multiple buffers into one buffer #define BUFFERED_COPY_AND_CONSOLIDATE 0x1A // Copy blocks from multiple buffers into one buffer and consolidate them +#define BUFFERED_GET_DATA_BYTES 0x1B // Get data bytes and return them in a BDPP packet +#define BUFFERED_COMPRESS 0x1C // Compress blocks from multiple buffers into one buffer +#define BUFFERED_DECOMPRESS 0x1D // Decompress blocks from multiple buffers into one buffer #define BUFFERED_DEBUG_INFO 0x20 // Get debug info about a buffer diff --git a/video/bdpp/bdp_protocol.cpp b/video/bdpp/bdp_protocol.cpp new file mode 100644 index 00000000..e8d4346d --- /dev/null +++ b/video/bdpp/bdp_protocol.cpp @@ -0,0 +1,111 @@ +// +// Title: Agon Video BIOS +// Author: Dean Belfield +// Subtitle: Bidirectional Packet Protocol +// Author: Curtis Whitley +// Contributors: +// Created: 29/01/2024 +// Last Updated: 29/01/2024 +// + +#include "bdp_protocol.h" +#include +#include +#include +#include "soc/uhci_struct.h" +#include "soc/uart_struct.h" +#include "soc/uart_periph.h" +#include "driver/uart.h" +#include "uhci_driver.h" +#include "uhci_hal.h" + +#define UHCI_NUM UHCI_NUM_0 +#define UART_NUM UART_NUM_2 +#define DEBUG_BDPP 0 + +#if DEBUG_BDPP +extern void debug_log(const char* fmt, ...); +#endif + +bool bdpp_initialized; // Whether the driver has been initialized +std::queue bdpp_tx_queue; // Transmit (TX) packet queue +std::queue bdpp_rx_queue[BDPP_MAX_STREAMS]; // Receive (RX) packet queue + +//-------------------------------------------------- + +// Get whether the driver has been initialized. +bool bdpp_is_initialized() { + return bdpp_initialized; +} + +// Initialize the BDPP driver. +// +void bdpp_initialize_driver() { +#if DEBUG_BDPP + debug_log("Activating BDPP.\n"); +#endif + + Serial2.end(); // stop existing communication + + uart_config_t uart_config = { + .baud_rate = 1152000, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, + .rx_flow_ctrl_thresh = 64, + .source_clk = UART_SCLK_APB + }; + + uhci_driver_install(UHCI_NUM, 0); + uhci_attach_uart_port(UHCI_NUM, UART_NUM, &uart_config); + uart_dma_read(); + bdpp_initialized = true; +} + +// Queue a packet for transmission to the EZ80. +// The packet is expected to be full (to contain all data that +// VDP wants to place into it) when this function is called. +void bdpp_queue_tx_packet(Packet* packet) { + auto uhci_packet = packet->get_uhci_packet(); + auto act_size = packet->get_uhci_packet()->get_actual_data_size(); + +#if DEBUG_BDPP + { + debug_log("Queue TX pkt: %02hX %02hX %02hX (%hu):", + uhci_packet->get_flags(), + uhci_packet->indexes, + uhci_packet->act_size, act_size); + auto data = uhci_packet->get_data(); + for (uint16_t i = 0; i < act_size; i++) { + debug_log(" %02hX", data[i]); + } + debug_log("\n"); + } +#endif + auto old_int = uhci_disable_interrupts(); + bdpp_tx_queue.push(packet); + uhci_enable_interrupts(old_int); + uart_dma_start_transmitter(); +} + +// Check for a received packet being available. +bool bdpp_rx_packet_available(uint8_t stream_index) { + auto old_int = uhci_disable_interrupts(); + bool available = !bdpp_rx_queue[stream_index].empty(); + uhci_enable_interrupts(old_int); + return available; +} + +// Get a received packet. +UhciPacket* bdpp_get_rx_packet(uint8_t stream_index) { + UhciPacket* packet = NULL; + auto old_int = uhci_disable_interrupts(); + auto queue = &bdpp_rx_queue[stream_index]; + if (!queue->empty()) { + packet = queue->front(); + queue->pop(); + } + uhci_enable_interrupts(old_int); + return packet; +} diff --git a/video/bdpp/bdp_protocol.h b/video/bdpp/bdp_protocol.h new file mode 100644 index 00000000..299a4ffe --- /dev/null +++ b/video/bdpp/bdp_protocol.h @@ -0,0 +1,37 @@ +// +// Title: Agon Video BIOS +// Author: Dean Belfield +// Subtitle: Bidirectional Packet Protocol +// Author: Curtis Whitley +// Contributors: +// Created: 29/01/2024 +// Last Updated: 29/01/2024 +// + +#ifndef BDPP_PROTOCOL_H +#define BDPP_PROTOCOL_H + +#include "packet.h" + +typedef uint8_t bool_t; // To match what the EZ80 is using for this + +#define ESP32_COMM_PROTOCOL_VERSION 0x04 // Range is 0x04 to 0x0F, for future enhancements + +// Initialize the BDPP driver. +void bdpp_initialize_driver(); + +// Get whether the driver has been initialized. +bool bdpp_is_initialized(); + +// Queue a packet for transmission to the EZ80. +// The packet is expected to be full (to contain all data that +// VDP wants to place into it) when this function is called. +void bdpp_queue_tx_packet(Packet* packet); + +// Check for a received packet being available. +bool bdpp_rx_packet_available(uint8_t stream_index); + +// Get a received packet. +UhciPacket* bdpp_get_rx_packet(uint8_t stream_index); + +#endif // BDPP_PROTOCOL_H diff --git a/video/bdpp/bdp_stream.h b/video/bdpp/bdp_stream.h new file mode 100644 index 00000000..7a005954 --- /dev/null +++ b/video/bdpp/bdp_stream.h @@ -0,0 +1,200 @@ +// +// Title: Agon Video BIOS +// Author: Dean Belfield +// Subtitle: Bidirectional Packet Protocol +// Author: Curtis Whitley +// Contributors: +// Created: 13/02/2024 +// Last Updated: 13/02/2024 +// + +#pragma once +#include +#include "bdpp/bdp_protocol.h" + +#define DEBUG_BDPP 0 + +#if DEBUG_BDPP +extern void debug_log(const char* f, ...); +#endif + +// This class represents a stream of data coming from BDPP. +// +class BdppStream : public Stream { + public: + // Construct a stream + // + // This defaults to stream #0, and is intended for creating + // an array of streams. To set the proper stream index, use + // the set_stream_index() function, below. + // + BdppStream() { + packet_index = 0; + stream_index = 0; + rx_packet = NULL; + tx_packet = NULL; + data_index = 0; + } + + // Destroy the stream. + // + virtual ~BdppStream() { + if (rx_packet) { + delete rx_packet; + } + if (tx_packet) { + delete tx_packet; + } + } + + // Set the stream index for this stream. + // + void set_stream_index(uint8_t stream_index) { + this->stream_index = stream_index; + } + + +#if DEBUG_BDPP +void show_rx_packet(UhciPacket* packet) { + auto act_size = packet->get_actual_data_size(); + auto data = packet->get_data(); + debug_log("RX pkt: %02hX %02hX %02hX (%u): ", + packet->get_flags(), + packet->indexes, + packet->act_size, act_size); + for (uint16_t i = 0; i < act_size; i++) { + auto ch = data[i]; + if (ch == 0x20) { + debug_log("-"); + } else if (ch > 0x20 && ch < 0x7E) { + debug_log("%c", ch); + } else { + debug_log("[%02hX]", ch); + } + } + debug_log("\n"); +} +#endif + + // Check for available data + // + // Data is available if we have a current packet where + // not all data bytes have been consumed (we discard + // packets that have a zero actual data size). + // + // If there is no current packet, but we can pull one from + // the packet queue, and the packet has a non-zero size, + // then data is available. + // + virtual int available() { + while (true) { + if (rx_packet) { + return rx_packet->get_actual_data_size() - data_index; + } + if (bdpp_rx_packet_available(stream_index)) { + rx_packet = bdpp_get_rx_packet(stream_index); +#if DEBUG_BDPP + show_rx_packet(rx_packet); +#endif + auto act_size = rx_packet->get_actual_data_size(); + if (act_size) { + data_index = 0; + return act_size; + } + // ignore empty packet + rx_packet = NULL; + } else { + return 0; // no data available + } + } + } + + // Read data from the current packet, if any. + // + // After reading a data byte, if the current packet has no more + // data left in it, we delete that packet (trusting that the + // "available()" function will grab another one from the queue later). + // + virtual int read() { + if (available()) { + auto result = (int)(uint)(rx_packet->get_data()[data_index++]); + if (data_index >= rx_packet->get_actual_data_size()) { + rx_packet = NULL; + } + return result; + } else { + return -1; + } + } + + // Peek at available data, if any exists. + // + // This will return an available data byte, but will not remove + // that byte from the current packet. + // + virtual int peek() { + if (available()) { + return (int)(uint)(rx_packet->get_data()[data_index]); + } else { + return -1; + } + } + + // Write data to the stream. + // + // This builds an outgoing (TX) packet, and sends it when full. + // + virtual size_t write(uint8_t data_byte) { + if (!tx_packet) { + tx_packet = Packet::create_driver_tx_packet( + BDPP_PKT_FLAG_PRINT | BDPP_PKT_FLAG_MIDDLE, + packet_index++, stream_index); + if (packet_index >= BDPP_MAX_DRIVER_PACKETS) { + packet_index = 0; + } + } + tx_packet->get_uhci_packet()->append_data(data_byte); + if (tx_packet->is_full()) { + bdpp_queue_tx_packet(tx_packet); + tx_packet = NULL; + } + return 1; + } + + // Make available for writing. + // + virtual int availableForWrite() { + return true; + } + + // Flush the stream. + // + // This will flush any packet currently being built. + // + virtual void flush() { + if (tx_packet) { + bdpp_queue_tx_packet(tx_packet); + tx_packet = NULL; + } + } + + // Start an app-owned packet + // + // This will flush any existing TX packet, and start a new one, + // intended for a particular app-owned packet index at the EZ80. + // + Packet* start_app_response_packet(uint8_t packet_index) { + flush(); + tx_packet = Packet::create_app_tx_packet( + BDPP_PKT_FLAG_PRINT | BDPP_PKT_FLAG_FIRST | BDPP_PKT_FLAG_RESPONSE, + packet_index, stream_index); + return tx_packet; + } + + protected: + uint8_t packet_index; // index of an outgoing packet + uint8_t stream_index; // index of this string (0..BDPP_MAX_STREAMS-1) + uint16_t data_index; // index into data portion of current packet + UhciPacket* rx_packet; // current packet used to extract data + Packet* tx_packet; // current packet used to output data +}; diff --git a/video/bdpp/bdpp.bas b/video/bdpp/bdpp.bas new file mode 100644 index 00000000..2b811b2c --- /dev/null +++ b/video/bdpp/bdpp.bas @@ -0,0 +1,184 @@ +90 REM PRINT "Before: ": VDU &89,&8B: PRINT "." +95 REM VDU 23,0,&C3: REM switch buffer +100 REM VDU 23,&89,&70,&80,&60,&10,&EA,&15,&15,&11: REM BDPP_PACKET_START/END_MARKER +110 REM VDU 23,&8B,&63,&94,&E2,&81,&66,&18,&20,&18: REM BDPP_PACKET_ESCAPE +130 REM PRINT "After: ": VDU &89,&8B: PRINT "." +190 OSCLI "BDPP" +200 DIM code% 300 +201 DIM fcn% 1: PRINT "fcn%: ";~fcn% +202 DIM index% 1: PRINT "index%: ";~index% +203 DIM flags% 1: PRINT "flags%: ";~flags% +204 DIM size% 4: PRINT "size%: ";~size% +205 DIM count% 4: PRINT "count%: ";~count% +206 DIM data% 4: PRINT "data%: ";~data% +210 PROC_assemble_bdpp +220 ?fcn%=0: rc%=USR(bdppSig1%): PRINT "is_allowed -> ";rc% +230 ?fcn%=1: rc%=USR(bdppSig1%): PRINT "is_enabled -> ";rc% +250 PRINT "<>" +251 PRINT "Printing a 'Q' as one byte:"; +252 ?fcn%=&0D: ?data%=&51: CALL bdppSig4% +253 PRINT "" +254 PRINT "This needs ESC characters:"; +255 PRINT CHR$(&89);CHR$(&8B);"!" +300 DIM app_pkt% 1: PRINT "app_pkt%: ";~app_pkt% +310 ?app_pkt%=0: ?fcn%=5: ?index%=5: !data%=app_pkt%: !size%=1 +311 PRINT "fcn=";?fcn% +312 PRINT "index=";?index% +313 PRINT "data=";~!data% +314 PRINT "size=";~!size% +315 REM hdr%=&0BC5B8 +316 REM FOR pi%=0 TO 15 +317 REM FOR di%=0 TO 11 +318 REM PRINT " ";~?hdr%;: hdr%=hdr%+1 +319 REM NEXT di%: PRINT "": NEXT pi% +320 rc%=USR(bdppSig6%): PRINT "rx pkt setup -> ";rc% +322 ?fcn%=&F: CALL bdppSig3% +323 REM hdr%=&0BC5B8 +324 REM FOR pi%=0 TO 15 +325 REM FOR di%=0 TO 11 +326 REM PRINT " ";~?hdr%;: hdr%=hdr%+1 +327 REM NEXT di%: PRINT "": NEXT pi% +330 VDU 23,0,&A2,1,5,&61 +335 ?fcn%=&F: CALL bdppSig3% +340 ?index%=5: ?fcn%=7: rc%=USR(bdppSig2%) +350 IF rc%=0 GOTO 340 +360 PRINT "echo returned -> ";~?app_pkt% +365 ?fcn%=&F: CALL bdppSig3% +370 PRINT "need to release pkt" +375 ?fcn%=&F: CALL bdppSig3% +999 END + +49985 REM IX: Data address +49986 REM IY: Size of buffer or Count of bytes +49987 REM D: Data byte +49988 REM C: Packet Flags +49989 REM B: Packet Index(es) +49990 REM A: BDPP function code +50000 DEF PROC_assemble_bdpp +50001 REM -- bdppSig1% -- +50002 REM BDPP uses several styles of function calls: +50004 REM BOOL bdpp_is_allowed(); +50006 REM BOOL bdpp_is_enabled(); +50010 REM BOOL bdpp_disable(); +50012 P%=code%: bdppSig1%=P% +50014 [OPT 2 +50015 LD HL,fcn%: LD A,(HL) +50016 RST.LIL &20 +50017 LD L,A +50018 LD H,0 +50019 XOR A +50020 EXX +50021 XOR A +50022 LD L,0 +50023 LD H,0 +50024 LD C,A +50025 RET +50026 ] +50039 REM -- bdppSig2% -- +50040 REM BOOL bdpp_enable(BYTE stream); +50042 REM BOOL bdpp_is_tx_app_packet_done(BYTE index); +50044 REM BOOL bdpp_is_rx_app_packet_done(BYTE index); +50046 REM BYTE bdpp_get_rx_app_packet_flags(BYTE index); +50048 REM BOOL bdpp_stop_using_app_packet(BYTE index); +50050 bdppSig2%=P% +50051 [OPT 2 +50052 LD HL,index%: LD B,(HL) +50053 LD HL,fcn%: LD A,(HL) +50054 RST.LIL &20 +50055 LD L,A +50056 LD H,0 +50057 XOR A +50058 EXX +50059 XOR A +50060 LD L,0 +50061 LD H,0 +50062 LD C,A +50063 RET +50064 ] +50079 REM -- bdppSig3% -- +50080 REM void bdpp_flush_drv_tx_packet(); +50082 bdppSig3%=P% +50084 [OPT 2 +50085 LD HL,fcn%: LD A,(HL) +50086 RST.LIL &20 +50088 RET +50090 ] +50099 REM -- bdppSig4% -- +50100 REM void bdpp_write_byte_to_drv_tx_packet(BYTE data); +50101 REM void bdpp_write_drv_tx_byte_with_usage(BYTE data); +50102 bdppSig4%=P% +50104 [OPT 2 +50109 LD HL,fcn%: LD A,(HL) +50110 LD HL,data%: LD D,(HL) +50112 RST.LIL &20 +50114 RET +50116 ] +50119 REM -- bdppSig5% -- +50120 REM void bdpp_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count); +50122 REM void bdpp_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count); +50124 bdppSig5%=P% +50126 [OPT 2 +50128 LD HL,count%: DEFB &ED: DEFB &31 +50130 LD HL,fcn%: LD A,(HL) +50132 LD HL,data%: DEFB &ED: DEFB &37 +50138 RST.LIL &20 +50140 RET +50142 ] +50159 REM -- bdppSig6% -- +50160 REM BOOL bdpp_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size); +50161 bdppSig6%=P% +50162 [OPT 2 +50163 LD HL,size%: DEFB &ED: DEFB &31 +50164 LD HL,index%: LD B,(HL) +50165 LD HL,fcn%: LD A,(HL) +50166 LD HL,data%: DEFB &ED: DEFB &37 +50167 RST.LIL &20 +50168 LD L,A +50169 LD H,0 +50170 XOR A +50171 EXX +50172 XOR A +50173 LD L,0 +50174 LD H,0 +50175 LD C,A +50176 RET +50178 ] +50199 REM -- bdppSig7% -- +50200 REM BOOL bdpp_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size); +50201 bdppSig7%=P% +50202 [OPT 2 +50203 LD HL,size%: DEFB &ED: DEFB &31 +50204 LD HL,flags%: LD D,(HL) +50205 LD HL,index%: LD B,(HL) +50206 LD HL,fcn%: LD A,(HL) +50207 LD HL,data%: DEFB &ED: DEFB &37 +50208 RST.LIL &20 +50209 LD L,A +50210 LD H,0 +50211 XOR A +50212 EXX +50213 XOR A +50214 LD L,0 +50215 LD H,0 +50216 LD C,A +50217 RET +50218 ] +50219 REM -- bdppSig8% -- +50230 REM WORD bdpp_get_rx_app_packet_size(BYTE index); +50231 bdppSig8%=P% +50232 [OPT 2 +50234 LD HL,index%: LD B,(HL) +50236 LD HL,fcn%: LD A,(HL) +50238 RST.LIL &20 +50240 RET +50242 ] + +50244 PRINT "bdppSig1% ";~bdppSig1% +50246 PRINT "bdppSig2% ";~bdppSig2% +50248 PRINT "bdppSig3% ";~bdppSig3% +50250 PRINT "bdppSig4% ";~bdppSig4% +50252 PRINT "bdppSig5% ";~bdppSig5% +50254 PRINT "bdppSig6% ";~bdppSig6% +50256 PRINT "bdppSig7% ";~bdppSig7% +50258 PRINT "total code: ";P%-code% +50260 ENDPROC diff --git a/video/bdpp/bdpp.md b/video/bdpp/bdpp.md new file mode 100644 index 00000000..e6cf4784 --- /dev/null +++ b/video/bdpp/bdpp.md @@ -0,0 +1,732 @@ +# Bidirectional Packet Protocol (BDPP) + +The Agon, in all of its derivatives, runs by cooperation between its EZ80 CPU +and its ESP32 CPU. While the former runs the main application program, the +latter provides peripheral support for video, audio, keyboard, and mouse. + +The EZ80 (MOS) talks to the ESP32 (VDP) through a direct serial link, at 1152000 baud, +with the EZ80 using its UART0 peripheral, and the ESP32 using its UART2 peripheral. + +Traditionally, and still by default, the EZ80 performs serial input by handling +UART0 receiver interrupts, but does not use interrupts for data transmission. +The ESP32 uses the Arduino Serial2 driver, which implies using interrupts for +its receiver and its transmitter; however, it does not make use of hardware DMA. + +Regarding data content, the EZ80 sends a stream of VDU commands and printable +characters to the ESP32, with no special wrappers around those characters. Each +character output by statements such as VDU, PRINT, PLOT, RST &10, and RST &18 +is output directly to the UART0 transmitter holding register in a synchronous +manner. The application waits for each byte to be sent out before writing the +next data byte to that register. + +When the ESP32 sends data, such as keyboard key state changes, to the EZ80, it +sends small data packets, which are interpreted by MOS in the EZ80. MOS modifies +certain system variables according to the contents of those small packets. The +packets are limited to 16 bytes in size. + +Some small packets are sent by the ESP32 in response to specific requests. For +example, MOS may ask the VDP for the current cursor position on the screen. +The VDP will reply with a small packet containing that information, and again, MOS +stores the results into system variables, so that the EZ80 application can +read those variables to obtain the cursor position. + +The EZ80 application has no direct knowledge of the small packets, and no ability to +get data from the ESP32 in larger quantities. If, for instance, the application +wanted to read the screen buffer contents, it would have to do so by asking for +the color of each pixel, one-by-one. + +## Purpose of BDPP + +The bidirectional packet protocol (BDPP) is designed to change how the communication +between the EZ80 (MOS) and the ESP32 (VDP) works, in order to make it more flexible +and less taxing on the CPUs (i.e., to give the CPUs more time to do other things +than to handle the data transfers). BDPP involves these topics: + +* Bidirectional packet flow - This means data transfers in both directions can use potentially larger data packets than the Agon uses by default. +* Multiple stream support - With multiple stream processors (VDU command interpreters) on the ESP32 end, the application can work on multiple jobs on the EZ80 end, and intermingle +any corresponding data packets required for those jobs. For example, the application can +load a large image or set of images from a file (or files), and send those to VDP stream buffers, while updating a progress indicator on the screen. +* Automatic packet division - The output from statements such as VDU, PRINT, PLOT, +RST &10, and RST &18 can be divided into packets automatically, and transmitted to VDP +when the packets get full. Non-full packets can also be flushed (output) on purpose. +* Driver-owned packets - Automatic packet division is performed using driver-owned packets, which are managed by the BDPP driver, and can contain up to 32 bytes of _data_ +in each packet, not counting packet overhead. +* App-owned packets - The application can allocate memory space for large packets, and +tell the BDPP driver that it would like to transmit data from or receive data into +such packets. Each packet can contain up to 256 bytes of _data_. + +## Hardware versus Software + +In the EZ80, BDPP uses the UART0 hardware FIFOs, and related TX and RX interrupts, but the TX and RX packet state machines are managed by software in the interrupt handler. The EZ80 UART does not use DMA, so the CPU may be interrupted often, as bytes go out or come in. + +In the ESP32, BDPP uses the UART2 hardware in conjunction with the UHCI0 DMA controller. UHCI manages the UART FIFOs, and interrupts the CPU after an entire packet has come in or gone out. Thus, the TX and RX packet state machines are managed by hardware. That is why the packet structure described below is important. + +## Packet Structure + +Each BDPP packet has the following physical structure: + +Start Marker - 0x89, indicates the start of a new packet in the serial stream. + +Flags - a single byte with these bits: +``` +#define BDPP_PKT_FLAG_PRINT 0x00 // Indicates packet contains printable data +#define BDPP_PKT_FLAG_COMMAND 0x01 // Indicates packet contains a command or request + +#define BDPP_PKT_FLAG_RESPONSE 0x02 // Indicates packet contains a response + +#define BDPP_PKT_FLAG_FIRST 0x04 // Indicates packet is first part of a message +#define BDPP_PKT_FLAG_MIDDLE 0x00 // Indicates packet is middle part of a message +#define BDPP_PKT_FLAG_LAST 0x08 // Indicates packet is last part of a message + +#define BDPP_PKT_FLAG_ENHANCED 0x10 // Indicates packet is enhanced in some way + +#define BDPP_PKT_FLAG_DONE 0x20 // Indicates packet was transmitted or received + +#define BDPP_PKT_FLAG_FOR_RX 0x40 // Indicates packet is for reception, not transmission + +#define BDPP_PKT_FLAG_DRIVER_OWNED 0x00 // Indicates packet is owned by the driver +#define BDPP_PKT_FLAG_APP_OWNED 0x80 // Indicates packet is owned by the application +``` + +Indexes - a single byte with the packet index (0..15) in the lower nibble, and the stream index (0..15) in the upper nibble. + +Size - a single byte (1..255, or 0) designating the size (1..255, or 256) of the data portion of the packet. If the size byte is zero, it means the actual data size is 256. +Otherwise, the actual data size equals the given size. + +Data - contains whatever print data, VDU commands, bitmap data, keyboard data, mouse data, etc., are appropriate. + +End Marker - 0x89, indicates the end of the new packet in the serial stream. + +The applications on either end do not use or care about the markers. They are handled by BDPP. + +Because the bytes between the two markers _might_ equal the value of the markers (0x89), the packet protocol supports using escape sequences. The value 0x89 is encoded as 0x8B, 0x8A. To prevent misinterpreting a real value of 0x8B, that value is encoded as 0x8B, 0x8D. + +For example, the following packet information: + +Flags: 0C
+Indexes: 62
+Size: 05
+Data: 03 89 E4 8B C7
+ +Would be marked, encoded, and transferred as: + +89 0C 62 05 03 8B 8A E4 8B 8D C7 89 + +It would be decoded into: + +0C 62 05 03 89 E4 8B C7 + +In the EZ80, the software state machines in the interrupt handler take care of marking, encoding, and decoding, so the EZ80 application does not need to do so. In the ESP32, the UHCI hardware does this, and the ESP32 application is unaware of it. + +## Enabling BDPP + +On startup (reboot), neither MOS nor VDP are in BDPP (packet) mode. They communicate +using the existing (legacy) methods. MOS uses UART0 interrupts for receiving data +from the UART FIFO, but does not use interrupts for transmitting data. VDP uses the +Arduino Serial2 stream, which is interrupt-driven, but may interrupt the CPU often, +as characters arrive or depart. Also, the data transfers are in raw (unpacketed) +mode. For example, "VDU a, b" sends just 2 bytes (a and b). The a and b values are +not encapsulated within a packet. + +The firmware in both CPUs must support BDPP in order for BDPP mode to be allowed. This is determined during the startup handshake, where the version bytes +are shared between the CPUs. Just because BDPP is allowed, does not imply that it +is enabled, and on startup, it is disabled. + +If both firmwares support it, +BDPP may be enabled by executing the "bdpp" command in MOS, either at the MOS command prompt, or in the "autoexec.txt" file. +BDPP may be enabled at the BASIC command prompt via "*bdpp". +From within a BASIC program, BDPP may be enabled via the OSCLI statement, +with a parameter of "bdpp". + +NOTE: Once BDPP is enabled, it cannot be disabled, except by resetting (rebooting) the Agon. + +When the "bdpp" command is executed, MOS will send a VDU command (equivalent to +VDU 23,0,&A2,0) to VDP, telling VDP to switch into BDPP (packet) mode. MOS will then wait a short time before sending any other data to VDP, because once that switch is +made, all communication is in packet mode, not the default raw mode. + +## Driver-owned Packets + +Driver-owned packets are limited to 32 bytes of _data_, not including the packet +overhead bytes, or any special escape characters (inserted and removed by the drivers). +When MOS uses printf(), putch(), RST &10, or RST &18, or when BASIC uses PRINT, +VDU, PLOT, etc., or those RST calls, driver-owned packets are used automatically. Packet are obtained (from the free packet list), filled, queued for +transmission, transmitted, and returned to the free packet list. + +Since packet data are buffered in driver-owned packets, the packets are not queued for transmission +until they are filled or flushed. MOS has various points in its code where it flushes +packets, in case data bytes are waiting to go out, but have not yet been sent. When +BDPP is disabled, the above functions and commands send data bytes to VDP immediately, +or at least relatively soon. When BDPP is enabled, data bytes are buffered, and at some +point, need to be flushed. For those cases where neither MOS nor BASIC (nor any other language for apps) knows what the programmer intends, and thus do not know when to flush, BDPP publicizes its flush functions, so that an app can flush intentionally. + +## Application-owned Packets + +Application-owned packets differ from driver-owned packets in two primary ways. +First, they are managed by the application, not by the driver. Second, they can contain +up to 256 data bytes, as opposed to just 32 data bytes. + +The application is responsible for allocating, and possibly deallocating, memory for app-owned packets. The app tells BDPP what to do with the app-owned packets, because +the app is in charge; the driver is not. + +Typically, app-owned packets will be used to receive response data from VDP. It is +essential for each VDU request command that will respond with data to include a +packet index (0..15) in the request parameters, so that VDU will know which packet +index to provide in the response. + +## BDPP Functions in MOS + +The following functions are compiled into the MOS source code, +and are available within MOS by direct function calls. Most +are available outside of MOS via the BDPP API, by using RST &20. +Many of the "foreground" +functions are called automatically when using driver-owned +packets via calls to printf(), putch(), RST &10, or RST &18. + +### *** OVERALL MANAGEMENT FROM FOREGROUND *** +NOTE: These functions will disable and enable interrupts as needed in order +to protect certain global variables managed by BDPP. Do not call any of +these functions with interrupts turned OFF! +``` +// Initialize the BDPP driver. +void bdpp_fg_initialize_driver(); + +// Get whether BDPP is allowed (both CPUs have it) +// [BDPP API function code 0x00, signature 1] +BOOL bdpp_fg_is_allowed(); + +// Get whether BDPP is presently enabled +// [BDPP API function code 0x01, signature 1] +BOOL bdpp_fg_is_enabled(); + +// Get whether BDPP is presently busy (TX or RX) +// [BDPP API function code 0x10, signature 1] +BOOL bdpp_fg_is_busy(); + +// Enable BDDP mode for a specific stream +// [BDPP API function code 0x02, signature 2] +BOOL bdpp_fg_enable(BYTE stream); + +// Disable BDDP mode +// [BDPP API function code 0x03, signature 1] +BOOL bdpp_fg_disable(); +``` + +### *** PACKET RECEPTION (RX) FROM FOREGROUND (MAIN THREAD) *** +NOTE: These functions will disable and enable interrupts as needed in order +to protect certain global variables managed by BDPP. Do not call any of +these functions with interrupts turned OFF! +``` +// Prepare an app-owned packet for reception +// This function can fail if the packet is presently involved in a data transfer. +// The given size is a maximum, based on app memory allocation, and the +// actual size of an incoming packet may be smaller, but not larger. +// [BDPP API function code 0x05, signature 6] +BOOL bdpp_fg_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size); + +// Check whether an incoming app-owned packet has been received +// [BDPP API function code 0x07, signature 2] +BOOL bdpp_fg_is_rx_app_packet_done(BYTE index); + +// Get the flags for a received app-owned packet. +// [BDPP API function code 0x08, signature 2] +BYTE bdpp_fg_get_rx_app_packet_flags(BYTE index); + +// Get the data size for a received app-owned packet. +// [BDPP API function code 0x09, signature 8] +WORD bdpp_fg_get_rx_app_packet_size(BYTE index); +``` + +### *** PACKET TRANSMISSION (TX) FROM FOREGROUND (MAIN THREAD) *** +NOTE: These functions will disable and enable interrupts as needed in order +to protect certain global variables managed by BDPP. Do not call any of +these functions with interrupts turned OFF! +``` +// Initialize an outgoing driver-owned packet, if one is available +// Returns NULL if no packet is available +volatile BDPP_PACKET* bdpp_fg_init_tx_drv_packet(BYTE flags, BYTE stream); + +// Queue an app-owned packet for transmission +// The packet is expected to be full when this function is called. +// This function can fail if the packet is presently involved in a data transfer. +// [BDPP API function code 0x04, signature 7] +BOOL bdpp_fg_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size); + +// Check whether an outgoing app-owned packet has been transmitted +// [BDPP API function code 0x06, signature 2] +BOOL bdpp_fg_is_tx_app_packet_done(BYTE index); + +// Free the driver from using an app-owned packet +// This function can fail if the packet is presently involved in a data transfer. +// [BDPP API function code 0x0A, signature 2] +BOOL bdpp_fg_stop_using_app_packet(BYTE index); + +// Start building a driver-owned, outgoing packet. +// If there is an existing packet being built, it will be flushed first. +// This returns NULL if there is no packet available. +volatile BDPP_PACKET* bdpp_fg_start_drv_tx_packet(BYTE flags, BYTE stream); + +// Append a data byte to a driver-owned, outgoing packet. +// This is a blocking call, and might wait for room for data. +// [BDPP API function code 0x0B, signature 4] +void bdpp_fg_write_byte_to_drv_tx_packet(BYTE data); + +// Append multiple data bytes to one or more driver-owned, outgoing packets. +// This is a blocking call, and might wait for room for data. +// [BDPP API function code 0x0C, signature 5] +void bdpp_fg_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count); + +// Append a single data byte to a driver-owned, outgoing packet. +// This is a potentially blocking call, and might wait for room for data. +// If necessary this function initializes and uses a new packet. It +// decides whether to use "print" data (versus "non-print" data) based on +// the value of the data. To guarantee that the packet usage flags are +// set correctly, be sure to flush the packet before switching from "print" +// to "non-print", or vice versa. +// [BDPP API function code 0x0D, signature 4] +void bdpp_fg_write_drv_tx_byte_with_usage(BYTE data); + +// Append multiple data bytes to one or more driver-owned, outgoing packets. +// This is a potentially blocking call, and might wait for room for data. +// If necessary this function initializes and uses additional packets. It +// decides whether to use "print" data (versus "non-print" data) based on +// the first byte in the data. To guarantee that the packet usage flags are +// set correctly, be sure to flush the packet before switching from "print" +// to "non-print", or vice versa. +// [BDPP API function code 0x0E, signature 5] +void bdpp_fg_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count); + +// Flush the currently-being-built, driver-owned, outgoing packet, if any exists. +// [BDPP API function code 0x0F, signature 3] +void bdpp_fg_flush_drv_tx_packet(); +``` + +### *** OVERALL MANAGEMENT FROM BACKGROUND *** +NOTE: These functions expect interrupts to be turned off already, +and may modify certain global variables managed by BDPP. Do not call +any of these functions with interrupts turned ON! +``` +// Get whether BDPP is presently busy (TX or RX) +// [BDPP API function code 0x1D, signature 1] +BOOL bdpp_bg_is_busy(); +``` + +### *** PACKET RECEPTION (RX) FROM BACKGROUND (ISR) *** +NOTE: These functions expect interrupts to be turned off already, +and may modify certain global variables managed by BDPP. Do not call +any of these functions with interrupts turned ON! +``` +// Initialize an incoming driver-owned packet, if one is available +// Returns NULL if no packet is available +volatile BDPP_PACKET* bdpp_bg_init_rx_drv_packet(); + +// Prepare an app-owned packet for reception +// This function can fail if the packet is presently involved in a data transfer. +// The given size is a maximum, based on app memory allocation, and the +// actual size of an incoming packet may be smaller, but not larger. +// [BDPP API function code 0x12, signature 6] +BOOL bdpp_bg_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size); + +// Check whether an incoming app-owned packet has been received +// [BDPP API function code 0x14, signature 2] +BOOL bdpp_bg_is_rx_app_packet_done(BYTE index); + +// Get the flags for a received app-owned packet. +// [BDPP API function code 0x15, signature 2] +BYTE bdpp_bg_get_rx_app_packet_flags(BYTE index); + +// Get the data size for a received app-owned packet. +// [BDPP API function code 0x16, signature 8] +WORD bdpp_bg_get_rx_app_packet_size(BYTE index); +``` + +### *** PACKET TRANSMISSION (TX) FROM BACKGROUND (ISR) *** +NOTE: These functions expect interrupts to be turned off already, +and may modify certain global variables managed by BDPP. Do not call +any of these functions with interrupts turned ON! +``` +// Initialize an outgoing driver-owned packet, if one is available +// Returns NULL if no packet is available +volatile BDPP_PACKET* bdpp_bg_init_tx_drv_packet(BYTE flags, BYTE stream); + +// Queue an app-owned packet for transmission +// The packet is expected to be full when this function is called. +// This function can fail if the packet is presently involved in a data transfer. +// [BDPP API function code 0x11, signature 7] +BOOL bdpp_bg_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size); + +// Check whether an outgoing app-owned packet has been transmitted +// [BDPP API function code 0x13, signature 2] +BOOL bdpp_bg_is_tx_app_packet_done(BYTE index); + +// Free the driver from using an app-owned packet +// This function can fail if the packet is presently involved in a data transfer. +// [BDPP API function code 0x17, signature 2] +BOOL bdpp_bg_stop_using_app_packet(BYTE index); + +// Start building a driver-owned, outgoing packet. +// If there is an existing packet being built, it will be flushed first. +// This returns NULL if there is no packet available. +volatile BDPP_PACKET* bdpp_bg_start_drv_tx_packet(BYTE flags, BYTE stream); + +// Append a data byte to a driver-owned, outgoing packet. +// This is a blocking call, and might wait for room for data. +// [BDPP API function code 0x18, signature 4] +void bdpp_bg_write_byte_to_drv_tx_packet(BYTE data); + +// Append multiple data bytes to one or more driver-owned, outgoing packets. +// This is a blocking call, and might wait for room for data. +// [BDPP API function code 0x19, signature 5] +void bdpp_bg_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count); + +// Append a single data byte to a driver-owned, outgoing packet. +// This is a potentially blocking call, and might wait for room for data. +// If necessary this function initializes and uses a new packet. It +// decides whether to use "print" data (versus "non-print" data) based on +// the value of the data. To guarantee that the packet usage flags are +// set correctly, be sure to flush the packet before switching from "print" +// to "non-print", or vice versa. +// [BDPP API function code 0x1A, signature 4] +void bdpp_bg_write_drv_tx_byte_with_usage(BYTE data); + +// Append multiple data bytes to one or more driver-owned, outgoing packets. +// This is a potentially blocking call, and might wait for room for data. +// If necessary this function initializes and uses additional packets. It +// decides whether to use "print" data (versus "non-print" data) based on +// the first byte in the data. To guarantee that the packet usage flags are +// set correctly, be sure to flush the packet before switching from "print" +// to "non-print", or vice versa. +// [BDPP API function code 0x1B, signature 5] +void bdpp_bg_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count); + +// Flush the currently-being-built, driver-owned, outgoing packet, if any exists. +// [BDPP API function code 0x1C, signature 3] +void bdpp_bg_flush_drv_tx_packet(); +``` + +## BDPP API in MOS + +On the EZ80, most BDPP functions may be accessed via the BDPP API, using RST &20. +The function codes for the available functions are listed in the comments above. +Functions are grouped by their type signatures, making it possible to reuse +assembler code, order to call functions with similar type signatures. + +The RST &20 interfaces to various BDPP API functions use some or all of the following EZ80 +registers as inputs and/or outputs. +In other words, set the appropriate input registers before using the RST &20 instruction, and check the proper output register, if any, after using RST. The "BOOL" +and "BYTE" types (seen above) are both 8 bits in size, so some functions that return +"BOOL" use the same type signature as similar functions that return "BYTE". + +Inputs:
+IX: Data address
+IY: Size of buffer or Count of bytes
+D: Data byte
+C: Packet Flags
+B: Packet/Stream Index(es)
+A: BDPP function code
+ +Outputs:
+C: BOOL indicator
+BC: WORD size
+ +The following sections detail each type signature, and provide sample RST calls in +BASIC-24 format, but without the line numbers. Also shown are some common definitions +that are used throughout the examples. It is assumed that this code runs in EZ80 ADL +(24-bit registers) mode. + +### Common definitions + +This code reserves space for parameter variables that can be set as needed in +the BASIC app, and will be read in the assembler code further below, to setup +paramer registers for the RST calls. You can omit the PRINT statements, +if you do not want theetir output on the screen. The procedure call to assemble +the code for the various type signatures is required. +```` +DIM code% 200 +DIM fcn% 1: PRINT "fcn%: ";~fcn% +DIM index% 1: PRINT "index%: ";~index% +DIM flags% 1: PRINT "flags%: ";~flags% +DIM size% 4: PRINT "size%: ";~size% +DIM count% 4: PRINT "count%: ";~count% +DIM data% 4: PRINT "data%: ";~data% +PROC_assemble_bdpp +```` + +### Function type signature 1 +BOOL bdpp_fg_is_allowed();
+BOOL bdpp_fg_is_enabled();
+BOOL bdpp_fg_is_busy();
+BOOL bdpp_fg_disable();
+BOOL bdpp_bg_is_busy();
+ +This (type signature 1) is the first section of a single BASIC procedure that +assembles code for all of the type signatures. Further below, +you will see the end of this procedure (in type signature 8). + +``` +DEF PROC_assemble_bdpp +P%=code%: bdppSig1%=P% +[OPT 2 +LD HL,fcn%: LD A,(HL) +RST.LIL &20 +LD L,A +LD H,0 +XOR A +EXX +XOR A +LD L,0 +LD H,0 +LD C,A +RET +] +``` + +### Function type signature 2 +BOOL bdpp_fg_enable(BYTE stream);
+BOOL bdpp_fg_is_rx_app_packet_done(BYTE index);
+BYTE bdpp_fg_get_rx_app_packet_flags(BYTE index);
+BOOL bdpp_fg_is_tx_app_packet_done(BYTE index);
+BOOL bdpp_fg_stop_using_app_packet(BYTE index);
+BOOL bdpp_bg_is_rx_app_packet_done(BYTE index);
+BYTE bdpp_bg_get_rx_app_packet_flags(BYTE index);
+BOOL bdpp_bg_is_tx_app_packet_done(BYTE index);
+BOOL bdpp_bg_stop_using_app_packet(BYTE index);
+``` +bdppSig2%=P% +[OPT 2 +LD HL,index%: LD B,(HL) +LD HL,fcn%: LD A,(HL) +RST.LIL &20 +LD L,A +LD H,0 +XOR A +EXX +XOR A +LD L,0 +LD H,0 +LD C,A +RET +] +``` + +### Function type signature 3 +void bdpp_fg_flush_drv_tx_packet();
+void bdpp_bg_flush_drv_tx_packet();
+``` +bdppSig3%=P% +[OPT 2 +LD HL,fcn%: LD A,(HL) +RST.LIL &20 +RET +] +``` + +### Function type signature 4 +void bdpp_fg_write_byte_to_drv_tx_packet(BYTE data);
+void bdpp_fg_write_drv_tx_byte_with_usage(BYTE data);
+void bdpp_bg_write_byte_to_drv_tx_packet(BYTE data);
+void bdpp_bg_write_drv_tx_byte_with_usage(BYTE data);
+``` +bdppSig4%=P% +[OPT 2 +LD HL,fcn%: LD A,(HL) +LD HL,data%: LD D,(HL) +RST.LIL &20 +RET +] +``` + +### Function type signature 5 +void bdpp_fg_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count);
+void bdpp_fg_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count);
+void bdpp_bg_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count);
+void bdpp_bg_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count);
+``` +bdppSig5%=P% +[OPT 2 +LD HL,count%: DEFB &ED: DEFB &31 +LD HL,fcn%: LD A,(HL) +LD HL,data%: DEFB &ED: DEFB &37 +RST.LIL &20 +RET +] +``` + +### Function type signature 6 +BOOL bdpp_fg_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size);
+BOOL bdpp_bg_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size);
+``` +bdppSig6%=P% +[OPT 2 +LD HL,size%: DEFB &ED: DEFB &31 +LD HL,index%: LD B,(HL) +LD HL,fcn%: LD A,(HL) +LD HL,data%: DEFB &ED: DEFB &37 +RST.LIL &20 +LD L,A +LD H,0 +XOR A +EXX +XOR A +LD L,0 +LD H,0 +LD C,A +RET +] +``` + +### Function type signature 7 +BOOL bdpp_fg_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size);
+BOOL bdpp_bg_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size);
+``` +bdppSig7%=P% +[OPT 2 +LD HL,size%: DEFB &ED: DEFB &31 +LD HL,flags%: LD D,(HL) +LD HL,index%: LD B,(HL) +LD HL,fcn%: LD A,(HL) +LD HL,data%: DEFB &ED: DEFB &37 +RST.LIL &20 +LD L,A +LD H,0 +XOR A +EXX +XOR A +LD L,0 +LD H,0 +LD C,A +RET +] +``` + +### Function type signature 8 +WORD bdpp_fg_get_rx_app_packet_size(BYTE index);
+WORD bdpp_bg_get_rx_app_packet_size(BYTE index);
+``` +bdppSig8%=P% +[OPT 2 +LD HL,index%: LD B,(HL) +LD HL,fcn%: LD A,(HL) +RST.LIL &20 +RET +] +ENDPROC +``` + +## Sample BDPP Function calls in BASIC-24 + +These samples are shown without line numbers. For most of these calls, BDPP +must be both allowed (both CPUs support it), and enabled. + +Print whether BDPP is allowed, and whether it is enabled. If BDPP is enabled, +the data sent to VDP will be enclosed in packets. If BDPP is disabled, the +data will not be enclosed in packets. Notice that this code does not set the +value of "fcn%"; it sets a memory byte at the location pointed to by +the address contained in "fcn%"! +``` +?fcn%=0: rc%=USR(bdppSig1%): PRINT "is_allowed -> ";rc% +?fcn%=1: rc%=USR(bdppSig1%): PRINT "is_enabled -> ";rc% +``` +Assuming that BDPP is enabled, this example shows a mixture of PRINT statements +with a call to buffer a single byte in the current driver-owned packet. +Notice that this code does not set the +value of "data%"; it sets a memory byte at the location pointed to by +the address contained in "data%"! That is typical of the input parameters +for the RST calls, used in BASIC, as detailed in this document. +``` +PRINT "<>" +PRINT "Printing a 'Q' as one byte:"; +?fcn%=&0D: ?data%=&51: CALL bdppSig4% +PRINT "" +PRINT "This needs ESC characters:"; +PRINT CHR$(&89);CHR$(&8B);"!" +``` + +This code prints some text, then flushes any remaining data, to make sure +that it gets displayed. +``` +PRINT "some goofy text here" +?fcn%=&F: CALL bdppSig3% +``` + +This code allocates RAM for an app-owned packet, makes an "echo" request to VDP, +waits for the response packet, and displays the resulting "echo data". Line +numbers are shown, because of illustrating the loop (via GOTO), but some other +loop structure could have been used. +``` +300 DIM app_pkt% 1: PRINT "app_pkt%: ";~app_pkt% +310 ?app_pkt%=0: ?fcn%=5: ?index%=5: !data%=app_pkt%: !size%=1 +320 rc%=USR(bdppSig6%): PRINT "rx pkt setup -> ";rc% +322 ?fcn%=&F: CALL bdppSig3% +330 VDU 23,0,&A2,1,5,&61 +335 ?fcn%=&F: CALL bdppSig3% +340 ?index%=5: ?fcn%=7: rc%=USR(bdppSig2%) +350 IF rc%=0 GOTO 340 +360 PRINT "echo returned -> ";~?app_pkt% +365 ?fcn%=&F: CALL bdppSig3% +``` +## BDPP VDU Commands + +The following VDU commands are handled by the BDPP section of the system command handler in the ESP32 stream processor. +Except the first way (command code 0), these commands all return data via app-owned packets, and thus take a packet index +as one of the command parameters. The EZ80 app must have setup an RX buffer with the same packet index before invoking +one of these commands. + +### VDU 23, 0, &A2, 0 - enable BDPP by initializing its driver + +This command is automatically invoked when the MOS "bdpp" command is executed. Do not invoke this VDU command independently, +because it only affects the VDP and not MOS itself, and will cause the two CPUs to stop communicating properly. + +### VDU 23, 0, &A2, 1, pkt_idx, echo_data - echo a single byte back to the EZ80 + +This command takes a single data byte as input and echos it back as output. + +### VDU 23, 0, &A2, 2, pkt_idx, n, caps0; caps1; ... - get amount of free ESP32 RAM with given capabilties + +This command inputs one or more sets of ESP32 memory capabilities flags, and determines the amount +of free memory, based on those flags. It returns a list of 32-bit values with the resulting free memory sizes. Within each flags set (e.g., 'caps0' parameter), flags may be ORed to indicate +more than one capability. Here is the list of flags from 'esp_heap_caps.h': + +``` +#define MALLOC_CAP_EXEC (1<<0) ///< Memory must be able to run executable code +#define MALLOC_CAP_32BIT (1<<1) ///< Memory must allow for aligned 32-bit data accesses +#define MALLOC_CAP_8BIT (1<<2) ///< Memory must allow for 8/16/...-bit data accesses +#define MALLOC_CAP_DMA (1<<3) ///< Memory must be able to accessed by DMA +#define MALLOC_CAP_PID2 (1<<4) ///< Memory must be mapped to PID2 memory space (PIDs are not currently used) +#define MALLOC_CAP_PID3 (1<<5) ///< Memory must be mapped to PID3 memory space (PIDs are not currently used) +#define MALLOC_CAP_PID4 (1<<6) ///< Memory must be mapped to PID4 memory space (PIDs are not currently used) +#define MALLOC_CAP_PID5 (1<<7) ///< Memory must be mapped to PID5 memory space (PIDs are not currently used) +#define MALLOC_CAP_PID6 (1<<8) ///< Memory must be mapped to PID6 memory space (PIDs are not currently used) +#define MALLOC_CAP_PID7 (1<<9) ///< Memory must be mapped to PID7 memory space (PIDs are not currently used) +#define MALLOC_CAP_SPIRAM (1<<10) ///< Memory must be in SPI RAM +#define MALLOC_CAP_INTERNAL (1<<11) ///< Memory must be internal; specifically it should not disappear when flash/spiram cache is switched off +#define MALLOC_CAP_DEFAULT (1<<12) ///< Memory can be returned in a non-capability-specific memory allocation (e.g. malloc(), calloc()) call +#define MALLOC_CAP_IRAM_8BIT (1<<13) ///< Memory must be in IRAM and allow unaligned access +#define MALLOC_CAP_RETENTION (1<<14) ///< Memory must be able to accessed by retention DMA +#define MALLOC_CAP_RTCRAM (1<<15) ///< Memory must be in RTC fast memory +``` + +### VDU 23, 0, &A2, 3, pkt_idx, addr_lo; addr_hi; n; - get ESP32 RAM contents as bytes (8 bits each) + +This command copies data from the ESP32 memory, starting at the given 32-bit address, copying 1 data byte at a time +into the output packet. The total number of bytes returned equals the value of n. + +### VDU 23, 0, &A2, 4, pkt_idx, addr_lo; addr_hi; n; - get ESP32 RAM contents as words (16 bits each) + +This command copies data from the ESP32 memory, starting at the given 32-bit address, copying 2 data bytes at a time +into the output packet. The total number of bytes returned equals the value of n times 2. + +### VDU 23, 0, &A2, 5, pkt_idx, addr_lo; addr_hi; n; - get ESP32 RAM contents as dwords (32 bits each) + +This command copies data from the ESP32 memory, starting at the given 32-bit address, copying 4 data bytes at a time +into the output packet. The total number of bytes returned equals the value of n times 4. + +### VDU 23, 0, &A2, 6, pkt_idx - get VDP version information + +This command returns the following VDP version information: + +* Major number (1 byte) +* Minor number (1 byte) +* Patch number (1 byte) +* Candidate number (1 byte) +* Type (null-terminated text string) +* Variant (null-terminated text string) diff --git a/video/bdpp/grabbuffer.bas b/video/bdpp/grabbuffer.bas new file mode 100644 index 00000000..0dd1a5f8 --- /dev/null +++ b/video/bdpp/grabbuffer.bas @@ -0,0 +1,221 @@ +10 REM This program writes colored text onto the screen, +20 REM reads it using BDPP, and writes it back onto the screen. +30 REM It illustrates the use of BDPP, but does not use buffers +40 REM or packets in the most efficient manner. +100 MODE 3 +140 DATA "*----------------------------------------------------------------------*" +150 DATA "| GRABBUFFER.BAS - Sample app shows using BDPP to grab VDP buffer data |" +160 DATA "| This program does the following things: |" +170 DATA "| (1) Write text on the screen in various colors |" +180 DATA "| (2) Capture a portion of the screen into a buffer on the ESP32 |" +190 DATA "| (3) Setup BDPP RX packets on the EZ80 |" +200 DATA "| (4) Tell the ESP32 to transmit the buffer contents to the EZ80 |" +210 DATA "| (5) Draw the captured image upside-down at the bottom of the screen |" +215 DATA "*----------------------------------------------------------------------*" +220 DATA "" +300 READ T$: IF T$="" GOTO 350 +310 L%=LEN(T$) +320 FOR I%=1 TO L% +330 COLOUR RND(63): PRINT MID$(T$,I%,1); +340 NEXT I%: PRINT "": GOTO 300 +350 VDU 23,0,&C0,0: REM Use normal (not logical) coordinates +360 OSCLI "BDPP": REM Turn on BDPP + +390 REM Assemble the interfaces to the BDPP API +400 DIM code% 200 +401 DIM fcn% 1 +402 DIM index% 1 +403 DIM flags% 1 +404 DIM size% 4 +405 DIM count% 4 +406 DIM data% 4 +407 packet_size%=256 +410 PROC_assemble_bdpp + +510 REM Create a local RX packet buffer for a scan line (576 bytes) +520 DIM buffer% 576 + +590 REM Capture upper portion of screen (the colored text) +600 capWidth%=72*8: capHeight%=9*8: bufferId%=64001: lineBufferId%=64002 +610 MOVE 0,0: MOVE capWidth%-1,capHeight%-1 +620 VDU 23,27,1,bufferId%,0,0; +630 ?fcn%=&F: CALL bdppSig3% + +700 offsetHi%=0: offsetLo%=0 +710 FOR i%=0 TO capHeight%-1 +715 PRINT "(";i%;")";: ?fcn%=&F: CALL bdppSig3% + +731 REM Request 3 sections of the captured pixels +732 ?fcn%=5: ?index%=0: !data%=buffer%: !size%=256 +733 rc%=USR(bdppSig6%) +734 ?fcn%=5: ?index%=1: !data%=buffer%+256: !size%=256 +735 rc%=USR(bdppSig6%) +736 ?fcn%=5: ?index%=2: !data%=buffer%+512: !size%=64 +737 rc%=USR(bdppSig6%) + +740 VDU 23,0,&A0,bufferId%;&1B,0,offsetLo%;offsetHi%;256; +742 VDU 23,0,&A0,bufferId%;&1B,1,offsetLo%+256;offsetHi%;256; +744 VDU 23,0,&A0,bufferId%;&1B,2,offsetLo%+512;offsetHi%;64; +750 ?fcn%=&F: CALL bdppSig3% + +760 offsetLo%=offsetLo%+capWidth% + +770 REM Wait for the response packets with pixel data +772 ?index%=0: ?fcn%=7 +774 rc%=USR(bdppSig2%): IF rc%=0 GOTO 774 +776 ?index%=1: ?fcn%=7 +778 rc%=USR(bdppSig2%): IF rc%=0 GOTO 778 +780 ?index%=2: ?fcn%=7 +782 rc%=USR(bdppSig2%): IF rc%=0 GOTO 782 + +793 REM PRINT "<";?buffer%;">": END + +795 REM Write the pixels to a single line buffer +800 VDU 23,0,&A0,lineBufferId%;0,capWidth%; + +802 address%=buffer% +804 FOR B%=1 TO capWidth% +806 VDU ?address%: address%=address%+1 +808 NEXT B% +810 ?fcn%=&F: CALL bdppSig3% + +871 REM address%=buffer%: PRINT i%;": "; +872 REM FOR B%=0 TO 15 +873 REM PRINT STR$(?address%);" ";: address%=address%+1 +874 REM NEXT B% +875 REM PRINT "" +876 REM ?fcn%=&F: CALL bdppSig3% + +900 VDU 23,27,&20,lineBufferId%;: REM Select bitmap (using a buffer ID) +910 VDU 23,27,&21,capWidth%;1;1: REM Create bitmap from buffer +920 VDU 25,&ED,0;(230-i%);: REM Show the bitmap on the screen line +930 lineBufferId%=lineBufferId%+1 +960 NEXT i% + +999 END + +49985 REM IX: Data address +49986 REM IY: Size of buffer or Count of bytes +49987 REM D: Data byte +49988 REM C: Packet Flags +49989 REM B: Packet Index(es) +49990 REM A: BDPP function code +50000 DEF PROC_assemble_bdpp +50001 REM -- bdppSig1% -- +50002 REM BDPP uses several styles of function calls: +50004 REM BOOL bdpp_is_allowed(); +50006 REM BOOL bdpp_is_enabled(); +50010 REM BOOL bdpp_disable(); +50012 P%=code%: bdppSig1%=P% +50014 [OPT 2 +50015 LD HL,fcn%: LD A,(HL) +50016 RST.LIL &20 +50017 LD L,A +50018 LD H,0 +50019 XOR A +50020 EXX +50021 XOR A +50022 LD L,0 +50023 LD H,0 +50024 LD C,A +50025 RET +50026 ] +50039 REM -- bdppSig2% -- +50040 REM BOOL bdpp_enable(BYTE stream); +50042 REM BOOL bdpp_is_tx_app_packet_done(BYTE index); +50044 REM BOOL bdpp_is_rx_app_packet_done(BYTE index); +50046 REM BYTE bdpp_get_rx_app_packet_flags(BYTE index); +50048 REM BOOL bdpp_stop_using_app_packet(BYTE index); +50050 bdppSig2%=P% +50051 [OPT 2 +50052 LD HL,index%: LD B,(HL) +50053 LD HL,fcn%: LD A,(HL) +50054 RST.LIL &20 +50055 LD L,A +50056 LD H,0 +50057 XOR A +50058 EXX +50059 XOR A +50060 LD L,0 +50061 LD H,0 +50062 LD C,A +50063 RET +50064 ] +50079 REM -- bdppSig3% -- +50080 REM void bdpp_flush_drv_tx_packet(); +50082 bdppSig3%=P% +50084 [OPT 2 +50085 LD HL,fcn%: LD A,(HL) +50086 RST.LIL &20 +50088 RET +50090 ] +50099 REM -- bdppSig4% -- +50100 REM void bdpp_write_byte_to_drv_tx_packet(BYTE data); +50101 REM void bdpp_write_drv_tx_byte_with_usage(BYTE data); +50102 bdppSig4%=P% +50104 [OPT 2 +50109 LD HL,fcn%: LD A,(HL) +50110 LD HL,data%: LD D,(HL) +50112 RST.LIL &20 +50114 RET +50116 ] +50119 REM -- bdppSig5% -- +50120 REM void bdpp_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count); +50122 REM void bdpp_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count); +50124 bdppSig5%=P% +50126 [OPT 2 +50128 LD HL,count%: DEFB &ED: DEFB &31 +50130 LD HL,fcn%: LD A,(HL) +50132 LD HL,data%: DEFB &ED: DEFB &37 +50138 RST.LIL &20 +50140 RET +50142 ] +50159 REM -- bdppSig6% -- +50160 REM BOOL bdpp_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size); +50161 bdppSig6%=P% +50162 [OPT 2 +50163 LD HL,size%: DEFB &ED: DEFB &31 +50164 LD HL,index%: LD B,(HL) +50165 LD HL,fcn%: LD A,(HL) +50166 LD HL,data%: DEFB &ED: DEFB &37 +50167 RST.LIL &20 +50168 LD L,A +50169 LD H,0 +50170 XOR A +50171 EXX +50172 XOR A +50173 LD L,0 +50174 LD H,0 +50175 LD C,A +50176 RET +50178 ] +50199 REM -- bdppSig7% -- +50200 REM BOOL bdpp_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size); +50201 bdppSig7%=P% +50202 [OPT 2 +50203 LD HL,size%: DEFB &ED: DEFB &31 +50204 LD HL,flags%: LD D,(HL) +50205 LD HL,index%: LD B,(HL) +50206 LD HL,fcn%: LD A,(HL) +50207 LD HL,data%: DEFB &ED: DEFB &37 +50208 RST.LIL &20 +50209 LD L,A +50210 LD H,0 +50211 XOR A +50212 EXX +50213 XOR A +50214 LD L,0 +50215 LD H,0 +50216 LD C,A +50217 RET +50218 ] +50219 REM -- bdppSig8% -- +50230 REM WORD bdpp_get_rx_app_packet_size(BYTE index); +50231 bdppSig8%=P% +50232 [OPT 2 +50234 LD HL,index%: LD B,(HL) +50236 LD HL,fcn%: LD A,(HL) +50238 RST.LIL &20 +50240 RET +50242 ] +50244 ENDPROC diff --git a/video/bdpp/packet.h b/video/bdpp/packet.h new file mode 100644 index 00000000..d7fa8840 --- /dev/null +++ b/video/bdpp/packet.h @@ -0,0 +1,158 @@ +// +// Title: Agon Video BIOS +// Author: Dean Belfield +// Subtitle: Packet for Bidirectional Packet Protocol +// Author: Curtis Whitley +// Contributors: +// Created: 13/02/2024 +// Last Updated: 13/02/2024 +// + +#pragma once + +#include +#include +#include "esp_heap_caps.h" + +#define BDPP_MAX_PACKET_DATA_SIZE 256 // Maximum size of the data in one packet +#define BDPP_SMALL_PACKET_DATA_SIZE 32 // Maximum payload data length for small packet +#define BDPP_MAX_DRIVER_PACKETS 16 // Maximum number of driver-owned small packets +#define BDPP_MAX_APP_PACKETS 16 // Maximum number of app-owned packets +#define BDPP_MAX_STREAMS 16 // Maximum number of command/data streams +#define BDPP_MAX_RX_PACKETS 32 // Maximum number of packets setup for DMA RX + +#define BDPP_STREAM_INDEX_BITS 0xF0 // Upper nibble used for stream index +#define BDPP_PACKET_INDEX_BITS 0x0F // Lower nibble used for packet index + +#define BDPP_PKT_FLAG_PRINT 0x00 // Indicates packet contains printable data +#define BDPP_PKT_FLAG_COMMAND 0x01 // Indicates packet contains a command or request +#define BDPP_PKT_FLAG_RESPONSE 0x02 // Indicates packet contains a response +#define BDPP_PKT_FLAG_FIRST 0x04 // Indicates packet is first part of a message +#define BDPP_PKT_FLAG_MIDDLE 0x00 // Indicates packet is middle part of a message +#define BDPP_PKT_FLAG_LAST 0x08 // Indicates packet is last part of a message +#define BDPP_PKT_FLAG_ENHANCED 0x10 // Indicates packet is enhanced in some way +#define BDPP_PKT_FLAG_DONE 0x20 // Indicates packet was transmitted or received +#define BDPP_PKT_FLAG_FOR_RX 0x40 // Indicates packet is for reception, not transmission +#define BDPP_PKT_FLAG_DRIVER_OWNED 0x00 // Indicates packet is owned by the driver +#define BDPP_PKT_FLAG_APP_OWNED 0x80 // Indicates packet is owned by the application +#define BDPP_PKT_FLAG_USAGE_BITS 0x0F // Flag bits that describe packet usage +#define BDPP_PKT_FLAG_PROCESS_BITS 0xF0 // Flag bits that affect packet processing + +// This structure represents the UHCI data for a packet. +// It does not include the enclosing separator characters or escape characters. +#pragma pack(push, 1) +typedef struct tagUhciPacket { + uint8_t flags; // Flags describing the packet + uint8_t indexes; // Index of the packet (lower nibble) & stream (upper nibble) + uint8_t act_size; // Actual size of the data portion + uint8_t data[BDPP_MAX_PACKET_DATA_SIZE]; // The real data bytes + uint8_t dummy; // Padding to even multiple of 4 bytes + + // Test whether a flag is set. + inline bool is_flag_set(uint8_t flag) { return ((flags & flag) != 0); } + + // Test whether a flag is clear. + inline bool is_flag_clear(uint8_t flag) { return ((flags & flag) == 0); } + + // Get the flags. + inline uint8_t get_flags() { return flags; } + + // Get the packet index. + inline uint8_t get_packet_index() { return (indexes & 0x0F); } + + // Get the stream index. + inline uint8_t get_stream_index() { return (indexes >> 4); } + + // Get the actual data size. + inline uint16_t get_actual_data_size() { return (act_size ? act_size : 256); } + + // Get the transfer packet size. + uint16_t get_transfer_size() { + return (get_actual_data_size() + 3); + } + + // Get a pointer to the data. + inline uint8_t* get_data() { return data; } + + // Set one or more flags. + inline void set_flags(uint8_t flags) { this->flags |= flags; } + + // Clear one or more flags. + inline void clear_flags(uint8_t flags) { this->flags &= ~flags; } + + // Append a data byte to the packet. + void append_data(uint8_t data_byte) { + // The size will wrap to zero if it becomes 256. + data[act_size++] = data_byte; + } + + // Append multiple data bytes to the packet. + void append_data(const uint8_t* data_bytes, uint16_t count) { + memcpy((void*) &data[act_size], data_bytes, count); + // The size will wrap to zero if it becomes 256. + act_size += count; + } + + // Set the actual size. + // + // This may be used after using get_data() to write to the packet directly. + inline void set_size(uint16_t size) { + act_size = size; + } +} UhciPacket; +#pragma pack(pop) + +// This class represents one BDPP data packet. +// +class Packet { + public: + // Create a new, empty, driver-owned packet. + static Packet* create_driver_tx_packet(uint8_t flags, uint8_t packet_index, uint8_t stream_index) { + return new Packet(flags & BDPP_PKT_FLAG_USAGE_BITS, packet_index, stream_index); + } + + // Create a new, empty, app-owned packet. + static Packet* create_app_tx_packet(uint8_t flags, uint8_t packet_index, uint8_t stream_index) { + return new Packet((flags & BDPP_PKT_FLAG_USAGE_BITS) | BDPP_PKT_FLAG_APP_OWNED, packet_index, stream_index); + } + + // Create a new, empty packet. + Packet(uint8_t flags, uint8_t packet_index, uint8_t stream_index) { + auto max_size = (flags & BDPP_PKT_FLAG_APP_OWNED) ? BDPP_MAX_PACKET_DATA_SIZE : BDPP_SMALL_PACKET_DATA_SIZE; + auto alloc_size = get_alloc_size(max_size); + uhci_packet = (UhciPacket *) heap_caps_calloc(1, alloc_size, MALLOC_CAP_DMA|MALLOC_CAP_8BIT); + uhci_packet->flags = flags; + uhci_packet->indexes = (packet_index | (stream_index << 4)); + this->max_size = max_size; + uhci_packet->act_size = 0; + } + + // Destroy the packet. + ~Packet() { + heap_caps_free((void*) uhci_packet); + } + + // Get a pointer to the allocated UHCI packet data memory. + inline uint8_t* get_uhci_data() { return (uint8_t*) uhci_packet; } + + // Set the maximum data size. + inline void set_maximum_data_sze(uint16_t max_size) { this->max_size = max_size; } + + // Get the maximum data size. + inline uint16_t get_maximum_data_size() { return max_size; } + + // Get the allocated memory size. + static uint16_t get_alloc_size(uint16_t max_size) { + return ((3 + max_size + 3) & 0xFFFFFFFC) + 4; + } + + // Determine whether the packet is full of data. + inline bool is_full() { return uhci_packet->get_actual_data_size() >= get_maximum_data_size(); } + + // Get a pointer to the UHCI structure. + inline UhciPacket* get_uhci_packet() { return uhci_packet; } + + protected: + uint16_t max_size; // Maximum size of the data portion + UhciPacket* uhci_packet; // Pointer to UHCI data for the packet +}; diff --git a/video/bdpp/transfer.bas b/video/bdpp/transfer.bas new file mode 100644 index 00000000..2ed0c04d --- /dev/null +++ b/video/bdpp/transfer.bas @@ -0,0 +1,186 @@ +10 REM Sample program of BDPP data transfer +20 REM Read packets of data from ESP32 SRAM0 memory bank +30 REM Illustrates have multiple outstanding requests, +40 REM and awaiting responses to those requests. +100 OSCLI "bdpp" +200 DIM code% 300 +201 DIM fcn% 1: PRINT "fcn%: ";~fcn% +202 DIM index% 1: PRINT "index%: ";~index% +203 DIM flags% 1: PRINT "flags%: ";~flags% +204 DIM size% 4: PRINT "size%: ";~size% +205 DIM count% 4: PRINT "count%: ";~count% +206 DIM data% 4: PRINT "data%: ";~data% +207 packet_size%=10 +210 PROC_assemble_bdpp +215 REM Setup a large (4KB) RX buffer, and divide it +220 REM into 16 RX packets of packet_size% bytes each. +230 DIM buffer% 4096: REM Max packet_size% of 256 bytes +235 PRINT "Setting up 16 RX packets of ";packet_size%;" bytes each" +240 FOR pi%=0 TO 15 +250 ?fcn%=5: ?index%=pi%: !data%=(buffer%+pi%*packet_size%): !size%=packet_size% +260 rc%=USR(bdppSig6%) +265 PRINT "RX pkt #";pi%;" at ";~!data%;" setup -> ";rc% +270 ?fcn%=&F: CALL bdppSig3% +280 NEXT pi% +282 PRINT " done." +284 PRINT "Sending 16 requests for ";packet_size%;" bytes each..."; +286 ?fcn%=&F: CALL bdppSig3% +288 ts=TIME +300 FOR pi%=0 TO 15 +310 VDU 23,0,&A2,3,pi%,&E000+pi%*packet_size%;&3FFA;packet_size%; +320 NEXT pi% +322 PRINT " done." +324 ?fcn%=&F: CALL bdppSig3% +330 FOR pi%=0 TO 15 +340 PRINT "Waiting for RX pkt #";pi%;"..."; +350 ?fcn%=&F: CALL bdppSig3% +360 ?index%=pi%: ?fcn%=7 +365 rc%=USR(bdppSig2%) +370 IF rc%=0 GOTO 365 +380 PRINT " arrived!" +385 ?fcn%=&F: CALL bdppSig3% +390 NEXT pi% +400 tt=TIME-ts +410 PRINT "Transfer time = ";tt/100;" seconds" +420 ?fcn%=&F: CALL bdppSig3% +430 FOR pi%=0 TO 15 +450 ?fcn%=&17: ?index%=pi%: rc%=USR(bdppSig2%) +460 PRINT "Release RX pkt #";pi%;" -> ";rc% +470 NEXT pi% +475 ?fcn%=&F: CALL bdppSig3% +999 END + +49985 REM IX: Data address +49986 REM IY: Size of buffer or Count of bytes +49987 REM D: Data byte +49988 REM C: Packet Flags +49989 REM B: Packet Index(es) +49990 REM A: BDPP function code +50000 DEF PROC_assemble_bdpp +50001 REM -- bdppSig1% -- +50002 REM BDPP uses several styles of function calls: +50004 REM BOOL bdpp_is_allowed(); +50006 REM BOOL bdpp_is_enabled(); +50010 REM BOOL bdpp_disable(); +50012 P%=code%: bdppSig1%=P% +50014 [OPT 2 +50015 LD HL,fcn%: LD A,(HL) +50016 RST.LIL &20 +50017 LD L,A +50018 LD H,0 +50019 XOR A +50020 EXX +50021 XOR A +50022 LD L,0 +50023 LD H,0 +50024 LD C,A +50025 RET +50026 ] +50039 REM -- bdppSig2% -- +50040 REM BOOL bdpp_enable(BYTE stream); +50042 REM BOOL bdpp_is_tx_app_packet_done(BYTE index); +50044 REM BOOL bdpp_is_rx_app_packet_done(BYTE index); +50046 REM BYTE bdpp_get_rx_app_packet_flags(BYTE index); +50048 REM BOOL bdpp_stop_using_app_packet(BYTE index); +50050 bdppSig2%=P% +50051 [OPT 2 +50052 LD HL,index%: LD B,(HL) +50053 LD HL,fcn%: LD A,(HL) +50054 RST.LIL &20 +50055 LD L,A +50056 LD H,0 +50057 XOR A +50058 EXX +50059 XOR A +50060 LD L,0 +50061 LD H,0 +50062 LD C,A +50063 RET +50064 ] +50079 REM -- bdppSig3% -- +50080 REM void bdpp_flush_drv_tx_packet(); +50082 bdppSig3%=P% +50084 [OPT 2 +50085 LD HL,fcn%: LD A,(HL) +50086 RST.LIL &20 +50088 RET +50090 ] +50099 REM -- bdppSig4% -- +50100 REM void bdpp_write_byte_to_drv_tx_packet(BYTE data); +50101 REM void bdpp_write_drv_tx_byte_with_usage(BYTE data); +50102 bdppSig4%=P% +50104 [OPT 2 +50109 LD HL,fcn%: LD A,(HL) +50110 LD HL,data%: LD D,(HL) +50112 RST.LIL &20 +50114 RET +50116 ] +50119 REM -- bdppSig5% -- +50120 REM void bdpp_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count); +50122 REM void bdpp_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count); +50124 bdppSig5%=P% +50126 [OPT 2 +50128 LD HL,count%: DEFB &ED: DEFB &31 +50130 LD HL,fcn%: LD A,(HL) +50132 LD HL,data%: DEFB &ED: DEFB &37 +50138 RST.LIL &20 +50140 RET +50142 ] +50159 REM -- bdppSig6% -- +50160 REM BOOL bdpp_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size); +50161 bdppSig6%=P% +50162 [OPT 2 +50163 LD HL,size%: DEFB &ED: DEFB &31 +50164 LD HL,index%: LD B,(HL) +50165 LD HL,fcn%: LD A,(HL) +50166 LD HL,data%: DEFB &ED: DEFB &37 +50167 RST.LIL &20 +50168 LD L,A +50169 LD H,0 +50170 XOR A +50171 EXX +50172 XOR A +50173 LD L,0 +50174 LD H,0 +50175 LD C,A +50176 RET +50178 ] +50199 REM -- bdppSig7% -- +50200 REM BOOL bdpp_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size); +50201 bdppSig7%=P% +50202 [OPT 2 +50203 LD HL,size%: DEFB &ED: DEFB &31 +50204 LD HL,flags%: LD D,(HL) +50205 LD HL,index%: LD B,(HL) +50206 LD HL,fcn%: LD A,(HL) +50207 LD HL,data%: DEFB &ED: DEFB &37 +50208 RST.LIL &20 +50209 LD L,A +50210 LD H,0 +50211 XOR A +50212 EXX +50213 XOR A +50214 LD L,0 +50215 LD H,0 +50216 LD C,A +50217 RET +50218 ] +50219 REM -- bdppSig8% -- +50230 REM WORD bdpp_get_rx_app_packet_size(BYTE index); +50231 bdppSig8%=P% +50232 [OPT 2 +50234 LD HL,index%: LD B,(HL) +50236 LD HL,fcn%: LD A,(HL) +50238 RST.LIL &20 +50240 RET +50242 ] + +50244 PRINT "bdppSig1% ";~bdppSig1% +50246 PRINT "bdppSig2% ";~bdppSig2% +50248 PRINT "bdppSig3% ";~bdppSig3% +50250 PRINT "bdppSig4% ";~bdppSig4% +50252 PRINT "bdppSig5% ";~bdppSig5% +50254 PRINT "bdppSig6% ";~bdppSig6% +50256 PRINT "bdppSig7% ";~bdppSig7% +50258 PRINT "total code: ";P%-code% +50260 ENDPROC diff --git a/video/bdpp/transfer4k.bas b/video/bdpp/transfer4k.bas new file mode 100644 index 00000000..48427381 --- /dev/null +++ b/video/bdpp/transfer4k.bas @@ -0,0 +1,186 @@ +10 REM Sample program of BDPP data transfer +20 REM Read packets of data from ESP32 SRAM0 memory bank +30 REM Illustrates have multiple outstanding requests, +40 REM and awaiting responses to those requests. +100 OSCLI "bdpp" +200 DIM code% 200 +201 DIM fcn% 1: PRINT "fcn%: ";~fcn% +202 DIM index% 1: PRINT "index%: ";~index% +203 DIM flags% 1: PRINT "flags%: ";~flags% +204 DIM size% 4: PRINT "size%: ";~size% +205 DIM count% 4: PRINT "count%: ";~count% +206 DIM data% 4: PRINT "data%: ";~data% +207 packet_size%=256 +210 PROC_assemble_bdpp +215 REM Setup a large (4KB) RX buffer, and divide it +220 REM into 16 RX packets of packet_size% bytes each. +230 DIM buffer% 4096: REM Max packet_size% of 256 bytes +235 PRINT "Setting up 16 RX packets of ";packet_size%;" bytes each" +240 FOR pi%=0 TO 15 +250 ?fcn%=5: ?index%=pi%: !data%=(buffer%+pi%*packet_size%): !size%=packet_size% +260 rc%=USR(bdppSig6%) +265 PRINT "RX pkt #";pi%;" at ";~!data%;" setup -> ";rc% +270 ?fcn%=&F: CALL bdppSig3% +280 NEXT pi% +282 PRINT " done." +284 PRINT "Sending 16 requests for ";packet_size%;" bytes each..."; +286 ?fcn%=&F: CALL bdppSig3% +288 ts=TIME +300 FOR pi%=0 TO 15 +310 VDU 23,0,&A2,3,pi%,&E000+pi%*packet_size%;&3FFA;packet_size%; +320 NEXT pi% +322 PRINT " done." +324 ?fcn%=&F: CALL bdppSig3% +330 FOR pi%=0 TO 15 +340 PRINT "Waiting for RX pkt #";pi%;"..."; +350 ?fcn%=&F: CALL bdppSig3% +360 ?index%=pi%: ?fcn%=7 +365 rc%=USR(bdppSig2%) +370 IF rc%=0 GOTO 365 +380 PRINT " arrived!" +385 ?fcn%=&F: CALL bdppSig3% +390 NEXT pi% +400 tt=TIME-ts +410 PRINT "Transfer time = ";tt/100;" seconds" +420 ?fcn%=&F: CALL bdppSig3% +430 FOR pi%=0 TO 15 +450 ?fcn%=&17: ?index%=pi%: rc%=USR(bdppSig2%) +460 PRINT "Release RX pkt #";pi%;" -> ";rc% +470 NEXT pi% +475 ?fcn%=&F: CALL bdppSig3% +999 END + +49985 REM IX: Data address +49986 REM IY: Size of buffer or Count of bytes +49987 REM D: Data byte +49988 REM C: Packet Flags +49989 REM B: Packet Index(es) +49990 REM A: BDPP function code +50000 DEF PROC_assemble_bdpp +50001 REM -- bdppSig1% -- +50002 REM BDPP uses several styles of function calls: +50004 REM BOOL bdpp_is_allowed(); +50006 REM BOOL bdpp_is_enabled(); +50010 REM BOOL bdpp_disable(); +50012 P%=code%: bdppSig1%=P% +50014 [OPT 2 +50015 LD HL,fcn%: LD A,(HL) +50016 RST.LIL &20 +50017 LD L,A +50018 LD H,0 +50019 XOR A +50020 EXX +50021 XOR A +50022 LD L,0 +50023 LD H,0 +50024 LD C,A +50025 RET +50026 ] +50039 REM -- bdppSig2% -- +50040 REM BOOL bdpp_enable(BYTE stream); +50042 REM BOOL bdpp_is_tx_app_packet_done(BYTE index); +50044 REM BOOL bdpp_is_rx_app_packet_done(BYTE index); +50046 REM BYTE bdpp_get_rx_app_packet_flags(BYTE index); +50048 REM BOOL bdpp_stop_using_app_packet(BYTE index); +50050 bdppSig2%=P% +50051 [OPT 2 +50052 LD HL,index%: LD B,(HL) +50053 LD HL,fcn%: LD A,(HL) +50054 RST.LIL &20 +50055 LD L,A +50056 LD H,0 +50057 XOR A +50058 EXX +50059 XOR A +50060 LD L,0 +50061 LD H,0 +50062 LD C,A +50063 RET +50064 ] +50079 REM -- bdppSig3% -- +50080 REM void bdpp_flush_drv_tx_packet(); +50082 bdppSig3%=P% +50084 [OPT 2 +50085 LD HL,fcn%: LD A,(HL) +50086 RST.LIL &20 +50088 RET +50090 ] +50099 REM -- bdppSig4% -- +50100 REM void bdpp_write_byte_to_drv_tx_packet(BYTE data); +50101 REM void bdpp_write_drv_tx_byte_with_usage(BYTE data); +50102 bdppSig4%=P% +50104 [OPT 2 +50109 LD HL,fcn%: LD A,(HL) +50110 LD HL,data%: LD D,(HL) +50112 RST.LIL &20 +50114 RET +50116 ] +50119 REM -- bdppSig5% -- +50120 REM void bdpp_write_bytes_to_drv_tx_packet(const BYTE* data, WORD count); +50122 REM void bdpp_write_drv_tx_bytes_with_usage(const BYTE* data, WORD count); +50124 bdppSig5%=P% +50126 [OPT 2 +50128 LD HL,count%: DEFB &ED: DEFB &31 +50130 LD HL,fcn%: LD A,(HL) +50132 LD HL,data%: DEFB &ED: DEFB &37 +50138 RST.LIL &20 +50140 RET +50142 ] +50159 REM -- bdppSig6% -- +50160 REM BOOL bdpp_prepare_rx_app_packet(BYTE index, BYTE* data, WORD size); +50161 bdppSig6%=P% +50162 [OPT 2 +50163 LD HL,size%: DEFB &ED: DEFB &31 +50164 LD HL,index%: LD B,(HL) +50165 LD HL,fcn%: LD A,(HL) +50166 LD HL,data%: DEFB &ED: DEFB &37 +50167 RST.LIL &20 +50168 LD L,A +50169 LD H,0 +50170 XOR A +50171 EXX +50172 XOR A +50173 LD L,0 +50174 LD H,0 +50175 LD C,A +50176 RET +50178 ] +50199 REM -- bdppSig7% -- +50200 REM BOOL bdpp_queue_tx_app_packet(BYTE indexes, BYTE flags, const BYTE* data, WORD size); +50201 bdppSig7%=P% +50202 [OPT 2 +50203 LD HL,size%: DEFB &ED: DEFB &31 +50204 LD HL,flags%: LD D,(HL) +50205 LD HL,index%: LD B,(HL) +50206 LD HL,fcn%: LD A,(HL) +50207 LD HL,data%: DEFB &ED: DEFB &37 +50208 RST.LIL &20 +50209 LD L,A +50210 LD H,0 +50211 XOR A +50212 EXX +50213 XOR A +50214 LD L,0 +50215 LD H,0 +50216 LD C,A +50217 RET +50218 ] +50219 REM -- bdppSig8% -- +50230 REM WORD bdpp_get_rx_app_packet_size(BYTE index); +50231 bdppSig8%=P% +50232 [OPT 2 +50234 LD HL,index%: LD B,(HL) +50236 LD HL,fcn%: LD A,(HL) +50238 RST.LIL &20 +50240 RET +50242 ] + +50244 PRINT "bdppSig1% ";~bdppSig1% +50246 PRINT "bdppSig2% ";~bdppSig2% +50248 PRINT "bdppSig3% ";~bdppSig3% +50250 PRINT "bdppSig4% ";~bdppSig4% +50252 PRINT "bdppSig5% ";~bdppSig5% +50254 PRINT "bdppSig6% ";~bdppSig6% +50256 PRINT "bdppSig7% ";~bdppSig7% +50258 PRINT "total code: ";P%-code% +50260 ENDPROC diff --git a/video/bdpp/uhci_driver.cpp b/video/bdpp/uhci_driver.cpp new file mode 100644 index 00000000..e9fa0d63 --- /dev/null +++ b/video/bdpp/uhci_driver.cpp @@ -0,0 +1,216 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include "esp_types.h" +#include "esp_attr.h" +#include "esp_intr_alloc.h" +#include "esp_log.h" +#include "esp_err.h" +#include "malloc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/xtensa_api.h" +#include "freertos/ringbuf.h" +#include "bdpp/uhci_hal.h" +#include "driver/uart.h" +#include "bdpp/uhci_driver.h" +#include "driver/gpio.h" +#include "driver/periph_ctrl.h" +#include "sdkconfig.h" +#include "soc/periph_defs.h" +#include "rom/lldesc.h" +#include "hal/uart_hal.h" +#include "bdp_protocol.h" +#include + +extern std::queue bdpp_tx_queue; // Transmit (TX) packet queue +extern std::queue bdpp_rx_queue[BDPP_MAX_STREAMS]; // Receive (RX) packet queue + +typedef struct { + Packet* tx_pkt; + + union { + uint32_t align1; + lldesc_t tx_dma; + }; + + union { + uint32_t align2; + lldesc_t rx_dma[BDPP_MAX_RX_PACKETS]; + }; + + union { + uint32_t align3; + UhciPacket rx_pkt[BDPP_MAX_RX_PACKETS]; + }; + + uart_hal_context_t uart_hal; + uhci_hal_context_t uhci_hal; + intr_handle_t intr_handle; + int uhci_num; +} uhci_obj_t; + +uhci_obj_t* uhci_obj = NULL; + +static void IRAM_ATTR uhci_isr_handler_for_bdpp(void *param) +{ + while (1) { + uint32_t intr_mask = uhci_hal_get_intr(&(uhci_obj->uhci_hal)); + if (intr_mask == 0) { + break; + } + uhci_hal_clear_intr(&(uhci_obj->uhci_hal), intr_mask); + + // handle RX interrupt */ + if (intr_mask & (UHCI_INTR_IN_DONE | UHCI_INTR_IN_SUC_EOF | UHCI_INTR_TX_HUNG|UHCI_INTR_RX_HUNG)) { + lldesc_t* descr = (lldesc_t*) uhci_obj->uhci_hal.dev->dma_in_suc_eof_des_addr; + if (descr) { + int dma_index = descr - uhci_obj->rx_dma; + if (dma_index <= BDPP_MAX_RX_PACKETS) { + if (descr->length >= sizeof(UhciPacket)-BDPP_MAX_PACKET_DATA_SIZE) { + // provide this packet to the app + auto packet = &uhci_obj->rx_pkt[dma_index]; + //show_rx_packet(packet); + packet->set_flags(BDPP_PKT_FLAG_DONE); + bdpp_rx_queue[packet->get_stream_index()].push(packet); + } + } + } + } + + /* handle TX interrupt */ + if (intr_mask & (UHCI_INTR_OUT_EOF)) { + auto packet = uhci_obj->tx_pkt; + if (packet) { + packet->get_uhci_packet()->set_flags(BDPP_PKT_FLAG_DONE); + delete packet; + uhci_obj->tx_pkt = NULL; + } + if (bdpp_tx_queue.size()) { + auto packet = bdpp_tx_queue.front(); + bdpp_tx_queue.pop(); + uhci_obj->tx_pkt = packet; + uart_dma_write(UHCI_NUM_0, packet->get_uhci_data(), + packet->get_uhci_packet()->get_transfer_size()); + } else { + uhci_hal_disable_intr(&uhci_obj->uhci_hal, UHCI_INTR_OUT_EOF); + } + } + } +} + +void uart_dma_read() +{ + for (uint32_t i = 0; i < BDPP_MAX_RX_PACKETS; i++) { + auto dma = &uhci_obj->rx_dma[i]; + auto packet = &uhci_obj->rx_pkt[i]; + auto alloc_size = Packet::get_alloc_size(BDPP_MAX_PACKET_DATA_SIZE); + dma->buf = (volatile uint8_t *) packet; + dma->eof = 1; + dma->owner = 1; + dma->size = alloc_size; + dma->length = 0; + dma->offset = 0; + dma->sosf = 0; + auto next = (i >= BDPP_MAX_RX_PACKETS-1 ? 0 : i + 1); + dma->empty = (uint32_t) &uhci_obj->rx_dma[next]; // actually, 'qe' field + packet->flags = BDPP_PKT_FLAG_FOR_RX; + } + + auto hal = &(uhci_obj->uhci_hal); + uhci_hal_rx_dma_restart(hal); + uhci_hal_set_rx_dma(hal, (uint32_t)(uhci_obj->rx_dma)); + + uhci_enable_interrupts(UHCI_INTR_IN_DONE|UHCI_INTR_IN_SUC_EOF|UHCI_INTR_TX_HUNG|UHCI_INTR_RX_HUNG); + uhci_hal_rx_dma_start(hal); +} + +int uart_dma_write(int uhci_num, uint8_t *pbuf, size_t wr) +{ + uhci_obj->tx_dma.owner = 1; + uhci_obj->tx_dma.eof = 1; + uhci_obj->tx_dma.buf = pbuf; + uhci_obj->tx_dma.length = wr; + uhci_obj->tx_dma.size = (wr+3)&0xFFFFFFFC; + uhci_obj->tx_dma.empty = 0; // actually 'qe' (ptr to next descr) + auto hal = &(uhci_obj->uhci_hal); + uhci_hal_set_tx_dma(hal, (uint32_t)(&(uhci_obj->tx_dma))); + uhci_hal_tx_dma_start(hal); + return 0; +} + +void uart_dma_start_transmitter() { + auto old_int = uhci_disable_interrupts(); + if (!uhci_obj->tx_pkt) { + if (bdpp_tx_queue.size()) { + auto packet = bdpp_tx_queue.front(); + bdpp_tx_queue.pop(); + uhci_obj->tx_pkt = packet; + uart_dma_write(UHCI_NUM_0, packet->get_uhci_data(), + packet->get_uhci_packet()->get_transfer_size()); + old_int |= UHCI_INTR_OUT_EOF; + } + } + uhci_enable_interrupts(old_int); +} + +esp_err_t uhci_driver_install(int uhci_num, int intr_flag) +{ + uhci_obj = (uhci_obj_t*) heap_caps_malloc(sizeof(uhci_obj_t), MALLOC_CAP_DMA | MALLOC_CAP_32BIT | MALLOC_CAP_8BIT); + memset(uhci_obj, 0, sizeof(uhci_obj_t)); + uhci_obj->uhci_num = uhci_num; + periph_module_enable(PERIPH_UHCI0_MODULE); + return esp_intr_alloc(ETS_UHCI0_INTR_SOURCE, intr_flag, &uhci_isr_handler_for_bdpp, + uhci_obj, &uhci_obj->intr_handle); +} + +esp_err_t uhci_attach_uart_port(int uhci_num, int uart_num, const uart_config_t *uart_config) +{ + { + // Configure UART params + auto hal = &(uhci_obj->uart_hal); + hal->dev = UART_LL_GET_HW(uart_num); + uart_hal_init(hal, uart_num); + periph_module_enable(uart_periph_signal[uart_num].module); + uart_hal_disable_intr_mask(hal, ~0); + uart_param_config(uart_num, uart_config); + uart_hal_set_loop_back(hal, false); + //uart_ll_set_rx_tout(hal->dev, 255*8); // 2040 baud bit times (1.5 character times?) + uart_ll_set_rx_tout(hal->dev, 0); // no timeout + uart_set_pin(uart_num, 2, 34, 13, 14); + } + { + //Configure UHCI param + uhci_seper_chr_t seper_char = { 0x89, 0x8B, 0x8A, 0x8B, 0x8D, 0x01 }; + auto hal = &(uhci_obj->uhci_hal); + uhci_hal_init(hal, uhci_num); + uhci_hal_disable_intr(hal, UHCI_INTR_MASK); + uhci_hal_set_eof_mode(hal, 0); + uhci_hal_attach_uart_port(hal, uart_num); + uhci_hal_set_seper_chr(hal, &seper_char); + uhci_hal_clear_intr(hal, UHCI_INTR_MASK); + } + return ESP_OK; +} + +uint32_t uhci_disable_interrupts() { + auto hal = &(uhci_obj->uhci_hal); + auto old_int = uhci_hal_get_enabled_intr(hal); + uhci_hal_disable_intr(hal, ~0); + return old_int; +} + +void uhci_enable_interrupts(uint32_t old_int) { + auto hal = &(uhci_obj->uhci_hal); + uhci_hal_enable_intr(hal, old_int); +} diff --git a/video/bdpp/uhci_driver.h b/video/bdpp/uhci_driver.h new file mode 100644 index 00000000..ecfa2968 --- /dev/null +++ b/video/bdpp/uhci_driver.h @@ -0,0 +1,55 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include +#include "esp_types.h" +#include "esp_attr.h" +#include "esp_intr_alloc.h" +#include "esp_log.h" +#include "esp_err.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" +#include "freertos/xtensa_api.h" +#include "driver/uart.h" +#include "driver/gpio.h" +#include "driver/periph_ctrl.h" +#include "sdkconfig.h" + +#define UHCI_NUM_0 (0) /*!< UHCI number 0 */ +#define UHCI_NUM_1 (1) /*!< UHCI number 1 */ +#define UHCI_NUM_MAX (2) /*!< UHCI number max */ +#define UHCI_INTR_MASK (0x1ffff) //All interrupt mask + +typedef enum { + UHCI_EVENT_DATA = 0x1, + UHCI_EVENT_EOF = 0x2, + UHCI_EVENT_BUF_FULL = 0x4, +} uhci_event_type_t; + +typedef struct { + uint32_t type; + int len; +} uhci_event_t; + +void uart_dma_read(); + +int uart_dma_write(int uhci_num, uint8_t *pbuf, size_t wr); + +esp_err_t uhci_driver_install(int uhci_num, int intr_flag); + +esp_err_t uhci_attach_uart_port(int uhci_num, int uart_num, const uart_config_t *uart_config); + +uint32_t uhci_disable_interrupts(); + +void uhci_enable_interrupts(uint32_t old_int); + +void uart_dma_start_transmitter(); diff --git a/video/bdpp/uhci_hal.c b/video/bdpp/uhci_hal.c new file mode 100644 index 00000000..be69a04b --- /dev/null +++ b/video/bdpp/uhci_hal.c @@ -0,0 +1,116 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The HAL layer for UHCI (common part) +#include "uhci_hal.h" + +void uhci_hal_attach_uart_port(uhci_hal_context_t *hal, int uart_num) +{ + uhci_ll_attach_uart_port(hal->dev, uart_num); +} + +void uhci_hal_set_seper_chr(uhci_hal_context_t *hal, uhci_seper_chr_t *seper_char) +{ + uhci_ll_set_seper_chr(hal->dev, seper_char); +} + +void uhci_hal_get_seper_chr(uhci_hal_context_t *hal, uhci_seper_chr_t *seper_chr) +{ + uhci_ll_get_seper_chr(hal->dev, seper_chr); +} + +void uhci_hal_set_swflow_ctrl_sub_chr(uhci_hal_context_t *hal, uhci_swflow_ctrl_sub_chr_t *sub_ctr) +{ + uhci_ll_set_swflow_ctrl_sub_chr(hal->dev, sub_ctr); +} + +void uhci_hal_dma_in_reset(uhci_hal_context_t *hal) +{ + uhci_ll_dma_in_reset(hal->dev); +} + +void uhci_hal_dma_out_reset(uhci_hal_context_t *hal) +{ + uhci_ll_dma_out_reset(hal->dev); +} + +uint32_t uhci_hal_get_enabled_intr(uhci_hal_context_t *hal) { + uhci_ll_get_enabled_intr(hal->dev); +} + +void uhci_hal_enable_intr(uhci_hal_context_t *hal, uint32_t intr_mask) +{ + uhci_ll_enable_intr(hal->dev, intr_mask); +} + +void uhci_hal_disable_intr(uhci_hal_context_t *hal, uint32_t intr_mask) +{ + uhci_ll_disable_intr(hal->dev, intr_mask); +} + +void uhci_hal_clear_intr(uhci_hal_context_t *hal, uint32_t intr_mask) +{ + uhci_ll_clear_intr(hal->dev, intr_mask); +} + +uint32_t uhci_hal_get_intr(uhci_hal_context_t *hal) +{ + return uhci_ll_get_intr(hal->dev); +} + +void uhci_hal_set_rx_dma(uhci_hal_context_t *hal, uint32_t addr) +{ + uhci_ll_set_rx_dma(hal->dev, addr); +} + +void uhci_hal_set_tx_dma(uhci_hal_context_t *hal, uint32_t addr) +{ + uhci_ll_set_tx_dma(hal->dev, addr); +} + +void uhci_hal_rx_dma_start(uhci_hal_context_t *hal) +{ + uhci_ll_rx_dma_start(hal->dev); +} + +void uhci_hal_rx_dma_restart(uhci_hal_context_t *hal) +{ + uhci_ll_rx_dma_restart(hal->dev); +} + +void uhci_hal_tx_dma_start(uhci_hal_context_t *hal) +{ + uhci_ll_tx_dma_start(hal->dev); +} + +void uhci_hal_rx_dma_stop(uhci_hal_context_t *hal) +{ + uhci_ll_rx_dma_stop(hal->dev); +} + +void uhci_hal_tx_dma_stop(uhci_hal_context_t *hal) +{ + uhci_ll_tx_dma_stop(hal->dev); +} + +void uhci_hal_set_eof_mode(uhci_hal_context_t *hal, uint32_t eof_mode) +{ + uhci_ll_set_eof_mode(hal->dev, eof_mode); +} + +void uhci_hal_init(uhci_hal_context_t *hal, int uhci_num) +{ + hal->dev = UHCI_LL_GET_HW(uhci_num); + hal->version = hal->dev->date; + uhci_ll_init(hal->dev); +} diff --git a/video/bdpp/uhci_hal.h b/video/bdpp/uhci_hal.h new file mode 100644 index 00000000..16525cf1 --- /dev/null +++ b/video/bdpp/uhci_hal.h @@ -0,0 +1,63 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The HAL layer for UHCI. +// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bdpp/uhci_ll.h" + +/** + * Context that should be maintained by both the driver and the HAL + */ +typedef struct { + uhci_dev_t *dev; + uint32_t version; +} uhci_hal_context_t; + + +void uhci_hal_attach_uart_port(uhci_hal_context_t *hal, int uart_num); +void uhci_hal_set_seper_chr(uhci_hal_context_t *hal, uhci_seper_chr_t *seper_char); +void uhci_hal_get_seper_chr(uhci_hal_context_t *hal, uhci_seper_chr_t *seper_chr); +void uhci_hal_set_swflow_ctrl_sub_chr(uhci_hal_context_t *hal, uhci_swflow_ctrl_sub_chr_t *sub_ctr); +void uhci_hal_dma_in_reset(uhci_hal_context_t *hal); +void uhci_hal_dma_out_reset(uhci_hal_context_t *hal); +uint32_t uhci_hal_get_enabled_intr(uhci_hal_context_t *hal); +void uhci_hal_enable_intr(uhci_hal_context_t *hal, uint32_t intr_mask); +void uhci_hal_disable_intr(uhci_hal_context_t *hal, uint32_t intr_mask); +void uhci_hal_clear_intr(uhci_hal_context_t *hal, uint32_t intr_mask); +uint32_t uhci_hal_get_intr(uhci_hal_context_t *hal); +void uhci_hal_set_rx_dma(uhci_hal_context_t *hal, uint32_t addr); +void uhci_hal_set_tx_dma(uhci_hal_context_t *hal, uint32_t addr); +void uhci_hal_rx_dma_start(uhci_hal_context_t *hal); +void uhci_hal_rx_dma_restart(uhci_hal_context_t *hal); +void uhci_hal_tx_dma_start(uhci_hal_context_t *hal); +void uhci_hal_rx_dma_stop(uhci_hal_context_t *hal); +void uhci_hal_tx_dma_stop(uhci_hal_context_t *hal); +void uhci_hal_set_eof_mode(uhci_hal_context_t *hal, uint32_t eof_mode); +void uhci_hal_init(uhci_hal_context_t *hal, int uhci_num); + +#ifdef __cplusplus +} +#endif diff --git a/video/bdpp/uhci_ll.h b/video/bdpp/uhci_ll.h new file mode 100644 index 00000000..ef7592b5 --- /dev/null +++ b/video/bdpp/uhci_ll.h @@ -0,0 +1,216 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for UHCI register operations. +// Note that most of the register operations in this layer are non-atomic operations. + + +#pragma once +#include "bdpp/uhci_types.h" +#include "soc/uhci_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UHCI_LL_GET_HW(num) (((num) == 0) ? (&UHCI0) : (&UHCI1)) + +static inline void uhci_ll_init(uhci_dev_t *hw) +{ + typeof(hw->conf0) conf0_reg; + hw->conf0.clk_en = 1; + conf0_reg.val = 0; + conf0_reg.clk_en = 1; + hw->conf0.val = conf0_reg.val; + hw->conf0.in_rst = 1; + hw->conf0.in_rst = 0; + hw->conf0.out_rst = 1; + hw->conf0.out_rst = 0; + hw->conf1.val = 0; + hw->conf1.dma_in_fifo_full_thrs = 100; + hw->conf1.check_owner = 0;//realy need? + hw->escape_conf.val = 0; + hw->hung_conf.val = 0; +} + +static inline void uhci_ll_attach_uart_port(uhci_dev_t *hw, int uart_num) +{ + typeof(hw->conf0) conf0_reg; + conf0_reg.val = hw->conf0.val; + conf0_reg.val &= 0xfffff1ff; + conf0_reg.val |= (0x1 << (9+uart_num)); + hw->conf0.val = conf0_reg.val; +} + +static inline void uhci_ll_set_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_char) +{ + if (seper_char->sub_chr_en) { + typeof(hw->esc_conf0) esc_conf0_reg; + esc_conf0_reg.val = hw->esc_conf0.val; + esc_conf0_reg.seper_char = seper_char->seper_chr; + esc_conf0_reg.seper_esc_char0 = seper_char->sub_chr1; + esc_conf0_reg.seper_esc_char1 = seper_char->sub_chr2; + hw->esc_conf0.val = esc_conf0_reg.val; + + typeof(hw->esc_conf1) esc_conf1_reg; + esc_conf1_reg.val = hw->esc_conf1.val; + esc_conf1_reg.seq0 = seper_char->sub_chr1; + esc_conf1_reg.seq0_char0 = seper_char->sub_chr1b; + esc_conf1_reg.seq0_char1 = seper_char->sub_chr2b; + hw->esc_conf1.val = esc_conf1_reg.val; + + hw->escape_conf.tx_c0_esc_en = 1; + hw->escape_conf.tx_db_esc_en = 1; + hw->escape_conf.rx_c0_esc_en = 1; + hw->escape_conf.rx_db_esc_en = 1; + + hw->conf0.seper_en = 1; + hw->conf0.uart_idle_eof_en = 0; + hw->conf0.len_eof_en = 0; + hw->conf0.indscr_burst_en = 0; + + hw->hung_conf.txfifo_timeout_ena = 1; + hw->hung_conf.txfifo_timeout = 0xFF; + hw->hung_conf.txfifo_timeout_shift = 4; + } else { + hw->escape_conf.tx_c0_esc_en = 0; + hw->escape_conf.tx_db_esc_en = 0; + hw->escape_conf.rx_c0_esc_en = 0; + hw->escape_conf.rx_db_esc_en = 0; + hw->conf0.seper_en = 0; + } +} + +static inline void uhci_ll_get_seper_chr(uhci_dev_t *hw, uhci_seper_chr_t *seper_chr) +{ + ; +} + +static inline void uhci_ll_set_swflow_ctrl_sub_chr(uhci_dev_t *hw, uhci_swflow_ctrl_sub_chr_t *sub_ctr) +{ + typeof(hw->escape_conf) escape_conf_reg; + escape_conf_reg.val = hw->escape_conf.val; + if (sub_ctr->flow_en == 1) { + typeof(hw->esc_conf2) esc_conf2_reg; + esc_conf2_reg.val = hw->esc_conf2.val; + typeof(hw->esc_conf3) esc_conf3_reg; + esc_conf3_reg.val = hw->esc_conf3.val; + esc_conf2_reg.seq1 = sub_ctr->xon_chr; + esc_conf2_reg.seq1_char0 = sub_ctr->xon_sub1; + esc_conf2_reg.seq1_char1 = sub_ctr->xon_sub2; + esc_conf3_reg.seq2 = sub_ctr->xoff_chr; + esc_conf3_reg.seq2_char0 = sub_ctr->xoff_sub1; + esc_conf3_reg.seq2_char1 = sub_ctr->xoff_sub2; + escape_conf_reg.tx_11_esc_en = 1; + escape_conf_reg.tx_13_esc_en = 1; + escape_conf_reg.rx_11_esc_en = 1; + escape_conf_reg.rx_13_esc_en = 1; + hw->esc_conf2.val = esc_conf2_reg.val; + hw->esc_conf3.val = esc_conf3_reg.val; + } else { + escape_conf_reg.tx_11_esc_en = 0; + escape_conf_reg.tx_13_esc_en = 0; + escape_conf_reg.rx_11_esc_en = 0; + escape_conf_reg.rx_13_esc_en = 0; + } + hw->escape_conf.val = escape_conf_reg.val; +} + +static inline void uhci_ll_dma_in_reset(uhci_dev_t *hw) +{ + hw->conf0.in_rst = 1; + hw->conf0.in_rst = 0; +} + +static inline void uhci_ll_dma_out_reset(uhci_dev_t *hw) +{ + hw->conf0.out_rst = 1; + hw->conf0.out_rst = 0; +} + +static inline void uhci_ll_enable_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_ena.val |= intr_mask; +} + +static inline uint32_t uhci_ll_get_enabled_intr(uhci_dev_t *hw) +{ + return hw->int_ena.val; +} + +static inline void uhci_ll_disable_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_ena.val &= (~intr_mask); +} + +static inline void uhci_ll_clear_intr(uhci_dev_t *hw, uint32_t intr_mask) +{ + hw->int_clr.val = intr_mask; +} + +static inline uint32_t uhci_ll_get_intr(uhci_dev_t *hw) +{ + return hw->int_st.val; +} + +static inline void uhci_ll_set_rx_dma(uhci_dev_t *hw, uint32_t addr) +{ + hw->dma_in_link.addr = addr; +} + +static inline void uhci_ll_set_tx_dma(uhci_dev_t *hw, uint32_t addr) +{ + hw->dma_out_link.addr = addr; +} + +static inline void uhci_ll_rx_dma_start(uhci_dev_t *hw) +{ + hw->dma_in_link.start = 1; +} + +static inline void uhci_ll_tx_dma_start(uhci_dev_t *hw) +{ + hw->dma_out_link.start = 1; +} + +static inline void uhci_ll_rx_dma_restart(uhci_dev_t *hw) +{ + hw->dma_in_link.restart = 1; +} + +static inline void uhci_ll_rx_dma_stop(uhci_dev_t *hw) +{ + hw->dma_in_link.stop = 1; +} + +static inline void uhci_ll_tx_dma_stop(uhci_dev_t *hw) +{ + hw->dma_out_link.stop = 1; +} + +static inline void uhci_ll_set_eof_mode(uhci_dev_t *hw, uint32_t eof_mode) +{ + if (eof_mode & UHCI_RX_BREAK_CHR_EOF) { + hw->conf0.uart_rx_brk_eof_en = 1; + } + if (eof_mode & UHCI_RX_IDLE_EOF) { + hw->conf0.uart_idle_eof_en = 1; + } + if (eof_mode & UHCI_RX_LEN_EOF) { + hw->conf0.len_eof_en = 1; + } +} + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/video/bdpp/uhci_types.h b/video/bdpp/uhci_types.h new file mode 100644 index 00000000..0fe58cc0 --- /dev/null +++ b/video/bdpp/uhci_types.h @@ -0,0 +1,78 @@ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + bool seper_en; + bool head_en; + bool crc_rec_en; + bool encode_crc_en; +} uhci_pk_cfg_t; + +typedef enum { + UHCI_RX_BREAK_CHR_EOF = 0x1, + UHCI_RX_IDLE_EOF = 0x2, + UHCI_RX_LEN_EOF = 0x4, + UHCI_RX_EOF_MAX = 0x7, +} uhci_rxeof_cfg_t; + +typedef struct { + uint8_t seper_chr; + uint8_t sub_chr1; + uint8_t sub_chr2; + uint8_t sub_chr1b; + uint8_t sub_chr2b; + bool sub_chr_en; +} uhci_seper_chr_t; + +typedef struct { + uint8_t xon_chr; + uint8_t xon_sub1; + uint8_t xon_sub2; + uint8_t xoff_chr; + uint8_t xoff_sub1; + uint8_t xoff_sub2; + uint8_t flow_en; +} uhci_swflow_ctrl_sub_chr_t; + +typedef enum { + UHCI_INTR_RX_START = (0x1 << 0), // 00001 + UHCI_INTR_TX_START = (0x1 << 1), // 00002 + UHCI_INTR_RX_HUNG = (0x1 << 2), // 00004 + UHCI_INTR_TX_HUNG = (0x1 << 3), // 00008 + UHCI_INTR_IN_DONE = (0x1 << 4), // 00010 + UHCI_INTR_IN_SUC_EOF = (0x1 << 5), // 00020 + UHCI_INTR_IN_ERR_EOF = (0x1 << 6), // 00040 + UHCI_INTR_OUT_DONE = (0x1 << 7), // 00080 + UHCI_INTR_OUT_EOF = (0x1 << 8), // 00100 + UHCI_INTR_IN_DSCR_ERR = (0x1 << 9), // 00200 + UHCI_INTR_OUT_DSCR_ERR = (0x1 << 10), // 00400 + UHCI_INTR_IN_DSCR_EMPTY = (0x1 << 11), // 00800 + UHCI_INTR_OUTLINK_EOF_ERR = (0x1 << 12), // 01000 + UHCI_INTR_OUT_TOT_EOF = (0x1 << 13), // 02000 + UHCI_INTR_SEND_S_Q = (0x1 << 14), // 04000 + UHCI_INTR_SEND_A_Q = (0x1 << 15), // 08000 + UHCI_INTR_IN_FIFO_FULL = (0x1 << 16), // 10000 +} uhci_intr_t; + +#ifdef __cplusplus +} +#endif diff --git a/video/compression.h b/video/compression.h new file mode 100644 index 00000000..75e0a2f6 --- /dev/null +++ b/video/compression.h @@ -0,0 +1,260 @@ +#ifndef COMPRESSION_H +#define COMPRESSION_H + +#include + +// This implementation uses a window size of 256 bytes, and a code size of 10 bits. +// The maximum compressed byte string size is 16 bytes. +// +// Code bits: +// 0000000000 +// 9876543210 +// ---------- +// 00xxxxxxxx New original data byte with value of xxxxxxxx +// 01iiiiiiii String of 4 bytes starting at window index iiiiiiii +// 10iiiiiiii String of 8 bytes starting at window index iiiiiiii +// 11iiiiiiii String of 16 bytes starting at window index iiiiiiii +// +// Note: Worst case, the output can be 25% LARGER than the input! + +#define COMPRESSION_WINDOW_SIZE 256 // power of 2 +#define COMPRESSION_STRING_SIZE 16 // power of 2 +#define COMPRESSION_TYPE_TURBO 'T' // TurboVega-style compression +#define TEMP_BUFFER_SIZE 256 + +#pragma pack(push, 1) +typedef struct { + uint8_t marker[3]; + uint8_t type; + uint32_t orig_size; +} CompressionFileHeader; +#pragma pack(pop) + + +typedef void (*WriteCompressedByte)(void*, uint8_t); +typedef void (*WriteDecompressedByte)(void*, uint8_t); + +typedef struct { + void* context; + WriteCompressedByte write_fcn; + uint32_t window_size; + uint32_t window_write_index; + uint32_t string_size; + uint32_t string_read_index; + uint32_t string_write_index; + uint32_t input_count; + uint32_t output_count; + uint8_t window_data[COMPRESSION_WINDOW_SIZE]; + uint8_t string_data[COMPRESSION_STRING_SIZE]; + uint8_t temp_buffer[TEMP_BUFFER_SIZE]; + uint8_t out_byte; + uint8_t out_bits; +} CompressionData; + +typedef struct { + void* context; + WriteDecompressedByte write_fcn; + uint32_t window_size; + uint32_t window_write_index; + uint32_t input_count; + uint32_t output_count; + uint8_t window_data[COMPRESSION_WINDOW_SIZE]; + uint8_t temp_buffer[TEMP_BUFFER_SIZE]; + uint16_t code; + uint8_t code_bits; +} DecompressionData; + +void agon_init_compression(CompressionData* cd, void* context, WriteCompressedByte write_fcn) { + memset(cd, 0, sizeof(CompressionData)); + cd->context = context; + cd->write_fcn = write_fcn; +} + +void agon_write_compressed_bit(CompressionData* cd, uint8_t comp_bit) { + cd->out_byte = (cd->out_byte << 1) | comp_bit; + if (++(cd->out_bits) >= 8) { + (*cd->write_fcn)(cd, cd->out_byte); + cd->out_byte = 0; + cd->out_bits = 0; + } +} + +void agon_write_compressed_byte(CompressionData* cd, uint8_t comp_byte) { + for (uint8_t bit = 0; bit < 8; bit++) { + agon_write_compressed_bit(cd, (comp_byte & 0x80) ? 1 : 0); + comp_byte <<= 1; + } +} + +void agon_compress_byte(CompressionData* cd, uint8_t orig_byte) { + // Add the new original byte to the string + cd->string_data[cd->string_write_index++] = orig_byte; + cd->string_write_index &= (COMPRESSION_STRING_SIZE - 1); + if (cd->string_size < COMPRESSION_STRING_SIZE) { + (cd->string_size)++; + } else { + cd->string_read_index = (cd->string_read_index + 1) & (COMPRESSION_STRING_SIZE - 1); + } + + if (cd->string_size >= 16) { + if (cd->window_size >= 16) { + // Determine whether the full string of 16 is in the window + for (uint32_t start = 0; start <= cd->window_size - 16; start++) { + uint32_t wi = start; + uint32_t si = cd->string_read_index; + uint8_t match = 1; + for (uint8_t i = 0; i < 16; i++) { + if (cd->window_data[wi++] != cd->string_data[si++]) { + match = 0; + break; + } + wi &= (COMPRESSION_WINDOW_SIZE - 1); + si &= (COMPRESSION_STRING_SIZE - 1); + } + if (match) { + agon_write_compressed_bit(cd, 1); // Output first '1' of '11iiiiiiii'. + agon_write_compressed_bit(cd, 1); // Output second '1' of '11iiiiiiii'. + agon_write_compressed_byte(cd, (uint8_t) (start)); // Output window index + cd->string_size = 0; + return; + } + } + } + + if (cd->window_size >= 8) { + // Determine whether the partial string of 8 is in the window + for (uint32_t start = 0; start <= cd->window_size - 8; start++) { + uint32_t wi = start; + uint32_t si = cd->string_read_index; + uint8_t match = 1; + for (uint8_t i = 0; i < 8; i++) { + if (cd->window_data[wi++] != cd->string_data[si++]) { + match = 0; + break; + } + wi &= (COMPRESSION_WINDOW_SIZE - 1); + si &= (COMPRESSION_STRING_SIZE - 1); + } + if (match) { + agon_write_compressed_bit(cd, 1); // Output '1' of '10iiiiiiii'. + agon_write_compressed_bit(cd, 0); // Output '0' of '10iiiiiiii'. + agon_write_compressed_byte(cd, (uint8_t) (start)); // Output window index + cd->string_size -= 8; + cd->string_read_index = (cd->string_read_index + 8) & (COMPRESSION_STRING_SIZE - 1); + return; + } + } + } + + if (cd->window_size >= 4) { + // Determine whether the partial string of 4 is in the window + for (uint32_t start = 0; start <= cd->window_size - 4; start++) { + uint32_t wi = start; + uint32_t si = cd->string_read_index; + uint8_t match = 1; + for (uint8_t i = 0; i < 4; i++) { + if (cd->window_data[wi++] != cd->string_data[si++]) { + match = 0; + break; + } + wi &= (COMPRESSION_WINDOW_SIZE - 1); + si &= (COMPRESSION_STRING_SIZE - 1); + } + if (match) { + agon_write_compressed_bit(cd, 0); // Output '0' of '01iiiiiiii'. + agon_write_compressed_bit(cd, 1); // Output '1' of '01iiiiiiii'. + agon_write_compressed_byte(cd, (uint8_t) (start)); // Output window index + cd->string_size -= 4; + cd->string_read_index = (cd->string_read_index + 4) & (COMPRESSION_STRING_SIZE - 1); + return; + } + } + } + + // Need to make room in the string for the next original byte + uint8_t old_byte = cd->string_data[cd->string_read_index++]; + agon_write_compressed_bit(cd, 0); // Output '0' of '00xxxxxxxx'. + agon_write_compressed_bit(cd, 0); // Output '0' of '00xxxxxxxx'. + agon_write_compressed_byte(cd, (uint8_t) (old_byte)); // Output old original byte + cd->string_size -= 1; + cd->string_read_index &= (COMPRESSION_STRING_SIZE - 1); + + // Add the old original byte to the window + cd->window_data[cd->window_write_index++] = old_byte; + cd->window_write_index &= (COMPRESSION_WINDOW_SIZE - 1); + if (cd->window_size < COMPRESSION_WINDOW_SIZE) { + (cd->window_size)++; + } + } +} + +void agon_finish_compression(CompressionData* cd) { + while (cd->string_size) { + agon_write_compressed_bit(cd, 0); // Output '0' of '00xxxxxxxx'. + agon_write_compressed_bit(cd, 0); // Output '0' of '00xxxxxxxx'. + agon_write_compressed_byte(cd, (uint8_t) (cd->string_data[cd->string_read_index++])); // Output orig byte + cd->string_size -= 1; + cd->string_read_index &= (COMPRESSION_STRING_SIZE - 1); + } + if (cd->out_bits) { + (*cd->write_fcn)(cd, (cd->out_byte << (8 - cd->out_bits))); // Output final bits + } +} + +void agon_init_decompression(DecompressionData* dd, void* context, WriteDecompressedByte write_fcn) { + memset(dd, 0, sizeof(DecompressionData)); + dd->context = context; + dd->write_fcn = write_fcn; +} + +void agon_decompress_byte(DecompressionData* dd, uint8_t comp_byte) { + for (uint8_t bit = 0; bit < 8; bit++) { + dd->code = (dd->code << 1) | ((comp_byte & 0x80) ? 1 : 0); + comp_byte <<= 1; + if (++(dd->code_bits) >= 10) { + // Interpret the incoming code + uint16_t command = (dd->code >> 8); + uint8_t value = (uint8_t)dd->code; + dd->code = 0; + dd->code_bits = 0; + uint8_t size; + + switch (command) + { + case 0: // value is copy of original byte + // Add the new decompressed byte to the window + dd->window_data[dd->window_write_index++] = value; + dd->window_write_index &= (COMPRESSION_WINDOW_SIZE - 1); + if (dd->window_size < COMPRESSION_WINDOW_SIZE) { + (dd->window_size)++; + } + (*(dd->write_fcn))(dd, value); + continue; + + case 1: // value is index to string of 4 bytes + size = 4; + break; + + case 2: // value is index to string of 8 bytes + size = 8; + break; + + case 3: // value is index to string of 16 bytes + size = 16; + break; + } + + // Extract a byte string from the window + uint8_t string_data[COMPRESSION_STRING_SIZE]; + uint32_t wi = value; + for (uint8_t si = 0; si < size; si++) { + uint8_t out_byte = dd->window_data[wi++]; + wi &= (COMPRESSION_WINDOW_SIZE - 1); + string_data[si] = out_byte; + (*(dd->write_fcn))(dd, out_byte); + } + } + } +} + +#endif // COMPRESSION_H diff --git a/video/graphics.h b/video/graphics.h index 4df29715..65737dff 100644 --- a/video/graphics.h +++ b/video/graphics.h @@ -42,6 +42,8 @@ std::vector pathPoints; // Storage for path points extern bool ttxtMode; // Teletext mode extern agon_ttxt ttxt_instance; // Teletext instance +extern int8_t use_otf_mode(int8_t mode); // Provides access to on-the-fly mode + // Copy the AGON font data from Flash to RAM // void copy_font() { @@ -826,6 +828,8 @@ int8_t change_mode(uint8_t mode) { case 18: errVal = change_resolution(2, SVGA_1024x768_60Hz); // VDP 1.03 Mode 0 break; + case 32 ... 79: + return use_otf_mode(mode); case 129: errVal = change_resolution(4, VGA_640x480_60Hz, true); break; diff --git a/video/on_the_fly.h b/video/on_the_fly.h new file mode 100644 index 00000000..9bc7f503 --- /dev/null +++ b/video/on_the_fly.h @@ -0,0 +1,178 @@ +#ifndef ON_THE_FLY +#define ON_THE_FLY + +#include "src/di_manager.h" +#include +#include +#include "agon.h" +#include "agon_fonts.h" +#include "dispdrivers/vgabasecontroller.h" +#include "src/di_timing.h" + +#define OTF_MANAGER_PRIORITY (configMAX_PRIORITIES - 1) // Task priority for manager for OTF (800x600x64) mode + +extern std::unique_ptr canvas; +extern std::unique_ptr _VGAController; +extern uint8_t videoMode; +extern uint8_t _VGAColourDepth; + +extern void print(char const * text); +extern int8_t change_mode(uint8_t mode); +extern void stream_send_mode_information(); + +DiManager* di_manager; // Used for OTF 800x600x64 mode + +void otf_task(void * options) { + debug_log("OTF task running\r\n"); + di_manager = new DiManager(); + di_manager->create_root(); + + auto opts = (uint32_t) options; + if (opts == 1) { + // Create a solid black rectangle as the screen background. + OtfCmd_41_Create_primitive_Solid_Rectangle cmd; + cmd.m_color = PIXEL_ALPHA_100_MASK|0x00; // 100% black + cmd.m_flags = PRIM_FLAGS_DEFAULT; + cmd.m_w = otf_video_params.m_active_pixels; + cmd.m_h = otf_video_params.m_active_lines; + cmd.m_id = 1; + cmd.m_pid = 0; + cmd.m_x = 0; + cmd.m_y = 0; + auto rect = di_manager->create_solid_rectangle(&cmd); + di_manager->generate_code_for_primitive(cmd.m_id); + } else if (opts == 2) { + // Create a full screen text area as the screen background. + OtfCmd_150_Create_primitive_Text_Area cmd; + cmd.m_flags = PRIM_FLAGS_DEFAULT; + cmd.m_id = 1; + cmd.m_pid = ROOT_PRIMITIVE_ID; + cmd.m_x = 0; + cmd.m_y = 0; + cmd.m_columns = otf_video_params.m_active_pixels / 8; + cmd.m_rows = otf_video_params.m_active_lines / 8; + cmd.m_bgcolor = PIXEL_ALPHA_100_MASK|0x00; + cmd.m_fgcolor = PIXEL_ALPHA_100_MASK|0x05; + auto text_area = di_manager->create_text_area(&cmd, fabgl::FONT_AGON_DATA); + di_manager->generate_code_for_primitive(cmd.m_id); + } + + stream_send_mode_information(); + debug_log("Running OTF manager...\r\n"); + di_manager->run(); +} + +int8_t use_otf_mode(int8_t mode) { + if (_VGAController) { + _VGAController->end(); + _VGAController.reset(); + } + canvas.reset(); + + // Modes: 32..47 (0x20..0x2F) - change mode, but create no primitives + // Modes: 48..63 (0x30..0x3F) - change mode, create full screen black rectangle + // Modes: 64..79 (0x40..0x4F) - change mode, create full screen text area + + auto options = (mode - 32) / 16; + auto resolution = (mode & 15); + + // Modeline for 800x600@60Hz resolution, positive syncs + #define SVGA_800x600_60Hz_Pos "\"800x600@60Hz\" 40 800 840 968 1056 600 601 605 628 +HSync +VSync" + + // Modeline for 684x384@60Hz resolution, opposite syncs + #define SVGA_684x384_60Hz "\"684x384@60Hz\" 42.75 684 720 792 900 384 385 387 398 -HSync +VSync DoubleScan" + + // Modeline for 1368x768@60Hz resolution, opposite syncs + #define SVGA_1368x768_60Hz "\"1368x768@60Hz\" 85.5 1368 1440 1584 1800 768 769 772 795 -HSync +VSync" + + // Modeline for 1280x720@60Hz resolution 1280 1468 1604 1664 + #define SVGA_1280x720_60Hz_ADJ "\"1280x720@60Hz\" 74.25 1280 1344 1480 1664 720 721 724 746 +hsync +vsync" + + // Modeline for 640x512@60Hz resolution (for pixel perfect 1280x1024 double scan resolution) + #define QSVGA_640x512_60Hz_ADJ "\"640x512@60Hz\" 54 640 664 720 844 512 513 515 533 -HSync -VSync DoubleScan" + + // Modeline for 320x200@75Hz resolution + #define VGA_320x200_75Hz_ADJ "\"320x200@75Hz\" 12.93 336 368 376 408 200 208 211 229 -HSync -VSync DoubleScan" + + // Modeline for 1024x768@60Hz resolution + #define SVGA_1024x768_60Hz_ADJ "\"1024x768@60Hz\" 65 1024 1056 1192 1344 768 771 777 806 -HSync -VSync" + + // Modeline for 320x200@70Hz resolution - the same of VGA_640x200_70Hz with horizontal halved + #define VGA_320x200_70Hz_ADJ "\"320x200@70Hz\" 12.5875 320 328 356 400 200 206 207 224 -HSync -VSync DoubleScan" + + const char* mode_line = NULL; + switch (resolution) { + case 0: mode_line = SVGA_800x600_60Hz_Pos; break; // (100x75) good + case 1: mode_line = SVGA_800x600_60Hz; break; // (100x75) good + case 2: mode_line = SVGA_684x384_60Hz; break; // (85x48) quarter of 1368x768, fuzzy + case 3: mode_line = QSVGA_640x512_60Hz_ADJ; break; // (80x64) quarter of 1280x1024, clean, but missing 4 rightmost columns + case 4: mode_line = VGA_640x480_60Hz; break; // (80x60) good + case 5: mode_line = VGA_640x240_60Hz; break; // (80x30) clean, but missing 2 rightmost columns + case 6: mode_line = VGA_512x384_60Hz; break; // (64x48) quarter of 1024x768, good + case 7: mode_line = QVGA_320x240_60Hz; break; // (40x30) quarter of 640x480, clean, but missing 1 rightmost column + case 8: mode_line = VGA_320x200_75Hz; break; // (40x25) clean, but missing 1 rightmost column + case 9: mode_line = VGA_320x200_70Hz_ADJ; break; // (40x25) clean, but missing 2 rightmost columns + case 10: mode_line = SVGA_1024x768_60Hz_ADJ; break; // (128x96) good + case 11: mode_line = SVGA_1280x720_60Hz_ADJ; break; // (160x90) clean, but missing columns 134 to 159 + case 12: mode_line = SVGA_1368x768_60Hz; break; // out of range on monitor + } + + if (!mode_line) { + return -1; // invalid mode + } + + fabgl::VGATimings timings; + if (!fabgl::VGABaseController::convertModelineToTimings(mode_line, &timings)) { + return -1; // invalid mode + } + + otf_video_params.m_mode_line = mode_line; + otf_video_params.m_scan_count = timings.scanCount; + otf_video_params.m_active_lines = timings.VVisibleArea; + otf_video_params.m_vfp_lines = timings.VFrontPorch; + otf_video_params.m_vs_lines = timings.VSyncPulse; + otf_video_params.m_vbp_lines = timings.VBackPorch; + otf_video_params.m_hfp_pixels = timings.HFrontPorch; + otf_video_params.m_hs_pixels = timings.HSyncPulse; + otf_video_params.m_active_pixels = timings.HVisibleArea; + otf_video_params.m_hbp_pixels = timings.HBackPorch; + otf_video_params.m_dma_clock_freq = timings.frequency; + otf_video_params.m_dma_total_lines = timings.VVisibleArea * timings.scanCount + timings.VFrontPorch + timings.VSyncPulse + timings.VBackPorch; + otf_video_params.m_dma_total_descr = otf_video_params.m_dma_total_lines; + otf_video_params.m_hs_on = (timings.HSyncLogic == '+' ? 1 : 0) << VGA_HSYNC_BIT; + otf_video_params.m_hs_off = (timings.HSyncLogic == '+' ? 0 : 1) << VGA_HSYNC_BIT; + otf_video_params.m_vs_on = (timings.VSyncLogic == '+' ? 1 : 0) << VGA_VSYNC_BIT; + otf_video_params.m_vs_off = (timings.VSyncLogic == '+' ? 0 : 1) << VGA_VSYNC_BIT; + otf_video_params.m_syncs_on = otf_video_params.m_hs_on | otf_video_params.m_vs_on; + otf_video_params.m_syncs_off = otf_video_params.m_hs_off | otf_video_params.m_vs_off; + otf_video_params.m_syncs_off_x4 = + (otf_video_params.m_syncs_off << 24) | (otf_video_params.m_syncs_off << 16) | + (otf_video_params.m_syncs_off << 8) | otf_video_params.m_syncs_off; + + int adj = 0; + otf_video_params.m_hfp_pixels += adj; + otf_video_params.m_hbp_pixels -= adj; + + //otf_video_params.dump(); + + uint8_t oldMode = videoMode; + videoMode = mode; + + TaskHandle_t xHandle = NULL; + xTaskCreatePinnedToCore(otf_task, "OTF-MODE", 4096, (void*) options, + OTF_MANAGER_PRIORITY, &xHandle, 1); // Core #1 + while (videoMode == mode); + return 0; // success +} + +bool is_otf_mode() { + return (di_manager != 0); +} + +void otf_print(const char* text) { + while (*text) { + di_manager->store_character(*text++); + } +} + +#endif diff --git a/video/src/LICENSE b/video/src/LICENSE new file mode 100644 index 00000000..97a4b632 --- /dev/null +++ b/video/src/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Curtis Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/video/src/di_bitmap.cpp b/video/src/di_bitmap.cpp new file mode 100644 index 00000000..c3fefbf8 --- /dev/null +++ b/video/src/di_bitmap.cpp @@ -0,0 +1,280 @@ +// di_bitmap.cpp - Function definitions for drawing bitmaps +// +// An opaque bitmap is a rectangle of fully opaque pixels of various colors. +// +// A masked bitmap is a combination of fully opaque of various colors, +// and fully transparent pixels. +// +// A transparent bitmap is a rectangle that is a combination of fully transparent pixels, +// partially transparent pixels, and fully opaque pixels, of various colors. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_bitmap.h" +#include "esp_heap_caps.h" +#include +#include "di_timing.h" + +DiBitmap::DiBitmap(uint32_t width, uint32_t height, uint16_t flags, bool use_psram) : DiPrimitive(flags) { + m_width = width; + m_height = height; + m_save_height = height; + m_flags |= PRIM_FLAGS_X_SRC; + m_transparent_color = 0; + m_use_psram = use_psram; + + if (flags & PRIM_FLAG_H_SCROLL_1) { + m_words_per_line = ((width + sizeof(uint32_t) - 1) / sizeof(uint32_t) + 2); + m_bytes_per_line = m_words_per_line * sizeof(uint32_t); + m_words_per_position = m_words_per_line * height; + m_bytes_per_position = m_words_per_position * sizeof(uint32_t); + + if (use_psram) { + m_pixels = (uint32_t*) heap_caps_malloc(m_bytes_per_position * 4, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT | MALLOC_CAP_32BIT); + } else { + m_pixels = new uint32_t[m_words_per_position * 4]; + } + + memset(m_pixels, 0x00, m_bytes_per_position * 4); + } else { + m_words_per_line = ((width + sizeof(uint32_t) - 1) / sizeof(uint32_t)); + m_bytes_per_line = m_words_per_line * sizeof(uint32_t); + m_words_per_position = m_words_per_line * height; + m_bytes_per_position = m_words_per_position * sizeof(uint32_t); + + if (use_psram) { + m_pixels = (uint32_t*) heap_caps_malloc(m_bytes_per_position, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT | MALLOC_CAP_32BIT); + } else { + m_pixels = new uint32_t[m_words_per_position]; + } + + memset(m_pixels, 0x00, m_bytes_per_position); + } + m_visible_start = m_pixels; + m_paint_code.enter_and_leave_outer_function(); +} + +DiBitmap::DiBitmap(uint16_t flags, DiBitmap* ref_bitmap) : DiPrimitive(flags) { + m_width = ref_bitmap->m_width; + m_height = ref_bitmap->m_height; + m_save_height = ref_bitmap->m_save_height; + m_flags |= (ref_bitmap->m_flags & (PRIM_FLAG_H_SCROLL_1|PRIM_FLAGS_BLENDED)) | (PRIM_FLAGS_X_SRC|PRIM_FLAGS_REF_DATA); + m_transparent_color = ref_bitmap->m_transparent_color; + m_words_per_line = ref_bitmap->m_words_per_line; + m_bytes_per_line = ref_bitmap->m_bytes_per_line; + m_words_per_position = ref_bitmap->m_words_per_position; + m_bytes_per_position = ref_bitmap->m_bytes_per_position; + m_pixels = ref_bitmap->m_pixels; + m_visible_start = m_pixels; + m_paint_code.enter_and_leave_outer_function(); +} + + +DiBitmap::~DiBitmap() { + if (!(m_flags & PRIM_FLAGS_REF_DATA)) { + if (m_use_psram) { + heap_caps_free(m_pixels); + } else { + delete [] m_pixels; + } + } +} + +void IRAM_ATTR DiBitmap::set_relative_position(int32_t x, int32_t y) { + DiPrimitive::set_relative_position(x, y); + m_visible_start = m_pixels; +} + +void DiBitmap::set_slice_position(int32_t x, int32_t y, uint32_t start_line, uint32_t height) { + DiPrimitive::set_relative_position(x, y); + m_height = height; + m_visible_start = m_pixels + start_line * m_words_per_line; +} + +void DiBitmap::set_transparent_pixel(uint32_t x, uint32_t y, uint8_t color) { + // Invert the meaning of the alpha bits. + set_pixel(x, y, PIXEL_ALPHA_INV_MASK(color)); +} + +void DiBitmap::set_transparent_color(uint8_t color) { + m_transparent_color = PIXEL_ALPHA_INV_MASK(color); +} + +void DiBitmap::set_pixel(uint32_t x, uint32_t y, uint8_t color) { + uint32_t* p; + int32_t index; + + if (m_flags & PRIM_FLAG_H_SCROLL_1) { + for (uint32_t pos = 0; pos < 4; pos++) { + p = m_pixels + pos * m_words_per_position + y * m_words_per_line + (FIX_INDEX(pos+x) / 4); + index = FIX_INDEX((pos+x)&3); + pixels(p)[index] = color; + } + } else { + p = m_pixels + y * m_words_per_line + (FIX_INDEX(x) / 4); + index = FIX_INDEX(x&3); + pixels(p)[index] = color; + } +} + +void DiBitmap::copy_pixels(DiBitmap* from_bitmap, uint8_t flip) { + auto lines = m_height; + if (m_flags & PRIM_FLAG_H_SCROLL_1) { + lines *= 4; + } + auto width = m_words_per_line * 4; + if (flip) { + auto src_pixels = (uint8_t*) from_bitmap->m_pixels; + auto dst_pixels = (uint8_t*) m_pixels; + if (flip & 0x02) { + dst_pixels = (uint8_t*)(m_pixels + (lines - 1)); + } + while (lines--) { + if (flip & 0x01) { + for (uint32_t x = 0; x < width; x++) { + auto psrc = src_pixels + FIX_INDEX(x); + auto pdst = dst_pixels + FIX_INDEX((width - 1 - x)); + *pdst = *psrc; + } + } else { + // pixels in line are not flipped + memcpy(dst_pixels, src_pixels, width); + } + } + src_pixels += m_bytes_per_line; + if (flip & 0x02) { + dst_pixels -= m_bytes_per_line; + } else { + dst_pixels += m_bytes_per_line; + } + } else { + memcpy(m_pixels, from_bitmap->m_pixels, lines * width); + } +} + +void DiBitmap::generate_instructions() { + delete_instructions(); + EspFixups fixups; + generate_code_for_positions(fixups, m_width, m_height); + m_paint_code.do_fixups(fixups); + set_current_paint_pointer(m_width, m_height); + setup_alpha_bits(); +} + +void DiBitmap::generate_instructions_if_needed() { + if (m_paint_code.get_code_size() <= 6) { + generate_instructions(); + } +} + +void DiBitmap::setup_alpha_bits() { + // Clear the alpha bits, and replace them with HS & VS bits, + // so that the bytes may be copied directly to the DMA buffers. + uint32_t n = m_words_per_position; + if (m_flags & PRIM_FLAG_H_SCROLL_1) { + n *= 4; + } + uint32_t* src_pixels = m_pixels; + while (n--) { + *src_pixels = (*src_pixels & 0x3F3F3F3F) | otf_video_params.m_syncs_off_x4; + src_pixels++; + } +} +extern void debug_log(const char* f,...); +void DiBitmap::generate_code_for_left_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { +debug_log("gcfle this %X xo %u w %u h %u h %u v %u\n",this,x_offset,width,height,hidden,visible); + DiPrimitive::generate_code_for_left_edge(fixups, x_offset, width, height, hidden, visible); +debug_log("@%i\n",__LINE__); + auto draw_width = (m_draw_x_extent - m_draw_x) - hidden; +debug_log("@%i\n",__LINE__); + if (m_flags & PRIM_FLAGS_ALL_SAME) { +debug_log("@%i\n",__LINE__); + m_paint_code.copy_line(fixups, x_offset, hidden, visible, m_flags, m_transparent_color, m_visible_start, true); +debug_log("@%i\n",__LINE__); + } else { +debug_log("@%i\n",__LINE__); + uint32_t at_jump_table = m_paint_code.init_jump_table(m_height); +debug_log("@%i\n",__LINE__); + uint32_t* src_pixels = m_visible_start; +debug_log("@%i src %X\n",__LINE__,src_pixels); + for (uint32_t i = 0; i < m_height; i++) { +debug_log("@%i\n",__LINE__); + m_paint_code.align32(); +debug_log("@%i\n",__LINE__); + m_paint_code.j_to_here(at_jump_table + i * sizeof(uint32_t)); +debug_log("@%i\n",__LINE__); + m_paint_code.copy_line(fixups, x_offset, hidden, visible, m_flags, m_transparent_color, src_pixels, false); +debug_log("@%i\n",__LINE__); + src_pixels += m_words_per_line; +debug_log("@%i\n",__LINE__); + } + } +debug_log("@%i\n",__LINE__); +} + +void DiBitmap::generate_code_for_right_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + DiPrimitive::generate_code_for_right_edge(fixups, x_offset, width, height, hidden, visible); + auto draw_width = (m_draw_x_extent - m_draw_x) - hidden; + if (m_flags & PRIM_FLAGS_ALL_SAME) { + m_paint_code.copy_line(fixups, x_offset, 0, visible, m_flags, m_transparent_color, m_visible_start, true); + } else { + uint32_t at_jump_table = m_paint_code.init_jump_table(m_height); + uint32_t* src_pixels = m_visible_start; + for (uint32_t i = 0; i < m_height; i++) { + m_paint_code.align32(); + m_paint_code.j_to_here(at_jump_table + i * sizeof(uint32_t)); + m_paint_code.copy_line(fixups, x_offset, 0, visible, m_flags, m_transparent_color, src_pixels, false); + src_pixels += m_words_per_line; + } + } +} + +void DiBitmap::generate_code_for_draw_area(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + DiPrimitive::generate_code_for_draw_area(fixups, x_offset, width, height, hidden, visible); + auto draw_width = m_draw_x_extent - m_draw_x; + if (m_flags & PRIM_FLAGS_ALL_SAME) { + m_paint_code.copy_line(fixups, x_offset, 0, draw_width, m_flags, m_transparent_color, m_visible_start, true); + } else { + uint32_t at_jump_table = m_paint_code.init_jump_table(m_height); + uint32_t* src_pixels = m_visible_start; + for (uint32_t i = 0; i < m_height; i++) { + m_paint_code.align32(); + m_paint_code.j_to_here(at_jump_table + i * sizeof(uint32_t)); + m_paint_code.copy_line(fixups, x_offset, 0, draw_width, m_flags, m_transparent_color, src_pixels, false); + src_pixels += m_words_per_line; + } + } +} + +void IRAM_ATTR DiBitmap::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { + auto line_offset = line_index - m_abs_y; + uint32_t pixels = (uint32_t)(m_visible_start + (m_words_per_line * line_offset)); + (*(m_cur_paint_ptr.m_a5a6))(this, p_scan_line, line_index, m_abs_x, pixels); +} + +void IRAM_ATTR DiBitmap::paint(volatile uint32_t* p_scan_line, uint32_t line_index, + uint32_t fcn_index, uint32_t src_pixel_offset) { + auto line_offset = line_index - m_abs_y; + uint32_t pixels = (uint32_t)(m_pixels + (m_words_per_line * line_offset) + src_pixel_offset); + EspFcnPtr paint_ptr = m_paint_ptrs[fcn_index]; + (*(paint_ptr.m_a5a6))(this, p_scan_line, line_index, 0, pixels); +} diff --git a/video/src/di_bitmap.h b/video/src/di_bitmap.h new file mode 100644 index 00000000..ab1d0129 --- /dev/null +++ b/video/src/di_bitmap.h @@ -0,0 +1,115 @@ +// di_bitmap.h - Function declarations for drawing bitmaps +// +// An opaque bitmap is a rectangle of fully opaque pixels of various colors. +// +// A masked bitmap is a combination of fully opaque pixels of various colors, +// and fully transparent pixels. +// +// A transparent bitmap is a rectangle that is a combination of fully transparent pixels, +// partially transparent pixels, and fully opaque pixels, of various colors. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" +#include "di_code.h" + +class DiBitmap : public DiPrimitive { + public: + // Construct a bitmap that owns its pixel data. + DiBitmap(uint32_t width, uint32_t height, uint16_t flags, bool use_psram); + + // Construct a bitmap that references (borrows) its pixel data. + DiBitmap(uint16_t flags, DiBitmap* ref_bitmap); + + // Destroy a bitmap. + ~DiBitmap(); + + // Set the X, Y position relative to the parent (which may be the screen). + virtual void IRAM_ATTR set_relative_position(int32_t rel_x, int32_t rel_y); + + // Set the position of the bitmap, and assume using pixels starting at the given line in the bitmap. + // This makes it possible to use a single (tall) bitmap to support animated sprites. + void IRAM_ATTR set_slice_position(int32_t x, int32_t y, uint32_t start_line, uint32_t height); + + // Set a single pixel within the allocated bitmap. The upper 2 bits of the color + // are the transparency level (00BBGGRR is 25% opaque, 01BBGGRR is 50% opaque, + // 10BBGGRR is 75% opaque, and 11BBGGRR is 100% opaque). If the given color value + // equals the already-set transparent color, then the pixel will be fully transparent, + // meaning 0% opaque. + void set_transparent_pixel(uint32_t x, uint32_t y, uint8_t color); + + // Set the single 8-bit color value used to represent a transparent pixel. This should be + // an unused color value in the visible image when designing the image. This does take out + // 1 of the 256 possible color values. The upper 2 bits of the color are the transparency + // level (00BBGGRR is 25% opaque, 01BBGGRR is 50% opaque, 10BBGGRR is 75% opaque, and + // 11BBGGRR is 100% opaque). + void set_transparent_color(uint8_t color); + + // Get the single 8-bit color value used to represent a transparent pixel. + // Since the alpha bits are stored inverted, we must invert them here to yield the original color. + inline uint8_t get_transparent_color() { return PIXEL_ALPHA_INV_MASK(m_transparent_color); } + + virtual void generate_code_for_left_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + virtual void generate_code_for_right_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + virtual void generate_code_for_draw_area(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + + // Reassemble the custom instructions required to draw the bitmap. + virtual void generate_instructions(); + + // Assemble the custom instructions required to draw the bitmap, if needed. + void generate_instructions_if_needed(); + + // Replace pixel alpha bits with VS & HS (synchs OFF) bits. + void setup_alpha_bits(); + + virtual void paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + // Paint the bitmap using certain predetermined paint parameters. + void IRAM_ATTR paint(volatile uint32_t* p_scan_line, uint32_t line_index, + uint32_t fcn_index, uint32_t src_pixel_offset); + + // Get a pointer to the pixel data. + inline uint32_t* get_pixels() { return m_pixels; } + + // Get the original height used to create the bitmap. + inline uint32_t get_original_height() { return m_save_height; } + + // Copy pixel data from another, similarly sized, bitmap. + // This allows flipping the pixels vertically (0x02), + // horizontally (0x01), or both (0x03). + void copy_pixels(DiBitmap* from_bitmap, uint8_t flip); + + protected: + // Set a single pixel with an adjusted color value. + void set_pixel(uint32_t x, uint32_t y, uint8_t color); + + uint32_t m_words_per_line; + uint32_t m_bytes_per_line; + uint32_t m_words_per_position; + uint32_t m_bytes_per_position; + uint32_t* m_visible_start; + uint32_t* m_pixels; + uint32_t m_save_height; + uint8_t m_transparent_color; + bool m_use_psram; +}; diff --git a/video/src/di_code.cpp b/video/src/di_code.cpp new file mode 100644 index 00000000..a464baa4 --- /dev/null +++ b/video/src/di_code.cpp @@ -0,0 +1,1402 @@ +// di_code.cpp - Supports creating ESP32 functions dynamically. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_code.h" +#include "di_constants.h" +#include "di_primitive_const.h" +#include "../agon.h" +#include "freertos/FreeRTOS.h" +#include +#include + +#define EXTRA_CODE_SIZE 8 + +#define OUTER_RET_ADDR_IN_STACK (4) +#define INNER_RET_ADDR_IN_STACK (8) + +#define FIX_OFFSET(off) ((off)^2) + +#define MASK_ISOLATE_BR 0x33333333 // mask to isolate blue & red, removing green +#define MASK_ISOLATE_G 0x0C0C0C0C // mask to isolate green, removing red & blue + +extern uint32_t fcn_draw_256_pixels_in_loop; +extern uint32_t fcn_draw_128_pixels; +extern uint32_t fcn_draw_128_pixels_last; +extern uint32_t fcn_draw_64_pixels; +extern uint32_t fcn_draw_64_pixels_last; +extern uint32_t fcn_draw_32_pixels; +extern uint32_t fcn_draw_32_pixels_last; +extern uint32_t fcn_draw_16_pixels; +extern uint32_t fcn_draw_16_pixels_last; +extern uint32_t fcn_draw_8_pixels; +extern uint32_t fcn_draw_8_pixels_last; +extern uint32_t fcn_get_blend_25_for_4_pixels; +extern uint32_t fcn_get_blend_50_for_4_pixels; +extern uint32_t fcn_get_blend_75_for_4_pixels; +extern uint32_t fcn_dummy; + +extern uint32_t fcn_skip_draw_256_pixels_in_loop; +extern uint32_t fcn_skip_draw_128_pixels; +extern uint32_t fcn_skip_draw_64_pixels; +extern uint32_t fcn_skip_draw_32_pixels; +extern uint32_t fcn_skip_draw_16_pixels; +extern uint32_t fcn_skip_draw_8_pixels; + +extern uint32_t fcn_copy_256_pixels_in_loop; +extern uint32_t fcn_copy_128_pixels; +extern uint32_t fcn_copy_128_pixels_last; +extern uint32_t fcn_copy_64_pixels; +extern uint32_t fcn_copy_64_pixels_last; +extern uint32_t fcn_copy_32_pixels; +extern uint32_t fcn_copy_32_pixels_last; +extern uint32_t fcn_copy_16_pixels; +extern uint32_t fcn_copy_16_pixels_last; +extern uint32_t fcn_copy_8_pixels; +extern uint32_t fcn_copy_8_pixels_last; + +extern uint32_t fcn_skip_copy_256_pixels_in_loop; +extern uint32_t fcn_skip_copy_128_pixels; +extern uint32_t fcn_skip_copy_64_pixels; +extern uint32_t fcn_skip_copy_32_pixels; +extern uint32_t fcn_skip_copy_16_pixels; +extern uint32_t fcn_skip_copy_8_pixels; + +extern uint32_t fcn_color_blend_25_for_256_pixels_in_loop; +extern uint32_t fcn_color_blend_25_for_128_pixels; +extern uint32_t fcn_color_blend_25_for_128_pixels_last; +extern uint32_t fcn_color_blend_25_for_64_pixels; +extern uint32_t fcn_color_blend_25_for_64_pixels_last; +extern uint32_t fcn_color_blend_25_for_32_pixels; +extern uint32_t fcn_color_blend_25_for_32_pixels_last; +extern uint32_t fcn_color_blend_25_for_16_pixels; +extern uint32_t fcn_color_blend_25_for_16_pixels_last; +extern uint32_t fcn_color_blend_25_for_8_pixels; +extern uint32_t fcn_color_blend_25_for_8_pixels_last; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_0; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_0_last; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_1; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_1_last; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_2; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_2_last; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_3; +extern uint32_t fcn_color_blend_25_for_1_pixel_at_offset_3_last; +extern uint32_t fcn_color_blend_25_for_2_pixels_at_offset_0; +extern uint32_t fcn_color_blend_25_for_2_pixels_at_offset_0_last; +extern uint32_t fcn_color_blend_25_for_2_pixels_at_offset_1; +extern uint32_t fcn_color_blend_25_for_2_pixels_at_offset_1_last; +extern uint32_t fcn_color_blend_25_for_2_pixels_at_offset_2; +extern uint32_t fcn_color_blend_25_for_2_pixels_at_offset_2_last; +extern uint32_t fcn_color_blend_25_for_3_pixels_at_offset_0; +extern uint32_t fcn_color_blend_25_for_3_pixels_at_offset_0_last; +extern uint32_t fcn_color_blend_25_for_3_pixels_at_offset_1; +extern uint32_t fcn_color_blend_25_for_3_pixels_at_offset_1_last; +extern uint32_t fcn_color_blend_25_for_4_pixels_at_offset_0; +extern uint32_t fcn_color_blend_25_for_4_pixels_at_offset_0_last; + +extern uint32_t fcn_color_blend_50_for_256_pixels_in_loop; +extern uint32_t fcn_color_blend_50_for_128_pixels; +extern uint32_t fcn_color_blend_50_for_128_pixels_last; +extern uint32_t fcn_color_blend_50_for_64_pixels; +extern uint32_t fcn_color_blend_50_for_64_pixels_last; +extern uint32_t fcn_color_blend_50_for_32_pixels; +extern uint32_t fcn_color_blend_50_for_32_pixels_last; +extern uint32_t fcn_color_blend_50_for_16_pixels; +extern uint32_t fcn_color_blend_50_for_16_pixels_last; +extern uint32_t fcn_color_blend_50_for_8_pixels; +extern uint32_t fcn_color_blend_50_for_8_pixels_last; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_0; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_0_last; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_1; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_1_last; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_2; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_2_last; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_3; +extern uint32_t fcn_color_blend_50_for_1_pixel_at_offset_3_last; +extern uint32_t fcn_color_blend_50_for_2_pixels_at_offset_0; +extern uint32_t fcn_color_blend_50_for_2_pixels_at_offset_0_last; +extern uint32_t fcn_color_blend_50_for_2_pixels_at_offset_1; +extern uint32_t fcn_color_blend_50_for_2_pixels_at_offset_1_last; +extern uint32_t fcn_color_blend_50_for_2_pixels_at_offset_2; +extern uint32_t fcn_color_blend_50_for_2_pixels_at_offset_2_last; +extern uint32_t fcn_color_blend_50_for_3_pixels_at_offset_0; +extern uint32_t fcn_color_blend_50_for_3_pixels_at_offset_0_last; +extern uint32_t fcn_color_blend_50_for_3_pixels_at_offset_1; +extern uint32_t fcn_color_blend_50_for_3_pixels_at_offset_1_last; +extern uint32_t fcn_color_blend_50_for_4_pixels_at_offset_0; +extern uint32_t fcn_color_blend_50_for_4_pixels_at_offset_0_last; + +extern uint32_t fcn_color_blend_75_for_256_pixels_in_loop; +extern uint32_t fcn_color_blend_75_for_128_pixels; +extern uint32_t fcn_color_blend_75_for_128_pixels_last; +extern uint32_t fcn_color_blend_75_for_64_pixels; +extern uint32_t fcn_color_blend_75_for_64_pixels_last; +extern uint32_t fcn_color_blend_75_for_32_pixels; +extern uint32_t fcn_color_blend_75_for_32_pixels_last; +extern uint32_t fcn_color_blend_75_for_16_pixels; +extern uint32_t fcn_color_blend_75_for_16_pixels_last; +extern uint32_t fcn_color_blend_75_for_8_pixels; +extern uint32_t fcn_color_blend_75_for_8_pixels_last; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_0; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_0_last; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_1; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_1_last; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_2; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_2_last; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_3; +extern uint32_t fcn_color_blend_75_for_1_pixel_at_offset_3_last; +extern uint32_t fcn_color_blend_75_for_2_pixels_at_offset_0; +extern uint32_t fcn_color_blend_75_for_2_pixels_at_offset_0_last; +extern uint32_t fcn_color_blend_75_for_2_pixels_at_offset_1; +extern uint32_t fcn_color_blend_75_for_2_pixels_at_offset_1_last; +extern uint32_t fcn_color_blend_75_for_2_pixels_at_offset_2; +extern uint32_t fcn_color_blend_75_for_2_pixels_at_offset_2_last; +extern uint32_t fcn_color_blend_75_for_3_pixels_at_offset_0; +extern uint32_t fcn_color_blend_75_for_3_pixels_at_offset_0_last; +extern uint32_t fcn_color_blend_75_for_3_pixels_at_offset_1; +extern uint32_t fcn_color_blend_75_for_3_pixels_at_offset_1_last; +extern uint32_t fcn_color_blend_75_for_4_pixels_at_offset_0; +extern uint32_t fcn_color_blend_75_for_4_pixels_at_offset_0_last; + +extern uint32_t fcn_src_blend_25_for_256_pixels_in_loop; +extern uint32_t fcn_src_blend_25_for_128_pixels; +extern uint32_t fcn_src_blend_25_for_128_pixels_last; +extern uint32_t fcn_src_blend_25_for_64_pixels; +extern uint32_t fcn_src_blend_25_for_64_pixels_last; +extern uint32_t fcn_src_blend_25_for_32_pixels; +extern uint32_t fcn_src_blend_25_for_32_pixels_last; +extern uint32_t fcn_src_blend_25_for_16_pixels; +extern uint32_t fcn_src_blend_25_for_16_pixels_last; +extern uint32_t fcn_src_blend_25_for_8_pixels; +extern uint32_t fcn_src_blend_25_for_8_pixels_last; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_0; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_0_last; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_1; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_1_last; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_2; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_2_last; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_3; +extern uint32_t fcn_src_blend_25_for_1_pixel_at_offset_3_last; +extern uint32_t fcn_src_blend_25_for_2_pixels_at_offset_0; +extern uint32_t fcn_src_blend_25_for_2_pixels_at_offset_0_last; +extern uint32_t fcn_src_blend_25_for_2_pixels_at_offset_1; +extern uint32_t fcn_src_blend_25_for_2_pixels_at_offset_1_last; +extern uint32_t fcn_src_blend_25_for_2_pixels_at_offset_2; +extern uint32_t fcn_src_blend_25_for_2_pixels_at_offset_2_last; +extern uint32_t fcn_src_blend_25_for_3_pixels_at_offset_0; +extern uint32_t fcn_src_blend_25_for_3_pixels_at_offset_0_last; +extern uint32_t fcn_src_blend_25_for_3_pixels_at_offset_1; +extern uint32_t fcn_src_blend_25_for_3_pixels_at_offset_1_last; +extern uint32_t fcn_src_blend_25_for_4_pixels_at_offset_0; +extern uint32_t fcn_src_blend_25_for_4_pixels_at_offset_0_last; + +extern uint32_t fcn_src_blend_50_for_256_pixels_in_loop; +extern uint32_t fcn_src_blend_50_for_128_pixels; +extern uint32_t fcn_src_blend_50_for_128_pixels_last; +extern uint32_t fcn_src_blend_50_for_64_pixels; +extern uint32_t fcn_src_blend_50_for_64_pixels_last; +extern uint32_t fcn_src_blend_50_for_32_pixels; +extern uint32_t fcn_src_blend_50_for_32_pixels_last; +extern uint32_t fcn_src_blend_50_for_16_pixels; +extern uint32_t fcn_src_blend_50_for_16_pixels_last; +extern uint32_t fcn_src_blend_50_for_8_pixels; +extern uint32_t fcn_src_blend_50_for_8_pixels_last; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_0; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_0_last; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_1; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_1_last; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_2; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_2_last; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_3; +extern uint32_t fcn_src_blend_50_for_1_pixel_at_offset_3_last; +extern uint32_t fcn_src_blend_50_for_2_pixels_at_offset_0; +extern uint32_t fcn_src_blend_50_for_2_pixels_at_offset_0_last; +extern uint32_t fcn_src_blend_50_for_2_pixels_at_offset_1; +extern uint32_t fcn_src_blend_50_for_2_pixels_at_offset_1_last; +extern uint32_t fcn_src_blend_50_for_2_pixels_at_offset_2; +extern uint32_t fcn_src_blend_50_for_2_pixels_at_offset_2_last; +extern uint32_t fcn_src_blend_50_for_3_pixels_at_offset_0; +extern uint32_t fcn_src_blend_50_for_3_pixels_at_offset_0_last; +extern uint32_t fcn_src_blend_50_for_3_pixels_at_offset_1; +extern uint32_t fcn_src_blend_50_for_3_pixels_at_offset_1_last; +extern uint32_t fcn_src_blend_50_for_4_pixels_at_offset_0; +extern uint32_t fcn_src_blend_50_for_4_pixels_at_offset_0_last; + +extern uint32_t fcn_src_blend_75_for_256_pixels_in_loop; +extern uint32_t fcn_src_blend_75_for_128_pixels; +extern uint32_t fcn_src_blend_75_for_128_pixels_last; +extern uint32_t fcn_src_blend_75_for_64_pixels; +extern uint32_t fcn_src_blend_75_for_64_pixels_last; +extern uint32_t fcn_src_blend_75_for_32_pixels; +extern uint32_t fcn_src_blend_75_for_32_pixels_last; +extern uint32_t fcn_src_blend_75_for_16_pixels; +extern uint32_t fcn_src_blend_75_for_16_pixels_last; +extern uint32_t fcn_src_blend_75_for_8_pixels; +extern uint32_t fcn_src_blend_75_for_8_pixels_last; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_0; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_0_last; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_1; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_1_last; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_2; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_2_last; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_3; +extern uint32_t fcn_src_blend_75_for_1_pixel_at_offset_3_last; +extern uint32_t fcn_src_blend_75_for_2_pixels_at_offset_0; +extern uint32_t fcn_src_blend_75_for_2_pixels_at_offset_0_last; +extern uint32_t fcn_src_blend_75_for_2_pixels_at_offset_1; +extern uint32_t fcn_src_blend_75_for_2_pixels_at_offset_1_last; +extern uint32_t fcn_src_blend_75_for_2_pixels_at_offset_2; +extern uint32_t fcn_src_blend_75_for_2_pixels_at_offset_2_last; +extern uint32_t fcn_src_blend_75_for_3_pixels_at_offset_0; +extern uint32_t fcn_src_blend_75_for_3_pixels_at_offset_0_last; +extern uint32_t fcn_src_blend_75_for_3_pixels_at_offset_1; +extern uint32_t fcn_src_blend_75_for_3_pixels_at_offset_1_last; +extern uint32_t fcn_src_blend_75_for_4_pixels_at_offset_0; +extern uint32_t fcn_src_blend_75_for_4_pixels_at_offset_0_last; + +EspFunction::EspFunction() { + init_members(); +} + +EspFunction::~EspFunction() { + if (m_code) { + heap_caps_free(m_code); + } +} + +void EspFunction::init_members() { + m_alloc_size = 0; + m_code_size = 0; + m_code_index = 0; + m_code = 0; +} + +void EspFunction::draw_line(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t draw_width, + const DiLineSections* sections, + uint16_t flags, uint8_t opaqueness, bool outer_fcn) { + auto at_jump = (outer_fcn ? enter_outer_function() : enter_inner_function()); + auto at_data = begin_data(); + + uint32_t at_isolate_br = 0; + uint32_t at_isolate_g = 0; + if (opaqueness != 100) { + at_isolate_br = d32(MASK_ISOLATE_BR); // mask to isolate blue & red, removing green + at_isolate_g = d32(MASK_ISOLATE_G); // mask to isolate green, removing red & blue + } + + begin_code(at_jump); + set_reg_dst_pixel_ptr_for_draw(flags); + + if (opaqueness != 100) { + l32r_from(REG_ISOLATE_BR, at_isolate_br); + l32r_from(REG_ISOLATE_G, at_isolate_g); + } + + l32i(REG_PIXEL_COLOR, REG_THIS_PTR, FLD_color); + s32i(REG_RETURN_ADDR, REG_STACK_PTR, (outer_fcn ? OUTER_RET_ADDR_IN_STACK : INNER_RET_ADDR_IN_STACK)); + + if (opaqueness != 100) { + mov(REG_SAVE_COLOR, REG_PIXEL_COLOR); + } + + draw_line_loop(fixups, x_offset, skip, draw_width, sections, flags, opaqueness); + + l32i(REG_RETURN_ADDR, REG_STACK_PTR, (outer_fcn ? OUTER_RET_ADDR_IN_STACK : INNER_RET_ADDR_IN_STACK)); + + if (outer_fcn) retw(); else ret(); +} + +void EspFunction::adjust_dst_pixel_ptr(uint32_t draw_x, uint32_t x) { + auto start_x = draw_x & 0xFFFFFFFC; + auto end_x = x & 0xFFFFFFFC; + while (end_x > start_x) { + uint32_t diff = end_x - start_x; + if (diff < 4) { + break; + } + if (diff >= 120) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120); + start_x += 120; + } else if (diff >= 64) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64); + start_x += 64; + } else if (diff >= 32) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32); + start_x += 32; + } else if (diff >= 16) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16); + start_x += 16; + } else if (diff >= 8) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8); + start_x += 8; + } else { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + start_x += 4; + } + } +} + +void EspFunction::draw_line_loop(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t draw_width, + const DiLineSections* sections, uint16_t flags, uint8_t opaqueness) { + + auto num_sections = (uint32_t)sections->m_pieces.size(); + auto x = x_offset; + + for (uint16_t si = 0; (si < num_sections) && draw_width;) { + if (skip && (skip >= draw_width)) { + break; + } + + auto next_x = sections->m_pieces[si].m_x; + uint16_t gap = 0; + if (next_x > x) { + gap = next_x - x; + if (gap >= draw_width) { + break; + } + if (skip) { + if (gap < skip) { + skip -= gap; + } else { + skip = 0; + } + } + cover_width(fixups, x_offset, gap, 0, false, true); + x += gap; + draw_width -= gap; + } + + auto width = sections->m_pieces[si].m_width; + if (x > next_x) { + width -= x - next_x; + } + width = MIN(width, draw_width); + if (skip >= width) { + auto skip_now = MIN(skip, width); + cover_width(fixups, x_offset, skip_now, 0, false, (si + 1 < num_sections)); + skip -= skip_now; + } else { + auto width_now = width; + if (skip) { + cover_width(fixups, x_offset, skip, 0, false, true); + width_now -= skip; + skip = 0; + } + cover_width(fixups, x_offset, width_now, opaqueness, false, (si + 1 < num_sections)); + } + x += width; + draw_width -= width; + si++; + } +} + +void EspFunction::cover_width(EspFixups& fixups, uint32_t& x_offset, u_int32_t width, uint8_t opaqueness, bool copy, bool more) { + uint32_t p_fcn = 0; + while (width) { + auto offset = x_offset & 3; + uint32_t sub = 1; + switch (offset) { + case 0: + if (width >= 4) { + if (width >= 256) { + // Need at least 64 full words + auto times = width / 256; + p_fcn = cover_256(fixups, times, opaqueness, copy); + sub = times * 256; + } else if (width >= 128) { + // Need at least 32 full words + p_fcn = cover_128(fixups, width, opaqueness, copy, more); + sub = 128; + } else if (width >= 64) { + // Need at least 16 full words + p_fcn = cover_64(fixups, width, opaqueness, copy, more); + sub = 64; + } else if (width >= 32) { + // Need at least 8 full words + p_fcn = cover_32(fixups, width, opaqueness, copy, more); + sub = 32; + } else if (width >= 16) { + // Need at least 4 full words + p_fcn = cover_16(fixups, width, opaqueness, copy, more); + sub = 16; + } else if (width >= 8) { + // Need at least 2 full words + p_fcn = cover_8(fixups, width, opaqueness, copy, more); + sub = 8; + } else { + // Need at least 1 full word + p_fcn = cover_4(fixups, width, opaqueness, copy, more); + sub = 4; + } + } else if (width == 3) { + p_fcn = cover_3_at_0(fixups, width, opaqueness, copy); + //if (more) { + // addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + //} + sub = 3; + } else if (width == 2) { + p_fcn = cover_2_at_0(fixups, width, opaqueness, copy); + //if (more) { + // addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + //} + sub = 2; + } else { // width == 1 + p_fcn = cover_1_at_0(fixups, width, opaqueness, copy); + //if (more) { + // addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + //} + } + break; + + case 1: + if (width >= 3) { + p_fcn = cover_3_at_1(fixups, width, opaqueness, copy, more); + sub = 3; + } else if (width == 2) { + p_fcn = cover_2_at_1(fixups, width, opaqueness, copy); + //if (more) { + // addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + //} + sub = 2; + } else { // width == 1 + p_fcn = cover_1_at_1(fixups, width, opaqueness, copy); + //if (more) { + // addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + //} + } + break; + + case 2: + if (width >= 2) { + p_fcn = cover_2_at_2(fixups, width, opaqueness, copy, more); + sub = 2; + } else { // width == 1 + p_fcn = cover_1_at_2(fixups, width, opaqueness, copy); + //if (more) { + // addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + //} + } + break; + + case 3: + p_fcn = cover_1_at_3(fixups, width, opaqueness, copy, more); + break; + } + width -= sub; + x_offset += sub; + if (p_fcn) { + fixups.push_back(EspFixup { get_code_index(), p_fcn }); + call0(0); + p_fcn = 0; + } + } +} + +void EspFunction::copy_line(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t width, + uint16_t flags, uint8_t transparent_color, + uint32_t* src_pixels, bool outer_fcn) { + auto at_jump = (outer_fcn ? enter_outer_function() : enter_inner_function()); + auto at_data = begin_data(); + + uint32_t at_isolate_br = 0; + uint32_t at_isolate_g = 0; + if (flags & PRIM_FLAGS_BLENDED) { + at_isolate_br = d32(MASK_ISOLATE_BR); // mask to isolate blue & red, removing green + at_isolate_g = d32(MASK_ISOLATE_G); // mask to isolate green, removing red & blue + } + + begin_code(at_jump); + set_reg_dst_pixel_ptr_for_copy(flags); + + if (flags & PRIM_FLAGS_BLENDED) { + l32r_from(REG_ISOLATE_BR, at_isolate_br); + l32r_from(REG_ISOLATE_G, at_isolate_g); + } + + s32i(REG_RETURN_ADDR, REG_STACK_PTR, (outer_fcn ? OUTER_RET_ADDR_IN_STACK : INNER_RET_ADDR_IN_STACK)); + + copy_line_loop(fixups, x_offset, skip, width, flags, transparent_color, src_pixels); + + l32i(REG_RETURN_ADDR, REG_STACK_PTR, (outer_fcn ? OUTER_RET_ADDR_IN_STACK : INNER_RET_ADDR_IN_STACK)); + + if (outer_fcn) retw(); else ret(); +} + +void EspFunction::copy_line_loop(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t draw_width, + uint16_t flags, uint8_t transparent_color, uint32_t* src_pixels) { + + auto x = x_offset; + + uint8_t* p_src_bytes = (uint8_t*) src_pixels; + + while (draw_width) { + + uint8_t opaqueness = 100; + uint32_t width; + if (skip) { + width = MIN(skip, draw_width); + opaqueness = 0; + skip = 0; + } else if (!(flags & (PRIM_FLAGS_MASKED|PRIM_FLAGS_BLENDED))) { + // Transfer all pixels at 100% opaqueness. + width = draw_width; + } else { + // Determine the width of adjacent, similarly transparent (or opaque) pixels in the line. + // The colors do not have to be equal. + width = 1; + uint32_t index = FIX_OFFSET(x_offset); + uint8_t src_color = p_src_bytes[index]; + uint8_t first_alpha = (src_color == transparent_color) ? 0xFF : (src_color & 0xC0); + for (uint32_t i = 1; i < draw_width; i++) { + index = FIX_OFFSET(x_offset + i); + src_color = p_src_bytes[index]; + uint8_t next_alpha = (src_color == transparent_color) ? 0xFF : (src_color & 0xC0); + if (next_alpha == first_alpha) { + width++; + } else { + break; + } + } + + // This tests using inverted alpha masks. + switch (first_alpha) { + case PIXEL_ALPHA_INV_25_MASK: opaqueness = 25; break; + case PIXEL_ALPHA_INV_50_MASK: opaqueness = 50; break; + case PIXEL_ALPHA_INV_75_MASK: opaqueness = 75; break; + case PIXEL_ALPHA_INV_100_MASK: opaqueness = 100; break; + default: opaqueness = 0; break; + } + } + draw_width -= width; + // Use the series of pixels, rather than the rest of the line, if necessary. + cover_width(fixups, x_offset, width, opaqueness, true, (draw_width > 0)); + } +} + +void EspFunction::do_fixups(EspFixups& fixups) { + uint32_t save_pc = get_code_index(); + for (auto fixup = fixups.begin(); + fixup != fixups.end(); + ++fixup) { + set_code_index(fixup->code_index); + call_inner_fcn(fixup->fcn_address); + } + set_code_index(save_pc); +} + +void EspFunction::enter_and_leave_outer_function() { + entry(REG_STACK_PTR, 32); + retw(); +} + +uint32_t EspFunction::enter_outer_function() { + entry(REG_STACK_PTR, 32); + auto at_jump = get_code_index(); + j(0); + return at_jump; +} + +uint32_t EspFunction::enter_inner_function() { + auto at_jump = get_code_index(); + j(0); + return at_jump; +} + +uint32_t EspFunction::begin_data() { + align32(); + return get_code_index(); +} + +uint32_t EspFunction::init_jump_table(uint32_t num_items) { + /* 00 */ entry(sp, 32); + /* 03 */ l32i(REG_ABS_Y, REG_THIS_PTR, FLD_abs_y); + /* 06 */ s32i(REG_RETURN_ADDR, REG_STACK_PTR, OUTER_RET_ADDR_IN_STACK); + /* 09 */ call0(0); // 8 + 0*4 + 4 + /* 12 */ sub(REG_LINE_INDEX, REG_LINE_INDEX, REG_ABS_Y); + /* 15 */ slli(REG_JUMP_ADDRESS, REG_LINE_INDEX, 2); + /* 18 */ addi(REG_JUMP_ADDRESS, REG_JUMP_ADDRESS, 24); + /* 21 */ add(REG_JUMP_ADDRESS, REG_JUMP_ADDRESS, REG_RETURN_ADDR); + /* 24 */ l32i(REG_PIXEL_COLOR, REG_THIS_PTR, FLD_color); + /* 27 */ callx0(REG_JUMP_ADDRESS); + /* 30 */ l32i(REG_RETURN_ADDR, REG_STACK_PTR, OUTER_RET_ADDR_IN_STACK); + /* 33 */ retw(); + /* 36 */ auto at_jump_table = get_code_index(); + for (uint32_t i = 0; i < num_items; i++) { + /* 36+i*4 */ ret(); // will be changed to j(?) later + /* 39+i*4 */ align32(); + } + return at_jump_table; +} + +void EspFunction::begin_code(uint32_t at_jump) { + align32(); + j_to_here(at_jump); +} + +void EspFunction::set_reg_dst_pixel_ptr_for_draw(uint16_t flags) { + if (!(flags & PRIM_FLAGS_X)) { + l32i(REG_DST_PIXEL_PTR, REG_THIS_PTR, FLD_draw_x); + } + srli(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 2); + slli(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 2); + add(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, REG_LINE_PTR); +} + +void EspFunction::set_reg_dst_pixel_ptr_for_copy(uint16_t flags) { + if (!(flags & PRIM_FLAGS_X_SRC)) { + l32i(REG_DST_PIXEL_PTR, REG_THIS_PTR, FLD_draw_x); + } + srli(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 2); + slli(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 2); + add(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, REG_LINE_PTR); +} + +void EspFunction::call_inner_fcn(uint32_t real_address) { + uint32_t offset = (real_address - 4 - (get_real_address(get_code_index() & 0xFFFFFFFC))) & 0xFFFFF; + call0(offset); +} + +void EspFunction::store(uint8_t instr_byte) { + auto i = m_code_index >> 2; + switch (m_code_index & 3) { + case 0: + m_code[i] = (m_code[i] & 0xFFFFFF00) | (uint32_t)instr_byte; + break; + case 1: + m_code[i] = (m_code[i] & 0xFFFF00FF) | ((uint32_t)instr_byte) << 8; + break; + case 2: + m_code[i] = (m_code[i] & 0xFF00FFFF) | ((uint32_t)instr_byte) << 16; + break; + case 3: + m_code[i] = (m_code[i] & 0x00FFFFFF) | ((uint32_t)instr_byte) << 24; + break; + } + + if (++m_code_index > m_code_size) { + m_code_size = m_code_index; + } +} + +void EspFunction::align16() { + if (m_code_index & 1) { + d8(0); + } +} + +void EspFunction::align32() { + align16(); + if (m_code_index & 2) { + d16(0); + } +} + +void EspFunction::j_to_here(uint32_t from) { + uint32_t save_pc = get_code_index(); + set_code_index(from); + j(save_pc - from - 4); + set_code_index(save_pc); +} + +void EspFunction::bgez_to_here(reg_t src, s_off_t from) { + auto save_pc = get_code_index(); + set_code_index(from); + beqz(src, save_pc - from - 4); + set_code_index(save_pc); +} + + +void EspFunction::l32r_from(reg_t reg, uint32_t from) { + l32r(reg, from - ((get_code_index() + 3) & 0xFFFFFFFC)); +} + +void EspFunction::loop_to_here(reg_t reg, uint32_t from) { + auto save_pc = get_code_index(); + set_code_index(from); + loop(reg, save_pc - from - 4); + set_code_index(save_pc); +} + +uint16_t EspFunction::dup8_to_16(uint8_t value) { + return (((uint16_t)value) << 8) | ((uint16_t)value); +} + +uint32_t EspFunction::dup8_to_32(uint8_t value) { + return (dup8_to_16(value) << 16) | dup8_to_16(value); +} + +uint32_t EspFunction::dup16_to_32(uint16_t value) { + return (((uint32_t)value) << 16) | ((uint32_t)value); +} + +void EspFunction::allocate(uint32_t size) { + if (m_alloc_size) { + if (m_alloc_size - m_code_index < size) { + size_t new_size = (size_t)(m_alloc_size + size + EXTRA_CODE_SIZE + 3) &0xFFFFFFFC; + void* p = heap_caps_malloc(new_size, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC); + if (!p) debug_log("*MEM*\n"); + memcpy(p, m_code, (m_code_size + 3) &0xFFFFFFFC); + heap_caps_free(m_code); + m_alloc_size = (uint32_t)new_size; + m_code = (uint32_t*)p; + } + } else { + size_t new_size = (size_t)(size + EXTRA_CODE_SIZE + 3) &0xFFFFFFFC; + void* p = heap_caps_malloc(new_size, MALLOC_CAP_32BIT|MALLOC_CAP_EXEC); + m_alloc_size = (uint32_t)new_size; + m_code = (uint32_t*)p; + } +} + +uint32_t EspFunction::write8(const char* mnemonic, instr_t data) { + allocate(1); + auto at_data = get_code_index(); + store((uint8_t)(data & 0xFF)); + return at_data; +} + +uint32_t EspFunction::write16(const char* mnemonic, instr_t data) { + allocate(2); + auto at_data = get_code_index(); + store((uint8_t)(data & 0xFF)); + store((uint8_t)((data >> 8) & 0xFF)); + return at_data; +} + +uint32_t EspFunction::write24(const char* mnemonic, instr_t data) { + allocate(3); + auto at_data = get_code_index(); + store((uint8_t)(data & 0xFF)); + store((uint8_t)((data >> 8) & 0xFF)); + store((uint8_t)((data >> 16) & 0xFF)); + return at_data; +} + +uint32_t EspFunction::write32(const char* mnemonic, instr_t data) { + allocate(4); + auto at_data = get_code_index(); + store((uint8_t)(data & 0xFF)); + store((uint8_t)((data >> 8) & 0xFF)); + store((uint8_t)((data >> 16) & 0xFF)); + store((uint8_t)((data >> 24) & 0xFF)); + return at_data; +} + +instr_t EspFunction::isieo(uint32_t instr, reg_t src, int32_t imm, u_off_t offset) { + if (imm == -1) imm = 0; + else if (imm == 10) imm = 9; + else if (imm == 12) imm = 10; + else if (imm == 16) imm = 11; + else if (imm == 32) imm = 12; + else if (imm == 64) imm = 13; + else if (imm == 128) imm = 14; + else if (imm == 256) imm = 15; + return instr | (offset << 16) | (imm << 12) | (src << 8); +} + +uint32_t EspFunction::cover_256(EspFixups& fixups, uint32_t times, uint8_t opaqueness, bool copy) { + movi(REG_LOOP_INDEX, times); + + if (copy) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_256_pixels_in_loop; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_256_pixels_in_loop; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_256_pixels_in_loop; break; + case 100: return (uint32_t) &fcn_copy_256_pixels_in_loop; break; + default: return (uint32_t) &fcn_skip_copy_256_pixels_in_loop; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_256_pixels_in_loop; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_256_pixels_in_loop; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_256_pixels_in_loop; break; + case 100: return (uint32_t) &fcn_draw_256_pixels_in_loop; break; + default: return (uint32_t) &fcn_skip_draw_256_pixels_in_loop; break; + } + } +} + +uint32_t EspFunction::cover_128(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 128 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_128_pixels; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_128_pixels; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_128_pixels; break; + case 100: return (uint32_t) &fcn_copy_128_pixels; break; + default: return (uint32_t) &fcn_skip_copy_128_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_128_pixels_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_128_pixels_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_128_pixels_last; break; + case 100: return (uint32_t) &fcn_copy_128_pixels_last; break; + } + } + } else { + if (width > 128 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_128_pixels; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_128_pixels; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_128_pixels; break; + case 100: return (uint32_t) &fcn_draw_128_pixels; break; + default: return (uint32_t) &fcn_skip_draw_128_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_128_pixels_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_128_pixels_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_128_pixels_last; break; + case 100: return (uint32_t) &fcn_draw_128_pixels_last; break; + } + } + } + return 0; +} + +uint32_t EspFunction::cover_64(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 64 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_64_pixels; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_64_pixels; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_64_pixels; break; + case 100: return (uint32_t) &fcn_copy_64_pixels; break; + default: return (uint32_t) &fcn_skip_copy_64_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_64_pixels_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_64_pixels_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_64_pixels_last; break; + case 100: return (uint32_t) &fcn_copy_64_pixels_last; break; + } + } + } else { + if (width > 64 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_64_pixels; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_64_pixels; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_64_pixels; break; + case 100: return (uint32_t) &fcn_draw_64_pixels; break; + default: return (uint32_t) &fcn_skip_draw_64_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_64_pixels_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_64_pixels_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_64_pixels_last; break; + case 100: return (uint32_t) &fcn_draw_64_pixels_last; break; + } + } + } + return 0; +} + +uint32_t EspFunction::cover_32(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 32 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_32_pixels; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_32_pixels; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_32_pixels; break; + case 100: return (uint32_t) &fcn_copy_32_pixels; break; + default: return (uint32_t) &fcn_skip_copy_32_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_32_pixels_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_32_pixels_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_32_pixels_last; break; + case 100: return (uint32_t) &fcn_copy_32_pixels_last; break; + } + } + } else { + if (width > 32 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_32_pixels; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_32_pixels; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_32_pixels; break; + case 100: return (uint32_t) &fcn_draw_32_pixels; break; + default: return (uint32_t) &fcn_skip_draw_32_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_32_pixels_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_32_pixels_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_32_pixels_last; break; + case 100: return (uint32_t) &fcn_draw_32_pixels_last; break; + } + } + } + return 0; +} + +uint32_t EspFunction::cover_16(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 16 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_16_pixels; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_16_pixels; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_16_pixels; break; + case 100: return (uint32_t) &fcn_copy_16_pixels; break; + default: return (uint32_t) &fcn_skip_copy_16_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_16_pixels_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_16_pixels_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_16_pixels_last; break; + case 100: return (uint32_t) &fcn_copy_16_pixels_last; break; + } + } + } else { + if (width > 16 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_16_pixels; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_16_pixels; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_16_pixels; break; + case 100: return (uint32_t) &fcn_draw_16_pixels; break; + default: return (uint32_t) &fcn_skip_draw_16_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_16_pixels_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_16_pixels_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_16_pixels_last; break; + case 100: return (uint32_t) &fcn_draw_16_pixels_last; break; + } + } + } + return 0; +} + +uint32_t EspFunction::cover_8(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 8 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_8_pixels; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_8_pixels; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_8_pixels; break; + case 100: return (uint32_t) &fcn_copy_8_pixels; break; + default: return (uint32_t) &fcn_skip_copy_8_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_8_pixels_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_8_pixels_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_8_pixels_last; break; + case 100: return (uint32_t) &fcn_copy_8_pixels_last; break; + } + } + } else { + if (width > 8 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_8_pixels; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_8_pixels; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_8_pixels; break; + case 100: return (uint32_t) &fcn_draw_8_pixels; break; + default: return (uint32_t) &fcn_skip_draw_8_pixels; break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_8_pixels_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_8_pixels_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_8_pixels_last; break; + case 100: return (uint32_t) &fcn_draw_8_pixels_last; break; + } + } + } + return 0; +} + +uint32_t EspFunction::cover_4(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 4 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_4_pixels_at_offset_0; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_4_pixels_at_offset_0; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_4_pixels_at_offset_0; break; + case 100: + l32i(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0); + s32i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0); + addi(REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_4_pixels_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_4_pixels_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_4_pixels_at_offset_0_last; break; + case 100: + l32i(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0); + s32i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0); + break; + } + } + } else { + if (width > 4 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_4_pixels_at_offset_0; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_4_pixels_at_offset_0; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_4_pixels_at_offset_0; break; + case 100: + s32i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + default: addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_4_pixels_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_4_pixels_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_4_pixels_at_offset_0_last; break; + case 100: + s32i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0); + break; + } + } + } + return 0; +} + +uint32_t EspFunction::cover_3_at_0(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy) { + if (copy) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_3_pixels_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_3_pixels_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_3_pixels_at_offset_0_last; break; + case 100: + l32i(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(0)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_3_pixels_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_3_pixels_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_3_pixels_at_offset_0_last; break; + case 100: + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + } + return 0; +} + +uint32_t EspFunction::cover_2_at_0(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy) { + if (copy) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_2_pixels_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_2_pixels_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_2_pixels_at_offset_0_last; break; + case 100: + l16ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(0)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0)); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_2_pixels_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_2_pixels_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_2_pixels_at_offset_0_last; break; + case 100: + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0)); + break; + } + } + return 0; +} + +uint32_t EspFunction::cover_1_at_0(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy) { + if (copy) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_1_pixel_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_1_pixel_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_1_pixel_at_offset_0_last; break; + case 100: + l8ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(0)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0)); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_1_pixel_at_offset_0_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_1_pixel_at_offset_0_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_1_pixel_at_offset_0_last; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0)); + break; + } + } + return 0; +} + +uint32_t EspFunction::cover_3_at_1(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 3 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_3_pixels_at_offset_1; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_3_pixels_at_offset_1; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_3_pixels_at_offset_1; break; + case 100: + l32i(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + addi(REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_3_pixels_at_offset_1_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_3_pixels_at_offset_1_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_3_pixels_at_offset_1_last; break; + case 100: + l32i(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + } + } else { + if (width > 3) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_3_pixels_at_offset_1; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_3_pixels_at_offset_1; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_3_pixels_at_offset_1; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + default: addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_3_pixels_at_offset_1_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_3_pixels_at_offset_1_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_3_pixels_at_offset_1_last; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + if (more) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + } + } + } + return 0; +} + +uint32_t EspFunction::cover_2_at_1(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy) { + if (copy) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_2_pixels_at_offset_1_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_2_pixels_at_offset_1_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_2_pixels_at_offset_1_last; break; + case 100: + l32i(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_2_pixels_at_offset_1_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_2_pixels_at_offset_1_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_2_pixels_at_offset_1_last; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + } + return 0; +} + +uint32_t EspFunction::cover_1_at_1(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy) { + if (copy) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_1_pixel_at_offset_1_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_1_pixel_at_offset_1_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_1_pixel_at_offset_1_last; break; + case 100: + l8ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(1)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_1_pixel_at_offset_1_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_1_pixel_at_offset_1_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_1_pixel_at_offset_1_last; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1)); + break; + } + } + return 0; +} + +uint32_t EspFunction::cover_2_at_2(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 2 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_2_pixels_at_offset_2; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_2_pixels_at_offset_2; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_2_pixels_at_offset_2; break; + case 100: + l16ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + addi(REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_2_pixels_at_offset_2_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_2_pixels_at_offset_2_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_2_pixels_at_offset_2_last; break; + case 100: + l16ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2)); + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + addi(REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + } + } + } else { + if (width > 2) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_2_pixels_at_offset_2; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_2_pixels_at_offset_2; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_2_pixels_at_offset_2; break; + case 100: + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + default: addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_2_pixels_at_offset_2_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_2_pixels_at_offset_2_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_2_pixels_at_offset_2_last; break; + case 100: + s16i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + if (more) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + } + } + } + return 0; +} + +uint32_t EspFunction::cover_1_at_2(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy) { + if (copy) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_1_pixel_at_offset_2_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_1_pixel_at_offset_2_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_1_pixel_at_offset_2_last; break; + case 100: + l8ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_1_pixel_at_offset_2_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_1_pixel_at_offset_2_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_1_pixel_at_offset_2_last; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2)); + break; + } + } + return 0; +} + +uint32_t EspFunction::cover_1_at_3(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more) { + if (copy) { + if (width > 1 || more) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_1_pixel_at_offset_3; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_1_pixel_at_offset_3; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_1_pixel_at_offset_3; break; + case 100: + l8ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(3)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3)); + addi(REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_src_blend_25_for_1_pixel_at_offset_3_last; break; + case 50: return (uint32_t) &fcn_src_blend_50_for_1_pixel_at_offset_3_last; break; + case 75: return (uint32_t) &fcn_src_blend_75_for_1_pixel_at_offset_3_last; break; + case 100: + l8ui(REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(3)); + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3)); + break; + } + } + } else { + if (width > 1) { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_1_pixel_at_offset_3; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_1_pixel_at_offset_3; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_1_pixel_at_offset_3; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3)); + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + break; + default: addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); break; + } + } else { + switch (opaqueness) { + case 25: return (uint32_t) &fcn_color_blend_25_for_1_pixel_at_offset_3_last; break; + case 50: return (uint32_t) &fcn_color_blend_50_for_1_pixel_at_offset_3_last; break; + case 75: return (uint32_t) &fcn_color_blend_75_for_1_pixel_at_offset_3_last; break; + case 100: + s8i(REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3)); + break; + } + if (more) { + addi(REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4); + } + } + } + return 0; +} diff --git a/video/src/di_code.h b/video/src/di_code.h new file mode 100644 index 00000000..73162112 --- /dev/null +++ b/video/src/di_code.h @@ -0,0 +1,291 @@ +// di_code.h - Supports creating ESP32 functions dynamically. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#include +#include +#include "di_line_pieces.h" + +typedef enum { + a0 = 0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, + ra = 0, sp = 1 +} reg_t; + +typedef uint32_t instr_t; // instruction +typedef uint32_t u_off_t; // unsigned offset +typedef int32_t s_off_t; // signed offset + +extern "C" { +typedef void (*CallEspFcn)(void* p_this, volatile uint32_t* p_scan_line, uint32_t line_index); +typedef void (*CallEspA5Fcn)(void* p_this, volatile uint32_t* p_scan_line, uint32_t line_index, + uint32_t x); +typedef void (*CallEspA5A6Fcn)(void* p_this, volatile uint32_t* p_scan_line, uint32_t line_index, + uint32_t a5_value, uint32_t a6_value); +}; + +typedef union { + uint32_t m_address; + CallEspFcn m_simple; + CallEspA5Fcn m_a5; + CallEspA5A6Fcn m_a5a6; + + void clear() { m_address = 0; } +} EspFcnPtr; + +typedef struct { + uint32_t code_index; + uint32_t fcn_address; +} EspFixup; + +typedef std::vector EspFixups; +typedef std::vector EspFcnPtrs; + +class EspFunction { + public: + EspFunction(); + ~EspFunction(); + + // Pixel-level operations: + + void draw_line(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t draw_width, + const DiLineSections* sections, uint16_t flags, + uint8_t opaqueness, bool outer_fcn); + + void draw_line_loop(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t draw_width, + const DiLineSections* sections, uint16_t flags, uint8_t opaqueness); + + void copy_line(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t width, + uint16_t flags, uint8_t transparent_color, + uint32_t* src_pixels, bool outer_fcn); + + void copy_line_loop(EspFixups& fixups, uint32_t x_offset, + uint32_t skip, uint32_t draw_width, + uint16_t flags, uint8_t transparent_color, + uint32_t* src_pixels); + + // Common operations in functions: + + void do_fixups(EspFixups& fixups); + void enter_and_leave_outer_function(); + uint32_t enter_outer_function(); + uint32_t enter_inner_function(); + uint32_t begin_data(); + uint32_t init_jump_table(uint32_t num_items); + void begin_code(uint32_t at_jump); + void set_reg_dst_pixel_ptr_for_draw(uint16_t flags); + void set_reg_dst_pixel_ptr_for_copy(uint16_t flags); + + // Utility operations: + + inline void clear() { m_code_index = 0; m_code_size = 0; } + inline uint32_t get_code_index() { return m_code_index; } + inline void set_code_index(uint32_t code_index) { m_code_index = code_index; } + inline uint32_t get_code_size() { return m_code_size; } + inline uint32_t get_code(uint32_t address) { return m_code[address >> 2]; } + inline uint32_t get_code_start() { return (uint32_t)(void*) m_code; } + inline uint32_t get_real_address() { return ((uint32_t)m_code) + m_code_index; } + inline uint32_t get_real_address(uint32_t code_index) { return ((uint32_t)m_code) + code_index; } + void align16(); + void align32(); + void j_to_here(uint32_t from); + void l32r_from(reg_t reg, uint32_t from); + void loop_to_here(reg_t reg, uint32_t from); + uint16_t dup8_to_16(uint8_t value); + uint32_t dup8_to_32(uint8_t value); + uint32_t dup16_to_32(uint16_t value); + + // Assembler-level instructions: + + void add(reg_t dst, reg_t src1, reg_t src2) { write24("add", issd(0x800000, src1, src2, dst)); } + void addi(reg_t dst, reg_t src, s_off_t offset) { write24("addi", idsi(0x00C002, dst, src, offset)); } + void bbc(reg_t src, reg_t dst, s_off_t offset) { write24("bbc", isdo(0x005007, src, dst, offset)); } + void bbci(reg_t src, uint32_t imm, s_off_t offset) { write24("bbci", isio(0x006007, src, imm, offset)); } + void bbs(reg_t src, reg_t dst, s_off_t offset) { write24("bbs", isdo(0x00D007, src, dst, offset)); } + void bbsi(reg_t src, uint32_t imm, s_off_t offset) { write24("bbsi", isio(0x007007, src, imm, offset)); } + void beq(reg_t src, reg_t dst, s_off_t offset) { write24("beq", isdo(0x001007, src, dst, offset)); } + void beqi(reg_t src, uint32_t imm, s_off_t offset) { write24("beqi", isieo(0x000026, src, imm, offset)); } + void beqz(reg_t src, s_off_t offset) { write24("beqz", iso(0x000016, src, offset)); } + void bne(reg_t src, reg_t dst, s_off_t offset) { write24("bne", isdo(0x009007, src, dst, offset)); } + void bnei(reg_t src, uint32_t imm, s_off_t offset) { write24("bnei", isieo(0x000066, src, imm, offset)); } + void bnez(reg_t src, s_off_t offset) { write24("bnez", iso(0x000056, src, offset)); } + void bge(reg_t src, reg_t dst, s_off_t offset) { write24("bge", isdo(0x00A007, src, dst, offset)); } + void bgei(reg_t src, uint32_t imm, s_off_t offset) { write24("bgei", isieo(0x0000E6, src, imm, offset)); } + void bgeu(reg_t src, reg_t dst, s_off_t offset) { write24("bgeu", isdo(0x00B007, src, dst, offset)); } + void bgeui(reg_t src, uint32_t imm, s_off_t offset) { write24("bgeui", isieo(0x0000F6, src, imm, offset)); } + void bgez(reg_t src, s_off_t offset) { write24("bgez", iso(0x0000D6, src, offset)); } + void bgez_to_here(reg_t src, s_off_t from); + void blt(reg_t src, reg_t dst, s_off_t offset) { write24("blt", isdo(0x002007, src, dst, offset)); } + void blti(reg_t src, uint32_t imm, s_off_t offset) { write24("blti", isieo(0x0000A6, src, imm, offset)); } + void bltu(reg_t src, reg_t dst, s_off_t offset) { write24("bltu", isdo(0x003007, src, dst, offset)); } + void bltui(reg_t src, uint32_t imm, s_off_t offset) { write24("bltui", isieo(0x0000B6, src, imm, offset)); } + void bltz(reg_t src, s_off_t offset) { write24("bltz", iso(0x000096, src, offset)); } + void call0(s_off_t offset) { write24("call0", isco(0x000005, offset)); } + void callx0(reg_t src) { write24("callx0", iscxo(0x0000C0, src)); } + uint32_t d8(uint32_t value) { return write8("d8", value); } + uint32_t d16(uint32_t value) { return write16("d16", value); } + uint32_t d24(uint32_t value) { return write24("d24", value); } + uint32_t d32(uint32_t value) { return write32("d32", value); } + void entry(reg_t src, u_off_t offset) { write24("entry", iso(0x000036, src, (offset >> 3))); } + void j(s_off_t offset) { write24("j", io(0x000006, offset)); } + void jx(reg_t src) { write24("jx", iscxo(0x0000A0, src)); } + void l16si(reg_t dst, reg_t src, u_off_t offset) { write24("l16si", idso16(0x009002, dst, src, offset)); } + void l16ui(reg_t dst, reg_t src, u_off_t offset) { write24("l16ui", idso16(0x001002, dst, src, offset)); } + void l32i(reg_t dst, reg_t src, u_off_t offset) { write24("l32i", idso32(0x002002, dst, src, offset)); } + void l32r(reg_t dst, s_off_t offset) { write24("l32r", ido(0x000001, dst, offset)); } + void l8ui(reg_t dst, reg_t src, u_off_t offset) { write24("l8ui", idso8(0x000002, dst, src, offset)); } + void loop(reg_t src, u_off_t offset) { write24("loop", iso8(0x008076, src, offset)); } + void mov(reg_t dst, reg_t src) { write24("mov", ids(0x200000, dst, src)); } + void movi(reg_t dst, uint32_t value) { write24("movi", iv(0x00A002, dst, value)); } + void ret() { write24("ret", 0x000080); } + void retw() { write24("retw", 0x000090); } + void s16i(reg_t dst, reg_t src, u_off_t offset) { write24("s16i", idso16(0x005002, dst, src, offset)); } + void s32i(reg_t dst, reg_t src, u_off_t offset) { write24("s32i", idso32(0x006002, dst, src, offset)); } + void s8i(reg_t dst, reg_t src, u_off_t offset) { write24("s8i", idso8(0x004002, dst, src, offset)); } + void slli(reg_t dst, reg_t src, uint8_t bits) { write24("slli", idsb(0x010000, dst, src, bits)); } + void srli(reg_t dst, reg_t src, uint8_t bits) { write24("srli", idsrb(0x410000, dst, src, bits)); } + void sub(reg_t dst, reg_t src1, reg_t src2) { write24("sub", issd(0xC00000, src1, src2, dst)); } + + // a0 = return address + // a1 = stack ptr + // a2 = p_this + // a3 = p_scan_line + // a4 = line_index + inline void call(void* p_this, volatile uint32_t* p_scan_line, uint32_t line_index) { + (*((CallEspFcn)m_code))(p_this, p_scan_line, line_index); + } + + // a0 = return address + // a1 = stack ptr + // a2 = p_this + // a3 = p_scan_line + // a4 = line_index + // a5 = draw_x + inline void call_x(void* p_this, volatile uint32_t* p_scan_line, uint32_t line_index, + uint32_t draw_x) { + (*((CallEspA5Fcn)m_code))(p_this, p_scan_line, line_index, draw_x); + } + + // a0 = return address + // a1 = stack ptr + // a2 = p_this + // a3 = p_scan_line + // a4 = line_index + // a5 = a5_value + // a6 = a6_value + inline void call_a5_a6(void* p_this, volatile uint32_t* p_scan_line, uint32_t line_index, + uint32_t a5_value, uint32_t a6_value) { + (*((CallEspA5A6Fcn)m_code))(p_this, p_scan_line, line_index, a5_value, a6_value); + } + + protected: + uint32_t m_alloc_size; + uint32_t m_code_size; + uint32_t m_code_index; + uint32_t* m_code; + + void init_members(); + void allocate(uint32_t size); + void store(uint8_t instr_byte); + uint32_t write8(const char* mnemonic, instr_t data); + uint32_t write16(const char* mnemonic, instr_t data); + uint32_t write24(const char* mnemonic, instr_t data); + uint32_t write32(const char* mnemonic, instr_t data); + void call_inner_fcn(uint32_t real_address); + void adjust_dst_pixel_ptr(uint32_t draw_x, uint32_t x); + + inline instr_t issd(uint32_t instr, reg_t src1, reg_t src2, reg_t dst) { + return instr | (dst << 12) | (src1 << 8) | (src2 << 4); } + + inline instr_t ids(uint32_t instr, reg_t dst, reg_t src) { + return instr | (dst << 12) | (src << 8) | (src << 4); } + + inline instr_t idso16(uint32_t instr, reg_t dst, reg_t src, u_off_t offset) { + return instr | ((offset >> 1) << 16) | (dst << 4) | (src << 8); } + + inline instr_t idso32(uint32_t instr, reg_t dst, reg_t src, u_off_t offset) { + return instr | ((offset >> 2) << 16) | (dst << 4) | (src << 8); } + + inline instr_t idso8(uint32_t instr, reg_t dst, reg_t src, u_off_t offset) { + return instr | (offset << 16) | (dst << 4) | (src << 8); } + + inline instr_t isdo(uint32_t instr, reg_t src, reg_t dst, s_off_t offset) { + return instr | (offset << 16) | (dst << 4) | (src << 8); } + + inline instr_t idsi(uint32_t instr, reg_t dst, reg_t src, s_off_t imm) { + return instr | (((int32_t)imm) << 16) | (dst << 4) | (src << 8); } + + inline instr_t idsb(uint32_t instr, reg_t dst, reg_t src, uint8_t bits) { + bits = 32 - bits; + return instr | ((bits >> 4) << 20) | (dst << 12) | (src << 8) | ((bits & 0xF) << 4); } + + inline instr_t idsrb(uint32_t instr, reg_t dst, reg_t src, uint8_t bits) { + return instr | (dst << 12) | (src << 4) | (bits << 8); } + + inline instr_t isio(uint32_t instr, reg_t src, uint32_t imm, s_off_t offset) { + return instr | (offset << 16) | ((imm & 0xF) << 4) | ((imm & 0x10) << 8) | (src << 8); } + + instr_t isieo(uint32_t instr, reg_t src, int32_t imm, u_off_t offset); + + inline instr_t iso(uint32_t instr, reg_t src, s_off_t offset) { + return instr | (offset << 12) | (src << 8); } + + inline instr_t isco(uint32_t instr, u_off_t offset) { + return instr | ((offset >> 2) << 6); } + + inline instr_t iscxo(uint32_t instr, reg_t src) { + return instr | (src << 8); } + + inline instr_t iso8(uint32_t instr, reg_t src, u_off_t offset) { + return instr | (offset << 16) | (src << 8); } + + inline instr_t ido(uint32_t instr, reg_t dst, u_off_t offset) { + return instr | ((offset >> 2) << 8) | (dst << 4); } + + inline instr_t io(uint32_t instr, u_off_t offset) { + return instr | (offset << 6); } + + inline instr_t iv(uint32_t instr, reg_t dst, uint32_t value) { + return instr | ((value & 0xFF) << 16) | (dst << 4) | (value & 0xF00); } + + void cover_width(EspFixups& fixups, uint32_t& x_offset, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_256(EspFixups& fixups, uint32_t times, uint8_t opaqueness, bool copy); + uint32_t cover_128(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_64(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_32(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_16(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_8(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_4(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_3_at_0(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy); + uint32_t cover_2_at_0(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy); + uint32_t cover_1_at_0(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy); + uint32_t cover_3_at_1(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_2_at_1(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy); + uint32_t cover_1_at_1(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy); + uint32_t cover_2_at_2(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); + uint32_t cover_1_at_2(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy); + uint32_t cover_1_at_3(EspFixups& fixups, uint32_t width, uint8_t opaqueness, bool copy, bool more); +}; diff --git a/video/src/di_commands.h b/video/src/di_commands.h new file mode 100644 index 00000000..ed8281e5 --- /dev/null +++ b/video/src/di_commands.h @@ -0,0 +1,393 @@ +// di_commands.h - Data structures of VDU serial commands. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#include + +#pragma pack(push, 1) + +#define _anglex int16_t m_anglex; +#define _angley int16_t m_angley; +#define _anglez int16_t m_anglez; +#define _blue uint8_t m_blue; +#define _bgcolor uint8_t m_bgcolor; +#define _bmid uint16_t m_bmid; +#define _bottom uint16_t m_bottom; +#define _bottom8 uint8_t m_bottom; +#define _char uint8_t m_char; +#define _color uint8_t m_color; +#define _colors uint8_t m_colors[1]; +#define _column uint16_t m_column; +#define _column8 uint8_t m_column; +#define _columns uint16_t m_columns; +#define _coords int16_t m_coords[1]; +#define _distx int16_t m_distx; +#define _disty int16_t m_disty; +#define _distz int16_t m_distz; +#define _firstchar uint8_t m_firstchar; +#define _fgcolor uint8_t m_fgcolor; +#define _flags uint16_t m_flags; +#define _flip uint8_t m_flip; +#define _green uint8_t m_green; +#define _h uint16_t m_h; +#define _i0 uint16_t m_i0; +#define _id uint16_t m_id; +#define _ignore uint8_t m_ignore; +#define _ix int16_t m_ix; +#define _iy int16_t m_iy; +#define _lastchar uint8_t m_lastchar; +#define _left uint16_t m_left; +#define _left8 uint8_t m_left; +#define _logical uint8_t m_logical; +#define _mid uint16_t m_mid; +#define _mode uint8_t m_mode; +#define _n uint16_t m_n; +#define _oid uint16_t m_oid; +#define _physical uint8_t m_physical; +#define _pid uint16_t m_pid; +#define _psram uint8_t m_psram; +#define _r1 uint8_t m_r1; +#define _r2 uint8_t m_r2; +#define _r3 uint8_t m_r3; +#define _r4 uint8_t m_r4; +#define _r5 uint8_t m_r5; +#define _r6 uint8_t m_r6; +#define _r7 uint8_t m_r7; +#define _r8 uint8_t m_r8; +#define _red uint8_t m_red; +#define _row uint16_t m_row; +#define _row8 uint8_t m_row; +#define _rows uint16_t m_rows; +#define _right uint16_t m_right; +#define _right8 uint8_t m_right; +#define _s uint16_t m_s; +#define _scalex uint16_t m_scalex; +#define _scaley uint16_t m_scaley; +#define _scalez uint16_t m_scalez; +#define _sx0 int16_t m_sx0; +#define _sx1 int16_t m_sx1; +#define _sy0 int16_t m_sy0; +#define _sy1 int16_t m_sy1; +#define _th uint16_t m_th; +#define _top uint16_t m_top; +#define _top8 uint8_t m_top; +#define _tw uint16_t m_tw; +#define _u0 uint16_t m_u0; +#define _ux uint16_t m_ux; +#define _uy uint16_t m_uy; +#define _v0 uint16_t m_v0; +#define _w uint16_t m_w; +#define _x int16_t m_x; +#define _x0 int16_t m_x0; +#define _x1 int16_t m_x1; +#define _x2 int16_t m_x2; +#define _x3 int16_t m_x3; +#define _x4 int16_t m_x4; +#define _y int16_t m_y; +#define _y0 int16_t m_y0; +#define _y1 int16_t m_y1; +#define _y2 int16_t m_y2; +#define _y3 int16_t m_y3; +#define _y4 int16_t m_y4; +#define _z0 int16_t m_z0; + +#define ARGS(...) __VA_ARGS__ + +#define OTFCMD(cmd, params, name) \ +typedef struct { \ + uint8_t m_category; \ + uint8_t m_subcategory; \ + uint8_t m_command; \ + ARGS params \ +} OtfCmd_##cmd##name; + +OTFCMD(0,(_id _flags),_Set_flags_for_primitive) +OTFCMD(1,(_id _x _y),_Set_primitive_position) +OTFCMD(2,(_id _ix _iy),_Adjust_primitive_position) +OTFCMD(3,(_id),_Delete_primitive) +OTFCMD(4,(_id),_Generate_code_for_primitive) +OTFCMD(10,(_id _pid _flags _x _y _color),_Create_primitive_Point) +OTFCMD(20,(_id _pid _flags _x1 _y1 _x2 _y2 _color),_Create_primitive_Line) +OTFCMD(30,(_id _pid _flags _color _x1 _y1 _x2 _y2 _x3 _y3),_Create_primitive_Triangle_Outline) +OTFCMD(31,(_id _pid _flags _color _x1 _y1 _x2 _y2 _x3 _y3),_Create_primitive_Solid_Triangle) +OTFCMD(32,(_id _pid _flags _n _color _coords),_Create_primitive_Triangle_List_Outline) +OTFCMD(33,(_id _pid _flags _n _color _coords),_Create_primitive_Solid_Triangle_List) +OTFCMD(34,(_id _pid _flags _n _color _sx0 _sy0 _sx1 _sy1 _coords),_Create_primitive_Triangle_Fan_Outline) +OTFCMD(35,(_id _pid _flags _n _color _sx0 _sy0 _sx1 _sy1 _coords),_Create_primitive_Solid_Triangle_Fan) +OTFCMD(36,(_id _pid _flags _n _color _sx0 _sy0 _sx1 _sy1 _coords),_Create_primitive_Triangle_Strip_Outline) +OTFCMD(37,(_id _pid _flags _n _color _sx0 _sy0 _sx1 _sy1 _coords),_Create_primitive_Solid_Triangle_Strip) +OTFCMD(40,(_id _pid _flags _x _y _w _h _color),_Create_primitive_Rectangle_Outline) +OTFCMD(41,(_id _pid _flags _x _y _w _h _color),_Create_primitive_Solid_Rectangle) +OTFCMD(50,(_id _pid _flags _x _y _w _h _color),_Create_primitive_Ellipse_Outline) +OTFCMD(51,(_id _pid _flags _x _y _w _h _color),_Create_primitive_Solid_Ellipse) +OTFCMD(60,(_id _pid _flags _color _x1 _y1 _x2 _y2 _x3 _y3 _x4 _y4),_Create_primitive_Quad_Outline) +OTFCMD(61,(_id _pid _flags _color _x1 _y1 _x2 _y2 _x3 _y3 _x4 _y4),_Create_primitive_Solid_Quad) +OTFCMD(62,(_id _pid _flags _n _color _coords),_Create_primitive_Quad_List_Outline) +OTFCMD(63,(_id _pid _flags _n _color _coords),_Create_primitive_Solid_Quad_List) +OTFCMD(64,(_id _pid _flags _n _color _sx0 _sy0 _sx1 _sy1 _coords),_Create_primitive_Quad_Strip_Outline) +OTFCMD(65,(_id _pid _flags _n _color _sx0 _sy0 _sx1 _sy1 _coords),_Create_primitive_Solid_Quad_Strip) +OTFCMD(80,(_id _pid _flags _columns _rows _tw _th _w _h),_Create_primitive_Tile_Array) +OTFCMD(81,(_id _bmid _psram),_Create_Solid_Bitmap_for_Tile_Array) +OTFCMD(82,(_id _bmid _psram _color),_Create_Masked_Bitmap_for_Tile_Array) +OTFCMD(83,(_id _bmid _psram _color),_Create_Transparent_Bitmap_for_Tile_Array) +OTFCMD(84,(_id _column _row _bmid),_Set_bitmap_ID_for_tile_in_Tile_Array) +OTFCMD(85,(_id _bmid _ux _uy _color),_Set_solid_bitmap_pixel_in_Tile_Array) +OTFCMD(86,(_id _bmid _ux _uy _color),_Set_masked_bitmap_pixel_in_Tile_Array) +OTFCMD(87,(_id _bmid _ux _uy _color),_Set_transparent_bitmap_pixel_in_Tile_Array) +OTFCMD(88,(_id _bmid _ux _uy _n _colors),_Set_solid_bitmap_pixels_in_Tile_Array) +OTFCMD(89,(_id _bmid _ux _uy _n _colors),_Set_masked_bitmap_pixels_in_Tile_Array) +OTFCMD(90,(_id _bmid _ux _uy _n _colors),_Set_transparent_bitmap_pixels_in_Tile_Array) +OTFCMD(100,(_id _pid _flags _columns _rows _tw _th _w _h),_Create_primitive_Tile_Map) +OTFCMD(101,(_id _bmid _psram),_Create_Solid_Bitmap_for_Tile_Map) +OTFCMD(102,(_id _bmid _psram _color),_Create_Masked_Bitmap_for_Tile_Map) +OTFCMD(103,(_id _bmid _psram _color),_Create_Transparent_Bitmap_for_Tile_Map) +OTFCMD(104,(_id _column _row _bmid),_Set_bitmap_ID_for_tile_in_Tile_Map) +OTFCMD(105,(_id _bmid _ux _uy _color),_Set_solid_bitmap_pixel_in_Tile_Map) +OTFCMD(106,(_id _bmid _ux _uy _color),_Set_masked_bitmap_pixel_in_Tile_Map) +OTFCMD(107,(_id _bmid _ux _uy _color),_Set_transparent_bitmap_pixel_in_Tile_Map) +OTFCMD(108,(_id _bmid _ux _uy _n _colors),_Set_solid_bitmap_pixels_in_Tile_Map) +OTFCMD(109,(_id _bmid _ux _uy _n _colors),_Set_masked_bitmap_pixels_in_Tile_Map) +OTFCMD(110,(_id _bmid _ux _uy _n _colors),_Set_transparent_bitmap_pixels_in_Tile_Map) +OTFCMD(120,(_id _pid _flags _w _h _psram),_Create_primitive_Solid_Bitmap) +OTFCMD(121,(_id _pid _flags _w _h _psram _color),_Create_primitive_Masked_Bitmap) +OTFCMD(122,(_id _pid _flags _w _h _psram _color),_Create_primitive_Transparent_Bitmap) +OTFCMD(123,(_id _x _y _s _h),_Set_position_and_slice_solid_bitmap) +OTFCMD(124,(_id _x _y _s _h),_Set_position_and_slice_masked_bitmap) +OTFCMD(125,(_id _x _y _s _h),_Set_position_and_slice_transparent_bitmap) +OTFCMD(126,(_id _x _y _s _h),_Adjust_position_and_slice_solid_bitmap) +OTFCMD(127,(_id _x _y _s _h),_Adjust_position_and_slice_masked_bitmap) +OTFCMD(128,(_id _x _y _s _h),_Adjust_position_and_slice_transparent_bitmap) +OTFCMD(129,(_id _ux _uy _color),_Set_solid_bitmap_pixel) +OTFCMD(130,(_id _ux _uy _color),_Set_masked_bitmap_pixel) +OTFCMD(131,(_id _ux _uy _color),_Set_transparent_bitmap_pixel) +OTFCMD(132,(_id _ux _uy _n _colors),_Set_solid_bitmap_pixels) +OTFCMD(133,(_id _ux _uy _n _colors),_Set_masked_bitmap_pixels) +OTFCMD(134,(_id _ux _uy _n _colors),_Set_transparent_bitmap_pixels) +OTFCMD(135,(_id _pid _flags _bmid),_Create_primitive_Reference_Solid_Bitmap) +OTFCMD(136,(_id _pid _flags _bmid),_Create_primitive_Reference_Masked_Bitmap) +OTFCMD(137,(_id _pid _flags _bmid),_Create_primitive_Reference_Transparent_Bitmap) +OTFCMD(140,(_id _pid _flags _x _y _w _h),_Create_primitive_Group) +OTFCMD(145,(_id _pid _flags _bmid _psram _flip),_Create_primitive_Duplicate_Solid_Bitmap) +OTFCMD(146,(_id _pid _flags _bmid _psram _flip),_Create_primitive_Duplicate_Masked_Bitmap) +OTFCMD(147,(_id _pid _flags _bmid _psram _flip),_Create_primitive_Duplicate_Transparent_Bitmap) +OTFCMD(150,(_id _pid _flags _x _y _columns _rows _fgcolor _bgcolor),_Create_primitive_Text_Area) +OTFCMD(151,(_id),_Select_Active_Text_Area) +OTFCMD(152,(_id _char _fgcolor _bgcolor),_Define_Text_Area_Character) +OTFCMD(153,(_id _firstchar _lastchar _fgcolor _bgcolor),_Define_Text_Area_Character_Range) +OTFCMD(200,(_id _pid _flags _x _y _w _h _psram),_Create_primitive_Solid_Render) +OTFCMD(201,(_id _pid _flags _x _y _w _h _psram _color),_Create_primitive_Masked_Render) +OTFCMD(202,(_id _pid _flags _x _y _w _h _psram _color),_Create_primitive_Transparent_Render) +OTFCMD(203,(_id _mid _n _x0 _y0 _z0),_Define_Mesh_Vertices) +OTFCMD(204,(_id _mid _n _i0),_Set_Mesh_Vertex_Indices) +OTFCMD(205,(_id _mid _n _u0 _v0),_Define_Texture_Coordinates) +OTFCMD(206,(_id _mid _n _i0),_Set_Texture_Coordinate_Indices) +OTFCMD(207,(_id _oid _mid _bmid),_Create_Object) +OTFCMD(208,(_id _oid _scalex),_Set_Object_X_Scale_Factor) +OTFCMD(209,(_id _oid _scaley),_Set_Object_Y_Scale_Factor) +OTFCMD(210,(_id _oid _scalez),_Set_Object_Z_Scale_Factor) +OTFCMD(211,(_id _oid _scalex _scaley _scalez),_Set_Object_XYZ_Scale_Factors) +OTFCMD(212,(_id _oid _anglex),_Set_Object_X_Rotation_Angle) +OTFCMD(213,(_id _oid _angley),_Set_Object_Y_Rotation_Angle) +OTFCMD(214,(_id _oid _anglez),_Set_Object_Z_Rotation_Angle) +OTFCMD(215,(_id _oid _anglex _angley _anglez),_Set_Object_XYZ_Rotation_Angles) +OTFCMD(216,(_id _oid _distx),_Set_Object_X_Translation_Distance) +OTFCMD(217,(_id _oid _disty),_Set_Object_Y_Translation_Distance) +OTFCMD(218,(_id _oid _distz),_Set_Object_Z_Translation_Distance) +OTFCMD(219,(_id _oid _distx _disty _distz),_Set_Object_XYZ_Translation_Distances) +OTFCMD(220,(_id),_Render_To_Bitmap) + +#define VDUCMD(cmd, params, name) \ +typedef struct { \ + uint8_t m_category; \ + ARGS params \ +} VduCmd_##cmd##name; + +VDUCMD(0,(_ignore),_Ignore_data) +VDUCMD(1,(_char),_Print_character) +VDUCMD(2,(),_Enable_print_mode) +VDUCMD(3,(),_Disable_print_mode) +VDUCMD(4,(),_Print_at_text_cursor) +VDUCMD(5,(),_Print_at_graphics_cursor) +VDUCMD(6,(),_Enable_output_to_screen) +VDUCMD(7,(),_Beep) +VDUCMD(8,(),_Move_text_cursor_left) +VDUCMD(9,(),_Move_text_cursor_right) +VDUCMD(10,(),_Move_text_cursor_down) +VDUCMD(11,(),_Move_text_cursor_up) +VDUCMD(12,(),_Clear_text_viewport) +VDUCMD(13,(),_Move_text_cursor_boln) +VDUCMD(14,(),_Enable_auto_page_mode) +VDUCMD(15,(),_Disable_auto_page_mode) +VDUCMD(16,(),_Clear_graphics_viewport) +VDUCMD(17,(_color),_Set_text_color) +VDUCMD(18,(_mode _color),_Set_graphics_mode_color) +VDUCMD(19,(_logical _physical _red _green _blue),_Set_palette_color) +VDUCMD(20,(),_Reset_colors) +VDUCMD(21,(),_Disable_output_to_screen) +VDUCMD(22,(_mode),_Set_video_mode) +VDUCMD(23,(_char _r1 _r2 _r3 _r4 _r5 _r6 _r7 _r8),_Manipulate_text) +VDUCMD(24,(_left _bottom _right _top),_Define_graphics_viewport) +VDUCMD(25,(_mode _x _y),_Plot_graphics) +VDUCMD(26,(),_Reset_viewports) +VDUCMD(27,(_char),_Display_character) +VDUCMD(28,(_left8 _bottom8 _right8 _top8),_Define_text_viewport) +VDUCMD(29,(_x _y),_Set_graphics_origin) +VDUCMD(30,(),_Move_text_cursor_home) +VDUCMD(31,(_row8 _column8),_Set_text_tab_position) +VDUCMD(127,(),_Backspace) + +typedef union { + OtfCmd_0_Set_flags_for_primitive m_0_Set_flags_for_primitive; + OtfCmd_1_Set_primitive_position m_1_Set_primitive_position; + OtfCmd_2_Adjust_primitive_position m_2_Adjust_primitive_position; + OtfCmd_3_Delete_primitive m_3_Delete_primitive; + OtfCmd_4_Generate_code_for_primitive m_4_Generate_code_for_primitive; + OtfCmd_10_Create_primitive_Point m_10_Create_primitive_Point; + OtfCmd_20_Create_primitive_Line m_20_Create_primitive_Line; + OtfCmd_30_Create_primitive_Triangle_Outline m_30_Create_primitive_Triangle_Outline; + OtfCmd_31_Create_primitive_Solid_Triangle m_31_Create_primitive_Solid_Triangle; + OtfCmd_32_Create_primitive_Triangle_List_Outline m_32_Create_primitive_Triangle_List_Outline; + OtfCmd_33_Create_primitive_Solid_Triangle_List m_33_Create_primitive_Solid_Triangle_List; + OtfCmd_34_Create_primitive_Triangle_Fan_Outline m_34_Create_primitive_Triangle_Fan_Outline; + OtfCmd_35_Create_primitive_Solid_Triangle_Fan m_35_Create_primitive_Solid_Triangle_Fan; + OtfCmd_36_Create_primitive_Triangle_Strip_Outline m_36_Create_primitive_Triangle_Strip_Outline; + OtfCmd_37_Create_primitive_Solid_Triangle_Strip m_37_Create_primitive_Solid_Triangle_Strip; + OtfCmd_40_Create_primitive_Rectangle_Outline m_40_Create_primitive_Rectangle_Outline; + OtfCmd_41_Create_primitive_Solid_Rectangle m_41_Create_primitive_Solid_Rectangle; + OtfCmd_50_Create_primitive_Ellipse_Outline m_50_Create_primitive_Ellipse_Outline; + OtfCmd_51_Create_primitive_Solid_Ellipse m_51_Create_primitive_Solid_Ellipse; + OtfCmd_60_Create_primitive_Quad_Outline m_60_Create_primitive_Quad_Outline; + OtfCmd_61_Create_primitive_Solid_Quad m_61_Create_primitive_Solid_Quad; + OtfCmd_62_Create_primitive_Quad_List_Outline m_62_Create_primitive_Quad_List_Outline; + OtfCmd_63_Create_primitive_Solid_Quad_List m_63_Create_primitive_Solid_Quad_List; + OtfCmd_64_Create_primitive_Quad_Strip_Outline m_64_Create_primitive_Quad_Strip_Outline; + OtfCmd_65_Create_primitive_Solid_Quad_Strip m_65_Create_primitive_Solid_Quad_Strip; + OtfCmd_80_Create_primitive_Tile_Array m_80_Create_primitive_Tile_Array; + OtfCmd_81_Create_Solid_Bitmap_for_Tile_Array m_81_Create_Solid_Bitmap_for_Tile_Array; + OtfCmd_82_Create_Masked_Bitmap_for_Tile_Array m_82_Create_Masked_Bitmap_for_Tile_Array; + OtfCmd_83_Create_Transparent_Bitmap_for_Tile_Array m_83_Create_Transparent_Bitmap_for_Tile_Array; + OtfCmd_84_Set_bitmap_ID_for_tile_in_Tile_Array m_84_Set_bitmap_ID_for_tile_in_Tile_Array; + OtfCmd_85_Set_solid_bitmap_pixel_in_Tile_Array m_85_Set_solid_bitmap_pixel_in_Tile_Array; + OtfCmd_86_Set_masked_bitmap_pixel_in_Tile_Array m_86_Set_masked_bitmap_pixel_in_Tile_Array; + OtfCmd_87_Set_transparent_bitmap_pixel_in_Tile_Array m_87_Set_transparent_bitmap_pixel_in_Tile_Array; + OtfCmd_88_Set_solid_bitmap_pixels_in_Tile_Array m_88_Set_solid_bitmap_pixels_in_Tile_Array; + OtfCmd_89_Set_masked_bitmap_pixels_in_Tile_Array m_89_Set_masked_bitmap_pixels_in_Tile_Array; + OtfCmd_90_Set_transparent_bitmap_pixels_in_Tile_Array m_90_Set_transparent_bitmap_pixels_in_Tile_Array; + OtfCmd_100_Create_primitive_Tile_Map m_100_Create_primitive_Tile_Map; + OtfCmd_101_Create_Solid_Bitmap_for_Tile_Map m_101_Create_Solid_Bitmap_for_Tile_Map; + OtfCmd_102_Create_Masked_Bitmap_for_Tile_Map m_102_Create_Masked_Bitmap_for_Tile_Map; + OtfCmd_103_Create_Transparent_Bitmap_for_Tile_Map m_103_Create_Transparent_Bitmap_for_Tile_Map; + OtfCmd_104_Set_bitmap_ID_for_tile_in_Tile_Map m_104_Set_bitmap_ID_for_tile_in_Tile_Map; + OtfCmd_105_Set_solid_bitmap_pixel_in_Tile_Map m_105_Set_solid_bitmap_pixel_in_Tile_Map; + OtfCmd_106_Set_masked_bitmap_pixel_in_Tile_Map m_106_Set_masked_bitmap_pixel_in_Tile_Map; + OtfCmd_107_Set_transparent_bitmap_pixel_in_Tile_Map m_107_Set_transparent_bitmap_pixel_in_Tile_Map; + OtfCmd_108_Set_solid_bitmap_pixels_in_Tile_Map m_108_Set_solid_bitmap_pixels_in_Tile_Map; + OtfCmd_109_Set_masked_bitmap_pixels_in_Tile_Map m_109_Set_masked_bitmap_pixels_in_Tile_Map; + OtfCmd_110_Set_transparent_bitmap_pixels_in_Tile_Map m_110_Set_transparent_bitmap_pixels_in_Tile_Map; + OtfCmd_120_Create_primitive_Solid_Bitmap m_120_Create_primitive_Solid_Bitmap; + OtfCmd_121_Create_primitive_Masked_Bitmap m_121_Create_primitive_Masked_Bitmap; + OtfCmd_122_Create_primitive_Transparent_Bitmap m_122_Create_primitive_Transparent_Bitmap; + OtfCmd_123_Set_position_and_slice_solid_bitmap m_123_Set_position_and_slice_solid_bitmap; + OtfCmd_124_Set_position_and_slice_masked_bitmap m_124_Set_position_and_slice_masked_bitmap; + OtfCmd_125_Set_position_and_slice_transparent_bitmap m_125_Set_position_and_slice_transparent_bitmap; + OtfCmd_126_Adjust_position_and_slice_solid_bitmap m_126_Adjust_position_and_slice_solid_bitmap; + OtfCmd_127_Adjust_position_and_slice_masked_bitmap m_127_Adjust_position_and_slice_masked_bitmap; + OtfCmd_128_Adjust_position_and_slice_transparent_bitmap m_128_Adjust_position_and_slice_transparent_bitmap; + OtfCmd_129_Set_solid_bitmap_pixel m_129_Set_solid_bitmap_pixel; + OtfCmd_130_Set_masked_bitmap_pixel m_130_Set_masked_bitmap_pixel; + OtfCmd_131_Set_transparent_bitmap_pixel m_131_Set_transparent_bitmap_pixel; + OtfCmd_132_Set_solid_bitmap_pixels m_132_Set_solid_bitmap_pixels; + OtfCmd_133_Set_masked_bitmap_pixels m_133_Set_masked_bitmap_pixels; + OtfCmd_134_Set_transparent_bitmap_pixels m_134_Set_transparent_bitmap_pixels; + OtfCmd_135_Create_primitive_Reference_Solid_Bitmap m_135_Create_primitive_Reference_Solid_Bitmap; + OtfCmd_136_Create_primitive_Reference_Masked_Bitmap m_136_Create_primitive_Reference_Masked_Bitmap; + OtfCmd_137_Create_primitive_Reference_Transparent_Bitmap m_137_Create_primitive_Reference_Transparent_Bitmap; + OtfCmd_140_Create_primitive_Group m_140_Create_primitive_Group; + OtfCmd_145_Create_primitive_Duplicate_Solid_Bitmap m_145_Create_primitive_Duplicate_Solid_Bitmap; + OtfCmd_146_Create_primitive_Duplicate_Masked_Bitmap m_146_Create_primitive_Duplicate_Masked_Bitmap; + OtfCmd_147_Create_primitive_Duplicate_Transparent_Bitmap m_147_Create_primitive_Duplicate_Transparent_Bitmap; + OtfCmd_150_Create_primitive_Text_Area m_150_Create_primitive_Text_Area; + OtfCmd_151_Select_Active_Text_Area m_151_Select_Active_Text_Area; + OtfCmd_152_Define_Text_Area_Character m_152_Define_Text_Area_Character; + OtfCmd_153_Define_Text_Area_Character_Range m_153_Define_Text_Area_Character_Range; + OtfCmd_200_Create_primitive_Solid_Render m_200_Create_primitive_Solid_Render; + OtfCmd_201_Create_primitive_Masked_Render m_201_Create_primitive_Masked_Render; + OtfCmd_202_Create_primitive_Transparent_Render m_202_Create_primitive_Transparent_Render; + OtfCmd_203_Define_Mesh_Vertices m_203_Define_Mesh_Vertices; + OtfCmd_204_Set_Mesh_Vertex_Indices m_204_Set_Mesh_Vertex_Indices; + OtfCmd_205_Define_Texture_Coordinates m_205_Define_Texture_Coordinates; + OtfCmd_206_Set_Texture_Coordinate_Indices m_206_Set_Texture_Coordinate_Indices; + OtfCmd_207_Create_Object m_207_Create_Object; + OtfCmd_208_Set_Object_X_Scale_Factor m_208_Set_Object_X_Scale_Factor; + OtfCmd_209_Set_Object_Y_Scale_Factor m_209_Set_Object_Y_Scale_Factor; + OtfCmd_210_Set_Object_Z_Scale_Factor m_210_Set_Object_Z_Scale_Factor; + OtfCmd_211_Set_Object_XYZ_Scale_Factors m_211_Set_Object_XYZ_Scale_Factors; + OtfCmd_212_Set_Object_X_Rotation_Angle m_212_Set_Object_X_Rotation_Angle; + OtfCmd_213_Set_Object_Y_Rotation_Angle m_213_Set_Object_Y_Rotation_Angle; + OtfCmd_214_Set_Object_Z_Rotation_Angle m_214_Set_Object_Z_Rotation_Angle; + OtfCmd_215_Set_Object_XYZ_Rotation_Angles m_215_Set_Object_XYZ_Rotation_Angles; + OtfCmd_216_Set_Object_X_Translation_Distance m_216_Set_Object_X_Translation_Distance; + OtfCmd_217_Set_Object_Y_Translation_Distance m_217_Set_Object_Y_Translation_Distance; + OtfCmd_218_Set_Object_Z_Translation_Distance m_218_Set_Object_Z_Translation_Distance; + OtfCmd_219_Set_Object_XYZ_Translation_Distances m_219_Set_Object_XYZ_Translation_Distances; + OtfCmd_220_Render_To_Bitmap m_220_Render_To_Bitmap; +} OtfCmdUnion; + +typedef union { + VduCmd_0_Ignore_data m_0_Ignore_data; + VduCmd_1_Print_character m_1_Print_character; + VduCmd_2_Enable_print_mode m_2_Enable_print_mode; + VduCmd_3_Disable_print_mode m_3_Disable_print_mode; + VduCmd_4_Print_at_text_cursor m_4_Print_at_text_cursor; + VduCmd_5_Print_at_graphics_cursor m_5_Print_at_graphics_cursor; + VduCmd_6_Enable_output_to_screen m_6_Enable_output_to_screen; + VduCmd_7_Beep m_7_Beep; + VduCmd_8_Move_text_cursor_left m_8_Move_text_cursor_left; + VduCmd_9_Move_text_cursor_right m_9_Move_text_cursor_right; + VduCmd_10_Move_text_cursor_down m_10_Move_text_cursor_down; + VduCmd_11_Move_text_cursor_up m_11_Move_text_cursor_up; + VduCmd_12_Clear_text_viewport m_12_Clear_text_viewport; + VduCmd_13_Move_text_cursor_boln m_13_Move_text_cursor_boln; + VduCmd_14_Enable_auto_page_mode m_14_Enable_auto_page_mode; + VduCmd_15_Disable_auto_page_mode m_15_Disable_auto_page_mode; + VduCmd_16_Clear_graphics_viewport m_16_Clear_graphics_viewport; + VduCmd_17_Set_text_color m_17_Set_text_color; + VduCmd_18_Set_graphics_mode_color m_18_Set_graphics_mode_color; + VduCmd_19_Set_palette_color m_19_Set_palette_color; + VduCmd_20_Reset_colors m_20_Reset_colors; + VduCmd_21_Disable_output_to_screen m_21_Disable_output_to_screen; + VduCmd_22_Set_video_mode m_22_Set_video_mode; + VduCmd_23_Manipulate_text m_23_Manipulate_text; + VduCmd_24_Define_graphics_viewport m_24_Define_graphics_viewport; + VduCmd_25_Plot_graphics m_25_Plot_graphics; + VduCmd_26_Reset_viewports m_26_Reset_viewports; + VduCmd_27_Display_character m_27_Display_character; + VduCmd_28_Define_text_viewport m_28_Define_text_viewport; + VduCmd_29_Set_graphics_origin m_29_Set_graphics_origin; + VduCmd_30_Move_text_cursor_home m_30_Move_text_cursor_home; + VduCmd_31_Set_text_tab_position m_31_Set_text_tab_position; + VduCmd_127_Backspace m_127_Backspace; +} VduCmdUnion; + +#pragma pack(pop) diff --git a/video/src/di_common_functions.S b/video/src/di_common_functions.S new file mode 100644 index 00000000..9cff3d2e --- /dev/null +++ b/video/src/di_common_functions.S @@ -0,0 +1,8511 @@ +// di_common_functions.S - Low-level assembler functions for setting pixels +// +// Copyright (c) 2023 Curtis Whitley +// +// The functions below are intended to be called using the CALL0 or CALLX0 +// instructions, and are thus not intended to be called directly from C++, +// which would require using instructions such as CALL8. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + + .section .text + .align 4 + + .global fcn_draw_256_pixels_in_loop + .global fcn_draw_128_pixels + .global fcn_draw_128_pixels_last + .global fcn_draw_64_pixels + .global fcn_draw_64_pixels_last + .global fcn_draw_32_pixels + .global fcn_draw_32_pixels_last + .global fcn_draw_16_pixels + .global fcn_draw_16_pixels_last + .global fcn_draw_8_pixels + .global fcn_draw_8_pixels_last + .global fcn_get_blend_25_for_4_pixels + .global fcn_get_blend_50_for_4_pixels + .global fcn_get_blend_75_for_4_pixels + .global fcn_dummy + + .global fcn_skip_draw_256_pixels_in_loop + .global fcn_skip_draw_128_pixels + .global fcn_skip_draw_64_pixels + .global fcn_skip_draw_32_pixels + .global fcn_skip_draw_16_pixels + .global fcn_skip_draw_8_pixels + + .global fcn_copy_words_in_loop + + .global fcn_copy_256_pixels_in_loop + .global fcn_copy_128_pixels + .global fcn_copy_128_pixels_last + .global fcn_copy_64_pixels + .global fcn_copy_64_pixels_last + .global fcn_copy_32_pixels + .global fcn_copy_32_pixels_last + .global fcn_copy_16_pixels + .global fcn_copy_16_pixels_last + .global fcn_copy_8_pixels + .global fcn_copy_8_pixels_last + + .global fcn_skip_copy_256_pixels_in_loop + .global fcn_skip_copy_128_pixels + .global fcn_skip_copy_64_pixels + .global fcn_skip_copy_32_pixels + .global fcn_skip_copy_16_pixels + .global fcn_skip_copy_8_pixels + + .global fcn_color_blend_25_for_256_pixels_in_loop + .global fcn_color_blend_25_for_128_pixels + .global fcn_color_blend_25_for_128_pixels_last + .global fcn_color_blend_25_for_64_pixels + .global fcn_color_blend_25_for_64_pixels_last + .global fcn_color_blend_25_for_32_pixels + .global fcn_color_blend_25_for_32_pixels_last + .global fcn_color_blend_25_for_16_pixels + .global fcn_color_blend_25_for_16_pixels_last + .global fcn_color_blend_25_for_8_pixels + .global fcn_color_blend_25_for_8_pixels_last + .global fcn_color_blend_25_for_1_pixel_at_offset_0 + .global fcn_color_blend_25_for_1_pixel_at_offset_0_last + .global fcn_color_blend_25_for_1_pixel_at_offset_1 + .global fcn_color_blend_25_for_1_pixel_at_offset_1_last + .global fcn_color_blend_25_for_1_pixel_at_offset_2 + .global fcn_color_blend_25_for_1_pixel_at_offset_2_last + .global fcn_color_blend_25_for_1_pixel_at_offset_3 + .global fcn_color_blend_25_for_1_pixel_at_offset_3_last + .global fcn_color_blend_25_for_2_pixels_at_offset_0 + .global fcn_color_blend_25_for_2_pixels_at_offset_0_last + .global fcn_color_blend_25_for_2_pixels_at_offset_1 + .global fcn_color_blend_25_for_2_pixels_at_offset_1_last + .global fcn_color_blend_25_for_2_pixels_at_offset_2 + .global fcn_color_blend_25_for_2_pixels_at_offset_2_last + .global fcn_color_blend_25_for_3_pixels_at_offset_0 + .global fcn_color_blend_25_for_3_pixels_at_offset_0_last + .global fcn_color_blend_25_for_3_pixels_at_offset_1 + .global fcn_color_blend_25_for_3_pixels_at_offset_1_last + .global fcn_color_blend_25_for_4_pixels_at_offset_0 + .global fcn_color_blend_25_for_4_pixels_at_offset_0_last + + .global fcn_color_blend_50_for_256_pixels_in_loop + .global fcn_color_blend_50_for_128_pixels + .global fcn_color_blend_50_for_128_pixels_last + .global fcn_color_blend_50_for_64_pixels + .global fcn_color_blend_50_for_64_pixels_last + .global fcn_color_blend_50_for_32_pixels + .global fcn_color_blend_50_for_32_pixels_last + .global fcn_color_blend_50_for_16_pixels + .global fcn_color_blend_50_for_16_pixels_last + .global fcn_color_blend_50_for_8_pixels + .global fcn_color_blend_50_for_8_pixels_last + .global fcn_color_blend_50_for_1_pixel_at_offset_0 + .global fcn_color_blend_50_for_1_pixel_at_offset_0_last + .global fcn_color_blend_50_for_1_pixel_at_offset_1 + .global fcn_color_blend_50_for_1_pixel_at_offset_1_last + .global fcn_color_blend_50_for_1_pixel_at_offset_2 + .global fcn_color_blend_50_for_1_pixel_at_offset_2_last + .global fcn_color_blend_50_for_1_pixel_at_offset_3 + .global fcn_color_blend_50_for_1_pixel_at_offset_3_last + .global fcn_color_blend_50_for_2_pixels_at_offset_0 + .global fcn_color_blend_50_for_2_pixels_at_offset_0_last + .global fcn_color_blend_50_for_2_pixels_at_offset_1 + .global fcn_color_blend_50_for_2_pixels_at_offset_1_last + .global fcn_color_blend_50_for_2_pixels_at_offset_2 + .global fcn_color_blend_50_for_2_pixels_at_offset_2_last + .global fcn_color_blend_50_for_3_pixels_at_offset_0 + .global fcn_color_blend_50_for_3_pixels_at_offset_0_last + .global fcn_color_blend_50_for_3_pixels_at_offset_1 + .global fcn_color_blend_50_for_3_pixels_at_offset_1_last + .global fcn_color_blend_50_for_4_pixels_at_offset_0 + .global fcn_color_blend_50_for_4_pixels_at_offset_0_last + + .global fcn_color_blend_75_for_256_pixels_in_loop + .global fcn_color_blend_75_for_128_pixels + .global fcn_color_blend_75_for_128_pixels_last + .global fcn_color_blend_75_for_64_pixels + .global fcn_color_blend_75_for_64_pixels_last + .global fcn_color_blend_75_for_32_pixels + .global fcn_color_blend_75_for_32_pixels_last + .global fcn_color_blend_75_for_16_pixels + .global fcn_color_blend_75_for_16_pixels_last + .global fcn_color_blend_75_for_8_pixels + .global fcn_color_blend_75_for_8_pixels_last + .global fcn_color_blend_75_for_1_pixel_at_offset_0 + .global fcn_color_blend_75_for_1_pixel_at_offset_0_last + .global fcn_color_blend_75_for_1_pixel_at_offset_1 + .global fcn_color_blend_75_for_1_pixel_at_offset_1_last + .global fcn_color_blend_75_for_1_pixel_at_offset_2 + .global fcn_color_blend_75_for_1_pixel_at_offset_2_last + .global fcn_color_blend_75_for_1_pixel_at_offset_3 + .global fcn_color_blend_75_for_1_pixel_at_offset_3_last + .global fcn_color_blend_75_for_2_pixels_at_offset_0 + .global fcn_color_blend_75_for_2_pixels_at_offset_0_last + .global fcn_color_blend_75_for_2_pixels_at_offset_1 + .global fcn_color_blend_75_for_2_pixels_at_offset_1_last + .global fcn_color_blend_75_for_2_pixels_at_offset_2 + .global fcn_color_blend_75_for_2_pixels_at_offset_2_last + .global fcn_color_blend_75_for_3_pixels_at_offset_0 + .global fcn_color_blend_75_for_3_pixels_at_offset_0_last + .global fcn_color_blend_75_for_3_pixels_at_offset_1 + .global fcn_color_blend_75_for_3_pixels_at_offset_1_last + .global fcn_color_blend_75_for_4_pixels_at_offset_0 + .global fcn_color_blend_75_for_4_pixels_at_offset_0_last + + .global fcn_src_blend_25_for_256_pixels_in_loop + .global fcn_src_blend_25_for_128_pixels + .global fcn_src_blend_25_for_128_pixels_last + .global fcn_src_blend_25_for_64_pixels + .global fcn_src_blend_25_for_64_pixels_last + .global fcn_src_blend_25_for_32_pixels + .global fcn_src_blend_25_for_32_pixels_last + .global fcn_src_blend_25_for_16_pixels + .global fcn_src_blend_25_for_16_pixels_last + .global fcn_src_blend_25_for_8_pixels + .global fcn_src_blend_25_for_8_pixels_last + .global fcn_src_blend_25_for_1_pixel_at_offset_0 + .global fcn_src_blend_25_for_1_pixel_at_offset_0_last + .global fcn_src_blend_25_for_1_pixel_at_offset_1 + .global fcn_src_blend_25_for_1_pixel_at_offset_1_last + .global fcn_src_blend_25_for_1_pixel_at_offset_2 + .global fcn_src_blend_25_for_1_pixel_at_offset_2_last + .global fcn_src_blend_25_for_1_pixel_at_offset_3 + .global fcn_src_blend_25_for_1_pixel_at_offset_3_last + .global fcn_src_blend_25_for_2_pixels_at_offset_0 + .global fcn_src_blend_25_for_2_pixels_at_offset_0_last + .global fcn_src_blend_25_for_2_pixels_at_offset_1 + .global fcn_src_blend_25_for_2_pixels_at_offset_1_last + .global fcn_src_blend_25_for_2_pixels_at_offset_2 + .global fcn_src_blend_25_for_2_pixels_at_offset_2_last + .global fcn_src_blend_25_for_3_pixels_at_offset_0 + .global fcn_src_blend_25_for_3_pixels_at_offset_0_last + .global fcn_src_blend_25_for_3_pixels_at_offset_1 + .global fcn_src_blend_25_for_3_pixels_at_offset_1_last + .global fcn_src_blend_25_for_4_pixels_at_offset_0 + .global fcn_src_blend_25_for_4_pixels_at_offset_0_last + + .global fcn_src_blend_50_for_256_pixels_in_loop + .global fcn_src_blend_50_for_128_pixels + .global fcn_src_blend_50_for_128_pixels_last + .global fcn_src_blend_50_for_64_pixels + .global fcn_src_blend_50_for_64_pixels_last + .global fcn_src_blend_50_for_32_pixels + .global fcn_src_blend_50_for_32_pixels_last + .global fcn_src_blend_50_for_16_pixels + .global fcn_src_blend_50_for_16_pixels_last + .global fcn_src_blend_50_for_8_pixels + .global fcn_src_blend_50_for_8_pixels_last + .global fcn_src_blend_50_for_1_pixel_at_offset_0 + .global fcn_src_blend_50_for_1_pixel_at_offset_0_last + .global fcn_src_blend_50_for_1_pixel_at_offset_1 + .global fcn_src_blend_50_for_1_pixel_at_offset_1_last + .global fcn_src_blend_50_for_1_pixel_at_offset_2 + .global fcn_src_blend_50_for_1_pixel_at_offset_2_last + .global fcn_src_blend_50_for_1_pixel_at_offset_3 + .global fcn_src_blend_50_for_1_pixel_at_offset_3_last + .global fcn_src_blend_50_for_2_pixels_at_offset_0 + .global fcn_src_blend_50_for_2_pixels_at_offset_0_last + .global fcn_src_blend_50_for_2_pixels_at_offset_1 + .global fcn_src_blend_50_for_2_pixels_at_offset_1_last + .global fcn_src_blend_50_for_2_pixels_at_offset_2 + .global fcn_src_blend_50_for_2_pixels_at_offset_2_last + .global fcn_src_blend_50_for_3_pixels_at_offset_0 + .global fcn_src_blend_50_for_3_pixels_at_offset_0_last + .global fcn_src_blend_50_for_3_pixels_at_offset_1 + .global fcn_src_blend_50_for_3_pixels_at_offset_1_last + .global fcn_src_blend_50_for_4_pixels_at_offset_0 + .global fcn_src_blend_50_for_4_pixels_at_offset_0_last + + .global fcn_src_blend_75_for_256_pixels_in_loop + .global fcn_src_blend_75_for_128_pixels + .global fcn_src_blend_75_for_128_pixels_last + .global fcn_src_blend_75_for_64_pixels + .global fcn_src_blend_75_for_64_pixels_last + .global fcn_src_blend_75_for_32_pixels + .global fcn_src_blend_75_for_32_pixels_last + .global fcn_src_blend_75_for_16_pixels + .global fcn_src_blend_75_for_16_pixels_last + .global fcn_src_blend_75_for_8_pixels + .global fcn_src_blend_75_for_8_pixels_last + .global fcn_src_blend_75_for_1_pixel_at_offset_0 + .global fcn_src_blend_75_for_1_pixel_at_offset_0_last + .global fcn_src_blend_75_for_1_pixel_at_offset_1 + .global fcn_src_blend_75_for_1_pixel_at_offset_1_last + .global fcn_src_blend_75_for_1_pixel_at_offset_2 + .global fcn_src_blend_75_for_1_pixel_at_offset_2_last + .global fcn_src_blend_75_for_1_pixel_at_offset_3 + .global fcn_src_blend_75_for_1_pixel_at_offset_3_last + .global fcn_src_blend_75_for_2_pixels_at_offset_0 + .global fcn_src_blend_75_for_2_pixels_at_offset_0_last + .global fcn_src_blend_75_for_2_pixels_at_offset_1 + .global fcn_src_blend_75_for_2_pixels_at_offset_1_last + .global fcn_src_blend_75_for_2_pixels_at_offset_2 + .global fcn_src_blend_75_for_2_pixels_at_offset_2_last + .global fcn_src_blend_75_for_3_pixels_at_offset_0 + .global fcn_src_blend_75_for_3_pixels_at_offset_0_last + .global fcn_src_blend_75_for_3_pixels_at_offset_1 + .global fcn_src_blend_75_for_3_pixels_at_offset_1_last + .global fcn_src_blend_75_for_4_pixels_at_offset_0 + .global fcn_src_blend_75_for_4_pixels_at_offset_0_last + +// Input registers: +#define REG_RETURN_ADDR a0 +#define REG_STACK_PTR a1 +#define REG_THIS_PTR a2 +#define REG_LINE_PTR a3 +#define REG_LINE_INDEX a4 +#define REG_DST_DRAW_X a5 +#define REG_SRC_PIXEL_PTR a6 +// Temporary registers: +#define REG_SAVE_RET_DEEP a3 +#define REG_DST_PIXEL_PTR a5 +#define REG_PIXEL_COLOR a7 +#define REG_LOOP_INDEX a4 +#define REG_SRC_PIXELS a8 +#define REG_SRC_BR_PIXELS a9 +#define REG_DST_BR_PIXELS a10 +#define REG_SRC_G_PIXELS a8 +#define REG_DST_G_PIXELS a11 +#define REG_ABS_Y a12 +#define REG_DOUBLE_COLOR a12 +#define REG_ISOLATE_BR a13 +#define REG_ISOLATE_G a14 +#define REG_JUMP_ADDRESS a14 +#define REG_SAVE_COLOR a15 // also the transparent color when copying pixels + +#define FIX_OFFSET(off) ((off)^2) + + .macro set_1_pixel_at_offset_0 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro set_1_pixel_at_offset_1 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + .endm + + .macro set_1_pixel_at_offset_2 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro set_1_pixel_at_offset_3 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + .endm + + .macro set_2_pixels_at_offset_0 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro set_2_pixels_at_offset_1 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro set_2_pixels_at_offset_2 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro set_3_pixels_at_offset_0 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro set_3_pixels_at_offset_1 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro set_4_pixels_at_offset offset + s32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, \offset + .endm + + .macro copy_0xxx_pixels_at_offset_0 + l8ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(0) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro copy_x1xx_pixels_at_offset_1 + l8ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(1) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + .endm + + .macro copy_x1x3_pixels_at_offset_1 + l32i REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0 + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 8 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + .endm + + .macro copy_01x3_pixels_at_offset_0 + l32i REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro copy_xx2x_pixels_at_offset_2 + l8ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro copy_0x2x_pixels_at_offset_0 + l32i REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro copy_xxx3_pixels_at_offset_3 + l8ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(3) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + .endm + + .macro copy_0xx3_pixels_at_offset_0 + l32i REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0 + l8ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(3) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 24 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro copy_0x23_pixels_at_offset_0 + l32i REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, 0 + l8ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(3) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro copy_01xx_pixels_at_offset_0 + l16ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(0) + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro copy_x12x_pixels_at_offset_1 + l16ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(1) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + l16ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro copy_xx23_pixels_at_offset_2 + l16ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2) + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro copy_012x_pixels_at_offset_0 + l16ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(0) + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + l16ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro copy_x123_pixels_at_offset_1 + l8ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(1) + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + l16ui REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, FIX_OFFSET(2) + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro copy_4_pixels_at_offset word_offset + l32i REG_PIXEL_COLOR, REG_SRC_PIXEL_PTR, \word_offset + s32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, \word_offset + .endm + +// In REG_PIXEL_COLOR +// 1 0 3 2 Logical X offset +// 3 2 1 0 Physical byte offset +// 31..24 23..16 15..08 07..00 +// pixel1 pixel0 pixel3 pixel2 + + .macro blend_for_0xxx_pixels_at_offset_0 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro blend_for_x1xx_pixels_at_offset_1 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 24 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + .endm + + .macro blend_for_0xx3_pixels_at_offset_0 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 24 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro blend_for_01x3_pixels_at_offset_0 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro blend_for_x1x3_pixels_at_offset_1 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 8 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + .endm + + .macro blend_for_0x2x_pixels_at_offset_0 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro blend_for_0x23_pixels_at_offset_0 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro blend_for_xx2x_pixels_at_offset_2 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro blend_for_xxx3_pixels_at_offset_3 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 8 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(3) + .endm + + .macro blend_for_01xx_pixels_at_offset_0 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro blend_for_x12x_pixels_at_offset_1 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 24 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + .endm + + .macro blend_for_xx23_pixels_at_offset_2 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + .endm + + .macro blend_for_012x_pixels_at_offset_0 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 16 + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(0) + .endm + + .macro blend_for_x123_pixels_at_offset_1 pct src + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, 0 + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, 0 + call0 fcn_get_blend_\pct\()_for_4_pixels + s16i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(2) + srli REG_PIXEL_COLOR, REG_PIXEL_COLOR, 24 + s8i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, FIX_OFFSET(1) + .endm + + .macro blend_for_4_pixels_at_offset pct src wo + .ifc \src\(),src + l32i REG_SRC_PIXELS, REG_SRC_PIXEL_PTR, \wo + .else + mov REG_SRC_PIXELS, REG_SAVE_COLOR + .endif + l32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, \wo + call0 fcn_get_blend_\pct\()_for_4_pixels + s32i REG_PIXEL_COLOR, REG_DST_PIXEL_PTR, \wo + .endm + + .macro enter_blend_fcn + mov REG_SAVE_RET_DEEP, REG_RETURN_ADDR + .endm + + .macro leave_blend_fcn + jx REG_SAVE_RET_DEEP + .endm + + .align 4 +fcn_draw_256_pixels_in_loop: +begin_loop: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + set_4_pixels_at_offset 16 + set_4_pixels_at_offset 20 + set_4_pixels_at_offset 24 + set_4_pixels_at_offset 28 + set_4_pixels_at_offset 32 + set_4_pixels_at_offset 36 + set_4_pixels_at_offset 40 + set_4_pixels_at_offset 44 + set_4_pixels_at_offset 48 + set_4_pixels_at_offset 52 + set_4_pixels_at_offset 56 + set_4_pixels_at_offset 60 + set_4_pixels_at_offset 64 + set_4_pixels_at_offset 68 + set_4_pixels_at_offset 72 + set_4_pixels_at_offset 76 + set_4_pixels_at_offset 80 + set_4_pixels_at_offset 84 + set_4_pixels_at_offset 88 + set_4_pixels_at_offset 92 + set_4_pixels_at_offset 96 + set_4_pixels_at_offset 100 + set_4_pixels_at_offset 104 + set_4_pixels_at_offset 108 + set_4_pixels_at_offset 112 + set_4_pixels_at_offset 116 + set_4_pixels_at_offset 120 + set_4_pixels_at_offset 124 + + set_4_pixels_at_offset 128 + set_4_pixels_at_offset 132 + set_4_pixels_at_offset 136 + set_4_pixels_at_offset 140 + set_4_pixels_at_offset 144 + set_4_pixels_at_offset 148 + set_4_pixels_at_offset 152 + set_4_pixels_at_offset 156 + set_4_pixels_at_offset 160 + set_4_pixels_at_offset 164 + set_4_pixels_at_offset 168 + set_4_pixels_at_offset 172 + set_4_pixels_at_offset 176 + set_4_pixels_at_offset 180 + set_4_pixels_at_offset 184 + set_4_pixels_at_offset 188 + set_4_pixels_at_offset 192 + set_4_pixels_at_offset 196 + set_4_pixels_at_offset 200 + set_4_pixels_at_offset 204 + set_4_pixels_at_offset 208 + set_4_pixels_at_offset 212 + set_4_pixels_at_offset 216 + set_4_pixels_at_offset 220 + set_4_pixels_at_offset 224 + set_4_pixels_at_offset 228 + set_4_pixels_at_offset 232 + set_4_pixels_at_offset 236 + set_4_pixels_at_offset 240 + set_4_pixels_at_offset 244 + set_4_pixels_at_offset 248 + set_4_pixels_at_offset 252 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_loop + j begin_loop +end_loop: + ret + + .align 4 +fcn_draw_128_pixels: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + set_4_pixels_at_offset 16 + set_4_pixels_at_offset 20 + set_4_pixels_at_offset 24 + set_4_pixels_at_offset 28 + set_4_pixels_at_offset 32 + set_4_pixels_at_offset 36 + set_4_pixels_at_offset 40 + set_4_pixels_at_offset 44 + set_4_pixels_at_offset 48 + set_4_pixels_at_offset 52 + set_4_pixels_at_offset 56 + set_4_pixels_at_offset 60 + set_4_pixels_at_offset 64 + set_4_pixels_at_offset 68 + set_4_pixels_at_offset 72 + set_4_pixels_at_offset 76 + set_4_pixels_at_offset 80 + set_4_pixels_at_offset 84 + set_4_pixels_at_offset 88 + set_4_pixels_at_offset 92 + set_4_pixels_at_offset 96 + set_4_pixels_at_offset 100 + set_4_pixels_at_offset 104 + set_4_pixels_at_offset 108 + set_4_pixels_at_offset 112 + set_4_pixels_at_offset 116 + set_4_pixels_at_offset 120 + set_4_pixels_at_offset 124 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + ret + + .align 4 +fcn_draw_128_pixels_last: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + set_4_pixels_at_offset 16 + set_4_pixels_at_offset 20 + set_4_pixels_at_offset 24 + set_4_pixels_at_offset 28 + set_4_pixels_at_offset 32 + set_4_pixels_at_offset 36 + set_4_pixels_at_offset 40 + set_4_pixels_at_offset 44 + set_4_pixels_at_offset 48 + set_4_pixels_at_offset 52 + set_4_pixels_at_offset 56 + set_4_pixels_at_offset 60 + set_4_pixels_at_offset 64 + set_4_pixels_at_offset 68 + set_4_pixels_at_offset 72 + set_4_pixels_at_offset 76 + set_4_pixels_at_offset 80 + set_4_pixels_at_offset 84 + set_4_pixels_at_offset 88 + set_4_pixels_at_offset 92 + set_4_pixels_at_offset 96 + set_4_pixels_at_offset 100 + set_4_pixels_at_offset 104 + set_4_pixels_at_offset 108 + set_4_pixels_at_offset 112 + set_4_pixels_at_offset 116 + set_4_pixels_at_offset 120 + set_4_pixels_at_offset 124 + ret + + .align 4 +fcn_draw_64_pixels: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + set_4_pixels_at_offset 16 + set_4_pixels_at_offset 20 + set_4_pixels_at_offset 24 + set_4_pixels_at_offset 28 + set_4_pixels_at_offset 32 + set_4_pixels_at_offset 36 + set_4_pixels_at_offset 40 + set_4_pixels_at_offset 44 + set_4_pixels_at_offset 48 + set_4_pixels_at_offset 52 + set_4_pixels_at_offset 56 + set_4_pixels_at_offset 60 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + ret + + .align 4 +fcn_draw_64_pixels_last: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + set_4_pixels_at_offset 16 + set_4_pixels_at_offset 20 + set_4_pixels_at_offset 24 + set_4_pixels_at_offset 28 + set_4_pixels_at_offset 32 + set_4_pixels_at_offset 36 + set_4_pixels_at_offset 40 + set_4_pixels_at_offset 44 + set_4_pixels_at_offset 48 + set_4_pixels_at_offset 52 + set_4_pixels_at_offset 56 + set_4_pixels_at_offset 60 + ret + + .align 4 +fcn_draw_32_pixels: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + set_4_pixels_at_offset 16 + set_4_pixels_at_offset 20 + set_4_pixels_at_offset 24 + set_4_pixels_at_offset 28 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + ret + + .align 4 +fcn_draw_32_pixels_last: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + set_4_pixels_at_offset 16 + set_4_pixels_at_offset 20 + set_4_pixels_at_offset 24 + set_4_pixels_at_offset 28 + ret + + .align 4 +fcn_draw_16_pixels: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + ret + + .align 4 +fcn_draw_16_pixels_last: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + set_4_pixels_at_offset 8 + set_4_pixels_at_offset 12 + ret + + .align 4 +fcn_draw_8_pixels: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + ret + + .align 4 +fcn_draw_8_pixels_last: + set_4_pixels_at_offset 0 + set_4_pixels_at_offset 4 + ret + + .align 4 +fcn_skip_draw_256_pixels_in_loop: +begin_skip_draw_loop: + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_skip_draw_loop + j begin_skip_draw_loop +end_skip_draw_loop: + ret + + .align 4 +fcn_skip_draw_128_pixels: + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + ret + + .align 4 +fcn_skip_draw_64_pixels: + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + ret + + .align 4 +fcn_skip_draw_32_pixels: + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + ret + + .align 4 +fcn_skip_draw_16_pixels: + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + ret + + .align 4 +fcn_skip_draw_8_pixels: + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + ret + + .align 4 +fcn_get_blend_25_for_4_pixels: + // 00BBGGRR 00BBGGRR 00BBGGRR 00BBGGRR - source or destination pixels + // 00110011 00110011 00110011 00110011 - isolate blue & red + // 00001100 00001100 00001100 00001100 - isolate green + and REG_SRC_BR_PIXELS, REG_SRC_PIXELS, REG_ISOLATE_BR // src blue & red (no green) + and REG_DST_BR_PIXELS, REG_PIXEL_COLOR, REG_ISOLATE_BR // dst blue & red (no green) + slli REG_DOUBLE_COLOR, REG_DST_BR_PIXELS, 1 // double the dst color values + add REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, REG_DOUBLE_COLOR // add dst color values again (total of 3X) + add REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, REG_SRC_BR_PIXELS // sum of blue & sum of red + srli REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, 2 // averages of mixed blue & mixed red, in 4 bits each + and REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, REG_ISOLATE_BR // averages in 2 bits each + + and REG_SRC_G_PIXELS, REG_SRC_PIXELS, REG_ISOLATE_G // src green (no red or blue) + and REG_DST_G_PIXELS, REG_PIXEL_COLOR, REG_ISOLATE_G // dst green (no red or blue) + slli REG_DOUBLE_COLOR, REG_DST_G_PIXELS, 1 // double the dst color values + add REG_DST_G_PIXELS, REG_DST_G_PIXELS, REG_DOUBLE_COLOR // add dst color values again (total of 3X) + add REG_DST_G_PIXELS, REG_DST_G_PIXELS, REG_SRC_G_PIXELS // sum of green + srli REG_DST_G_PIXELS, REG_DST_G_PIXELS, 2 // averages of mixed green, in 4 bits each + and REG_DST_G_PIXELS, REG_DST_G_PIXELS, REG_ISOLATE_G // averages in 2 bits each + + or REG_PIXEL_COLOR, REG_DST_BR_PIXELS, REG_DST_G_PIXELS // 4 mixed pixels + ret + + .align 4 +fcn_get_blend_50_for_4_pixels: + and REG_SRC_BR_PIXELS, REG_SRC_PIXELS, REG_ISOLATE_BR // src blue & red (no green) + and REG_DST_BR_PIXELS, REG_PIXEL_COLOR, REG_ISOLATE_BR // dst blue & red (no green) + add REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, REG_SRC_BR_PIXELS // sum of blue & sum of red + srli REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, 1 // averages of mixed blue & mixed red, in 3 bits each + and REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, REG_ISOLATE_BR // averages in 2 bits each + + and REG_SRC_G_PIXELS, REG_SRC_PIXELS, REG_ISOLATE_G // src green (no red or blue) + and REG_DST_G_PIXELS, REG_PIXEL_COLOR, REG_ISOLATE_G // dst green (no red or blue) + add REG_DST_G_PIXELS, REG_DST_G_PIXELS, REG_SRC_G_PIXELS // sum of green + srli REG_DST_G_PIXELS, REG_DST_G_PIXELS, 1 // averages of mixed green, in 3 bits each + and REG_DST_G_PIXELS, REG_DST_G_PIXELS, REG_ISOLATE_G // averages in 2 bits each + + or REG_PIXEL_COLOR, REG_DST_BR_PIXELS, REG_DST_G_PIXELS // 4 mixed pixels + ret + + .align 4 +fcn_get_blend_75_for_4_pixels: + and REG_SRC_BR_PIXELS, REG_SRC_PIXELS, REG_ISOLATE_BR // src blue & red (no green) + and REG_DST_BR_PIXELS, REG_PIXEL_COLOR, REG_ISOLATE_BR // dst blue & red (no green) + slli REG_DOUBLE_COLOR, REG_SRC_BR_PIXELS, 1 // double the src color values + add REG_SRC_BR_PIXELS, REG_SRC_BR_PIXELS, REG_DOUBLE_COLOR // add src color values again (total of 3X) + add REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, REG_SRC_BR_PIXELS // sum of blue & sum of red + srli REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, 2 // averages of mixed blue & mixed red, in 4 bits each + and REG_DST_BR_PIXELS, REG_DST_BR_PIXELS, REG_ISOLATE_BR // averages in 2 bits each + + and REG_SRC_G_PIXELS, REG_SRC_PIXELS, REG_ISOLATE_G // src green (no red or blue) + and REG_DST_G_PIXELS, REG_PIXEL_COLOR, REG_ISOLATE_G // dst green (no red or blue) + slli REG_DOUBLE_COLOR, REG_SRC_G_PIXELS, 1 // double the src color values + add REG_SRC_G_PIXELS, REG_SRC_G_PIXELS, REG_DOUBLE_COLOR // add src color values again (total of 3X) + add REG_DST_G_PIXELS, REG_DST_G_PIXELS, REG_SRC_G_PIXELS // sum of green + srli REG_DST_G_PIXELS, REG_DST_G_PIXELS, 2 // averages of mixed green, in 4 bits each + and REG_DST_G_PIXELS, REG_DST_G_PIXELS, REG_ISOLATE_G // averages in 2 bits each + + or REG_PIXEL_COLOR, REG_DST_BR_PIXELS, REG_DST_G_PIXELS // 4 mixed pixels + ret + + .align 4 +fcn_dummy: + ret + +// a0: return address +// a1: stack pointer +// a2: destination pointer +// a3: source pointer +// a4: number of words + .align 4 +fcn_copy_words_in_loop: + entry sp,32 + loop a4,end_loop_words + l32i a5,a3,0 + s32i a5,a2,0 + addi a3,a3,4 + addi a2,a2,4 +end_loop_words: + retw + + .align 4 +fcn_copy_256_pixels_in_loop: +begin_copy_loop: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + copy_4_pixels_at_offset 16 + copy_4_pixels_at_offset 20 + copy_4_pixels_at_offset 24 + copy_4_pixels_at_offset 28 + copy_4_pixels_at_offset 32 + copy_4_pixels_at_offset 36 + copy_4_pixels_at_offset 40 + copy_4_pixels_at_offset 44 + copy_4_pixels_at_offset 48 + copy_4_pixels_at_offset 52 + copy_4_pixels_at_offset 56 + copy_4_pixels_at_offset 60 + copy_4_pixels_at_offset 64 + copy_4_pixels_at_offset 68 + copy_4_pixels_at_offset 72 + copy_4_pixels_at_offset 76 + copy_4_pixels_at_offset 80 + copy_4_pixels_at_offset 84 + copy_4_pixels_at_offset 88 + copy_4_pixels_at_offset 92 + copy_4_pixels_at_offset 96 + copy_4_pixels_at_offset 100 + copy_4_pixels_at_offset 104 + copy_4_pixels_at_offset 108 + copy_4_pixels_at_offset 112 + copy_4_pixels_at_offset 116 + copy_4_pixels_at_offset 120 + copy_4_pixels_at_offset 124 + + copy_4_pixels_at_offset 128 + copy_4_pixels_at_offset 132 + copy_4_pixels_at_offset 136 + copy_4_pixels_at_offset 140 + copy_4_pixels_at_offset 144 + copy_4_pixels_at_offset 148 + copy_4_pixels_at_offset 152 + copy_4_pixels_at_offset 156 + copy_4_pixels_at_offset 160 + copy_4_pixels_at_offset 164 + copy_4_pixels_at_offset 168 + copy_4_pixels_at_offset 172 + copy_4_pixels_at_offset 176 + copy_4_pixels_at_offset 180 + copy_4_pixels_at_offset 184 + copy_4_pixels_at_offset 188 + copy_4_pixels_at_offset 192 + copy_4_pixels_at_offset 196 + copy_4_pixels_at_offset 200 + copy_4_pixels_at_offset 204 + copy_4_pixels_at_offset 208 + copy_4_pixels_at_offset 212 + copy_4_pixels_at_offset 216 + copy_4_pixels_at_offset 220 + copy_4_pixels_at_offset 224 + copy_4_pixels_at_offset 228 + copy_4_pixels_at_offset 232 + copy_4_pixels_at_offset 236 + copy_4_pixels_at_offset 240 + copy_4_pixels_at_offset 244 + copy_4_pixels_at_offset 248 + copy_4_pixels_at_offset 252 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_copy_loop + j begin_copy_loop +end_copy_loop: + ret + + .align 4 +fcn_copy_128_pixels: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + copy_4_pixels_at_offset 16 + copy_4_pixels_at_offset 20 + copy_4_pixels_at_offset 24 + copy_4_pixels_at_offset 28 + copy_4_pixels_at_offset 32 + copy_4_pixels_at_offset 36 + copy_4_pixels_at_offset 40 + copy_4_pixels_at_offset 44 + copy_4_pixels_at_offset 48 + copy_4_pixels_at_offset 52 + copy_4_pixels_at_offset 56 + copy_4_pixels_at_offset 60 + copy_4_pixels_at_offset 64 + copy_4_pixels_at_offset 68 + copy_4_pixels_at_offset 72 + copy_4_pixels_at_offset 76 + copy_4_pixels_at_offset 80 + copy_4_pixels_at_offset 84 + copy_4_pixels_at_offset 88 + copy_4_pixels_at_offset 92 + copy_4_pixels_at_offset 96 + copy_4_pixels_at_offset 100 + copy_4_pixels_at_offset 104 + copy_4_pixels_at_offset 108 + copy_4_pixels_at_offset 112 + copy_4_pixels_at_offset 116 + copy_4_pixels_at_offset 120 + copy_4_pixels_at_offset 124 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + ret + + .align 4 +fcn_copy_128_pixels_last: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + copy_4_pixels_at_offset 16 + copy_4_pixels_at_offset 20 + copy_4_pixels_at_offset 24 + copy_4_pixels_at_offset 28 + copy_4_pixels_at_offset 32 + copy_4_pixels_at_offset 36 + copy_4_pixels_at_offset 40 + copy_4_pixels_at_offset 44 + copy_4_pixels_at_offset 48 + copy_4_pixels_at_offset 52 + copy_4_pixels_at_offset 56 + copy_4_pixels_at_offset 60 + copy_4_pixels_at_offset 64 + copy_4_pixels_at_offset 68 + copy_4_pixels_at_offset 72 + copy_4_pixels_at_offset 76 + copy_4_pixels_at_offset 80 + copy_4_pixels_at_offset 84 + copy_4_pixels_at_offset 88 + copy_4_pixels_at_offset 92 + copy_4_pixels_at_offset 96 + copy_4_pixels_at_offset 100 + copy_4_pixels_at_offset 104 + copy_4_pixels_at_offset 108 + copy_4_pixels_at_offset 112 + copy_4_pixels_at_offset 116 + copy_4_pixels_at_offset 120 + copy_4_pixels_at_offset 124 + ret + + .align 4 +fcn_copy_64_pixels: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + copy_4_pixels_at_offset 16 + copy_4_pixels_at_offset 20 + copy_4_pixels_at_offset 24 + copy_4_pixels_at_offset 28 + copy_4_pixels_at_offset 32 + copy_4_pixels_at_offset 36 + copy_4_pixels_at_offset 40 + copy_4_pixels_at_offset 44 + copy_4_pixels_at_offset 48 + copy_4_pixels_at_offset 52 + copy_4_pixels_at_offset 56 + copy_4_pixels_at_offset 60 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + ret + + .align 4 +fcn_copy_64_pixels_last: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + copy_4_pixels_at_offset 16 + copy_4_pixels_at_offset 20 + copy_4_pixels_at_offset 24 + copy_4_pixels_at_offset 28 + copy_4_pixels_at_offset 32 + copy_4_pixels_at_offset 36 + copy_4_pixels_at_offset 40 + copy_4_pixels_at_offset 44 + copy_4_pixels_at_offset 48 + copy_4_pixels_at_offset 52 + copy_4_pixels_at_offset 56 + copy_4_pixels_at_offset 60 + ret + + .align 4 +fcn_copy_32_pixels: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + copy_4_pixels_at_offset 16 + copy_4_pixels_at_offset 20 + copy_4_pixels_at_offset 24 + copy_4_pixels_at_offset 28 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 32 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + + ret + + .align 4 +fcn_copy_32_pixels_last: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + copy_4_pixels_at_offset 16 + copy_4_pixels_at_offset 20 + copy_4_pixels_at_offset 24 + copy_4_pixels_at_offset 28 + ret + + .align 4 +fcn_copy_16_pixels: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + ret + + .align 4 +fcn_copy_16_pixels_last: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + copy_4_pixels_at_offset 8 + copy_4_pixels_at_offset 12 + ret + + .align 4 +fcn_copy_8_pixels: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 8 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + + ret + + .align 4 +fcn_copy_8_pixels_last: + copy_4_pixels_at_offset 0 + copy_4_pixels_at_offset 4 + ret + + .align 4 +fcn_skip_copy_256_pixels_in_loop: +begin_skip_copy_loop: + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_skip_copy_loop + j begin_skip_copy_loop +end_skip_copy_loop: + ret + + .align 4 +fcn_skip_copy_128_pixels: + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + ret + + .align 4 +fcn_skip_copy_64_pixels: + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + ret + + .align 4 +fcn_skip_copy_32_pixels: + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 32 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + ret + + .align 4 +fcn_skip_copy_16_pixels: + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + ret + + .align 4 +fcn_skip_copy_8_pixels: + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 8 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + ret + + .align 4 +fcn_color_blend_25_for_256_pixels_in_loop: + enter_blend_fcn +begin_color_blend_25_loop: + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + blend_for_4_pixels_at_offset 25 clr 16 + blend_for_4_pixels_at_offset 25 clr 20 + blend_for_4_pixels_at_offset 25 clr 24 + blend_for_4_pixels_at_offset 25 clr 28 + blend_for_4_pixels_at_offset 25 clr 32 + blend_for_4_pixels_at_offset 25 clr 36 + blend_for_4_pixels_at_offset 25 clr 40 + blend_for_4_pixels_at_offset 25 clr 44 + blend_for_4_pixels_at_offset 25 clr 48 + blend_for_4_pixels_at_offset 25 clr 52 + blend_for_4_pixels_at_offset 25 clr 56 + blend_for_4_pixels_at_offset 25 clr 60 + blend_for_4_pixels_at_offset 25 clr 64 + blend_for_4_pixels_at_offset 25 clr 68 + blend_for_4_pixels_at_offset 25 clr 72 + blend_for_4_pixels_at_offset 25 clr 76 + blend_for_4_pixels_at_offset 25 clr 80 + blend_for_4_pixels_at_offset 25 clr 84 + blend_for_4_pixels_at_offset 25 clr 88 + blend_for_4_pixels_at_offset 25 clr 92 + blend_for_4_pixels_at_offset 25 clr 96 + blend_for_4_pixels_at_offset 25 clr 100 + blend_for_4_pixels_at_offset 25 clr 104 + blend_for_4_pixels_at_offset 25 clr 108 + blend_for_4_pixels_at_offset 25 clr 112 + blend_for_4_pixels_at_offset 25 clr 116 + blend_for_4_pixels_at_offset 25 clr 120 + blend_for_4_pixels_at_offset 25 clr 124 + + blend_for_4_pixels_at_offset 25 clr 128 + blend_for_4_pixels_at_offset 25 clr 132 + blend_for_4_pixels_at_offset 25 clr 136 + blend_for_4_pixels_at_offset 25 clr 140 + blend_for_4_pixels_at_offset 25 clr 144 + blend_for_4_pixels_at_offset 25 clr 148 + blend_for_4_pixels_at_offset 25 clr 152 + blend_for_4_pixels_at_offset 25 clr 156 + blend_for_4_pixels_at_offset 25 clr 160 + blend_for_4_pixels_at_offset 25 clr 164 + blend_for_4_pixels_at_offset 25 clr 168 + blend_for_4_pixels_at_offset 25 clr 172 + blend_for_4_pixels_at_offset 25 clr 176 + blend_for_4_pixels_at_offset 25 clr 180 + blend_for_4_pixels_at_offset 25 clr 184 + blend_for_4_pixels_at_offset 25 clr 188 + blend_for_4_pixels_at_offset 25 clr 192 + blend_for_4_pixels_at_offset 25 clr 196 + blend_for_4_pixels_at_offset 25 clr 200 + blend_for_4_pixels_at_offset 25 clr 204 + blend_for_4_pixels_at_offset 25 clr 208 + blend_for_4_pixels_at_offset 25 clr 212 + blend_for_4_pixels_at_offset 25 clr 216 + blend_for_4_pixels_at_offset 25 clr 220 + blend_for_4_pixels_at_offset 25 clr 224 + blend_for_4_pixels_at_offset 25 clr 228 + blend_for_4_pixels_at_offset 25 clr 232 + blend_for_4_pixels_at_offset 25 clr 236 + blend_for_4_pixels_at_offset 25 clr 240 + blend_for_4_pixels_at_offset 25 clr 244 + blend_for_4_pixels_at_offset 25 clr 248 + blend_for_4_pixels_at_offset 25 clr 252 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_color_blend_25_loop + j begin_color_blend_25_loop +end_color_blend_25_loop: + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_128_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + blend_for_4_pixels_at_offset 25 clr 16 + blend_for_4_pixels_at_offset 25 clr 20 + blend_for_4_pixels_at_offset 25 clr 24 + blend_for_4_pixels_at_offset 25 clr 28 + blend_for_4_pixels_at_offset 25 clr 32 + blend_for_4_pixels_at_offset 25 clr 36 + blend_for_4_pixels_at_offset 25 clr 40 + blend_for_4_pixels_at_offset 25 clr 44 + blend_for_4_pixels_at_offset 25 clr 48 + blend_for_4_pixels_at_offset 25 clr 52 + blend_for_4_pixels_at_offset 25 clr 56 + blend_for_4_pixels_at_offset 25 clr 60 + blend_for_4_pixels_at_offset 25 clr 64 + blend_for_4_pixels_at_offset 25 clr 68 + blend_for_4_pixels_at_offset 25 clr 72 + blend_for_4_pixels_at_offset 25 clr 76 + blend_for_4_pixels_at_offset 25 clr 80 + blend_for_4_pixels_at_offset 25 clr 84 + blend_for_4_pixels_at_offset 25 clr 88 + blend_for_4_pixels_at_offset 25 clr 92 + blend_for_4_pixels_at_offset 25 clr 96 + blend_for_4_pixels_at_offset 25 clr 100 + blend_for_4_pixels_at_offset 25 clr 104 + blend_for_4_pixels_at_offset 25 clr 108 + blend_for_4_pixels_at_offset 25 clr 112 + blend_for_4_pixels_at_offset 25 clr 116 + blend_for_4_pixels_at_offset 25 clr 120 + blend_for_4_pixels_at_offset 25 clr 124 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_128_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + blend_for_4_pixels_at_offset 25 clr 16 + blend_for_4_pixels_at_offset 25 clr 20 + blend_for_4_pixels_at_offset 25 clr 24 + blend_for_4_pixels_at_offset 25 clr 28 + blend_for_4_pixels_at_offset 25 clr 32 + blend_for_4_pixels_at_offset 25 clr 36 + blend_for_4_pixels_at_offset 25 clr 40 + blend_for_4_pixels_at_offset 25 clr 44 + blend_for_4_pixels_at_offset 25 clr 48 + blend_for_4_pixels_at_offset 25 clr 52 + blend_for_4_pixels_at_offset 25 clr 56 + blend_for_4_pixels_at_offset 25 clr 60 + blend_for_4_pixels_at_offset 25 clr 64 + blend_for_4_pixels_at_offset 25 clr 68 + blend_for_4_pixels_at_offset 25 clr 72 + blend_for_4_pixels_at_offset 25 clr 76 + blend_for_4_pixels_at_offset 25 clr 80 + blend_for_4_pixels_at_offset 25 clr 84 + blend_for_4_pixels_at_offset 25 clr 88 + blend_for_4_pixels_at_offset 25 clr 92 + blend_for_4_pixels_at_offset 25 clr 96 + blend_for_4_pixels_at_offset 25 clr 100 + blend_for_4_pixels_at_offset 25 clr 104 + blend_for_4_pixels_at_offset 25 clr 108 + blend_for_4_pixels_at_offset 25 clr 112 + blend_for_4_pixels_at_offset 25 clr 116 + blend_for_4_pixels_at_offset 25 clr 120 + blend_for_4_pixels_at_offset 25 clr 124 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_64_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + blend_for_4_pixels_at_offset 25 clr 16 + blend_for_4_pixels_at_offset 25 clr 20 + blend_for_4_pixels_at_offset 25 clr 24 + blend_for_4_pixels_at_offset 25 clr 28 + blend_for_4_pixels_at_offset 25 clr 32 + blend_for_4_pixels_at_offset 25 clr 36 + blend_for_4_pixels_at_offset 25 clr 40 + blend_for_4_pixels_at_offset 25 clr 44 + blend_for_4_pixels_at_offset 25 clr 48 + blend_for_4_pixels_at_offset 25 clr 52 + blend_for_4_pixels_at_offset 25 clr 56 + blend_for_4_pixels_at_offset 25 clr 60 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_64_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + blend_for_4_pixels_at_offset 25 clr 16 + blend_for_4_pixels_at_offset 25 clr 20 + blend_for_4_pixels_at_offset 25 clr 24 + blend_for_4_pixels_at_offset 25 clr 28 + blend_for_4_pixels_at_offset 25 clr 32 + blend_for_4_pixels_at_offset 25 clr 36 + blend_for_4_pixels_at_offset 25 clr 40 + blend_for_4_pixels_at_offset 25 clr 44 + blend_for_4_pixels_at_offset 25 clr 48 + blend_for_4_pixels_at_offset 25 clr 52 + blend_for_4_pixels_at_offset 25 clr 56 + blend_for_4_pixels_at_offset 25 clr 60 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_32_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + blend_for_4_pixels_at_offset 25 clr 16 + blend_for_4_pixels_at_offset 25 clr 20 + blend_for_4_pixels_at_offset 25 clr 24 + blend_for_4_pixels_at_offset 25 clr 28 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_32_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + blend_for_4_pixels_at_offset 25 clr 16 + blend_for_4_pixels_at_offset 25 clr 20 + blend_for_4_pixels_at_offset 25 clr 24 + blend_for_4_pixels_at_offset 25 clr 28 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_16_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_16_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + blend_for_4_pixels_at_offset 25 clr 8 + blend_for_4_pixels_at_offset 25 clr 12 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_8_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_8_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + blend_for_4_pixels_at_offset 25 clr 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_0: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_0_last: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_1: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_1_last: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_2: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_2_last: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_3: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_1_pixel_at_offset_3_last: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_2_pixels_at_offset_0: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_2_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_2_pixels_at_offset_1: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_2_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_2_pixels_at_offset_2: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_2_pixels_at_offset_2_last: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_3_pixels_at_offset_0: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_3_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_3_pixels_at_offset_1: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 25 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_3_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 25 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_4_pixels_at_offset_0: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_25_for_4_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 clr 0 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_256_pixels_in_loop: + enter_blend_fcn +begin_color_blend_50_loop: + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + blend_for_4_pixels_at_offset 50 clr 16 + blend_for_4_pixels_at_offset 50 clr 20 + blend_for_4_pixels_at_offset 50 clr 24 + blend_for_4_pixels_at_offset 50 clr 28 + blend_for_4_pixels_at_offset 50 clr 32 + blend_for_4_pixels_at_offset 50 clr 36 + blend_for_4_pixels_at_offset 50 clr 40 + blend_for_4_pixels_at_offset 50 clr 44 + blend_for_4_pixels_at_offset 50 clr 48 + blend_for_4_pixels_at_offset 50 clr 52 + blend_for_4_pixels_at_offset 50 clr 56 + blend_for_4_pixels_at_offset 50 clr 60 + blend_for_4_pixels_at_offset 50 clr 64 + blend_for_4_pixels_at_offset 50 clr 68 + blend_for_4_pixels_at_offset 50 clr 72 + blend_for_4_pixels_at_offset 50 clr 76 + blend_for_4_pixels_at_offset 50 clr 80 + blend_for_4_pixels_at_offset 50 clr 84 + blend_for_4_pixels_at_offset 50 clr 88 + blend_for_4_pixels_at_offset 50 clr 92 + blend_for_4_pixels_at_offset 50 clr 96 + blend_for_4_pixels_at_offset 50 clr 100 + blend_for_4_pixels_at_offset 50 clr 104 + blend_for_4_pixels_at_offset 50 clr 108 + blend_for_4_pixels_at_offset 50 clr 112 + blend_for_4_pixels_at_offset 50 clr 116 + blend_for_4_pixels_at_offset 50 clr 120 + blend_for_4_pixels_at_offset 50 clr 124 + + blend_for_4_pixels_at_offset 50 clr 128 + blend_for_4_pixels_at_offset 50 clr 132 + blend_for_4_pixels_at_offset 50 clr 136 + blend_for_4_pixels_at_offset 50 clr 140 + blend_for_4_pixels_at_offset 50 clr 144 + blend_for_4_pixels_at_offset 50 clr 148 + blend_for_4_pixels_at_offset 50 clr 152 + blend_for_4_pixels_at_offset 50 clr 156 + blend_for_4_pixels_at_offset 50 clr 160 + blend_for_4_pixels_at_offset 50 clr 164 + blend_for_4_pixels_at_offset 50 clr 168 + blend_for_4_pixels_at_offset 50 clr 172 + blend_for_4_pixels_at_offset 50 clr 176 + blend_for_4_pixels_at_offset 50 clr 180 + blend_for_4_pixels_at_offset 50 clr 184 + blend_for_4_pixels_at_offset 50 clr 188 + blend_for_4_pixels_at_offset 50 clr 192 + blend_for_4_pixels_at_offset 50 clr 196 + blend_for_4_pixels_at_offset 50 clr 200 + blend_for_4_pixels_at_offset 50 clr 204 + blend_for_4_pixels_at_offset 50 clr 208 + blend_for_4_pixels_at_offset 50 clr 212 + blend_for_4_pixels_at_offset 50 clr 216 + blend_for_4_pixels_at_offset 50 clr 220 + blend_for_4_pixels_at_offset 50 clr 224 + blend_for_4_pixels_at_offset 50 clr 228 + blend_for_4_pixels_at_offset 50 clr 232 + blend_for_4_pixels_at_offset 50 clr 236 + blend_for_4_pixels_at_offset 50 clr 240 + blend_for_4_pixels_at_offset 50 clr 244 + blend_for_4_pixels_at_offset 50 clr 248 + blend_for_4_pixels_at_offset 50 clr 252 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_color_blend_50_loop + j begin_color_blend_50_loop +end_color_blend_50_loop: + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_128_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + blend_for_4_pixels_at_offset 50 clr 16 + blend_for_4_pixels_at_offset 50 clr 20 + blend_for_4_pixels_at_offset 50 clr 24 + blend_for_4_pixels_at_offset 50 clr 28 + blend_for_4_pixels_at_offset 50 clr 32 + blend_for_4_pixels_at_offset 50 clr 36 + blend_for_4_pixels_at_offset 50 clr 40 + blend_for_4_pixels_at_offset 50 clr 44 + blend_for_4_pixels_at_offset 50 clr 48 + blend_for_4_pixels_at_offset 50 clr 52 + blend_for_4_pixels_at_offset 50 clr 56 + blend_for_4_pixels_at_offset 50 clr 60 + blend_for_4_pixels_at_offset 50 clr 64 + blend_for_4_pixels_at_offset 50 clr 68 + blend_for_4_pixels_at_offset 50 clr 72 + blend_for_4_pixels_at_offset 50 clr 76 + blend_for_4_pixels_at_offset 50 clr 80 + blend_for_4_pixels_at_offset 50 clr 84 + blend_for_4_pixels_at_offset 50 clr 88 + blend_for_4_pixels_at_offset 50 clr 92 + blend_for_4_pixels_at_offset 50 clr 96 + blend_for_4_pixels_at_offset 50 clr 100 + blend_for_4_pixels_at_offset 50 clr 104 + blend_for_4_pixels_at_offset 50 clr 108 + blend_for_4_pixels_at_offset 50 clr 112 + blend_for_4_pixels_at_offset 50 clr 116 + blend_for_4_pixels_at_offset 50 clr 120 + blend_for_4_pixels_at_offset 50 clr 124 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_128_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + blend_for_4_pixels_at_offset 50 clr 16 + blend_for_4_pixels_at_offset 50 clr 20 + blend_for_4_pixels_at_offset 50 clr 24 + blend_for_4_pixels_at_offset 50 clr 28 + blend_for_4_pixels_at_offset 50 clr 32 + blend_for_4_pixels_at_offset 50 clr 36 + blend_for_4_pixels_at_offset 50 clr 40 + blend_for_4_pixels_at_offset 50 clr 44 + blend_for_4_pixels_at_offset 50 clr 48 + blend_for_4_pixels_at_offset 50 clr 52 + blend_for_4_pixels_at_offset 50 clr 56 + blend_for_4_pixels_at_offset 50 clr 60 + blend_for_4_pixels_at_offset 50 clr 64 + blend_for_4_pixels_at_offset 50 clr 68 + blend_for_4_pixels_at_offset 50 clr 72 + blend_for_4_pixels_at_offset 50 clr 76 + blend_for_4_pixels_at_offset 50 clr 80 + blend_for_4_pixels_at_offset 50 clr 84 + blend_for_4_pixels_at_offset 50 clr 88 + blend_for_4_pixels_at_offset 50 clr 92 + blend_for_4_pixels_at_offset 50 clr 96 + blend_for_4_pixels_at_offset 50 clr 100 + blend_for_4_pixels_at_offset 50 clr 104 + blend_for_4_pixels_at_offset 50 clr 108 + blend_for_4_pixels_at_offset 50 clr 112 + blend_for_4_pixels_at_offset 50 clr 116 + blend_for_4_pixels_at_offset 50 clr 120 + blend_for_4_pixels_at_offset 50 clr 124 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_64_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + blend_for_4_pixels_at_offset 50 clr 16 + blend_for_4_pixels_at_offset 50 clr 20 + blend_for_4_pixels_at_offset 50 clr 24 + blend_for_4_pixels_at_offset 50 clr 28 + blend_for_4_pixels_at_offset 50 clr 32 + blend_for_4_pixels_at_offset 50 clr 36 + blend_for_4_pixels_at_offset 50 clr 40 + blend_for_4_pixels_at_offset 50 clr 44 + blend_for_4_pixels_at_offset 50 clr 48 + blend_for_4_pixels_at_offset 50 clr 52 + blend_for_4_pixels_at_offset 50 clr 56 + blend_for_4_pixels_at_offset 50 clr 60 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_64_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + blend_for_4_pixels_at_offset 50 clr 16 + blend_for_4_pixels_at_offset 50 clr 20 + blend_for_4_pixels_at_offset 50 clr 24 + blend_for_4_pixels_at_offset 50 clr 28 + blend_for_4_pixels_at_offset 50 clr 32 + blend_for_4_pixels_at_offset 50 clr 36 + blend_for_4_pixels_at_offset 50 clr 40 + blend_for_4_pixels_at_offset 50 clr 44 + blend_for_4_pixels_at_offset 50 clr 48 + blend_for_4_pixels_at_offset 50 clr 52 + blend_for_4_pixels_at_offset 50 clr 56 + blend_for_4_pixels_at_offset 50 clr 60 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_32_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + blend_for_4_pixels_at_offset 50 clr 16 + blend_for_4_pixels_at_offset 50 clr 20 + blend_for_4_pixels_at_offset 50 clr 24 + blend_for_4_pixels_at_offset 50 clr 28 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_32_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + blend_for_4_pixels_at_offset 50 clr 16 + blend_for_4_pixels_at_offset 50 clr 20 + blend_for_4_pixels_at_offset 50 clr 24 + blend_for_4_pixels_at_offset 50 clr 28 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_16_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_16_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + blend_for_4_pixels_at_offset 50 clr 8 + blend_for_4_pixels_at_offset 50 clr 12 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_8_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_8_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + blend_for_4_pixels_at_offset 50 clr 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_0: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_0_last: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_1: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_1_last: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_2: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_2_last: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_3: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_1_pixel_at_offset_3_last: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_2_pixels_at_offset_0: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_2_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_2_pixels_at_offset_1: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_2_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_2_pixels_at_offset_2: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_2_pixels_at_offset_2_last: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_3_pixels_at_offset_0: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_3_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_3_pixels_at_offset_1: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 50 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_3_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 50 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_4_pixels_at_offset_0: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_50_for_4_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 clr 0 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_256_pixels_in_loop: + enter_blend_fcn +begin_color_blend_75_loop: + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + blend_for_4_pixels_at_offset 75 clr 16 + blend_for_4_pixels_at_offset 75 clr 20 + blend_for_4_pixels_at_offset 75 clr 24 + blend_for_4_pixels_at_offset 75 clr 28 + blend_for_4_pixels_at_offset 75 clr 32 + blend_for_4_pixels_at_offset 75 clr 36 + blend_for_4_pixels_at_offset 75 clr 40 + blend_for_4_pixels_at_offset 75 clr 44 + blend_for_4_pixels_at_offset 75 clr 48 + blend_for_4_pixels_at_offset 75 clr 52 + blend_for_4_pixels_at_offset 75 clr 56 + blend_for_4_pixels_at_offset 75 clr 60 + blend_for_4_pixels_at_offset 75 clr 64 + blend_for_4_pixels_at_offset 75 clr 68 + blend_for_4_pixels_at_offset 75 clr 72 + blend_for_4_pixels_at_offset 75 clr 76 + blend_for_4_pixels_at_offset 75 clr 80 + blend_for_4_pixels_at_offset 75 clr 84 + blend_for_4_pixels_at_offset 75 clr 88 + blend_for_4_pixels_at_offset 75 clr 92 + blend_for_4_pixels_at_offset 75 clr 96 + blend_for_4_pixels_at_offset 75 clr 100 + blend_for_4_pixels_at_offset 75 clr 104 + blend_for_4_pixels_at_offset 75 clr 108 + blend_for_4_pixels_at_offset 75 clr 112 + blend_for_4_pixels_at_offset 75 clr 116 + blend_for_4_pixels_at_offset 75 clr 120 + blend_for_4_pixels_at_offset 75 clr 124 + + blend_for_4_pixels_at_offset 75 clr 128 + blend_for_4_pixels_at_offset 75 clr 132 + blend_for_4_pixels_at_offset 75 clr 136 + blend_for_4_pixels_at_offset 75 clr 140 + blend_for_4_pixels_at_offset 75 clr 144 + blend_for_4_pixels_at_offset 75 clr 148 + blend_for_4_pixels_at_offset 75 clr 152 + blend_for_4_pixels_at_offset 75 clr 156 + blend_for_4_pixels_at_offset 75 clr 160 + blend_for_4_pixels_at_offset 75 clr 164 + blend_for_4_pixels_at_offset 75 clr 168 + blend_for_4_pixels_at_offset 75 clr 172 + blend_for_4_pixels_at_offset 75 clr 176 + blend_for_4_pixels_at_offset 75 clr 180 + blend_for_4_pixels_at_offset 75 clr 184 + blend_for_4_pixels_at_offset 75 clr 188 + blend_for_4_pixels_at_offset 75 clr 192 + blend_for_4_pixels_at_offset 75 clr 196 + blend_for_4_pixels_at_offset 75 clr 200 + blend_for_4_pixels_at_offset 75 clr 204 + blend_for_4_pixels_at_offset 75 clr 208 + blend_for_4_pixels_at_offset 75 clr 212 + blend_for_4_pixels_at_offset 75 clr 216 + blend_for_4_pixels_at_offset 75 clr 220 + blend_for_4_pixels_at_offset 75 clr 224 + blend_for_4_pixels_at_offset 75 clr 228 + blend_for_4_pixels_at_offset 75 clr 232 + blend_for_4_pixels_at_offset 75 clr 236 + blend_for_4_pixels_at_offset 75 clr 240 + blend_for_4_pixels_at_offset 75 clr 244 + blend_for_4_pixels_at_offset 75 clr 248 + blend_for_4_pixels_at_offset 75 clr 252 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_color_blend_75_loop + j begin_color_blend_75_loop +end_color_blend_75_loop: + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_128_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + blend_for_4_pixels_at_offset 75 clr 16 + blend_for_4_pixels_at_offset 75 clr 20 + blend_for_4_pixels_at_offset 75 clr 24 + blend_for_4_pixels_at_offset 75 clr 28 + blend_for_4_pixels_at_offset 75 clr 32 + blend_for_4_pixels_at_offset 75 clr 36 + blend_for_4_pixels_at_offset 75 clr 40 + blend_for_4_pixels_at_offset 75 clr 44 + blend_for_4_pixels_at_offset 75 clr 48 + blend_for_4_pixels_at_offset 75 clr 52 + blend_for_4_pixels_at_offset 75 clr 56 + blend_for_4_pixels_at_offset 75 clr 60 + blend_for_4_pixels_at_offset 75 clr 64 + blend_for_4_pixels_at_offset 75 clr 68 + blend_for_4_pixels_at_offset 75 clr 72 + blend_for_4_pixels_at_offset 75 clr 76 + blend_for_4_pixels_at_offset 75 clr 80 + blend_for_4_pixels_at_offset 75 clr 84 + blend_for_4_pixels_at_offset 75 clr 88 + blend_for_4_pixels_at_offset 75 clr 92 + blend_for_4_pixels_at_offset 75 clr 96 + blend_for_4_pixels_at_offset 75 clr 100 + blend_for_4_pixels_at_offset 75 clr 104 + blend_for_4_pixels_at_offset 75 clr 108 + blend_for_4_pixels_at_offset 75 clr 112 + blend_for_4_pixels_at_offset 75 clr 116 + blend_for_4_pixels_at_offset 75 clr 120 + blend_for_4_pixels_at_offset 75 clr 124 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_128_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + blend_for_4_pixels_at_offset 75 clr 16 + blend_for_4_pixels_at_offset 75 clr 20 + blend_for_4_pixels_at_offset 75 clr 24 + blend_for_4_pixels_at_offset 75 clr 28 + blend_for_4_pixels_at_offset 75 clr 32 + blend_for_4_pixels_at_offset 75 clr 36 + blend_for_4_pixels_at_offset 75 clr 40 + blend_for_4_pixels_at_offset 75 clr 44 + blend_for_4_pixels_at_offset 75 clr 48 + blend_for_4_pixels_at_offset 75 clr 52 + blend_for_4_pixels_at_offset 75 clr 56 + blend_for_4_pixels_at_offset 75 clr 60 + blend_for_4_pixels_at_offset 75 clr 64 + blend_for_4_pixels_at_offset 75 clr 68 + blend_for_4_pixels_at_offset 75 clr 72 + blend_for_4_pixels_at_offset 75 clr 76 + blend_for_4_pixels_at_offset 75 clr 80 + blend_for_4_pixels_at_offset 75 clr 84 + blend_for_4_pixels_at_offset 75 clr 88 + blend_for_4_pixels_at_offset 75 clr 92 + blend_for_4_pixels_at_offset 75 clr 96 + blend_for_4_pixels_at_offset 75 clr 100 + blend_for_4_pixels_at_offset 75 clr 104 + blend_for_4_pixels_at_offset 75 clr 108 + blend_for_4_pixels_at_offset 75 clr 112 + blend_for_4_pixels_at_offset 75 clr 116 + blend_for_4_pixels_at_offset 75 clr 120 + blend_for_4_pixels_at_offset 75 clr 124 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_64_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + blend_for_4_pixels_at_offset 75 clr 16 + blend_for_4_pixels_at_offset 75 clr 20 + blend_for_4_pixels_at_offset 75 clr 24 + blend_for_4_pixels_at_offset 75 clr 28 + blend_for_4_pixels_at_offset 75 clr 32 + blend_for_4_pixels_at_offset 75 clr 36 + blend_for_4_pixels_at_offset 75 clr 40 + blend_for_4_pixels_at_offset 75 clr 44 + blend_for_4_pixels_at_offset 75 clr 48 + blend_for_4_pixels_at_offset 75 clr 52 + blend_for_4_pixels_at_offset 75 clr 56 + blend_for_4_pixels_at_offset 75 clr 60 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_64_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + blend_for_4_pixels_at_offset 75 clr 16 + blend_for_4_pixels_at_offset 75 clr 20 + blend_for_4_pixels_at_offset 75 clr 24 + blend_for_4_pixels_at_offset 75 clr 28 + blend_for_4_pixels_at_offset 75 clr 32 + blend_for_4_pixels_at_offset 75 clr 36 + blend_for_4_pixels_at_offset 75 clr 40 + blend_for_4_pixels_at_offset 75 clr 44 + blend_for_4_pixels_at_offset 75 clr 48 + blend_for_4_pixels_at_offset 75 clr 52 + blend_for_4_pixels_at_offset 75 clr 56 + blend_for_4_pixels_at_offset 75 clr 60 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_32_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + blend_for_4_pixels_at_offset 75 clr 16 + blend_for_4_pixels_at_offset 75 clr 20 + blend_for_4_pixels_at_offset 75 clr 24 + blend_for_4_pixels_at_offset 75 clr 28 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_32_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + blend_for_4_pixels_at_offset 75 clr 16 + blend_for_4_pixels_at_offset 75 clr 20 + blend_for_4_pixels_at_offset 75 clr 24 + blend_for_4_pixels_at_offset 75 clr 28 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_16_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_16_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + blend_for_4_pixels_at_offset 75 clr 8 + blend_for_4_pixels_at_offset 75 clr 12 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_8_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_8_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + blend_for_4_pixels_at_offset 75 clr 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_0: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_0_last: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_1: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_1_last: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_2: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_2_last: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_3: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_1_pixel_at_offset_3_last: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_2_pixels_at_offset_0: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_2_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_2_pixels_at_offset_1: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_2_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_2_pixels_at_offset_2: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_2_pixels_at_offset_2_last: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_3_pixels_at_offset_0: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_3_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_3_pixels_at_offset_1: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 75 clr + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_3_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 75 clr + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_4_pixels_at_offset_0: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_color_blend_75_for_4_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 clr 0 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_256_pixels_in_loop: + enter_blend_fcn +begin_src_blend_25_loop: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + blend_for_4_pixels_at_offset 25 src 16 + blend_for_4_pixels_at_offset 25 src 20 + blend_for_4_pixels_at_offset 25 src 24 + blend_for_4_pixels_at_offset 25 src 28 + blend_for_4_pixels_at_offset 25 src 32 + blend_for_4_pixels_at_offset 25 src 36 + blend_for_4_pixels_at_offset 25 src 40 + blend_for_4_pixels_at_offset 25 src 44 + blend_for_4_pixels_at_offset 25 src 48 + blend_for_4_pixels_at_offset 25 src 52 + blend_for_4_pixels_at_offset 25 src 56 + blend_for_4_pixels_at_offset 25 src 60 + blend_for_4_pixels_at_offset 25 src 64 + blend_for_4_pixels_at_offset 25 src 68 + blend_for_4_pixels_at_offset 25 src 72 + blend_for_4_pixels_at_offset 25 src 76 + blend_for_4_pixels_at_offset 25 src 80 + blend_for_4_pixels_at_offset 25 src 84 + blend_for_4_pixels_at_offset 25 src 88 + blend_for_4_pixels_at_offset 25 src 92 + blend_for_4_pixels_at_offset 25 src 96 + blend_for_4_pixels_at_offset 25 src 100 + blend_for_4_pixels_at_offset 25 src 104 + blend_for_4_pixels_at_offset 25 src 108 + blend_for_4_pixels_at_offset 25 src 112 + blend_for_4_pixels_at_offset 25 src 116 + blend_for_4_pixels_at_offset 25 src 120 + blend_for_4_pixels_at_offset 25 src 124 + + blend_for_4_pixels_at_offset 25 src 128 + blend_for_4_pixels_at_offset 25 src 132 + blend_for_4_pixels_at_offset 25 src 136 + blend_for_4_pixels_at_offset 25 src 140 + blend_for_4_pixels_at_offset 25 src 144 + blend_for_4_pixels_at_offset 25 src 148 + blend_for_4_pixels_at_offset 25 src 152 + blend_for_4_pixels_at_offset 25 src 156 + blend_for_4_pixels_at_offset 25 src 160 + blend_for_4_pixels_at_offset 25 src 164 + blend_for_4_pixels_at_offset 25 src 168 + blend_for_4_pixels_at_offset 25 src 172 + blend_for_4_pixels_at_offset 25 src 176 + blend_for_4_pixels_at_offset 25 src 180 + blend_for_4_pixels_at_offset 25 src 184 + blend_for_4_pixels_at_offset 25 src 188 + blend_for_4_pixels_at_offset 25 src 192 + blend_for_4_pixels_at_offset 25 src 196 + blend_for_4_pixels_at_offset 25 src 200 + blend_for_4_pixels_at_offset 25 src 204 + blend_for_4_pixels_at_offset 25 src 208 + blend_for_4_pixels_at_offset 25 src 212 + blend_for_4_pixels_at_offset 25 src 216 + blend_for_4_pixels_at_offset 25 src 220 + blend_for_4_pixels_at_offset 25 src 224 + blend_for_4_pixels_at_offset 25 src 228 + blend_for_4_pixels_at_offset 25 src 232 + blend_for_4_pixels_at_offset 25 src 236 + blend_for_4_pixels_at_offset 25 src 240 + blend_for_4_pixels_at_offset 25 src 244 + blend_for_4_pixels_at_offset 25 src 248 + blend_for_4_pixels_at_offset 25 src 252 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_src_blend_25_loop + j begin_src_blend_25_loop +end_src_blend_25_loop: + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_128_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + blend_for_4_pixels_at_offset 25 src 16 + blend_for_4_pixels_at_offset 25 src 20 + blend_for_4_pixels_at_offset 25 src 24 + blend_for_4_pixels_at_offset 25 src 28 + blend_for_4_pixels_at_offset 25 src 32 + blend_for_4_pixels_at_offset 25 src 36 + blend_for_4_pixels_at_offset 25 src 40 + blend_for_4_pixels_at_offset 25 src 44 + blend_for_4_pixels_at_offset 25 src 48 + blend_for_4_pixels_at_offset 25 src 52 + blend_for_4_pixels_at_offset 25 src 56 + blend_for_4_pixels_at_offset 25 src 60 + blend_for_4_pixels_at_offset 25 src 64 + blend_for_4_pixels_at_offset 25 src 68 + blend_for_4_pixels_at_offset 25 src 72 + blend_for_4_pixels_at_offset 25 src 76 + blend_for_4_pixels_at_offset 25 src 80 + blend_for_4_pixels_at_offset 25 src 84 + blend_for_4_pixels_at_offset 25 src 88 + blend_for_4_pixels_at_offset 25 src 92 + blend_for_4_pixels_at_offset 25 src 96 + blend_for_4_pixels_at_offset 25 src 100 + blend_for_4_pixels_at_offset 25 src 104 + blend_for_4_pixels_at_offset 25 src 108 + blend_for_4_pixels_at_offset 25 src 112 + blend_for_4_pixels_at_offset 25 src 116 + blend_for_4_pixels_at_offset 25 src 120 + blend_for_4_pixels_at_offset 25 src 124 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_128_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + blend_for_4_pixels_at_offset 25 src 16 + blend_for_4_pixels_at_offset 25 src 20 + blend_for_4_pixels_at_offset 25 src 24 + blend_for_4_pixels_at_offset 25 src 28 + blend_for_4_pixels_at_offset 25 src 32 + blend_for_4_pixels_at_offset 25 src 36 + blend_for_4_pixels_at_offset 25 src 40 + blend_for_4_pixels_at_offset 25 src 44 + blend_for_4_pixels_at_offset 25 src 48 + blend_for_4_pixels_at_offset 25 src 52 + blend_for_4_pixels_at_offset 25 src 56 + blend_for_4_pixels_at_offset 25 src 60 + blend_for_4_pixels_at_offset 25 src 64 + blend_for_4_pixels_at_offset 25 src 68 + blend_for_4_pixels_at_offset 25 src 72 + blend_for_4_pixels_at_offset 25 src 76 + blend_for_4_pixels_at_offset 25 src 80 + blend_for_4_pixels_at_offset 25 src 84 + blend_for_4_pixels_at_offset 25 src 88 + blend_for_4_pixels_at_offset 25 src 92 + blend_for_4_pixels_at_offset 25 src 96 + blend_for_4_pixels_at_offset 25 src 100 + blend_for_4_pixels_at_offset 25 src 104 + blend_for_4_pixels_at_offset 25 src 108 + blend_for_4_pixels_at_offset 25 src 112 + blend_for_4_pixels_at_offset 25 src 116 + blend_for_4_pixels_at_offset 25 src 120 + blend_for_4_pixels_at_offset 25 src 124 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_64_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + blend_for_4_pixels_at_offset 25 src 16 + blend_for_4_pixels_at_offset 25 src 20 + blend_for_4_pixels_at_offset 25 src 24 + blend_for_4_pixels_at_offset 25 src 28 + blend_for_4_pixels_at_offset 25 src 32 + blend_for_4_pixels_at_offset 25 src 36 + blend_for_4_pixels_at_offset 25 src 40 + blend_for_4_pixels_at_offset 25 src 44 + blend_for_4_pixels_at_offset 25 src 48 + blend_for_4_pixels_at_offset 25 src 52 + blend_for_4_pixels_at_offset 25 src 56 + blend_for_4_pixels_at_offset 25 src 60 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_64_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + blend_for_4_pixels_at_offset 25 src 16 + blend_for_4_pixels_at_offset 25 src 20 + blend_for_4_pixels_at_offset 25 src 24 + blend_for_4_pixels_at_offset 25 src 28 + blend_for_4_pixels_at_offset 25 src 32 + blend_for_4_pixels_at_offset 25 src 36 + blend_for_4_pixels_at_offset 25 src 40 + blend_for_4_pixels_at_offset 25 src 44 + blend_for_4_pixels_at_offset 25 src 48 + blend_for_4_pixels_at_offset 25 src 52 + blend_for_4_pixels_at_offset 25 src 56 + blend_for_4_pixels_at_offset 25 src 60 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_32_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + blend_for_4_pixels_at_offset 25 src 16 + blend_for_4_pixels_at_offset 25 src 20 + blend_for_4_pixels_at_offset 25 src 24 + blend_for_4_pixels_at_offset 25 src 28 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 32 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_32_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + blend_for_4_pixels_at_offset 25 src 16 + blend_for_4_pixels_at_offset 25 src 20 + blend_for_4_pixels_at_offset 25 src 24 + blend_for_4_pixels_at_offset 25 src 28 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_16_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_16_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + blend_for_4_pixels_at_offset 25 src 8 + blend_for_4_pixels_at_offset 25 src 12 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_8_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 8 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_8_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + blend_for_4_pixels_at_offset 25 src 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_0: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_0_last: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_1: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_1_last: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_2: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_2_last: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_3: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_1_pixel_at_offset_3_last: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_2_pixels_at_offset_0: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_2_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_2_pixels_at_offset_1: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_2_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_2_pixels_at_offset_2: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_2_pixels_at_offset_2_last: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_3_pixels_at_offset_0: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_3_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_3_pixels_at_offset_1: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 25 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_3_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_4_pixels_at_offset_0: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_25_for_4_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_256_pixels_in_loop: + enter_blend_fcn +begin_src_blend_50_loop: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + blend_for_4_pixels_at_offset 50 src 16 + blend_for_4_pixels_at_offset 50 src 20 + blend_for_4_pixels_at_offset 50 src 24 + blend_for_4_pixels_at_offset 50 src 28 + blend_for_4_pixels_at_offset 50 src 32 + blend_for_4_pixels_at_offset 50 src 36 + blend_for_4_pixels_at_offset 50 src 40 + blend_for_4_pixels_at_offset 50 src 44 + blend_for_4_pixels_at_offset 50 src 48 + blend_for_4_pixels_at_offset 50 src 52 + blend_for_4_pixels_at_offset 50 src 56 + blend_for_4_pixels_at_offset 50 src 60 + blend_for_4_pixels_at_offset 50 src 64 + blend_for_4_pixels_at_offset 50 src 68 + blend_for_4_pixels_at_offset 50 src 72 + blend_for_4_pixels_at_offset 50 src 76 + blend_for_4_pixels_at_offset 50 src 80 + blend_for_4_pixels_at_offset 50 src 84 + blend_for_4_pixels_at_offset 50 src 88 + blend_for_4_pixels_at_offset 50 src 92 + blend_for_4_pixels_at_offset 50 src 96 + blend_for_4_pixels_at_offset 50 src 100 + blend_for_4_pixels_at_offset 50 src 104 + blend_for_4_pixels_at_offset 50 src 108 + blend_for_4_pixels_at_offset 50 src 112 + blend_for_4_pixels_at_offset 50 src 116 + blend_for_4_pixels_at_offset 50 src 120 + blend_for_4_pixels_at_offset 50 src 124 + + blend_for_4_pixels_at_offset 50 src 128 + blend_for_4_pixels_at_offset 50 src 132 + blend_for_4_pixels_at_offset 50 src 136 + blend_for_4_pixels_at_offset 50 src 140 + blend_for_4_pixels_at_offset 50 src 144 + blend_for_4_pixels_at_offset 50 src 148 + blend_for_4_pixels_at_offset 50 src 152 + blend_for_4_pixels_at_offset 50 src 156 + blend_for_4_pixels_at_offset 50 src 160 + blend_for_4_pixels_at_offset 50 src 164 + blend_for_4_pixels_at_offset 50 src 168 + blend_for_4_pixels_at_offset 50 src 172 + blend_for_4_pixels_at_offset 50 src 176 + blend_for_4_pixels_at_offset 50 src 180 + blend_for_4_pixels_at_offset 50 src 184 + blend_for_4_pixels_at_offset 50 src 188 + blend_for_4_pixels_at_offset 50 src 192 + blend_for_4_pixels_at_offset 50 src 196 + blend_for_4_pixels_at_offset 50 src 200 + blend_for_4_pixels_at_offset 50 src 204 + blend_for_4_pixels_at_offset 50 src 208 + blend_for_4_pixels_at_offset 50 src 212 + blend_for_4_pixels_at_offset 50 src 216 + blend_for_4_pixels_at_offset 50 src 220 + blend_for_4_pixels_at_offset 50 src 224 + blend_for_4_pixels_at_offset 50 src 228 + blend_for_4_pixels_at_offset 50 src 232 + blend_for_4_pixels_at_offset 50 src 236 + blend_for_4_pixels_at_offset 50 src 240 + blend_for_4_pixels_at_offset 50 src 244 + blend_for_4_pixels_at_offset 50 src 248 + blend_for_4_pixels_at_offset 50 src 252 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_src_blend_50_loop + j begin_src_blend_50_loop +end_src_blend_50_loop: + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_128_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + blend_for_4_pixels_at_offset 50 src 16 + blend_for_4_pixels_at_offset 50 src 20 + blend_for_4_pixels_at_offset 50 src 24 + blend_for_4_pixels_at_offset 50 src 28 + blend_for_4_pixels_at_offset 50 src 32 + blend_for_4_pixels_at_offset 50 src 36 + blend_for_4_pixels_at_offset 50 src 40 + blend_for_4_pixels_at_offset 50 src 44 + blend_for_4_pixels_at_offset 50 src 48 + blend_for_4_pixels_at_offset 50 src 52 + blend_for_4_pixels_at_offset 50 src 56 + blend_for_4_pixels_at_offset 50 src 60 + blend_for_4_pixels_at_offset 50 src 64 + blend_for_4_pixels_at_offset 50 src 68 + blend_for_4_pixels_at_offset 50 src 72 + blend_for_4_pixels_at_offset 50 src 76 + blend_for_4_pixels_at_offset 50 src 80 + blend_for_4_pixels_at_offset 50 src 84 + blend_for_4_pixels_at_offset 50 src 88 + blend_for_4_pixels_at_offset 50 src 92 + blend_for_4_pixels_at_offset 50 src 96 + blend_for_4_pixels_at_offset 50 src 100 + blend_for_4_pixels_at_offset 50 src 104 + blend_for_4_pixels_at_offset 50 src 108 + blend_for_4_pixels_at_offset 50 src 112 + blend_for_4_pixels_at_offset 50 src 116 + blend_for_4_pixels_at_offset 50 src 120 + blend_for_4_pixels_at_offset 50 src 124 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_128_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + blend_for_4_pixels_at_offset 50 src 16 + blend_for_4_pixels_at_offset 50 src 20 + blend_for_4_pixels_at_offset 50 src 24 + blend_for_4_pixels_at_offset 50 src 28 + blend_for_4_pixels_at_offset 50 src 32 + blend_for_4_pixels_at_offset 50 src 36 + blend_for_4_pixels_at_offset 50 src 40 + blend_for_4_pixels_at_offset 50 src 44 + blend_for_4_pixels_at_offset 50 src 48 + blend_for_4_pixels_at_offset 50 src 52 + blend_for_4_pixels_at_offset 50 src 56 + blend_for_4_pixels_at_offset 50 src 60 + blend_for_4_pixels_at_offset 50 src 64 + blend_for_4_pixels_at_offset 50 src 68 + blend_for_4_pixels_at_offset 50 src 72 + blend_for_4_pixels_at_offset 50 src 76 + blend_for_4_pixels_at_offset 50 src 80 + blend_for_4_pixels_at_offset 50 src 84 + blend_for_4_pixels_at_offset 50 src 88 + blend_for_4_pixels_at_offset 50 src 92 + blend_for_4_pixels_at_offset 50 src 96 + blend_for_4_pixels_at_offset 50 src 100 + blend_for_4_pixels_at_offset 50 src 104 + blend_for_4_pixels_at_offset 50 src 108 + blend_for_4_pixels_at_offset 50 src 112 + blend_for_4_pixels_at_offset 50 src 116 + blend_for_4_pixels_at_offset 50 src 120 + blend_for_4_pixels_at_offset 50 src 124 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_64_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + blend_for_4_pixels_at_offset 50 src 16 + blend_for_4_pixels_at_offset 50 src 20 + blend_for_4_pixels_at_offset 50 src 24 + blend_for_4_pixels_at_offset 50 src 28 + blend_for_4_pixels_at_offset 50 src 32 + blend_for_4_pixels_at_offset 50 src 36 + blend_for_4_pixels_at_offset 50 src 40 + blend_for_4_pixels_at_offset 50 src 44 + blend_for_4_pixels_at_offset 50 src 48 + blend_for_4_pixels_at_offset 50 src 52 + blend_for_4_pixels_at_offset 50 src 56 + blend_for_4_pixels_at_offset 50 src 60 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_64_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + blend_for_4_pixels_at_offset 50 src 16 + blend_for_4_pixels_at_offset 50 src 20 + blend_for_4_pixels_at_offset 50 src 24 + blend_for_4_pixels_at_offset 50 src 28 + blend_for_4_pixels_at_offset 50 src 32 + blend_for_4_pixels_at_offset 50 src 36 + blend_for_4_pixels_at_offset 50 src 40 + blend_for_4_pixels_at_offset 50 src 44 + blend_for_4_pixels_at_offset 50 src 48 + blend_for_4_pixels_at_offset 50 src 52 + blend_for_4_pixels_at_offset 50 src 56 + blend_for_4_pixels_at_offset 50 src 60 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_32_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + blend_for_4_pixels_at_offset 50 src 16 + blend_for_4_pixels_at_offset 50 src 20 + blend_for_4_pixels_at_offset 50 src 24 + blend_for_4_pixels_at_offset 50 src 28 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 32 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_32_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + blend_for_4_pixels_at_offset 50 src 16 + blend_for_4_pixels_at_offset 50 src 20 + blend_for_4_pixels_at_offset 50 src 24 + blend_for_4_pixels_at_offset 50 src 28 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_16_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_16_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + blend_for_4_pixels_at_offset 50 src 8 + blend_for_4_pixels_at_offset 50 src 12 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_8_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 8 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_8_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + blend_for_4_pixels_at_offset 50 src 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_0: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_0_last: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_1: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_1_last: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_2: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_2_last: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_3: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_1_pixel_at_offset_3_last: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_2_pixels_at_offset_0: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_2_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_2_pixels_at_offset_1: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_2_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_2_pixels_at_offset_2: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_2_pixels_at_offset_2_last: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_3_pixels_at_offset_0: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_3_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_3_pixels_at_offset_1: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 50 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_3_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_4_pixels_at_offset_0: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_50_for_4_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_256_pixels_in_loop: + enter_blend_fcn +begin_src_blend_75_loop: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + blend_for_4_pixels_at_offset 75 src 16 + blend_for_4_pixels_at_offset 75 src 20 + blend_for_4_pixels_at_offset 75 src 24 + blend_for_4_pixels_at_offset 75 src 28 + blend_for_4_pixels_at_offset 75 src 32 + blend_for_4_pixels_at_offset 75 src 36 + blend_for_4_pixels_at_offset 75 src 40 + blend_for_4_pixels_at_offset 75 src 44 + blend_for_4_pixels_at_offset 75 src 48 + blend_for_4_pixels_at_offset 75 src 52 + blend_for_4_pixels_at_offset 75 src 56 + blend_for_4_pixels_at_offset 75 src 60 + blend_for_4_pixels_at_offset 75 src 64 + blend_for_4_pixels_at_offset 75 src 68 + blend_for_4_pixels_at_offset 75 src 72 + blend_for_4_pixels_at_offset 75 src 76 + blend_for_4_pixels_at_offset 75 src 80 + blend_for_4_pixels_at_offset 75 src 84 + blend_for_4_pixels_at_offset 75 src 88 + blend_for_4_pixels_at_offset 75 src 92 + blend_for_4_pixels_at_offset 75 src 96 + blend_for_4_pixels_at_offset 75 src 100 + blend_for_4_pixels_at_offset 75 src 104 + blend_for_4_pixels_at_offset 75 src 108 + blend_for_4_pixels_at_offset 75 src 112 + blend_for_4_pixels_at_offset 75 src 116 + blend_for_4_pixels_at_offset 75 src 120 + blend_for_4_pixels_at_offset 75 src 124 + + blend_for_4_pixels_at_offset 75 src 128 + blend_for_4_pixels_at_offset 75 src 132 + blend_for_4_pixels_at_offset 75 src 136 + blend_for_4_pixels_at_offset 75 src 140 + blend_for_4_pixels_at_offset 75 src 144 + blend_for_4_pixels_at_offset 75 src 148 + blend_for_4_pixels_at_offset 75 src 152 + blend_for_4_pixels_at_offset 75 src 156 + blend_for_4_pixels_at_offset 75 src 160 + blend_for_4_pixels_at_offset 75 src 164 + blend_for_4_pixels_at_offset 75 src 168 + blend_for_4_pixels_at_offset 75 src 172 + blend_for_4_pixels_at_offset 75 src 176 + blend_for_4_pixels_at_offset 75 src 180 + blend_for_4_pixels_at_offset 75 src 184 + blend_for_4_pixels_at_offset 75 src 188 + blend_for_4_pixels_at_offset 75 src 192 + blend_for_4_pixels_at_offset 75 src 196 + blend_for_4_pixels_at_offset 75 src 200 + blend_for_4_pixels_at_offset 75 src 204 + blend_for_4_pixels_at_offset 75 src 208 + blend_for_4_pixels_at_offset 75 src 212 + blend_for_4_pixels_at_offset 75 src 216 + blend_for_4_pixels_at_offset 75 src 220 + blend_for_4_pixels_at_offset 75 src 224 + blend_for_4_pixels_at_offset 75 src 228 + blend_for_4_pixels_at_offset 75 src 232 + blend_for_4_pixels_at_offset 75 src 236 + blend_for_4_pixels_at_offset 75 src 240 + blend_for_4_pixels_at_offset 75 src 244 + blend_for_4_pixels_at_offset 75 src 248 + blend_for_4_pixels_at_offset 75 src 252 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 120 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 120 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + addi REG_LOOP_INDEX, REG_LOOP_INDEX, -1 + beqz REG_LOOP_INDEX, end_src_blend_75_loop + j begin_src_blend_75_loop +end_src_blend_75_loop: + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_128_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + blend_for_4_pixels_at_offset 75 src 16 + blend_for_4_pixels_at_offset 75 src 20 + blend_for_4_pixels_at_offset 75 src 24 + blend_for_4_pixels_at_offset 75 src 28 + blend_for_4_pixels_at_offset 75 src 32 + blend_for_4_pixels_at_offset 75 src 36 + blend_for_4_pixels_at_offset 75 src 40 + blend_for_4_pixels_at_offset 75 src 44 + blend_for_4_pixels_at_offset 75 src 48 + blend_for_4_pixels_at_offset 75 src 52 + blend_for_4_pixels_at_offset 75 src 56 + blend_for_4_pixels_at_offset 75 src 60 + blend_for_4_pixels_at_offset 75 src 64 + blend_for_4_pixels_at_offset 75 src 68 + blend_for_4_pixels_at_offset 75 src 72 + blend_for_4_pixels_at_offset 75 src 76 + blend_for_4_pixels_at_offset 75 src 80 + blend_for_4_pixels_at_offset 75 src 84 + blend_for_4_pixels_at_offset 75 src 88 + blend_for_4_pixels_at_offset 75 src 92 + blend_for_4_pixels_at_offset 75 src 96 + blend_for_4_pixels_at_offset 75 src 100 + blend_for_4_pixels_at_offset 75 src 104 + blend_for_4_pixels_at_offset 75 src 108 + blend_for_4_pixels_at_offset 75 src 112 + blend_for_4_pixels_at_offset 75 src 116 + blend_for_4_pixels_at_offset 75 src 120 + blend_for_4_pixels_at_offset 75 src 124 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_128_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + blend_for_4_pixels_at_offset 75 src 16 + blend_for_4_pixels_at_offset 75 src 20 + blend_for_4_pixels_at_offset 75 src 24 + blend_for_4_pixels_at_offset 75 src 28 + blend_for_4_pixels_at_offset 75 src 32 + blend_for_4_pixels_at_offset 75 src 36 + blend_for_4_pixels_at_offset 75 src 40 + blend_for_4_pixels_at_offset 75 src 44 + blend_for_4_pixels_at_offset 75 src 48 + blend_for_4_pixels_at_offset 75 src 52 + blend_for_4_pixels_at_offset 75 src 56 + blend_for_4_pixels_at_offset 75 src 60 + blend_for_4_pixels_at_offset 75 src 64 + blend_for_4_pixels_at_offset 75 src 68 + blend_for_4_pixels_at_offset 75 src 72 + blend_for_4_pixels_at_offset 75 src 76 + blend_for_4_pixels_at_offset 75 src 80 + blend_for_4_pixels_at_offset 75 src 84 + blend_for_4_pixels_at_offset 75 src 88 + blend_for_4_pixels_at_offset 75 src 92 + blend_for_4_pixels_at_offset 75 src 96 + blend_for_4_pixels_at_offset 75 src 100 + blend_for_4_pixels_at_offset 75 src 104 + blend_for_4_pixels_at_offset 75 src 108 + blend_for_4_pixels_at_offset 75 src 112 + blend_for_4_pixels_at_offset 75 src 116 + blend_for_4_pixels_at_offset 75 src 120 + blend_for_4_pixels_at_offset 75 src 124 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_64_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + blend_for_4_pixels_at_offset 75 src 16 + blend_for_4_pixels_at_offset 75 src 20 + blend_for_4_pixels_at_offset 75 src 24 + blend_for_4_pixels_at_offset 75 src 28 + blend_for_4_pixels_at_offset 75 src 32 + blend_for_4_pixels_at_offset 75 src 36 + blend_for_4_pixels_at_offset 75 src 40 + blend_for_4_pixels_at_offset 75 src 44 + blend_for_4_pixels_at_offset 75 src 48 + blend_for_4_pixels_at_offset 75 src 52 + blend_for_4_pixels_at_offset 75 src 56 + blend_for_4_pixels_at_offset 75 src 60 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 64 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 64 + + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_64_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + blend_for_4_pixels_at_offset 75 src 16 + blend_for_4_pixels_at_offset 75 src 20 + blend_for_4_pixels_at_offset 75 src 24 + blend_for_4_pixels_at_offset 75 src 28 + blend_for_4_pixels_at_offset 75 src 32 + blend_for_4_pixels_at_offset 75 src 36 + blend_for_4_pixels_at_offset 75 src 40 + blend_for_4_pixels_at_offset 75 src 44 + blend_for_4_pixels_at_offset 75 src 48 + blend_for_4_pixels_at_offset 75 src 52 + blend_for_4_pixels_at_offset 75 src 56 + blend_for_4_pixels_at_offset 75 src 60 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_32_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + blend_for_4_pixels_at_offset 75 src 16 + blend_for_4_pixels_at_offset 75 src 20 + blend_for_4_pixels_at_offset 75 src 24 + blend_for_4_pixels_at_offset 75 src 28 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 32 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 32 + + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_32_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + blend_for_4_pixels_at_offset 75 src 16 + blend_for_4_pixels_at_offset 75 src 20 + blend_for_4_pixels_at_offset 75 src 24 + blend_for_4_pixels_at_offset 75 src 28 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_16_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 16 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 16 + + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_16_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + blend_for_4_pixels_at_offset 75 src 8 + blend_for_4_pixels_at_offset 75 src 12 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_8_pixels: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 8 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 8 + + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_8_pixels_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + blend_for_4_pixels_at_offset 75 src 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_0: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_0_last: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_1: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_1_last: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_2: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_2_last: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_3: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_1_pixel_at_offset_3_last: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_2_pixels_at_offset_0: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_2_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_2_pixels_at_offset_1: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_2_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_2_pixels_at_offset_2: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_2_pixels_at_offset_2_last: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_3_pixels_at_offset_0: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_3_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_3_pixels_at_offset_1: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 75 src + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_3_pixels_at_offset_1_last: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_4_pixels_at_offset_0: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + addi REG_SRC_PIXEL_PTR, REG_SRC_PIXEL_PTR, 4 + addi REG_DST_PIXEL_PTR, REG_DST_PIXEL_PTR, 4 + leave_blend_fcn + + .align 4 +fcn_src_blend_75_for_4_pixels_at_offset_0_last: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + leave_blend_fcn + + +#define OP025 _025 +#define OP050 _050 +#define OP075 _075 +#define OP100 _100 +#define OPSKP _skp + +#define OPV025 0 +#define OPV050 1 +#define OPV075 2 +#define OPV100 3 +#define OPVSKP 4 +#define NUMOPS 5 + +#define OPMUL0 (NUMOPS*NUMOPS*NUMOPS) +#define OPMUL1 (NUMOPS*NUMOPS) +#define OPMUL2 (NUMOPS) + +#define FCNINX(opv0,opv1,opv2,opv3) (((opv0)*OPMUL0)|((opv1)*OPMUL1)|((opv2)*OPMUL2)|(opv3)) + + .macro begin_op_fcn op0,op1,op2,op3 +fcn\()\op0\()\op1\()\op2\()\op3: + .endm + + .macro end_op_fcn + ret + .endm + + .macro def_op_fcn3 op0,op1,op2,op3 + .global fcn\()\op0\()\op1\()\op2\()\op3 + .endm + + .macro def_op_fcn2 op0,op1,op2 + def_op_fcn3 \op0,\op1,\op2,OP025 + def_op_fcn3 \op0,\op1,\op2,OP050 + def_op_fcn3 \op0,\op1,\op2,OP075 + def_op_fcn3 \op0,\op1,\op2,OP100 + def_op_fcn3 \op0,\op1,\op2,OPSKP + .endm + + .macro def_op_fcn1 op0,op1 + def_op_fcn2 \op0,\op1,OP025 + def_op_fcn2 \op0,\op1,OP050 + def_op_fcn2 \op0,\op1,OP075 + def_op_fcn2 \op0,\op1,OP100 + def_op_fcn2 \op0,\op1,OPSKP + .endm + + .macro def_op_fcn0 op0 + def_op_fcn1 \op0,OP025 + def_op_fcn1 \op0,OP050 + def_op_fcn1 \op0,OP075 + def_op_fcn1 \op0,OP100 + def_op_fcn1 \op0,OPSKP + .endm + + .macro def_op_fcns + def_op_fcn0 OP025 + def_op_fcn0 OP050 + def_op_fcn0 OP075 + def_op_fcn0 OP100 + def_op_fcn0 OPSKP + .endm + + .macro ref_op_fcn3 op0,op1,op2,op3 + .extern fcn\()\op0\()\op1\()\op2\()\op3 + .endm + + .macro ref_op_fcn2 op0,op1,op2 + ref_op_fcn3 \op0,\op1,\op2,OP025 + ref_op_fcn3 \op0,\op1,\op2,OP050 + ref_op_fcn3 \op0,\op1,\op2,OP075 + ref_op_fcn3 \op0,\op1,\op2,OP100 + ref_op_fcn3 \op0,\op1,\op2,OPSKP + .endm + + .macro ref_op_fcn1 op0,op1 + ref_op_fcn2 \op0,\op1,OP025 + ref_op_fcn2 \op0,\op1,OP050 + ref_op_fcn2 \op0,\op1,OP075 + ref_op_fcn2 \op0,\op1,OP100 + ref_op_fcn2 \op0,\op1,OPSKP + .endm + + .macro ref_op_fcn0 op0 + ref_op_fcn1 \op0,OP025 + ref_op_fcn1 \op0,OP050 + ref_op_fcn1 \op0,OP075 + ref_op_fcn1 \op0,OP100 + ref_op_fcn1 \op0,OPSKP + .endm + + .macro ref_op_fcns + ref_op_fcn0 OP025 + ref_op_fcn0 OP050 + ref_op_fcn0 OP075 + ref_op_fcn0 OP100 + ref_op_fcn0 OPSKP + .endm + + def_op_fcns // define all operation functions as global + + .align 4 +fcn_skp_skp_skp_skp: + ret + + .align 4 +fcn_skp_skp_skp_025: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_skp_050: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_skp_075: + enter_blend_fcn + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_skp_100: + copy_xxx3_pixels_at_offset_3 + ret + + .align 4 +fcn_skp_skp_025_skp: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_025_025: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_025_050: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_025_075: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_025_100: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_skp_050_skp: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_050_025: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_050_050: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_050_075: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_050_100: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_skp_075_skp: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_075_025: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_075_050: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_075_075: + enter_blend_fcn + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_075_100: + enter_blend_fcn + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_skp_100_skp: + copy_xx2x_pixels_at_offset_2 + ret + + .align 4 +fcn_skp_skp_100_025: + enter_blend_fcn + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_100_050: + enter_blend_fcn + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_100_075: + enter_blend_fcn + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_skp_100_100: + copy_xx23_pixels_at_offset_2 + ret + + .align 4 +fcn_skp_025_skp_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_skp_025_skp_025: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_skp_025_skp_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_025_skp_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_025_skp_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_025_025_skp: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_skp_025_025_025: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_skp_025_025_050: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_025_025_075: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_025_025_100: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_025_050_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_025_050_025: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_025_050_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_025_050_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_025_050_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_025_075_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_025_075_025: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_025_075_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_025_075_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_025_075_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_025_100_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_025_100_025: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_025_100_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_025_100_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_025_100_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_050_skp_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_skp_050_skp_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_050_skp_050: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_skp_050_skp_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_050_skp_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_050_025_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_050_025_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_050_025_050: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_050_025_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_050_025_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_050_050_skp: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_skp_050_050_025: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_050_050_050: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_skp_050_050_075: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_050_050_100: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_050_075_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_050_075_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_050_075_050: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_050_075_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_050_075_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_050_100_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_050_100_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_050_100_050: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_050_100_075: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_050_100_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_075_skp_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_skp_075_skp_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_075_skp_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_075_skp_075: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_skp_075_skp_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_075_025_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_075_025_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_075_025_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_075_025_075: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_075_025_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_075_050_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_075_050_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_075_050_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_075_050_075: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_075_050_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_075_075_skp: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_skp_075_075_025: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_075_075_050: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_075_075_075: + enter_blend_fcn + blend_for_x123_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_skp_075_075_100: + enter_blend_fcn + blend_for_x12x_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_skp_075_100_skp: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_075_100_025: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_075_100_050: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_075_100_075: + enter_blend_fcn + blend_for_x1x3_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_075_100_100: + enter_blend_fcn + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_skp_100_skp_skp: + copy_x1xx_pixels_at_offset_1 + ret + + .align 4 +fcn_skp_100_skp_025: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_100_skp_050: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_100_skp_075: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_100_skp_100: + copy_x1x3_pixels_at_offset_1 + ret + + .align 4 +fcn_skp_100_025_skp: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_100_025_025: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_100_025_050: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_100_025_075: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_100_025_100: + enter_blend_fcn + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_skp_100_050_skp: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_100_050_025: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_100_050_050: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_100_050_075: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_100_050_100: + enter_blend_fcn + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_skp_100_075_skp: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_100_075_025: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_100_075_050: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_100_075_075: + enter_blend_fcn + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_100_075_100: + enter_blend_fcn + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_skp_100_100_skp: + copy_x12x_pixels_at_offset_1 + ret + + .align 4 +fcn_skp_100_100_025: + enter_blend_fcn + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_skp_100_100_050: + enter_blend_fcn + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_skp_100_100_075: + enter_blend_fcn + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_skp_100_100_100: + copy_x123_pixels_at_offset_1 + ret + + .align 4 +fcn_025_skp_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_025_skp_skp_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_025_skp_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_skp_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_skp_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_skp_025_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_025_skp_025_025: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_025_skp_025_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_skp_025_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_skp_025_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_skp_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_skp_050_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_skp_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_skp_050_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_skp_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_skp_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_skp_075_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_skp_075_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_skp_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_skp_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_skp_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_skp_100_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_skp_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_skp_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_skp_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_025_skp_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_025_025_skp_025: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_025_025_skp_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_025_skp_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_025_skp_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_025_025_skp: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 src + leave_blend_fcn + + .align 4 +fcn_025_025_025_025: + enter_blend_fcn + blend_for_4_pixels_at_offset 25 src 0 + leave_blend_fcn + + .align 4 +fcn_025_025_025_050: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_025_025_075: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_025_025_100: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_025_050_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_025_050_025: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_025_050_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_025_050_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_025_050_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_025_075_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_025_075_025: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_025_075_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_025_075_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_025_075_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_025_100_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_025_100_025: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_025_100_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_025_100_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_025_100_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 25 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_050_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_skp_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_050_025_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_025_025: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_025_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_025_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_025_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_050_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_050_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x123_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_025_050_050_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_050_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_075_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_075_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_050_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_050_100_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_050_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_050_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_050_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_075_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_skp_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_075_025_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_025_025: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_025_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_025_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_025_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_075_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_050_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_050_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_075_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_075_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_075_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x123_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_025_075_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x12x_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_025_075_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_075_100_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_075_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_075_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1x3_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_075_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_025_100_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_skp_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1x3_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_025_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_025_025: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_025_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_025_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_025_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 25 src + copy_x1x3_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_050_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_050_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_075_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_075_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x12x_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_100_025: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 25 src + copy_x12x_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_025_100_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_025_100_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_025_100_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 25 src + copy_x123_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_skp_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_050_skp_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_skp_skp_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_050_skp_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_skp_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_skp_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_skp_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_skp_025_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_skp_025_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_skp_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_skp_050_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_050_skp_050_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_skp_050_050: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_050_skp_050_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_skp_050_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_skp_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_skp_075_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_skp_075_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_skp_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_skp_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_skp_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_skp_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_skp_100_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_skp_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_skp_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_025_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_skp_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_025_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x123_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_025_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_025_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_025_050_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_050_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_050_050: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_050_025_050_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_050_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_025_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_075_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_075_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_025_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_025_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_025_100_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_025_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_025_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_050_skp_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_050_050_skp_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_050_skp_050: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_050_050_skp_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_050_skp_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_050_025_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_050_025_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_050_025_050: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_050_025_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_050_025_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_050_050_skp: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 src + leave_blend_fcn + + .align 4 +fcn_050_050_050_025: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_050_050_050: + enter_blend_fcn + blend_for_4_pixels_at_offset 50 src 0 + leave_blend_fcn + + .align 4 +fcn_050_050_050_075: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_050_050_100: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_050_075_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_050_075_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_050_075_050: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_050_075_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_050_075_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_050_100_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_050_100_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_050_100_050: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_050_100_075: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_050_100_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 50 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_075_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_skp_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_075_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_025_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_025_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_075_050_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_050_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_050_050: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_050_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_050_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_075_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_075_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_075_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x123_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_050_075_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x12x_pixels_at_offset_1 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_050_075_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_075_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_075_100_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_075_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1x3_pixels_at_offset_1 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_075_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + blend_for_x1xx_pixels_at_offset_1 75 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_050_100_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_skp_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_skp_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1x3_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_025_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_025_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_050_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_050_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_050_050: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_050_075: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_050_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 50 src + copy_x1x3_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_075_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_075_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_075_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_075_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_075_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x12x_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_050_100_100_050: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 50 src + copy_x12x_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_050_100_100_075: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_050_100_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 50 src + copy_x123_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_skp_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_075_skp_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_skp_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_skp_skp_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_075_skp_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_skp_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_skp_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_skp_025_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_skp_025_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_skp_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_skp_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_skp_050_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_skp_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_skp_050_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_skp_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_skp_075_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_075_skp_075_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_skp_075_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_skp_075_075: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_075_skp_075_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_skp_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_skp_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_skp_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_skp_100_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_skp_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_025_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_skp_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_025_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x123_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_025_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_025_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_025_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_050_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_050_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_025_075_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_075_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_075_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_075_075: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_075_025_075_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_025_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_025_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_025_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_025_100_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_025_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 25 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_050_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_skp_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_050_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_025_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_025_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_050_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_050_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x123_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_050_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x12x_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_050_075_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_075_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_075_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_075_075: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_075_050_075_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_050_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_050_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_050_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1x3_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_050_100_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_050_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + blend_for_x1xx_pixels_at_offset_1 50 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_075_skp_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_075_075_skp_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_075_skp_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_075_skp_075: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_075_075_skp_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_075_025_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_075_025_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_075_025_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_075_025_075: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_075_025_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_075_050_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_075_050_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_075_050_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_075_050_075: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_075_050_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_075_075_skp: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 src + leave_blend_fcn + + .align 4 +fcn_075_075_075_025: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_075_075_050: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_075_075_075: + enter_blend_fcn + blend_for_4_pixels_at_offset 75 src 0 + leave_blend_fcn + + .align 4 +fcn_075_075_075_100: + enter_blend_fcn + blend_for_012x_pixels_at_offset_0 75 src + copy_xxx3_pixels_at_offset_3 + leave_blend_fcn + + .align 4 +fcn_075_075_100_skp: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_075_100_025: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_075_100_050: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_075_100_075: + enter_blend_fcn + blend_for_01x3_pixels_at_offset_0 75 src + copy_xx2x_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_075_100_100: + enter_blend_fcn + blend_for_01xx_pixels_at_offset_0 75 src + copy_xx23_pixels_at_offset_2 + leave_blend_fcn + + .align 4 +fcn_075_100_skp_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_skp_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_skp_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_skp_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_skp_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1x3_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_025_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_025_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_025_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_025_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_025_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_050_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_050_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_050_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_050_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_050_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x1x3_pixels_at_offset_1 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_075_skp: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_075_025: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_075_050: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_075_075: + enter_blend_fcn + blend_for_0x23_pixels_at_offset_0 75 src + copy_x1xx_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_075_100: + enter_blend_fcn + blend_for_0x2x_pixels_at_offset_0 75 src + copy_x1x3_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_100_skp: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x12x_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_100_025: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_075_100_100_050: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x12x_pixels_at_offset_1 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_075_100_100_075: + enter_blend_fcn + blend_for_0xx3_pixels_at_offset_0 75 src + copy_x12x_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_075_100_100_100: + enter_blend_fcn + blend_for_0xxx_pixels_at_offset_0 75 src + copy_x123_pixels_at_offset_1 + leave_blend_fcn + + .align 4 +fcn_100_skp_skp_skp: + copy_0xxx_pixels_at_offset_0 + ret + + .align 4 +fcn_100_skp_skp_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_skp_skp_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_skp_skp_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_skp_skp_100: + copy_0xx3_pixels_at_offset_0 + ret + + .align 4 +fcn_100_skp_025_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_skp_025_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_skp_025_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_skp_025_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_skp_025_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_skp_050_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_skp_050_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_skp_050_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_skp_050_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_skp_050_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_skp_075_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_skp_075_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_skp_075_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_skp_075_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_skp_075_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_skp_100_skp: + copy_0x2x_pixels_at_offset_0 + ret + + .align 4 +fcn_100_skp_100_025: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_skp_100_050: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_skp_100_075: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_skp_100_100: + copy_0x23_pixels_at_offset_0 + ret + + .align 4 +fcn_100_025_skp_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_skp_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_skp_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_skp_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_skp_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_025_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_025_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x123_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_025_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_025_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_025_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_050_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_050_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_050_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_050_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_050_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_075_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_075_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_075_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_075_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_075_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_100_skp: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_100_025: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_025_100_050: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_025_100_075: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_025_100_100: + enter_blend_fcn + copy_0x23_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_skp_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_skp_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_skp_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_skp_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_skp_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_025_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_025_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_025_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_025_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_025_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_050_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_050_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_050_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x123_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_050_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_050_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_075_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_075_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_075_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_075_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_075_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_100_skp: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_100_025: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_050_100_050: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_050_100_075: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_050_100_100: + enter_blend_fcn + copy_0x23_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_skp_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_skp_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_skp_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_skp_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_skp_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_025_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_025_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_025_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_025_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_025_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_050_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_050_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_050_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_050_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_050_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_075_skp: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_075_025: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_075_050: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_075_075: + enter_blend_fcn + copy_0xxx_pixels_at_offset_0 + blend_for_x123_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_075_100: + enter_blend_fcn + copy_0xx3_pixels_at_offset_0 + blend_for_x12x_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_100_skp: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_100_025: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_075_100_050: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_075_100_075: + enter_blend_fcn + copy_0x2x_pixels_at_offset_0 + blend_for_x1x3_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_075_100_100: + enter_blend_fcn + copy_0x23_pixels_at_offset_0 + blend_for_x1xx_pixels_at_offset_1 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_skp_skp: + copy_01xx_pixels_at_offset_0 + ret + + .align 4 +fcn_100_100_skp_025: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_100_skp_050: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_100_skp_075: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_skp_100: + copy_01x3_pixels_at_offset_0 + ret + + .align 4 +fcn_100_100_025_skp: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_100_025_025: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx23_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_100_025_050: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_100_025_075: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_025_100: + enter_blend_fcn + copy_01x3_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 25 src + leave_blend_fcn + + .align 4 +fcn_100_100_050_skp: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_100_050_025: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_100_050_050: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx23_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_100_050_075: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_050_100: + enter_blend_fcn + copy_01x3_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 50 src + leave_blend_fcn + + .align 4 +fcn_100_100_075_skp: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_075_025: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_100_075_050: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_100_075_075: + enter_blend_fcn + copy_01xx_pixels_at_offset_0 + blend_for_xx23_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_075_100: + enter_blend_fcn + copy_01x3_pixels_at_offset_0 + blend_for_xx2x_pixels_at_offset_2 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_100_skp: + copy_012x_pixels_at_offset_0 + ret + + .align 4 +fcn_100_100_100_025: + enter_blend_fcn + copy_012x_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 25 src + leave_blend_fcn + + .align 4 +fcn_100_100_100_050: + enter_blend_fcn + copy_012x_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 50 src + leave_blend_fcn + + .align 4 +fcn_100_100_100_075: + enter_blend_fcn + copy_012x_pixels_at_offset_0 + blend_for_xxx3_pixels_at_offset_3 75 src + leave_blend_fcn + + .align 4 +fcn_100_100_100_100: + copy_4_pixels_at_offset 0 + ret + +//----------------------------------------- + + .macro tbl_op_fcn3 op0,op1,op2,op3 + .word fcn\()\op0\()\op1\()\op2\()\op3 + .endm + + .macro tbl_op_fcn2 op0,op1,op2 + tbl_op_fcn3 \op0,\op1,\op2,OP025 + tbl_op_fcn3 \op0,\op1,\op2,OP050 + tbl_op_fcn3 \op0,\op1,\op2,OP075 + tbl_op_fcn3 \op0,\op1,\op2,OP100 + tbl_op_fcn3 \op0,\op1,\op2,OPSKP + .endm + + .macro tbl_op_fcn1 op0,op1 + tbl_op_fcn2 \op0,\op1,OP025 + tbl_op_fcn2 \op0,\op1,OP050 + tbl_op_fcn2 \op0,\op1,OP075 + tbl_op_fcn2 \op0,\op1,OP100 + tbl_op_fcn2 \op0,\op1,OPSKP + .endm + + .macro tbl_op_fcn0 op0 + tbl_op_fcn1 \op0,OP025 + tbl_op_fcn1 \op0,OP050 + tbl_op_fcn1 \op0,OP075 + tbl_op_fcn1 \op0,OP100 + tbl_op_fcn1 \op0,OPSKP + .endm + + .macro tbl_op_fcns + tbl_op_fcn0 OP025 + tbl_op_fcn0 OP050 + tbl_op_fcn0 OP075 + tbl_op_fcn0 OP100 + tbl_op_fcn0 OPSKP + .endm + + .align 4 +fcn_ptr_table: + tbl_op_fcns diff --git a/video/src/di_constants.h b/video/src/di_constants.h new file mode 100644 index 00000000..128d309e --- /dev/null +++ b/video/src/di_constants.h @@ -0,0 +1,143 @@ +// di_constants.h - Constants used in agon_crayon files. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) +#define ABS(X) (((X) >= 0) ? (X) : (-(X))) + +#define GPIO_RED_0 GPIO_NUM_21 +#define GPIO_RED_1 GPIO_NUM_22 +#define GPIO_GREEN_0 GPIO_NUM_18 +#define GPIO_GREEN_1 GPIO_NUM_19 +#define GPIO_BLUE_0 GPIO_NUM_4 +#define GPIO_BLUE_1 GPIO_NUM_5 +#define GPIO_HSYNC GPIO_NUM_23 +#define GPIO_VSYNC GPIO_NUM_15 + +#define VS0 0 +#define VS1 1 +#define HS0 0 +#define HS1 1 +#define R0 0 +#define R1 1 +#define R2 2 +#define R3 3 +#define G0 0 +#define G1 1 +#define G2 2 +#define G3 3 +#define B0 0 +#define B1 1 +#define B2 2 +#define B3 3 + +#define VGA_RED_BIT 0 +#define VGA_GREEN_BIT 2 +#define VGA_BLUE_BIT 4 +#define VGA_HSYNC_BIT 6 +#define VGA_VSYNC_BIT 7 + +#define MASK_RGB(r,g,b) (((r)< +#include + +typedef union { + int64_t value64; + struct { + uint32_t low; + int32_t high; + } value32; +} Overlay; + +void DiLineSections::add_piece(uint8_t id, int16_t x, uint16_t width, bool solid) { + auto xe = x + width; + auto encloser = m_pieces.end(); + + for (auto piece = m_pieces.begin(); piece != m_pieces.end(); piece++) { + auto px = piece->m_x; + auto pe = px + piece->m_width; + // (a) px----------pe + // x-----------xe + // + // (b) px----------pe + // x-----------xe + // + // (c) x-------xe + // px--------pe + // + // (d) x-------xe + // px--------pe + // + if (solid || + x >= px && x <= pe || // case (a) + xe >= px && xe <= pe || // case (b) + px >= x && px <= xe || // case (c) + pe >= x && pe <= xe) { // case (d) + // merge the new piece with the old piece + px = MIN(x, px); + piece->m_x = px; + pe = MAX(xe, pe); + piece->m_width = pe - px; + + // check whether to merge with the next piece + while (true) { + auto next_piece = piece + 1; + if (next_piece == m_pieces.end()) { + break; + } + auto pe = piece->m_x + piece->m_width; + if (solid || pe >= next_piece->m_x) { + auto ne = next_piece->m_x + next_piece->m_width; + auto nw = ne - piece->m_x; + piece->m_width = MAX(piece->m_width, nw); + m_pieces.erase(next_piece); + } else { + break; + } + } + return; + } else if (xe < px) { + // insert a new piece before the old piece + DiLinePiece new_piece; + new_piece.m_id = id; + new_piece.m_x = x; + new_piece.m_width = width; + m_pieces.insert(piece, new_piece); + return; + } + } + // insert a new piece after the old piece + DiLinePiece new_piece; + new_piece.m_id = id; + new_piece.m_x = x; + new_piece.m_width = width; + m_pieces.push_back(new_piece); +} + +//------------------------------------------------------------------------------- + +DiLineDetails::DiLineDetails() { + m_min_x = 0; + m_min_y = 0; + m_max_x = 0; + m_max_y = 0; +} + +DiLineDetails::~DiLineDetails() { +} + +void DiLineDetails::make_line(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool solid) { + auto min_x = MIN(x1, x2); + auto max_x = MAX(x1, x2); + auto min_y = MIN(y1, y2); + auto max_y = MAX(y1, y2); + auto flip_vertically = (x1y2); + auto flip_horizontally = (x1>x2 && y1m_pieces.begin(); + piece != sections->m_pieces.end(); + piece++) { + } + y++; + } +} + +void DiLineDetails::make_solid_triangle(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3) { + make_line(id, x1, y1, x2, y2, true); + make_line(id, x2, y2, x3, y3, true); + make_line(id, x3, y3, x1, y1, true); +} + +void DiLineDetails::make_quad_outline(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, + int16_t x3, int16_t y3, int16_t x4, int16_t y4) { + make_line(id, x1, y1, x2, y2, false); + make_line(id, x2, y2, x3, y3, false); + make_line(id, x3, y3, x4, y4, false); + make_line(id, x4, y4, x1, y1, false); +} + +void DiLineDetails::make_solid_quad(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, + int16_t x3, int16_t y3, int16_t x4, int16_t y4) { + make_line(id, x1, y1, x2, y2, true); + make_line(id, x2, y2, x3, y3, true); + make_line(id, x3, y3, x4, y4, true); + make_line(id, x4, y4, x1, y1, true); +} + +void DiLineDetails::add_piece(uint8_t id, int16_t x, int16_t y, uint16_t width, bool solid) { + if (m_sections.size()) { + // determine whether to add a new section + if (y < m_min_y) { + // insert one or more new sections at lower Y values + auto new_count = m_min_y - y; + DiLineSections new_sections; + m_sections.insert(m_sections.begin(), new_count, new_sections); + m_sections[0].add_piece(id, x, width, solid); + m_min_y = y; + } else if (y > m_max_y) { + // insert one or more new sections at higher Y values + auto new_count = y - m_max_y; + DiLineSections new_sections; + m_sections.resize(m_sections.size() + new_count); + m_sections[m_sections.size() - 1].add_piece(id, x, width, solid); + m_max_y = y; + } else { + // reuse an existing section with the same Y value + m_sections[y - m_min_y].add_piece(id, x, width, solid); + } + m_min_x = MIN(m_min_x, x); + m_max_x = MAX(m_max_x, x); + } else { + // add the first section + DiLineSections new_section; + new_section.add_piece(id, x, width, solid); + m_sections.push_back(new_section); + m_min_x = x; + m_min_y = y; + m_max_x = x; + m_max_y = y; + } +} + +void DiLineDetails::merge(const DiLineDetails& details) { + auto y = details.m_min_y; + for (auto sections = details.m_sections.begin(); + sections != details.m_sections.end(); + sections++) { + for (auto piece = sections->m_pieces.begin(); + piece != sections->m_pieces.end(); + piece++) { + add_piece(piece->m_id, piece->m_x, y, piece->m_width, false); + } + y++; + } +} \ No newline at end of file diff --git a/video/src/di_line_pieces.h b/video/src/di_line_pieces.h new file mode 100644 index 00000000..f5401fd6 --- /dev/null +++ b/video/src/di_line_pieces.h @@ -0,0 +1,94 @@ +// di_line_pieces.h - Function declarations for generating line pieces +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include +#include +#include "di_constants.h" + +#pragma pack(push,1) + +// This structure tells how to draw a section of a line, +// on a single scan line that intersects with that line, +// and represents a (possibly) short section of a larger line. +typedef struct { + uint8_t m_id; + int16_t m_x; + uint16_t m_width; +} DiLinePiece; + +#pragma pack(pop) + +// This structure tells how to draw sections of one or more lines, +// on a single scan line that intersects with those lines, +// and represents (possibly) short sections of larger lines. +class DiLineSections { + public: + std::vector m_pieces; + + // Each added piece represents colored pixels, meaning + // pixels that are drawn. + void add_piece(uint8_t id, int16_t x, uint16_t width, bool solid); +}; + +// This class represents enough details to draw a set of lines, +// based on sections of them, arranged by scan lines. +// +class DiLineDetails { + public: + int16_t m_min_x; + int16_t m_min_y; + int16_t m_max_x; + int16_t m_max_y; + std::vector m_sections; + + // Constructs an empty object. You must call a function below to create the line sections. + DiLineDetails(); + + // Destroys the line sections. + ~DiLineDetails(); + + // This function creates line sections for a line from two points. + void make_line(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, bool solid); + + // This function creates a triangle outline from three points. + void make_triangle_outline(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3); + + // This function creates a solid (filled) triangle from three points. + void make_solid_triangle(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, int16_t x3, int16_t y3); + + // This function creates a quad outline from four points. + void make_quad_outline(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, + int16_t x3, int16_t y3, int16_t x4, int16_t y4); + + // This function creates a solid (filled) quad from four points. + void make_solid_quad(uint8_t id, int16_t x1, int16_t y1, int16_t x2, int16_t y2, + int16_t x3, int16_t y3, int16_t x4, int16_t y4); + + // Each added piece represents colored pixels, meaning + // pixels that are drawn. + void add_piece(uint8_t id, int16_t x, int16_t y, uint16_t width, bool solid); + + // This function merges the given set of details with this set. + void merge(const DiLineDetails& details); +}; diff --git a/video/src/di_manager.cpp b/video/src/di_manager.cpp new file mode 100644 index 00000000..9a5e141e --- /dev/null +++ b/video/src/di_manager.cpp @@ -0,0 +1,3134 @@ +// di_manager.cpp - Function definitions for managing drawing-instruction primitives +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_manager.h" + +#include +#include "soc/i2s_struct.h" +#include "soc/i2s_reg.h" +#include "driver/periph_ctrl.h" +#include "soc/rtc.h" +#include "driver/gpio.h" +#include "soc/io_mux_reg.h" +#include "fabgl_pieces.h" + +#include "di_general_line.h" +#include "di_horiz_line.h" +#include "di_set_pixel.h" +#include "di_vert_line.h" +#include "di_ellipse.h" +#include "di_solid_ellipse.h" +#include "di_rectangle.h" +#include "di_solid_rectangle.h" +#include "di_tile_map.h" +#include "di_bitmap.h" + +#include "../agon.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "soc/i2s_struct.h" +#include "soc/i2s_reg.h" +#include "ESP32Time.h" +#include "HardwareSerial.h" + +// These things are defined in video.ino, already. +typedef uint8_t byte; +extern void send_packet(uint8_t code, uint16_t len, uint8_t data[]); +extern void sendTime(); +extern void stream_send_keyboard_state(); +extern void sendPlayNote(int channel, int success); +extern void setKeyboardLayout(uint8_t region); +extern void do_keyboard(); +extern void do_mouse(); +extern bool initialised; +extern bool logicalCoords; +extern bool cursorEnabled; +extern int videoMode; + +extern bool stream_byte_available(); +extern uint8_t stream_read_byte(); + +namespace fabgl { + extern uint8_t FONT_AGON_DATA[256*8]; +} + +extern "C" { +extern void fcn_copy_words_in_loop(void* dst, void* src, uint32_t num_words); +} + +typedef enum { + WritingActiveLines, + ProcessingIncomingData, + NearNewFrameStart +} LoopState; + +// Default callback functions +void default_on_vertical_blank() {} + +DiManager::DiManager() { + m_next_buffer_write = 0; + m_next_buffer_read = 0; + m_num_buffer_chars = 0; + m_text_area = NULL; + m_cursor = NULL; + m_flash_count = 0; + m_on_vertical_blank_cb = &default_on_vertical_blank; + memset(m_primitives, 0, sizeof(m_primitives)); + m_groups = new std::vector[otf_video_params.m_active_lines]; + + logicalCoords = false; // this mode always uses regular coordinates +} + +DiManager::~DiManager() { + clear(); + delete [] m_groups; + + if (m_video_lines) { + delete m_video_lines; + } + if (m_front_porch) { + delete m_front_porch; + } + if (m_vertical_sync) { + delete m_vertical_sync; + } + if (m_back_porch) { + delete m_back_porch; + } +} + +void DiManager::create_root() { + // The root primitive covers the entire screen, and is not drawn. + // The application should define what the base layer of the screen + // is (e.g., solid rectangle, text_area, tile map, etc.). + + DiPrimitive* root = new DiPrimitive(0); + root->init_root(); + m_primitives[ROOT_PRIMITIVE_ID] = root; +} + +void DiManager::initialize() { + size_t new_size = (size_t)(sizeof(lldesc_t) * otf_video_params.m_dma_total_descr); + void* p = heap_caps_malloc(new_size, MALLOC_CAP_32BIT|MALLOC_CAP_8BIT|MALLOC_CAP_DMA); + m_dma_descriptor = (volatile lldesc_t *)p; + + m_video_lines = new DiVideoScanLine(NUM_ACTIVE_BUFFERS); + m_front_porch = new DiVideoScanLine(1); + m_vertical_sync = new DiVideoScanLine(1); + m_back_porch = new DiVideoScanLine(1); + // DMA buffer chain: ACT + uint32_t descr_index = 0; + m_video_lines->init_to_black(); + for (uint32_t i = 0; i < otf_video_params.m_active_lines; i++) { + if (otf_video_params.m_scan_count == 1) { + init_dma_descriptor(m_video_lines, (i & (NUM_ACTIVE_BUFFERS - 1)), descr_index++); + } else if (otf_video_params.m_scan_count == 2) { + init_dma_descriptor(m_video_lines, (i & (NUM_ACTIVE_BUFFERS - 1)), descr_index++); + init_dma_descriptor(m_video_lines, (i & (NUM_ACTIVE_BUFFERS - 1)), descr_index++); + } else if (otf_video_params.m_scan_count == 4) { + init_dma_descriptor(m_video_lines, (i & (NUM_ACTIVE_BUFFERS - 1)), descr_index++); + init_dma_descriptor(m_video_lines, (i & (NUM_ACTIVE_BUFFERS - 1)), descr_index++); + init_dma_descriptor(m_video_lines, (i & (NUM_ACTIVE_BUFFERS - 1)), descr_index++); + init_dma_descriptor(m_video_lines, (i & (NUM_ACTIVE_BUFFERS - 1)), descr_index++); + } + } + + // DMA buffer chain: VFP + m_front_porch->init_to_black(); + for (uint i = 0; i < otf_video_params.m_vfp_lines; i++) { + init_dma_descriptor(m_front_porch, 0, descr_index++); + } + + // DMA buffer chain: VS + m_vertical_sync->init_for_vsync(); + for (uint i = 0; i < otf_video_params.m_vs_lines; i++) { + init_dma_descriptor(m_vertical_sync, 0, descr_index++); + } + + // DMA buffer chain: VBP + m_back_porch->init_to_black(); + for (uint i = 0; i < otf_video_params.m_vbp_lines; i++) { + init_dma_descriptor(m_back_porch, 0, descr_index++); + } + + // GPIO configuration for color bits + setupGPIO(GPIO_RED_0, VGA_RED_BIT, GPIO_MODE_OUTPUT); + setupGPIO(GPIO_RED_1, VGA_RED_BIT + 1, GPIO_MODE_OUTPUT); + setupGPIO(GPIO_GREEN_0, VGA_GREEN_BIT, GPIO_MODE_OUTPUT); + setupGPIO(GPIO_GREEN_1, VGA_GREEN_BIT + 1, GPIO_MODE_OUTPUT); + setupGPIO(GPIO_BLUE_0, VGA_BLUE_BIT, GPIO_MODE_OUTPUT); + setupGPIO(GPIO_BLUE_1, VGA_BLUE_BIT + 1, GPIO_MODE_OUTPUT); + + // GPIO configuration for VSync and HSync + setupGPIO(GPIO_HSYNC, VGA_HSYNC_BIT, GPIO_MODE_OUTPUT); + setupGPIO(GPIO_VSYNC, VGA_VSYNC_BIT, GPIO_MODE_OUTPUT); + + // Start the DMA + + // Power on device + periph_module_enable(PERIPH_I2S1_MODULE); + + // Initialize I2S device + I2S1.conf.tx_reset = 1; + I2S1.conf.tx_reset = 0; + + // Reset DMA + I2S1.lc_conf.out_rst = 1; + I2S1.lc_conf.out_rst = 0; + + // Reset FIFO + I2S1.conf.tx_fifo_reset = 1; + I2S1.conf.tx_fifo_reset = 0; + + // Stop DMA clock + I2S1.clkm_conf.clk_en = 0; + + // LCD mode + I2S1.conf2.val = 0; + I2S1.conf2.lcd_en = 1; + I2S1.conf2.lcd_tx_wrx2_en = (otf_video_params.m_scan_count >= 2 ? 1 : 0); + I2S1.conf2.lcd_tx_sdx2_en = 0; + + I2S1.sample_rate_conf.val = 0; + I2S1.sample_rate_conf.tx_bits_mod = 8; + + // Start DMA clock + APLLParams prms = {0, 0, 0, 0}; + double error, out_freq; + uint8_t a = 1, b = 0; + APLLCalcParams(otf_video_params.m_dma_clock_freq, &prms, &a, &b, &out_freq, &error); + + I2S1.clkm_conf.val = 0; + I2S1.clkm_conf.clkm_div_b = b; + I2S1.clkm_conf.clkm_div_a = a; + I2S1.clkm_conf.clkm_div_num = 2; // not less than 2 + + I2S1.sample_rate_conf.tx_bck_div_num = 1; // this makes I2S1O_BCK = I2S1_CLK + + rtc_clk_apll_enable(true, prms.sdm0, prms.sdm1, prms.sdm2, prms.o_div); + + I2S1.clkm_conf.clka_en = 1; + + // Setup FIFO + I2S1.fifo_conf.val = 0; + I2S1.fifo_conf.tx_fifo_mod_force_en = 1; + I2S1.fifo_conf.tx_fifo_mod = 1; + I2S1.fifo_conf.tx_fifo_mod = 1; + I2S1.fifo_conf.tx_data_num = 32; + I2S1.fifo_conf.dscr_en = 1; + + I2S1.conf1.val = 0; + I2S1.conf1.tx_stop_en = 0; + I2S1.conf1.tx_pcm_bypass = 1; + + I2S1.conf_chan.val = 0; + I2S1.conf_chan.tx_chan_mod = 1; + + //I2S1.conf.tx_right_first = 0; + I2S1.conf.tx_right_first = 1; + + I2S1.timing.val = 0; + + // Reset AHB interface of DMA + I2S1.lc_conf.ahbm_rst = 1; + I2S1.lc_conf.ahbm_fifo_rst = 1; + I2S1.lc_conf.ahbm_rst = 0; + I2S1.lc_conf.ahbm_fifo_rst = 0; + + // Prepare to start DMA + I2S1.lc_conf.val = I2S_OUT_DATA_BURST_EN | I2S_OUTDSCR_BURST_EN; + I2S1.out_link.addr = (uint32_t)m_dma_descriptor; + I2S1.int_clr.val = 0xFFFFFFFF; + +/////////////////// +/* +#define SHOWIT(dd) debug_log(#dd ": %u %X\n", dd, dd); + SHOWIT(I2S1.conf2.val) + SHOWIT(I2S1.conf2.lcd_en) + SHOWIT(I2S1.conf2.lcd_tx_wrx2_en) + SHOWIT(I2S1.conf2.lcd_tx_sdx2_en) + + SHOWIT(I2S1.sample_rate_conf.val) + SHOWIT(I2S1.sample_rate_conf.tx_bits_mod) + + SHOWIT(I2S1.clkm_conf.val) + SHOWIT(I2S1.clkm_conf.clkm_div_b) + SHOWIT(I2S1.clkm_conf.clkm_div_a) + SHOWIT(I2S1.clkm_conf.clkm_div_num) + SHOWIT(I2S1.sample_rate_conf.tx_bck_div_num) + SHOWIT(I2S1.clkm_conf.clka_en) + + SHOWIT(I2S1.fifo_conf.val) + SHOWIT(I2S1.fifo_conf.tx_fifo_mod_force_en) + SHOWIT(I2S1.fifo_conf.tx_fifo_mod) + SHOWIT(I2S1.fifo_conf.tx_fifo_mod) + SHOWIT(I2S1.fifo_conf.tx_data_num) + SHOWIT(I2S1.fifo_conf.dscr_en) + + SHOWIT(I2S1.conf1.val) + SHOWIT(I2S1.conf1.tx_stop_en) + SHOWIT(I2S1.conf1.tx_pcm_bypass) + + SHOWIT(I2S1.conf_chan.val) + SHOWIT(I2S1.conf_chan.tx_chan_mod) + + SHOWIT(I2S1.conf.tx_right_first) + + SHOWIT(I2S1.timing.val) + + SHOWIT(I2S1.lc_conf.ahbm_rst) + SHOWIT(I2S1.lc_conf.ahbm_fifo_rst) + SHOWIT(I2S1.lc_conf.ahbm_rst) + SHOWIT(I2S1.lc_conf.ahbm_fifo_rst) + + SHOWIT(I2S1.lc_conf.val) + SHOWIT(I2S1.out_link.addr) + SHOWIT(I2S1.int_clr.val) + SHOWIT(I2S1.out_link.start) + SHOWIT(I2S1.conf.tx_start) +*/ +/////////////////// + + // Start DMA + I2S1.out_link.start = 1; + I2S1.conf.tx_start = 1; +} + +void DiManager::clear() { + for (int g = 0; g < otf_video_params.m_active_lines; g++) { + std::vector * vp = &m_groups[g]; + vp->clear(); + } + + for (int i = FIRST_PRIMITIVE_ID; i <= LAST_PRIMITIVE_ID; i++) { + if (m_primitives[i]) { + delete m_primitives[i]; + m_primitives[i] = NULL; + } + } + m_primitives[ROOT_PRIMITIVE_ID]->clear_child_ptrs(); + + heap_caps_free((void*)m_dma_descriptor); +} + +void DiManager::add_primitive(DiPrimitive* prim, DiPrimitive* parent) { + auto old_prim = m_primitives[prim->get_id()]; + if (old_prim) { + remove_primitive(old_prim); + } + + parent->attach_child(prim); + while (parent != m_primitives[ROOT_PRIMITIVE_ID] && !(parent->get_flags() & PRIM_FLAG_CLIP_KIDS)) { + parent = parent->get_parent(); + } + + m_primitives[prim->get_id()] = prim; + recompute_primitive(prim, 0, -1, -1); +} + +void DiManager::remove_primitive(DiPrimitive* prim) { + if (prim) { + if (prim->get_flags() & PRIM_FLAGS_CAN_DRAW) { + int32_t min_group, max_group; + if (prim->get_vertical_group_range(min_group, max_group)) { + for (int32_t g = min_group; g <= max_group; g++) { + std::vector * vp = &m_groups[g]; + auto position2 = std::find(vp->begin(), vp->end(), prim); + if (position2 != vp->end()) { + vp->erase(position2); + } + } + } + } + + prim->get_parent()->detach_child(prim); + DiPrimitive* child = prim->get_first_child(); + while (child) { + DiPrimitive* next = child->get_next_sibling(); + remove_primitive(child); + child = next; + } + + m_primitives[prim->get_id()] = NULL; + delete prim; + } +} + +void DiManager::recompute_primitive(DiPrimitive* prim, uint16_t old_flags, + int32_t old_min_group, int32_t old_max_group) { + prim->compute_absolute_geometry(); + bool old_use_groups = (old_min_group >= 0); + bool new_use_groups = false; + int32_t new_min_group = -1; + int32_t new_max_group = -1; + if (prim->get_flags() & PRIM_FLAG_PAINT_THIS) { + new_use_groups = prim->get_vertical_group_range(new_min_group, new_max_group); + } + + if (old_use_groups) { + if (new_use_groups) { + // Adjust which groups primitive is in + // + // There are several (vertical) cases: + // 1. New groups fully above old groups. + // 2. New groups cross first old group, but not last old group. + // 3. New groups fully within old groups. + // 4. New groups cross last old group, but not first old group. + // 5. New groups fully below old groups. + // 6. Old groups fully within new groups. + + if (old_min_group < new_min_group) { + // Remove primitive from old groups that are above new groups + int32_t end = MIN((old_max_group+1), new_min_group); + for (int32_t g = old_min_group; g < end; g++) { + std::vector * vp = &m_groups[g]; + auto position2 = std::find(vp->begin(), vp->end(), prim); + if (position2 != vp->end()) { + vp->erase(position2); + } + } + } + + if (old_max_group > new_max_group) { + // Remove primitive from old groups that are below new groups + int32_t begin = MAX((new_max_group+1), old_min_group); + for (int32_t g = begin; g <= old_max_group; g++) { + std::vector * vp = &m_groups[g]; + auto position2 = std::find(vp->begin(), vp->end(), prim); + if (position2 != vp->end()) { + vp->erase(position2); + } + } + } + + if (new_min_group < old_min_group) { + // Add primitive to new groups that are above old groups + int32_t end = MIN((new_max_group+1), old_min_group); + for (int32_t g = new_min_group; g < end; g++) { + std::vector * vp = &m_groups[g]; + insert_primitive_into_vertical_group(prim, vp); + } + } + + if (new_max_group > old_max_group) { + // Add primitive to new groups that are below old groups + int32_t begin = MAX((old_max_group+1), new_min_group); + for (int32_t g = begin; g <= new_max_group; g++) { + std::vector * vp = &m_groups[g]; + insert_primitive_into_vertical_group(prim, vp); + } + } + prim->add_flags(PRIM_FLAGS_CAN_DRAW); + } else { + // Just remove primitive from old groups + for (int32_t g = old_min_group; g <= old_max_group; g++) { + std::vector * vp = &m_groups[g]; + auto position2 = std::find(vp->begin(), vp->end(), prim); + if (position2 != vp->end()) { + vp->erase(position2); + } + } + prim->remove_flags(PRIM_FLAGS_CAN_DRAW); + } + } else { + if (new_use_groups) { + // Just place primitive into new groups + for (int32_t g = new_min_group; g <= new_max_group; g++) { + std::vector * vp = &m_groups[g]; + insert_primitive_into_vertical_group(prim, vp); + } + prim->add_flags(PRIM_FLAGS_CAN_DRAW); + } else { + prim->remove_flags(PRIM_FLAGS_CAN_DRAW); + } + } +} + +void DiManager::insert_primitive_into_vertical_group(DiPrimitive* prim, std::vector * vp) { + auto prim_id = prim->get_id(); + for (auto grouped_prim = vp->begin(); grouped_prim != vp->end(); grouped_prim++) { + if (prim_id < (*grouped_prim)->get_id()) { + vp->insert(grouped_prim, prim); + return; + } + } + vp->push_back(prim); +} + +DiPrimitive* DiManager::finish_create(uint16_t id, DiPrimitive* prim, DiPrimitive* parent_prim) { + prim->set_id(id); + add_primitive(prim, parent_prim); + return prim; +} + +DiPrimitive* DiManager::create_point(OtfCmd_10_Create_primitive_Point* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + DiPrimitive* prim = new DiSetPixel(cmd->m_flags, cmd->m_x, cmd->m_y, cmd->m_color); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_line(OtfCmd_20_Create_primitive_Line* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto sep_color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(sep_color); + DiPrimitive* prim; + if (cmd->m_x1 == cmd->m_x2) { + if (cmd->m_y1 == cmd->m_y2) { + prim = new DiSetPixel(cmd->m_flags, cmd->m_x1, cmd->m_y1, cmd->m_color); + } else if (cmd->m_y1 < cmd->m_y2) { + auto line = new DiVerticalLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_y2 - cmd->m_y1 + 1, cmd->m_color); + prim = line; + } else { + auto line = new DiVerticalLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y2, cmd->m_y1 - cmd->m_y2 + 1, cmd->m_color); + prim = line; + } + } else if (cmd->m_x1 < cmd->m_x2) { + if (cmd->m_y1 == cmd->m_y2) { + auto line = new DiHorizontalLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2 - cmd->m_x1 + 1, cmd->m_color); + prim = line; + } else if (cmd->m_y1 < cmd->m_y2) { + if (cmd->m_y2 - cmd->m_y1 == cmd->m_x2 - cmd->m_x1) { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } else { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } + } else { + if (cmd->m_y2 - cmd->m_y1 == cmd->m_x2 - cmd->m_x1) { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } else { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } + } + } else { + if (cmd->m_y1 == cmd->m_y2) { + auto line = new DiHorizontalLine(cmd->m_flags); + line->make_line(cmd->m_x2, cmd->m_y1, cmd->m_x1 - cmd->m_x2 + 1, cmd->m_color); + prim = line; + } else if (cmd->m_y1 < cmd->m_y2) { + if (cmd->m_y2 - cmd->m_y1 == cmd->m_x1 - cmd->m_x2) { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } else { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } + } else { + if (cmd->m_y2 - cmd->m_y1 == cmd->m_x1 - cmd->m_x2) { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } else { + auto line = new DiGeneralLine(cmd->m_flags); + line->make_line(cmd->m_x1, cmd->m_y1, cmd->m_x2, cmd->m_y2, sep_color, opaqueness); + prim = line; + } + } + } + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiSolidRectangle* DiManager::create_solid_rectangle(OtfCmd_41_Create_primitive_Solid_Rectangle* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_ALL_SAME; + auto prim = new DiSolidRectangle(cmd->m_flags); + prim->make_rectangle(cmd->m_x, cmd->m_y, cmd->m_w, cmd->m_h, cmd->m_color); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiPrimitive* DiManager::create_triangle_outline(OtfCmd_30_Create_primitive_Triangle_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_triangle_outline(&cmd->m_x1, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_triangle(OtfCmd_31_Create_primitive_Solid_Triangle* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_solid_triangle(&cmd->m_x1, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_triangle_list_outline(OtfCmd_32_Create_primitive_Triangle_List_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_triangle_list_outline(cmd->m_coords, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_triangle_list(OtfCmd_33_Create_primitive_Solid_Triangle_List* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_solid_triangle_list(cmd->m_coords, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_triangle_fan_outline(OtfCmd_34_Create_primitive_Triangle_Fan_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_triangle_fan_outline(&cmd->m_sx0, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_triangle_fan(OtfCmd_35_Create_primitive_Solid_Triangle_Fan* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_solid_triangle_fan(&cmd->m_sx0, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_triangle_strip_outline(OtfCmd_36_Create_primitive_Triangle_Strip_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_triangle_strip_outline(&cmd->m_sx0, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_triangle_strip(OtfCmd_37_Create_primitive_Solid_Triangle_Strip* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_solid_triangle_strip(&cmd->m_sx0, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_quad_outline(OtfCmd_60_Create_primitive_Quad_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_quad_outline(&cmd->m_x1, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_quad(OtfCmd_61_Create_primitive_Solid_Quad* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_solid_quad(&cmd->m_x1, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_quad_list_outline(OtfCmd_62_Create_primitive_Quad_List_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_quad_list_outline(cmd->m_coords, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_quad_list(OtfCmd_63_Create_primitive_Solid_Quad_List* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_solid_quad_list(cmd->m_coords, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_quad_strip_outline(OtfCmd_64_Create_primitive_Quad_Strip_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_quad_strip_outline(&cmd->m_sx0, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_quad_strip(OtfCmd_65_Create_primitive_Solid_Quad_Strip* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiGeneralLine(cmd->m_flags); + auto color = cmd->m_color; + uint8_t opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + prim->make_solid_quad_strip(&cmd->m_sx0, cmd->m_n, color, opaqueness); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiTileMap* DiManager::create_tile_map(OtfCmd_100_Create_primitive_Tile_Map* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + DiTileMap* tile_map = + new DiTileMap(cmd->m_w, cmd->m_h, cmd->m_columns, cmd->m_rows, cmd->m_tw, cmd->m_th, cmd->m_flags); + + finish_create(cmd->m_id, tile_map, parent_prim); + return tile_map; +} + +DiTileArray* DiManager::create_tile_array(OtfCmd_80_Create_primitive_Tile_Array* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + DiTileArray* tile_array = + new DiTileArray(cmd->m_w, cmd->m_h, cmd->m_columns, cmd->m_rows, cmd->m_tw, cmd->m_th, cmd->m_flags); + + finish_create(cmd->m_id, tile_array, parent_prim); + return tile_array; +} + +DiTextArea* DiManager::create_text_area(OtfCmd_150_Create_primitive_Text_Area* cmd, const uint8_t* font) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + DiTextArea* text_area = new DiTextArea(cmd->m_x, cmd->m_y, cmd->m_flags, cmd->m_columns, cmd->m_rows, font); + + finish_create(cmd->m_id, text_area, parent_prim); + m_text_area = text_area; + text_area->set_background_color(cmd->m_bgcolor); + text_area->set_foreground_color(cmd->m_fgcolor); + text_area->clear_screen(); + + if (m_cursor) { + // Hide the current cursor (from another text area) + set_primitive_flags(m_cursor->get_id(), m_cursor->get_flags() & ~(PRIM_FLAG_PAINT_THIS|PRIM_FLAG_PAINT_KIDS)); + } + + // Create a child rectangle as a text cursor. + int16_t cx, cy, cx_extent, cy_extent; + cx = cy = cx_extent = cy_extent = 0; + m_text_area->get_rel_tile_coordinates(0, 0, cx, cy, cx_extent, cy_extent); + auto w = cx_extent - cx; + + OtfCmd_41_Create_primitive_Solid_Rectangle cursor_cmd; + cursor_cmd.m_id = cmd->m_id + 1; + cursor_cmd.m_pid = cmd->m_id; + cursor_cmd.m_flags = cmd->m_flags & PRIM_FLAGS_DEFAULT; + cursor_cmd.m_x = cx; + cursor_cmd.m_y = cy_extent - 2; + cursor_cmd.m_w = w; + cursor_cmd.m_h = 2; + cursor_cmd.m_color = cmd->m_fgcolor; + m_cursor = create_solid_rectangle(&cursor_cmd); + cursorEnabled = true; + + send_cursor_position(); + return text_area; +} + +void IRAM_ATTR DiManager::run() { + initialize(); + loop(); + clear(); +} + +void IRAM_ATTR DiManager::loop() { + uint32_t current_line_index = 0; + uint32_t current_buffer_index = 0; + uint32_t frame_count = 0; + LoopState loop_state = LoopState::NearNewFrameStart; + + while (true) { + uint32_t descr_addr = (uint32_t) I2S1.out_link_dscr; + + uint32_t descr_index = (descr_addr - (uint32_t)m_dma_descriptor) / sizeof(lldesc_t); + uint32_t descr_index_div; + if (otf_video_params.m_scan_count == 2) { + descr_index_div = (descr_index >> 1); + } else if (otf_video_params.m_scan_count == 4) { + descr_index_div = (descr_index >> 2); + } else { + descr_index_div = descr_index; + } + + if (descr_index_div < otf_video_params.m_active_lines) { + + uint32_t dma_buffer_index = descr_index_div & (NUM_ACTIVE_BUFFERS-1); + if (dma_buffer_index != current_buffer_index) { + draw_primitives(m_video_lines->get_buffer_ptr(dma_buffer_index), descr_index_div); + current_buffer_index = dma_buffer_index; + } + loop_state = LoopState::WritingActiveLines; + + while (stream_byte_available()) { + store_character(stream_read_byte()); + } + } else if (loop_state == LoopState::WritingActiveLines) { + // Timing just moved into the vertical blanking area. + process_stored_characters(); + while (stream_byte_available()) { + process_character(stream_read_byte()); + } + (*m_on_vertical_blank_cb)(); + + if (cursorEnabled && m_cursor) { + auto flags = m_cursor->get_flags(); + auto cid = m_cursor->get_id(); + if ((flags & PRIM_FLAG_PAINT_THIS) == 0) { + if (++m_flash_count >= 50) { + // turn ON cursor + m_text_area->bring_current_position_into_view(); + int16_t cx, cy, cx_extent, cy_extent; + cx = cy = cx_extent = cy_extent = 0; + uint16_t col = 0; + uint16_t row = 0; + m_text_area->get_position(col, row); + m_text_area->get_rel_tile_coordinates(col, row, cx, cy, cx_extent, cy_extent); + auto w = cx_extent - cx; + set_primitive_flags(cid, flags | PRIM_FLAG_PAINT_THIS); + auto y = cy_extent - 2; + if (m_cursor->get_relative_x() != cx || m_cursor->get_relative_y() != y) { + set_primitive_position(cid, cx, y); + } + m_flash_count = 0; + } + } else { + if (++m_flash_count >= 10) { + // turn OFF cursor + set_primitive_flags(cid, flags ^ PRIM_FLAG_PAINT_THIS); + m_flash_count = 0; + } + } + } + + do_keyboard(); + do_mouse(); + loop_state = LoopState::ProcessingIncomingData; + } else if (loop_state == LoopState::ProcessingIncomingData) { + if (descr_index >= otf_video_params.m_dma_total_descr - NUM_ACTIVE_BUFFERS - 1) { + // Prepare the start of the next frame. + for (current_line_index = 0; + current_line_index < NUM_ACTIVE_BUFFERS; + current_line_index++) { + draw_primitives(m_video_lines->get_buffer_ptr(current_line_index), current_line_index); + } + + loop_state = LoopState::NearNewFrameStart; + current_line_index = NUM_ACTIVE_BUFFERS; + current_buffer_index = 0; + } else { + // Keep handling incoming characters + if (stream_byte_available()) { + process_character(stream_read_byte()); + } + } + } else { + // LoopState::NearNewFrameStart + // Keep storing incoming characters + if (stream_byte_available()) { + store_character(stream_read_byte()); + } + } + } +} + +void IRAM_ATTR DiManager::draw_primitives(volatile uint32_t* p_scan_line, uint32_t line_index) { + std::vector * vp = &m_groups[line_index]; + for (auto prim = vp->begin(); prim != vp->end(); ++prim) { + (*prim)->paint(p_scan_line, line_index); + } +} + +void DiManager::set_on_vertical_blank_cb(DiVoidCallback callback_fcn) { + if (callback_fcn) { + m_on_vertical_blank_cb = callback_fcn; + } else { + m_on_vertical_blank_cb = default_on_vertical_blank; + } +} + +void DiManager::init_dma_descriptor(DiVideoScanLine* vscan, uint32_t scan_index, uint32_t descr_index) { + volatile lldesc_t * dd = &m_dma_descriptor[descr_index]; + + if (descr_index == 0) { + m_dma_descriptor[otf_video_params.m_dma_total_descr - 1].qe.stqe_next = (lldesc_t*)dd; + } else { + m_dma_descriptor[descr_index - 1].qe.stqe_next = (lldesc_t*)dd; + } + + dd->sosf = dd->offset = dd->eof = 0; + dd->owner = 1; + dd->size = vscan->get_buffer_size(); + dd->length = vscan->get_buffer_size(); + dd->buf = (uint8_t volatile *)vscan->get_buffer_ptr(scan_index); +} + +void DiManager::store_character(uint8_t character) { + if (m_num_buffer_chars < INCOMING_DATA_BUFFER_SIZE) { + m_incoming_data[m_next_buffer_write++] = character; + if (m_next_buffer_write >= INCOMING_DATA_BUFFER_SIZE) { + m_next_buffer_write = 0; + } + m_num_buffer_chars++; + } +} + +void DiManager::store_string(const uint8_t* string) { + while (uint8_t character = *string++) { + store_character(character); + } +} + +void DiManager::process_stored_characters() { + while (m_num_buffer_chars > 0) { + bool rc = process_character(m_incoming_data[m_next_buffer_read++]); + if (m_next_buffer_read >= INCOMING_DATA_BUFFER_SIZE) { + m_next_buffer_read = 0; + } + m_num_buffer_chars--; + } +} + +/* +From Agon Wiki: https://github.com/breakintoprogram/agon-docs/wiki/VDP +VDU 8: Cursor left +VDU 9: Cursor right +VDU 10: Cursor down +VDU 11: Cursor up +VDU 12: CLS +VDU 13: Carriage return +VDU 14: Page mode ON (VDP 1.03 or greater) +VDU 15: Page mode OFF (VDP 1.03 or greater) +VDU 16: CLG +VDU 17 colour: COLOUR colour +VDU 18, mode, colour: GCOL mode, colour +VDU 19, l, p, r, g, b: COLOUR l, p / COLOUR l, r, g, b +VDU 22, n: Mode n +VDU 23, n: UDG / System Commands +VDU 24, left; bottom; right; top;: Set graphics viewport (VDP 1.04 or greater) +VDU 25, mode, x; y;: PLOT mode, x, y +VDU 26: Reset graphics and text viewports (VDP 1.04 or greater) +VDU 28, left, bottom, right, top: Set text viewport (VDP 1.04 or greater) +VDU 29, x; y;: Graphics origin +VDU 30: Home cursor +VDU 31, x, y: TAB(x, y) +VDU 127: Backspace +*/ +bool DiManager::process_character(uint8_t character) { + if (m_incoming_command.size() && m_incoming_command[0] == 23) { + return handle_udg_sys_cmd(character); // handle UDG/system command + } + + if (!m_incoming_command.size() && (character >= 0x20 && character != 0x7F)) { + // printable character + write_character(character); + } else { + m_incoming_command.push_back(character); + VduCmdUnion* cu = (VduCmdUnion*)(&m_incoming_command[0]); + switch (m_incoming_command[0]) { + case 0: { + auto cmd = &cu->m_0_Ignore_data; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 1: { + auto cmd = &cu->m_1_Print_character; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 2: { + auto cmd = &cu->m_2_Enable_print_mode; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 3: { + auto cmd = &cu->m_3_Disable_print_mode; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 4: { + auto cmd = &cu->m_4_Print_at_text_cursor; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 5: { + auto cmd = &cu->m_5_Print_at_graphics_cursor; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 6: { + auto cmd = &cu->m_6_Enable_output_to_screen; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 7: { + auto cmd = &cu->m_7_Beep; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 8: { + auto cmd = &cu->m_8_Move_text_cursor_left; + if (m_incoming_command.size() >= sizeof(*cmd)) { + move_cursor_left(); + m_incoming_command.clear(); + return true; + } + } break; + + case 9: { + auto cmd = &cu->m_9_Move_text_cursor_right; + if (m_incoming_command.size() >= sizeof(*cmd)) { + move_cursor_right(); + m_incoming_command.clear(); + return true; + } + } break; + + case 10: { + auto cmd = &cu->m_10_Move_text_cursor_down; + if (m_incoming_command.size() >= sizeof(*cmd)) { + move_cursor_down(); + m_incoming_command.clear(); + return true; + } + } break; + + case 11: { + auto cmd = &cu->m_11_Move_text_cursor_up; + if (m_incoming_command.size() >= sizeof(*cmd)) { + move_cursor_up(); + m_incoming_command.clear(); + return true; + } + } break; + + case 12: { + auto cmd = &cu->m_12_Clear_text_viewport; + if (m_incoming_command.size() >= sizeof(*cmd)) { + clear_screen(); + m_incoming_command.clear(); + return true; + } + } break; + + case 13: { + auto cmd = &cu->m_13_Move_text_cursor_boln; + if (m_incoming_command.size() >= sizeof(*cmd)) { + move_cursor_boln(); + m_incoming_command.clear(); + return true; + } + } break; + + case 14: { + auto cmd = &cu->m_14_Enable_auto_page_mode; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 15: { + auto cmd = &cu->m_15_Disable_auto_page_mode; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 16: { + auto cmd = &cu->m_16_Clear_graphics_viewport; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 17: { + auto cmd = &cu->m_17_Set_text_color; + if (m_incoming_command.size() >= sizeof(*cmd)) { + if (m_text_area) { + // Because the upper bit is used to indicate background (vs foreground), + // this command does not support transparency settings, and we assume + // using 100% opaque color values here. + if (cmd->m_color & 0x80) { + m_text_area->set_background_color(PIXEL_ALPHA_100_MASK|(cmd->m_color & 0x3F)); + } else { + m_text_area->set_foreground_color(PIXEL_ALPHA_100_MASK|(cmd->m_color & 0x3F)); + } + } + m_incoming_command.clear(); + return true; + } + } break; + + case 18: { + auto cmd = &cu->m_18_Set_graphics_mode_color; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 19: { + auto cmd = &cu->m_19_Set_palette_color; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 20: { + auto cmd = &cu->m_20_Reset_colors; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 21: { + auto cmd = &cu->m_21_Disable_output_to_screen; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 22: { + auto cmd = &cu->m_22_Set_video_mode; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 24: { + auto cmd = &cu->m_24_Define_graphics_viewport; + if (m_incoming_command.size() >= sizeof(*cmd)) { + return define_graphics_viewport(); + } + } break; + + case 25: { + auto cmd = &cu->m_25_Plot_graphics; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 26: { + auto cmd = &cu->m_26_Reset_viewports; + if (m_incoming_command.size() >= sizeof(*cmd)) { + clear_screen(); // reset text and graphic viewports + m_incoming_command.clear(); + return true; + } + } break; + + case 27: { + auto cmd = &cu->m_27_Display_character; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 28: { + auto cmd = &cu->m_28_Define_text_viewport; + if (m_incoming_command.size() >= sizeof(*cmd)) { + return define_text_viewport(); + } + } break; + + case 29: { + auto cmd = &cu->m_29_Set_graphics_origin; + if (m_incoming_command.size() >= sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 30: { + auto cmd = &cu->m_30_Move_text_cursor_home; + if (m_incoming_command.size() >= sizeof(*cmd)) { + move_cursor_home(); + m_incoming_command.clear(); + return true; + } + } break; + + case 31: { + auto cmd = &cu->m_31_Set_text_tab_position; + if (m_incoming_command.size() >= sizeof(*cmd)) { + move_cursor_tab(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 127: { + auto cmd = &cu->m_127_Backspace; + if (m_incoming_command.size() >= sizeof(*cmd)) { + do_backspace(); + m_incoming_command.clear(); + return true; + } + } break; + } + } + return true; +} + +void DiManager::process_string(const uint8_t* string) { + while (uint8_t character = *string++) { + if (!process_character(character)) { + break; + } + } +} + +bool DiManager::define_graphics_viewport() { + if (m_incoming_command.size() >= 9) { + int16_t left = get_param_16(1); + int16_t bottom = get_param_16(3); + int16_t right = get_param_16(5); + int16_t top = get_param_16(7); + m_incoming_command.clear(); + return true; + } + return false; +} + +bool DiManager::define_text_viewport() { + if (m_incoming_command.size() >= 5) { + uint8_t left = get_param_8(1); + uint8_t bottom = get_param_8(2); + uint8_t right = get_param_8(3); + uint8_t top = get_param_8(4); + m_incoming_command.clear(); + return true; + } + return false; +} + +void DiManager::report(uint8_t character) { + write_character('['); + write_character(to_hex(character >> 4)); + write_character(to_hex(character & 0xF)); + write_character(']'); +} + +uint8_t DiManager::to_hex(uint8_t value) { + if (value < 10) { + return value + 0x30; // '0' + } else { + return value - 10 + 0x41; // 'A' + } +} + +uint8_t DiManager::peek_into_buffer() { + return m_incoming_data[m_next_buffer_read]; +} + +uint8_t DiManager::read_from_buffer() { + if (m_num_buffer_chars) { + uint8_t character = m_incoming_data[m_next_buffer_read++]; + if (m_next_buffer_read >= INCOMING_DATA_BUFFER_SIZE) { + m_next_buffer_read = 0; + } + m_num_buffer_chars--; + return character; + } else { + return 0; + } +} + +void DiManager::skip_from_buffer() { + if (++m_next_buffer_read >= INCOMING_DATA_BUFFER_SIZE) { + m_next_buffer_read = 0; + } + m_num_buffer_chars--; +} + +/* +From Agon Wiki: https://github.com/breakintoprogram/agon-docs/wiki/VDP +VDU 23, 0, &80, b: General poll +VDU 23, 0, &81, n: Set the keyboard locale (0=UK, 1=US, etc) +VDU 23, 0, &82: Request cursor position +VDU 23, 0, &83, x; y;: Get ASCII code of character at character position x, y +VDU 23, 0, &84, x; y;: Get colour of pixel at pixel position x, y +VDU 23, 0, &85, channel, waveform, volume, freq; duration;: Send a note to the VDP audio driver +VDU 23, 0, &86: Fetch the screen dimensions +VDU 23, 0, &87: RTC control (Requires MOS 1.03 or above) +VDU 23, 0, &88, delay; rate; led: Keyboard Control (Requires MOS 1.03 or above) +VDU 23, 0, &C0, n: Turn logical screen scaling on and off, where 1=on and 0=off (Requires MOS 1.03 or above) +VDU 23, 0, &FF: Switch to terminal mode for CP/M (This will disable keyboard entry in BBC BASIC/MOS) + +From Julian Regel's tile map commands: https://github.com/julianregel/agonnotes +VDU 23, 0, &C2, 0: Initialise/Reset Tile Layer +VDU 23, 0, &C2, 1: Set Layer Properties +VDU 23, 0, &C2, 2: Set Tile Properties +VDU 23, 0, &C2, 3: Draw Layer +VDU 23, 0, &C4, 0: Set Border Colour +VDU 23, 0, &C4, 1: Draw Border + +From this page: https://www.bbcbasic.co.uk/bbcwin/manual/bbcwin8.html#vdu23 +VDU 23, 1, 0; 0; 0; 0;: Text Cursor Control +*/ +bool DiManager::handle_udg_sys_cmd(uint8_t character) { + if (m_incoming_command.size() >= 2 && get_param_8(1) == 30) { + return handle_otf_cmd(character); + } + m_incoming_command.push_back(character); + if (m_incoming_command.size() >= 2 && get_param_8(1) == 1) { + // VDU 23, 1, enable; 0; 0; 0;: Text Cursor Control + if (m_incoming_command.size() >= 10) { + if (m_text_area) { + cursorEnabled = (get_param_8(2) != 0); + auto flags = m_cursor->get_flags(); + if (cursorEnabled) { + if (flags & PRIM_FLAG_PAINT_THIS == 0) { + // turn ON cursor + set_primitive_flags(m_cursor->get_id(), flags | (PRIM_FLAG_PAINT_THIS|PRIM_FLAG_PAINT_KIDS)); + } + } else { + if (flags & PRIM_FLAG_PAINT_THIS != 0) { + // turn OFF cursor + set_primitive_flags(m_cursor->get_id(), flags & ~(PRIM_FLAG_PAINT_THIS|PRIM_FLAG_PAINT_KIDS)); + } + } + } + m_incoming_command.clear(); + return true; + } + return false; + } + if (m_incoming_command.size() >= 3) { + switch (m_incoming_command[2]) { + + // VDU 23, 0, &80, b: General poll + case VDP_GP: /*0x80*/ { + if (m_incoming_command.size() == 4) { + uint8_t echo = get_param_8(3); + send_general_poll(echo); + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &81, n: Set the keyboard locale (0=UK, 1=US, etc) + case VDP_KEYCODE: /*0x81*/ { + if (m_incoming_command.size() == 4) { + uint8_t region = get_param_8(3); + setKeyboardLayout(region); + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &82: Request cursor position + case VDP_CURSOR: /*0x82*/ { + if (m_incoming_command.size() == 3) { + send_cursor_position(); + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &83, x; y;: Get ASCII code of character at character position x, y + case VDP_SCRCHAR: /*0x83*/ { + if (m_incoming_command.size() == 7) { + int32_t x = get_param_16(3); + int32_t y = get_param_16(5); + send_screen_char(x, y); + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &84, x; y;: Get colour of pixel at pixel position x, y + case VDP_SCRPIXEL: /*0x84*/ { + if (m_incoming_command.size() == 7) { + int32_t x = get_param_16(3); + int32_t y = get_param_16(5); + send_screen_pixel(x, y); + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &85, channel, waveform, volume, freq; duration;: Send a note to the VDP audio driver + case VDP_AUDIO: /*0x85*/ { + if (m_incoming_command.size() == 10) { + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &86: Fetch the screen dimensions + case VDP_MODE: /*0x86*/ { + if (m_incoming_command.size() == 3) { + send_mode_information(); + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &87: RTC control (Requires MOS 1.03 or above) + case VDP_RTC: /*0x87*/ { + if (m_incoming_command.size() == 3) { + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &88, delay; rate; led: Keyboard Control (Requires MOS 1.03 or above) + case VDP_KEYSTATE: /*0x88*/ { + if (m_incoming_command.size() == 8) { + stream_send_keyboard_state(); + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &C0, n: Turn logical screen scaling on and off, where 1=on and 0=off (Requires MOS 1.03 or above) + case VDP_LOGICALCOORDS: /*0xC0*/ { + if (m_incoming_command.size() == 4) { + // This command is ignored; this mode always uses regular coordinates. + m_incoming_command.clear(); + return true; + } + } break; + + // VDU 23, 0, &FF: Switch to terminal mode for CP/M (This will disable keyboard entry in BBC BASIC/MOS) + case VDP_TERMINALMODE: /*0xFF*/ { + if (m_incoming_command.size() == 3) { + // This command is ignored. + m_incoming_command.clear(); + return true; + } + } break; + + default: { + m_incoming_command.clear(); + return true; + } + } + } + return false; +} + +// Process 800x600x64 On-the-Fly Command Set +// +bool DiManager::handle_otf_cmd(uint8_t character) { + if (m_incoming_command.size() >= 4) { + // Check for commands that can be quite long, with their data. + OtfCmdUnion* cu = (OtfCmdUnion*)(&m_incoming_command[0]); + switch (m_incoming_command[2]) { + case 88: { + auto cmd = &cu->m_88_Set_solid_bitmap_pixels_in_Tile_Array; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_85_Set_solid_bitmap_pixel_in_Tile_Array cmd85; + cmd85.m_bmid = cmd->m_bmid; + cmd85.m_color = character; + cmd85.m_id = cmd->m_id; + cmd85.m_ux = cmd->m_ux; + cmd85.m_uy = cmd->m_uy; + set_solid_bitmap_pixel_for_tile_array(&cmd85, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 89: { + auto cmd = &cu->m_89_Set_masked_bitmap_pixels_in_Tile_Array; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_86_Set_masked_bitmap_pixel_in_Tile_Array cmd86; + cmd86.m_bmid = cmd->m_bmid; + cmd86.m_color = character; + cmd86.m_id = cmd->m_id; + cmd86.m_ux = cmd->m_ux; + cmd86.m_uy = cmd->m_uy; + set_masked_bitmap_pixel_for_tile_array(&cmd86, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 90: { + auto cmd = &cu->m_90_Set_transparent_bitmap_pixels_in_Tile_Array; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_87_Set_transparent_bitmap_pixel_in_Tile_Array cmd87; + cmd87.m_bmid = cmd->m_bmid; + cmd87.m_color = character; + cmd87.m_id = cmd->m_id; + cmd87.m_ux = cmd->m_ux; + cmd87.m_uy = cmd->m_uy; + set_transparent_bitmap_pixel_for_tile_array(&cmd87, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 108: { + auto cmd = &cu->m_108_Set_solid_bitmap_pixels_in_Tile_Map; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_105_Set_solid_bitmap_pixel_in_Tile_Map cmd105; + cmd105.m_bmid = cmd->m_bmid; + cmd105.m_color = character; + cmd105.m_id = cmd->m_id; + cmd105.m_ux = cmd->m_ux; + cmd105.m_uy = cmd->m_uy; + set_solid_bitmap_pixel_for_tile_map(&cmd105, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 109: { + auto cmd = &cu->m_109_Set_masked_bitmap_pixels_in_Tile_Map; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_106_Set_masked_bitmap_pixel_in_Tile_Map cmd106; + cmd106.m_bmid = cmd->m_bmid; + cmd106.m_color = character; + cmd106.m_id = cmd->m_id; + cmd106.m_ux = cmd->m_ux; + cmd106.m_uy = cmd->m_uy; + set_masked_bitmap_pixel_for_tile_map(&cmd106, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 110: { + auto cmd = &cu->m_110_Set_transparent_bitmap_pixels_in_Tile_Map; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_107_Set_transparent_bitmap_pixel_in_Tile_Map cmd107; + cmd107.m_bmid = cmd->m_bmid; + cmd107.m_color = character; + cmd107.m_id = cmd->m_id; + cmd107.m_ux = cmd->m_ux; + cmd107.m_uy = cmd->m_uy; + set_transparent_bitmap_pixel_for_tile_map(&cmd107, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 132: { + auto cmd = &cu->m_132_Set_solid_bitmap_pixels; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_129_Set_solid_bitmap_pixel cmd129; + cmd129.m_color = character; + cmd129.m_id = cmd->m_id; + cmd129.m_ux = cmd->m_ux; + cmd129.m_uy = cmd->m_uy; + set_solid_bitmap_pixel(&cmd129, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 133: { + auto cmd = &cu->m_133_Set_masked_bitmap_pixels; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_130_Set_masked_bitmap_pixel cmd130; + cmd130.m_color = character; + cmd130.m_id = cmd->m_id; + cmd130.m_ux = cmd->m_ux; + cmd130.m_uy = cmd->m_uy; + set_masked_bitmap_pixel(&cmd130, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + + case 134: { + auto cmd = &cu->m_134_Set_transparent_bitmap_pixels; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)-1) { + OtfCmd_131_Set_transparent_bitmap_pixel cmd131; + cmd131.m_color = character; + cmd131.m_id = cmd->m_id; + cmd131.m_ux = cmd->m_ux; + cmd131.m_uy = cmd->m_uy; + set_transparent_bitmap_pixel(&cmd131, m_command_data_index); + if (++m_command_data_index >= cmd->m_n) { + m_incoming_command.clear(); + return true; + } + } else { + m_incoming_command.push_back(character); + m_command_data_index = 0; + } + return false; + } break; + } + + // Handle shorter commands of various lengths. + m_incoming_command.push_back(character); + switch (m_incoming_command[2]) { + + case 0: { + auto cmd = &cu->m_0_Set_flags_for_primitive; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_primitive_flags(cmd->m_id, cmd->m_flags); + m_incoming_command.clear(); + return true; + } + } break; + + case 1: { + auto cmd = &cu->m_1_Set_primitive_position; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_primitive_position(cmd->m_id, cmd->m_x, cmd->m_y); + m_incoming_command.clear(); + return true; + } + } break; + + case 2: { + auto cmd = &cu->m_2_Adjust_primitive_position; + if (m_incoming_command.size() == sizeof(*cmd)) { + adjust_primitive_position(cmd->m_id, cmd->m_ix, cmd->m_iy); + m_incoming_command.clear(); + return true; + } + } break; + + case 3: { + auto cmd = &cu->m_3_Delete_primitive; + if (m_incoming_command.size() == sizeof(*cmd)) { + if (m_text_area && (m_text_area->get_id() == cmd->m_id)) { + m_text_area = NULL; + } + delete_primitive(cmd->m_id); + m_incoming_command.clear(); + return true; + } + } break; + + case 4: { + auto cmd = &cu->m_4_Generate_code_for_primitive; + if (m_incoming_command.size() == sizeof(*cmd)) { + generate_code_for_primitive(cmd->m_id); + m_incoming_command.clear(); + return true; + } + } break; + + case 10: { + auto cmd = &cu->m_10_Create_primitive_Point; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_point(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 20: { + auto cmd = &cu->m_20_Create_primitive_Line; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_line(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 30: { + auto cmd = &cu->m_30_Create_primitive_Triangle_Outline; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_triangle_outline(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 31: { + auto cmd = &cu->m_31_Create_primitive_Solid_Triangle; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_solid_triangle(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 32: { + auto cmd = &cu->m_32_Create_primitive_Triangle_List_Outline; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 3 * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_triangle_list_outline(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 33: { + auto cmd = &cu->m_33_Create_primitive_Solid_Triangle_List; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 3 * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_solid_triangle_list(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 34: { + auto cmd = &cu->m_34_Create_primitive_Triangle_Fan_Outline; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_triangle_fan_outline(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 35: { + auto cmd = &cu->m_35_Create_primitive_Solid_Triangle_Fan; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_solid_triangle_fan(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 36: { + auto cmd = &cu->m_36_Create_primitive_Triangle_Strip_Outline; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_triangle_strip_outline(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 37: { + auto cmd = &cu->m_37_Create_primitive_Solid_Triangle_Strip; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_solid_triangle_strip(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 40: { + auto cmd = &cu->m_40_Create_primitive_Rectangle_Outline; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_rectangle_outline(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 41: { + auto cmd = &cu->m_41_Create_primitive_Solid_Rectangle; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_solid_rectangle(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 50: { + auto cmd = &cu->m_50_Create_primitive_Ellipse_Outline; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_ellipse(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 51: { + auto cmd = &cu->m_51_Create_primitive_Solid_Ellipse; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_solid_ellipse(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 60: { + auto cmd = &cu->m_60_Create_primitive_Quad_Outline; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_quad_outline(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 61: { + auto cmd = &cu->m_61_Create_primitive_Solid_Quad; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_solid_quad(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 62: { + auto cmd = &cu->m_62_Create_primitive_Quad_List_Outline; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 4 * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_quad_list_outline(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 63: { + auto cmd = &cu->m_63_Create_primitive_Solid_Quad_List; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + ((uint32_t)cmd->m_n * 4 * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_solid_quad_list(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 64: { + auto cmd = &cu->m_64_Create_primitive_Quad_Strip_Outline; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + (((uint32_t)cmd->m_n * 2) * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_quad_strip_outline(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 65: { + auto cmd = &cu->m_65_Create_primitive_Solid_Quad_Strip; + auto len = m_incoming_command.size(); + if (len >= sizeof(*cmd)) { + auto total_size = sizeof(*cmd) - sizeof(cmd->m_coords) + (((uint32_t)cmd->m_n * 2) * 2 * sizeof(uint16_t)); + if (len >= total_size) { + create_solid_quad_strip(cmd); + m_incoming_command.clear(); + return true; + } + } + } break; + + case 80: { + auto cmd = &cu->m_80_Create_primitive_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_tile_array(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 81: { + auto cmd = &cu->m_81_Create_Solid_Bitmap_for_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_solid_bitmap_for_tile_array(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 82: { + auto cmd = &cu->m_82_Create_Masked_Bitmap_for_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_masked_bitmap_for_tile_array(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 83: { + auto cmd = &cu->m_83_Create_Transparent_Bitmap_for_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_transparent_bitmap_for_tile_array(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 84: { + auto cmd = &cu->m_84_Set_bitmap_ID_for_tile_in_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_tile_array_bitmap_id(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 85: { + auto cmd = &cu->m_85_Set_solid_bitmap_pixel_in_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_solid_bitmap_pixel_for_tile_array(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 86: { + auto cmd = &cu->m_86_Set_masked_bitmap_pixel_in_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_masked_bitmap_pixel_for_tile_array(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 87: { + auto cmd = &cu->m_87_Set_transparent_bitmap_pixel_in_Tile_Array; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_transparent_bitmap_pixel_for_tile_array(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 100: { + auto cmd = &cu->m_100_Create_primitive_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_tile_map(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 101: { + auto cmd = &cu->m_101_Create_Solid_Bitmap_for_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_solid_bitmap_for_tile_map(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 102: { + auto cmd = &cu->m_102_Create_Masked_Bitmap_for_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_masked_bitmap_for_tile_map(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 103: { + auto cmd = &cu->m_103_Create_Transparent_Bitmap_for_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_transparent_bitmap_for_tile_map(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 104: { + auto cmd = &cu->m_104_Set_bitmap_ID_for_tile_in_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_tile_map_bitmap_id(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 105: { + auto cmd = &cu->m_105_Set_solid_bitmap_pixel_in_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_solid_bitmap_pixel_for_tile_map(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 106: { + auto cmd = &cu->m_106_Set_masked_bitmap_pixel_in_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_masked_bitmap_pixel_for_tile_map(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 107: { + auto cmd = &cu->m_107_Set_transparent_bitmap_pixel_in_Tile_Map; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_transparent_bitmap_pixel_for_tile_map(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 120: { + auto cmd = &cu->m_120_Create_primitive_Solid_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_solid_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 121: { + auto cmd = &cu->m_121_Create_primitive_Masked_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_masked_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 122: { + auto cmd = &cu->m_122_Create_primitive_Transparent_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_transparent_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 123: { + auto cmd = &cu->m_123_Set_position_and_slice_solid_bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + slice_solid_bitmap_absolute(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 124: { + auto cmd = &cu->m_124_Set_position_and_slice_masked_bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + slice_masked_bitmap_absolute(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 125: { + auto cmd = &cu->m_125_Set_position_and_slice_transparent_bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + slice_transparent_bitmap_absolute(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 126: { + auto cmd = &cu->m_126_Adjust_position_and_slice_solid_bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + slice_solid_bitmap_relative(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 127: { + auto cmd = &cu->m_127_Adjust_position_and_slice_masked_bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + slice_masked_bitmap_relative(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 128: { + auto cmd = &cu->m_128_Adjust_position_and_slice_transparent_bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + slice_transparent_bitmap_relative(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 129: { + auto cmd = &cu->m_129_Set_solid_bitmap_pixel; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_solid_bitmap_pixel(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 130: { + auto cmd = &cu->m_130_Set_masked_bitmap_pixel; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_masked_bitmap_pixel(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 131: { + auto cmd = &cu->m_131_Set_transparent_bitmap_pixel; + if (m_incoming_command.size() == sizeof(*cmd)) { + set_transparent_bitmap_pixel(cmd, 0); + m_incoming_command.clear(); + return true; + } + } break; + + case 135: { + auto cmd = &cu->m_135_Create_primitive_Reference_Solid_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_reference_solid_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 136: { + auto cmd = &cu->m_136_Create_primitive_Reference_Masked_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_reference_masked_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 137: { + auto cmd = &cu->m_137_Create_primitive_Reference_Transparent_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_reference_transparent_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 140: { + auto cmd = &cu->m_140_Create_primitive_Group; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_primitive_group(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 145: { + auto cmd = &cu->m_145_Create_primitive_Duplicate_Solid_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_duplicate_solid_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 146: { + auto cmd = &cu->m_146_Create_primitive_Duplicate_Masked_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_duplicate_masked_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 147: { + auto cmd = &cu->m_147_Create_primitive_Duplicate_Transparent_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_duplicate_transparent_bitmap(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 150: { + auto cmd = &cu->m_150_Create_primitive_Text_Area; + if (m_incoming_command.size() == sizeof(*cmd)) { + create_text_area(cmd, fabgl::FONT_AGON_DATA); + m_incoming_command.clear(); + return true; + } + } break; + + case 151: { + auto cmd = &cu->m_151_Select_Active_Text_Area; + if (m_incoming_command.size() == sizeof(*cmd)) { + select_active_text_area(cmd); + m_incoming_command.clear(); + return true; + } + } break; + + case 152: { + auto cmd = &cu->m_152_Define_Text_Area_Character; + if (m_incoming_command.size() == sizeof(*cmd)) { + DiTextArea* text_area = (DiTextArea*) get_safe_primitive(cmd->m_id); + if (text_area) { + text_area->define_character(cmd->m_char, cmd->m_fgcolor, cmd->m_bgcolor); + } + m_incoming_command.clear(); + return true; + } + } break; + + case 153: { + auto cmd = &cu->m_153_Define_Text_Area_Character_Range; + if (m_incoming_command.size() == sizeof(*cmd)) { + DiTextArea* text_area = (DiTextArea*) get_safe_primitive(cmd->m_id); + if (text_area) { + text_area->define_character_range(cmd->m_firstchar, cmd->m_lastchar, cmd->m_fgcolor, cmd->m_bgcolor); + } + m_incoming_command.clear(); + return true; + } + } break; + + case 200: { + auto cmd = &cu->m_200_Create_primitive_Solid_Render; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 201: { + auto cmd = &cu->m_201_Create_primitive_Masked_Render; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 202: { + auto cmd = &cu->m_202_Create_primitive_Transparent_Render; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 203: { + auto cmd = &cu->m_203_Define_Mesh_Vertices; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 204: { + auto cmd = &cu->m_204_Set_Mesh_Vertex_Indices; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 205: { + auto cmd = &cu->m_205_Define_Texture_Coordinates; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 206: { + auto cmd = &cu->m_206_Set_Texture_Coordinate_Indices; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 207: { + auto cmd = &cu->m_207_Create_Object; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 208: { + auto cmd = &cu->m_208_Set_Object_X_Scale_Factor; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 209: { + auto cmd = &cu->m_209_Set_Object_Y_Scale_Factor; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 210: { + auto cmd = &cu->m_210_Set_Object_Z_Scale_Factor; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 211: { + auto cmd = &cu->m_211_Set_Object_XYZ_Scale_Factors; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 212: { + auto cmd = &cu->m_212_Set_Object_X_Rotation_Angle; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 213: { + auto cmd = &cu->m_213_Set_Object_Y_Rotation_Angle; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 214: { + auto cmd = &cu->m_214_Set_Object_Z_Rotation_Angle; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 215: { + auto cmd = &cu->m_215_Set_Object_XYZ_Rotation_Angles; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 216: { + auto cmd = &cu->m_216_Set_Object_X_Translation_Distance; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 217: { + auto cmd = &cu->m_217_Set_Object_Y_Translation_Distance; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 218: { + auto cmd = &cu->m_218_Set_Object_Z_Translation_Distance; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 219: { + auto cmd = &cu->m_219_Set_Object_XYZ_Translation_Distances; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + case 220: { + auto cmd = &cu->m_220_Render_To_Bitmap; + if (m_incoming_command.size() == sizeof(*cmd)) { + m_incoming_command.clear(); + return true; + } + } break; + + default: { + m_incoming_command.clear(); + return true; // ignore the command + } + } + } else { + m_incoming_command.push_back(character); + } + return false; +} + +void DiManager::clear_screen() { + if (m_text_area) { + m_text_area->clear_screen(); + } +} + +void DiManager::move_cursor_left() { + if (m_text_area) { + m_text_area->move_cursor_left(); + } +} + +void DiManager::move_cursor_right() { + if (m_text_area) { + m_text_area->move_cursor_right(); + } +} + +void DiManager::move_cursor_down() { + if (m_text_area) { + m_text_area->move_cursor_down(); + } +} + +void DiManager::move_cursor_up() { + if (m_text_area) { + m_text_area->move_cursor_up(); + } +} + +void DiManager::move_cursor_home() { + if (m_text_area) { + m_text_area->move_cursor_home(); + } +} + +void DiManager::move_cursor_boln() { + if (m_text_area) { + m_text_area->move_cursor_boln(); + } +} + +void DiManager::do_backspace() { + if (m_text_area) { + m_text_area->do_backspace(); + } +} + +void DiManager::move_cursor_tab(VduCmd_31_Set_text_tab_position* cmd) { + if (m_text_area) { + m_text_area->move_cursor_tab(cmd->m_column, cmd->m_row); + } +} + +uint8_t DiManager::read_character(int16_t x, int16_t y) { + if (m_text_area) { + return m_text_area->read_character(x, y); + } else { + return 0; + } +} + +void DiManager::write_character(uint8_t character) { + if (m_text_area) { + m_text_area->write_character(character); + } +} + +uint8_t DiManager::get_param_8(uint32_t index) { + return m_incoming_command[index]; +} + +int16_t DiManager::get_param_16(uint32_t index) { + return (int16_t)((((uint16_t)m_incoming_command[index+1]) << 8) | m_incoming_command[index]); +} + +// Send the cursor position back to MOS +// +void DiManager::send_cursor_position() { + uint16_t column = 0; + uint16_t row = 0; + if (m_text_area) { + m_text_area->get_position(column, row); + } + byte packet[] = { + (byte) column, + (byte) row + }; + send_packet(PACKET_CURSOR, sizeof packet, packet); +} + +// Send a character back to MOS +// +void DiManager::send_screen_char(int16_t x, int16_t y) { + uint8_t c = read_character(x, y); + byte packet[] = { + c + }; + send_packet(PACKET_SCRCHAR, sizeof packet, packet); +} + +// Send a pixel value back to MOS +// +void DiManager::send_screen_pixel(int16_t x, int16_t y) { + byte packet[] = { + 0, // R + 0, // G + 0, // B + 0 // There is no palette in this mode. + }; + send_packet(PACKET_SCRPIXEL, sizeof packet, packet); +} + +// Send MODE information (screen details) +// +void DiManager::send_mode_information() { + byte packet[] = { + (uint8_t)(otf_video_params.m_active_pixels), // Width in pixels (L) + (uint8_t)(otf_video_params.m_active_pixels >> 8), // Width in pixels (H) + (uint8_t)(otf_video_params.m_active_lines), // Height in pixels (L) + (uint8_t)(otf_video_params.m_active_pixels >> 8), // Height in pixels (H) + (uint8_t)(otf_video_params.m_active_pixels / 8), // Width in characters (byte) + (uint8_t)(otf_video_params.m_active_lines / 8), // Height in characters (byte) + 64, // Colour depth + (uint8_t)videoMode // The video mode number + }; + send_packet(PACKET_MODE, sizeof packet, packet); +} + +// Send a general poll +// +void DiManager::send_general_poll(uint8_t b) { + byte packet[] = { + b + }; + send_packet(PACKET_GP, sizeof packet, packet); + initialised = true; +} + +void DiManager::set_primitive_flags(uint16_t id, uint16_t flags) { + DiPrimitive* prim; if (!(prim = (DiPrimitive*)get_safe_primitive(id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + auto chg_flags = flags & PRIM_FLAGS_CHANGEABLE; + auto new_flags = (old_flags & ~PRIM_FLAGS_CHANGEABLE) | chg_flags; + prim->set_flags(new_flags); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::set_primitive_position(uint16_t id, int32_t x, int32_t y) { + DiPrimitive* prim; if (!(prim = (DiPrimitive*)get_safe_primitive(id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + prim->set_relative_position(x, y); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::adjust_primitive_position(uint16_t id, int32_t x, int32_t y) { + DiPrimitive* prim; if (!(prim = (DiPrimitive*)get_safe_primitive(id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + auto x2 = prim->get_relative_x() + x; + auto y2 = prim->get_relative_y() + y; + prim->set_relative_position(x2, y2); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::delete_primitive(uint16_t id) { + DiPrimitive* prim; if (!(prim = (DiPrimitive*)get_safe_primitive(id))) return; + remove_primitive(prim); +} + +void DiManager::generate_code_for_primitive(uint16_t id) { + DiPrimitive* prim; if (!(prim = (DiPrimitive*)get_safe_primitive(id))) return; + prim->delete_instructions(); + prim->generate_instructions(); +} + +DiPrimitive* DiManager::create_rectangle_outline(OtfCmd_40_Create_primitive_Rectangle_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiRectangle(cmd->m_flags); + prim->make_rectangle_outline(cmd->m_x, cmd->m_y, cmd->m_w, cmd->m_h, cmd->m_color); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_ellipse(OtfCmd_50_Create_primitive_Ellipse_Outline* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiEllipse(cmd->m_flags); + prim->init_params(cmd->m_x, cmd->m_y, cmd->m_w, cmd->m_h, cmd->m_color); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiPrimitive* DiManager::create_solid_ellipse(OtfCmd_51_Create_primitive_Solid_Ellipse* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiSolidEllipse(cmd->m_flags); + prim->init_params(cmd->m_x, cmd->m_y, cmd->m_w, cmd->m_h, cmd->m_color); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +DiBitmap* DiManager::create_solid_bitmap(OtfCmd_120_Create_primitive_Solid_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_ALL_SAME; + auto prim = new DiBitmap(cmd->m_w, cmd->m_h, cmd->m_flags, (cmd->m_psram != 0)); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiBitmap* DiManager::create_masked_bitmap(OtfCmd_121_Create_primitive_Masked_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_MASKED; + auto prim = new DiBitmap(cmd->m_w, cmd->m_h, cmd->m_flags, (cmd->m_psram != 0)); + prim->set_transparent_color(cmd->m_color); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiBitmap* DiManager::create_transparent_bitmap(OtfCmd_122_Create_primitive_Transparent_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_BLENDED; + auto prim = new DiBitmap(cmd->m_w, cmd->m_h, cmd->m_flags, (cmd->m_psram != 0)); + prim->set_transparent_color(cmd->m_color); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiBitmap* DiManager::create_reference_solid_bitmap(OtfCmd_135_Create_primitive_Reference_Solid_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + DiBitmap* ref_prim; if (!(ref_prim = (DiBitmap*) get_safe_primitive(cmd->m_bmid))) return NULL; + + auto prim = new DiBitmap(cmd->m_flags, ref_prim); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiBitmap* DiManager::create_reference_masked_bitmap(OtfCmd_136_Create_primitive_Reference_Masked_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + DiBitmap* ref_prim; if (!(ref_prim = (DiBitmap*) get_safe_primitive(cmd->m_bmid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_MASKED; + auto prim = new DiBitmap(cmd->m_flags, ref_prim); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiBitmap* DiManager::create_reference_transparent_bitmap(OtfCmd_137_Create_primitive_Reference_Transparent_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + DiBitmap* ref_prim; if (!(ref_prim = (DiBitmap*) get_safe_primitive(cmd->m_bmid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_BLENDED; + auto prim = new DiBitmap(cmd->m_flags, ref_prim); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiBitmap* DiManager::create_duplicate_solid_bitmap(OtfCmd_145_Create_primitive_Duplicate_Solid_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + DiBitmap* dup_prim; if (!(dup_prim = (DiBitmap*) get_safe_primitive(cmd->m_bmid))) return NULL; + auto prim = new DiBitmap(cmd->m_flags|PRIM_FLAGS_ALL_SAME, dup_prim->get_width(), + dup_prim->get_original_height(), cmd->m_psram); + finish_create(cmd->m_id, prim, parent_prim); + prim->copy_pixels(dup_prim, cmd->m_flip); + return prim; +} + +DiBitmap* DiManager::create_duplicate_masked_bitmap(OtfCmd_146_Create_primitive_Duplicate_Masked_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + DiBitmap* dup_prim; if (!(dup_prim = (DiBitmap*) get_safe_primitive(cmd->m_bmid))) return NULL; + auto prim = new DiBitmap(cmd->m_flags|PRIM_FLAGS_MASKED, dup_prim->get_width(), + dup_prim->get_original_height(), cmd->m_psram); + finish_create(cmd->m_id, prim, parent_prim); + prim->set_transparent_color(dup_prim->get_transparent_color()); + prim->copy_pixels(dup_prim, cmd->m_flip); + return prim; +} + +DiBitmap* DiManager::create_duplicate_transparent_bitmap(OtfCmd_147_Create_primitive_Duplicate_Transparent_Bitmap* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + DiBitmap* dup_prim; if (!(dup_prim = (DiBitmap*) get_safe_primitive(cmd->m_bmid))) return NULL; + auto prim = new DiBitmap(cmd->m_flags|PRIM_FLAGS_BLENDED, dup_prim->get_width(), + dup_prim->get_original_height(), cmd->m_psram); + finish_create(cmd->m_id, prim, parent_prim); + prim->set_transparent_color(dup_prim->get_transparent_color()); + prim->copy_pixels(dup_prim, cmd->m_flip); + return prim; +} + +DiBitmap* DiManager::create_solid_bitmap_for_tile_array(OtfCmd_81_Create_Solid_Bitmap_for_Tile_Array* cmd) { + DiTileArray* prim; if (!(prim = (DiTileArray*)get_safe_primitive(cmd->m_id))) return NULL; + auto bitmap = prim->create_bitmap(cmd->m_bmid, (cmd->m_psram != 0)); + return bitmap; +} + +DiBitmap* DiManager::create_masked_bitmap_for_tile_array(OtfCmd_82_Create_Masked_Bitmap_for_Tile_Array* cmd) { + DiTileArray* prim; if (!(prim = (DiTileArray*)get_safe_primitive(cmd->m_id))) return NULL; + auto bitmap = prim->create_bitmap(cmd->m_bmid, (cmd->m_psram != 0)); + bitmap->add_flags(PRIM_FLAGS_MASKED); + bitmap->set_transparent_color(cmd->m_color); + return bitmap; +} + +DiBitmap* DiManager::create_transparent_bitmap_for_tile_array(OtfCmd_83_Create_Transparent_Bitmap_for_Tile_Array* cmd) { + DiTileArray* prim; if (!(prim = (DiTileArray*)get_safe_primitive(cmd->m_id))) return NULL; + auto bitmap = prim->create_bitmap(cmd->m_bmid, (cmd->m_psram != 0)); + bitmap->add_flags(PRIM_FLAGS_BLENDED); + bitmap->set_transparent_color(cmd->m_color); + return bitmap; +} + +DiBitmap* DiManager::create_solid_bitmap_for_tile_map(OtfCmd_101_Create_Solid_Bitmap_for_Tile_Map* cmd) { + DiTileMap* prim; if (!(prim = (DiTileMap*)get_safe_primitive(cmd->m_id))) return NULL; + auto bitmap = prim->create_bitmap(cmd->m_bmid, (cmd->m_psram != 0)); + return bitmap; +} + +DiBitmap* DiManager::create_masked_bitmap_for_tile_map(OtfCmd_102_Create_Masked_Bitmap_for_Tile_Map* cmd) { + DiTileMap* prim; if (!(prim = (DiTileMap*)get_safe_primitive(cmd->m_id))) return NULL; + auto bitmap = prim->create_bitmap(cmd->m_bmid, (cmd->m_psram != 0)); + bitmap->set_transparent_color(cmd->m_color); + bitmap->add_flags(PRIM_FLAGS_MASKED); + return bitmap; +} + +DiBitmap* DiManager::create_transparent_bitmap_for_tile_map(OtfCmd_103_Create_Transparent_Bitmap_for_Tile_Map* cmd) { + DiTileMap* prim; if (!(prim = (DiTileMap*)get_safe_primitive(cmd->m_id))) return NULL; + auto bitmap = prim->create_bitmap(cmd->m_bmid, (cmd->m_psram != 0)); + bitmap->set_transparent_color(cmd->m_color); + bitmap->add_flags(PRIM_FLAGS_BLENDED); + return bitmap; +} + +DiRender* DiManager::create_solid_render(OtfCmd_200_Create_primitive_Solid_Render* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + auto prim = new DiRender(cmd->m_w, cmd->m_h, cmd->m_flags, (cmd->m_psram != 0)); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiRender* DiManager::create_masked_render(OtfCmd_201_Create_primitive_Masked_Render* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_MASKED; + auto prim = new DiRender(cmd->m_w, cmd->m_h, cmd->m_flags, (cmd->m_psram != 0)); + prim->set_transparent_color(cmd->m_color); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiRender* DiManager::create_transparent_render(OtfCmd_202_Create_primitive_Transparent_Render* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + cmd->m_flags |= PRIM_FLAGS_BLENDED; + auto prim = new DiRender(cmd->m_w, cmd->m_h, cmd->m_flags, (cmd->m_psram != 0)); + prim->set_transparent_color(cmd->m_color); + + finish_create(cmd->m_id, prim, parent_prim); + return prim; +} + +DiPrimitive* DiManager::create_primitive_group(OtfCmd_140_Create_primitive_Group* cmd) { + if (!validate_id(cmd->m_id)) return NULL; + DiPrimitive* parent_prim; if (!(parent_prim = get_safe_primitive(cmd->m_pid))) return NULL; + + cmd->m_flags &= ~PRIM_FLAG_PAINT_THIS; + DiPrimitive* prim = new DiPrimitive(cmd->m_flags); + prim->set_relative_position(cmd->m_x, cmd->m_y); + prim->set_size(cmd->m_w, cmd->m_h); + + return finish_create(cmd->m_id, prim, parent_prim); +} + +void DiManager::slice_solid_bitmap_absolute(OtfCmd_123_Set_position_and_slice_solid_bitmap* cmd) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + prim->set_slice_position(cmd->m_x, cmd->m_y, cmd->m_s, cmd->m_h); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::slice_masked_bitmap_absolute(OtfCmd_124_Set_position_and_slice_masked_bitmap* cmd) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + prim->set_slice_position(cmd->m_x, cmd->m_y, cmd->m_s, cmd->m_h); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::slice_transparent_bitmap_absolute(OtfCmd_125_Set_position_and_slice_transparent_bitmap* cmd) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + prim->set_slice_position(cmd->m_x, cmd->m_y, cmd->m_s, cmd->m_h); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::slice_solid_bitmap_relative( OtfCmd_126_Adjust_position_and_slice_solid_bitmap* cmd) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + auto x2 = prim->get_relative_x() + cmd->m_x; + auto y2 = prim->get_relative_y() + cmd->m_y; + prim->set_slice_position(x2, y2, cmd->m_s, cmd->m_h); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::slice_masked_bitmap_relative(OtfCmd_127_Adjust_position_and_slice_masked_bitmap* cmd) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + auto x2 = prim->get_relative_x() + cmd->m_x; + auto y2 = prim->get_relative_y() + cmd->m_y; + prim->set_slice_position(x2, y2, cmd->m_s, cmd->m_h); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::slice_transparent_bitmap_relative(OtfCmd_128_Adjust_position_and_slice_transparent_bitmap* cmd) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + auto old_flags = prim->get_flags(); + int32_t old_min_group = -1, old_max_group = -1; + if (old_flags & PRIM_FLAGS_CAN_DRAW) { + prim->get_vertical_group_range(old_min_group, old_max_group); + } + auto x2 = prim->get_relative_x() + cmd->m_x; + auto y2 = prim->get_relative_y() + cmd->m_y; + prim->set_slice_position(x2, y2, cmd->m_s, cmd->m_h); + recompute_primitive(prim, old_flags, old_min_group, old_max_group); +} + +void DiManager::set_solid_bitmap_pixel(OtfCmd_129_Set_solid_bitmap_pixel* cmd, uint16_t nth) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_width()); + px %= prim->get_width(); + prim->set_transparent_pixel(px, py, cmd->m_color|PIXEL_ALPHA_100_MASK); +} + +void DiManager::set_masked_bitmap_pixel(OtfCmd_130_Set_masked_bitmap_pixel* cmd, uint16_t nth) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_width()); + px %= prim->get_width(); + if (cmd->m_color != prim->get_transparent_color()) { + cmd->m_color |= PIXEL_ALPHA_100_MASK; + } + prim->set_transparent_pixel(px, py, cmd->m_color); +} + +void DiManager::set_transparent_bitmap_pixel(OtfCmd_131_Set_transparent_bitmap_pixel* cmd, uint16_t nth) { + DiBitmap* prim; if (!(prim = (DiBitmap*)get_safe_primitive(cmd->m_id))) return; + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_width()); + px %= prim->get_width(); + prim->set_transparent_pixel(px, py, cmd->m_color); +} + +void DiManager::set_solid_bitmap_pixel_for_tile_array(OtfCmd_85_Set_solid_bitmap_pixel_in_Tile_Array* cmd, uint16_t nth) { + DiTileArray* prim; if (!(prim = (DiTileArray*)get_safe_primitive(cmd->m_id))) return; + + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_tile_width()); + px %= prim->get_tile_width(); + + prim->set_pixel(cmd->m_bmid, px, py, cmd->m_color|PIXEL_ALPHA_100_MASK); +} + +void DiManager::set_masked_bitmap_pixel_for_tile_array(OtfCmd_86_Set_masked_bitmap_pixel_in_Tile_Array* cmd, uint16_t nth) { + DiTileArray* prim; if (!(prim = (DiTileArray*)get_safe_primitive(cmd->m_id))) return; + + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_tile_width()); + px %= prim->get_tile_width(); + if (cmd->m_color != prim->get_bitmap(cmd->m_bmid)->get_transparent_color()) { + cmd->m_color |= PIXEL_ALPHA_100_MASK; + } + prim->set_pixel(cmd->m_bmid, px, py, cmd->m_color); +} + +void DiManager::set_transparent_bitmap_pixel_for_tile_array(OtfCmd_87_Set_transparent_bitmap_pixel_in_Tile_Array* cmd, uint16_t nth) { + DiTileArray* prim; if (!(prim = (DiTileArray*)get_safe_primitive(cmd->m_id))) return; + + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_tile_width()); + px %= prim->get_tile_width(); + + prim->set_pixel(cmd->m_bmid, px, py, cmd->m_color); +} + +void DiManager::set_solid_bitmap_pixel_for_tile_map(OtfCmd_105_Set_solid_bitmap_pixel_in_Tile_Map* cmd, uint16_t nth) { + DiTileMap* prim; if (!(prim = (DiTileMap*)get_safe_primitive(cmd->m_id))) return; + + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_tile_width()); + px %= prim->get_tile_width(); + + prim->set_pixel(cmd->m_bmid, px, py, cmd->m_color|PIXEL_ALPHA_100_MASK); +} + +void DiManager::set_masked_bitmap_pixel_for_tile_map(OtfCmd_106_Set_masked_bitmap_pixel_in_Tile_Map* cmd, uint16_t nth) { + DiTileMap* prim; if (!(prim = (DiTileMap*)get_safe_primitive(cmd->m_id))) return; + + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_tile_width()); + px %= prim->get_tile_width(); + if (cmd->m_color != prim->get_bitmap(cmd->m_bmid)->get_transparent_color()) { + cmd->m_color |= PIXEL_ALPHA_100_MASK; + } + prim->set_pixel(cmd->m_bmid, px, py, cmd->m_color); +} + +void DiManager::set_transparent_bitmap_pixel_for_tile_map(OtfCmd_107_Set_transparent_bitmap_pixel_in_Tile_Map* cmd, uint16_t nth) { + DiTileMap* prim; if (!(prim = (DiTileMap*)get_safe_primitive(cmd->m_id))) return; + + uint32_t px = (uint32_t)cmd->m_ux + (uint32_t)nth; + uint32_t py = (uint32_t)cmd->m_uy + (px / prim->get_tile_width()); + px %= prim->get_tile_width(); + + prim->set_pixel(cmd->m_bmid, px, py, cmd->m_color); +} + +void DiManager::set_tile_array_bitmap_id(OtfCmd_84_Set_bitmap_ID_for_tile_in_Tile_Array* cmd) { + DiTileArray* prim; if (!(prim = (DiTileArray*)get_safe_primitive(cmd->m_id))) return; + prim->set_tile(cmd->m_column, cmd->m_row, cmd->m_bmid); +} + +void DiManager::set_tile_map_bitmap_id(OtfCmd_104_Set_bitmap_ID_for_tile_in_Tile_Map* cmd) { + DiTileMap* prim; if (!(prim = (DiTileMap*)get_safe_primitive(cmd->m_id))) return; + prim->set_tile(cmd->m_column, cmd->m_row, cmd->m_bmid); +} + +void DiManager::select_active_text_area(OtfCmd_151_Select_Active_Text_Area* cmd) { + DiTextArea* text_area = (DiTextArea*) get_safe_primitive(cmd->m_id); + if (text_area) { + if (m_cursor) { + set_primitive_flags(m_cursor->get_id(), m_cursor->get_flags() & ~(PRIM_FLAG_PAINT_THIS|PRIM_FLAG_PAINT_KIDS)); + } + m_text_area = text_area; + m_cursor = text_area->get_first_child(); + set_primitive_flags(m_cursor->get_id(), m_cursor->get_flags() | (PRIM_FLAG_PAINT_THIS|PRIM_FLAG_PAINT_KIDS)); + send_cursor_position(); + } +} \ No newline at end of file diff --git a/video/src/di_manager.h b/video/src/di_manager.h new file mode 100644 index 00000000..af402b6d --- /dev/null +++ b/video/src/di_manager.h @@ -0,0 +1,254 @@ +// di_manager.h - Function declarations for managing drawing-instruction primitives +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#include +#include +#include "rom/lldesc.h" +#include "di_video_buffer.h" +#include "di_text_area.h" +#include "di_tile_map.h" +#include "di_render.h" +#include "di_solid_rectangle.h" +#include "di_commands.h" + +typedef void (*DiVoidCallback)(); + +#define INCOMING_DATA_BUFFER_SIZE 2048 + +class DiManager { + public: + // Construct a drawing-instruction manager, which handles multiple drawing primitives. + DiManager(); + + // Destroy the manager and its child primitives. + ~DiManager(); + + // Create the root primitive. + void create_root(); + + // Create various types of drawing primitives. + DiPrimitive* create_point(OtfCmd_10_Create_primitive_Point* cmd); + DiPrimitive* create_line(OtfCmd_20_Create_primitive_Line* cmd); + DiPrimitive* create_rectangle_outline(OtfCmd_40_Create_primitive_Rectangle_Outline* cmd); + DiSolidRectangle* create_solid_rectangle(OtfCmd_41_Create_primitive_Solid_Rectangle* cmd); + DiPrimitive* create_ellipse(OtfCmd_50_Create_primitive_Ellipse_Outline* cmd); + DiPrimitive* create_solid_ellipse(OtfCmd_51_Create_primitive_Solid_Ellipse* cmd); + DiPrimitive* create_triangle_outline(OtfCmd_30_Create_primitive_Triangle_Outline* cmd); + DiPrimitive* create_solid_triangle(OtfCmd_31_Create_primitive_Solid_Triangle* cmd); + DiPrimitive* create_triangle_list_outline(OtfCmd_32_Create_primitive_Triangle_List_Outline* cmd); + DiPrimitive* create_solid_triangle_list(OtfCmd_33_Create_primitive_Solid_Triangle_List* cmd); + DiPrimitive* create_triangle_fan_outline(OtfCmd_34_Create_primitive_Triangle_Fan_Outline* cmd); + DiPrimitive* create_solid_triangle_fan(OtfCmd_35_Create_primitive_Solid_Triangle_Fan* cmd); + DiPrimitive* create_triangle_strip_outline(OtfCmd_36_Create_primitive_Triangle_Strip_Outline* cmd); + DiPrimitive* create_solid_triangle_strip(OtfCmd_37_Create_primitive_Solid_Triangle_Strip* cmd); + DiPrimitive* create_quad_outline(OtfCmd_60_Create_primitive_Quad_Outline* cmd); + DiPrimitive* create_solid_quad(OtfCmd_61_Create_primitive_Solid_Quad* cmd); + DiPrimitive* create_quad_list_outline(OtfCmd_62_Create_primitive_Quad_List_Outline* cmd); + DiPrimitive* create_solid_quad_list(OtfCmd_63_Create_primitive_Solid_Quad_List* cmd); + DiPrimitive* create_quad_strip_outline(OtfCmd_64_Create_primitive_Quad_Strip_Outline* cmd); + DiPrimitive* create_solid_quad_strip(OtfCmd_65_Create_primitive_Solid_Quad_Strip* cmd); + DiTileMap* create_tile_map(OtfCmd_100_Create_primitive_Tile_Map* cmd); + DiTileArray* create_tile_array(OtfCmd_80_Create_primitive_Tile_Array* cmd); + DiTextArea* create_text_area(OtfCmd_150_Create_primitive_Text_Area* cmd, const uint8_t* font); + void select_active_text_area(OtfCmd_151_Select_Active_Text_Area* cmd); + DiBitmap* create_solid_bitmap(OtfCmd_120_Create_primitive_Solid_Bitmap* cmd); + DiBitmap* create_masked_bitmap(OtfCmd_121_Create_primitive_Masked_Bitmap* cmd); + DiBitmap* create_transparent_bitmap(OtfCmd_122_Create_primitive_Transparent_Bitmap* cmd); + DiBitmap* create_reference_solid_bitmap(OtfCmd_135_Create_primitive_Reference_Solid_Bitmap* cmd); + DiBitmap* create_reference_masked_bitmap(OtfCmd_136_Create_primitive_Reference_Masked_Bitmap* cmd); + DiBitmap* create_reference_transparent_bitmap(OtfCmd_137_Create_primitive_Reference_Transparent_Bitmap* cmd); + DiBitmap* create_duplicate_solid_bitmap(OtfCmd_145_Create_primitive_Duplicate_Solid_Bitmap* cmd); + DiBitmap* create_duplicate_masked_bitmap(OtfCmd_146_Create_primitive_Duplicate_Masked_Bitmap* cmd); + DiBitmap* create_duplicate_transparent_bitmap(OtfCmd_147_Create_primitive_Duplicate_Transparent_Bitmap* cmd); + DiBitmap* create_solid_bitmap_for_tile_array(OtfCmd_81_Create_Solid_Bitmap_for_Tile_Array* cmd); + DiBitmap* create_masked_bitmap_for_tile_array(OtfCmd_82_Create_Masked_Bitmap_for_Tile_Array* cmd); + DiBitmap* create_transparent_bitmap_for_tile_array(OtfCmd_83_Create_Transparent_Bitmap_for_Tile_Array* cmd); + DiBitmap* create_solid_bitmap_for_tile_map(OtfCmd_101_Create_Solid_Bitmap_for_Tile_Map *cmd); + DiBitmap* create_masked_bitmap_for_tile_map(OtfCmd_102_Create_Masked_Bitmap_for_Tile_Map* cmd); + DiBitmap* create_transparent_bitmap_for_tile_map(OtfCmd_103_Create_Transparent_Bitmap_for_Tile_Map* cmd); + DiRender* create_solid_render(OtfCmd_200_Create_primitive_Solid_Render* cmd); + DiRender* create_masked_render(OtfCmd_201_Create_primitive_Masked_Render* cmd); + DiRender* create_transparent_render(OtfCmd_202_Create_primitive_Transparent_Render* cmd); + DiPrimitive* create_primitive_group(OtfCmd_140_Create_primitive_Group* cmd); + + // Set the flags for an existing primitive. + void set_primitive_flags(uint16_t id, uint16_t flags); + + // Move an existing primitive to an absolute position. + void set_primitive_position(uint16_t id, int32_t x, int32_t y); + + // Move an existing primitive to a relative position. + void adjust_primitive_position(uint16_t id, int32_t x, int32_t y); + + // Delete an existing primitive. + void delete_primitive(uint16_t id); + + // Generate code for an existing primitive. + void generate_code_for_primitive(uint16_t id); + + // Move an existing bitmap to an absolute position and slice it. + void slice_solid_bitmap_absolute(OtfCmd_123_Set_position_and_slice_solid_bitmap* cmd); + void slice_masked_bitmap_absolute(OtfCmd_124_Set_position_and_slice_masked_bitmap* cmd); + void slice_transparent_bitmap_absolute(OtfCmd_125_Set_position_and_slice_transparent_bitmap* cmd); + + // Move an existing bitmap to a relative position and slice it. + void slice_solid_bitmap_relative(OtfCmd_126_Adjust_position_and_slice_solid_bitmap* cmd); + void slice_masked_bitmap_relative(OtfCmd_127_Adjust_position_and_slice_masked_bitmap* cmd); + void slice_transparent_bitmap_relative(OtfCmd_128_Adjust_position_and_slice_transparent_bitmap* cmd); + + // Set a pixel within an existing bitmap. + void set_solid_bitmap_pixel(OtfCmd_129_Set_solid_bitmap_pixel* cmd, uint16_t nth); + void set_masked_bitmap_pixel(OtfCmd_130_Set_masked_bitmap_pixel* cmd, uint16_t nth); + void set_transparent_bitmap_pixel(OtfCmd_131_Set_transparent_bitmap_pixel* cmd, uint16_t nth); + void set_solid_bitmap_pixel_for_tile_array(OtfCmd_85_Set_solid_bitmap_pixel_in_Tile_Array* cmd, uint16_t nth); + void set_masked_bitmap_pixel_for_tile_array(OtfCmd_86_Set_masked_bitmap_pixel_in_Tile_Array* cmd, uint16_t nth); + void set_transparent_bitmap_pixel_for_tile_array(OtfCmd_87_Set_transparent_bitmap_pixel_in_Tile_Array* cmd, uint16_t nth); + void set_solid_bitmap_pixel_for_tile_map(OtfCmd_105_Set_solid_bitmap_pixel_in_Tile_Map* cmd, uint16_t nth); + void set_masked_bitmap_pixel_for_tile_map(OtfCmd_106_Set_masked_bitmap_pixel_in_Tile_Map* cmd, uint16_t nth); + void set_transparent_bitmap_pixel_for_tile_map(OtfCmd_107_Set_transparent_bitmap_pixel_in_Tile_Map* cmd, uint16_t nth); + + // Set bitmap ID for tile in tile array. + void set_tile_array_bitmap_id(OtfCmd_84_Set_bitmap_ID_for_tile_in_Tile_Array* cmd); + + // Set bitmap ID for tile in tile map. + void set_tile_map_bitmap_id(OtfCmd_104_Set_bitmap_ID_for_tile_in_Tile_Map* cmd); + + // Setup a callback for when the visible frame pixels have been sent to DMA, + // and the vertical blanking time begins. + void set_on_vertical_blank_cb(DiVoidCallback callback_fcn); + + // Setup and run the main loop to do continuous drawing. + // For the demo, the loop never ends. + void IRAM_ATTR run(); + + // Store an incoming character for use later. + void store_character(uint8_t character); + + // Store an incoming character string for use later. + // The string is null-terminated. + void store_string(const uint8_t* string); + inline void store_string(const char* string) { store_string((const uint8_t*) string); } + + // Validate a primitive ID. + inline bool validate_id(int16_t id) { return (id >= 0) && (id < MAX_NUM_PRIMITIVES); } + + // Get a safe primitive pointer. + inline DiPrimitive* get_safe_primitive(int16_t id) { return validate_id(id) ? m_primitives[id] : NULL; } + + protected: + // Structures used to support DMA for video. + volatile lldesc_t * m_dma_descriptor; // [DMA_TOTAL_DESCR] + DiVideoScanLine * m_video_lines; // [NUM_ACTIVE_BUFFERS] + DiVideoScanLine * m_front_porch; + DiVideoScanLine * m_vertical_sync; + DiVideoScanLine * m_back_porch; + DiVoidCallback m_on_vertical_blank_cb; + uint32_t m_next_buffer_write; + uint32_t m_next_buffer_read; + uint32_t m_num_buffer_chars; + uint32_t m_command_data_index; + DiTextArea* m_text_area; + DiPrimitive* m_cursor; + uint8_t m_flash_count; + uint8_t m_incoming_data[INCOMING_DATA_BUFFER_SIZE]; + std::vector m_incoming_command; + DiPrimitive * m_primitives[MAX_NUM_PRIMITIVES]; // Indexes of array are primitive IDs + std::vector* m_groups; // Vertical scan groups (for optimizing paint calls) + + // Setup the DMA stuff. + void initialize(); + + // Run the main loop. + void IRAM_ATTR loop(); + + // Clear the primitive data, etc. + void clear(); + + // Add a primitive to the manager. + void add_primitive(DiPrimitive* prim, DiPrimitive* parent); + + // Delete a primitive from the manager. + void remove_primitive(DiPrimitive* prim); + + // Recompute the geometry and paint list membership for a primitive. + void recompute_primitive(DiPrimitive* prim, uint16_t old_flags, + int32_t old_min_group, int32_t old_max_group); + // Finish creating a primitive. + DiPrimitive* finish_create(uint16_t id, DiPrimitive* prim, DiPrimitive* parent_prim); + + // Draw all primitives that belong to the active scan line group. + void IRAM_ATTR draw_primitives(volatile uint32_t* p_scan_line, uint32_t line_index); + + // Setup a single DMA descriptor. + void init_dma_descriptor(DiVideoScanLine* vscan, uint32_t scan_index, uint32_t descr_index); + + // Process all stored characters. + void process_stored_characters(); + + // Process an incoming character, which could be printable data or part of some + // VDU command. If the character is printable, it will be written to the text_area + // display. If the character is non-printable, or part of a VDU command, it will + // be treated accordingly. This function returns true if the character was fully + // processed, and false otherwise. + bool process_character(uint8_t character); + + // Process an incoming string, which could be printable data and/or part of some + // VDU command(s). This function calls process_character(), for each character + // in the given string. The string is null-terminated. + void process_string(const uint8_t* string); + + // Insert a primitive into a vertical drawing group. This is unrelated to group primitives. + // The Z-order of drawing primitives is based on their primitive IDs, not on their order + // of creation, and not on their parent-child relationships. + void insert_primitive_into_vertical_group(DiPrimitive* prim, std::vector * vp); + + uint8_t get_param_8(uint32_t index); + int16_t get_param_16(uint32_t index); + bool handle_udg_sys_cmd(uint8_t character); + bool handle_otf_cmd(uint8_t character); + bool define_graphics_viewport(); + bool define_text_viewport(); + void move_cursor_tab(VduCmd_31_Set_text_tab_position* cmd); + void clear_screen(); + void move_cursor_left(); + void move_cursor_right(); + void move_cursor_down(); + void move_cursor_up(); + void move_cursor_home(); + void move_cursor_boln(); + void do_backspace(); + uint8_t read_character(int16_t x, int16_t y); + void write_character(uint8_t character); + void report(uint8_t character); + static uint8_t to_hex(uint8_t value); + uint8_t peek_into_buffer(); + uint8_t read_from_buffer(); + void skip_from_buffer(); + void send_cursor_position(); + void send_screen_char(int16_t x, int16_t y); + void send_screen_pixel(int16_t x, int16_t y); + void send_mode_information(); + void send_general_poll(uint8_t b); +}; \ No newline at end of file diff --git a/video/src/di_primitive.cpp b/video/src/di_primitive.cpp new file mode 100644 index 00000000..048afce7 --- /dev/null +++ b/video/src/di_primitive.cpp @@ -0,0 +1,427 @@ +// di_primitive.cpp - Function definitions for base drawing primitives +// +// A drawing primitive tells how to draw a particular type of simple graphic object. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_primitive.h" +#include +#include "di_timing.h" + +DiPrimitive::DiPrimitive(uint16_t flags) { + // Zero out everything but the vtable pointer. + memset(((uint8_t*)this)+sizeof(DiPrimitive*), 0, sizeof(DiPrimitive)-sizeof(DiPrimitive*)); + m_flags = flags; +} + +DiPrimitive::~DiPrimitive() { +} + +void DiPrimitive::init_root() { + // The root primitive covers the entire screen, and is not drawn. + // The application should define what the base layer of the screen + // is (e.g., solid rectangle, text area, tile map, etc.). + + m_flags = PRIM_FLAG_PAINT_KIDS|PRIM_FLAG_CLIP_KIDS; + m_width = otf_video_params.m_active_pixels; + m_height = otf_video_params.m_active_lines; + m_x_extent = otf_video_params.m_active_pixels; + m_y_extent = otf_video_params.m_active_lines; + m_view_x_extent = otf_video_params.m_active_pixels; + m_view_y_extent = otf_video_params.m_active_lines; + m_draw_x_extent = otf_video_params.m_active_pixels; + m_draw_y_extent = otf_video_params.m_active_lines; +} + +void DiPrimitive::set_id(uint16_t id) { + m_id = id; +} + +bool IRAM_ATTR DiPrimitive::get_vertical_group_range(int32_t& min_group, int32_t& max_group) { + if (m_draw_x_extent <= m_draw_x || m_draw_y_extent <= m_draw_y) { + // The primitive should not be drawn + return false; + } else { + // The primitive should be drawn + min_group = m_draw_y; + max_group = m_draw_y_extent - 1; + return true; + } +} + +void IRAM_ATTR DiPrimitive::paint(volatile uint32_t* p_scan_line, uint32_t line_index) {} + +void IRAM_ATTR DiPrimitive::attach_child(DiPrimitive* child) { + if (m_last_child) { + m_last_child->m_next_sibling = child; + child->m_prev_sibling = m_last_child; + } else { + m_first_child = child; + } + child->m_parent = this; + m_last_child = child; +} + +void IRAM_ATTR DiPrimitive::detach_child(DiPrimitive* child) { + if (child->m_next_sibling) { + child->m_next_sibling->m_prev_sibling = child->m_prev_sibling; + } + if (child->m_prev_sibling) { + child->m_prev_sibling->m_next_sibling = child->m_next_sibling; + } + if (m_first_child == child) { + m_first_child = child->m_next_sibling; + } + if (m_last_child == child) { + m_last_child = child->m_prev_sibling; + } +} + +void IRAM_ATTR DiPrimitive::set_relative_position(int32_t rel_x, int32_t rel_y) { + m_rel_x = rel_x; + m_rel_y = rel_y; +} + +void IRAM_ATTR DiPrimitive::set_relative_deltas(int32_t rel_dx, int32_t rel_dy, uint32_t auto_moves) { + m_rel_dx = rel_dx; + m_rel_dy = rel_dy; + m_auto_moves = auto_moves; +} + +void IRAM_ATTR DiPrimitive::set_size(uint32_t width, uint32_t height) { + m_width = width; + m_height = height; +} + +void IRAM_ATTR DiPrimitive::compute_absolute_geometry() { + if (m_parent) { + if (m_parent->get_flags() & PRIM_FLAG_CLIP_KIDS) { + compute_absolute_geometry(m_parent->get_draw_x(), m_parent->get_draw_y(), + m_parent->get_draw_x_extent(), m_parent->get_draw_y_extent()); + } else { + compute_absolute_geometry(m_parent->get_view_x(), m_parent->get_view_y(), + m_parent->get_view_x_extent(), m_parent->get_view_y_extent()); + } + } else { + compute_absolute_geometry(0, 0, m_width, m_height); + } +} + +void IRAM_ATTR DiPrimitive::compute_absolute_geometry( + int32_t view_x, int32_t view_y, int32_t view_x_extent, int32_t view_y_extent) { + if ((m_flags & PRIM_FLAG_ABSOLUTE) | !m_parent) { + m_abs_x = m_rel_x; + m_abs_y = m_rel_y; + } else { + m_abs_x = m_parent->m_abs_x + m_rel_x; + m_abs_y = m_parent->m_abs_y + m_rel_y; + } + + m_x_extent = m_abs_x + m_width; + m_y_extent = m_abs_y + m_height; + + if (m_flags & PRIM_FLAG_CLIP_THIS) { + m_view_x = view_x; + m_view_y = view_y; + m_view_x_extent = view_x_extent; + m_view_y_extent = view_y_extent; + } else { + m_view_x = 0; + m_view_y = 0; + m_view_x_extent = otf_video_params.m_active_pixels; + m_view_y_extent = otf_video_params.m_active_lines; + } + + m_draw_x = MAX(m_abs_x, m_view_x); + m_draw_y = MAX(m_abs_y, m_view_y); + m_draw_x_extent = MIN(m_x_extent, m_view_x_extent); + m_draw_y_extent = MIN(m_y_extent, m_view_y_extent); + + if (m_paint_ptrs.size()) { + set_current_paint_pointer(); + } + + DiPrimitive* child = m_first_child; + while (child) { + if (m_flags & PRIM_FLAG_CLIP_KIDS) { + child->compute_absolute_geometry(m_draw_x, m_draw_y, m_draw_x_extent, m_draw_y_extent); + } else { + child->compute_absolute_geometry(view_x, view_y, view_x_extent, view_y_extent); + } + child = child->m_next_sibling; + } +} + +void DiPrimitive::clear_child_ptrs() { + m_first_child = NULL; + m_last_child = NULL; +} + +void DiPrimitive::delete_instructions() { + m_paint_code.clear(); + m_paint_ptrs.clear(); + m_cur_paint_ptr.clear(); +} + +void DiPrimitive::generate_instructions() { +} + +// Convert normal alpha bits of color to opaqueness percentage. +// This will also remove the alpha bits from the color. +uint8_t DiPrimitive::normal_alpha_to_opaqueness(uint8_t &color) { + uint8_t alpha = color >> 6; + color &= 0x3F; // remove alpha bits + switch (alpha) { + case 0: return 25; + case 1: return 50; + case 2: return 75; + default: return 100; + } +} + +// Convert inverted alpha bits of color to opaqueness percentage. +// This will also remove the alpha bits from the color. +uint8_t DiPrimitive::inverted_alpha_to_opaqueness(uint8_t &color) { + uint8_t alpha = color >> 6; + color &= 0x3F; // remove alpha bits + switch (alpha) { + case 1: return 75; + case 2: return 50; + case 3: return 25; + default: return 100; + } +} + +/* + Overall cases for clipping the drawing of a primitive horizontally: + + Clipping Area (dots) + + m_view_x m_view_x_extent + v v + .............................. + : : + *********** : + *********** Primitive : Clip on Left Side + *********** (stars) : + *********** : + *********** : + ^ : : + m_abs_x .............................. + ^ ^ + m_draw_x m_draw_x_extent, m_x_extent + + .............................. + : : + : *********** : + : *********** : Show Full Primitive + : *********** : (no clipping) + : *********** : + : *********** : + : : + .............................. + ^ ^ + m_abs_x, m_draw_x m_draw_x_extent, m_x_extent + + .............................. + : : + : *********** + : *********** Clip on Right Side + : *********** + : *********** + : *********** + : : ^ + .............................. m_x_extent + ^ ^ + m_abs_x, m_draw_x m_draw_x_extent + + What code we generate depends on the above cases, plus whether the + primitive can be moved (scrolled), as indicated by its flag bits. +*/ + +void DiPrimitive::generate_code_for_left_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + start_paint_section(); +} + +void DiPrimitive::generate_code_for_right_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + start_paint_section(); +} + +void DiPrimitive::generate_code_for_draw_area(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + start_paint_section(); +} + +void DiPrimitive::generate_code_for_positions(EspFixups& fixups, uint32_t width, uint32_t height) { + delete_instructions(); + + if (m_flags & PRIM_FLAG_H_SCROLL_1) { + // Support scrolling by 1 pixel + if (m_flags & PRIM_FLAGS_LEFT_EDGE) { + // Support left edge being hidden + for (uint32_t hidden = 1; hidden < width; hidden++) { + uint32_t visible = width - hidden; + for (uint32_t pos = 0; pos < 4; pos++) { + generate_code_for_left_edge(fixups, pos, width, height, hidden, visible); + } + } + } + if (m_flags & PRIM_FLAGS_RIGHT_EDGE) { + // Support right edge being hidden + for (uint32_t hidden = 1; hidden < width; hidden++) { + uint32_t visible = width - hidden; + for (uint32_t pos = 0; pos < 4; pos++) { + generate_code_for_right_edge(fixups, pos, width, height, hidden, visible); + } + } + } + + // Support drawing full primitive + for (uint32_t pos = 0; pos < 4; pos++) { + generate_code_for_draw_area(fixups, pos, width, height, 0, width); + } + } else if (m_flags & PRIM_FLAG_H_SCROLL_4) { + // Support scrolling by 4 pixels + uint32_t pos = m_abs_x & 3; + if (m_flags & PRIM_FLAGS_LEFT_EDGE) { + // Support left edge being hidden + for (uint32_t hidden = 4; hidden < width; hidden += 4) { + uint32_t visible = width - hidden; + generate_code_for_left_edge(fixups, pos, width, height, hidden, visible); + } + } + if (m_flags & PRIM_FLAGS_RIGHT_EDGE) { + // Support right edge being hidden + for (uint32_t hidden = 4; hidden < width; hidden += 4) { + uint32_t visible = width - hidden; + generate_code_for_right_edge(fixups, pos, width, height, hidden, visible); + } + } + + // Support drawing full primitive + generate_code_for_draw_area(fixups, pos, width, height, 0, width); + } else { + // Primitive must be static (no scrolling) + uint32_t pos = m_abs_x & 3; + uint32_t hidden = m_draw_x - m_abs_x; + uint32_t visible = m_draw_x_extent - m_draw_x; + generate_code_for_draw_area(fixups, pos, width, height, hidden, visible); + } + + // Convert function offsets to function pointers. + for (auto ptr = m_paint_ptrs.begin(); ptr != m_paint_ptrs.end(); ptr++) { + ptr->m_address = m_paint_code.get_real_address(ptr->m_address); + } +} + +extern void debug_log(const char* f, ...); + +void DiPrimitive::set_current_paint_pointer(uint32_t width, uint32_t height, + uint32_t left_hidden, uint32_t right_hidden) { +// debug_log(" @%i ",__LINE__); + m_cur_paint_ptr = get_paint_pointer(width, height, left_hidden, right_hidden); +} + +void DiPrimitive::set_current_paint_pointer(uint32_t width, uint32_t height) { +// debug_log(" @%i ",__LINE__); + m_cur_paint_ptr = get_paint_pointer(width, height); +} + +void DiPrimitive::set_current_paint_pointer() { + set_current_paint_pointer(m_width, m_height); +} + +uint32_t DiPrimitive::get_paint_fcn_index(uint32_t width, uint32_t height, uint32_t left_hidden, uint32_t right_hidden) { + debug_log("gpfi %u %u %u %u\n",width, height, left_hidden, right_hidden); + uint32_t index = 0; + uint32_t pos = m_abs_x & 3; + + do { + if (m_flags & PRIM_FLAG_H_SCROLL_1) { + // Support scrolling by 1 pixel + if (m_flags & PRIM_FLAGS_LEFT_EDGE) { + // Support left edge being hidden + if (left_hidden) { + index = (left_hidden - 1) * 4 + pos; + break; + } else { + index += (width - 1) * 4; + } + } + if (m_flags & PRIM_FLAGS_RIGHT_EDGE) { + // Support right edge being hidden + if (right_hidden) { + index += (right_hidden - 1) * 4 + pos; + break; + } else { + index += (width - 1) * 4; + } + } + + index += pos; + } else if (m_flags & PRIM_FLAG_H_SCROLL_4) { + // Support scrolling by 4 pixels + if (m_flags & PRIM_FLAGS_LEFT_EDGE) { + // Support left edge being hidden + if (left_hidden) { + index += left_hidden / 4; + break; + } else { + index += width / 4; + } + } + if (m_flags & PRIM_FLAGS_RIGHT_EDGE) { + // Support right edge being hidden + if (right_hidden) { + index += right_hidden / 4; + break; + } else { + index += width / 4; + } + } + } + } while (false); + return index; +} + +EspFcnPtr DiPrimitive::get_paint_pointer(uint32_t width, uint32_t height, uint32_t left_hidden, uint32_t right_hidden) { + return m_paint_ptrs[get_paint_fcn_index(width, height, left_hidden, right_hidden)]; +} + +EspFcnPtr DiPrimitive::get_paint_pointer(uint32_t width, uint32_t height) { + uint32_t hidden_left = 0; + uint32_t hidden_right = 0; + if (m_abs_x < m_draw_x) { + hidden_left = m_draw_x - m_abs_x; + } + if (m_draw_x_extent < m_x_extent) { + hidden_right = m_x_extent - m_draw_x_extent; + } + // debug_log("gpp id %hu w %u h %u hL %u hR %u\n",m_id,width,height,hidden_left,hidden_right); + return get_paint_pointer(width, height, hidden_left, hidden_right); +} + +void DiPrimitive::start_paint_section() { + m_paint_code.align32(); + EspFcnPtr p; + p.m_address = m_paint_code.get_code_index(); + m_paint_ptrs.push_back(p); +} diff --git a/video/src/di_primitive.h b/video/src/di_primitive.h new file mode 100644 index 00000000..c0d05313 --- /dev/null +++ b/video/src/di_primitive.h @@ -0,0 +1,187 @@ +// di_primitive.h - Function declarations for base drawing primitives +// NOTE: This file must track exactly with constants in di_primitive_const.h. +// +// A drawing primitive tells how to draw a particular type of simple graphic object. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include +#include +#include "driver/gpio.h" +#include "di_constants.h" +#include "di_code.h" + +#pragma pack(push,1) + +class DiPrimitive { + public: + // An object to be drawn on the screen. + DiPrimitive(uint16_t flags); + + // Destroys an allocated RAM required by the primitive. + virtual ~DiPrimitive(); + + // Initialize as a root primitive. + void init_root(); + + // Set the ID of this primitive as defined by the BASIC application. This + // ID is actually the index of the primitive in a table of pointers. + void set_id(uint16_t id); + + // Draws the primitive to the DMA scan line buffer. + virtual void IRAM_ATTR paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + // Groups scan lines for optimizing paint calls. + bool IRAM_ATTR get_vertical_group_range(int32_t& min_group, int32_t& max_group); + + // Attach a child primitive. + void IRAM_ATTR attach_child(DiPrimitive* child); + + // Detach a child primitive. + void IRAM_ATTR detach_child(DiPrimitive* child); + + // Set the X, Y position relative to the parent (which may be the screen). + virtual void IRAM_ATTR set_relative_position(int32_t rel_x, int32_t rel_y); + + // Set the delta X, Y position, relative to the parent, and the move count. + // These values are used to update the relative position automatically, frame-by-frame. + void IRAM_ATTR set_relative_deltas(int32_t rel_dx, int32_t rel_dy, uint32_t auto_moves); + + // Set the size of the primitive. This only used for certain types of primitives. + virtual void IRAM_ATTR set_size(uint32_t width, uint32_t height); + + // Compute the absolute position and related data members, based on the + // current position, relative to the parent primitive. The viewport of + // this primitive is based on the parent draw parameters and certain flags. + void IRAM_ATTR compute_absolute_geometry(); + + // Compute the absolute position and related data members, based on the + // current position, relative to the parent primitive. The viewport of + // this primitive is based on the given viewport parameters and certain flags. + void IRAM_ATTR compute_absolute_geometry(int32_t view_x, int32_t view_y, int32_t view_x_extent, int32_t view_y_extent); + + // Clear the custom instructions needed to draw the primitive. + virtual void delete_instructions(); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + // Convert normal alpha bits of color to opaqueness percentage. + // This will also remove the alpha bits from the color. + static uint8_t normal_alpha_to_opaqueness(uint8_t &color); + + // Convert inverted alpha bits of color to opaqueness percentage. + // This will also remove the alpha bits from the color. + static uint8_t inverted_alpha_to_opaqueness(uint8_t &color); + + // Gets various data members. + inline uint16_t get_id() { return m_id; } + inline uint16_t get_flags() { return m_flags; } + inline int32_t get_relative_x() { return m_rel_x; } + inline int32_t get_relative_y() { return m_rel_y; } + inline int32_t get_absolute_x() { return m_abs_x; } + inline int32_t get_absolute_y() { return m_abs_y; } + inline int32_t get_width() { return m_width; } + inline int32_t get_height() { return m_height; } + inline int32_t get_view_x() { return m_view_x; } + inline int32_t get_view_y() { return m_view_y; } + inline int32_t get_view_x_extent() { return m_view_x_extent; } + inline int32_t get_view_y_extent() { return m_view_y_extent; } + inline int32_t get_draw_x() { return m_draw_x; } + inline int32_t get_draw_y() { return m_draw_y; } + inline int32_t get_draw_x_extent() { return m_draw_x_extent; } + inline int32_t get_draw_y_extent() { return m_draw_y_extent; } + inline DiPrimitive* get_parent() { return m_parent; } + inline DiPrimitive* get_first_child() { return m_first_child; } + inline DiPrimitive* get_next_sibling() { return m_next_sibling; } + inline uint8_t get_color() { return (uint8_t)m_color; } + inline uint32_t get_color32() { return m_color; } + inline uint32_t get_custom() { return m_custom; } + + // Sets some data members. + inline void set_flags(uint16_t flags) { m_flags = flags; } + inline void add_flags(uint16_t flags) { m_flags |= flags; } + inline void remove_flags(uint16_t flags) { m_flags &= ~flags; } + inline void set_color32(uint32_t color) { m_color = color; } + inline void set_custom(uint32_t custom) { m_custom = custom; } + + // Clear the pointers to children. + void clear_child_ptrs(); + + uint32_t get_paint_fcn_index(uint32_t width, uint32_t height, uint32_t left_hidden, uint32_t right_hidden); + EspFcnPtr get_paint_pointer(uint32_t width, uint32_t height, uint32_t left_hidden, uint32_t right_hidden); + EspFcnPtr get_paint_pointer(uint32_t width, uint32_t height); + + protected: + // Used to type-case some pointers. (Might be removed in future.) + inline uint8_t* pixels(uint32_t* line) { + return (uint8_t*)line; + } + + // Generically generate the drawing instructions for various X/Y positions. + virtual void generate_code_for_left_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + virtual void generate_code_for_right_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + virtual void generate_code_for_draw_area(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + void generate_code_for_positions(EspFixups& fixups, uint32_t width, uint32_t height); + void set_current_paint_pointer(uint32_t width, uint32_t height, uint32_t left_hidden, uint32_t right_hidden); + void set_current_paint_pointer(uint32_t width, uint32_t height); + void set_current_paint_pointer(); + void start_paint_section(); + + int32_t m_view_x; // upper-left x coordinate of the enclosing viewport, relative to the screen + int32_t m_view_y; // upper-left y coordinate of the enclosing viewport, relative to the screen + int32_t m_view_x_extent; // lower-right x coordinate plus 1, of the enclosing viewport + int32_t m_view_y_extent; // lower-right y coordinate plus 1, of the enclosing viewport + int32_t m_rel_x; // upper-left x coordinate, relative to the parent + int32_t m_rel_y; // upper-left y coordinate, relative to the parent + int32_t m_rel_dx; // auto-delta-x as a 16-bit fraction, relative to the parent + int32_t m_rel_dy; // auto-delta-y as a 16-bit fraction, relative to the parent + int32_t m_auto_moves; // number of times to move this primitive automatically + int32_t m_abs_x; // upper-left x coordinate, relative to the screen + int32_t m_abs_y; // upper-left y coordinate, relative to the screen + int32_t m_width; // coverage width in pixels + int32_t m_height; // coverage height in pixels + int32_t m_x_extent; // sum of m_abs_x + m_width + int32_t m_y_extent; // sum of m_abs_y + m_height + int32_t m_draw_x; // max of m_abs_x and m_view_x + int32_t m_draw_y; // max of m_abs_y and m_view_y + int32_t m_draw_x_extent; // min of m_x_extent and m_view_x_extent + int32_t m_draw_y_extent; // min of m_y_extent and m_view_y_extent + uint32_t m_color; // applies to some primitives, but not to others + uint32_t m_custom; // for custom use + DiPrimitive* m_parent; // id of parent primitive + DiPrimitive* m_first_child; // id of first child primitive + DiPrimitive* m_last_child; // id of last child primitive + DiPrimitive* m_prev_sibling; // id of previous sibling primitive + DiPrimitive* m_next_sibling; // id of next sibling primitive + EspFunction m_paint_code; // generated code used to draw the primitive + EspFcnPtrs m_paint_ptrs; // pointers to sections of generated paint code + EspFcnPtr m_cur_paint_ptr; // points to pointers to code sections based on position + int16_t m_first_group; // lowest index of drawing group in which it is a member + int16_t m_last_group; // highest index of drawing group in which it is a member + int16_t m_id; // id of this primitive + uint16_t m_flags; // flag bits to control painting, etc. + uint16_t m_num_fcns; // Number of allocated paint functions +}; + +#pragma pack(pop) \ No newline at end of file diff --git a/video/src/di_primitive_const.h b/video/src/di_primitive_const.h new file mode 100644 index 00000000..7e5f8eac --- /dev/null +++ b/video/src/di_primitive_const.h @@ -0,0 +1,31 @@ +// di_primitive_const.INC - Structure member offsets for base drawing primitives +// NOTE: This file must track exactly with structures in di_primitive.h. +// +// A drawing primitive tells how to draw a particular type of simple graphic object. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +// Offsets into DiPrimitive base class structure: + +#define FLD_color 80 // 20 * 4 +#define FLD_abs_y 44 // 11 * 4 +#define FLD_draw_x 64 // 16 * 4 diff --git a/video/src/di_rectangle.cpp b/video/src/di_rectangle.cpp new file mode 100644 index 00000000..1a9a04e3 --- /dev/null +++ b/video/src/di_rectangle.cpp @@ -0,0 +1,71 @@ +// di_rectangle.cpp - Function definitions for drawing rectangle outlines +// +// A rectangle outline is a thin rectangle that is left unfilled. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_rectangle.h" +#include "di_timing.h" + +DiRectangle::DiRectangle(uint16_t flags) : DiPrimitive(flags) { +} + +void DiRectangle::make_rectangle_outline(int32_t x, int32_t y, uint32_t width, uint32_t height, uint8_t color) { + m_rel_x = x; + m_rel_y = y; + m_width = width; + m_height = height; + m_opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + m_color = PIXEL_COLOR_X4(color) | otf_video_params.m_syncs_off_x4; +} + +void DiRectangle::generate_instructions() { + /* + delete_instructions(); + auto width = (uint16_t)m_width; + { + EspFixups fixups; + DiLineSections sections; + sections.add_piece(1, 0, width, false); + m_paint_code[0].draw_line(fixups, m_draw_x, m_draw_x, §ions, m_flags, m_opaqueness, true); + m_paint_code[0].do_fixups(fixups); + } + { + EspFixups fixups; + DiLineSections sections; + sections.add_piece(1, 0, 1, false); + sections.add_piece(1, width-1, 1, false); + m_paint_code[1].draw_line(fixups, m_draw_x, m_draw_x, §ions, m_flags, m_opaqueness, true); + m_paint_code[1].do_fixups(fixups); + } + */ +} + +void IRAM_ATTR DiRectangle::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { + /* + if (line_index == m_abs_y || line_index + 1 == m_y_extent) { + m_paint_code[0].call(this, p_scan_line, line_index); + } else { + m_paint_code[1].call(this, p_scan_line, line_index); + } + */ +} diff --git a/video/src/di_rectangle.h b/video/src/di_rectangle.h new file mode 100644 index 00000000..d9fe924d --- /dev/null +++ b/video/src/di_rectangle.h @@ -0,0 +1,44 @@ +// di_rectangle.h - Function declarations for drawing rectangle outlines +// +// A rectangle outline is a thin rectangle that is left unfilled. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" + +class DiRectangle: public DiPrimitive { + public: + // Construct a rectangle outline. This requires calling init_params() afterward. + DiRectangle(uint16_t flags); + + // Draws a rectangle outline on the screen. + void make_rectangle_outline(int32_t x, int32_t y, uint32_t width, uint32_t height, uint8_t color); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + virtual void paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + protected: + uint8_t m_opaqueness; +}; diff --git a/video/src/di_render.cpp b/video/src/di_render.cpp new file mode 100644 index 00000000..3a9fefb2 --- /dev/null +++ b/video/src/di_render.cpp @@ -0,0 +1,186 @@ +// di_render.cpp - Function definitions for drawing bitmaps via 3D rendering +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// This code reliese on 'pingo' for its rendering functions. Refer to the +// README.md and LICENSE in the pingo directory for more information. +// + +#include "di_render.h" +#include "esp_heap_caps.h" + +extern "C" { + +#include "pingo/assets/teapot.h" + +#include "pingo/render/mesh.h" +#include "pingo/render/object.h" +#include "pingo/render/pixel.h" +#include "pingo/render/renderer.h" +#include "pingo/render/scene.h" +#include "pingo/render/backend.h" +#include "pingo/render/depth.h" +#include + +typedef struct Pixel Pixel; + +typedef struct { + BackEnd backend; + Vec2i size; +} DiRenderBackEnd; + +void di_render_init(DiRenderBackEnd * backend, Vec2i size); + +DiRenderBackEnd my_backend; +Vec4i rect; +Vec2i totalSize; +PingoDepth * zetaBuffer; +Pixel * frameBuffer; +PingoDepth * my_zetaBuffer; + + +void init( Renderer * ren, BackEnd * backEnd, Vec4i _rect) { + rect = _rect; + +} + +void beforeRender( Renderer * ren, BackEnd * backEnd) { + //DiRenderBackEnd * backend = (DiRenderBackEnd *) backEnd; +} + +void afterRender( Renderer * ren, BackEnd * backEnd) { +} + +Pixel * getFrameBuffer( Renderer * ren, BackEnd * backEnd) { + return frameBuffer; +} + +PingoDepth * getZetaBuffer( Renderer * ren, BackEnd * backEnd) { + return my_zetaBuffer; +} + +void di_render_init( DiRenderBackEnd * backend, Vec2i size) { + frameBuffer = (Pixel*) heap_caps_malloc(sizeof(Pixel) * 160 * 120, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + my_zetaBuffer = (PingoDepth*) heap_caps_malloc(sizeof(PingoDepth) * 160 * 120, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM); + + totalSize = size; + backend->backend.init = &init; + backend->backend.beforeRender = &beforeRender; + backend->backend.afterRender = &afterRender; + backend->backend.getFrameBuffer = &getFrameBuffer; + backend->backend.getZetaBuffer = &getZetaBuffer; + backend->backend.drawPixel = 0; +} + +} // extern "C" + +//----------------------------------------- + +DiRender::DiRender(uint32_t width, uint32_t height, uint16_t flags, bool use_psram) : + DiBitmap(width, height, flags, use_psram) { +} + +DiRender::~DiRender() { +} + +extern "C" { + +float angleZ = 3.142128; + +void do_render(int width, int height) { + Vec2i size = {width, height}; + + di_render_init(&my_backend, size); + Renderer renderer; + rendererInit(&renderer, size,(BackEnd*) &my_backend ); + rendererSetCamera(&renderer,(Vec4i){0,0,size.x,size.y}); + + Scene s; + sceneInit(&s); + rendererSetScene(&renderer, &s); + + Object object; + //object.material = NULL; + object.mesh = &mesh_teapot; + +/* + Material m; + Texture tex; + tex.size = Vec2i{2,2}; + Pixel solid[4]; + solid[0] = Pixel { 0xFE, 0xFD, 0x00, 0xFF }; + solid[1] = Pixel { 0xEE, 0x00, 0xEC, 0xFF }; + solid[2] = Pixel { 0x00, 0xDD, 0xDC, 0xFF }; + solid[3] = Pixel { 0xCE, 0x00, 0x00, 0xFF }; + tex.frameBuffer = solid; + m.texture = &tex; + object.material = &m; +*/ + object.material = NULL; + + sceneAddRenderable(&s, object_as_renderable(&object)); + + float phi = 0; + Mat4 t; + + // PROJECTION MATRIX - Defines the type of projection used + renderer.camera_projection = mat4Perspective( 1, 2500.0,(float)size.x / (float)size.y, 0.6); + + //VIEW MATRIX - Defines position and orientation of the "camera" + Mat4 v = mat4Translate((Vec3f) { 0,2,-35}); + + Mat4 rotateDown = mat4RotateX(-0.40); //Rotate around origin/orbit + renderer.camera_view = mat4MultiplyM(&rotateDown, &v ); + + object.transform = mat4Scale(Vec3f { 6.0f, 6.0f, 6.0f }); + + //TRANSFORM - Defines position and orientation of the object + t = mat4RotateZ(angleZ); + angleZ += 3.142128f/4.0f; + + object.transform = mat4MultiplyM(&object.transform, &t ); + + t = mat4RotateZ(0); + object.transform = mat4MultiplyM(&object.transform, &t ); + + //SCENE + s.transform = mat4RotateY(phi); + phi += 0.01; + + rendererRender(&renderer); +} + +} // extern "C" + +void DiRender::render() { + do_render(m_width, m_height); + + Pixel* p_render_pixels = frameBuffer; + for (uint y = 0; y < m_height; y++) { + for (uint x = 0; x < m_width; x++) { + uint8_t c = ((p_render_pixels->b >> 6) << 4) | + ((p_render_pixels->g >> 6) << 2) | + ((p_render_pixels->r >> 6)); + set_transparent_pixel(x, y, c|PIXEL_ALPHA_100_MASK); + p_render_pixels++; + } + } +} diff --git a/video/src/di_render.h b/video/src/di_render.h new file mode 100644 index 00000000..da668730 --- /dev/null +++ b/video/src/di_render.h @@ -0,0 +1,43 @@ +// di_render.h - Function declarations for drawing bitmaps via 3D rendering +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// This code reliese on 'pingo' for its rendering functions. Refer to the +// README.md and LICENSE in the pingo directory for more information. +// + +#pragma once +#include "di_bitmap.h" +#include "di_code.h" + +class DiRender : public DiBitmap { + public: + // Construct a render. + DiRender(uint32_t width, uint32_t height, uint16_t flags, bool use_psram); + + // Destroy a render. + ~DiRender(); + + // Render the 3D image onto the bitmap. + void render(); + + protected: +}; diff --git a/video/src/di_set_pixel.cpp b/video/src/di_set_pixel.cpp new file mode 100644 index 00000000..905332e6 --- /dev/null +++ b/video/src/di_set_pixel.cpp @@ -0,0 +1,52 @@ +// di_set_pixel.cpp - Function definitions for setting individual pixels +// +// A pixel is the smallest visible dot on the screen. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_set_pixel.h" +#include "di_timing.h" + +DiSetPixel::DiSetPixel(uint16_t flags, int32_t x, int32_t y, uint8_t color) : DiPrimitive(flags) { + m_opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + m_rel_x = x; + m_rel_y = y; + m_width = 1; + m_height = 1; + m_color = PIXEL_COLOR_X4(color) | otf_video_params.m_syncs_off_x4; + m_paint_code.enter_and_leave_outer_function(); +} + +void DiSetPixel::generate_instructions() { + delete_instructions(); + EspFixups fixups; + uint16_t width = 1; + DiLineSections sections; + sections.add_piece(1, 0, 1, false); + auto x_offset = m_abs_x & 3; + m_paint_code.draw_line(fixups, x_offset, 0, width, §ions, m_flags, m_opaqueness, true); + m_paint_code.do_fixups(fixups); +} + +void IRAM_ATTR DiSetPixel::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { + m_paint_code.call(this, p_scan_line, line_index); +} diff --git a/video/src/di_set_pixel.h b/video/src/di_set_pixel.h new file mode 100644 index 00000000..cebe2f51 --- /dev/null +++ b/video/src/di_set_pixel.h @@ -0,0 +1,42 @@ +// di_set_pixel.h - Function declarations for setting individual pixels +// +// A pixel is the smallest visible dot on the screen. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" +#include "di_code.h" + +class DiSetPixel: public DiPrimitive { + public: + // Draws a single pixel on the screen. + DiSetPixel(uint16_t flags, int32_t x, int32_t y, uint8_t color); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + virtual void paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + protected: + uint8_t m_opaqueness; +}; \ No newline at end of file diff --git a/video/src/di_solid_ellipse.cpp b/video/src/di_solid_ellipse.cpp new file mode 100644 index 00000000..997ef7c0 --- /dev/null +++ b/video/src/di_solid_ellipse.cpp @@ -0,0 +1,42 @@ +// di_solid_ellipse.cpp - Function definitions for drawing solid ellipses +// +// A solid ellipse is filled with a single color. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_solid_ellipse.h" +#include "di_timing.h" + +DiSolidEllipse::DiSolidEllipse(uint16_t flags) : DiPrimitive(flags) { +} + +void DiSolidEllipse::init_params(int32_t x, int32_t y, uint32_t width, uint32_t height, uint8_t color) { + m_rel_x = x; + m_rel_y = y; + m_width = width; + m_height = height; + color &= 0x3F; // remove any alpha bits + m_color = PIXEL_COLOR_X4(color) | otf_video_params.m_syncs_off_x4; +} + +void IRAM_ATTR DiSolidEllipse::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { +} diff --git a/video/src/di_solid_ellipse.h b/video/src/di_solid_ellipse.h new file mode 100644 index 00000000..6d6149a8 --- /dev/null +++ b/video/src/di_solid_ellipse.h @@ -0,0 +1,38 @@ +// di_solid_ellipse.h - Function declarations for drawing solid ellipses +// +// A solid ellipse is filled with a single color. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" + +class DiSolidEllipse: public DiPrimitive { + public: + // Construct a solid ellipse. This requires calling init_params() afterward. + DiSolidEllipse(uint16_t flags); + + // Draws a solid (filled) ellipse on the screen. + void init_params(int32_t x, int32_t y, uint32_t width, uint32_t height, uint8_t color); + + virtual void IRAM_ATTR paint(volatile uint32_t* p_scan_line, uint32_t line_index); +}; diff --git a/video/src/di_solid_rectangle.cpp b/video/src/di_solid_rectangle.cpp new file mode 100644 index 00000000..ee315edc --- /dev/null +++ b/video/src/di_solid_rectangle.cpp @@ -0,0 +1,77 @@ +// di_solid_rectangle.cpp - Function definitions for drawing solid rectangles +// +// A solid rectangle is filled with a single color. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_solid_rectangle.h" +#include "di_timing.h" + +DiSolidRectangle::DiSolidRectangle(uint16_t flags) : DiPrimitive(flags) { + m_flags |= PRIM_FLAGS_X; +} + +void DiSolidRectangle::make_rectangle(int32_t x, int32_t y, uint32_t width, uint32_t height, uint8_t color) { + m_opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + m_rel_x = x; + m_rel_y = y; + m_width = width; + m_height = height; + m_color = PIXEL_COLOR_X4(color) | otf_video_params.m_syncs_off_x4; + m_paint_code.enter_and_leave_outer_function(); +} + +void DiSolidRectangle::generate_instructions() { + delete_instructions(); + EspFixups fixups; + generate_code_for_positions(fixups, m_width, m_height); + m_paint_code.do_fixups(fixups); + set_current_paint_pointer(m_width, m_height); +} + +void DiSolidRectangle::generate_code_for_left_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + DiPrimitive::generate_code_for_left_edge(fixups, x_offset, width, height, hidden, visible); + auto draw_width = (m_draw_x_extent - m_draw_x) - hidden; + DiLineSections sections; + sections.add_piece(1, 0, (uint16_t)draw_width, false); + m_paint_code.draw_line(fixups, x_offset, hidden, visible, §ions, m_flags, m_opaqueness, true); +} + +void DiSolidRectangle::generate_code_for_right_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + DiPrimitive::generate_code_for_right_edge(fixups, x_offset, width, height, hidden, visible); + auto draw_width = (m_draw_x_extent - m_draw_x) - hidden; + DiLineSections sections; + sections.add_piece(1, 0, (uint16_t)draw_width, false); + m_paint_code.draw_line(fixups, x_offset, 0, visible, §ions, m_flags, m_opaqueness, true); +} + +void DiSolidRectangle::generate_code_for_draw_area(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible) { + DiPrimitive::generate_code_for_draw_area(fixups, x_offset, width, height, hidden, visible); + auto draw_width = m_draw_x_extent - m_draw_x; + DiLineSections sections; + sections.add_piece(1, 0, (uint16_t)draw_width, false); + m_paint_code.draw_line(fixups, x_offset, 0, draw_width, §ions, m_flags, m_opaqueness, true); +} + +void IRAM_ATTR DiSolidRectangle::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { + (*(m_cur_paint_ptr.m_a5))(this, p_scan_line, line_index, m_abs_x); +} diff --git a/video/src/di_solid_rectangle.h b/video/src/di_solid_rectangle.h new file mode 100644 index 00000000..d2513192 --- /dev/null +++ b/video/src/di_solid_rectangle.h @@ -0,0 +1,50 @@ +// di_solid_rectangle.h - Function declarations for drawing solid rectangles +// +// A solid rectangle is filled with a single color. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" +#include "di_code.h" + +class DiSolidRectangle: public DiPrimitive { + public: + uint8_t m_opaqueness; + + // Construct a solid rectangle. This requires calling init_params() afterward. + DiSolidRectangle(uint16_t flags); + + // Draws a solid (filled) rectangle on the screen. + void make_rectangle(int32_t x, int32_t y, uint32_t width, uint32_t height, uint8_t color); + + virtual void generate_code_for_left_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + virtual void generate_code_for_right_edge(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + virtual void generate_code_for_draw_area(EspFixups& fixups, uint32_t x_offset, uint32_t width, uint32_t height, uint32_t hidden, uint32_t visible); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + virtual void IRAM_ATTR paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + protected: +}; \ No newline at end of file diff --git a/video/src/di_text_area.cpp b/video/src/di_text_area.cpp new file mode 100644 index 00000000..f5eae58e --- /dev/null +++ b/video/src/di_text_area.cpp @@ -0,0 +1,286 @@ +// di_text_area.cpp - Function definitions for supporting a character text_area display +// +// A text_area is a specialized tile array, where each tile is a single character +// cell, and the character codes are used as tile image IDs. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_text_area.h" +#include +#include "di_timing.h" + +DiTextArea::DiTextArea(uint32_t x, uint32_t y, uint8_t flags, + uint32_t columns, uint32_t rows, const uint8_t* font) : + DiTileArray(columns*8, rows*8, columns, rows, 8, 8, flags) { + m_flags |= PRIM_FLAGS_ALL_SAME; + m_current_column = 0; + m_current_row = 0; + m_fg_color = PIXEL_COLOR_ARGB(3, 1, 1, 0); + m_bg_color = PIXEL_COLOR_ARGB(3, 0, 0, 0); + m_font = font; + m_rel_x = x; + m_rel_y = y; +} + +DiTextArea::~DiTextArea() { +} + +void DiTextArea::delete_instructions() { + DiTileArray::delete_instructions(); + auto cursor = get_first_child(); + if (cursor) { + cursor->delete_instructions(); + } +} + +void DiTextArea::generate_instructions() { + delete_instructions(); + DiTileArray::generate_instructions(); + auto cursor = get_first_child(); + if (cursor) { + cursor->generate_instructions(); + } +} + +void DiTextArea::define_character_range(uint8_t first_char, uint8_t last_char, + uint8_t fg_color, uint8_t bg_color) { + auto ch = (uint16_t) first_char; + auto last = (uint16_t) last_char; + while (ch <= last) { + define_character((uint8_t)ch++, fg_color, bg_color); + } +} + +DiTileBitmapID DiTextArea::get_bitmap_id(uint8_t character) { + return ((DiTileBitmapID)character) | ((DiTileBitmapID)m_bg_color << 24) | ((DiTileBitmapID)m_fg_color << 16); +} + +DiTileBitmapID DiTextArea::get_bitmap_id(uint8_t character, uint8_t fg_color, uint8_t bg_color) { + return ((DiTileBitmapID)character) | ((DiTileBitmapID)bg_color << 24) | ((DiTileBitmapID)fg_color << 16); +} + +DiTileBitmapID DiTextArea::define_character(uint8_t character, uint8_t fg_color, uint8_t bg_color) { + auto bm_id = get_bitmap_id(character, fg_color, bg_color); + if (m_id_to_bitmap_map.find(bm_id) == m_id_to_bitmap_map.end()) { + auto bitmap = create_bitmap(bm_id, false); + uint32_t char_start = (uint32_t)character * 8; + for (uint y = 0; y < 8; y++) { + uint8_t pixels = m_font[char_start+y]; + for (uint x = 0; x < 8; x++) { + if (pixels & 0x80) { + set_pixel(bm_id, x, y, fg_color); + } else { + set_pixel(bm_id, x, y, bg_color); + } + pixels <<= 1; + } + } + bitmap->compute_absolute_geometry(); + bitmap->generate_instructions(); + } + return bm_id; +} + +void DiTextArea::set_character_position(int32_t column, int32_t row) { + m_current_column = column; + m_current_row = row; +} + +void DiTextArea::bring_current_position_into_view() { + if (m_current_column < 0) { + // scroll text to the right (insert on the left) + int32_t move = m_columns + m_current_column; + int32_t open = -m_current_column; + move_text(0, 0, move, m_rows, open, 0); + erase_text(0, 0, open, m_rows); + m_current_column = 0; + } + if (m_current_column >= m_columns) { + // scroll text to the left (insert on the right) + int32_t open = m_current_column - m_columns + 1; + int32_t move = m_columns - open; + move_text(open, 0, move, m_rows, 0, 0); + erase_text(move, 0, open, m_rows); + m_current_column = m_columns - 1; + } + if (m_current_row < 0) { + // scroll text down (insert at the top) + int32_t move = m_rows + m_current_row; + int32_t open = -m_current_row; + move_text(0, 0, m_columns, move, 0, open); + erase_text(0, 0, m_columns, open); + m_current_row = 0; + } + if (m_current_row >= m_rows) { + // scroll text up (insert at the bottom) + int32_t open = m_current_row - m_rows + 1; + int32_t move = m_rows - open; + move_text(0, open, m_columns, move, 0, -open); + erase_text(0, move, m_columns, open); + m_current_row = m_rows - 1; + } +} + +void DiTextArea::write_character(uint8_t character) { + bring_current_position_into_view(); + + // Set the tile image ID using the character code. + set_character(m_current_column, m_current_row, character); + + // Advance the current position + if (++m_current_column >= m_columns) { + m_current_column = 0; + m_current_row++; + } +} + +void DiTextArea::set_character(int32_t column, int32_t row, uint8_t character) { + auto bm_id = define_character(character, m_fg_color, m_bg_color); + set_tile(column, row, bm_id); +} + +DiTileBitmapID DiTextArea::read_character() { + return read_character(m_current_column, m_current_row); +} + +DiTileBitmapID DiTextArea::read_character(int32_t column, int32_t row) { + return get_tile(column, row); +} + +void DiTextArea::erase_text(int32_t column, int32_t row, int32_t columns, int32_t rows) { + while (rows-- > 0) { + int32_t col = column; + auto bm_id = get_bitmap_id(0x20); + for (int32_t c = 0; c < columns; c++) { + set_character(col++, row, bm_id); + } + row++; + } +} + +void DiTextArea::move_text(int32_t column, int32_t row, int32_t columns, int32_t rows, + int32_t delta_horiz, int32_t delta_vert) { + if (delta_vert > 0) { + // moving rows down; copy bottom-up + row += rows - 1; + while (rows-- > 0) { + auto col = column; + auto n = columns; + while (n-- > 0) { + auto bm_id = get_tile(col, row); + set_tile(col++, row + delta_vert, bm_id); + } + row--; + } + } else { + // moving rows up; copy top-down + while (rows-- > 0) { + auto col = column; + auto n = columns; + while (n-- > 0) { + auto bm_id = get_tile(col, row); + set_tile(col++, row + delta_vert, bm_id); + } + row++; + } + } +} + +void DiTextArea::clear_screen() { + erase_text(0, 0, m_columns, m_rows); + m_current_column = 0; + m_current_row = 0; +} + +void DiTextArea::move_cursor_left() { + bring_current_position_into_view(); + if (m_current_column > 0) { + m_current_column--; + } else if (m_current_row > 0) { + m_current_row--; + m_current_column = m_columns - 1; + } +} + +void DiTextArea::move_cursor_right() { + bring_current_position_into_view(); + if (m_current_column < m_columns - 1) { + m_current_column++; + } else if (m_current_row < m_rows - 1) { + m_current_row++; + m_current_column = 0; + } +} + +void DiTextArea::move_cursor_down() { + bring_current_position_into_view(); + m_current_row++; +} + +void DiTextArea::move_cursor_up() { + bring_current_position_into_view(); + if (m_current_row > 0) { + m_current_row--; + } +} + +void DiTextArea::move_cursor_home() { + bring_current_position_into_view(); + m_current_row = 0; + m_current_column = 0; +} + +void DiTextArea::move_cursor_boln() { + bring_current_position_into_view(); + m_current_column = 0; +} + +void DiTextArea::do_backspace() { + bring_current_position_into_view(); + if (m_current_column > 0) { + m_current_column--; + auto bm_id = get_bitmap_id(0x20); + set_character(m_current_column, m_current_row, bm_id); + } else if (m_current_row > 0) { + m_current_row--; + m_current_column = m_columns - 1; + auto bm_id = get_bitmap_id(0x20); + set_character(m_current_column, m_current_row, bm_id); + } +} + +void DiTextArea::move_cursor_tab(uint8_t x, uint8_t y) { + set_character_position(x, y); +} + +void DiTextArea::get_position(uint16_t& column, uint16_t& row) { + column = m_current_column; + row = m_current_row; +} + +void DiTextArea::set_foreground_color(uint8_t color) { + m_fg_color = color; +} + +void DiTextArea::set_background_color(uint8_t color) { + m_bg_color = color; +} diff --git a/video/src/di_text_area.h b/video/src/di_text_area.h new file mode 100644 index 00000000..3cd92af2 --- /dev/null +++ b/video/src/di_text_area.h @@ -0,0 +1,126 @@ +// di_text_area.h - Function declarations for supporting a character text_area display +// +// A text_area is a specialized tile array, where each tile is a single character +// cell, and the character codes are used as tile image IDs. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_tile_array.h" + +class DiTextArea: public DiTileArray { + public: + + // Construct a text_area. The text_area always shows characters that are 8x8 + // pixels, based on the built-in Agon font. + // + // The given x coordinate must be a multiple of 4, to align the text_area on + // a 4-byte boundary, which saves memory and processing time. + // + DiTextArea(uint32_t x, uint32_t y, uint8_t flags, uint32_t columns, uint32_t rows, const uint8_t* font); + + // Destroy a text_area, including its allocated data. + virtual ~DiTextArea(); + + // Clear the custom instructions needed to draw the primitive. + virtual void delete_instructions(); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + // Define a range of characters using given colors and 8x8 font. + void define_character_range(uint8_t first_char, uint8_t last_char, + uint8_t fg_color, uint8_t bg_color); + + // Define an individual character using given colors and 8x8 font. + DiTileBitmapID define_character(uint8_t character, uint8_t fg_color, uint8_t bg_color); + + // Set the current character position. The position given may be within the text_area + // display, or may be outside of it. If it is within the display, then the next + // character written by write_character(ch) will appear at the given position. If the + // position is outside of the display, then writing the next character will cause the + // text_area display to scroll far enough to bring the current character position into + // view, and the current position will be updated accordingly. + void set_character_position(int32_t column, int32_t row); + + // Write a character at the current character position. This may cause scrolling + // BEFORE writing the character (not after), if the current character position is + // off the visible text_area area. This function will advance the current character + // position. The character is treated as part of a tile image ID, and is not + // interpreted as a text_area command of any kind. + void write_character(uint8_t character); + + // Set the image ID to use to draw a character at a specific row and column. + // This function does not cause scrolling, nor does it change the current + // character position. The character is treated as part of a tile image ID, + // and is not interpreted as a text_area command of any kind. + void set_character(int32_t column, int32_t row, uint8_t character); + + // Read the character code at the current character position. If the current position + // is outside of the text_area display, this function returns zero. + DiTileBitmapID read_character(); + + // Read the character code at the given character position. + DiTileBitmapID read_character(int32_t column, int32_t row); + + // Erase an area of text within the text_area display. + void erase_text(int32_t column, int32_t row, int32_t columns, int32_t rows); + + // Move an area of text within the text_area display. This may be used to scroll + // text at the character level (not at the pixel level). + void move_text(int32_t column, int32_t row, int32_t columns, int32_t rows, + int32_t delta_horiz, int32_t delta_vert); + + // Set the foreground color. + void set_foreground_color(uint8_t color); + + // Set the background color. + void set_background_color(uint8_t color); + + void clear_screen(); + void move_cursor_left(); + void move_cursor_right(); + void move_cursor_down(); + void move_cursor_up(); + void move_cursor_home(); + void move_cursor_boln(); + void move_cursor_tab(uint8_t column, uint8_t row); + void do_backspace(); + void get_position(uint16_t& column, uint16_t& row); + + // Bring a potentially off-screen position into view. + void bring_current_position_into_view(); + + protected: + // Get the bitmap ID for a character, based on current colors. + DiTileBitmapID get_bitmap_id(uint8_t character); + + // Get the bitmap ID for a character, based on given colors. + DiTileBitmapID get_bitmap_id(uint8_t character, uint8_t fg_color, uint8_t bg_color); + + int32_t m_current_column; + int32_t m_current_row; + uint8_t m_fg_color; + uint8_t m_bg_color; + const uint8_t* m_font; +}; + diff --git a/video/src/di_tile_array.cpp b/video/src/di_tile_array.cpp new file mode 100644 index 00000000..3614bc28 --- /dev/null +++ b/video/src/di_tile_array.cpp @@ -0,0 +1,256 @@ +// di_tile_array.cpp - Function definitions for drawing tile arrays +// +// A tile array is a set of rectangular tiles, where each tile is a bitmap of +// the same size (width and height). Tiles are arranged in a rectangular +// grid, where the entire portion of the grid that fits within the visible +// area of the screen may be displayed at any given moment. In other words +// multiple tiles show at the same time. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_tile_array.h" +#include + +DiTileArray::DiTileArray(uint32_t screen_width, uint32_t screen_height, + uint32_t columns, uint32_t rows, + uint32_t tile_width, uint32_t tile_height, uint16_t flags) : DiPrimitive(flags) { + m_flags |= PRIM_FLAGS_X_SRC; + m_tile_width = tile_width; + m_tile_height = tile_height; + m_rows = rows; + m_columns = columns; + uint32_t draw_words_per_line = (tile_width + sizeof(uint32_t) - 1) / sizeof(uint32_t); + uint32_t words_per_line = draw_words_per_line; + + if (flags & PRIM_FLAG_H_SCROLL_1) { + draw_words_per_line += 2; + } + + m_bytes_per_line = words_per_line * sizeof(uint32_t); + uint32_t words_per_position = words_per_line * tile_height; + m_bytes_per_position = words_per_position * sizeof(uint32_t); + + m_visible_columns = (screen_width + tile_width - 1) / tile_width; + if (m_visible_columns > columns) { + m_visible_columns = columns; + } + + m_visible_rows = (screen_height + tile_height - 1) / tile_height; + if (m_visible_rows > rows) { + m_visible_rows = rows; + } + + m_width = tile_width * columns; + m_height = tile_height * rows; + + m_tile_bitmaps.resize(rows * columns); +} + +DiTileArray::~DiTileArray() { + for (auto bitmap_item = m_id_to_bitmap_map.begin(); bitmap_item != m_id_to_bitmap_map.end(); bitmap_item++) { + delete bitmap_item->second; + } +} + +void DiTileArray::generate_instructions() { + for (auto bitmap_item = m_id_to_bitmap_map.begin(); bitmap_item != m_id_to_bitmap_map.end(); bitmap_item++) { + auto bitmap = bitmap_item->second; + bitmap->compute_absolute_geometry(); + bitmap->generate_instructions(); + } + compute_paint_parameters(); +} + +DiBitmap* DiTileArray::create_bitmap(DiTileBitmapID bm_id, bool psram) { + auto bitmap_item = m_id_to_bitmap_map.find(bm_id); + if (bitmap_item == m_id_to_bitmap_map.end()) { + auto bitmap = new DiBitmap(m_tile_width, m_tile_height, m_flags, psram); + bitmap->set_custom(bm_id); + m_id_to_bitmap_map[bm_id] = bitmap; + return bitmap; + } else { + return bitmap_item->second; + } +} + +DiBitmap* DiTileArray::get_bitmap(DiTileBitmapID bm_id) { + return m_id_to_bitmap_map[bm_id]; +} + +void DiTileArray::set_pixel(DiTileBitmapID bm_id, uint32_t x, uint32_t y, uint8_t color) { + m_id_to_bitmap_map[bm_id]->set_transparent_pixel(x, y, color); +} +extern void debug_log(const char* f,...); +void DiTileArray::set_tile(int16_t column, int16_t row, DiTileBitmapID bm_id) { + if (column >= 0 && column < m_columns && row >= 0 && row < m_rows) { + auto bitmap_item = m_id_to_bitmap_map.find(bm_id); + if (bitmap_item != m_id_to_bitmap_map.end()) { + auto index = row * m_columns + column; + auto bitmap = bitmap_item->second; + m_tile_bitmaps[index] = bitmap; + } + } +} + +void DiTileArray::set_tiles(int16_t column, int16_t row, DiTileBitmapID bm_id, + int16_t columns, int16_t rows) { + while (rows-- > 0) { + auto cols = columns; + auto col = column; + while (cols-- > 0) { + set_tile(col++, row, bm_id); + } + row++; + } +} + +void DiTileArray::unset_tiles(int16_t column, int16_t row, int16_t columns, int16_t rows) { + while (rows-- > 0) { + auto cols = columns; + auto col = column; + while (cols-- > 0) { + unset_tile(col++, row); + } + row++; + } +} + +void DiTileArray::unset_tile(int16_t column, int16_t row) { + auto index = row * m_columns + column; + m_tile_bitmaps[index] = NULL; +} + +DiTileBitmapID DiTileArray::get_tile(int16_t column, int16_t row) { + auto index = row * m_columns + column; + auto bitmap = m_tile_bitmaps[index]; + if (bitmap) { + return bitmap->get_custom(); + } + return (DiTileBitmapID)0; +} + +void DiTileArray::get_rel_tile_coordinates(int16_t column, int16_t row, + int16_t& x, int16_t& y, int16_t& x_extent, int16_t& y_extent) { + x = column * m_tile_width; + x_extent = x + m_tile_width; + y = row * m_tile_height; + y_extent = y + m_tile_height; +} + +void DiTileArray::get_abs_tile_coordinates(int16_t column, int16_t row, + int16_t& x, int16_t& y, int16_t& x_extent, int16_t& y_extent) { + x = column * m_tile_width + m_abs_x; + x_extent = x + m_tile_width; + y = row * m_tile_height + m_abs_y; + y_extent = y + m_tile_height; +} + +void IRAM_ATTR DiTileArray::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { + /* FROM PRIMITIVE: + uint32_t hidden_left = 0; + uint32_t hidden_right = 0; + if (m_abs_x < m_draw_x) { + hidden_left = m_draw_x - m_abs_x; + } else if (m_draw_x_extent < m_x_extent) { + hidden_right = m_x_extent - m_draw_x_extent; + } + return get_paint_pointer(width, height, hidden_left, hidden_right); + */ + /* + p_scan_line += m_abs_x / 4; + auto y_offset_within_tile_array = (int32_t)line_index - m_abs_y; + auto y_offset_within_tile = y_offset_within_tile_array % (int32_t)m_tile_height; + auto row = y_offset_within_tile_array / (int32_t)m_tile_height; + auto src_pixels_offset = y_offset_within_tile * m_bytes_per_line; + auto row_array = (uint32_t)(m_tile_pixels + row * m_columns); + m_paint_code.call_a5_a6(this, p_scan_line, y_offset_within_tile, row_array, src_pixels_offset); + */ + + p_scan_line += m_abs_x / 4; + auto y_offset_within_tile_array = (int32_t)line_index - m_abs_y; + auto y_offset_within_tile = y_offset_within_tile_array % (int32_t)m_tile_height; + auto row = y_offset_within_tile_array / (int32_t)m_tile_height; + auto src_pixels_offset = y_offset_within_tile * m_bytes_per_line; + auto index = row * m_columns + 0; + for (int i = 0; i < m_visible_columns-1; i++) { + auto bitmap = m_tile_bitmaps[index]; + if (bitmap) { + // debug_log("paint %u %u %u %u\n",m_id,bitmap->get_custom(),index,y_offset_within_tile); + bitmap->paint(p_scan_line, y_offset_within_tile); + p_scan_line += m_tile_width / 4; + } + } +} + +void DiTileArray::compute_paint_parameters() { + m_left_tile_count = 0; + m_left_src_pixel_offset = 0; + m_left_paint_fcn_index = 0; + m_mid_tile_count = 0; + m_mid_src_pixel_offset = 0; + m_mid_paint_fcn_index = 0; + m_right_tile_count = 0; + m_right_src_pixel_offset = 0; + m_right_paint_fcn_index = 0; + m_dst_x_offset = m_abs_x & 3; + m_dst_pixel_offset = 0; + + debug_log("cpp id %hu ax %i axe %i dx %i dxe %i dw %i\n",m_id,m_abs_x,m_abs_x+m_width,m_draw_x,m_draw_x_extent,m_draw_x_extent-m_draw_x); + + if (m_tile_bitmaps.size()) { + auto bitmap = *m_tile_bitmaps.begin(); + + uint32_t hidden_left = 0; + uint32_t hidden_right = 0; + auto draw_width = m_draw_x_extent - m_draw_x; + debug_log(" dw %i\n", draw_width); + + if (m_abs_x < m_draw_x) { + hidden_left = (m_draw_x - m_abs_x) % m_tile_width; + } + + if (m_draw_x_extent < m_x_extent) { + hidden_right = (m_x_extent - m_draw_x_extent) % m_tile_width; + } + + if (hidden_left) { + draw_width -= hidden_left; + m_left_tile_count = 1; + m_left_paint_fcn_index = bitmap->get_paint_fcn_index(m_tile_width, m_tile_height, hidden_left, 0); + debug_log(" dw %i ltc %u lpfi %u\n", draw_width, m_left_tile_count, m_left_paint_fcn_index); + } + + if (hidden_right) { + draw_width -= hidden_right; + m_right_tile_count = 1; + m_right_paint_fcn_index = bitmap->get_paint_fcn_index(m_tile_width, m_tile_height, 0, hidden_right); + debug_log(" dw %i rtc %u rpfi %u\n", draw_width, m_right_tile_count, m_right_paint_fcn_index); + } + + if (draw_width) { + m_mid_tile_count = draw_width % m_tile_width; + m_mid_paint_fcn_index = bitmap->get_paint_fcn_index(m_tile_width, m_tile_height, 0, 0); + debug_log(" mtc %u mpfi %u\n", m_mid_tile_count, m_mid_paint_fcn_index); + } + } + debug_log(" --\n"); +} \ No newline at end of file diff --git a/video/src/di_tile_array.h b/video/src/di_tile_array.h new file mode 100644 index 00000000..a9178dd0 --- /dev/null +++ b/video/src/di_tile_array.h @@ -0,0 +1,125 @@ +// di_tile_array.h - Function declarations for drawing tile arrays +// +// A tile array is a set of rectangular tiles, where each tile is a bitmap of +// the same size (width and height). Tiles are arranged in a rectangular +// grid, where the entire portion of the grid that fits within the visible +// area of the screen may be displayed at any given moment. In other words +// multiple tiles show at the same time. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" +#include "di_code.h" +#include "di_bitmap.h" +#include + +typedef uint32_t DiRowColumn; + +#ifndef _DiTileBitmapID +#define _DiTileBitmapID +typedef uint32_t DiTileBitmapID; +typedef std::map DiTileIdToBitmapMap; +#endif + +class DiTileArray: public DiPrimitive { + public: + // Construct a tile array. + DiTileArray(uint32_t screen_width, uint32_t screen_height, + uint32_t columns, uint32_t rows, + uint32_t tile_width, uint32_t tile_height, uint16_t flags); + + // Destroy a tile array. + virtual ~DiTileArray(); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + // Create the array of pixels for the tile bitmap. + DiBitmap* create_bitmap(DiTileBitmapID bm_id, bool psram); + + // Get a pointer to a tile bitmap. + DiBitmap* get_bitmap(DiTileBitmapID bm_id); + + // Save the pixel value of a particular pixel in a specific tile bitmap. A tile bitmap + // may appear many times on the screen, based on the use of the bitmap ID. + void set_pixel(DiTileBitmapID bm_id, uint32_t x, uint32_t y, uint8_t color); + + // Set the bitmap ID to use to draw a tile at a specific row and column. + void set_tile(int16_t column, int16_t row, DiTileBitmapID bm_id); + + // Unset the bitmap ID at a specific row and column, to remove the tile. + void unset_tile(int16_t column, int16_t row); + + // Set the bitmap ID to use to fill a rectangle of tiles. + void set_tiles(int16_t column, int16_t row, DiTileBitmapID bm_id, int16_t columns, int16_t rows); + + // Unset the bitmap IDs to remove a rectangle of tiles. + void unset_tiles(int16_t column, int16_t row, int16_t columns, int16_t rows); + + // Get the bitmap ID presently at the given row and column. + DiTileBitmapID get_tile(int16_t column, int16_t row); + + // Get the relative coordinates of a specific tile position. + void get_rel_tile_coordinates(int16_t column, int16_t row, + int16_t& x, int16_t& y, int16_t& x_extent, int16_t& y_extent); + + // Get the absolute coordinates of a specific tile position. + void get_abs_tile_coordinates(int16_t column, int16_t row, + int16_t& x, int16_t& y, int16_t& x_extent, int16_t& y_extent); + + virtual void IRAM_ATTR paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + // Get the tile width. + inline uint32_t get_tile_width() { return m_tile_width; } + + // Get the tile height. + inline uint32_t get_tile_height() { return m_tile_height; } + + protected: + uint32_t m_columns; // number of columns (cells in each row) + uint32_t m_rows; // number of rows (cells in each column) + uint32_t m_bytes_per_line; // number of 1-pixel bytes in each bitmap line + uint32_t m_bytes_per_position; // number of 1-pixel bytes in each bitmap position + uint32_t m_visible_columns; // number of columns that fit on the screen + uint32_t m_visible_rows; // number of rows that fit on the screen + uint32_t m_tile_width; // width of 1 tile in pixels + uint32_t m_tile_height; // height of 1 tile in pixels + uint8_t m_transparent_color; // value indicating not to draw the pixel + DiTileIdToBitmapMap m_id_to_bitmap_map; // caches bitmaps based on bitmap ID + std::vector m_tile_bitmaps; // 2D array of pointers to bitmaps + + uint32_t m_left_tile_count; // How many tiles to paint on the left edge + uint32_t m_left_src_pixel_offset; // Source pixel offset for painting on the left edge + uint32_t m_left_paint_fcn_index; // Paint function index for painting on the left edge + uint32_t m_mid_tile_count; // How many tiles to paint in the middle + uint32_t m_mid_src_pixel_offset; // Source pixel offset for painting in the middle + uint32_t m_mid_paint_fcn_index; // Paint function index for painting in the middle + uint32_t m_right_tile_count; // How many tiles to paint on the right edge + uint32_t m_right_src_pixel_offset; // Source pixel offset for painting on the right edge + uint32_t m_right_paint_fcn_index; // Paint function index for painting on the right edge + uint32_t m_dst_x_offset; // Destination X offset (0..3) + uint32_t m_dst_pixel_offset; // Destination pixel (byte) offset + + // Determine how to paint, based on current X position + void compute_paint_parameters(); +}; diff --git a/video/src/di_tile_map.cpp b/video/src/di_tile_map.cpp new file mode 100644 index 00000000..87650c20 --- /dev/null +++ b/video/src/di_tile_map.cpp @@ -0,0 +1,175 @@ +// di_tile_map.cpp - Function definitions for drawing tile maps +// +// A tile map is a set of rectangular tiles, where each tile is a bitmap of +// the same size (width and height). Tiles are arranged in a rectangular +// grid, where the entire portion of the grid that fits within the visible +// area of the screen may be displayed at any given moment. In other words +// multiple tiles show at the same time. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_tile_map.h" +#include + +DiTileMap::DiTileMap(uint32_t screen_width, uint32_t screen_height, + uint32_t columns, uint32_t rows, + uint32_t tile_width, uint32_t tile_height, uint16_t flags) : DiPrimitive(flags) { + m_flags |= PRIM_FLAGS_X_SRC; + m_tile_width = tile_width; + m_tile_height = tile_height; + m_rows = rows; + m_columns = columns; + uint32_t draw_words_per_line = (tile_width + sizeof(uint32_t) - 1) / sizeof(uint32_t); + uint32_t words_per_line = draw_words_per_line; + + if (flags & PRIM_FLAG_H_SCROLL_1) { + draw_words_per_line += 2; + } + + m_bytes_per_line = words_per_line * sizeof(uint32_t); + uint32_t words_per_position = words_per_line * tile_height; + m_bytes_per_position = words_per_position * sizeof(uint32_t); + + m_visible_columns = (screen_width + tile_width - 1) / tile_width; + if (m_visible_columns > columns) { + m_visible_columns = columns; + } + + m_visible_rows = (screen_height + tile_height - 1) / tile_height; + if (m_visible_rows > rows) { + m_visible_rows = rows; + } + + m_width = tile_width * columns; + m_height = tile_height * rows; +} + +DiTileMap::~DiTileMap() { + for (auto bitmap_item = m_id_to_bitmap_map.begin(); bitmap_item != m_id_to_bitmap_map.end(); bitmap_item++) { + delete bitmap_item->second; + } + for (auto map = m_row_to_col_map.begin(); map != m_row_to_col_map.end(); map++) { + delete map->second; + } +} + +void DiTileMap::delete_instructions() { + for (auto bitmap = m_id_to_bitmap_map.begin(); bitmap != m_id_to_bitmap_map.end(); bitmap++) { + bitmap->second->delete_instructions(); + } +} + +void DiTileMap::generate_instructions() { + //for (auto bitmap = m_id_to_bitmap_map.begin(); bitmap != m_id_to_bitmap_map.end(); bitmap++) { + // bitmap->second->generate_instructions(m_draw_x, 0, m_tile_width); + // bitmap_item->second->setup_alpha_bits(); + //} +} + +DiBitmap* DiTileMap::create_bitmap(DiTileBitmapID bm_id, bool psram) { + auto bitmap_item = m_id_to_bitmap_map.find(bm_id); + if (bitmap_item == m_id_to_bitmap_map.end()) { + auto bitmap = new DiBitmap(m_tile_width, m_tile_height, m_flags, psram); + bitmap->set_custom(bm_id); + m_id_to_bitmap_map[bm_id] = bitmap; + return bitmap; + } else { + return bitmap_item->second; + } +} + +DiBitmap* DiTileMap::get_bitmap(DiTileBitmapID bm_id) { + return m_id_to_bitmap_map[bm_id]; +} + +void DiTileMap::set_pixel(DiTileBitmapID bm_id, uint32_t x, uint32_t y, uint8_t color) { + m_id_to_bitmap_map[bm_id]->set_transparent_pixel(x, y, color); +} + +void DiTileMap::set_tile(int16_t column, int16_t row, DiTileBitmapID bm_id) { + auto bitmap_item = m_id_to_bitmap_map.find(bm_id); + if (bitmap_item != m_id_to_bitmap_map.end()) { + auto row_item = m_row_to_col_map.find(row); + if (row_item != m_row_to_col_map.end()) { + auto cb_map = row_item->second; + (*cb_map)[column] = bitmap_item->second; + } else { + auto cb_map = new DiTileColumnToBitmapMap(); + m_row_to_col_map[row] = cb_map; + (*cb_map)[column] = bitmap_item->second; + } + } +} + +void DiTileMap::unset_tile(int16_t column, int16_t row) { + auto row_item = m_row_to_col_map.find(row); + if (row_item != m_row_to_col_map.end()) { + auto cb_map = row_item->second; + auto bitmap_item = cb_map->find(column); + if (bitmap_item != cb_map->end()) { + cb_map->erase(bitmap_item); + if (!cb_map->size()) { + delete cb_map; + m_row_to_col_map.erase(row_item); + } + } + } +} + +DiTileBitmapID DiTileMap::get_tile(int16_t column, int16_t row) { + auto row_item = m_row_to_col_map.find(row); + if (row_item != m_row_to_col_map.end()) { + auto cb_map = row_item->second; + auto bitmap_item = cb_map->find(column); + if (bitmap_item != cb_map->end()) { + return bitmap_item->second->get_custom(); + } + } + return 0; +} + +void IRAM_ATTR DiTileMap::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { + auto y_offset_within_tile_map = (int32_t)line_index - m_abs_y; + if (y_offset_within_tile_map >= 0 && y_offset_within_tile_map < m_height) { + auto row = y_offset_within_tile_map / (int32_t)m_tile_height; + auto row_item = m_row_to_col_map.find((uint16_t)row); + if (row_item != m_row_to_col_map.end()) { + auto cb_map = row_item->second; + auto start_x_offset_within_tile_map = m_draw_x - m_abs_x; + auto start_column = (start_x_offset_within_tile_map + m_tile_width - 1) / m_tile_width; + auto end_x_offset_within_tile_map = m_draw_x_extent - m_abs_x; + auto end_column = end_x_offset_within_tile_map / m_tile_width; + auto fcn_index = m_draw_x & 0x3; + uint32_t draw_x = m_draw_x & 0xFFFFFFFC; + auto y_offset_within_tile = y_offset_within_tile_map % (int32_t)m_tile_height; + auto src_pixels_offset = fcn_index * m_bytes_per_position + y_offset_within_tile * m_bytes_per_line; + for (auto column = start_column; column < end_column; column++) { + auto bitmap_item = cb_map->find(column); + if (bitmap_item != cb_map->end()) { + auto bitmap = bitmap_item->second; + //bitmap->paint(this, fcn_index, p_scan_line, y_offset_within_tile, draw_x, src_pixels_offset); + } + draw_x += m_tile_width; + } + } + } +} diff --git a/video/src/di_tile_map.h b/video/src/di_tile_map.h new file mode 100644 index 00000000..8bd5e28f --- /dev/null +++ b/video/src/di_tile_map.h @@ -0,0 +1,96 @@ +// di_tile_map.h - Function declarations for drawing tile maps +// +// A tile map is a set of rectangular tiles, where each tile is a bitmap of +// the same size (width and height). Tiles are arranged in a rectangular +// grid, where the entire portion of the grid that fits within the visible +// area of the screen may be displayed at any given moment. In other words +// multiple tiles show at the same time. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" +#include "di_code.h" +#include "di_tile_array.h" +#include + +typedef uint32_t DiRowColumn; + +typedef std::map DiTileColumnToBitmapMap; +typedef std::map DiTileRowToColumnMap; + +class DiTileMap: public DiPrimitive { + public: + // Construct a tile map. + DiTileMap(uint32_t screen_width, uint32_t screen_height, + uint32_t columns, uint32_t rows, + uint32_t tile_width, uint32_t tile_height, uint16_t flags); + + // Destroy a tile map. + virtual ~DiTileMap(); + + // Clear the custom instructions needed to draw the primitive. + virtual void delete_instructions(); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + // Create the array of pixels for the tile bitmap. + DiBitmap* create_bitmap(DiTileBitmapID bm_id, bool psram); + + // Get a pointer to a tile bitmap. + DiBitmap* get_bitmap(DiTileBitmapID bm_id); + + // Save the pixel value of a particular pixel in a specific tile bitmap. A tile bitmap + // may appear many times on the screen, based on the use of the bitmap ID. + void set_pixel(DiTileBitmapID bm_id, uint32_t x, uint32_t y, uint8_t color); + + // Set the bitmap ID to use to draw a tile at a specific row and column. + void set_tile(int16_t column, int16_t row, DiTileBitmapID bm_id); + + // Unset the bitmap ID to use to draw a tile at a specific row and column. + void unset_tile(int16_t column, int16_t row); + + // Get the bitmap ID presently at the given row and column. + DiTileBitmapID get_tile(int16_t column, int16_t row); + + virtual void IRAM_ATTR paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + // Get the tile width. + inline uint32_t get_tile_width() { return m_tile_width; } + + // Get the tile height. + inline uint32_t get_tile_height() { return m_tile_height; } + + protected: + uint32_t m_columns; // number of columns (cells in each row) + uint32_t m_rows; // number of rows (cells in each column) + uint32_t m_bytes_per_line; // number of 1-pixel bytes in each bitmap line + uint32_t m_bytes_per_position; // number of 1-pixel bytes in each bitmap position + uint32_t m_visible_columns; // number of columns that fit on the screen + uint32_t m_visible_rows; // number of rows that fit on the screen + uint32_t m_tile_width; // width of 1 tile in pixels + uint32_t m_tile_height; // height of 1 tile in pixels + uint8_t m_transparent_color; // value indicating not to draw the pixel + DiTileIdToBitmapMap m_id_to_bitmap_map; // caches bitmaps based on bitmap ID + DiTileRowToColumnMap m_row_to_col_map; // refers to bitmaps based on row & column +}; diff --git a/video/src/di_timing.cpp b/video/src/di_timing.cpp new file mode 100644 index 00000000..8c46e128 --- /dev/null +++ b/video/src/di_timing.cpp @@ -0,0 +1,51 @@ +// di_timing.cpp - Video timing data structures. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_timing.h" +//extern void debug_log(const char* fmt, ...); + +OtfVideoParams otf_video_params; + +/* +void OtfVideoParams::dump() { + debug_log("m_active_lines: %u\n", m_active_lines); + debug_log("m_vfp_lines: %u\n", m_vfp_lines); + debug_log("m_vs_lines: %u\n", m_vs_lines); + debug_log("m_vbp_lines: %u\n", m_vbp_lines); + debug_log("m_hfp_pixels: %u\n", m_hfp_pixels); + debug_log("m_hs_pixels: %u\n", m_hs_pixels); + debug_log("m_active_pixels: %u\n", m_active_pixels); + debug_log("m_hbp_pixels: %u\n", m_hbp_pixels); + debug_log("m_dma_clock_freq: %u\n", m_dma_clock_freq); + debug_log("m_dma_total_lines: %u\n", m_dma_total_lines); + debug_log("m_dma_total_descr: %u\n", m_dma_total_descr); + debug_log("m_hs_on: %X\n", m_hs_on); + debug_log("m_hs_off: %X\n", m_hs_off); + debug_log("m_vs_on: %X\n", m_vs_on); + debug_log("m_vs_off: %X\n", m_vs_off); + debug_log("m_syncs_on: %X\n", m_syncs_on); + debug_log("m_syncs_off: %X\n", m_syncs_off); + debug_log("m_syncs_off_x4: %X\n", m_syncs_off_x4); + debug_log("m_scan_count: %u\n", m_scan_count); +} +*/ \ No newline at end of file diff --git a/video/src/di_timing.h b/video/src/di_timing.h new file mode 100644 index 00000000..ffc227d7 --- /dev/null +++ b/video/src/di_timing.h @@ -0,0 +1,54 @@ +// di_timing.h - Video timing constant data structures. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once + +#include "di_constants.h" +#include + +typedef struct { + const char* m_mode_line; + uint32_t m_active_lines; + uint32_t m_vfp_lines; + uint32_t m_vs_lines; + uint32_t m_vbp_lines; + uint32_t m_hfp_pixels; + uint32_t m_hs_pixels; + uint32_t m_active_pixels; + uint32_t m_hbp_pixels; + uint32_t m_dma_clock_freq; + uint32_t m_dma_total_lines; + uint32_t m_dma_total_descr; + uint32_t m_hs_on; + uint32_t m_hs_off; + uint32_t m_vs_on; + uint32_t m_vs_off; + uint32_t m_syncs_on; + uint32_t m_syncs_off; + uint32_t m_syncs_off_x4; + uint32_t m_scan_count; + + //void dump(); +} OtfVideoParams; + +extern OtfVideoParams otf_video_params; diff --git a/video/src/di_vert_line.cpp b/video/src/di_vert_line.cpp new file mode 100644 index 00000000..2891f9bc --- /dev/null +++ b/video/src/di_vert_line.cpp @@ -0,0 +1,56 @@ +// di_vert_line.cpp - Function definitions for drawing vertical lines +// +// A vertical line is 1 pixel wide and N pixels high. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include "di_vert_line.h" +#include "di_timing.h" + +DiVerticalLine::DiVerticalLine(uint16_t flags) : DiPrimitive(flags) { + m_flags |= PRIM_FLAGS_X; +} + +void DiVerticalLine::make_line(int32_t x, int32_t y, uint32_t height, uint8_t color) { + m_opaqueness = DiPrimitive::normal_alpha_to_opaqueness(color); + m_rel_x = x; + m_rel_y = y; + m_width = 1; + m_height = height; + m_color = PIXEL_COLOR_X4(color) | otf_video_params.m_syncs_off_x4; + m_paint_code.enter_and_leave_outer_function(); +} + +void DiVerticalLine::generate_instructions() { + delete_instructions(); + EspFixups fixups; + uint16_t width = 1; + DiLineSections sections; + sections.add_piece(1, 0, 1, false); + auto x_offset = m_abs_x & 3; + m_paint_code.draw_line(fixups, x_offset, 0, width, §ions, m_flags, m_opaqueness, true); + m_paint_code.do_fixups(fixups); +} + +void IRAM_ATTR DiVerticalLine::paint(volatile uint32_t* p_scan_line, uint32_t line_index) { + m_paint_code.call(this, p_scan_line, line_index); +} diff --git a/video/src/di_vert_line.h b/video/src/di_vert_line.h new file mode 100644 index 00000000..76dd1adc --- /dev/null +++ b/video/src/di_vert_line.h @@ -0,0 +1,45 @@ +// di_vert_line.h - Function declarations for drawing vertical lines +// +// A vertical line is 1 pixel wide and N pixels high. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_primitive.h" +#include "di_code.h" + +class DiVerticalLine: public DiPrimitive { + public: + // Construct a vertical line. This requires calling init_params() afterward. + DiVerticalLine(uint16_t flags); + + // The line is vertical, covering the given number of pixels. + void make_line(int32_t x, int32_t y, uint32_t height, uint8_t color); + + // Reassemble the custom instructions needed to draw the primitive. + virtual void generate_instructions(); + + virtual void IRAM_ATTR paint(volatile uint32_t* p_scan_line, uint32_t line_index); + + protected: + uint8_t m_opaqueness; +}; diff --git a/video/src/di_video_buffer.cpp b/video/src/di_video_buffer.cpp new file mode 100644 index 00000000..b406d106 --- /dev/null +++ b/video/src/di_video_buffer.cpp @@ -0,0 +1,126 @@ +// di_video_buffer.cpp - Function definitions for painting video scan lines +// +// A a video buffer is a set of 1-pixel-high video scan lines that are equal +// in length (number of pixels) to the total width of the video screen and +// horizontal synchronization pixels. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#include +#include +#include +#include "di_video_buffer.h" +#include "di_timing.h" +#include "freertos/FreeRTOS.h" + +DiVideoScanLine::DiVideoScanLine(uint32_t num_lines) { + m_num_lines = num_lines; + auto new_size = (size_t)(get_buffer_size() * num_lines); + auto p = heap_caps_malloc(new_size, MALLOC_CAP_32BIT|MALLOC_CAP_8BIT|MALLOC_CAP_DMA); + m_scan_line = (uint32_t *)p; +} + +DiVideoScanLine::~DiVideoScanLine() { + if (m_scan_line) { + delete [] m_scan_line; + } +} + +volatile uint32_t * DiVideoScanLine::get_buffer_ptr(uint32_t index) volatile { + uint32_t offset = get_buffer_size() * index; + return (volatile uint32_t *) (((uint8_t*) m_scan_line) + offset); +} + +uint32_t DiVideoScanLine::get_buffer_size() +{ + return otf_video_params.m_active_pixels + + otf_video_params.m_hfp_pixels + + otf_video_params.m_hs_pixels + + otf_video_params.m_hbp_pixels; +} + +uint32_t DiVideoScanLine::get_total_size() { + return get_buffer_size() * m_num_lines; +} + +volatile uint32_t* DiVideoScanLine::get_active_pixels() { + return m_scan_line; +} + +volatile uint32_t* DiVideoScanLine::get_hfp_pixels() { + return (volatile uint32_t*) + (((volatile uint8_t*) m_scan_line) + + otf_video_params.m_active_pixels); +} + +volatile uint32_t* DiVideoScanLine::get_hs_pixels() { + return (volatile uint32_t*) + (((volatile uint8_t*) m_scan_line) + + otf_video_params.m_active_pixels + + otf_video_params.m_hfp_pixels); +} + +volatile uint32_t* DiVideoScanLine::get_hbp_pixels() { + return (volatile uint32_t*) + (((volatile uint8_t*) m_scan_line) + + otf_video_params.m_active_pixels + + otf_video_params.m_hfp_pixels + + otf_video_params.m_hs_pixels); +} + +volatile uint32_t* DiVideoScanLine::get_active_pixels(uint32_t index) { + uint32_t offset = get_buffer_size() * index; + return (volatile uint32_t*)(((volatile uint8_t*)get_active_pixels()) + offset); +} + +volatile uint32_t* DiVideoScanLine::get_hfp_pixels(uint32_t index) { + uint32_t offset = get_buffer_size() * index; + return (volatile uint32_t*)(((volatile uint8_t*)get_hfp_pixels()) + offset); +} + +volatile uint32_t* DiVideoScanLine::get_hs_pixels(uint32_t index) { + uint32_t offset = get_buffer_size() * index; + return (volatile uint32_t*)(((volatile uint8_t*)get_hs_pixels()) + offset); +} + +volatile uint32_t* DiVideoScanLine::get_hbp_pixels(uint32_t index) { + uint32_t offset = get_buffer_size() * index; + return (volatile uint32_t*)(((volatile uint8_t*)get_hbp_pixels()) + offset); +} + +void DiVideoScanLine::init_to_black() { + for (uint32_t i = 0; i < m_num_lines; i++) { + memset((void*)get_active_pixels(i), otf_video_params.m_syncs_off, otf_video_params.m_active_pixels); + memset((void*)get_hfp_pixels(i), otf_video_params.m_syncs_off, otf_video_params.m_hfp_pixels); + memset((void*)get_hs_pixels(i), (otf_video_params.m_hs_on|otf_video_params.m_vs_off), otf_video_params.m_hs_pixels); + memset((void*)get_hbp_pixels(i), otf_video_params.m_syncs_off, otf_video_params.m_hbp_pixels); + } +} + +void DiVideoScanLine::init_for_vsync() { + for (uint32_t i = 0; i < m_num_lines; i++) { + memset((void*)get_active_pixels(i), (otf_video_params.m_hs_off|otf_video_params.m_vs_on), otf_video_params.m_active_pixels); + memset((void*)get_hfp_pixels(i), (otf_video_params.m_hs_off|otf_video_params.m_vs_on), otf_video_params.m_hfp_pixels); + memset((void*)get_hs_pixels(i), otf_video_params.m_syncs_on, otf_video_params.m_hs_pixels); + memset((void*)get_hbp_pixels(i), (otf_video_params.m_hs_off|otf_video_params.m_vs_on), otf_video_params.m_hbp_pixels); + } +} diff --git a/video/src/di_video_buffer.h b/video/src/di_video_buffer.h new file mode 100644 index 00000000..dcbc12c6 --- /dev/null +++ b/video/src/di_video_buffer.h @@ -0,0 +1,65 @@ +// di_video_buffer.h - Function declarations for painting video scan lines +// +// A a video buffer is a set of 1-pixel-high video scan lines that are equal +// in length (number of pixels) to the total width of the video screen and +// horizontal synchronization pixels. +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +#pragma once +#include "di_timing.h" + +// Holds the DMA scan line buffer for a single visible line. +class DiVideoScanLine { + protected: + + uint32_t m_num_lines; + uint32_t* m_scan_line; + + public: + + DiVideoScanLine(uint32_t num_lines); + ~DiVideoScanLine(); + + static uint32_t get_buffer_size(); + uint32_t get_total_size(); + + volatile uint32_t* get_active_pixels(); + volatile uint32_t* get_hfp_pixels(); + volatile uint32_t* get_hs_pixels(); + volatile uint32_t* get_hbp_pixels(); + + volatile uint32_t* get_active_pixels(uint32_t index); + volatile uint32_t* get_hfp_pixels(uint32_t index); + volatile uint32_t* get_hs_pixels(uint32_t index); + volatile uint32_t* get_hbp_pixels(uint32_t index); + + inline volatile uint32_t * get_buffer_ptr() volatile { + return (volatile uint32_t *) m_scan_line; + } + + volatile uint32_t * get_buffer_ptr(uint32_t index) volatile; + + void init_to_black(); + + void init_for_vsync(); +}; diff --git a/video/src/docs/bitmap.png b/video/src/docs/bitmap.png new file mode 100644 index 00000000..a964022c Binary files /dev/null and b/video/src/docs/bitmap.png differ diff --git a/video/src/docs/drawings.xcf b/video/src/docs/drawings.xcf new file mode 100644 index 00000000..fe5136f7 Binary files /dev/null and b/video/src/docs/drawings.xcf differ diff --git a/video/src/docs/ellipse.png b/video/src/docs/ellipse.png new file mode 100644 index 00000000..a1e6d03f Binary files /dev/null and b/video/src/docs/ellipse.png differ diff --git a/video/src/docs/line.png b/video/src/docs/line.png new file mode 100644 index 00000000..a2cb0e12 Binary files /dev/null and b/video/src/docs/line.png differ diff --git a/video/src/docs/otf_bitmap.md b/video/src/docs/otf_bitmap.md new file mode 100644 index 00000000..209d0fa9 --- /dev/null +++ b/video/src/docs/otf_bitmap.md @@ -0,0 +1,267 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Solid Bitmap +VDU 23, 30, 120, id; pid; flags; w; h; psram : Create primitive: Solid Bitmap + +This commmand creates a primitive that draws a solid bitmap, meaning +that every pixel is fully opaque (though each pixel has its own color). +A solid bitmap may be the most efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower, and their overuse could cause flicker. + +OTF mode will automatically set the PRIM_FLAGS_ALL_SAME flag +when this command is used. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create primitive: Masked Bitmap +VDU 23, 30, 121, id; pid; flags; w; h; psram, color : Create primitive: Masked Bitmap + +This commmand creates a primitive that draws a masked bitmap, meaning +that every pixel is either fully opaque (though each pixel has its own color) or fully transparent. +A solid bitmap may be the most efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower, and their overuse could cause flicker. + +The given color is used to represent fully transparent pixels, +so be sure to specify a byte value that is unique from any +visible color in the source bitmap. When setting the color of +each pixel in the bitmap, use that given color for any pixels +that must be invisible. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create primitive: Transparent Bitmap +VDU 23, 30, 122, id; pid; flags; w; h; psram, color : Create primitive: Transparent Bitmap + +This commmand creates a primitive that draws a transparent bitmap, meaning +that each pixel has either 0%, 25%, 50%, 75%, or 100% opacity. +A transparent bitmap may be the least efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower than solid bitmaps, and their overuse could cause flicker. + +The given color is used to represent fully transparent pixels, +so be sure to specify a byte value that is unique from any +visible color in the source bitmap. When setting the color of +each pixel in the bitmap, use that given color for any pixels +that must be invisible. + +OTF mode will automatically set the PRIM_FLAGS_BLENDED flag +when this command is used. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Set position & slice solid bitmap +VDU 23, 30, 123, id; x; y; s; h; : Set position & slice solid bitmap + +This command sets the position of a solid bitmap, and specifies +the starting vertical offset within the bitmap, plus the height +to draw. It is not necessary to draw the entire bitmap. This command +may be used to select the individual frames of a sprite, or to +scroll a bitmap vertically within a specified height. + +By default, when a bitmap is created, its starting vertical offset +is zero, and its draw height is equal to its created height. + +## Set position & slice masked bitmap +VDU 23, 30, 124, id; x; y; s; h; : Set position & slice masked bitmap + +This command sets the position of a masked bitmap, and specifies +the starting vertical offset within the bitmap, plus the height +to draw. It is not necessary to draw the entire bitmap. This command +may be used to select the individual frames of a sprite, or to +scroll a bitmap vertically within a specified height. + +By default, when a bitmap is created, its starting vertical offset +is zero, and its draw height is equal to its created height. + +## Set position & slice transparent bitmap +VDU 23, 30, 125, id; x; y; s; h; : Set position & slice transparent bitmap + +This command sets the position of a transparent bitmap, and specifies +the starting vertical offset within the bitmap, plus the height +to draw. It is not necessary to draw the entire bitmap. This command +may be used to select the individual frames of a sprite, or to +scroll a bitmap vertically within a specified height. + +By default, when a bitmap is created, its starting vertical offset +is zero, and its draw height is equal to its created height. + +## Adjust position & slice solid bitmap +VDU 23, 30, 126, id; x; y; s; h; : Adjust position & slice solid bitmap + +This command adjusts the position of a solid bitmap, and specifies +the starting vertical offset within the bitmap, plus the height +to draw. It is not necessary to draw the entire bitmap. This command +may be used to select the individual frames of a sprite, or to +scroll a bitmap vertically within a specified height. + +By default, when a bitmap is created, its starting vertical offset +is zero, and its draw height is equal to its created height. + +## Adjust position & slice masked bitmap +VDU 23, 30, 127, id; x; y; s; h; : Adjust position & slice masked bitmap + +This command adjusts the position of a masked bitmap, and specifies +the starting vertical offset within the bitmap, plus the height +to draw. It is not necessary to draw the entire bitmap. This command +may be used to select the individual frames of a sprite, or to +scroll a bitmap vertically within a specified height. + +By default, when a bitmap is created, its starting vertical offset +is zero, and its draw height is equal to its created height. + +## Adjust position & slice transparent bitmap +VDU 23, 30, 128, id; x; y; s; h; : Adjust position & slice transparent bitmap + +This command adjusts the position of a transparent bitmap, and specifies +the starting vertical offset within the bitmap, plus the height +to draw. It is not necessary to draw the entire bitmap. This command +may be used to select the individual frames of a sprite, or to +scroll a bitmap vertically within a specified height. + +By default, when a bitmap is created, its starting vertical offset +is zero, and its draw height is equal to its created height. + +## Set solid bitmap pixel +VDU 23, 30, 129, id; x; y; color : Set solid bitmap pixel + +This command sets the color of a single pixel within a solid bitmap. +You must use the same alpha bits for every pixel in the bitmap; +otherwise, undesirable results may occur. + +## Set masked bitmap pixel +VDU 23, 30, 130, id; x; y; color : Set masked bitmap pixel + +This command sets the color of a single pixel within a masked bitmap. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. All other pixels must have equal +alpha bits (i.e., be at the same opacity level). + +## Set transparent bitmap pixel +VDU 23, 30, 131, id; x; y; color : Set transparent bitmap pixel + +This command sets the color of a single pixel within a transparent bitmap. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. + +## Set solid bitmap pixels +VDU 23, 30, 132, id; x; y; n; c0, c1, c2, ... : Set solid bitmap pixels + +This command sets the colors of multiple pixels within a solid bitmap. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. + +The "n" parameter is the number of pixels. + +## Set masked bitmap pixels +VDU 23, 30, 133, id; x; y; n; c0, c1, c2, ... : Set masked bitmap pixels + +This command sets the colors of multiple pixels within a masked bitmap. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. + +The "n" parameter is the number of pixels. + +## Set transparent bitmap pixels +VDU 23, 30, 134, id; x; y; n; c0, c1, c2, ... : Set transparent bitmap pixels + +This command sets the colors of multiple pixels within a transparent bitmap. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. + +The "n" parameter is the number of pixels. + +## Create primitive: Reference Solid Bitmap +VDU 23, 30, 135, id; pid; flags; bmid; : Create primitive: Reference Solid Bitmap + +This commmand creates a primitive that references a solid bitmap. +The new primitive has its own position and slicing information, but has no +pixel data. It borrows (shares) the pixel data from the +referenced bitmap. This makes it possible to display multiple +similar bitmaps, using only one set of pixel data. + +This command sets the PRIM_FLAGS_REF_DATA flag for the new primitive automatically. + +## Create primitive: Reference Masked Bitmap +VDU 23, 30, 136, id; pid; flags; bmid; : Create primitive: Reference Masked Bitmap + +This commmand creates a primitive that references a solid bitmap. +The new primitive has its own position and slicing information, but has no +pixel data. It borrows (shares) the pixel data from the +referenced bitmap. This makes it possible to display multiple +similar bitmaps, using only one set of pixel data. + +This command sets the PRIM_FLAGS_REF_DATA flag for the new primitive automatically. + +## Create primitive: Reference Transparent Bitmap +VDU 23, 30, 137, id; pid; flags; bmid; : Create primitive: Reference Transparent Bitmap + +This commmand creates a primitive that references a solid bitmap. +The new primitive has its own position and slicing information, but has no +pixel data. It borrows (shares) the pixel data from the +referenced bitmap. This makes it possible to display multiple +similar bitmaps, using only one set of pixel data. + +This command sets the PRIM_FLAGS_REF_DATA flag for the new primitive automatically. + +## Create primitive: Duplicate Solid Bitmap +VDU 23, 30, 145, id; pid; flags; bmid, psram, flip : Create primitive: Duplicate Solid Bitmap + +This command duplicates a solid bitmap (bmid), while allowing you to make some +changes to the pixel data in the process. First, the RAM location of the +new bitmap may differ from the RAM location of the original bitmap. +Second, you can flip the bitmap vertically (&02), horizontally (&01), or both (&03). + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create primitive: Duplicate Masked Bitmap +VDU 23, 30, 146, id; pid; flags; bmid, psram, flip : Create primitive: Duplicate Masked Bitmap + +This command duplicates a masked bitmap (bmid), while allowing you to make some +changes to the pixel data in the process. First, the RAM location of the +new bitmap may differ from the RAM location of the original bitmap. +Second, you can flip the bitmap vertically (&02), horizontally (&01), or both (&03). + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create primitive: Duplicate Transparent Bitmap +VDU 23, 30, 147, id; pid; flags; bmid, psram, flip : Create primitive: Duplicate Transparent Bitmap + +This command duplicates a transparent bitmap (bmid), while allowing you to make some +changes to the pixel data in the process. First, the RAM location of the +new bitmap may differ from the RAM location of the original bitmap. +Second, you can flip the bitmap vertically (&02), horizontally (&01), or both (&03). + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Bitmap](bitmap.png) + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_code_gen.md b/video/src/docs/otf_code_gen.md new file mode 100644 index 00000000..471612d5 --- /dev/null +++ b/video/src/docs/otf_code_gen.md @@ -0,0 +1,22 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +# OTF Dynamic Code Generation + +As mentioned above, the OTF mode uses some built-in ESP32 assembler functions to help with drawing primitives quickly; however, it +goes a step further. In order to reduce the number of decisions made +while drawing, it uses the primitive definitions to generate portions +of ESP32 code at runtime. In some cases, instructions are generated +that call built-in functions in whatever sequence is required. +In other cases, instructions are generated that write to the specific +pixel data bytes. +

+For example, to draw a 20 pixel long line from X position 39 to X position 58, inclusive, the OTF mode will generate instructions to +set the single pixel at 39, set the 16 pixels from 40 to 55 (4 pixels at a time), set 2 pixels at 56 to 57, and finally, set the remaining +single pixel at 58. +

+The code generation operation itself does take a small amount of time, +and depending on how many primitives are processed to do so, there +may be some temporary effect on painting the screen, meaning +that it may flicker or duplicate scan lines during that time. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_colors.md b/video/src/docs/otf_colors.md new file mode 100644 index 00000000..a662ceb0 --- /dev/null +++ b/video/src/docs/otf_colors.md @@ -0,0 +1,41 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +# OTF Colors + +The OTF mode can display all 64 colors that the Agon is capable +of showing. Since the OTF mode supports transparency, it uses +the upper 2 bits of the color byte for that. In other words, +it uses an AABBGGRR format, where the 8 bits of the color byte +are concerned. The alpha (opacity) values are as follows: + +00BBGGRR - the pixel is 25% opaque (75% transparent) +01BBGGRR - the pixel is 50% opaque (50% transparent) +10BBGGRR - the pixel is 75% opaque (25% transparent) +11BBGGRR - the pixel is 100% opaque (0% transparent) + +The obvious question is, how do we specify a pixel that is 0% +opaque (100% transparent)? That is done by choosing a byte value +that will not be used in the primitive to represent a color. If +the primitive has a consistent opaqueness (all visible pixels are at +the same opacity level), then the chosen byte value can be any value +that does not specify that particular opacity level. For example, +if all pixels are supposed to be 75% opaque (alpha 10 in binary), +then the value 0 (0x00) works just fine as the transparent +color, because it does not indicate 75% opacity. + +The potential conflict arises when the primitive, such as a +bitmap, is intended to have variable blending, meaning that each +pixel can have its own opacity level. In that case, one of the +255 possible byte values must be sacrificed, and used as the +fully transparent color. Simply put, you must choose a value +that does not exist in the source bitmap. Bear in mind that the +whole byte value is used to represent an invisible pixel, +not just the color bits. This means that the transparent color +can have color bits equal to an actual color in the primitive, +but it must have different alpha bits, in that case. For example, +if 0x7F (bright white at 50% opacity) is a color in the source +bitmap, you cannot use 0x7F as the transparent color, but you +could use 0xFF, if there will be no bright white pixels at +100% opacity. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_critical.md b/video/src/docs/otf_critical.md new file mode 100644 index 00000000..6f6aa738 --- /dev/null +++ b/video/src/docs/otf_critical.md @@ -0,0 +1,56 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +# OTF Critical Section + +There are certain aspects to how the OTF mode draws (paints) the screen that +should be kept in mind when designing the graphics for applications. + +* Timing is everything. At a pixel clock rate of 40 MHz, each scan line, +including the visible and invisible portions of it, lasts just 0.0000264 seconds +(which is 26.4 microseconds). Not a lot of time! At the 240 MHz internal clock +rate of the ESP32, each clock tick lasts about 0.004167 microseconds (which is +4.167 picoseconds). Dividing the scan line time by the CPU clock tick time +indicates that there are approximately 6336 CPU clock cycles per scan line. +During those cycles, the CPU must execute enough instructions to draw one line. +While one scan line is being displayed by the I2S hardware, the OTF manager must +draw (create 800 colored pixels for) a future scan line, and it must do so in under +6336 CPU clock cycles. Again, not a lot of time.

For this reason, it is critical to avoid drawing (layering) too many things on the same scan line. Each time the same pixel in the current scan line buffer is written, +time is used, so if there are too many objects (primitives) layered on top of +each other, there may not be enough time to draw the scan line, before the next +scan line should be drawn. If time runs out, the screen will show flashing +(flickering) scan lines. It is unlikely that an entire object (such as a sprite) +will flicker on and off. What is much more likely is that distinct scan lines +within the object will flicker, or be vertically out of place.

Another reason that flickering may occur, meaning that the time to draw a scan line exceeds the limit, is that CPU time can be stolen away from the OTF manager +via interrupts and by other tasks. To help to reduce this possibility, the OTF manager runs in a high-priority task. + +* Everything must be painted. Every scan line on the screen (all 600 of them) must be drawn (painted) on every frame (i.e., 60 times per second). What +happens if one of those scan lines is not painted? Whatever was left in the scan +line buffer will be displayed again, at whatever vertical position the I2S hardware happens to be outputting. To exaggerate a bit, if the code only painted the first (top) scan line (out of the 8 lines used) once, and never again, then the display would show that scan line's pixels on the screen 75 times, once per group of 8 lines, going down the screen's 600 lines.

+So, how does this requirement affect the EZ80 application, and how does it affect the OTF manager in the ESP32? Let's take the latter part first. In order +to redraw each active primitive 60 times per second, the manager must keep them +all in RAM (as mentioned above). Primitives are not transferred, written, and +deleted. They are stored for continual use, until the EZ80 application sends the +OTF commands to delete them. There is a big advantage to having them kept in RAM, because they can be used for a long time, without being transferred across +the serial port again (i.e., sending the command(s) to create a primitive once +is enough).

+Now, on to the former part. In order to make sure that every scan line is painted during each frame, the EZ80 application must define at least 1 primitive +that covers each pixel on the screen, so that there is at least one "drop" of +paint landing on that pixel during frame output. If any pixel is missed, it will +not be painted, and will be shown multiple times with the last drop of paint +that it received (most likely from somewhere else on the screen).

+There are 2 simple ways to be sure that every pixel is painted by at least 1 +layer of paint. The first alternative is to create a text area primitive, or a custom +tile array, that covers the entire screen. The text area, if full-screen, implies a tile array of characters in 8x8-pixel cells, totalling 100 +columns across by 75 rows down. Every pixel on the screen is covered by such a +text area primitive (at present there is no way to make it smaller; that is +a future enhancement). The second alternative is to create a solid rectangle primitive with the +X/Y coordinates at (0, 0), a width of 800 pixels, and a height of 600 pixels. +Such a rectangle can be any of the 64 colors, and would serve as a background +for the entire video frame. Other things could be drawn on top of it.

+Of course, you have the option of piecing together various primitives of +your choosing, as long as you cover the entire screen.

+To be clear, if the EZ80 application does not define some kind of background +(often, either a full tile array or a solid rectangle), then some part(s) of the +screen will not be painted properly, giving undesirable effects. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_ellipse.md b/video/src/docs/otf_ellipse.md new file mode 100644 index 00000000..93afe71e --- /dev/null +++ b/video/src/docs/otf_ellipse.md @@ -0,0 +1,23 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Ellipse Outline +VDU 23, 30, 50, id; pid; flags; x; y; w; h; color : Create primitive: Ellipse Outline + +This commmand creates a primitive that draws the outline of an ellipse. The ellipse is not filled. Note that width and height +are given, not the diagonal coordinates. + +## Create primitive: Solid Ellipse +VDU 23, 30, 51, id; pid; flags; x; y; w; h; color : Create primitive: Solid Ellipse + +This commmand creates a primitive that draws a solid, filled ellipse. +The ellipse does not have a distinct outline with a different +color than the fill color. +Note that width and height are given, not +the diagonal coordinates. + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Ellipse](ellipse.png) + + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_flags.md b/video/src/docs/otf_flags.md new file mode 100644 index 00000000..4b1f865f --- /dev/null +++ b/video/src/docs/otf_flags.md @@ -0,0 +1,187 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +# OTF Primitve Flags + +The OTF mode uses flags to control certain aspects of primitives. +Here is an overview of the current set of flags (which is always +subject to additions in the future): + +``` +#define PRIM_FLAG_PAINT_THIS 0x0001 // whether to paint this primitive +#define PRIM_FLAG_PAINT_KIDS 0x0002 // whether to paint child primitives +#define PRIM_FLAG_CLIP_THIS 0x0004 // whether to clip this primitive +#define PRIM_FLAG_CLIP_KIDS 0x0008 // whether to clip child primitives +#define PRIM_FLAG_H_SCROLL_1 0x0010 // whether to support horizontal scrolling on 1-pixel boundary +#define PRIM_FLAG_H_SCROLL_4 0x0020 // whether to support horizontal scrolling on 4-pixel boundary +#define PRIM_FLAG_ABSOLUTE 0x0040 // whether to use absolute coordinates always +#define PRIM_FLAGS_MASKED 0x0080 // hint that pixels are fully opaque or transparent +#define PRIM_FLAGS_BLENDED 0x0100 // hint that pixels may be blended +#define PRIM_FLAGS_ALL_SAME 0x0200 // hint that all lines can be drawn the same way +#define PRIM_FLAGS_LEFT_EDGE 0x0400 // hint that left edge of primitive may be cut off +#define PRIM_FLAGS_RIGHT_EDGE 0x0800 // hint that right edge of primitive may be cut off +#define PRIM_FLAGS_CAN_DRAW 0x1000 // whether this primitive can be drawn at all +#define PRIM_FLAGS_X 0x2000 // hint that x will be given +#define PRIM_FLAGS_X_SRC 0x4000 // hint that x and src pixel ptr will be given +#define PRIM_FLAGS_REF_DATA 0x8000 // whether this primitive references (vs owns) data +#define PRIM_FLAGS_DEFAULT 0x000F // flags set when a new base primitive is constructed +#define PRIM_FLAGS_CHANGEABLE 0x000F // flags that the app can change after primitive creation +``` + +The following describes the individual flags in more detail. + +PRIM_FLAG_PAINT_THIS
+This flag determines whether the primitive is painted (drawn). +It is essentially a visibility flag, because it partially +determines whether the primitive can be visible. Other factors, +such as position may also affect visibility. Inverting this flag +on a periodic basis will cause the primitive to blink. + +PRIM_FLAG_PAINT_KIDS
+This flag determines whether this children of the primitive, +if any, are painted (drawn). This flag controls whether drawing +traverses lower levels of the primitive tree (nesting), below +the primitive itself. Note that even if this flag is set, +a child primitive will not be drawn if its own PRIM_FLAG_PAINT_THIS +flag is cleared. Inverting this flag on a periodic basis will +cause child primitives to blink. + +PRIM_FLAG_CLIP_THIS
+This flag determines whether this primitive is clipped by the draw +region of its parent. If this flag is cleared, the primitive +is clipped by the screen. +Presently, the draw region of any primitive +is defined when it is created, based on the designated size at +that time. There is currently no way to resize a primitive after +it has been created. It is possible to use a group primitive to +define a clipping region for child primitives. The group itself +has no visible aspect, but can affect its children. For example, +a group of spaceships can be moved together by moving their +parent group, if created as children of that group. It is possible +to simulate growing or shrinking by using multiple primitives, +and only displaying one at a time. + +PRIM_FLAG_CLIP_KIDS
+This flag determines whether to clip child primitives by the parent +primitive's draw region. If this flag is clear, the children are +clipped by their grandparent, if any, or by the screen, not by their parent. + +PRIM_FLAG_H_SCROLL_1
+This flag determines whether the primitive will need to be scrolled +horizontally on a 1-pixel boundary. This flag does not need to be +specified in order to scroll on a 4-pixel boundary (that flag is below). +If this flag is set when creating the primitive, more RAM will be used to +support the smooth horizontal motion. Using this flag implies being +able to scroll on a 1-, 2-, 3-, or 4-pixel boundary. +If no motion is necessary (i.e., the +primitive has just one location on the screen), then do not set +the PRIM_FLAG_H_SCROLL_1 flag or the PRIM_FLAG_H_SCROLL_4 flag. + +NOTE: If any ancestor of the primitive uses this flag, then +this primitive must also use this flag. + +PRIM_FLAG_H_SCROLL_4
+This flag determines whether the primitive will need to be scrolled +horizontally on a 4-pixel boundary. If this flag +is set when creating the primitive, more RAM will be used to support +the rough horizontal motion. If no motion is necessary (i.e., the +primitive has just one location on the screen), then do not set +the PRIM_FLAG_H_SCROLL_1 flag or the PRIM_FLAG_H_SCROLL_4 flag. + +NOTE: If any ancestor of the primitive uses this flag, then +this primitive must also use this flag. + +PRIM_FLAG_ABSOLUTE
+This flag determines whether the primitive should always be +positioned relative to the screen, and not to any of its ancestors. +If this flag is cleared, the displayed location of the primitive +may be affected by the locations of its parent, grandparent, etc. + +PRIM_FLAGS_MASKED
+This flag determines whether a primitive is intended to be drawn +in a masked manner, as opposed to a solid manner. In a solid, all +pixels are 100% opaque. In a mask, all pixels are either 100% +opaque or 0% opaque (100% transparent). This flag is used +for bitmaps, and helps the OTF mode to optimize drawing speed. + +PRIM_FLAGS_BLENDED
+This flag determines whether a primitive is intended to be drawn +in a blended manner, as opposed to a solid manner. In a solid, all +pixels are 100% opaque. In a blend, all pixels are either 100%, +75%, 50%, 25%, or 0% opaque (0%, 25%, 50%, 75%, or 100% transparent, +respectively). This flag is used +for bitmaps, and helps the OTF mode to optimize drawing speed. It +may also be used for other primitives such as lines and triangles. + +PRIM_FLAGS_ALL_SAME
+This flag determines whether all of the scan lines in the primitive +can be drawn using the same dynamic instructions. It is used for +rectangles and bitmaps, and helps the OTF mode to optimize drawing +speed, plus reduces the RAM used. It cannot be used with blending, +unless all pixels in the primitive are at the same opacity +level (e.g., all pixels are 50% opaque). + +PRIM_FLAGS_LEFT_EDGE
+This flag determines whether to generate code that can draw the +primitive with part of its left edge missing, such as hidden off +of the left side of the screen, as a result of being moved +(scrolled). This flag must be set for any +primitive that will be repositioned +(after dynamic code generation for it) +such that its left edge is +hidden, either by being off-screen or clipped by some ancestor. +This flag is not required when part of the primitive is hidden +only by virtue of being underneath some other primitive, and is +not required for a static primitive that happens to be clipped +(meaning that part of it will never be drawn). + +PRIM_FLAGS_RIGHT_EDGE
+This flag determines whether to generate code that can draw the +primitive with part of its right edge missing, such as hidden off +of the right side of the screen, as a result of being moved +(scrolled). This flag must be set for any +primitive that will be repositioned +(after dynamic code generation for it) +such that its right edge is +hidden, either by being off-screen or clipped by some ancestor. +This flag is not required when part of the primitive is hidden +only by virtue of being underneath some other primitive, and is +not required for a static primitive that happens to be clipped +(meaning that part of it will never be drawn). + +PRIM_FLAGS_CAN_DRAW
+This OTF-internal flag determines whether a primitive can be +drawn based on various factors, such as position, clipping, and +transparency. Its value is determined dynamically by OTF. + +PRIM_FLAGS_X
+This OTF-internal flag determines whether the X coordinate is provided, +as opposed to being fixed, when each scan line of a primitive +is drawn. This flag and some related code exist for potential future use. + +PRIM_FLAGS_X_SRC
+This OTF-internal flag determines whether the X coordinate is provided, +as opposed to being fixed, when each scan line of a primitive +is drawn. An example of where this is required is when drawing +a tile array or a tile map. OTF will set this flag automatically +in such cases, because it affects dynamic code generation. + +PRIM_FLAGS_REF_DATA
+This flag indicates that the primitive references underlying data +rather than owning the data. For example, the reference bitmap +primitives borrow pixel data from other bitmap primitives, but +do not own the bitmap data themselves. + +PRIM_FLAGS_DEFAULT
+This flag illustrates which flags are typically set when +creating a primitive. Most often, when creating a primitive, +such as a triangle, you would pass a value of 15 (0x000F) +as the flags parameter. You may want to use another value, +if you intend to create, but not immediately display, +the new primitive. + +PRIM_FLAGS_CHANGEABLE
+This flag illustrates which flags my be changed after the +primitive is created. Setting or clearing any of these flags +may have an affect on how or whether the primitive is drawn. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_group.md b/video/src/docs/otf_group.md new file mode 100644 index 00000000..5cdac1f0 --- /dev/null +++ b/video/src/docs/otf_group.md @@ -0,0 +1,17 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Group +VDU 23, 30, 140, id; pid; flags; x; y; w; h; : Create primitive: Group + +This commmand creates a primitive that groups its child primitives, +for the purposes of motion and clipping. If a group node has +children, and the group node is moved, and the children are positioned +relative to their parent (i.e., they do not use the PRIM_FLAG_ABSOLUTE flag), +then the children are moved with the parent. Note that a group node +has no visible representation (i.e., is not drawn). + +When this command is used, OTF will automatically clear the PRIM_FLAG_PAINT_THIS flag. + +Changing the flags of a group node can show or hide its children. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_issues.md b/video/src/docs/otf_issues.md new file mode 100644 index 00000000..8c90151f --- /dev/null +++ b/video/src/docs/otf_issues.md @@ -0,0 +1,26 @@ +## Issues and Considerations + +The following OTF capabilities have not yet been implemented or are presently incomplete, and should not be used (yet): + +* Drawing circles and ellipses. +* Doing 3D rendering. +* Using tile maps (you can use tile arrays). +* Using a mouse (because there is no support for the mouse pointer). +* Using some video modes, especially certain double-scan modes. You can try, but some pixels/characters may be cut off (not shown). +* Using sound. This has not been tested at all, and the high-priority OTF task may prevent it from working at present. +* Using very large bitmaps (from PSRAM) at resolutions above 320x240, because PSRAM is too slow to keep up with fast pixel clock rates. It is still possible to use smaller bitmaps at higher resolutions, such as 800x600. +* Once the video mode is changed to an OTF mode, there is no way to exit that mode without resetting the Agon. This will be fixed later. +* Partial transparency (as opposed to fully transparent or fully opaque) may not work (yet) in video modes with negative HS or VS signals. It should work in video modes where both signals are positive. This will be corrected soon. + +The following things should be considered: + +* OTF requires a different way of planning and construction an application from a displayable primitives perspective. +* OTF is not suitable for every kind of application, such as those that constantly draw on a full-screen buffer, purposely overwriting what was there. +* OTF is more suitable for applications that create various primitives and then manipulate (move, show, hide, delete) them. +* Where there is a need to move groups of objects together, consider using group primitives. +* Use group primitives to show/hide sets of objects with little serial communication (one command versus several), bearing in mind that the primitive flags need to be set correctly to support this. +* OTF may be a relatively simple idea, but its code is complex, so do not be surprised if you discover a latent bug. +* OTF is not currently hooked into all of the existing video-related BASIC statements (or their corresponding VDU commands), such as the PLOT command; however, some of the VDU commands, such as those that move the text cursor, are tied to OTF. Their will be more integration in the future. For the time being, in order to do any kind of graphics with OTF, use the VDU commands described in the OTF documentation. +* OTF supports multiple text areas, which means that you can have, for example, a full-screen text area plus one or more other text areas over it. Or you can have some other background (a solid rectangle, tile map, tile array, or large bitmap), and place one or more text areas over that. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_line.md b/video/src/docs/otf_line.md new file mode 100644 index 00000000..582e4b94 --- /dev/null +++ b/video/src/docs/otf_line.md @@ -0,0 +1,13 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Line +VDU 23, 30, 20, id; pid; flags; x1; y1; x2; y2; color : Create primitive: Line + +This commmand creates a primitive that draws a line. The endpoints +are included (i.e., are drawn). + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Line](line.png) + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_mode.md b/video/src/docs/otf_mode.md new file mode 100644 index 00000000..21f73128 --- /dev/null +++ b/video/src/docs/otf_mode.md @@ -0,0 +1,91 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +# 800x600x64 On-the-Fly (OTF) Mode + +The AgonLight VDP-GL (video display processor graphics library) is based on a fork of the FabGL, and includes support for VGA displays at various resolutions and color palettes, plus support for the keyboard, mouse, and serial communication btween the EZ80 CPU and the ESP32 CPU. + +FabGL, and thus its VDP-GL derivative, processes graphics primitives (such as points, lines, triangles, and bitmaps) by writing to one or two full-frame memory buffers, and then allowing I2S DMA hardware to output the VGA pixel data by reading buffered bytes. The final output includes signals for 8 bits: 1 horizontal synchronization bit, 1 vertical synchronization bit, 2 red color bits, 2 green color bits, and 2 blue color bits. Because there are 6 color bits, the AgonLight can show a maximum of 64 distinct colors. + +If two buffers are used, VDP-GL can write to one buffer while the hardware outputs the other buffer. If only one buffer is used, VDP-GL can only write to it during the vertical blanking period, to avoid visible tearing, a situation where parts of 2 successive frames are shown, rather than one complete frame. + +Because DMA-accessible RAM, also known as internal RAM, in the ESP32 is limited, there is insufficient RAM available to display all 64 possible colors at resolutions higher than about one-quarter of VGA, meaning about 320x200 or 320x240 pixels. + +To show more colors at a higher resolution is the goal of the 800x600x64 mode, dubbed the On-the-Fly (OTF) mode, because of how it works. This special mode conserves DMA RAM by using only 8 horizontal scan line buffers, as opposed to using 1 scan line buffer per vertical line of resolution. Thus, it does not need 600 scan line buffers for active (visible) pixels. Instead of drawing a complete video frame before outputting that frame, it draws individual scan lines on-the-fly while the frame is being output, making every attempt to stay slightly ahead of the DMA hardware, so as to avoid causing visible flickering. + +The OTF mode runs using a pixel clock of 40 MHz in order to provide the required 800x600 visible pixels, along with the hidden horizontal and vertical blanking pixels, at a frame rate of 60 Hz +(60 FPS, meaning 60 visible frames per second). The pixel clock in this mode is significantly +faster than the 25.175 MHz clock used for VGA with 640x480 pixels at 60 FPS. Therefore, the amount +of time needed for each scan line in OTF mode is significantly less than the amount of time needed +for each scan line in 640x480 mode, or any mode using a slower pixel clock. + +For that reason, all of the core drawing functions for OTF mode are written in ESP32 assembly language, +to make those functions as fast as possible. The drawing primitives are C++ classes, with common +and non-common data members and function members, but these members are all geared toward helping +the core assembler routines run very quickly. This means that various data elements, such as +pixel colors for bitmaps, and tile information for tile maps, are stored in specific formats that +will help to reduce decision-making while drawing the primitives. For example, if a bitmap supports +horizontal scrolling (on a 1-pixel boundary), there are multiple copies of the bitmap in memory, +each pre-shifted based on the pixel alignment. This allows the bitmap to be copied very quickly, +a whole word (4 bytes) at a time, when drawing, regardless of the destination byte alignment. + +# OTF Video Modes + +When the Agon boots, it is normally in video mode 1, but can be +placed into other video modes using either the BASIC MODE statement, or the proper VDU statement. OTF supports the following new video modes, many of which have the same resolution as older modes (that are not OTF-based). + +Modes 32..47 (&20..&2F) - change mode, but create no OTF primitives initially.
+Modes 48..63 (&30..&3F) - change mode, and create full screen black rectangle.
+Modes 64..79 (&40..&4F) - change mode, and create full screen text area.
+ +NOTE: The video timing settings for several of these +video modes are still in flux, and may need adjusting, +after some experimentation, +so be aware, when using any OTF modes. + +32/48/64 (&20/&30/&40): 800x600 @ 60Hz, 100x75 (positive synchs)
+33/49/65 (&21/&31/&41): 800x600 @ 60Hz, 100x75 (negative synchs)
+34/50/66 (&22/&32/&42): 684x384 @ 60Hz, 85x48
+35/51/67 (&23/&33/&43): 640x512 @ 60Hz, 80x64
+36/52/68 (&24/&34/&44): 640x480 @ 60Hz, 80x60
+37/53/69 (&25/&35/&45): 640x240 @ 60Hz, 80x30
+38/54/70 (&26/&36/&46): 512x384 @ 60Hz, 64x48
+39/55/71 (&27/&37/&47): 320x240 @ 60Hz, 40x30
+40/56/72 (&28/&38/&48): 320x200 @ 75Hz, 40x25
+41/57/73 (&29/&39/&49): 320x200 @ 70Hz, 40x25
+42/58/74 (&2A/&3A/&4A): 1024x768 @ 60Hz, 128x96
+43/59/75 (&2B/&3B/&4B): 1280x720 @ 60Hz, 160x90
+44/60/76 (&2C/&3C/&4C): 1368x768 @ 60Hz, TBD
+45/61/77 (&2D/&3D/&4D): reserved
+46/62/78 (&2E/&3E/&4E): reserved
+47/63/79 (&2F/&3F/&4F): reserved
+ +IMPORTANT: At present, once an application enters one +of the OTF video modes, whether by program statement or by user +entry at the command prompt, there is no way to exit the OTF mode, and go into a different mode, without resetting the Agon! +Being able to change modes will be a future enhancement. + +# OTF Function Codes + +The OTF mode uses VDU 23, 30 as its command signature for defining and processing drawing primitives. +Most links below point to document sections describing the available commands in OTF mode; +however, not all of these commands have +been implemented yet, and the sections are subject to change! + +# Document Sections + +
[Bitmap Primitive](otf_bitmap.md) +
[Code Generation](otf_code_gen.md) +
[Ellipse Primitive](otf_ellipse.md) +
[Group Primitive](otf_group.md) +
[Line Primitive](otf_line.md) +
[OTF Colors](otf_colors.md) +
[OTF Critical Section](otf_critical.md) +
[OTF Strategy](otf_strategy.md) +
[Point Primitive](otf_point.md) +
[Primitive Commands](otf_primitive.md) +
[Primitive Flags](otf_flags.md) +
[Rectangle Primitive](otf_rectangle.md) +
[Text Area Primitive](otf_text_area.md) +
[Tile Array Primitive](otf_tile_array.md) +
[Tile Map Primitive](otf_tile_map.md) +
[Triangle Primitive](otf_triangle.md) diff --git a/video/src/docs/otf_point.md b/video/src/docs/otf_point.md new file mode 100644 index 00000000..227c735b --- /dev/null +++ b/video/src/docs/otf_point.md @@ -0,0 +1,13 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Point +VDU 23, 30, 10, id; pid; flags; x; y; color : Create primitive: Point + +This command creates a primitive that draws a point (sets a single pixel). + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Point](point.png) + + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_primitive.md b/video/src/docs/otf_primitive.md new file mode 100644 index 00000000..80d46975 --- /dev/null +++ b/video/src/docs/otf_primitive.md @@ -0,0 +1,52 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Set flags for primitive +VDU 23, 30, 0, id; flags; : Set flags for primitive + +This command modifies certain flag bits for a primitive. Some flag bits are fixed upon creation +of the primitive, and cannot be changed. Refer to the OTF Primitive +Flags section, above, for more information. + +## Set primitive position +VDU 23, 30, 1, id; x; y; : Set primitive position + +If a primitive is not using the PRIM_FLAG_ABSOLUTE flag, then +this command sets the relative position of the primitive, with respect to its parent's position. If the +parent is at (100, 100), then setting the primitive's position to (5, 5) will +place the primitive at position (105, 105), relative to the primitive's grandparent (if any), +or in other words, at a 5-pixel offset from its parent, in X and Y. + +If a primitive is using the PRIM_FLAG_ABSOLUTE flag, then this command +sets the absolute position of the primitive, and that position is relative to the screen, +not to the parent. + +## Adjust primitive position +VDU 23, 30, 2, id; x; y; : Adjust primitive position + +If a primitive is not using the PRIM_FLAG_ABSOLUTE flag, then +this command ajusts the relative position of the primitive, with respect to its parent's position. If the +parent is at (100, 100), and the primitive is at (5, 5) then adjusting the primitive's position by (2, 2) will +place the primitive at position (107, 107), relative to the primitive's grandparent (if any), +or in other words, at a 7-pixel offset from its parent, in X and Y. + +If a primitive is using the PRIM_FLAG_ABSOLUTE flag, then this command +adjusts the absolute position of the primitive, and that position is relative to the screen, +not to the parent. + +## Delete primitive +VDU 23, 30, 3, id; : Delete primitive + +This command deletes the primitive, and any children that it has. If +the primitive, such as a tile map, holds its own bitmaps, those will be +deleted with the primitive. Bear in mind that you can hide a +primitive by changing its flags, while still keeping it intact. + +## Generate code for primitive +VDU 23, 30, 4, id; : Generate code for primitive + +This command generates dynamic code for the primitive, and any children that it has. +This command must be used after creating the primitive, and if needed, configuring +it, before the primitive will be drawn. For example, after creating a tile map and +its child bitmaps, use this command to generate code that can draw the tile map. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_quad.md b/video/src/docs/otf_quad.md new file mode 100644 index 00000000..800916a5 --- /dev/null +++ b/video/src/docs/otf_quad.md @@ -0,0 +1,52 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Quad Outline +VDU 23, 30, 60, id; pid; flags; color, x1; y1; x2; y2; x3; y3; x4; y4; : Create primitive: Quad Outline + +A quad is a 4-sided, convex polygon that does not necessarily have any internal right angles, but could. +The quad is not filled. + +## Create primitive: Solid Quad +VDU 23, 30, 61, id; pid; flags; color, x1; y1; x2; y2; x3; y3; x4; y4; : Create primitive: Solid Quad + +A quad is a 4-sided, convex polygon that does not necessarily have any internal right angles, but could. +The quad is filled, but does not have a distinct +edge color that differs from the given color. + +## Create primitive: Quad List Outline +VDU 23, 30, 62, id; pid; flags; n; color, x1; y1; ... : Create primitive: Quad List Outline + +A quad list is a series of quads that do not necessarily share points, but could, if those points are duplicated. They may be located together or apart. For each quad, its 4 points must be specified. + +The "n" parameter is the number of quads, so the total number of points specified equals n*4. + +## Create primitive: Solid Quad List +VDU 23, 30, 63, id; pid; flags; n; color, x1; y1; ... : Create primitive: Solid Quad List + +A quad list is a series of quads that do not necessarily share points, but could, if those points are duplicated. +The quads are filled, but do not have a distinct +edge color that differs from the given color. + +The "n" parameter is the number of quads, so the total number of points specified equals n*4. + +## Create primitive: Quad Strip Outline +VDU 23, 30, 64, id; pid; flags; n; color, sx0; sy0; sx1; sy1; x1; y1; ... : Create primitive: Quad Strip Outline + +A quad strip is a series of quads where each 2 consecutive quads share 2 common points. The quads are not filled. + +The "n" parameter is the number of quads, so the total number of points specified equals n*2+2. + +## Create primitive: Solid Quad Strip +VDU 23, 30, 65, id; pid; flags; n; color, sx0; sy0; sx1; sy1; x1; y1; ... : Create primitive: Solid Quad Strip + +A quad strip is a series of quads where each 2 consecutive quads share 2 common points. The quads are filled, but do not have a distinct +edge color that differs from the given color. + +The "n" parameter is the number of quads, so the total number of points specified equals n*2+2. + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Quad](quad.png) + + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_rectangle.md b/video/src/docs/otf_rectangle.md new file mode 100644 index 00000000..4fe14acc --- /dev/null +++ b/video/src/docs/otf_rectangle.md @@ -0,0 +1,24 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Rectangle Outline +VDU 23, 30, 40, id; pid; flags; x; y; w; h; color : Create primitive: Rectangle Outline + +This commmand creates a primitive that draws the outline of a rectangle. The rectangle is not filled. Note that the width and +height are given, not the diagonal coordinates. + +## Create primitive: Solid Rectangle +VDU 23, 30, 41, id; pid; flags; x; y; w; h; color : Create primitive: Solid Rectangle + +This commmand creates a primitive that draws a solid, filled rectangle. +The rectangle does not have a distinct outline with a different +color than the fill color. +Note that the width and height are given, not the diagonal coordinates. + +OTF mode will automatically set the PRIM_FLAGS_ALL_SAME flag +when this command is used. + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Rectangle](rectangle.png) + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_render.md b/video/src/docs/otf_render.md new file mode 100644 index 00000000..40f96958 --- /dev/null +++ b/video/src/docs/otf_render.md @@ -0,0 +1,270 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Introduction to 3D Render Commands + +A 3D scene is composed of one or more object models (meshes), each of which uses +some texture for colorizing the model. A texture uses a bitmap for its +pixel colors, and the model uses texture coordinates to assign colors to its +surfaces when the render is performed. + +There are various mathematical computations involved in 3D rendering, of course, +and floating point numbers are used for many of those computations. However, VDU +commands do not directly support passing floating point numbers, as the VDU statement +only supports passing 1-byte and 2-byte values. For that reason, many of the +values passed to the render commands are scaled values. + +The commands below use numbers with the following meaning and ranges: +

id: A specific primitive ID in the range 0 to 65535, where 0 is the root primitve. +In this document, it refers to a render primitive, which is an enhanced bitmap primitive. +

pid: A parent primitive ID in the range 0 to 65535, where 0 is the root primitve. +

mid: A specific mesh ID in the range 0 to 65535. This is not a primitive ID. +

oid: A specific object ID in the range 0 to 65535. This is not a primitive ID. +

flags: Refer to the Primitive Flags section of this document. +

n: A positive number (count) of things that follow within the same command. +

x: A 2D X coordinate in the range -32768 to +32767. Often, the value is in or near the range of 0 to 800. +

y: A 2D Y coordinate in the range -32768 to +32767. Often, the value is in or near the range of 0 to 600. +

w: A positive width that typically ranges from 1 to 800. +

h: A positive height that typically ranges from 1 to 600. +

x0, y0, z0: A prescaled 3D X, Y, or Z coordinate in the range -32767 to +32767. +This number is divided by 32767 to yield a floating point number in the range -1.0 to +1.0, for 3D computations. +To prescale a set of coordinates for use in a VDU command, scale them all to fit within the range -1.0 to +1.0, +then multiply the original floating point values by 32767. +``` +F = FACTOR * 32767 +PX = X * F +PY = Y * F +PZ = Z * F +VDU ... PX; PY; PZ; ... +``` +

i0: A zero-based index into a list of coordinates (mesh or texture). +

u0, v0: A texture coordinate ranging from 0 to the width or height of the texture. +This value is divided by the texture width or height to yield a floating point number, for 3D computations. +To prescale a set of coordinates for use in a VDU command, scale them all to fit within the range 0.0 to +1.0, +then multiply the original floating point values by the texture width or height, as appropriate. +``` +PU = U * FACTOR * TEXWIDTH +PV = V * FACTOR * TEXHEIGHT +VDU ... PU; PV; ... +``` +

scalex, scaley, scalez: A prescaled 3D X, Y, or Z scale value in the range 0 to 65535. +This number is divided by 256 to yield a floating point number in the approximate range 0.0 to 256.0, for 3D computations. +To prescale a set of scale factors for use in a VDU command, multiply them by 256. +``` +F = 256 +PSX = SX * F +PSY = SY * F +PSZ = SZ * F +VDU ... PSX; PSY; PSZ; ... +``` +

anglex, angley, anglez: A prescaled 3D X, Y, or Z rotation angle value in the range -32767 to +32767. +This number is divided by 32767 to yield a floating point number in the range -1.0 to +1.0, for 3D computations. +The resulting number is multiplied by 2PI, to yield an angle in radians. +Thus, the passed value of -32767 means -2PI, and +32767 means +2PI. +To prescale a set of angles in radians for use in a VDU command, divide the angles by 2PI, which will +scale them all to fit within the range -1.0 to +1.0, +then multiply the original floating point values by 32767. +``` +F = 32767 / TWOPI +PAX = AX * F +PAY = AY * F +PAZ = AZ * F +VDU ... PAX; PAY; PAZ; ... +``` +

distx, disty, distz: A prescaled 3D X, Y, or Z translation distance in the range -32767 to +32767. +This number is divided by 32767 to yield a floating point number in the range -1.0 to +1.0, for 3D computations. +The resulting number is multiplied by 256.0. +Thus, the passed value of -32767 means -256.0, and +32767 means +256.0. +To prescale a set of distances for use in a VDU command, divide the distances by 256, +scale them all to fit within the range -1.0 to +1.0, +then multiply the original floating point values by 32767. +``` +F = 256 +PDX = DX * F +PDY = DY * F +PDZ = DZ * F +VDU ... PDX; PDY; PDZ; ... +``` +
+ +## Create primitive: Solid Render +VDU 23, 30, 200, id; pid; flags; x; y; w; h; psram : Create primitive: Solid Render + +This command creates a primitive that renders a 3D scene to a bitmap. The bitmap can be +manipulated or altered using the bitmap primitive commands, after the scene image +has been rendered. A scene may contain multiple objects. This render primitive must be +created prior to using other 3D related commands, below. + +A solid render has pixels that are all 100% opaque (0% transparent). + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create primitive: Masked Render +VDU 23, 30, 201, id; pid; flags; x; y; w; h; psram, color : Create primitive: Masked Render + +This command creates a primitive that renders a 3D scene to a bitmap. The bitmap can be +manipulated or altered using the bitmap primitive commands, after the scene image +has been rendered. A scene may contain multiple objects. This render primitive must be +created prior to using other 3D related commands, below. + +A masked render has pixels that are all either 100% opaque (0% transparent) or +0% opaque (100% transparent). The given color is used as the transparency color, +and should be a color (including its alpha bits) that is not likely to appear in +the rendered image. For example, if the image will have no dark red pixels that are 25% +opaque, then the color could be specified as 1 or &01 in BASIC (0x01 in C). + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create primitive: Transparent Render +VDU 23, 30, 202, id; pid; flags; x; y; w; h; psram, color : Create primitive: Transparent Render + +This command creates a primitive that renders a 3D scene to a bitmap. The bitmap can be +manipulated or altered using the bitmap primitive commands, after the scene image +has been rendered. A scene may contain multiple objects. This render primitive must be +created prior to using other 3D related commands, below. + +A transparent render has pixels that are 100% opaque (0% transparent), 75% opaque +(25% transparent), 50% opaque (50% transparent), 25% opaque (75% transparent), or +0% opaque (100% transparent). The given color is used as the transparency color, +and should be a color (including its alpha bits) that is not likely to appear in +the rendered image. For example, if the image will have no dark red pixels that are 25% +opaque, then the color could be specified as 1 or &01 in BASIC (0x01 in C). + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Define Mesh Vertices +VDU 23, 30, 203, id; mid; n; x0; y0; z0; ... : Define Mesh Vertices + +This command establishes the list of mesh coordinates to be used to define +a surface structure. The mesh may be referenced by multiple objects. + +The "n" parameter is the number of vertices, so the total number of coordinates specified equals n*3. + +## Set Mesh Vertex Indices +VDU 23, 30, 204, id; mid; n; i0; ... : Set Mesh Vertex Indices + +This command lists the indexes of the vertices that define a 3D mesh. Individual +vertices are often referenced multiple times within a mesh, because they are +often part of multiple surface triangles. Each index value ranges from 0 to +the number of defined mesh vertices. + +The "n" parameter is the number of indices. + +## Define Texture Coordinates +VDU 23, 30, 205, id; mid; n; u0; v0; ... : Define Texture Coordinates + +This command establishes the list of U/V texture coordinates that define texturing +for a mesh. + +The "n" parameter is the number of coordinate pairs, so the total number of coordinates specified equals n*2. + +## Set Texture Coordinate Indices +VDU 23, 30, 206, id; mid; n; i0; ... : Set Texture Coordinate Indices + +This command lists the indexes of the coordinates that define a 3D texture for a mesh. +Individual coordinates may be referenced multiple times within a texture, +but that is not required. The number of indices passed in this command must match +the number of mesh indices defining the mesh. Thus, each mesh vertex has texture +coordinates associated with it. + +The "n" parameter is the number of indices. + +## Define Object +VDU 23, 30, 207, id; oid; mid; bmid; : Create Object + +This command defines a renderable object in terms of its already-defined mesh, +plus a reference to an existing bitmap that provides its coloring, via the +texture coordinates used by the mesh. The same mesh can be used multiple times, +with the same or different bitmaps for coloring. + +## Set Object X Scale Factor +VDU 23, 30, 208, id; oid; scalex; : Set Object X Scale Factor + +This command sets the X scale factor for an object. + +## Set Object Y Scale Factor +VDU 23, 30, 209, id; oid; scaley; : Set Object Y Scale Factor + +This command sets the Y scale factor for an object. + +## Set Object Z Scale Factor +VDU 23, 30, 210, id; oid; scalez; : Set Object Z Scale Factor + +This command sets the Z scale factor for an object. + +## Set Object XYZ Scale Factors +VDU 23, 30, 211, id; oid; scalex; scaley; scalez : Set Object XYZ Scale Factors + +This command sets the X, Y, and Z scale factors for an object. + +## Set Object X Rotation Angle +VDU 23, 30, 212, id; oid; anglex; : Set Object X Rotation Angle + +This command sets the X rotation angle for an object. + +## Set Object Y Rotation Angle +VDU 23, 30, 213, id; oid; angley; : Set Object Y Rotation Angle + +This command sets the Y rotation angle for an object. + +## Set Object Z Rotation Angle +VDU 23, 30, 214, id; oid; anglez; : Set Object Z Rotation Angle + +This command sets the Z rotation angle for an object. + +## Set Object XYZ Rotation Angles +VDU 23, 30, 215, id; oid; anglex; angley; anglez; : Set Object XYZ Rotation Angles + +This command sets the X, Y, and Z rotation angles for an object. + +## Set Object X Translation Distance +VDU 23, 30, 216, id; oid; distx; : Set Object X Translation Distance + +This command sets the X translation distance for an object. +Note that 3D translation of an object is independent of 2D translation of the bitmap +belonging to the render primitive. + +## Set Object Y Translation Distance +VDU 23, 30, 217, id; oid; disty; : Set Object Y Translation Distance + +This command sets the Y translation distance for an object. +Note that 3D translation of an object is independent of 2D translation of the bitmap +belonging to the render primitive. + +## Set Object Z Translation Distance +VDU 23, 30, 218, id; oid; distz; : Set Object Z Translation Distance + +This command sets the Z translation distance for an object. +Note that 3D translation of an object is independent of 2D translation of the bitmap +belonging to the render primitive. + +## Set Object XYZ Translation Distances +VDU 23, 30, 219, id; oid; distx; disty; distz : Set Object XYZ Translation Distances + +This command sets the X, Y, and Z translation distances for an object. +Note that 3D translation of an object is independent of 2D translation of the bitmap +belonging to the render primitive. + +## Render To Bitmap +VDU 23, 30, 220, id; : Render To Bitmap + +This command uses information provided by the above commands to render the 3D scene +onto the bitmap belonging to the render primitive. This command must be used in +order to perform the render operation; it does not happen automatically, when other +commands change some of the render parameters. + +The following image illustrates the concept. + +![Render](render.png) + + +[Bitmap](otf_bitmap.md) +[Home](otf_mode.md) diff --git a/video/src/docs/otf_strategy.md b/video/src/docs/otf_strategy.md new file mode 100644 index 00000000..9c08e498 --- /dev/null +++ b/video/src/docs/otf_strategy.md @@ -0,0 +1,36 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +# OTF Strategy + +In the OTF mode, each drawing primitive is a node in a tree of primitives. The tree branches (nesting) can +serve to affect how primitives are moved, drawn, and clipped. For example, in the simplest case, if primitve B +is a child of primitive A, and A is moved (in X and/or Y), then B is moved along with A, so that its relative +postion with respect to A does not change, but its physical position on the display does change. Thus, an entire array of enemy ships can +be moved simply by moving a single "group" primitive that is the parent of all of the ships. + +The Z-order of drawing primitives is based on their primitive IDs, not on their order +of creation, and not on their parent-child relationships. This means that if you want to +guarantee that a child primitive is always drawn after (over) the parent primitive, you +must create the child with an ID that is greater than the ID of the parent. + +Another important aspect of how the OTF mode works is that it must keep all primitives in internal RAM, +so that it can draw them repeatedly, without being told to do so by the BASIC (EZ80) application. Since +the ESP32 holds the primitives in RAM, they can easily be manipulated (e.g., moved), without sending +all of the information required to recreate them across the serial channel. VDP-GL already does something +similar with bitmaps and sprites, but as a Fab-GL derivative, not with simpler primitives such as lines and triangles. However, +enhancements are in the works that allow VDP-GL to create buffered +commands, so that it can replay them without a large data transfer. + +Bitmap primitives can have their pixel data stored in PSRAM (external SPI RAM), to save memory space +in the internal DRAM; however, using PSRAM is slower, and can cause flicker at higher resolutions. + +When primitives are no longer needed by the BASIC application, they may be deleted. Deleting a group +primitive will delete its children, too, reducing the number of serial commands required to delete +the parent and all of its children. + +One other benefit of keeping the primitives in RAM is the ability to turn them on and off, meaning +to show them or to hide them, very easily, just by changing their flag bits. For example, a blinking +cursor could be actuated just by changing its flag bit for being painted (drawn). The cursor itself can +be any primitive (a point, line, rectangle, etc.), based on the needs of the application. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_text_area.md b/video/src/docs/otf_text_area.md new file mode 100644 index 00000000..00ec7395 --- /dev/null +++ b/video/src/docs/otf_text_area.md @@ -0,0 +1,73 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Text Area +VDU 23, 30, 150, id; pid; flags; x; y; columns; rows; fgcolor, bgcolor : Create primitive: Text Area + +This command creates a text area primitive, which is a tile array +used to show text characters. The text area supports a flashing +cursor and cursor movement as characters are written, or as +directed by certain VDU commands. + +You may create more than one text area. If you have no other full +background defined, you can use a full-screen text area as the +background, by creating it with 100 columns and 75 rows, +resulting in 800x600 pixel coverage. + +At present, the only font available for a text area is the +built-in Agon system font (8x8 pixel characters), so there +is no font specified in this command. If other fonts are used +in the future, a new command will be added to the OTF mode. + +When a text area is created, the OTF manager also creates a cursor +for it, which is a child primitive to the text area, with an ID +equal to the text area's ID plus one. Be sure not to use the ID +of the cursor for some other new primitive, or the cursor will +not function properly, and your new primitive may get moved +as text area characters are displayed. + +The given foreground and background colors are set as the initial +current colors for the text area, so that when characters are printed, +they use those colors. The colors may be changed with the COLOUR statement +in BASIC, or with the proper VDU command. + +The given foreground color is also used as the color of the blinking cursor, +which is a horizontal bar by default. In the future, it may be possible to +change the appearance of the cursor. + +## Select Active Text Area +VDU 23, 30, 151, id; : Select Active Text Area + +This command tells the OTF manager which text area should be the +active text area, when more than one text area was created. This +allows, for example, two separate areas of the screen to have +independent text (and possibly in the future, independent fonts). + +## Define Text Area Character +VDU 23, 30, 152, id; char, fgcolor, bgcolor : Define Text Area Character + +This command defines a single character to be used within a text area +primitive, meaning that it both creates a bitmap and sets the +initial pixel data of the bitmap, using the font that is +referenced by the text area. + +It is possible to use multiple different colors for the same +character glyph, in a single text area, simply by defining +the character multiple times, using different colors. + +Simply printing a new character will define it automatically, meaning that this command is not absolutely necessary. + +## Define Text Area Character Range +VDU 23, 30, 153, id; firstchar, lastchar, fgcolor, bgcolor : Define Text Area Character Range + +This command defines a range of characters to be used within a text area +primitive, meaning that it both creates the bitmaps and sets the +initial pixel data of the bitmaps, using the font that is +referenced by the text area. + +It is possible to use multiple different colors for the same +character glyphs, in a single text area, simply by defining +the characters multiple times, using different colors. + +Simply printing a new character will define it automatically, meaning that this command is not absolutely necessary. + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_tile_array.md b/video/src/docs/otf_tile_array.md new file mode 100644 index 00000000..d02065c7 --- /dev/null +++ b/video/src/docs/otf_tile_array.md @@ -0,0 +1,173 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Tile Array +VDU 23, 30, 80, id; pid; flags; columns; rows; tw; th; w; h; : Create primitive: Tile Array + +This commmand creates a primitive that draws a full or mostly full tile array, as opposed to a sparse tile map. +The number of cells in the array is equal to the number of rows +multiplied by the number of columns. The given tile width and tile height +specify the size of a single tile. The overall width and height of the tile +array are specified separately. + +The given width must be a multiple of 4 pixels. The given height can be any positive number, bearing in mind the memory requirements for +storing bitmaps. + +The tile array will store its own setup of bitmaps, which are distinct +from any bitmaps created as individual primitives. If the +tile array is deleted, its owned bitmaps are deleted with it. + +A tile array is intended to be used when the ratio of defined +(used) cells to undefined (unused) cells is rather high. Since it +is implemented as an array, processing it is faster than using a +tile map. The trade-off is that the entire array is allocated +from RAM, so it may be more expensive than a sparse tile map. +Thus, if you want a set of tiles with a low used-to-unused ratio, +consider using a tile map, to avoid wasting space for unused cells. + +Even though a tile array is fully allocated, each cell is just a pointer +to the pixel data for some tile bitmap (such bitmaps can be shared), and that pointer can be NULL, +in which case, nothing is drawn for the corresponding cell. In that +manner, you can create an array that appears to be sparse. Such is +the case with random-length text lines in the text area primitive, +which is a tile array. + +## Create Solid Bitmap for Tile Array +VDU 23, 30, 81, id; pid; flags; w; h; psram : Create Solid Bitmap for Tile Array + +This commmand creates a solid bitmap to be used within a tile array. +Every pixel is fully opaque (though each pixel has its own color). +A solid bitmap may be the most efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower, and their overuse could cause flicker. + +OTF mode will automatically set the PRIM_FLAGS_ALL_SAME flag +when this command is used. + +If you create a text area primitive, which is a tile array, and +use the Define Text Area Character or Define Text Area Character +Range command, then the required solid bitmap(s) is(are) +created automatically. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create Masked Bitmap for Tile Array +VDU 23, 30, 82, id; pid; flags; w; h; psram, color : Create Masked Bitmap for Tile Array + +This command code is reserved for potential future use. +The command is not presently implemented. + +This commmand creates a masked bitmap to be used within a tile array. +Every pixel is either fully opaque (though each pixel has its own color) or fully transparent. +A solid bitmap may be the most efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower, and their overuse could cause flicker. + +The given color is used to represent fully transparent pixels, +so be sure to specify a byte value that is unique from any +visible color in the source bitmap. When setting the color of +each pixel in the bitmap, use that given color for any pixels +that must be invisible. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create Transparent Bitmap for Tile Array +VDU 23, 30, 83, id; pid; flags; w; h; psram, color : Create Transparent Bitmap for Tile Array + +This command code is reserved for potential future use. +The command is not presently implemented. + +This commmand creates a transparent bitmap to be used within a tile array. +Each pixel has either 0%, 25%, 50%, 75%, or 100% opacity. +A transparent bitmap may be the least efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower than solid bitmaps, and their overuse could cause flicker. + +The given color is used to represent fully transparent pixels, +so be sure to specify a byte value that is unique from any +visible color in the source bitmap. When setting the color of +each pixel in the bitmap, use that given color for any pixels +that must be invisible. + +OTF mode will automatically set the PRIM_FLAGS_BLENDED flag +when this command is used. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Set bitmap ID for tile in tile array +VDU 23, 30, 84, id; column; row; bmid; : Set bitmap ID for tile in Tile Array + +This command specifies which bitmap should be draw in a specific +cell of a tile array. The bitmap must have been created already. +Passing a zero for the bitmap ID will prevent the cell from +being drawn, so it will appear as an empty cell. + +## Set solid bitmap pixel in tile array +VDU 23, 30, 85, id; bmid; x; y; color : Set solid bitmap pixel in Tile Array + +This command sets the color of a single pixel within a solid +bitmap that belongs to a tile array. + +## Set masked bitmap pixel in tile array +VDU 23, 30, 86, id; bmid; x; y; color : Set masked bitmap pixel in Tile Array + +This command sets the color of a single pixel within a masked +bitmap that belongs to a tile array. +To specify a fully transparent pixel, use the same color that +was used to create the tile bitmap. + +## Set transparent bitmap pixel in tile array +VDU 23, 30, 87, id; bmid; x; y; color : Set transparent bitmap pixel in Tile Array + +This command sets the color of a single pixel within a transparent +bitmap that belongs to a tile array. +To specify a fully transparent pixel, use the same color that +was used to create the tile bitmap. + +## Set solid bitmap pixels in tile array +VDU 23, 30, 88, id; bmid; x; y; n; c0, c1, c2, ... : Set solid bitmap pixels in Tile Array + +This command sets the colors of multiple pixels within a tile array. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. + +The "n" parameter is the number of pixels. + +## Set masked bitmap pixels in tile array +VDU 23, 30, 89, id; bmid; x; y; n; c0, c1, c2, ... : Set masked bitmap pixels in Tile Array + +This command sets the colors of multiple pixels within a tile array. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. + +The "n" parameter is the number of pixels. + +## Set transparent bitmap pixels in tile array +VDU 23, 30, 90, id; bmid; x; y; n; c0, c1, c2, ... : Set transparent bitmap pixels in Tile Array + +This command sets the colors of multiple pixels within a tile array. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. + +The "n" parameter is the number of pixels. + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Tile Array](tile_array.png) + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_tile_map.md b/video/src/docs/otf_tile_map.md new file mode 100644 index 00000000..4d1ec01a --- /dev/null +++ b/video/src/docs/otf_tile_map.md @@ -0,0 +1,158 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Tile Map +VDU 23, 30, 100, id; pid; flags; columns; rows; tw; th; w; h; : Create primitive: Tile Map + +This commmand creates a primitive that draws a sparse tile map, +as opposed to a full or mostly full tile array. +The number of cells in the map is equal to the number of rows +multiplied by the number of columns. The given tile width and tile height +specify the size of a single tile. The overall width and height of the tile +map are specified separately. + +The given width must be a multiple of 4 pixels. The given height can be any positive number, bearing in mind the memory requirements for +storing bitmaps. + +The tile map will store its own setup of bitmaps, which are distinct +from any bitmaps created as individual primitives. If the +tile map is deleted, its owned bitmaps are deleted with it. + +A sparse tile map is intended to be used when the ratio of defined +(used) cells to undefined (unused) cells is rather low. Since it +is implemented as a map, processing it is slower than using a +tile array. Thus, if you want a set of tiles with a high used-to-unused ratio, +it would be more efficient to use a tile array. Slower processing +might cause flicker. + +Refer to the section on OTF Primitive Flags for information about +certain flags that are useful for tile maps. + +## Create Solid Bitmap for Tile Map +VDU 23, 30, 101, id; bmid; psram : Create Solid Bitmap for Tile Map + +This commmand creates a solid bitmap to be used within a tile map. +Every pixel is fully opaque (though each pixel has its own color). +A solid bitmap may be the most efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower, and their overuse could cause flicker. + +OTF mode will automatically set the PRIM_FLAGS_ALL_SAME flag +when this command is used. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create Masked Bitmap for Tile Map +VDU 23, 30, 102, id; bmid; psram, color : Create Masked Bitmap for Tile Map + +This commmand creates a masked bitmap to be used within a tile map. +Every pixel is either fully opaque (though each pixel has its own color) or fully transparent. +A solid bitmap may be the most efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower, and their overuse could cause flicker. + +The given color is used to represent fully transparent pixels, +so be sure to specify a byte value that is unique from any +visible color in the source bitmap. When setting the color of +each pixel in the bitmap, use that given color for any pixels +that must be invisible. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Create Transparent Bitmap for Tile Map +VDU 23, 30, 103, id; bmid; psram, color : Create Transparent Bitmap for Tile Map + +This commmand creates a transparent bitmap to be used within a tile map. +Each pixel has either 0%, 25%, 50%, 75%, or 100% opacity. +A transparent bitmap may be the least efficient kind of bitmap, from a +processing speed perspective. Bitmaps with any transparency may be slower than solid bitmaps, and their overuse could cause flicker. + +The given color is used to represent fully transparent pixels, +so be sure to specify a byte value that is unique from any +visible color in the source bitmap. When setting the color of +each pixel in the bitmap, use that given color for any pixels +that must be invisible. + +OTF mode will automatically set the PRIM_FLAGS_BLENDED flag +when this command is used. + +If the psram parameter is nonzero, the bitmap pixels are kept in PSRAM (SPI RAM) +rather than in DRAM. This should only be done in resolutions where the pixel clock +rate is relatively slow, or the total size of bitmaps coming from PSRAM is +relatively small; otherwise, flicker may occur. + +## Set bitmap ID for tile in tile map +VDU 23, 30, 104, id; col; row; bmid; : Set bitmap ID for tile in Tile Map + +This command specifies which bitmap should be draw in a specific +cell of a tile map. The bitmap must have been created already. +Passing a zero for the bitmap ID will prevent the cell from +being drawn, so it will appear as an empty cell. + +## Set solid bitmap pixel in tile map +VDU 23, 30, 105, id; bmid; x; y; color : Set solid bitmap pixel in Tile Map + +This command sets the color of a single pixel within a solid +bitmap that belongs to a tile map. + +## Set masked bitmap pixel in tile map +VDU 23, 30, 106, id; bmid; x; y; color : Set masked bitmap pixel in Tile Map + +This command sets the color of a single pixel within a masked +bitmap that belongs to a tile map. +To specify a fully transparent pixel, use the same color that +was used to create the tile bitmap. + +## Set transparent bitmap pixel in tile map +VDU 23, 30, 107, id; bmid; x; y; color : Set transparent bitmap pixel in Tile Map + +This command sets the color of a single pixel within a transparent +bitmap that belongs to a tile map. +To specify a fully transparent pixel, use the same color that +was used to create the tile bitmap. + +## Set solid bitmap pixels in tile map +VDU 23, 30, 108, id; bmid; x; y; n; c0, c1, c2, ... : Set solid bitmap pixels in Tile Map + +This command sets the colors of multiple pixels within a tile map. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. + +The "n" parameter is the number of pixels. + +## Set masked bitmap pixels in tile map +VDU 23, 30, 109, id; bmid; x; y; n; c0, c1, c2, ... : Set masked bitmap pixels in Tile Map + +This command sets the colors of multiple pixels within a tile map. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. + +The "n" parameter is the number of pixels. + +## Set transparent bitmap pixels in tile map +VDU 23, 30, 110, id; bmid; x; y; n; c0, c1, c2, ... : Set transparent bitmap pixels in Tile Map + +This command sets the colors of multiple pixels within a tile map. +As colors are processed, if the end of a scan line in the +bitmap is reached, processing moves to the first pixel in +the next scan line. Thus, it is possible to provide colors +for every pixel in the bitmap, using a single command. +To specify a fully transparent pixel, use the same color that +was used to create the bitmap. + +The "n" parameter is the number of pixels. + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Tile Map](tile_map.png) + +[Home](otf_mode.md) diff --git a/video/src/docs/otf_triangle.md b/video/src/docs/otf_triangle.md new file mode 100644 index 00000000..83deea2d --- /dev/null +++ b/video/src/docs/otf_triangle.md @@ -0,0 +1,68 @@ +This is an early release of the OTF capability. Please read [Issues and Considerations](otf_issues.md)! + +## Create primitive: Triangle Outline +VDU 23, 30, 30, id; pid; flags; color, x1; y1; x2; y2; x3; y3; : Create primitive: Triangle Outline + +This commmand creates a primitive that draws the outline of a triangle. The triangle is not filled. + +## Create primitive: Solid Triangle +VDU 23, 30, 31, id; pid; flags; color, x1; y1; x2; y2; x3; y3; : Create primitive: Solid Triangle + +This commmand creates a primitive that draws a solid, filled +traingle. The triangle does not have a distinct outline with +a different color than the fill color. + +## Create primitive: Triangle List Outline +VDU 23, 30, 32, id; pid; flags; n; color, x1; y1; ... : Create primitive: Triangle List Outline + +This command creates a series of separate triangle outlines. + +A triangle list is a series of triangles that do not necessarily share points, but could, if those points are duplicated. They may be located together or apart. For each triangle, its 3 points must be specified. The triangles are not filled. + +The "n" parameter is the number of triangles, so the total number of points specified equals n*3. + +## Create primitive: Solid Triangle List +VDU 23, 30, 33, id; pid; flags; n; color, x1; y1; ... : Create primitive: Solid Triangle List + +A triangle list is a series of triangles that do not necessarily share points, but could, if those points are duplicated. They may be located together or apart. For each triangle, its 3 points must be specified. The triangles are filled, but do not have a distinct +edge color that differs from the given color. + +The "n" parameter is the number of triangles, so the total number of points specified equals n*3. + +## Create primitive: Triangle Fan Outline +VDU 23, 30, 34, id; pid; flags; n; color, sx0; sy0; sx1; sy1; x1; y1; ... : Create primitive: Triangle Fan Outline + +A triangle fan is a series of triangles that share a common center point, and each 2 consecutive triangles share an edge point. +The triangles are not filled. + +The "n" parameter is the number of triangles, so the total number of points specified equals n+2. + +## Create primitive: Solid Triangle Fan +VDU 23, 30, 35, id; pid; flags; n; color, sx0; sy0; sx1; sy1; x1; y1; ... : Create primitive: Solid Triangle Fan + +A triangle fan is a series of triangles that share a common center point, and each 2 consecutive triangles share an edge point. +The triangles are filled, but do not have a distinct +edge color that differs from the given color. + +The "n" parameter is the number of triangles, so the total number of points specified equals n+2. + +## Create primitive: Triangle Strip Outline +VDU 23, 30, 36, id; pid; flags; n; color, sx0; sy0; sx1; sy1; x1; y1; ... : Create primitive: Triangle Strip Outline + +A triangle strip is a series of triangles where each 2 consecutive triangles share 2 common points. The triangles are not filled. + +The "n" parameter is the number of triangles, so the total number of points specified equals n+2. + +## Create primitive: Solid Triangle Strip +VDU 23, 30, 37, id; pid; flags; n; color, sx0; sy0; sx1; sy1; x1; y1; ... : Create primitive: Solid Triangle Strip + +A triangle strip is a series of triangles where each 2 consecutive triangles share 2 common points. The triangles filled, but do not have a distinct +edge color that differs from the given color. + +The "n" parameter is the number of triangles, so the total number of points specified equals n+2. + +The following image illustrates the concepts, but the actual appearances will differ on the Agon, because this image was created on a PC. + +![Triangle](triangle.png) + +[Home](otf_mode.md) diff --git a/video/src/docs/point.png b/video/src/docs/point.png new file mode 100644 index 00000000..08cae435 Binary files /dev/null and b/video/src/docs/point.png differ diff --git a/video/src/docs/quad.png b/video/src/docs/quad.png new file mode 100644 index 00000000..30f9ab56 Binary files /dev/null and b/video/src/docs/quad.png differ diff --git a/video/src/docs/rectangle.png b/video/src/docs/rectangle.png new file mode 100644 index 00000000..9e1dcb47 Binary files /dev/null and b/video/src/docs/rectangle.png differ diff --git a/video/src/docs/render.png b/video/src/docs/render.png new file mode 100644 index 00000000..23228205 Binary files /dev/null and b/video/src/docs/render.png differ diff --git a/video/src/docs/tile_array.png b/video/src/docs/tile_array.png new file mode 100644 index 00000000..1b42609c Binary files /dev/null and b/video/src/docs/tile_array.png differ diff --git a/video/src/docs/tile_map.png b/video/src/docs/tile_map.png new file mode 100644 index 00000000..bb96a6d3 Binary files /dev/null and b/video/src/docs/tile_map.png differ diff --git a/video/src/docs/triangle.png b/video/src/docs/triangle.png new file mode 100644 index 00000000..92c833d6 Binary files /dev/null and b/video/src/docs/triangle.png differ diff --git a/video/src/fabgl_pieces.h b/video/src/fabgl_pieces.h new file mode 100644 index 00000000..bfe02461 --- /dev/null +++ b/video/src/fabgl_pieces.h @@ -0,0 +1,244 @@ +// +// +// Copyright (c) 2023 Curtis Whitley +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// + +struct APLLParams { + uint8_t sdm0; + uint8_t sdm1; + uint8_t sdm2; + uint8_t o_div; +}; + +void configureGPIO(gpio_num_t gpio, gpio_mode_t mode) +{ + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); + gpio_set_direction(gpio, mode); +} + +template +const T & tmax(const T & a, const T & b) +{ + return (a < b) ? b : a; +} + +template +const T & tmin(const T & a, const T & b) +{ + return !(b < a) ? a : b; +} + +// definitions: +// apll_clk = XTAL * (4 + sdm2 + sdm1 / 256 + sdm0 / 65536) / (2 * o_div + 4) +// dividend = XTAL * (4 + sdm2 + sdm1 / 256 + sdm0 / 65536) +// divisor = (2 * o_div + 4) +// freq = apll_clk / (2 + b / a) => assumes tx_bck_div_num = 1 and clkm_div_num = 2 +// Other values range: +// sdm0 0..255 +// sdm1 0..255 +// sdm2 0..63 +// o_div 0..31 +// Assume xtal = FABGLIB_XTAL (40MHz) +// The dividend should be in the range of 350 - 500 MHz (350000000-500000000), so these are the +// actual parameters ranges (so the minimum apll_clk is 5303030 Hz and maximum is 125000000Hz): +// MIN 87500000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 0 +// MAX 125000000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 0 +// +// MIN 58333333Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 1 +// MAX 83333333Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 1 +// +// MIN 43750000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 2 +// MAX 62500000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 2 +// +// MIN 35000000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 3 +// MAX 50000000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 3 +// +// MIN 29166666Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 4 +// MAX 41666666Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 4 +// +// MIN 25000000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 5 +// MAX 35714285Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 5 +// +// MIN 21875000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 6 +// MAX 31250000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 6 +// +// MIN 19444444Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 7 +// MAX 27777777Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 7 +// +// MIN 17500000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 8 +// MAX 25000000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 8 +// +// MIN 15909090Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 9 +// MAX 22727272Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 9 +// +// MIN 14583333Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 10 +// MAX 20833333Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 10 +// +// MIN 13461538Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 11 +// MAX 19230769Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 11 +// +// MIN 12500000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 12 +// MAX 17857142Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 12 +// +// MIN 11666666Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 13 +// MAX 16666666Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 13 +// +// MIN 10937500Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 14 +// MAX 15625000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 14 +// +// MIN 10294117Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 15 +// MAX 14705882Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 15 +// +// MIN 9722222Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 16 +// MAX 13888888Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 16 +// +// MIN 9210526Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 17 +// MAX 13157894Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 17 +// +// MIN 8750000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 18 +// MAX 12500000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 18 +// +// MIN 8333333Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 19 +// MAX 11904761Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 19 +// +// MIN 7954545Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 20 +// MAX 11363636Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 20 +// +// MIN 7608695Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 21 +// MAX 10869565Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 21 +// +// MIN 7291666Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 22 +// MAX 10416666Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 22 +// +// MIN 7000000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 23 +// MAX 10000000Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 23 +// +// MIN 6730769Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 24 +// MAX 9615384Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 24 +// +// MIN 6481481Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 25 +// MAX 9259259Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 25 +// +// MIN 6250000Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 26 +// MAX 8928571Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 26 +// +// MIN 6034482Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 27 +// MAX 8620689Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 27 +// +// MIN 5833333Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 28 +// MAX 8333333Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 28 +// +// MIN 5645161Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 29 +// MAX 8064516Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 29 +// +// MIN 5468750Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 30 +// MAX 7812500Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 30 +// +// MIN 5303030Hz - sdm0 = 0 sdm1 = 192 sdm2 = 4 o_div = 31 +// MAX 7575757Hz - sdm0 = 0 sdm1 = 128 sdm2 = 8 o_div = 31 +void APLLCalcParams(double freq, APLLParams * params, uint8_t * a, uint8_t * b, double * out_freq, double * error) +{ + double FXTAL = 40000000.0; + + *error = 999999999; + + double apll_freq = freq * 2; + + for (int o_div = 0; o_div <= 31; ++o_div) { + + int idivisor = (2 * o_div + 4); + + for (int sdm2 = 4; sdm2 <= 8; ++sdm2) { + + // from tables above + int minSDM1 = (sdm2 == 4 ? 192 : 0); + int maxSDM1 = (sdm2 == 8 ? 128 : 255); + // apll_freq = XTAL * (4 + sdm2 + sdm1 / 256) / divisor -> sdm1 = (apll_freq * divisor - XTAL * 4 - XTAL * sdm2) * 256 / XTAL + int startSDM1 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2) * 256.0 / FXTAL); +#if FABGLIB_USE_APLL_AB_COEF + for (int isdm1 = tmax(minSDM1, startSDM1); isdm1 <= maxSDM1; ++isdm1) { +#else + int isdm1 = startSDM1; { +#endif + + int sdm1 = isdm1; + sdm1 = tmax(minSDM1, sdm1); + sdm1 = tmin(maxSDM1, sdm1); + + // apll_freq = XTAL * (4 + sdm2 + sdm1 / 256 + sdm0 / 65536) / divisor -> sdm0 = (apll_freq * divisor - XTAL * 4 - XTAL * sdm2 - XTAL * sdm1 / 256) * 65536 / XTAL + int sdm0 = ((apll_freq * idivisor - FXTAL * 4.0 - FXTAL * sdm2 - FXTAL * sdm1 / 256.0) * 65536.0 / FXTAL); + // from tables above + sdm0 = (sdm2 == 8 && sdm1 == 128 ? 0 : tmin(255, sdm0)); + sdm0 = tmax(0, sdm0); + + // dividend inside 350-500Mhz? + double dividend = FXTAL * (4.0 + sdm2 + sdm1 / 256.0 + sdm0 / 65536.0); + if (dividend >= 350000000 && dividend <= 500000000) { + // adjust output frequency using "b/a" + double oapll_freq = dividend / idivisor; + + // Calculates "b/a", assuming tx_bck_div_num = 1 and clkm_div_num = 2: + // freq = apll_clk / (2 + clkm_div_b / clkm_div_a) + // abr = clkm_div_b / clkm_div_a + // freq = apll_clk / (2 + abr) => abr = apll_clk / freq - 2 + uint8_t oa = 1, ob = 0; +#if FABGLIB_USE_APLL_AB_COEF + double abr = oapll_freq / freq - 2.0; + if (abr > 0 && abr < 1) { + int num, den; + floatToFraction(abr, 63, &num, &den); + ob = tclamp(num, 0, 63); + oa = tclamp(den, 0, 63); + } +#endif + + // is this the best? + double ofreq = oapll_freq / (2.0 + (double)ob / oa); + double err = freq - ofreq; + if (abs(err) < abs(*error)) { + *params = (APLLParams){(uint8_t)sdm0, (uint8_t)sdm1, (uint8_t)sdm2, (uint8_t)o_div}; + *a = oa; + *b = ob; + *out_freq = ofreq; + *error = err; + if (err == 0.0) + return; + } + } + } + + } + } +} + +// if bit is -1 = clock signal +// gpio = GPIO_UNUSED means not set +void setupGPIO(gpio_num_t gpio, int bit, gpio_mode_t mode) +{ + if (bit == -1) { + // I2S1 clock out to CLK_OUT1 (fixed to GPIO0) + WRITE_PERI_REG(PIN_CTRL, 0xF); + PIN_FUNC_SELECT(GPIO_PIN_REG_0, FUNC_GPIO0_CLK_OUT1); + } else { + configureGPIO(gpio, mode); + gpio_matrix_out(gpio, I2S1O_DATA_OUT0_IDX + bit, false, false); + } +} diff --git a/video/src/pingo/LICENSE b/video/src/pingo/LICENSE new file mode 100644 index 00000000..0e259d42 --- /dev/null +++ b/video/src/pingo/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/video/src/pingo/README.md b/video/src/pingo/README.md new file mode 100644 index 00000000..836b5069 --- /dev/null +++ b/video/src/pingo/README.md @@ -0,0 +1,30 @@ + +# pingo + +Pingo is a low level 2D/3D software graphics library. It uses no dynamically allocated memory and provides a simple low level backend interface to implement for your platform. This library can easily be compiled for many different platforms since it has no dependencies except for a working C compiler, it has been tested on Windows, Linux x86, Linux ARM, ESP32, Arm Cortex M3 and even RISC V CPUs. + +The cmake project contains targets that build examples that show 3D rendering on different platforms. +``` +git clone git@github.com:fededevi/pingo.git +cd pingo +mkdir build && cd build +cmake .. && make +``` + +If you compile on Linux the default cmake project will build 3 example binaries: +- linux_window -> An example that renders to an X11 window +- linux_framebuffer -> An example that renders to a framebuffer device +- linux_terminal -> An example that renders to the terminal + +If you compile on Windows the default cmake project will build 2 example binaries: +- win_window -> An example that renders to a Windows window +- win_terminal -> An example that renders to the terminal + +Some backends like the linux framebuffer require exact dimension and pixel format, see pixel.h and this line in the example's main.c: +``` +int main(){ + Vec2i size = {300, 150}; +``` + +#### An example with texture and per-triangle shading +![Example](/public/viking.png) \ No newline at end of file diff --git a/video/src/pingo/assets/teapot.c b/video/src/pingo/assets/teapot.c new file mode 100644 index 00000000..9a3b482b --- /dev/null +++ b/video/src/pingo/assets/teapot.c @@ -0,0 +1,3476 @@ +#include "../render/mesh.h" + +#define teapot_vertices 1728 + +Vec3f positions[teapot_vertices] = { + {0.700000f, -1.200000f, 0.000000f}, + {0.605600f, -1.200000f, -0.355700f}, + {0.598800f, -1.243700f, -0.351700f}, + {0.598800f, -1.243700f, -0.351700f}, + {0.692100f, -1.243700f, 0.000000f}, + {0.700000f, -1.200000f, 0.000000f}, + {0.692100f, -1.243700f, 0.000000f}, + {0.598800f, -1.243700f, -0.351700f}, + {0.619600f, -1.243700f, -0.363900f}, + {0.619600f, -1.243700f, -0.363900f}, + {0.716200f, -1.243700f, 0.000000f}, + {0.692100f, -1.243700f, 0.000000f}, + {0.716200f, -1.243700f, 0.000000f}, + {0.619600f, -1.243700f, -0.363900f}, + {0.648900f, -1.200000f, -0.381100f}, + {0.648900f, -1.200000f, -0.381100f}, + {0.750000f, -1.200000f, 0.000000f}, + {0.716200f, -1.243700f, 0.000000f}, + {0.605600f, -1.200000f, -0.355700f}, + {0.355700f, -1.200000f, -0.605600f}, + {0.351700f, -1.243700f, -0.598800f}, + {0.351700f, -1.243700f, -0.598800f}, + {0.598800f, -1.243700f, -0.351700f}, + {0.605600f, -1.200000f, -0.355700f}, + {0.598800f, -1.243700f, -0.351700f}, + {0.351700f, -1.243700f, -0.598800f}, + {0.363900f, -1.243800f, -0.619600f}, + {0.363900f, -1.243800f, -0.619600f}, + {0.619600f, -1.243700f, -0.363900f}, + {0.598800f, -1.243700f, -0.351700f}, + {0.619600f, -1.243700f, -0.363900f}, + {0.363900f, -1.243800f, -0.619600f}, + {0.381100f, -1.200000f, -0.648900f}, + {0.381100f, -1.200000f, -0.648900f}, + {0.648900f, -1.200000f, -0.381100f}, + {0.619600f, -1.243700f, -0.363900f}, + {0.355700f, -1.200000f, -0.605600f}, + {0.000000f, -1.200000f, -0.700000f}, + {0.000000f, -1.243700f, -0.692100f}, + {0.000000f, -1.243700f, -0.692100f}, + {0.351700f, -1.243700f, -0.598800f}, + {0.355700f, -1.200000f, -0.605600f}, + {0.351700f, -1.243700f, -0.598800f}, + {0.000000f, -1.243700f, -0.692100f}, + {0.000000f, -1.243800f, -0.716200f}, + {0.000000f, -1.243800f, -0.716200f}, + {0.363900f, -1.243800f, -0.619600f}, + {0.351700f, -1.243700f, -0.598800f}, + {0.363900f, -1.243800f, -0.619600f}, + {0.000000f, -1.243800f, -0.716200f}, + {0.000000f, -1.200000f, -0.750000f}, + {0.000000f, -1.200000f, -0.750000f}, + {0.381100f, -1.200000f, -0.648900f}, + {0.363900f, -1.243800f, -0.619600f}, + {0.000000f, -1.200000f, -0.700000f}, + {-0.375700f, -1.200000f, -0.605600f}, + {-0.357600f, -1.243700f, -0.598800f}, + {-0.357600f, -1.243700f, -0.598800f}, + {0.000000f, -1.243700f, -0.692100f}, + {0.000000f, -1.200000f, -0.700000f}, + {0.000000f, -1.243700f, -0.692100f}, + {-0.357600f, -1.243700f, -0.598800f}, + {-0.364700f, -1.243700f, -0.619600f}, + {-0.364700f, -1.243700f, -0.619600f}, + {0.000000f, -1.243800f, -0.716200f}, + {0.000000f, -1.243700f, -0.692100f}, + {0.000000f, -1.243800f, -0.716200f}, + {-0.364700f, -1.243700f, -0.619600f}, + {-0.381100f, -1.200000f, -0.648900f}, + {-0.381100f, -1.200000f, -0.648900f}, + {0.000000f, -1.200000f, -0.750000f}, + {0.000000f, -1.243800f, -0.716200f}, + {-0.375700f, -1.200000f, -0.605600f}, + {-0.615600f, -1.200000f, -0.355700f}, + {-0.601800f, -1.243700f, -0.351700f}, + {-0.601800f, -1.243700f, -0.351700f}, + {-0.357600f, -1.243700f, -0.598800f}, + {-0.375700f, -1.200000f, -0.605600f}, + {-0.357600f, -1.243700f, -0.598800f}, + {-0.601800f, -1.243700f, -0.351700f}, + {-0.620000f, -1.243700f, -0.363900f}, + {-0.620000f, -1.243700f, -0.363900f}, + {-0.364700f, -1.243700f, -0.619600f}, + {-0.357600f, -1.243700f, -0.598800f}, + {-0.364700f, -1.243700f, -0.619600f}, + {-0.620000f, -1.243700f, -0.363900f}, + {-0.648900f, -1.200000f, -0.381100f}, + {-0.648900f, -1.200000f, -0.381100f}, + {-0.381100f, -1.200000f, -0.648900f}, + {-0.364700f, -1.243700f, -0.619600f}, + {-0.615600f, -1.200000f, -0.355700f}, + {-0.700000f, -1.200000f, 0.000000f}, + {-0.692100f, -1.243700f, 0.000000f}, + {-0.692100f, -1.243700f, 0.000000f}, + {-0.601800f, -1.243700f, -0.351700f}, + {-0.615600f, -1.200000f, -0.355700f}, + {-0.601800f, -1.243700f, -0.351700f}, + {-0.692100f, -1.243700f, 0.000000f}, + {-0.716200f, -1.243700f, 0.000000f}, + {-0.716200f, -1.243700f, 0.000000f}, + {-0.620000f, -1.243700f, -0.363900f}, + {-0.601800f, -1.243700f, -0.351700f}, + {-0.620000f, -1.243700f, -0.363900f}, + {-0.716200f, -1.243700f, 0.000000f}, + {-0.750000f, -1.200000f, 0.000000f}, + {-0.750000f, -1.200000f, 0.000000f}, + {-0.648900f, -1.200000f, -0.381100f}, + {-0.620000f, -1.243700f, -0.363900f}, + {-0.700000f, -1.200000f, 0.000000f}, + {-0.605600f, -1.200000f, 0.355700f}, + {-0.598800f, -1.243700f, 0.351700f}, + {-0.598800f, -1.243700f, 0.351700f}, + {-0.692100f, -1.243700f, 0.000000f}, + {-0.700000f, -1.200000f, 0.000000f}, + {-0.692100f, -1.243700f, 0.000000f}, + {-0.598800f, -1.243700f, 0.351700f}, + {-0.619600f, -1.243700f, 0.363900f}, + {-0.619600f, -1.243700f, 0.363900f}, + {-0.716200f, -1.243700f, 0.000000f}, + {-0.692100f, -1.243700f, 0.000000f}, + {-0.716200f, -1.243700f, 0.000000f}, + {-0.619600f, -1.243700f, 0.363900f}, + {-0.648900f, -1.200000f, 0.381100f}, + {-0.648900f, -1.200000f, 0.381100f}, + {-0.750000f, -1.200000f, 0.000000f}, + {-0.716200f, -1.243700f, 0.000000f}, + {-0.605600f, -1.200000f, 0.355700f}, + {-0.355700f, -1.200000f, 0.605600f}, + {-0.351700f, -1.243700f, 0.598800f}, + {-0.351700f, -1.243700f, 0.598800f}, + {-0.598800f, -1.243700f, 0.351700f}, + {-0.605600f, -1.200000f, 0.355700f}, + {-0.598800f, -1.243700f, 0.351700f}, + {-0.351700f, -1.243700f, 0.598800f}, + {-0.363900f, -1.243700f, 0.619600f}, + {-0.363900f, -1.243700f, 0.619600f}, + {-0.619600f, -1.243700f, 0.363900f}, + {-0.598800f, -1.243700f, 0.351700f}, + {-0.619600f, -1.243700f, 0.363900f}, + {-0.363900f, -1.243700f, 0.619600f}, + {-0.381100f, -1.200000f, 0.648900f}, + {-0.381100f, -1.200000f, 0.648900f}, + {-0.648900f, -1.200000f, 0.381100f}, + {-0.619600f, -1.243700f, 0.363900f}, + {-0.355700f, -1.200000f, 0.605600f}, + {0.000000f, -1.200000f, 0.700000f}, + {0.000000f, -1.243700f, 0.692100f}, + {0.000000f, -1.243700f, 0.692100f}, + {-0.351700f, -1.243700f, 0.598800f}, + {-0.355700f, -1.200000f, 0.605600f}, + {-0.351700f, -1.243700f, 0.598800f}, + {0.000000f, -1.243700f, 0.692100f}, + {0.000000f, -1.243700f, 0.716200f}, + {0.000000f, -1.243700f, 0.716200f}, + {-0.363900f, -1.243700f, 0.619600f}, + {-0.351700f, -1.243700f, 0.598800f}, + {-0.363900f, -1.243700f, 0.619600f}, + {0.000000f, -1.243700f, 0.716200f}, + {0.000000f, -1.200000f, 0.750000f}, + {0.000000f, -1.200000f, 0.750000f}, + {-0.381100f, -1.200000f, 0.648900f}, + {-0.363900f, -1.243700f, 0.619600f}, + {0.000000f, -1.200000f, 0.700000f}, + {0.355700f, -1.200000f, 0.605600f}, + {0.351700f, -1.243700f, 0.598800f}, + {0.351700f, -1.243700f, 0.598800f}, + {0.000000f, -1.243700f, 0.692100f}, + {0.000000f, -1.200000f, 0.700000f}, + {0.000000f, -1.243700f, 0.692100f}, + {0.351700f, -1.243700f, 0.598800f}, + {0.363900f, -1.243700f, 0.619600f}, + {0.363900f, -1.243700f, 0.619600f}, + {0.000000f, -1.243700f, 0.716200f}, + {0.000000f, -1.243700f, 0.692100f}, + {0.000000f, -1.243700f, 0.716200f}, + {0.363900f, -1.243700f, 0.619600f}, + {0.381100f, -1.200000f, 0.648900f}, + {0.381100f, -1.200000f, 0.648900f}, + {0.000000f, -1.200000f, 0.750000f}, + {0.000000f, -1.243700f, 0.716200f}, + {0.355700f, -1.200000f, 0.605600f}, + {0.605600f, -1.200000f, 0.355700f}, + {0.598800f, -1.243700f, 0.351700f}, + {0.598800f, -1.243700f, 0.351700f}, + {0.351700f, -1.243700f, 0.598800f}, + {0.355700f, -1.200000f, 0.605600f}, + {0.351700f, -1.243700f, 0.598800f}, + {0.598800f, -1.243700f, 0.351700f}, + {0.619600f, -1.243700f, 0.363900f}, + {0.619600f, -1.243700f, 0.363900f}, + {0.363900f, -1.243700f, 0.619600f}, + {0.351700f, -1.243700f, 0.598800f}, + {0.363900f, -1.243700f, 0.619600f}, + {0.619600f, -1.243700f, 0.363900f}, + {0.648900f, -1.200000f, 0.381100f}, + {0.648900f, -1.200000f, 0.381100f}, + {0.381100f, -1.200000f, 0.648900f}, + {0.363900f, -1.243700f, 0.619600f}, + {0.605600f, -1.200000f, 0.355700f}, + {0.700000f, -1.200000f, 0.000000f}, + {0.692100f, -1.243700f, 0.000000f}, + {0.692100f, -1.243700f, 0.000000f}, + {0.598800f, -1.243700f, 0.351700f}, + {0.605600f, -1.200000f, 0.355700f}, + {0.598800f, -1.243700f, 0.351700f}, + {0.692100f, -1.243700f, 0.000000f}, + {0.716200f, -1.243700f, 0.000000f}, + {0.716200f, -1.243700f, 0.000000f}, + {0.619600f, -1.243700f, 0.363900f}, + {0.598800f, -1.243700f, 0.351700f}, + {0.619600f, -1.243700f, 0.363900f}, + {0.716200f, -1.243700f, 0.000000f}, + {0.750000f, -1.200000f, 0.000000f}, + {0.750000f, -1.200000f, 0.000000f}, + {0.648900f, -1.200000f, 0.381100f}, + {0.619600f, -1.243700f, 0.363900f}, + {0.750000f, -1.200000f, 0.000000f}, + {0.648900f, -1.200000f, -0.381100f}, + {0.753000f, -0.938900f, -0.442300f}, + {0.753000f, -0.938900f, -0.442300f}, + {0.870400f, -0.938900f, 0.000000f}, + {0.750000f, -1.200000f, 0.000000f}, + {0.870400f, -0.938900f, 0.000000f}, + {0.753000f, -0.938900f, -0.442300f}, + {0.833100f, -0.686100f, -0.489300f}, + {0.833100f, -0.686100f, -0.489300f}, + {0.963000f, -0.686100f, 0.000000f}, + {0.870400f, -0.938900f, 0.000000f}, + {0.963000f, -0.686100f, 0.000000f}, + {0.833100f, -0.686100f, -0.489300f}, + {0.865200f, -0.450000f, -0.508100f}, + {0.865200f, -0.450000f, -0.508100f}, + {1.000000f, -0.450000f, 0.000000f}, + {0.963000f, -0.686100f, 0.000000f}, + {0.648900f, -1.200000f, -0.381100f}, + {0.381100f, -1.200000f, -0.648900f}, + {0.442300f, -0.938900f, -0.753000f}, + {0.442300f, -0.938900f, -0.753000f}, + {0.753000f, -0.938900f, -0.442300f}, + {0.648900f, -1.200000f, -0.381100f}, + {0.753000f, -0.938900f, -0.442300f}, + {0.442300f, -0.938900f, -0.753000f}, + {0.489300f, -0.686100f, -0.833100f}, + {0.489300f, -0.686100f, -0.833100f}, + {0.833100f, -0.686100f, -0.489300f}, + {0.753000f, -0.938900f, -0.442300f}, + {0.833100f, -0.686100f, -0.489300f}, + {0.489300f, -0.686100f, -0.833100f}, + {0.508100f, -0.450000f, -0.865200f}, + {0.508100f, -0.450000f, -0.865200f}, + {0.865200f, -0.450000f, -0.508100f}, + {0.833100f, -0.686100f, -0.489300f}, + {0.381100f, -1.200000f, -0.648900f}, + {0.000000f, -1.200000f, -0.750000f}, + {0.000000f, -0.938900f, -0.870400f}, + {0.000000f, -0.938900f, -0.870400f}, + {0.442300f, -0.938900f, -0.753000f}, + {0.381100f, -1.200000f, -0.648900f}, + {0.442300f, -0.938900f, -0.753000f}, + {0.000000f, -0.938900f, -0.870400f}, + {0.000000f, -0.686100f, -0.963000f}, + {0.000000f, -0.686100f, -0.963000f}, + {0.489300f, -0.686100f, -0.833100f}, + {0.442300f, -0.938900f, -0.753000f}, + {0.489300f, -0.686100f, -0.833100f}, + {0.000000f, -0.686100f, -0.963000f}, + {0.000000f, -0.450000f, -1.000000f}, + {0.000000f, -0.450000f, -1.000000f}, + {0.508100f, -0.450000f, -0.865200f}, + {0.489300f, -0.686100f, -0.833100f}, + {0.000000f, -1.200000f, -0.750000f}, + {-0.381100f, -1.200000f, -0.648900f}, + {-0.442300f, -0.938900f, -0.753000f}, + {-0.442300f, -0.938900f, -0.753000f}, + {0.000000f, -0.938900f, -0.870400f}, + {0.000000f, -1.200000f, -0.750000f}, + {0.000000f, -0.938900f, -0.870400f}, + {-0.442300f, -0.938900f, -0.753000f}, + {-0.489300f, -0.686100f, -0.833100f}, + {-0.489300f, -0.686100f, -0.833100f}, + {0.000000f, -0.686100f, -0.963000f}, + {0.000000f, -0.938900f, -0.870400f}, + {0.000000f, -0.686100f, -0.963000f}, + {-0.489300f, -0.686100f, -0.833100f}, + {-0.508100f, -0.450000f, -0.865200f}, + {-0.508100f, -0.450000f, -0.865200f}, + {0.000000f, -0.450000f, -1.000000f}, + {0.000000f, -0.686100f, -0.963000f}, + {-0.381100f, -1.200000f, -0.648900f}, + {-0.648900f, -1.200000f, -0.381100f}, + {-0.753000f, -0.938900f, -0.442300f}, + {-0.753000f, -0.938900f, -0.442300f}, + {-0.442300f, -0.938900f, -0.753000f}, + {-0.381100f, -1.200000f, -0.648900f}, + {-0.442300f, -0.938900f, -0.753000f}, + {-0.753000f, -0.938900f, -0.442300f}, + {-0.833100f, -0.686100f, -0.489300f}, + {-0.833100f, -0.686100f, -0.489300f}, + {-0.489300f, -0.686100f, -0.833100f}, + {-0.442300f, -0.938900f, -0.753000f}, + {-0.489300f, -0.686100f, -0.833100f}, + {-0.833100f, -0.686100f, -0.489300f}, + {-0.865200f, -0.450000f, -0.508100f}, + {-0.865200f, -0.450000f, -0.508100f}, + {-0.508100f, -0.450000f, -0.865200f}, + {-0.489300f, -0.686100f, -0.833100f}, + {-0.648900f, -1.200000f, -0.381100f}, + {-0.750000f, -1.200000f, 0.000000f}, + {-0.870400f, -0.938900f, 0.000000f}, + {-0.870400f, -0.938900f, 0.000000f}, + {-0.753000f, -0.938900f, -0.442300f}, + {-0.648900f, -1.200000f, -0.381100f}, + {-0.753000f, -0.938900f, -0.442300f}, + {-0.870400f, -0.938900f, 0.000000f}, + {-0.963000f, -0.686100f, 0.000000f}, + {-0.963000f, -0.686100f, 0.000000f}, + {-0.833100f, -0.686100f, -0.489300f}, + {-0.753000f, -0.938900f, -0.442300f}, + {-0.833100f, -0.686100f, -0.489300f}, + {-0.963000f, -0.686100f, 0.000000f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-0.865200f, -0.450000f, -0.508100f}, + {-0.833100f, -0.686100f, -0.489300f}, + {-0.750000f, -1.200000f, 0.000000f}, + {-0.648900f, -1.200000f, 0.381100f}, + {-0.753000f, -0.938900f, 0.442300f}, + {-0.753000f, -0.938900f, 0.442300f}, + {-0.870400f, -0.938900f, 0.000000f}, + {-0.750000f, -1.200000f, 0.000000f}, + {-0.870400f, -0.938900f, 0.000000f}, + {-0.753000f, -0.938900f, 0.442300f}, + {-0.833100f, -0.686100f, 0.489300f}, + {-0.833100f, -0.686100f, 0.489300f}, + {-0.963000f, -0.686100f, 0.000000f}, + {-0.870400f, -0.938900f, 0.000000f}, + {-0.963000f, -0.686100f, 0.000000f}, + {-0.833100f, -0.686100f, 0.489300f}, + {-0.865200f, -0.450000f, 0.508100f}, + {-0.865200f, -0.450000f, 0.508100f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-0.963000f, -0.686100f, 0.000000f}, + {-0.648900f, -1.200000f, 0.381100f}, + {-0.381100f, -1.200000f, 0.648900f}, + {-0.442300f, -0.938900f, 0.753000f}, + {-0.442300f, -0.938900f, 0.753000f}, + {-0.753000f, -0.938900f, 0.442300f}, + {-0.648900f, -1.200000f, 0.381100f}, + {-0.753000f, -0.938900f, 0.442300f}, + {-0.442300f, -0.938900f, 0.753000f}, + {-0.489300f, -0.686100f, 0.833100f}, + {-0.489300f, -0.686100f, 0.833100f}, + {-0.833100f, -0.686100f, 0.489300f}, + {-0.753000f, -0.938900f, 0.442300f}, + {-0.833100f, -0.686100f, 0.489300f}, + {-0.489300f, -0.686100f, 0.833100f}, + {-0.508100f, -0.450000f, 0.865200f}, + {-0.508100f, -0.450000f, 0.865200f}, + {-0.865200f, -0.450000f, 0.508100f}, + {-0.833100f, -0.686100f, 0.489300f}, + {-0.381100f, -1.200000f, 0.648900f}, + {0.000000f, -1.200000f, 0.750000f}, + {0.000000f, -0.938900f, 0.870400f}, + {0.000000f, -0.938900f, 0.870400f}, + {-0.442300f, -0.938900f, 0.753000f}, + {-0.381100f, -1.200000f, 0.648900f}, + {-0.442300f, -0.938900f, 0.753000f}, + {0.000000f, -0.938900f, 0.870400f}, + {0.000000f, -0.686100f, 0.963000f}, + {0.000000f, -0.686100f, 0.963000f}, + {-0.489300f, -0.686100f, 0.833100f}, + {-0.442300f, -0.938900f, 0.753000f}, + {-0.489300f, -0.686100f, 0.833100f}, + {0.000000f, -0.686100f, 0.963000f}, + {0.000000f, -0.450000f, 1.000000f}, + {0.000000f, -0.450000f, 1.000000f}, + {-0.508100f, -0.450000f, 0.865200f}, + {-0.489300f, -0.686100f, 0.833100f}, + {0.000000f, -1.200000f, 0.750000f}, + {0.381100f, -1.200000f, 0.648900f}, + {0.442300f, -0.938900f, 0.753000f}, + {0.442300f, -0.938900f, 0.753000f}, + {0.000000f, -0.938900f, 0.870400f}, + {0.000000f, -1.200000f, 0.750000f}, + {0.000000f, -0.938900f, 0.870400f}, + {0.442300f, -0.938900f, 0.753000f}, + {0.489300f, -0.686100f, 0.833100f}, + {0.489300f, -0.686100f, 0.833100f}, + {0.000000f, -0.686100f, 0.963000f}, + {0.000000f, -0.938900f, 0.870400f}, + {0.000000f, -0.686100f, 0.963000f}, + {0.489300f, -0.686100f, 0.833100f}, + {0.508100f, -0.450000f, 0.865200f}, + {0.508100f, -0.450000f, 0.865200f}, + {0.000000f, -0.450000f, 1.000000f}, + {0.000000f, -0.686100f, 0.963000f}, + {0.381100f, -1.200000f, 0.648900f}, + {0.648900f, -1.200000f, 0.381100f}, + {0.753000f, -0.938900f, 0.442300f}, + {0.753000f, -0.938900f, 0.442300f}, + {0.442300f, -0.938900f, 0.753000f}, + {0.381100f, -1.200000f, 0.648900f}, + {0.442300f, -0.938900f, 0.753000f}, + {0.753000f, -0.938900f, 0.442300f}, + {0.833100f, -0.686100f, 0.489300f}, + {0.833100f, -0.686100f, 0.489300f}, + {0.489300f, -0.686100f, 0.833100f}, + {0.442300f, -0.938900f, 0.753000f}, + {0.489300f, -0.686100f, 0.833100f}, + {0.833100f, -0.686100f, 0.489300f}, + {0.865200f, -0.450000f, 0.508100f}, + {0.865200f, -0.450000f, 0.508100f}, + {0.508100f, -0.450000f, 0.865200f}, + {0.489300f, -0.686100f, 0.833100f}, + {0.648900f, -1.200000f, 0.381100f}, + {0.750000f, -1.200000f, 0.000000f}, + {0.870400f, -0.938900f, 0.000000f}, + {0.870400f, -0.938900f, 0.000000f}, + {0.753000f, -0.938900f, 0.442300f}, + {0.648900f, -1.200000f, 0.381100f}, + {0.753000f, -0.938900f, 0.442300f}, + {0.870400f, -0.938900f, 0.000000f}, + {0.963000f, -0.686100f, 0.000000f}, + {0.963000f, -0.686100f, 0.000000f}, + {0.833100f, -0.686100f, 0.489300f}, + {0.753000f, -0.938900f, 0.442300f}, + {0.833100f, -0.686100f, 0.489300f}, + {0.963000f, -0.686100f, 0.000000f}, + {1.000000f, -0.450000f, 0.000000f}, + {1.000000f, -0.450000f, 0.000000f}, + {0.865200f, -0.450000f, 0.508100f}, + {0.833100f, -0.686100f, 0.489300f}, + {1.000000f, -0.450000f, 0.000000f}, + {0.865200f, -0.450000f, -0.508100f}, + {0.809100f, -0.261100f, -0.475200f}, + {0.809100f, -0.261100f, -0.475200f}, + {0.935200f, -0.261100f, 0.000000f}, + {1.000000f, -0.450000f, 0.000000f}, + {0.935200f, -0.261100f, 0.000000f}, + {0.809100f, -0.261100f, -0.475200f}, + {0.705000f, -0.138900f, -0.414000f}, + {0.705000f, -0.138900f, -0.414000f}, + {0.814800f, -0.138900f, 0.000000f}, + {0.935200f, -0.261100f, 0.000000f}, + {0.814800f, -0.138900f, 0.000000f}, + {0.705000f, -0.138900f, -0.414000f}, + {0.648900f, -0.075000f, -0.381100f}, + {0.648900f, -0.075000f, -0.381100f}, + {0.750000f, -0.075000f, 0.000000f}, + {0.814800f, -0.138900f, 0.000000f}, + {0.865200f, -0.450000f, -0.508100f}, + {0.508100f, -0.450000f, -0.865200f}, + {0.475200f, -0.261100f, -0.809100f}, + {0.475200f, -0.261100f, -0.809100f}, + {0.809100f, -0.261100f, -0.475200f}, + {0.865200f, -0.450000f, -0.508100f}, + {0.809100f, -0.261100f, -0.475200f}, + {0.475200f, -0.261100f, -0.809100f}, + {0.414000f, -0.138900f, -0.705000f}, + {0.414000f, -0.138900f, -0.705000f}, + {0.705000f, -0.138900f, -0.414000f}, + {0.809100f, -0.261100f, -0.475200f}, + {0.705000f, -0.138900f, -0.414000f}, + {0.414000f, -0.138900f, -0.705000f}, + {0.381100f, -0.075000f, -0.648900f}, + {0.381100f, -0.075000f, -0.648900f}, + {0.648900f, -0.075000f, -0.381100f}, + {0.705000f, -0.138900f, -0.414000f}, + {0.508100f, -0.450000f, -0.865200f}, + {0.000000f, -0.450000f, -1.000000f}, + {0.000000f, -0.261100f, -0.935200f}, + {0.000000f, -0.261100f, -0.935200f}, + {0.475200f, -0.261100f, -0.809100f}, + {0.508100f, -0.450000f, -0.865200f}, + {0.475200f, -0.261100f, -0.809100f}, + {0.000000f, -0.261100f, -0.935200f}, + {0.000000f, -0.138900f, -0.814800f}, + {0.000000f, -0.138900f, -0.814800f}, + {0.414000f, -0.138900f, -0.705000f}, + {0.475200f, -0.261100f, -0.809100f}, + {0.414000f, -0.138900f, -0.705000f}, + {0.000000f, -0.138900f, -0.814800f}, + {0.000000f, -0.075000f, -0.750000f}, + {0.000000f, -0.075000f, -0.750000f}, + {0.381100f, -0.075000f, -0.648900f}, + {0.414000f, -0.138900f, -0.705000f}, + {0.000000f, -0.450000f, -1.000000f}, + {-0.508100f, -0.450000f, -0.865200f}, + {-0.475200f, -0.261100f, -0.809100f}, + {-0.475200f, -0.261100f, -0.809100f}, + {0.000000f, -0.261100f, -0.935200f}, + {0.000000f, -0.450000f, -1.000000f}, + {0.000000f, -0.261100f, -0.935200f}, + {-0.475200f, -0.261100f, -0.809100f}, + {-0.414000f, -0.138900f, -0.705000f}, + {-0.414000f, -0.138900f, -0.705000f}, + {0.000000f, -0.138900f, -0.814800f}, + {0.000000f, -0.261100f, -0.935200f}, + {0.000000f, -0.138900f, -0.814800f}, + {-0.414000f, -0.138900f, -0.705000f}, + {-0.381100f, -0.075000f, -0.648900f}, + {-0.381100f, -0.075000f, -0.648900f}, + {0.000000f, -0.075000f, -0.750000f}, + {0.000000f, -0.138900f, -0.814800f}, + {-0.508100f, -0.450000f, -0.865200f}, + {-0.865200f, -0.450000f, -0.508100f}, + {-0.809100f, -0.261100f, -0.475200f}, + {-0.809100f, -0.261100f, -0.475200f}, + {-0.475200f, -0.261100f, -0.809100f}, + {-0.508100f, -0.450000f, -0.865200f}, + {-0.475200f, -0.261100f, -0.809100f}, + {-0.809100f, -0.261100f, -0.475200f}, + {-0.705000f, -0.138900f, -0.414000f}, + {-0.705000f, -0.138900f, -0.414000f}, + {-0.414000f, -0.138900f, -0.705000f}, + {-0.475200f, -0.261100f, -0.809100f}, + {-0.414000f, -0.138900f, -0.705000f}, + {-0.705000f, -0.138900f, -0.414000f}, + {-0.648900f, -0.075000f, -0.381100f}, + {-0.648900f, -0.075000f, -0.381100f}, + {-0.381100f, -0.075000f, -0.648900f}, + {-0.414000f, -0.138900f, -0.705000f}, + {-0.865200f, -0.450000f, -0.508100f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-0.935200f, -0.261100f, 0.000000f}, + {-0.935200f, -0.261100f, 0.000000f}, + {-0.809100f, -0.261100f, -0.475200f}, + {-0.865200f, -0.450000f, -0.508100f}, + {-0.809100f, -0.261100f, -0.475200f}, + {-0.935200f, -0.261100f, 0.000000f}, + {-0.814800f, -0.138900f, 0.000000f}, + {-0.814800f, -0.138900f, 0.000000f}, + {-0.705000f, -0.138900f, -0.414000f}, + {-0.809100f, -0.261100f, -0.475200f}, + {-0.705000f, -0.138900f, -0.414000f}, + {-0.814800f, -0.138900f, 0.000000f}, + {-0.750000f, -0.075000f, 0.000000f}, + {-0.750000f, -0.075000f, 0.000000f}, + {-0.648900f, -0.075000f, -0.381100f}, + {-0.705000f, -0.138900f, -0.414000f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-0.865200f, -0.450000f, 0.508100f}, + {-0.809100f, -0.261100f, 0.475200f}, + {-0.809100f, -0.261100f, 0.475200f}, + {-0.935200f, -0.261100f, 0.000000f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-0.935200f, -0.261100f, 0.000000f}, + {-0.809100f, -0.261100f, 0.475200f}, + {-0.705000f, -0.138900f, 0.414000f}, + {-0.705000f, -0.138900f, 0.414000f}, + {-0.814800f, -0.138900f, 0.000000f}, + {-0.935200f, -0.261100f, 0.000000f}, + {-0.814800f, -0.138900f, 0.000000f}, + {-0.705000f, -0.138900f, 0.414000f}, + {-0.648900f, -0.075000f, 0.381100f}, + {-0.648900f, -0.075000f, 0.381100f}, + {-0.750000f, -0.075000f, 0.000000f}, + {-0.814800f, -0.138900f, 0.000000f}, + {-0.865200f, -0.450000f, 0.508100f}, + {-0.508100f, -0.450000f, 0.865200f}, + {-0.475200f, -0.261100f, 0.809100f}, + {-0.475200f, -0.261100f, 0.809100f}, + {-0.809100f, -0.261100f, 0.475200f}, + {-0.865200f, -0.450000f, 0.508100f}, + {-0.809100f, -0.261100f, 0.475200f}, + {-0.475200f, -0.261100f, 0.809100f}, + {-0.414000f, -0.138900f, 0.705000f}, + {-0.414000f, -0.138900f, 0.705000f}, + {-0.705000f, -0.138900f, 0.414000f}, + {-0.809100f, -0.261100f, 0.475200f}, + {-0.705000f, -0.138900f, 0.414000f}, + {-0.414000f, -0.138900f, 0.705000f}, + {-0.381100f, -0.075000f, 0.648900f}, + {-0.381100f, -0.075000f, 0.648900f}, + {-0.648900f, -0.075000f, 0.381100f}, + {-0.705000f, -0.138900f, 0.414000f}, + {-0.508100f, -0.450000f, 0.865200f}, + {0.000000f, -0.450000f, 1.000000f}, + {0.000000f, -0.261100f, 0.935200f}, + {0.000000f, -0.261100f, 0.935200f}, + {-0.475200f, -0.261100f, 0.809100f}, + {-0.508100f, -0.450000f, 0.865200f}, + {-0.475200f, -0.261100f, 0.809100f}, + {0.000000f, -0.261100f, 0.935200f}, + {0.000000f, -0.138900f, 0.814800f}, + {0.000000f, -0.138900f, 0.814800f}, + {-0.414000f, -0.138900f, 0.705000f}, + {-0.475200f, -0.261100f, 0.809100f}, + {-0.414000f, -0.138900f, 0.705000f}, + {0.000000f, -0.138900f, 0.814800f}, + {0.000000f, -0.075000f, 0.750000f}, + {0.000000f, -0.075000f, 0.750000f}, + {-0.381100f, -0.075000f, 0.648900f}, + {-0.414000f, -0.138900f, 0.705000f}, + {0.000000f, -0.450000f, 1.000000f}, + {0.508100f, -0.450000f, 0.865200f}, + {0.475200f, -0.261100f, 0.809100f}, + {0.475200f, -0.261100f, 0.809100f}, + {0.000000f, -0.261100f, 0.935200f}, + {0.000000f, -0.450000f, 1.000000f}, + {0.000000f, -0.261100f, 0.935200f}, + {0.475200f, -0.261100f, 0.809100f}, + {0.414000f, -0.138900f, 0.705000f}, + {0.414000f, -0.138900f, 0.705000f}, + {0.000000f, -0.138900f, 0.814800f}, + {0.000000f, -0.261100f, 0.935200f}, + {0.000000f, -0.138900f, 0.814800f}, + {0.414000f, -0.138900f, 0.705000f}, + {0.381100f, -0.075000f, 0.648900f}, + {0.381100f, -0.075000f, 0.648900f}, + {0.000000f, -0.075000f, 0.750000f}, + {0.000000f, -0.138900f, 0.814800f}, + {0.508100f, -0.450000f, 0.865200f}, + {0.865200f, -0.450000f, 0.508100f}, + {0.809100f, -0.261100f, 0.475200f}, + {0.809100f, -0.261100f, 0.475200f}, + {0.475200f, -0.261100f, 0.809100f}, + {0.508100f, -0.450000f, 0.865200f}, + {0.475200f, -0.261100f, 0.809100f}, + {0.809100f, -0.261100f, 0.475200f}, + {0.705000f, -0.138900f, 0.414000f}, + {0.705000f, -0.138900f, 0.414000f}, + {0.414000f, -0.138900f, 0.705000f}, + {0.475200f, -0.261100f, 0.809100f}, + {0.414000f, -0.138900f, 0.705000f}, + {0.705000f, -0.138900f, 0.414000f}, + {0.648900f, -0.075000f, 0.381100f}, + {0.648900f, -0.075000f, 0.381100f}, + {0.381100f, -0.075000f, 0.648900f}, + {0.414000f, -0.138900f, 0.705000f}, + {0.865200f, -0.450000f, 0.508100f}, + {1.000000f, -0.450000f, 0.000000f}, + {0.935200f, -0.261100f, 0.000000f}, + {0.935200f, -0.261100f, 0.000000f}, + {0.809100f, -0.261100f, 0.475200f}, + {0.865200f, -0.450000f, 0.508100f}, + {0.809100f, -0.261100f, 0.475200f}, + {0.935200f, -0.261100f, 0.000000f}, + {0.814800f, -0.138900f, 0.000000f}, + {0.814800f, -0.138900f, 0.000000f}, + {0.705000f, -0.138900f, 0.414000f}, + {0.809100f, -0.261100f, 0.475200f}, + {0.705000f, -0.138900f, 0.414000f}, + {0.814800f, -0.138900f, 0.000000f}, + {0.750000f, -0.075000f, 0.000000f}, + {0.750000f, -0.075000f, 0.000000f}, + {0.648900f, -0.075000f, 0.381100f}, + {0.705000f, -0.138900f, 0.414000f}, + {0.750000f, -0.075000f, 0.000000f}, + {0.648900f, -0.075000f, -0.381100f}, + {0.617600f, -0.038900f, -0.362800f}, + {0.617600f, -0.038900f, -0.362800f}, + {0.713900f, -0.038900f, 0.000000f}, + {0.750000f, -0.075000f, 0.000000f}, + {0.713900f, -0.038900f, 0.000000f}, + {0.617600f, -0.038900f, -0.362800f}, + {0.442200f, -0.011100f, -0.259700f}, + {0.442200f, -0.011100f, -0.259700f}, + {0.511100f, -0.011100f, 0.000000f}, + {0.713900f, -0.038900f, 0.000000f}, + {0.511100f, -0.011100f, 0.000000f}, + {0.442200f, -0.011100f, -0.259700f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.511100f, -0.011100f, 0.000000f}, + {0.648900f, -0.075000f, -0.381100f}, + {0.381100f, -0.075000f, -0.648900f}, + {0.362800f, -0.038900f, -0.617600f}, + {0.362800f, -0.038900f, -0.617600f}, + {0.617600f, -0.038900f, -0.362800f}, + {0.648900f, -0.075000f, -0.381100f}, + {0.617600f, -0.038900f, -0.362800f}, + {0.362800f, -0.038900f, -0.617600f}, + {0.259700f, -0.011100f, -0.442200f}, + {0.259700f, -0.011100f, -0.442200f}, + {0.442200f, -0.011100f, -0.259700f}, + {0.617600f, -0.038900f, -0.362800f}, + {0.442200f, -0.011100f, -0.259700f}, + {0.259700f, -0.011100f, -0.442200f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.442200f, -0.011100f, -0.259700f}, + {0.381100f, -0.075000f, -0.648900f}, + {0.000000f, -0.075000f, -0.750000f}, + {0.000000f, -0.038900f, -0.713900f}, + {0.000000f, -0.038900f, -0.713900f}, + {0.362800f, -0.038900f, -0.617600f}, + {0.381100f, -0.075000f, -0.648900f}, + {0.362800f, -0.038900f, -0.617600f}, + {0.000000f, -0.038900f, -0.713900f}, + {0.000000f, -0.011100f, -0.511100f}, + {0.000000f, -0.011100f, -0.511100f}, + {0.259700f, -0.011100f, -0.442200f}, + {0.362800f, -0.038900f, -0.617600f}, + {0.259700f, -0.011100f, -0.442200f}, + {0.000000f, -0.011100f, -0.511100f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.259700f, -0.011100f, -0.442200f}, + {0.000000f, -0.075000f, -0.750000f}, + {-0.381100f, -0.075000f, -0.648900f}, + {-0.362800f, -0.038900f, -0.617600f}, + {-0.362800f, -0.038900f, -0.617600f}, + {0.000000f, -0.038900f, -0.713900f}, + {0.000000f, -0.075000f, -0.750000f}, + {0.000000f, -0.038900f, -0.713900f}, + {-0.362800f, -0.038900f, -0.617600f}, + {-0.259700f, -0.011100f, -0.442200f}, + {-0.259700f, -0.011100f, -0.442200f}, + {0.000000f, -0.011100f, -0.511100f}, + {0.000000f, -0.038900f, -0.713900f}, + {0.000000f, -0.011100f, -0.511100f}, + {-0.259700f, -0.011100f, -0.442200f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, -0.011100f, -0.511100f}, + {-0.381100f, -0.075000f, -0.648900f}, + {-0.648900f, -0.075000f, -0.381100f}, + {-0.617600f, -0.038900f, -0.362800f}, + {-0.617600f, -0.038900f, -0.362800f}, + {-0.362800f, -0.038900f, -0.617600f}, + {-0.381100f, -0.075000f, -0.648900f}, + {-0.362800f, -0.038900f, -0.617600f}, + {-0.617600f, -0.038900f, -0.362800f}, + {-0.442200f, -0.011100f, -0.259700f}, + {-0.442200f, -0.011100f, -0.259700f}, + {-0.259700f, -0.011100f, -0.442200f}, + {-0.362800f, -0.038900f, -0.617600f}, + {-0.259700f, -0.011100f, -0.442200f}, + {-0.442200f, -0.011100f, -0.259700f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {-0.259700f, -0.011100f, -0.442200f}, + {-0.648900f, -0.075000f, -0.381100f}, + {-0.750000f, -0.075000f, 0.000000f}, + {-0.713900f, -0.038900f, 0.000000f}, + {-0.713900f, -0.038900f, 0.000000f}, + {-0.617600f, -0.038900f, -0.362800f}, + {-0.648900f, -0.075000f, -0.381100f}, + {-0.617600f, -0.038900f, -0.362800f}, + {-0.713900f, -0.038900f, 0.000000f}, + {-0.511100f, -0.011100f, 0.000000f}, + {-0.511100f, -0.011100f, 0.000000f}, + {-0.442200f, -0.011100f, -0.259700f}, + {-0.617600f, -0.038900f, -0.362800f}, + {-0.442200f, -0.011100f, -0.259700f}, + {-0.511100f, -0.011100f, 0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {-0.442200f, -0.011100f, -0.259700f}, + {-0.750000f, -0.075000f, 0.000000f}, + {-0.648900f, -0.075000f, 0.381100f}, + {-0.617600f, -0.038900f, 0.362800f}, + {-0.617600f, -0.038900f, 0.362800f}, + {-0.713900f, -0.038900f, 0.000000f}, + {-0.750000f, -0.075000f, 0.000000f}, + {-0.713900f, -0.038900f, 0.000000f}, + {-0.617600f, -0.038900f, 0.362800f}, + {-0.442200f, -0.011100f, 0.259700f}, + {-0.442200f, -0.011100f, 0.259700f}, + {-0.511100f, -0.011100f, 0.000000f}, + {-0.713900f, -0.038900f, 0.000000f}, + {-0.511100f, -0.011100f, 0.000000f}, + {-0.442200f, -0.011100f, 0.259700f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {-0.511100f, -0.011100f, 0.000000f}, + {-0.648900f, -0.075000f, 0.381100f}, + {-0.381100f, -0.075000f, 0.648900f}, + {-0.362800f, -0.038900f, 0.617600f}, + {-0.362800f, -0.038900f, 0.617600f}, + {-0.617600f, -0.038900f, 0.362800f}, + {-0.648900f, -0.075000f, 0.381100f}, + {-0.617600f, -0.038900f, 0.362800f}, + {-0.362800f, -0.038900f, 0.617600f}, + {-0.259700f, -0.011100f, 0.442200f}, + {-0.259700f, -0.011100f, 0.442200f}, + {-0.442200f, -0.011100f, 0.259700f}, + {-0.617600f, -0.038900f, 0.362800f}, + {-0.442200f, -0.011100f, 0.259700f}, + {-0.259700f, -0.011100f, 0.442200f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {-0.442200f, -0.011100f, 0.259700f}, + {-0.381100f, -0.075000f, 0.648900f}, + {0.000000f, -0.075000f, 0.750000f}, + {0.000000f, -0.038900f, 0.713900f}, + {0.000000f, -0.038900f, 0.713900f}, + {-0.362800f, -0.038900f, 0.617600f}, + {-0.381100f, -0.075000f, 0.648900f}, + {-0.362800f, -0.038900f, 0.617600f}, + {0.000000f, -0.038900f, 0.713900f}, + {0.000000f, -0.011100f, 0.511100f}, + {0.000000f, -0.011100f, 0.511100f}, + {-0.259700f, -0.011100f, 0.442200f}, + {-0.362800f, -0.038900f, 0.617600f}, + {-0.259700f, -0.011100f, 0.442200f}, + {0.000000f, -0.011100f, 0.511100f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {-0.259700f, -0.011100f, 0.442200f}, + {0.000000f, -0.075000f, 0.750000f}, + {0.381100f, -0.075000f, 0.648900f}, + {0.362800f, -0.038900f, 0.617600f}, + {0.362800f, -0.038900f, 0.617600f}, + {0.000000f, -0.038900f, 0.713900f}, + {0.000000f, -0.075000f, 0.750000f}, + {0.000000f, -0.038900f, 0.713900f}, + {0.362800f, -0.038900f, 0.617600f}, + {0.259700f, -0.011100f, 0.442200f}, + {0.259700f, -0.011100f, 0.442200f}, + {0.000000f, -0.011100f, 0.511100f}, + {0.000000f, -0.038900f, 0.713900f}, + {0.000000f, -0.011100f, 0.511100f}, + {0.259700f, -0.011100f, 0.442200f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, -0.011100f, 0.511100f}, + {0.381100f, -0.075000f, 0.648900f}, + {0.648900f, -0.075000f, 0.381100f}, + {0.617600f, -0.038900f, 0.362800f}, + {0.617600f, -0.038900f, 0.362800f}, + {0.362800f, -0.038900f, 0.617600f}, + {0.381100f, -0.075000f, 0.648900f}, + {0.362800f, -0.038900f, 0.617600f}, + {0.617600f, -0.038900f, 0.362800f}, + {0.442200f, -0.011100f, 0.259700f}, + {0.442200f, -0.011100f, 0.259700f}, + {0.259700f, -0.011100f, 0.442200f}, + {0.362800f, -0.038900f, 0.617600f}, + {0.259700f, -0.011100f, 0.442200f}, + {0.442200f, -0.011100f, 0.259700f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.259700f, -0.011100f, 0.442200f}, + {0.648900f, -0.075000f, 0.381100f}, + {0.750000f, -0.075000f, 0.000000f}, + {0.713900f, -0.038900f, 0.000000f}, + {0.713900f, -0.038900f, 0.000000f}, + {0.617600f, -0.038900f, 0.362800f}, + {0.648900f, -0.075000f, 0.381100f}, + {0.617600f, -0.038900f, 0.362800f}, + {0.713900f, -0.038900f, 0.000000f}, + {0.511100f, -0.011100f, 0.000000f}, + {0.511100f, -0.011100f, 0.000000f}, + {0.442200f, -0.011100f, 0.259700f}, + {0.617600f, -0.038900f, 0.362800f}, + {0.442200f, -0.011100f, 0.259700f}, + {0.511100f, -0.011100f, 0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.000000f, 0.000000f, -0.000000f}, + {0.442200f, -0.011100f, 0.259700f}, + {-0.800000f, -1.012500f, 0.000000f}, + {-0.787000f, -1.041700f, -0.100000f}, + {-1.115900f, -1.036400f, -0.100000f}, + {-1.115900f, -1.036400f, -0.100000f}, + {-1.098100f, -1.008300f, 0.000000f}, + {-0.800000f, -1.012500f, 0.000000f}, + {-1.098100f, -1.008300f, 0.000000f}, + {-1.115900f, -1.036400f, -0.100000f}, + {-1.319300f, -0.999700f, -0.100000f}, + {-1.319300f, -0.999700f, -0.100000f}, + {-1.285200f, -0.979200f, 0.000000f}, + {-1.098100f, -1.008300f, 0.000000f}, + {-1.285200f, -0.979200f, 0.000000f}, + {-1.319300f, -0.999700f, -0.100000f}, + {-1.388900f, -0.900000f, -0.100000f}, + {-1.388900f, -0.900000f, -0.100000f}, + {-1.350000f, -0.900000f, 0.000000f}, + {-1.285200f, -0.979200f, 0.000000f}, + {-0.787000f, -1.041700f, -0.100000f}, + {-0.763000f, -1.095800f, -0.100000f}, + {-1.148900f, -1.088600f, -0.100000f}, + {-1.148900f, -1.088600f, -0.100000f}, + {-1.115900f, -1.036400f, -0.100000f}, + {-0.787000f, -1.041700f, -0.100000f}, + {-1.115900f, -1.036400f, -0.100000f}, + {-1.148900f, -1.088600f, -0.100000f}, + {-1.382600f, -1.037800f, -0.100000f}, + {-1.382600f, -1.037800f, -0.100000f}, + {-1.319300f, -0.999700f, -0.100000f}, + {-1.115900f, -1.036400f, -0.100000f}, + {-1.319300f, -0.999700f, -0.100000f}, + {-1.382600f, -1.037800f, -0.100000f}, + {-1.461100f, -0.900000f, -0.100000f}, + {-1.461100f, -0.900000f, -0.100000f}, + {-1.388900f, -0.900000f, -0.100000f}, + {-1.319300f, -0.999700f, -0.100000f}, + {-0.763000f, -1.095800f, -0.100000f}, + {-0.750000f, -1.125000f, 0.000000f}, + {-1.166700f, -1.116700f, 0.000000f}, + {-1.166700f, -1.116700f, 0.000000f}, + {-1.148900f, -1.088600f, -0.100000f}, + {-0.763000f, -1.095800f, -0.100000f}, + {-1.148900f, -1.088600f, -0.100000f}, + {-1.166700f, -1.116700f, 0.000000f}, + {-1.416700f, -1.058300f, 0.000000f}, + {-1.416700f, -1.058300f, 0.000000f}, + {-1.382600f, -1.037800f, -0.100000f}, + {-1.148900f, -1.088600f, -0.100000f}, + {-1.382600f, -1.037800f, -0.100000f}, + {-1.416700f, -1.058300f, 0.000000f}, + {-1.500000f, -0.900000f, 0.000000f}, + {-1.500000f, -0.900000f, 0.000000f}, + {-1.461100f, -0.900000f, -0.100000f}, + {-1.382600f, -1.037800f, -0.100000f}, + {-0.750000f, -1.125000f, 0.000000f}, + {-0.763000f, -1.095800f, 0.100000f}, + {-1.148900f, -1.088600f, 0.100000f}, + {-1.148900f, -1.088600f, 0.100000f}, + {-1.166700f, -1.116700f, 0.000000f}, + {-0.750000f, -1.125000f, 0.000000f}, + {-1.166700f, -1.116700f, 0.000000f}, + {-1.148900f, -1.088600f, 0.100000f}, + {-1.382600f, -1.037800f, 0.100000f}, + {-1.382600f, -1.037800f, 0.100000f}, + {-1.416700f, -1.058300f, 0.000000f}, + {-1.166700f, -1.116700f, 0.000000f}, + {-1.416700f, -1.058300f, 0.000000f}, + {-1.382600f, -1.037800f, 0.100000f}, + {-1.461100f, -0.900000f, 0.100000f}, + {-1.461100f, -0.900000f, 0.100000f}, + {-1.500000f, -0.900000f, 0.000000f}, + {-1.416700f, -1.058300f, 0.000000f}, + {-0.763000f, -1.095800f, 0.100000f}, + {-0.787000f, -1.041700f, 0.100000f}, + {-1.115900f, -1.036400f, 0.100000f}, + {-1.115900f, -1.036400f, 0.100000f}, + {-1.148900f, -1.088600f, 0.100000f}, + {-0.763000f, -1.095800f, 0.100000f}, + {-1.148900f, -1.088600f, 0.100000f}, + {-1.115900f, -1.036400f, 0.100000f}, + {-1.319300f, -0.999700f, 0.100000f}, + {-1.319300f, -0.999700f, 0.100000f}, + {-1.382600f, -1.037800f, 0.100000f}, + {-1.148900f, -1.088600f, 0.100000f}, + {-1.382600f, -1.037800f, 0.100000f}, + {-1.319300f, -0.999700f, 0.100000f}, + {-1.388900f, -0.900000f, 0.100000f}, + {-1.388900f, -0.900000f, 0.100000f}, + {-1.461100f, -0.900000f, 0.100000f}, + {-1.382600f, -1.037800f, 0.100000f}, + {-0.787000f, -1.041700f, 0.100000f}, + {-0.800000f, -1.012500f, 0.000000f}, + {-1.098100f, -1.008300f, 0.000000f}, + {-1.098100f, -1.008300f, 0.000000f}, + {-1.115900f, -1.036400f, 0.100000f}, + {-0.787000f, -1.041700f, 0.100000f}, + {-1.115900f, -1.036400f, 0.100000f}, + {-1.098100f, -1.008300f, 0.000000f}, + {-1.285200f, -0.979200f, 0.000000f}, + {-1.285200f, -0.979200f, 0.000000f}, + {-1.319300f, -0.999700f, 0.100000f}, + {-1.115900f, -1.036400f, 0.100000f}, + {-1.319300f, -0.999700f, 0.100000f}, + {-1.285200f, -0.979200f, 0.000000f}, + {-1.350000f, -0.900000f, 0.000000f}, + {-1.350000f, -0.900000f, 0.000000f}, + {-1.388900f, -0.900000f, 0.100000f}, + {-1.319300f, -0.999700f, 0.100000f}, + {-1.350000f, -0.900000f, 0.000000f}, + {-1.388900f, -0.900000f, -0.100000f}, + {-1.347500f, -0.738500f, -0.100000f}, + {-1.347500f, -0.738500f, -0.100000f}, + {-1.314800f, -0.758300f, 0.000000f}, + {-1.350000f, -0.900000f, 0.000000f}, + {-1.314800f, -0.758300f, 0.000000f}, + {-1.347500f, -0.738500f, -0.100000f}, + {-1.216700f, -0.562900f, -0.100000f}, + {-1.216700f, -0.562900f, -0.100000f}, + {-1.201900f, -0.591700f, 0.000000f}, + {-1.314800f, -0.758300f, 0.000000f}, + {-1.201900f, -0.591700f, 0.000000f}, + {-1.216700f, -0.562900f, -0.100000f}, + {-0.987000f, -0.411100f, -0.100000f}, + {-0.987000f, -0.411100f, -0.100000f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-1.201900f, -0.591700f, 0.000000f}, + {-1.388900f, -0.900000f, -0.100000f}, + {-1.461100f, -0.900000f, -0.100000f}, + {-1.408100f, -0.701700f, -0.100000f}, + {-1.408100f, -0.701700f, -0.100000f}, + {-1.347500f, -0.738500f, -0.100000f}, + {-1.388900f, -0.900000f, -0.100000f}, + {-1.347500f, -0.738500f, -0.100000f}, + {-1.408100f, -0.701700f, -0.100000f}, + {-1.244400f, -0.509400f, -0.100000f}, + {-1.244400f, -0.509400f, -0.100000f}, + {-1.216700f, -0.562900f, -0.100000f}, + {-1.347500f, -0.738500f, -0.100000f}, + {-1.216700f, -0.562900f, -0.100000f}, + {-1.244400f, -0.509400f, -0.100000f}, + {-0.963000f, -0.338900f, -0.100000f}, + {-0.963000f, -0.338900f, -0.100000f}, + {-0.987000f, -0.411100f, -0.100000f}, + {-1.216700f, -0.562900f, -0.100000f}, + {-1.461100f, -0.900000f, -0.100000f}, + {-1.500000f, -0.900000f, 0.000000f}, + {-1.440700f, -0.681900f, 0.000000f}, + {-1.440700f, -0.681900f, 0.000000f}, + {-1.408100f, -0.701700f, -0.100000f}, + {-1.461100f, -0.900000f, -0.100000f}, + {-1.408100f, -0.701700f, -0.100000f}, + {-1.440700f, -0.681900f, 0.000000f}, + {-1.259300f, -0.480600f, 0.000000f}, + {-1.259300f, -0.480600f, 0.000000f}, + {-1.244400f, -0.509400f, -0.100000f}, + {-1.408100f, -0.701700f, -0.100000f}, + {-1.244400f, -0.509400f, -0.100000f}, + {-1.259300f, -0.480600f, 0.000000f}, + {-0.950000f, -0.300000f, 0.000000f}, + {-0.950000f, -0.300000f, 0.000000f}, + {-0.963000f, -0.338900f, -0.100000f}, + {-1.244400f, -0.509400f, -0.100000f}, + {-1.500000f, -0.900000f, 0.000000f}, + {-1.461100f, -0.900000f, 0.100000f}, + {-1.408100f, -0.701700f, 0.100000f}, + {-1.408100f, -0.701700f, 0.100000f}, + {-1.440700f, -0.681900f, 0.000000f}, + {-1.500000f, -0.900000f, 0.000000f}, + {-1.440700f, -0.681900f, 0.000000f}, + {-1.408100f, -0.701700f, 0.100000f}, + {-1.244400f, -0.509400f, 0.100000f}, + {-1.244400f, -0.509400f, 0.100000f}, + {-1.259300f, -0.480600f, 0.000000f}, + {-1.440700f, -0.681900f, 0.000000f}, + {-1.259300f, -0.480600f, 0.000000f}, + {-1.244400f, -0.509400f, 0.100000f}, + {-0.963000f, -0.338900f, 0.100000f}, + {-0.963000f, -0.338900f, 0.100000f}, + {-0.950000f, -0.300000f, 0.000000f}, + {-1.259300f, -0.480600f, 0.000000f}, + {-1.461100f, -0.900000f, 0.100000f}, + {-1.388900f, -0.900000f, 0.100000f}, + {-1.347500f, -0.738500f, 0.100000f}, + {-1.347500f, -0.738500f, 0.100000f}, + {-1.408100f, -0.701700f, 0.100000f}, + {-1.461100f, -0.900000f, 0.100000f}, + {-1.408100f, -0.701700f, 0.100000f}, + {-1.347500f, -0.738500f, 0.100000f}, + {-1.216700f, -0.562900f, 0.100000f}, + {-1.216700f, -0.562900f, 0.100000f}, + {-1.244400f, -0.509400f, 0.100000f}, + {-1.408100f, -0.701700f, 0.100000f}, + {-1.244400f, -0.509400f, 0.100000f}, + {-1.216700f, -0.562900f, 0.100000f}, + {-0.987000f, -0.411100f, 0.100000f}, + {-0.987000f, -0.411100f, 0.100000f}, + {-0.963000f, -0.338900f, 0.100000f}, + {-1.244400f, -0.509400f, 0.100000f}, + {-1.388900f, -0.900000f, 0.100000f}, + {-1.350000f, -0.900000f, 0.000000f}, + {-1.314800f, -0.758300f, 0.000000f}, + {-1.314800f, -0.758300f, 0.000000f}, + {-1.347500f, -0.738500f, 0.100000f}, + {-1.388900f, -0.900000f, 0.100000f}, + {-1.347500f, -0.738500f, 0.100000f}, + {-1.314800f, -0.758300f, 0.000000f}, + {-1.201900f, -0.591700f, 0.000000f}, + {-1.201900f, -0.591700f, 0.000000f}, + {-1.216700f, -0.562900f, 0.100000f}, + {-1.347500f, -0.738500f, 0.100000f}, + {-1.216700f, -0.562900f, 0.100000f}, + {-1.201900f, -0.591700f, 0.000000f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-1.000000f, -0.450000f, 0.000000f}, + {-0.987000f, -0.411100f, 0.100000f}, + {-1.216700f, -0.562900f, 0.100000f}, + {0.850000f, -0.712500f, 0.000000f}, + {0.850000f, -0.605600f, -0.220000f}, + {1.169800f, -0.737100f, -0.184600f}, + {1.169800f, -0.737100f, -0.184600f}, + {1.135200f, -0.805600f, 0.000000f}, + {0.850000f, -0.712500f, 0.000000f}, + {1.135200f, -0.805600f, 0.000000f}, + {1.169800f, -0.737100f, -0.184600f}, + {1.274700f, -0.981400f, -0.118800f}, + {1.274700f, -0.981400f, -0.118800f}, + {1.231500f, -1.006900f, 0.000000f}, + {1.135200f, -0.805600f, 0.000000f}, + {1.231500f, -1.006900f, 0.000000f}, + {1.274700f, -0.981400f, -0.118800f}, + {1.427800f, -1.200000f, -0.083300f}, + {1.427800f, -1.200000f, -0.083300f}, + {1.350000f, -1.200000f, 0.000000f}, + {1.231500f, -1.006900f, 0.000000f}, + {0.850000f, -0.605600f, -0.220000f}, + {0.850000f, -0.406900f, -0.220000f}, + {1.234000f, -0.610100f, -0.184600f}, + {1.234000f, -0.610100f, -0.184600f}, + {1.169800f, -0.737100f, -0.184600f}, + {0.850000f, -0.605600f, -0.220000f}, + {1.169800f, -0.737100f, -0.184600f}, + {1.234000f, -0.610100f, -0.184600f}, + {1.354900f, -0.933900f, -0.118800f}, + {1.354900f, -0.933900f, -0.118800f}, + {1.274700f, -0.981400f, -0.118800f}, + {1.169800f, -0.737100f, -0.184600f}, + {1.274700f, -0.981400f, -0.118800f}, + {1.354900f, -0.933900f, -0.118800f}, + {1.572200f, -1.200000f, -0.083300f}, + {1.572200f, -1.200000f, -0.083300f}, + {1.427800f, -1.200000f, -0.083300f}, + {1.274700f, -0.981400f, -0.118800f}, + {0.850000f, -0.406900f, -0.220000f}, + {0.850000f, -0.300000f, 0.000000f}, + {1.268500f, -0.541700f, 0.000000f}, + {1.268500f, -0.541700f, 0.000000f}, + {1.234000f, -0.610100f, -0.184600f}, + {0.850000f, -0.406900f, -0.220000f}, + {1.234000f, -0.610100f, -0.184600f}, + {1.268500f, -0.541700f, 0.000000f}, + {1.398100f, -0.908300f, 0.000000f}, + {1.398100f, -0.908300f, 0.000000f}, + {1.354900f, -0.933900f, -0.118800f}, + {1.234000f, -0.610100f, -0.184600f}, + {1.354900f, -0.933900f, -0.118800f}, + {1.398100f, -0.908300f, 0.000000f}, + {1.650000f, -1.200000f, 0.000000f}, + {1.650000f, -1.200000f, 0.000000f}, + {1.572200f, -1.200000f, -0.083300f}, + {1.354900f, -0.933900f, -0.118800f}, + {0.850000f, -0.300000f, 0.000000f}, + {0.850000f, -0.406900f, 0.220000f}, + {1.234000f, -0.610100f, 0.184600f}, + {1.234000f, -0.610100f, 0.184600f}, + {1.268500f, -0.541700f, 0.000000f}, + {0.850000f, -0.300000f, 0.000000f}, + {1.268500f, -0.541700f, 0.000000f}, + {1.234000f, -0.610100f, 0.184600f}, + {1.354900f, -0.933900f, 0.118800f}, + {1.354900f, -0.933900f, 0.118800f}, + {1.398100f, -0.908300f, 0.000000f}, + {1.268500f, -0.541700f, 0.000000f}, + {1.398100f, -0.908300f, 0.000000f}, + {1.354900f, -0.933900f, 0.118800f}, + {1.572200f, -1.200000f, 0.083300f}, + {1.572200f, -1.200000f, 0.083300f}, + {1.650000f, -1.200000f, 0.000000f}, + {1.398100f, -0.908300f, 0.000000f}, + {0.850000f, -0.406900f, 0.220000f}, + {0.850000f, -0.605600f, 0.220000f}, + {1.169800f, -0.737100f, 0.184600f}, + {1.169800f, -0.737100f, 0.184600f}, + {1.234000f, -0.610100f, 0.184600f}, + {0.850000f, -0.406900f, 0.220000f}, + {1.234000f, -0.610100f, 0.184600f}, + {1.169800f, -0.737100f, 0.184600f}, + {1.274700f, -0.981400f, 0.118800f}, + {1.274700f, -0.981400f, 0.118800f}, + {1.354900f, -0.933900f, 0.118800f}, + {1.234000f, -0.610100f, 0.184600f}, + {1.354900f, -0.933900f, 0.118800f}, + {1.274700f, -0.981400f, 0.118800f}, + {1.427800f, -1.200000f, 0.083300f}, + {1.427800f, -1.200000f, 0.083300f}, + {1.572200f, -1.200000f, 0.083300f}, + {1.354900f, -0.933900f, 0.118800f}, + {0.850000f, -0.605600f, 0.220000f}, + {0.850000f, -0.712500f, 0.000000f}, + {1.135200f, -0.805600f, 0.000000f}, + {1.135200f, -0.805600f, 0.000000f}, + {1.169800f, -0.737100f, 0.184600f}, + {0.850000f, -0.605600f, 0.220000f}, + {1.169800f, -0.737100f, 0.184600f}, + {1.135200f, -0.805600f, 0.000000f}, + {1.231500f, -1.006900f, 0.000000f}, + {1.231500f, -1.006900f, 0.000000f}, + {1.274700f, -0.981400f, 0.118800f}, + {1.169800f, -0.737100f, 0.184600f}, + {1.274700f, -0.981400f, 0.118800f}, + {1.231500f, -1.006900f, 0.000000f}, + {1.350000f, -1.200000f, 0.000000f}, + {1.350000f, -1.200000f, 0.000000f}, + {1.427800f, -1.200000f, 0.083300f}, + {1.274700f, -0.981400f, 0.118800f}, + {1.350000f, -1.200000f, 0.000000f}, + {1.427800f, -1.200000f, -0.083300f}, + {1.478900f, -1.227200f, -0.074700f}, + {1.478900f, -1.227200f, -0.074700f}, + {1.396300f, -1.225000f, 0.000000f}, + {1.350000f, -1.200000f, 0.000000f}, + {1.396300f, -1.225000f, 0.000000f}, + {1.478900f, -1.227200f, -0.074700f}, + {1.491200f, -1.227700f, -0.058600f}, + {1.491200f, -1.227700f, -0.058600f}, + {1.420400f, -1.225000f, 0.000000f}, + {1.396300f, -1.225000f, 0.000000f}, + {1.420400f, -1.225000f, 0.000000f}, + {1.491200f, -1.227700f, -0.058600f}, + {1.451900f, -1.200000f, -0.050000f}, + {1.451900f, -1.200000f, -0.050000f}, + {1.400000f, -1.200000f, 0.000000f}, + {1.420400f, -1.225000f, 0.000000f}, + {1.427800f, -1.200000f, -0.083300f}, + {1.572200f, -1.200000f, -0.083300f}, + {1.632200f, -1.231200f, -0.074700f}, + {1.632200f, -1.231200f, -0.074700f}, + {1.478900f, -1.227200f, -0.074700f}, + {1.427800f, -1.200000f, -0.083300f}, + {1.478900f, -1.227200f, -0.074700f}, + {1.632200f, -1.231200f, -0.074700f}, + {1.622700f, -1.232700f, -0.058600f}, + {1.622700f, -1.232700f, -0.058600f}, + {1.491200f, -1.227700f, -0.058600f}, + {1.478900f, -1.227200f, -0.074700f}, + {1.491200f, -1.227700f, -0.058600f}, + {1.622700f, -1.232700f, -0.058600f}, + {1.548100f, -1.200000f, -0.050000f}, + {1.548100f, -1.200000f, -0.050000f}, + {1.451900f, -1.200000f, -0.050000f}, + {1.491200f, -1.227700f, -0.058600f}, + {1.572200f, -1.200000f, -0.083300f}, + {1.650000f, -1.200000f, 0.000000f}, + {1.714800f, -1.233300f, 0.000000f}, + {1.714800f, -1.233300f, 0.000000f}, + {1.632200f, -1.231200f, -0.074700f}, + {1.572200f, -1.200000f, -0.083300f}, + {1.632200f, -1.231200f, -0.074700f}, + {1.714800f, -1.233300f, 0.000000f}, + {1.693500f, -1.235400f, 0.000000f}, + {1.693500f, -1.235400f, 0.000000f}, + {1.622700f, -1.232700f, -0.058600f}, + {1.632200f, -1.231200f, -0.074700f}, + {1.622700f, -1.232700f, -0.058600f}, + {1.693500f, -1.235400f, 0.000000f}, + {1.600000f, -1.200000f, 0.000000f}, + {1.600000f, -1.200000f, 0.000000f}, + {1.548100f, -1.200000f, -0.050000f}, + {1.622700f, -1.232700f, -0.058600f}, + {1.650000f, -1.200000f, 0.000000f}, + {1.572200f, -1.200000f, 0.083300f}, + {1.632200f, -1.231200f, 0.074700f}, + {1.632200f, -1.231200f, 0.074700f}, + {1.714800f, -1.233300f, 0.000000f}, + {1.650000f, -1.200000f, 0.000000f}, + {1.714800f, -1.233300f, 0.000000f}, + {1.632200f, -1.231200f, 0.074700f}, + {1.622700f, -1.232700f, 0.058600f}, + {1.622700f, -1.232700f, 0.058600f}, + {1.693500f, -1.235400f, 0.000000f}, + {1.714800f, -1.233300f, 0.000000f}, + {1.693500f, -1.235400f, 0.000000f}, + {1.622700f, -1.232700f, 0.058600f}, + {1.548100f, -1.200000f, 0.050000f}, + {1.548100f, -1.200000f, 0.050000f}, + {1.600000f, -1.200000f, 0.000000f}, + {1.693500f, -1.235400f, 0.000000f}, + {1.572200f, -1.200000f, 0.083300f}, + {1.427800f, -1.200000f, 0.083300f}, + {1.478900f, -1.227200f, 0.074700f}, + {1.478900f, -1.227200f, 0.074700f}, + {1.632200f, -1.231200f, 0.074700f}, + {1.572200f, -1.200000f, 0.083300f}, + {1.632200f, -1.231200f, 0.074700f}, + {1.478900f, -1.227200f, 0.074700f}, + {1.491200f, -1.227700f, 0.058600f}, + {1.491200f, -1.227700f, 0.058600f}, + {1.622700f, -1.232700f, 0.058600f}, + {1.632200f, -1.231200f, 0.074700f}, + {1.622700f, -1.232700f, 0.058600f}, + {1.491200f, -1.227700f, 0.058600f}, + {1.451900f, -1.200000f, 0.050000f}, + {1.451900f, -1.200000f, 0.050000f}, + {1.548100f, -1.200000f, 0.050000f}, + {1.622700f, -1.232700f, 0.058600f}, + {1.427800f, -1.200000f, 0.083300f}, + {1.350000f, -1.200000f, 0.000000f}, + {1.396300f, -1.225000f, 0.000000f}, + {1.396300f, -1.225000f, 0.000000f}, + {1.478900f, -1.227200f, 0.074700f}, + {1.427800f, -1.200000f, 0.083300f}, + {1.478900f, -1.227200f, 0.074700f}, + {1.396300f, -1.225000f, 0.000000f}, + {1.420400f, -1.225000f, 0.000000f}, + {1.420400f, -1.225000f, 0.000000f}, + {1.491200f, -1.227700f, 0.058600f}, + {1.478900f, -1.227200f, 0.074700f}, + {1.491200f, -1.227700f, 0.058600f}, + {1.420400f, -1.225000f, 0.000000f}, + {1.400000f, -1.200000f, 0.000000f}, + {1.400000f, -1.200000f, 0.000000f}, + {1.451900f, -1.200000f, 0.050000f}, + {1.491200f, -1.227700f, 0.058600f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.157100f, -1.533300f, -0.092400f}, + {0.157100f, -1.533300f, -0.092400f}, + {0.181500f, -1.533300f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.181500f, -1.533300f, 0.000000f}, + {0.157100f, -1.533300f, -0.092400f}, + {0.102600f, -1.441700f, -0.060300f}, + {0.102600f, -1.441700f, -0.060300f}, + {0.118500f, -1.441700f, 0.000000f}, + {0.181500f, -1.533300f, 0.000000f}, + {0.118500f, -1.441700f, 0.000000f}, + {0.102600f, -1.441700f, -0.060300f}, + {0.086500f, -1.350000f, -0.050800f}, + {0.086500f, -1.350000f, -0.050800f}, + {0.100000f, -1.350000f, 0.000000f}, + {0.118500f, -1.441700f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.092400f, -1.533300f, -0.157100f}, + {0.092400f, -1.533300f, -0.157100f}, + {0.157100f, -1.533300f, -0.092400f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.157100f, -1.533300f, -0.092400f}, + {0.092400f, -1.533300f, -0.157100f}, + {0.060300f, -1.441700f, -0.102600f}, + {0.060300f, -1.441700f, -0.102600f}, + {0.102600f, -1.441700f, -0.060300f}, + {0.157100f, -1.533300f, -0.092400f}, + {0.102600f, -1.441700f, -0.060300f}, + {0.060300f, -1.441700f, -0.102600f}, + {0.050800f, -1.350000f, -0.086500f}, + {0.050800f, -1.350000f, -0.086500f}, + {0.086500f, -1.350000f, -0.050800f}, + {0.102600f, -1.441700f, -0.060300f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.533300f, -0.181500f}, + {0.000000f, -1.533300f, -0.181500f}, + {0.092400f, -1.533300f, -0.157100f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.092400f, -1.533300f, -0.157100f}, + {0.000000f, -1.533300f, -0.181500f}, + {0.000000f, -1.441700f, -0.118500f}, + {0.000000f, -1.441700f, -0.118500f}, + {0.060300f, -1.441700f, -0.102600f}, + {0.092400f, -1.533300f, -0.157100f}, + {0.060300f, -1.441700f, -0.102600f}, + {0.000000f, -1.441700f, -0.118500f}, + {0.000000f, -1.350000f, -0.100000f}, + {0.000000f, -1.350000f, -0.100000f}, + {0.050800f, -1.350000f, -0.086500f}, + {0.060300f, -1.441700f, -0.102600f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.092400f, -1.533300f, -0.157100f}, + {-0.092400f, -1.533300f, -0.157100f}, + {0.000000f, -1.533300f, -0.181500f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.533300f, -0.181500f}, + {-0.092400f, -1.533300f, -0.157100f}, + {-0.060300f, -1.441700f, -0.102600f}, + {-0.060300f, -1.441700f, -0.102600f}, + {0.000000f, -1.441700f, -0.118500f}, + {0.000000f, -1.533300f, -0.181500f}, + {0.000000f, -1.441700f, -0.118500f}, + {-0.060300f, -1.441700f, -0.102600f}, + {-0.050800f, -1.350000f, -0.086500f}, + {-0.050800f, -1.350000f, -0.086500f}, + {0.000000f, -1.350000f, -0.100000f}, + {0.000000f, -1.441700f, -0.118500f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.157100f, -1.533300f, -0.092400f}, + {-0.157100f, -1.533300f, -0.092400f}, + {-0.092400f, -1.533300f, -0.157100f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.092400f, -1.533300f, -0.157100f}, + {-0.157100f, -1.533300f, -0.092400f}, + {-0.102600f, -1.441700f, -0.060300f}, + {-0.102600f, -1.441700f, -0.060300f}, + {-0.060300f, -1.441700f, -0.102600f}, + {-0.092400f, -1.533300f, -0.157100f}, + {-0.060300f, -1.441700f, -0.102600f}, + {-0.102600f, -1.441700f, -0.060300f}, + {-0.086500f, -1.350000f, -0.050800f}, + {-0.086500f, -1.350000f, -0.050800f}, + {-0.050800f, -1.350000f, -0.086500f}, + {-0.060300f, -1.441700f, -0.102600f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.181500f, -1.533300f, 0.000000f}, + {-0.181500f, -1.533300f, 0.000000f}, + {-0.157100f, -1.533300f, -0.092400f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.157100f, -1.533300f, -0.092400f}, + {-0.181500f, -1.533300f, 0.000000f}, + {-0.118500f, -1.441700f, 0.000000f}, + {-0.118500f, -1.441700f, 0.000000f}, + {-0.102600f, -1.441700f, -0.060300f}, + {-0.157100f, -1.533300f, -0.092400f}, + {-0.102600f, -1.441700f, -0.060300f}, + {-0.118500f, -1.441700f, 0.000000f}, + {-0.100000f, -1.350000f, 0.000000f}, + {-0.100000f, -1.350000f, 0.000000f}, + {-0.086500f, -1.350000f, -0.050800f}, + {-0.102600f, -1.441700f, -0.060300f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.157100f, -1.533300f, 0.092400f}, + {-0.157100f, -1.533300f, 0.092400f}, + {-0.181500f, -1.533300f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.181500f, -1.533300f, 0.000000f}, + {-0.157100f, -1.533300f, 0.092400f}, + {-0.102600f, -1.441700f, 0.060300f}, + {-0.102600f, -1.441700f, 0.060300f}, + {-0.118500f, -1.441700f, 0.000000f}, + {-0.181500f, -1.533300f, 0.000000f}, + {-0.118500f, -1.441700f, 0.000000f}, + {-0.102600f, -1.441700f, 0.060300f}, + {-0.086500f, -1.350000f, 0.050800f}, + {-0.086500f, -1.350000f, 0.050800f}, + {-0.100000f, -1.350000f, 0.000000f}, + {-0.118500f, -1.441700f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.092400f, -1.533300f, 0.157100f}, + {-0.092400f, -1.533300f, 0.157100f}, + {-0.157100f, -1.533300f, 0.092400f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.157100f, -1.533300f, 0.092400f}, + {-0.092400f, -1.533300f, 0.157100f}, + {-0.060300f, -1.441700f, 0.102600f}, + {-0.060300f, -1.441700f, 0.102600f}, + {-0.102600f, -1.441700f, 0.060300f}, + {-0.157100f, -1.533300f, 0.092400f}, + {-0.102600f, -1.441700f, 0.060300f}, + {-0.060300f, -1.441700f, 0.102600f}, + {-0.050800f, -1.350000f, 0.086500f}, + {-0.050800f, -1.350000f, 0.086500f}, + {-0.086500f, -1.350000f, 0.050800f}, + {-0.102600f, -1.441700f, 0.060300f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.533300f, 0.181500f}, + {0.000000f, -1.533300f, 0.181500f}, + {-0.092400f, -1.533300f, 0.157100f}, + {0.000000f, -1.575000f, 0.000000f}, + {-0.092400f, -1.533300f, 0.157100f}, + {0.000000f, -1.533300f, 0.181500f}, + {0.000000f, -1.441700f, 0.118500f}, + {0.000000f, -1.441700f, 0.118500f}, + {-0.060300f, -1.441700f, 0.102600f}, + {-0.092400f, -1.533300f, 0.157100f}, + {-0.060300f, -1.441700f, 0.102600f}, + {0.000000f, -1.441700f, 0.118500f}, + {0.000000f, -1.350000f, 0.100000f}, + {0.000000f, -1.350000f, 0.100000f}, + {-0.050800f, -1.350000f, 0.086500f}, + {-0.060300f, -1.441700f, 0.102600f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.092400f, -1.533300f, 0.157100f}, + {0.092400f, -1.533300f, 0.157100f}, + {0.000000f, -1.533300f, 0.181500f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.533300f, 0.181500f}, + {0.092400f, -1.533300f, 0.157100f}, + {0.060300f, -1.441700f, 0.102600f}, + {0.060300f, -1.441700f, 0.102600f}, + {0.000000f, -1.441700f, 0.118500f}, + {0.000000f, -1.533300f, 0.181500f}, + {0.000000f, -1.441700f, 0.118500f}, + {0.060300f, -1.441700f, 0.102600f}, + {0.050800f, -1.350000f, 0.086500f}, + {0.050800f, -1.350000f, 0.086500f}, + {0.000000f, -1.350000f, 0.100000f}, + {0.000000f, -1.441700f, 0.118500f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.157100f, -1.533300f, 0.092400f}, + {0.157100f, -1.533300f, 0.092400f}, + {0.092400f, -1.533300f, 0.157100f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.092400f, -1.533300f, 0.157100f}, + {0.157100f, -1.533300f, 0.092400f}, + {0.102600f, -1.441700f, 0.060300f}, + {0.102600f, -1.441700f, 0.060300f}, + {0.060300f, -1.441700f, 0.102600f}, + {0.092400f, -1.533300f, 0.157100f}, + {0.060300f, -1.441700f, 0.102600f}, + {0.102600f, -1.441700f, 0.060300f}, + {0.086500f, -1.350000f, 0.050800f}, + {0.086500f, -1.350000f, 0.050800f}, + {0.050800f, -1.350000f, 0.086500f}, + {0.060300f, -1.441700f, 0.102600f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.181500f, -1.533300f, 0.000000f}, + {0.181500f, -1.533300f, 0.000000f}, + {0.157100f, -1.533300f, 0.092400f}, + {0.000000f, -1.575000f, 0.000000f}, + {0.157100f, -1.533300f, 0.092400f}, + {0.181500f, -1.533300f, 0.000000f}, + {0.118500f, -1.441700f, 0.000000f}, + {0.118500f, -1.441700f, 0.000000f}, + {0.102600f, -1.441700f, 0.060300f}, + {0.157100f, -1.533300f, 0.092400f}, + {0.102600f, -1.441700f, 0.060300f}, + {0.118500f, -1.441700f, 0.000000f}, + {0.100000f, -1.350000f, 0.000000f}, + {0.100000f, -1.350000f, 0.000000f}, + {0.086500f, -1.350000f, 0.050800f}, + {0.102600f, -1.441700f, 0.060300f}, + {0.100000f, -1.350000f, 0.000000f}, + {0.086500f, -1.350000f, -0.050800f}, + {0.248300f, -1.294400f, -0.145900f}, + {0.248300f, -1.294400f, -0.145900f}, + {0.287000f, -1.294400f, 0.000000f}, + {0.100000f, -1.350000f, 0.000000f}, + {0.287000f, -1.294400f, 0.000000f}, + {0.248300f, -1.294400f, -0.145900f}, + {0.458200f, -1.255600f, -0.269100f}, + {0.458200f, -1.255600f, -0.269100f}, + {0.529600f, -1.255600f, 0.000000f}, + {0.287000f, -1.294400f, 0.000000f}, + {0.529600f, -1.255600f, 0.000000f}, + {0.458200f, -1.255600f, -0.269100f}, + {0.562400f, -1.200000f, -0.330300f}, + {0.562400f, -1.200000f, -0.330300f}, + {0.650000f, -1.200000f, 0.000000f}, + {0.529600f, -1.255600f, 0.000000f}, + {0.086500f, -1.350000f, -0.050800f}, + {0.050800f, -1.350000f, -0.086500f}, + {0.145900f, -1.294400f, -0.248300f}, + {0.145900f, -1.294400f, -0.248300f}, + {0.248300f, -1.294400f, -0.145900f}, + {0.086500f, -1.350000f, -0.050800f}, + {0.248300f, -1.294400f, -0.145900f}, + {0.145900f, -1.294400f, -0.248300f}, + {0.269100f, -1.255600f, -0.458200f}, + {0.269100f, -1.255600f, -0.458200f}, + {0.458200f, -1.255600f, -0.269100f}, + {0.248300f, -1.294400f, -0.145900f}, + {0.458200f, -1.255600f, -0.269100f}, + {0.269100f, -1.255600f, -0.458200f}, + {0.330300f, -1.200000f, -0.562400f}, + {0.330300f, -1.200000f, -0.562400f}, + {0.562400f, -1.200000f, -0.330300f}, + {0.458200f, -1.255600f, -0.269100f}, + {0.050800f, -1.350000f, -0.086500f}, + {0.000000f, -1.350000f, -0.100000f}, + {0.000000f, -1.294400f, -0.287000f}, + {0.000000f, -1.294400f, -0.287000f}, + {0.145900f, -1.294400f, -0.248300f}, + {0.050800f, -1.350000f, -0.086500f}, + {0.145900f, -1.294400f, -0.248300f}, + {0.000000f, -1.294400f, -0.287000f}, + {0.000000f, -1.255600f, -0.529600f}, + {0.000000f, -1.255600f, -0.529600f}, + {0.269100f, -1.255600f, -0.458200f}, + {0.145900f, -1.294400f, -0.248300f}, + {0.269100f, -1.255600f, -0.458200f}, + {0.000000f, -1.255600f, -0.529600f}, + {0.000000f, -1.200000f, -0.650000f}, + {0.000000f, -1.200000f, -0.650000f}, + {0.330300f, -1.200000f, -0.562400f}, + {0.269100f, -1.255600f, -0.458200f}, + {0.000000f, -1.350000f, -0.100000f}, + {-0.050800f, -1.350000f, -0.086500f}, + {-0.145900f, -1.294400f, -0.248300f}, + {-0.145900f, -1.294400f, -0.248300f}, + {0.000000f, -1.294400f, -0.287000f}, + {0.000000f, -1.350000f, -0.100000f}, + {0.000000f, -1.294400f, -0.287000f}, + {-0.145900f, -1.294400f, -0.248300f}, + {-0.269100f, -1.255600f, -0.458200f}, + {-0.269100f, -1.255600f, -0.458200f}, + {0.000000f, -1.255600f, -0.529600f}, + {0.000000f, -1.294400f, -0.287000f}, + {0.000000f, -1.255600f, -0.529600f}, + {-0.269100f, -1.255600f, -0.458200f}, + {-0.330300f, -1.200000f, -0.562400f}, + {-0.330300f, -1.200000f, -0.562400f}, + {0.000000f, -1.200000f, -0.650000f}, + {0.000000f, -1.255600f, -0.529600f}, + {-0.050800f, -1.350000f, -0.086500f}, + {-0.086500f, -1.350000f, -0.050800f}, + {-0.248300f, -1.294400f, -0.145900f}, + {-0.248300f, -1.294400f, -0.145900f}, + {-0.145900f, -1.294400f, -0.248300f}, + {-0.050800f, -1.350000f, -0.086500f}, + {-0.145900f, -1.294400f, -0.248300f}, + {-0.248300f, -1.294400f, -0.145900f}, + {-0.458200f, -1.255600f, -0.269100f}, + {-0.458200f, -1.255600f, -0.269100f}, + {-0.269100f, -1.255600f, -0.458200f}, + {-0.145900f, -1.294400f, -0.248300f}, + {-0.269100f, -1.255600f, -0.458200f}, + {-0.458200f, -1.255600f, -0.269100f}, + {-0.562400f, -1.200000f, -0.330300f}, + {-0.562400f, -1.200000f, -0.330300f}, + {-0.330300f, -1.200000f, -0.562400f}, + {-0.269100f, -1.255600f, -0.458200f}, + {-0.086500f, -1.350000f, -0.050800f}, + {-0.100000f, -1.350000f, 0.000000f}, + {-0.287000f, -1.294400f, 0.000000f}, + {-0.287000f, -1.294400f, 0.000000f}, + {-0.248300f, -1.294400f, -0.145900f}, + {-0.086500f, -1.350000f, -0.050800f}, + {-0.248300f, -1.294400f, -0.145900f}, + {-0.287000f, -1.294400f, 0.000000f}, + {-0.529600f, -1.255600f, 0.000000f}, + {-0.529600f, -1.255600f, 0.000000f}, + {-0.458200f, -1.255600f, -0.269100f}, + {-0.248300f, -1.294400f, -0.145900f}, + {-0.458200f, -1.255600f, -0.269100f}, + {-0.529600f, -1.255600f, 0.000000f}, + {-0.650000f, -1.200000f, 0.000000f}, + {-0.650000f, -1.200000f, 0.000000f}, + {-0.562400f, -1.200000f, -0.330300f}, + {-0.458200f, -1.255600f, -0.269100f}, + {-0.100000f, -1.350000f, 0.000000f}, + {-0.086500f, -1.350000f, 0.050800f}, + {-0.248300f, -1.294400f, 0.145900f}, + {-0.248300f, -1.294400f, 0.145900f}, + {-0.287000f, -1.294400f, 0.000000f}, + {-0.100000f, -1.350000f, 0.000000f}, + {-0.287000f, -1.294400f, 0.000000f}, + {-0.248300f, -1.294400f, 0.145900f}, + {-0.458200f, -1.255600f, 0.269100f}, + {-0.458200f, -1.255600f, 0.269100f}, + {-0.529600f, -1.255600f, 0.000000f}, + {-0.287000f, -1.294400f, 0.000000f}, + {-0.529600f, -1.255600f, 0.000000f}, + {-0.458200f, -1.255600f, 0.269100f}, + {-0.562400f, -1.200000f, 0.330300f}, + {-0.562400f, -1.200000f, 0.330300f}, + {-0.650000f, -1.200000f, 0.000000f}, + {-0.529600f, -1.255600f, 0.000000f}, + {-0.086500f, -1.350000f, 0.050800f}, + {-0.050800f, -1.350000f, 0.086500f}, + {-0.145900f, -1.294400f, 0.248300f}, + {-0.145900f, -1.294400f, 0.248300f}, + {-0.248300f, -1.294400f, 0.145900f}, + {-0.086500f, -1.350000f, 0.050800f}, + {-0.248300f, -1.294400f, 0.145900f}, + {-0.145900f, -1.294400f, 0.248300f}, + {-0.269100f, -1.255600f, 0.458200f}, + {-0.269100f, -1.255600f, 0.458200f}, + {-0.458200f, -1.255600f, 0.269100f}, + {-0.248300f, -1.294400f, 0.145900f}, + {-0.458200f, -1.255600f, 0.269100f}, + {-0.269100f, -1.255600f, 0.458200f}, + {-0.330300f, -1.200000f, 0.562400f}, + {-0.330300f, -1.200000f, 0.562400f}, + {-0.562400f, -1.200000f, 0.330300f}, + {-0.458200f, -1.255600f, 0.269100f}, + {-0.050800f, -1.350000f, 0.086500f}, + {0.000000f, -1.350000f, 0.100000f}, + {0.000000f, -1.294400f, 0.287000f}, + {0.000000f, -1.294400f, 0.287000f}, + {-0.145900f, -1.294400f, 0.248300f}, + {-0.050800f, -1.350000f, 0.086500f}, + {-0.145900f, -1.294400f, 0.248300f}, + {0.000000f, -1.294400f, 0.287000f}, + {0.000000f, -1.255600f, 0.529600f}, + {0.000000f, -1.255600f, 0.529600f}, + {-0.269100f, -1.255600f, 0.458200f}, + {-0.145900f, -1.294400f, 0.248300f}, + {-0.269100f, -1.255600f, 0.458200f}, + {0.000000f, -1.255600f, 0.529600f}, + {0.000000f, -1.200000f, 0.650000f}, + {0.000000f, -1.200000f, 0.650000f}, + {-0.330300f, -1.200000f, 0.562400f}, + {-0.269100f, -1.255600f, 0.458200f}, + {0.000000f, -1.350000f, 0.100000f}, + {0.050800f, -1.350000f, 0.086500f}, + {0.145900f, -1.294400f, 0.248300f}, + {0.145900f, -1.294400f, 0.248300f}, + {0.000000f, -1.294400f, 0.287000f}, + {0.000000f, -1.350000f, 0.100000f}, + {0.000000f, -1.294400f, 0.287000f}, + {0.145900f, -1.294400f, 0.248300f}, + {0.269100f, -1.255600f, 0.458200f}, + {0.269100f, -1.255600f, 0.458200f}, + {0.000000f, -1.255600f, 0.529600f}, + {0.000000f, -1.294400f, 0.287000f}, + {0.000000f, -1.255600f, 0.529600f}, + {0.269100f, -1.255600f, 0.458200f}, + {0.330300f, -1.200000f, 0.562400f}, + {0.330300f, -1.200000f, 0.562400f}, + {0.000000f, -1.200000f, 0.650000f}, + {0.000000f, -1.255600f, 0.529600f}, + {0.050800f, -1.350000f, 0.086500f}, + {0.086500f, -1.350000f, 0.050800f}, + {0.248300f, -1.294400f, 0.145900f}, + {0.248300f, -1.294400f, 0.145900f}, + {0.145900f, -1.294400f, 0.248300f}, + {0.050800f, -1.350000f, 0.086500f}, + {0.145900f, -1.294400f, 0.248300f}, + {0.248300f, -1.294400f, 0.145900f}, + {0.458200f, -1.255600f, 0.269100f}, + {0.458200f, -1.255600f, 0.269100f}, + {0.269100f, -1.255600f, 0.458200f}, + {0.145900f, -1.294400f, 0.248300f}, + {0.269100f, -1.255600f, 0.458200f}, + {0.458200f, -1.255600f, 0.269100f}, + {0.562400f, -1.200000f, 0.330300f}, + {0.562400f, -1.200000f, 0.330300f}, + {0.330300f, -1.200000f, 0.562400f}, + {0.269100f, -1.255600f, 0.458200f}, + {0.086500f, -1.350000f, 0.050800f}, + {0.100000f, -1.350000f, 0.000000f}, + {0.287000f, -1.294400f, 0.000000f}, + {0.287000f, -1.294400f, 0.000000f}, + {0.248300f, -1.294400f, 0.145900f}, + {0.086500f, -1.350000f, 0.050800f}, + {0.248300f, -1.294400f, 0.145900f}, + {0.287000f, -1.294400f, 0.000000f}, + {0.529600f, -1.255600f, 0.000000f}, + {0.529600f, -1.255600f, 0.000000f}, + {0.458200f, -1.255600f, 0.269100f}, + {0.248300f, -1.294400f, 0.145900f}, + {0.458200f, -1.255600f, 0.269100f}, + {0.529600f, -1.255600f, 0.000000f}, + {0.650000f, -1.200000f, 0.000000f}, + {0.650000f, -1.200000f, 0.000000f}, + {0.562400f, -1.200000f, 0.330300f}, + {0.458200f, -1.255600f, 0.269100f} +}; + +uint16_t indexes[teapot_vertices] = { + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 259, + 260, + 261, + 262, + 263, + 264, + 265, + 266, + 267, + 268, + 269, + 270, + 271, + 272, + 273, + 274, + 275, + 276, + 277, + 278, + 279, + 280, + 281, + 282, + 283, + 284, + 285, + 286, + 287, + 288, + 289, + 290, + 291, + 292, + 293, + 294, + 295, + 296, + 297, + 298, + 299, + 300, + 301, + 302, + 303, + 304, + 305, + 306, + 307, + 308, + 309, + 310, + 311, + 312, + 313, + 314, + 315, + 316, + 317, + 318, + 319, + 320, + 321, + 322, + 323, + 324, + 325, + 326, + 327, + 328, + 329, + 330, + 331, + 332, + 333, + 334, + 335, + 336, + 337, + 338, + 339, + 340, + 341, + 342, + 343, + 344, + 345, + 346, + 347, + 348, + 349, + 350, + 351, + 352, + 353, + 354, + 355, + 356, + 357, + 358, + 359, + 360, + 361, + 362, + 363, + 364, + 365, + 366, + 367, + 368, + 369, + 370, + 371, + 372, + 373, + 374, + 375, + 376, + 377, + 378, + 379, + 380, + 381, + 382, + 383, + 384, + 385, + 386, + 387, + 388, + 389, + 390, + 391, + 392, + 393, + 394, + 395, + 396, + 397, + 398, + 399, + 400, + 401, + 402, + 403, + 404, + 405, + 406, + 407, + 408, + 409, + 410, + 411, + 412, + 413, + 414, + 415, + 416, + 417, + 418, + 419, + 420, + 421, + 422, + 423, + 424, + 425, + 426, + 427, + 428, + 429, + 430, + 431, + 432, + 433, + 434, + 435, + 436, + 437, + 438, + 439, + 440, + 441, + 442, + 443, + 444, + 445, + 446, + 447, + 448, + 449, + 450, + 451, + 452, + 453, + 454, + 455, + 456, + 457, + 458, + 459, + 460, + 461, + 462, + 463, + 464, + 465, + 466, + 467, + 468, + 469, + 470, + 471, + 472, + 473, + 474, + 475, + 476, + 477, + 478, + 479, + 480, + 481, + 482, + 483, + 484, + 485, + 486, + 487, + 488, + 489, + 490, + 491, + 492, + 493, + 494, + 495, + 496, + 497, + 498, + 499, + 500, + 501, + 502, + 503, + 504, + 505, + 506, + 507, + 508, + 509, + 510, + 511, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 529, + 530, + 531, + 532, + 533, + 534, + 535, + 536, + 537, + 538, + 539, + 540, + 541, + 542, + 543, + 544, + 545, + 546, + 547, + 548, + 549, + 550, + 551, + 552, + 553, + 554, + 555, + 556, + 557, + 558, + 559, + 560, + 561, + 562, + 563, + 564, + 565, + 566, + 567, + 568, + 569, + 570, + 571, + 572, + 573, + 574, + 575, + 576, + 577, + 578, + 579, + 580, + 581, + 582, + 583, + 584, + 585, + 586, + 587, + 588, + 589, + 590, + 591, + 592, + 593, + 594, + 595, + 596, + 597, + 598, + 599, + 600, + 601, + 602, + 603, + 604, + 605, + 606, + 607, + 608, + 609, + 610, + 611, + 612, + 613, + 614, + 615, + 616, + 617, + 618, + 619, + 620, + 621, + 622, + 623, + 624, + 625, + 626, + 627, + 628, + 629, + 630, + 631, + 632, + 633, + 634, + 635, + 636, + 637, + 638, + 639, + 640, + 641, + 642, + 643, + 644, + 645, + 646, + 647, + 648, + 649, + 650, + 651, + 652, + 653, + 654, + 655, + 656, + 657, + 658, + 659, + 660, + 661, + 662, + 663, + 664, + 665, + 666, + 667, + 668, + 669, + 670, + 671, + 672, + 673, + 674, + 675, + 676, + 677, + 678, + 679, + 680, + 681, + 682, + 683, + 684, + 685, + 686, + 687, + 688, + 689, + 690, + 691, + 692, + 693, + 694, + 695, + 696, + 697, + 698, + 699, + 700, + 701, + 702, + 703, + 704, + 705, + 706, + 707, + 708, + 709, + 710, + 711, + 712, + 713, + 714, + 715, + 716, + 717, + 718, + 719, + 720, + 721, + 722, + 723, + 724, + 725, + 726, + 727, + 728, + 729, + 730, + 731, + 732, + 733, + 734, + 735, + 736, + 737, + 738, + 739, + 740, + 741, + 742, + 743, + 744, + 745, + 746, + 747, + 748, + 749, + 750, + 751, + 752, + 753, + 754, + 755, + 756, + 757, + 758, + 759, + 760, + 761, + 762, + 763, + 764, + 765, + 766, + 767, + 768, + 769, + 770, + 771, + 772, + 773, + 774, + 775, + 776, + 777, + 778, + 779, + 780, + 781, + 782, + 783, + 784, + 785, + 786, + 787, + 788, + 789, + 790, + 791, + 792, + 793, + 794, + 795, + 796, + 797, + 798, + 799, + 800, + 801, + 802, + 803, + 804, + 805, + 806, + 807, + 808, + 809, + 810, + 811, + 812, + 813, + 814, + 815, + 816, + 817, + 818, + 819, + 820, + 821, + 822, + 823, + 824, + 825, + 826, + 827, + 828, + 829, + 830, + 831, + 832, + 833, + 834, + 835, + 836, + 837, + 838, + 839, + 840, + 841, + 842, + 843, + 844, + 845, + 846, + 847, + 848, + 849, + 850, + 851, + 852, + 853, + 854, + 855, + 856, + 857, + 858, + 859, + 860, + 861, + 862, + 863, + 864, + 865, + 866, + 867, + 868, + 869, + 870, + 871, + 872, + 873, + 874, + 875, + 876, + 877, + 878, + 879, + 880, + 881, + 882, + 883, + 884, + 885, + 886, + 887, + 888, + 889, + 890, + 891, + 892, + 893, + 894, + 895, + 896, + 897, + 898, + 899, + 900, + 901, + 902, + 903, + 904, + 905, + 906, + 907, + 908, + 909, + 910, + 911, + 912, + 913, + 914, + 915, + 916, + 917, + 918, + 919, + 920, + 921, + 922, + 923, + 924, + 925, + 926, + 927, + 928, + 929, + 930, + 931, + 932, + 933, + 934, + 935, + 936, + 937, + 938, + 939, + 940, + 941, + 942, + 943, + 944, + 945, + 946, + 947, + 948, + 949, + 950, + 951, + 952, + 953, + 954, + 955, + 956, + 957, + 958, + 959, + 960, + 961, + 962, + 963, + 964, + 965, + 966, + 967, + 968, + 969, + 970, + 971, + 972, + 973, + 974, + 975, + 976, + 977, + 978, + 979, + 980, + 981, + 982, + 983, + 984, + 985, + 986, + 987, + 988, + 989, + 990, + 991, + 992, + 993, + 994, + 995, + 996, + 997, + 998, + 999, + 1000, + 1001, + 1002, + 1003, + 1004, + 1005, + 1006, + 1007, + 1008, + 1009, + 1010, + 1011, + 1012, + 1013, + 1014, + 1015, + 1016, + 1017, + 1018, + 1019, + 1020, + 1021, + 1022, + 1023, + 1024, + 1025, + 1026, + 1027, + 1028, + 1029, + 1030, + 1031, + 1032, + 1033, + 1034, + 1035, + 1036, + 1037, + 1038, + 1039, + 1040, + 1041, + 1042, + 1043, + 1044, + 1045, + 1046, + 1047, + 1048, + 1049, + 1050, + 1051, + 1052, + 1053, + 1054, + 1055, + 1056, + 1057, + 1058, + 1059, + 1060, + 1061, + 1062, + 1063, + 1064, + 1065, + 1066, + 1067, + 1068, + 1069, + 1070, + 1071, + 1072, + 1073, + 1074, + 1075, + 1076, + 1077, + 1078, + 1079, + 1080, + 1081, + 1082, + 1083, + 1084, + 1085, + 1086, + 1087, + 1088, + 1089, + 1090, + 1091, + 1092, + 1093, + 1094, + 1095, + 1096, + 1097, + 1098, + 1099, + 1100, + 1101, + 1102, + 1103, + 1104, + 1105, + 1106, + 1107, + 1108, + 1109, + 1110, + 1111, + 1112, + 1113, + 1114, + 1115, + 1116, + 1117, + 1118, + 1119, + 1120, + 1121, + 1122, + 1123, + 1124, + 1125, + 1126, + 1127, + 1128, + 1129, + 1130, + 1131, + 1132, + 1133, + 1134, + 1135, + 1136, + 1137, + 1138, + 1139, + 1140, + 1141, + 1142, + 1143, + 1144, + 1145, + 1146, + 1147, + 1148, + 1149, + 1150, + 1151, + 1152, + 1153, + 1154, + 1155, + 1156, + 1157, + 1158, + 1159, + 1160, + 1161, + 1162, + 1163, + 1164, + 1165, + 1166, + 1167, + 1168, + 1169, + 1170, + 1171, + 1172, + 1173, + 1174, + 1175, + 1176, + 1177, + 1178, + 1179, + 1180, + 1181, + 1182, + 1183, + 1184, + 1185, + 1186, + 1187, + 1188, + 1189, + 1190, + 1191, + 1192, + 1193, + 1194, + 1195, + 1196, + 1197, + 1198, + 1199, + 1200, + 1201, + 1202, + 1203, + 1204, + 1205, + 1206, + 1207, + 1208, + 1209, + 1210, + 1211, + 1212, + 1213, + 1214, + 1215, + 1216, + 1217, + 1218, + 1219, + 1220, + 1221, + 1222, + 1223, + 1224, + 1225, + 1226, + 1227, + 1228, + 1229, + 1230, + 1231, + 1232, + 1233, + 1234, + 1235, + 1236, + 1237, + 1238, + 1239, + 1240, + 1241, + 1242, + 1243, + 1244, + 1245, + 1246, + 1247, + 1248, + 1249, + 1250, + 1251, + 1252, + 1253, + 1254, + 1255, + 1256, + 1257, + 1258, + 1259, + 1260, + 1261, + 1262, + 1263, + 1264, + 1265, + 1266, + 1267, + 1268, + 1269, + 1270, + 1271, + 1272, + 1273, + 1274, + 1275, + 1276, + 1277, + 1278, + 1279, + 1280, + 1281, + 1282, + 1283, + 1284, + 1285, + 1286, + 1287, + 1288, + 1289, + 1290, + 1291, + 1292, + 1293, + 1294, + 1295, + 1296, + 1297, + 1298, + 1299, + 1300, + 1301, + 1302, + 1303, + 1304, + 1305, + 1306, + 1307, + 1308, + 1309, + 1310, + 1311, + 1312, + 1313, + 1314, + 1315, + 1316, + 1317, + 1318, + 1319, + 1320, + 1321, + 1322, + 1323, + 1324, + 1325, + 1326, + 1327, + 1328, + 1329, + 1330, + 1331, + 1332, + 1333, + 1334, + 1335, + 1336, + 1337, + 1338, + 1339, + 1340, + 1341, + 1342, + 1343, + 1344, + 1345, + 1346, + 1347, + 1348, + 1349, + 1350, + 1351, + 1352, + 1353, + 1354, + 1355, + 1356, + 1357, + 1358, + 1359, + 1360, + 1361, + 1362, + 1363, + 1364, + 1365, + 1366, + 1367, + 1368, + 1369, + 1370, + 1371, + 1372, + 1373, + 1374, + 1375, + 1376, + 1377, + 1378, + 1379, + 1380, + 1381, + 1382, + 1383, + 1384, + 1385, + 1386, + 1387, + 1388, + 1389, + 1390, + 1391, + 1392, + 1393, + 1394, + 1395, + 1396, + 1397, + 1398, + 1399, + 1400, + 1401, + 1402, + 1403, + 1404, + 1405, + 1406, + 1407, + 1408, + 1409, + 1410, + 1411, + 1412, + 1413, + 1414, + 1415, + 1416, + 1417, + 1418, + 1419, + 1420, + 1421, + 1422, + 1423, + 1424, + 1425, + 1426, + 1427, + 1428, + 1429, + 1430, + 1431, + 1432, + 1433, + 1434, + 1435, + 1436, + 1437, + 1438, + 1439, + 1440, + 1441, + 1442, + 1443, + 1444, + 1445, + 1446, + 1447, + 1448, + 1449, + 1450, + 1451, + 1452, + 1453, + 1454, + 1455, + 1456, + 1457, + 1458, + 1459, + 1460, + 1461, + 1462, + 1463, + 1464, + 1465, + 1466, + 1467, + 1468, + 1469, + 1470, + 1471, + 1472, + 1473, + 1474, + 1475, + 1476, + 1477, + 1478, + 1479, + 1480, + 1481, + 1482, + 1483, + 1484, + 1485, + 1486, + 1487, + 1488, + 1489, + 1490, + 1491, + 1492, + 1493, + 1494, + 1495, + 1496, + 1497, + 1498, + 1499, + 1500, + 1501, + 1502, + 1503, + 1504, + 1505, + 1506, + 1507, + 1508, + 1509, + 1510, + 1511, + 1512, + 1513, + 1514, + 1515, + 1516, + 1517, + 1518, + 1519, + 1520, + 1521, + 1522, + 1523, + 1524, + 1525, + 1526, + 1527, + 1528, + 1529, + 1530, + 1531, + 1532, + 1533, + 1534, + 1535, + 1536, + 1537, + 1538, + 1539, + 1540, + 1541, + 1542, + 1543, + 1544, + 1545, + 1546, + 1547, + 1548, + 1549, + 1550, + 1551, + 1552, + 1553, + 1554, + 1555, + 1556, + 1557, + 1558, + 1559, + 1560, + 1561, + 1562, + 1563, + 1564, + 1565, + 1566, + 1567, + 1568, + 1569, + 1570, + 1571, + 1572, + 1573, + 1574, + 1575, + 1576, + 1577, + 1578, + 1579, + 1580, + 1581, + 1582, + 1583, + 1584, + 1585, + 1586, + 1587, + 1588, + 1589, + 1590, + 1591, + 1592, + 1593, + 1594, + 1595, + 1596, + 1597, + 1598, + 1599, + 1600, + 1601, + 1602, + 1603, + 1604, + 1605, + 1606, + 1607, + 1608, + 1609, + 1610, + 1611, + 1612, + 1613, + 1614, + 1615, + 1616, + 1617, + 1618, + 1619, + 1620, + 1621, + 1622, + 1623, + 1624, + 1625, + 1626, + 1627, + 1628, + 1629, + 1630, + 1631, + 1632, + 1633, + 1634, + 1635, + 1636, + 1637, + 1638, + 1639, + 1640, + 1641, + 1642, + 1643, + 1644, + 1645, + 1646, + 1647, + 1648, + 1649, + 1650, + 1651, + 1652, + 1653, + 1654, + 1655, + 1656, + 1657, + 1658, + 1659, + 1660, + 1661, + 1662, + 1663, + 1664, + 1665, + 1666, + 1667, + 1668, + 1669, + 1670, + 1671, + 1672, + 1673, + 1674, + 1675, + 1676, + 1677, + 1678, + 1679, + 1680, + 1681, + 1682, + 1683, + 1684, + 1685, + 1686, + 1687, + 1688, + 1689, + 1690, + 1691, + 1692, + 1693, + 1694, + 1695, + 1696, + 1697, + 1698, + 1699, + 1700, + 1701, + 1702, + 1703, + 1704, + 1705, + 1706, + 1707, + 1708, + 1709, + 1710, + 1711, + 1712, + 1713, + 1714, + 1715, + 1716, + 1717, + 1718, + 1719, + 1720, + 1721, + 1722, + 1723, + 1724, + 1725, + 1726, + 1727 +}; + +Vec2f tex_coords = { 0.5, 0.5 }; +uint16_t tex_indexes[1728] = { 0 }; + +Mesh mesh_teapot = { + .indexes_count = teapot_vertices, + .positions = positions, + .pos_indices = indexes, + .tex_indices = tex_indexes, + .textCoord = &tex_coords +}; diff --git a/video/src/pingo/assets/teapot.h b/video/src/pingo/assets/teapot.h new file mode 100644 index 00000000..55855362 --- /dev/null +++ b/video/src/pingo/assets/teapot.h @@ -0,0 +1,3 @@ +#include "../render/mesh.h" + +extern Mesh mesh_teapot; diff --git a/video/src/pingo/math/mat3.c b/video/src/pingo/math/mat3.c new file mode 100644 index 00000000..091ae37e --- /dev/null +++ b/video/src/pingo/math/mat3.c @@ -0,0 +1,167 @@ +#include "mat3.h" +#include "vec2.h" + +#include +#include + +Mat3 mat3Identity() { + return (Mat3){{ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 + }}; +} + +Mat3 mat3Translate(Vec2f l) { + F_TYPE x = l.x; + F_TYPE y = l.y; + return (Mat3){{ + 1, 0, x, + 0, 1, y, + 0, 0, 1 + }}; +} + +Mat3 mat3Rotate(F_TYPE theta) { + F_TYPE s = sin(theta); + F_TYPE c = cos(theta); + return (Mat3){{ + c, -s, 0, + s, c, 0, + 0, 0, 1 + }}; +} + +extern Mat3 mat3Scale(Vec2f s) { + F_TYPE p = s.x; + F_TYPE q = s.y; + return (Mat3){{ + p, 0, 0, + 0, q, 0, + 0, 0, 1 + }}; +} + +Vec2f mat3Multiply(Vec2f *v, Mat3 *t) { + F_TYPE a = v->x * t->elements[0] + v->y * t->elements[1] + 1.0 * t->elements[2]; + F_TYPE b = v->x * t->elements[3] + v->y * t->elements[4] + 1.0 * t->elements[5]; + //F_TYPE c = v->x * t->elements[6] + v->y * t->elements[7] + 1.0 * t->elements[8]; + return (Vec2f){a,b}; +} + +Mat3 mat3MultiplyM( Mat3 * m1, Mat3 * m2) { + Mat3 out; + F_TYPE * a = m2->elements; + F_TYPE * b = m1->elements; + out.elements[0] = a[0] * b[0] + a[1] * b[3] + a[2] * b[6]; + out.elements[1] = a[0] * b[1] + a[1] * b[4] + a[2] * b[7]; + out.elements[2] = a[0] * b[2] + a[1] * b[5] + a[2] * b[8]; + out.elements[3] = a[3] * b[0] + a[4] * b[3] + a[5] * b[6]; + out.elements[4] = a[3] * b[1] + a[4] * b[4] + a[5] * b[7]; + out.elements[5] = a[3] * b[2] + a[4] * b[5] + a[5] * b[8]; + out.elements[6] = a[6] * b[0] + a[7] * b[3] + a[8] * b[6]; + out.elements[7] = a[6] * b[1] + a[7] * b[4] + a[8] * b[7]; + out.elements[8] = a[6] * b[2] + a[7] * b[5] + a[8] * b[8]; + return out; +} + +F_TYPE mat3Determinant(Mat3 * mat) +{ + F_TYPE * m = mat->elements; + return m[0] * (m[4] * m[8] - m[5] * m[7]) - + m[3] * (m[3] * m[8] - m[5] * m[6]) + + m[6] * (m[3] * m[7] - m[4] * m[6]); +} + +Mat3 mat3Inverse(Mat3 *v) +{ + F_TYPE * b = v->elements; + F_TYPE s = 1.0 / mat3Determinant(v); + + Mat3 out; + F_TYPE * a = out.elements; + + //calculate inverse + a[0] = (s) * (b[4] * b[8] - b[5] * b[7]); + a[1] = (s) * (b[2] * b[7] - b[1] * b[8]); + a[2] = (s) * (b[1] * b[5] - b[2] * b[4]); + a[3] = (s) * (b[5] * b[6] - b[3] * b[8]); + a[4] = (s) * (b[0] * b[8] - b[2] * b[6]); + a[5] = (s) * (b[2] * b[3] - b[0] * b[5]); + a[6] = (s) * (b[3] * b[7] - b[4] * b[6]); + a[7] = (s) * (b[1] * b[6] - b[0] * b[7]); + a[8] = (s) * (b[0] * b[4] - b[1] * b[3]); + + //homongenize the matrix so that homo coord is 1.0 + a[0] = a[0] / a[8]; + a[1] = a[1] / a[8]; + a[2] = a[2] / a[8]; + a[3] = a[3] / a[8]; + a[4] = a[4] / a[8]; + a[5] = a[5] / a[8]; + a[6] = a[6] / a[8]; + a[7] = a[7] / a[8]; + a[8] = a[8] / a[8]; + + return out; +} + +extern Mat3 mat3Complete( Vec2f origin, Vec2f translation, Vec2f scale, F_TYPE rotation ){ + int isRotated = rotation != 0; + int isScaled = scale.x != 1.0 || scale.y != 1.0; + + //This is just a translation + if (!isRotated && !isScaled) { + return mat3Translate(translation); + } + + //Transform is more complex, translate first in the origin + Mat3 m = mat3Translate((Vec2f){-origin.x,-origin.y}); + + //Apply rotation + if (isRotated) { + Mat3 r = mat3Rotate(rotation); + m = mat3MultiplyM(&m, &r); + } + + //Apply scale + if (isScaled) { + Mat3 s = mat3Scale(scale); + m = mat3MultiplyM(&m, &s); + } + + //Translate it to supposed location + Vec2f finalTranslation = {origin.x + translation.x, origin.y + translation.y}; + Mat3 t = mat3Translate(finalTranslation); + m = mat3MultiplyM(&m, &t); + + return m; +} + +int mat3IsOnlyTranslation(Mat3 *m ) +{ + if (m->elements[0] != 1.0) return 0; + if (m->elements[1] != 0.0) return 0; + //if (m->elements[2] != 0.0) return 0; This is a translation component + if (m->elements[3] != 0.0) return 0; + if (m->elements[4] != 1.0) return 0; + //if (m->elements[5] != 1.0) return 0; This is a translation component + if (m->elements[6] != 0.0) return 0; + if (m->elements[7] != 0.0) return 0; + if (m->elements[8] != 1.0) return 0; + return 1; +} + +int mat3IsOnlyTranslationDoubled(Mat3 *m) +{ + if (m->elements[0] != 2.0) return 0; + if (m->elements[1] != 0.0) return 0; + //if (m->elements[2] != 0.0) return 0; This is a translation component + if (m->elements[3] != 0.0) return 0; + if (m->elements[4] != 2.0) return 0; + //if (m->elements[5] != 1.0) return 0; This is a translation component + if (m->elements[6] != 0.0) return 0; + if (m->elements[7] != 0.0) return 0; + if (m->elements[8] != 1.0) return 0; + return 1; +} diff --git a/video/src/pingo/math/mat3.h b/video/src/pingo/math/mat3.h new file mode 100644 index 00000000..c4e0a2fb --- /dev/null +++ b/video/src/pingo/math/mat3.h @@ -0,0 +1,68 @@ +#pragma once +#include "types.h" +#include "vec2.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct Mat3 { + F_TYPE elements[9]; +} Mat3; + +/* Returns identity + |1|0|x| + |0|1|y| + |0|0|1| +*/ +extern Mat3 mat3Identity(); + +/* Builds a clean translation matrix with x and y translation along relative axes + |1|0|x| + |0|1|y| + |0|0|1| +*/ +extern Mat3 mat3Translate(Vec2f l); + +/* Builds a clean rotation matrix of Θ angle + | c(Θ) | -s(Θ) | 0 | + | s(Θ) | c(Θ) | 0 | + | 0 | 0 | 1 | +*/ +extern Mat3 mat3Rotate(float theta); + + +/* Builds a clean scale matrix of x, y scaling factors + | x | 0 | 0 | + | 0 | y | 0 | + | 0 | 0 | 1 | +*/ +extern Mat3 mat3Scale(Vec2f s); + +//Multiply 2 component vector b 3x3 matrix +extern Vec2f mat3Multiply(Vec2f * v, Mat3 * t); + +//Multiply 3x3 matrix with 3x3 matrix (v*t) +extern Mat3 mat3MultiplyM( Mat3 *v, Mat3 *t); + +//Calculate homogeneous inverse of matrix +extern Mat3 mat3Inverse( Mat3 *v ); + +/* Calculate a complete matrix transformation with translation rotation and scale working as expected + * Rotation and scaled are applied in reference to the provided origin + */ +extern Mat3 mat3Complete( Vec2f origin, Vec2f translation, Vec2f scale, float rotation ); + +//Calculate determinant of matrix +extern F_TYPE mat3Determinant(Mat3 * m); + +//If a matrix has only translation some optimization can be done during rendering. +extern int mat3IsOnlyTranslation(Mat3 *m); + +//If a matrix has only translation and doubles the size some optimization can be done during rendering. +extern int mat3IsOnlyTranslationDoubled(Mat3 *m); + +#ifdef __cplusplus +} +#endif diff --git a/video/src/pingo/math/mat4.c b/video/src/pingo/math/mat4.c new file mode 100644 index 00000000..2d16b56e --- /dev/null +++ b/video/src/pingo/math/mat4.c @@ -0,0 +1,318 @@ +#include "mat4.h" +#include "vec2.h" +#include "vec3.h" +#include "vec4.h" + +#include +#include + +Mat4 mat4Identity() { + return (Mat4){{ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }}; +} + +Mat4 mat4Translate(Vec3f l) { + F_TYPE x = l.x; + F_TYPE y = l.y; + F_TYPE z = l.z; + return (Mat4){{ + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1, + }}; +} + +Mat4 mat4RotateX(F_TYPE phi) { + F_TYPE s = sin(phi); + F_TYPE c = cos(phi); + return (Mat4){{ + 1, 0, 0, 0, + 0, c, -s, 0, + 0, s, c, 0, + 0, 0, 0, 1, + }}; +} +Mat4 mat4RotateY(F_TYPE phi) { + F_TYPE s = sin(phi); + F_TYPE c = cos(phi); + return (Mat4){{ + c, 0, s, 0, + 0, 1, 0, 0, + -s, 0, c, 0, + 0, 0, 0, 1, + }}; +} +Mat4 mat4RotateZ(F_TYPE phi) { + F_TYPE s = sin(phi); + F_TYPE c = cos(phi); + return (Mat4){{ + c, -s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + }}; +} + +extern Mat4 mat4Scale(Vec3f s) { + F_TYPE p = s.x; + F_TYPE q = s.y; + F_TYPE r = s.z; + return (Mat4){{ + p, 0, 0, 0, + 0, q, 0, 0, + 0, 0, r, 0, + 0, 0, 0, 1, + }}; +} + +Vec2f mat4MultiplyVec2(Vec2f *v, Mat4 *t) { + F_TYPE a = v->x * t->elements[0] + v->y * t->elements[1] + 1.0 * t->elements[2] + 1.0 * t->elements[3]; + F_TYPE b = v->x * t->elements[4] + v->y * t->elements[5] + 1.0 * t->elements[6] + 1.0 * t->elements[7]; + return (Vec2f){a,b}; +} + +Vec3f mat4MultiplyVec3(Vec3f *v, Mat4 *t) { + F_TYPE a = v->x * t->elements[0] + v->y * t->elements[1] + v->z * t->elements[2] + 1.0 * t->elements[3]; + F_TYPE b = v->x * t->elements[4] + v->y * t->elements[5] + v->z * t->elements[6] + 1.0 * t->elements[7]; + F_TYPE c = v->x * t->elements[8] + v->y * t->elements[9] + v->z * t->elements[10] + 1.0 * t->elements[11]; + return (Vec3f){a,b,c}; +} + +Vec4f mat4MultiplyVec4(Vec4f *v, Mat4 *t) { + F_TYPE a = v->x * t->elements[0] + v->y * t->elements[1] + v->z * t->elements[2] + 1.0 * t->elements[3]; + F_TYPE b = v->x * t->elements[4] + v->y * t->elements[5] + v->z * t->elements[6] + 1.0 * t->elements[7]; + F_TYPE c = v->x * t->elements[8] + v->y * t->elements[9] + v->z * t->elements[10] + 1.0 * t->elements[11]; + F_TYPE d = v->x * t->elements[12] + v->y * t->elements[13] + v->z * t->elements[14] + 1.0 * t->elements[15]; + return (Vec4f){a,b,c,d}; +} + +Vec4f mat4MultiplyVec4in( Vec4f *v, Mat4 *t ) { + F_TYPE a = v->x * t->elements[0] + v->y * t->elements[4] + v->z * t->elements[8] + 1.0 * t->elements[12]; + F_TYPE b = v->x * t->elements[1] + v->y * t->elements[5] + v->z * t->elements[9] + 1.0 * t->elements[13]; + F_TYPE c = v->x * t->elements[2] + v->y * t->elements[6] + v->z * t->elements[10] + 1.0 * t->elements[14]; + F_TYPE d = v->x * t->elements[3] + v->y * t->elements[7] + v->z * t->elements[1] + 1.0 * t->elements[15]; + return (Vec4f){a,b,c,d}; +} + +Mat4 mat4MultiplyM( Mat4 * m1, Mat4 * m2) { + Mat4 out; + F_TYPE * a = m2->elements; + F_TYPE * b = m1->elements; + + out.elements[0x0] = a[0x0] * b[0x0] + a[0x1] * b[0x4] + a[0x2] * b[0x8] + a[0x3] * b[0xc]; + out.elements[0x1] = a[0x0] * b[0x1] + a[0x1] * b[0x5] + a[0x2] * b[0x9] + a[0x3] * b[0xd]; + out.elements[0x2] = a[0x0] * b[0x2] + a[0x1] * b[0x6] + a[0x2] * b[0xa] + a[0x3] * b[0xe]; + out.elements[0x3] = a[0x0] * b[0x3] + a[0x1] * b[0x7] + a[0x2] * b[0xb] + a[0x3] * b[0xf]; + + out.elements[0x4] = a[0x4] * b[0x0] + a[0x5] * b[0x4] + a[0x6] * b[0x8] + a[0x7] * b[0xc]; + out.elements[0x5] = a[0x4] * b[0x1] + a[0x5] * b[0x5] + a[0x6] * b[0x9] + a[0x7] * b[0xd]; + out.elements[0x6] = a[0x4] * b[0x2] + a[0x5] * b[0x6] + a[0x6] * b[0xa] + a[0x7] * b[0xe]; + out.elements[0x7] = a[0x4] * b[0x3] + a[0x5] * b[0x7] + a[0x6] * b[0xb] + a[0x7] * b[0xf]; + + out.elements[0x8] = a[0x8] * b[0x0] + a[0x9] * b[0x4] + a[0xa] * b[0x8] + a[0xb] * b[0xc]; + out.elements[0x9] = a[0x8] * b[0x1] + a[0x9] * b[0x5] + a[0xa] * b[0x9] + a[0xb] * b[0xd]; + out.elements[0xA] = a[0x8] * b[0x2] + a[0x9] * b[0x6] + a[0xa] * b[0xa] + a[0xb] * b[0xe]; + out.elements[0xB] = a[0x8] * b[0x3] + a[0x9] * b[0x7] + a[0xa] * b[0xb] + a[0xb] * b[0xf]; + + out.elements[0xC] = a[0xc] * b[0x0] + a[0xd] * b[0x4] + a[0xe] * b[0x8] + a[0xf] * b[0xc]; + out.elements[0xD] = a[0xc] * b[0x1] + a[0xd] * b[0x5] + a[0xe] * b[0x9] + a[0xf] * b[0xd]; + out.elements[0xE] = a[0xc] * b[0x2] + a[0xd] * b[0x6] + a[0xe] * b[0xa] + a[0xf] * b[0xe]; + out.elements[0xF] = a[0xc] * b[0x3] + a[0xd] * b[0x7] + a[0xe] * b[0xb] + a[0xf] * b[0xf]; + + return out; +} + +F_TYPE mat4Determinant(Mat4 * mat) +{ + F_TYPE * a = mat->elements; + float a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], + a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], + a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], + a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + F_TYPE b00 = a00 * a11 - a01 * a10; + F_TYPE b01 = a00 * a12 - a02 * a10; + F_TYPE b02 = a00 * a13 - a03 * a10; + F_TYPE b03 = a01 * a12 - a02 * a11; + F_TYPE b04 = a01 * a13 - a03 * a11; + F_TYPE b05 = a02 * a13 - a03 * a12; + F_TYPE b06 = a20 * a31 - a21 * a30; + F_TYPE b07 = a20 * a32 - a22 * a30; + F_TYPE b08 = a20 * a33 - a23 * a30; + F_TYPE b09 = a21 * a32 - a22 * a31; + F_TYPE b10 = a21 * a33 - a23 * a31; + F_TYPE b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; +} + +Mat4 mat4Inverse(Mat4 * mat) +{ + F_TYPE * m = mat->elements; + float inv[16], det; + + inv[0] = m[5] * m[10] * m[15] - + m[5] * m[11] * m[14] - + m[9] * m[6] * m[15] + + m[9] * m[7] * m[14] + + m[13] * m[6] * m[11] - + m[13] * m[7] * m[10]; + + inv[4] = -m[4] * m[10] * m[15] + + m[4] * m[11] * m[14] + + m[8] * m[6] * m[15] - + m[8] * m[7] * m[14] - + m[12] * m[6] * m[11] + + m[12] * m[7] * m[10]; + + inv[8] = m[4] * m[9] * m[15] - + m[4] * m[11] * m[13] - + m[8] * m[5] * m[15] + + m[8] * m[7] * m[13] + + m[12] * m[5] * m[11] - + m[12] * m[7] * m[9]; + + inv[12] = -m[4] * m[9] * m[14] + + m[4] * m[10] * m[13] + + m[8] * m[5] * m[14] - + m[8] * m[6] * m[13] - + m[12] * m[5] * m[10] + + m[12] * m[6] * m[9]; + + inv[1] = -m[1] * m[10] * m[15] + + m[1] * m[11] * m[14] + + m[9] * m[2] * m[15] - + m[9] * m[3] * m[14] - + m[13] * m[2] * m[11] + + m[13] * m[3] * m[10]; + + inv[5] = m[0] * m[10] * m[15] - + m[0] * m[11] * m[14] - + m[8] * m[2] * m[15] + + m[8] * m[3] * m[14] + + m[12] * m[2] * m[11] - + m[12] * m[3] * m[10]; + + inv[9] = -m[0] * m[9] * m[15] + + m[0] * m[11] * m[13] + + m[8] * m[1] * m[15] - + m[8] * m[3] * m[13] - + m[12] * m[1] * m[11] + + m[12] * m[3] * m[9]; + + inv[13] = m[0] * m[9] * m[14] - + m[0] * m[10] * m[13] - + m[8] * m[1] * m[14] + + m[8] * m[2] * m[13] + + m[12] * m[1] * m[10] - + m[12] * m[2] * m[9]; + + inv[2] = m[1] * m[6] * m[15] - + m[1] * m[7] * m[14] - + m[5] * m[2] * m[15] + + m[5] * m[3] * m[14] + + m[13] * m[2] * m[7] - + m[13] * m[3] * m[6]; + + inv[6] = -m[0] * m[6] * m[15] + + m[0] * m[7] * m[14] + + m[4] * m[2] * m[15] - + m[4] * m[3] * m[14] - + m[12] * m[2] * m[7] + + m[12] * m[3] * m[6]; + + inv[10] = m[0] * m[5] * m[15] - + m[0] * m[7] * m[13] - + m[4] * m[1] * m[15] + + m[4] * m[3] * m[13] + + m[12] * m[1] * m[7] - + m[12] * m[3] * m[5]; + + inv[14] = -m[0] * m[5] * m[14] + + m[0] * m[6] * m[13] + + m[4] * m[1] * m[14] - + m[4] * m[2] * m[13] - + m[12] * m[1] * m[6] + + m[12] * m[2] * m[5]; + + inv[3] = -m[1] * m[6] * m[11] + + m[1] * m[7] * m[10] + + m[5] * m[2] * m[11] - + m[5] * m[3] * m[10] - + m[9] * m[2] * m[7] + + m[9] * m[3] * m[6]; + + inv[7] = m[0] * m[6] * m[11] - + m[0] * m[7] * m[10] - + m[4] * m[2] * m[11] + + m[4] * m[3] * m[10] + + m[8] * m[2] * m[7] - + m[8] * m[3] * m[6]; + + inv[11] = -m[0] * m[5] * m[11] + + m[0] * m[7] * m[9] + + m[4] * m[1] * m[11] - + m[4] * m[3] * m[9] - + m[8] * m[1] * m[7] + + m[8] * m[3] * m[5]; + + inv[15] = m[0] * m[5] * m[10] - + m[0] * m[6] * m[9] - + m[4] * m[1] * m[10] + + m[4] * m[2] * m[9] + + m[8] * m[1] * m[6] - + m[8] * m[2] * m[5]; + + det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; + //assert(det != 0); + + Mat4 out; + det = 1.0 / det; + + for (int i = 0; i < 16; i++) + out.elements[i] = inv[i] * det; + + return out; +} + +Mat4 mat4Perspective(float near, float far, float aspect, float fov) +{ + float h = cos(fov/2.0) / sin(fov/2.0); + float w = h / aspect; + float nearFar = near * far; + float farNear = far - near; + + Mat4 m = {{ + w, 0, 0, 0, + 0, h, 0, 0, + 0, 0, far/(farNear), 1, + 0, 0, -nearFar/farNear, 0 + }}; + + return m; +} + +float mat4NearFromProjection(Mat4 mat) +{ + float C = mat.elements[10]; // 2 2 + float D = mat.elements[11]; // 2 3 + + return D / (C - 1.0); +} + +float mat4FarFromProjection(Mat4 mat) +{ + float C = mat.elements[10]; // 2 2 + float D = mat.elements[11]; // 2 3 + + return D / (C + 1.0); +} + + + diff --git a/video/src/pingo/math/mat4.h b/video/src/pingo/math/mat4.h new file mode 100644 index 00000000..b9242bb7 --- /dev/null +++ b/video/src/pingo/math/mat4.h @@ -0,0 +1,41 @@ +#pragma once + +#include "types.h" +#include "vec2.h" +#include "vec3.h" +#include "vec4.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Mat4 { + F_TYPE elements[16]; +} Mat4; + +Mat4 mat4Identity(); +Mat4 mat4Translate(Vec3f l); + +Mat4 mat4RotateX(F_TYPE phi); +Mat4 mat4RotateY(F_TYPE phi); +Mat4 mat4RotateZ(F_TYPE phi); + +Vec2f mat4MultiplyVec2(Vec2f *v, Mat4 *t); +Vec3f mat4MultiplyVec3(Vec3f *v, Mat4 *t); + +Vec4f mat4MultiplyVec4(Vec4f *v, Mat4 *t); +Vec4f mat4MultiplyVec4in( Vec4f *v, Mat4 *t ); + +Mat4 mat4MultiplyM( Mat4 * m1, Mat4 * m2); +Mat4 mat4Inverse(Mat4 * mat); +Mat4 mat4Scale(Vec3f s); + +Mat4 mat4Perspective(float near, float far, float aspect, float fov); +Mat4 mat4Perspective(float near, float far, float aspect, float fov ); + +float mat4NearFromProjection(Mat4 mat); +float mat4FarFromProjection(Mat4 mat); + +#ifdef __cplusplus +} +#endif diff --git a/video/src/pingo/math/types.h b/video/src/pingo/math/types.h new file mode 100644 index 00000000..50450512 --- /dev/null +++ b/video/src/pingo/math/types.h @@ -0,0 +1,13 @@ +#pragma once + +/** + * @brief I_TYPE is the integer type used in the math libraries, change to the desired size + */ +typedef int I_TYPE; + +/** + * @brief F_TYPE is the floating point type used in the math libraries, change to the desired precision + */ +typedef float F_TYPE; + + diff --git a/video/src/pingo/math/vec2.c b/video/src/pingo/math/vec2.c new file mode 100644 index 00000000..29c304d8 --- /dev/null +++ b/video/src/pingo/math/vec2.c @@ -0,0 +1,16 @@ +#include "vec2.h" + +Vec2i vector2ISum(Vec2i l, Vec2i r) +{ + return (Vec2i){l.x+r.x,l.y+r.y}; +} + +Vec2f vecItoF(Vec2i v) +{ + return (Vec2f){v.x,v.y}; +} + +Vec2i vecFtoI(Vec2f v) +{ + return (Vec2i){v.x,v.y}; +} diff --git a/video/src/pingo/math/vec2.h b/video/src/pingo/math/vec2.h new file mode 100644 index 00000000..bc5bff0f --- /dev/null +++ b/video/src/pingo/math/vec2.h @@ -0,0 +1,27 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Vec2i { + I_TYPE x; + I_TYPE y; +} Vec2i; + +typedef struct { + F_TYPE x; + F_TYPE y; +} Vec2f; + +extern Vec2i vector2ISum(Vec2i l, Vec2i r); + +extern Vec2f vecItoF(Vec2i v); + +extern Vec2i vecFtoI(Vec2f v); + +#ifdef __cplusplus +} +#endif diff --git a/video/src/pingo/math/vec3.c b/video/src/pingo/math/vec3.c new file mode 100644 index 00000000..fe671a00 --- /dev/null +++ b/video/src/pingo/math/vec3.c @@ -0,0 +1,62 @@ +#include "vec3.h" +#include + +Vec3f vec3fmul(Vec3f a, float b) +{ + a.x = a.x * b; + a.y = a.y * b; + a.z = a.z * b; + + return a; +} + +Vec3f vec3fsumV(Vec3f a, Vec3f b) +{ + a.x = a.x + b.x; + a.y = a.y + b.y; + a.z = a.z + b.z; + + return a; +} + +Vec3f vec3fsubV(Vec3f a, Vec3f b) +{ + a.x = a.x - b.x; + a.y = a.y - b.y; + a.z = a.z - b.z; + + return a; +} + +Vec3f vec3fsum(Vec3f a, float b) +{ + a.x = a.x + b; + a.y = a.y + b; + a.z = a.z + b; + + return a; +} + +float vec3Dot(Vec3f a, Vec3f b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +Vec3f vec3f(float x, float y, float z) +{ + return (Vec3f){x,y,z}; +} + +Vec3f vec3Cross(Vec3f a, Vec3f b) +{ + + return (Vec3f) {a.y * b.z - b.y * a.z, + a.z * b.x - b.z * a.x, + a.x * b.y - b.x * a.y}; +} + +Vec3f vec3Normalize(Vec3f v) +{ + float sqrt = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); + return (Vec3f){v.x / sqrt, v.y / sqrt, v.z / sqrt}; +} diff --git a/video/src/pingo/math/vec3.h b/video/src/pingo/math/vec3.h new file mode 100644 index 00000000..3c4a9b95 --- /dev/null +++ b/video/src/pingo/math/vec3.h @@ -0,0 +1,32 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Vec3i { + I_TYPE x; + I_TYPE y; + I_TYPE z; +} Vec3i; + +typedef struct Vec3f { + F_TYPE x; + F_TYPE y; + F_TYPE z; +} Vec3f; + +Vec3f vec3f(float,float,float); +Vec3f vec3fmul(Vec3f,float); +Vec3f vec3fsumV(Vec3f,Vec3f); +Vec3f vec3fsubV(Vec3f,Vec3f); +Vec3f vec3fsum(Vec3f,float); +float vec3Dot(Vec3f,Vec3f); +Vec3f vec3Cross(Vec3f,Vec3f); +Vec3f vec3Normalize(Vec3f); + +#ifdef __cplusplus +} +#endif diff --git a/video/src/pingo/math/vec4.c b/video/src/pingo/math/vec4.c new file mode 100644 index 00000000..69dbf3c0 --- /dev/null +++ b/video/src/pingo/math/vec4.c @@ -0,0 +1 @@ +#include "vec4.h" diff --git a/video/src/pingo/math/vec4.h b/video/src/pingo/math/vec4.h new file mode 100644 index 00000000..5bc213c1 --- /dev/null +++ b/video/src/pingo/math/vec4.h @@ -0,0 +1,25 @@ +#pragma once + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct Vec4i { + I_TYPE x; + I_TYPE y; + I_TYPE z; + I_TYPE w; +} Vec4i; + +typedef struct Vec4f { + F_TYPE x; + F_TYPE y; + F_TYPE z; + F_TYPE w; +} Vec4f; + +#ifdef __cplusplus +} +#endif diff --git a/video/src/pingo/render/backend.h b/video/src/pingo/render/backend.h new file mode 100644 index 00000000..e89bc0b6 --- /dev/null +++ b/video/src/pingo/render/backend.h @@ -0,0 +1,33 @@ +#pragma once + +#include "../math/vec2.h" +#include "../math/vec4.h" + +/** + * Privdes a common interface to multiple graphical backends + */ + +typedef struct Renderer Renderer; +typedef struct Pixel Pixel; +typedef struct PingoDepth PingoDepth; +typedef struct Texture Texture; + +typedef struct BackEnd { + //Called on initialization and re-initialization + void (*init)(Renderer *, struct BackEnd *, Vec4i rect); + + //Called before starting rendering + void (*beforeRender)(Renderer *, struct BackEnd * ); + + //Called after having finished a render + void (*afterRender)(Renderer *, struct BackEnd * ); + + //Should return the address of the buffer (height*width*sizeof(Pixel)) + Pixel * (*getFrameBuffer)(Renderer *, struct BackEnd * ); + + //Handle backend specific final framebuffer draw (can apply lighting in a different way if needed) + void (*drawPixel)(Texture * f, Vec2i pos, Pixel color, float illumination); + + //Should return the address of the buffer (height*width*sizeof(Pixel)) + PingoDepth * (*getZetaBuffer)(Renderer *, struct BackEnd * ); +} BackEnd; diff --git a/video/src/pingo/render/depth.c b/video/src/pingo/render/depth.c new file mode 100644 index 00000000..93974bbe --- /dev/null +++ b/video/src/pingo/render/depth.c @@ -0,0 +1,32 @@ +#include "depth.h" + +#ifdef ZBUFFER32 +void depth_write (PingoDepth * d, int idx, float value) { + d[idx].d = (uint32_t)(value * (float)UINT32_MAX); +} + +bool depth_check(PingoDepth * d, int idx, float value){ + return (uint32_t)(value * (float)UINT32_MAX) < d[idx].d; +} +#endif + +#ifdef ZBUFFER16 +void depth_write (PingoDepth * d, int idx, float value) { + d[idx].d = (uint16_t)(value * UINT16_MAX); +} + +bool depth_check(PingoDepth * d, int idx, float value){ + return (uint16_t)(value * UINT16_MAX) < d[idx].d; +} +#endif + +#ifdef ZBUFFER8 +void depth_write (PingoDepth * d, int idx, float value) { + d[idx].d = (uint8_t)(value * UINT8_MAX); +} + +bool depth_check(PingoDepth * d, int idx, float value){ + return (uint8_t)(value * UINT8_MAX) > d[idx].d; +} +#endif + diff --git a/video/src/pingo/render/depth.h b/video/src/pingo/render/depth.h new file mode 100644 index 00000000..9d5fa4a7 --- /dev/null +++ b/video/src/pingo/render/depth.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#define ZBUFFER32 // [ZBUFFER32 | ZBUFFER16 | ZBUFFER8] + +#ifdef ZBUFFER32 +typedef struct PingoDepth { + uint32_t d; +} PingoDepth; +#endif + +#ifdef ZBUFFER16 +typedef struct Depth { + uint16_t d; +} Depth; +#endif + +#ifdef ZBUFFER8 +typedef struct Depth { + uint8_t d; +} Depth; +#endif + +void depth_write(PingoDepth * d, int idx, float value); +bool depth_check(PingoDepth * d, int idx, float value); + diff --git a/video/src/pingo/render/material.c b/video/src/pingo/render/material.c new file mode 100644 index 00000000..996a4d33 --- /dev/null +++ b/video/src/pingo/render/material.c @@ -0,0 +1,5 @@ +#include "material.h" + + + + diff --git a/video/src/pingo/render/material.h b/video/src/pingo/render/material.h new file mode 100644 index 00000000..fe52b174 --- /dev/null +++ b/video/src/pingo/render/material.h @@ -0,0 +1,9 @@ +#pragma once + +#include "texture.h" + +typedef struct Material { + Texture * texture; +} Material; + + diff --git a/video/src/pingo/render/mesh.c b/video/src/pingo/render/mesh.c new file mode 100644 index 00000000..3df4dfb7 --- /dev/null +++ b/video/src/pingo/render/mesh.c @@ -0,0 +1,10 @@ +#include "mesh.h" + + + + + + + + + diff --git a/video/src/pingo/render/mesh.h b/video/src/pingo/render/mesh.h new file mode 100644 index 00000000..7512dd52 --- /dev/null +++ b/video/src/pingo/render/mesh.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "../math/vec2.h" +#include "../math/vec3.h" + +typedef struct Mesh { + int indexes_count; + uint16_t * pos_indices; + uint16_t * tex_indices; + Vec3f * positions; + Vec2f * textCoord; +} Mesh; + + diff --git a/video/src/pingo/render/object.c b/video/src/pingo/render/object.c new file mode 100644 index 00000000..c40a7101 --- /dev/null +++ b/video/src/pingo/render/object.c @@ -0,0 +1,8 @@ +#include "object.h" + + +Renderable object_as_renderable(Object * object) +{ + return (Renderable){.renderableType = RENDERABLE_OBJECT, .impl = object}; +} + diff --git a/video/src/pingo/render/object.h b/video/src/pingo/render/object.h new file mode 100644 index 00000000..0d3205f4 --- /dev/null +++ b/video/src/pingo/render/object.h @@ -0,0 +1,16 @@ +#pragma once + +#include "../math/mat4.h" + +#include "mesh.h" +#include "renderable.h" +#include "material.h" + +typedef struct Object { + Mesh * mesh; + Mat4 transform; + Material * material; +} Object; + +Renderable object_as_renderable(Object * object); + diff --git a/video/src/pingo/render/pixel.c b/video/src/pingo/render/pixel.c new file mode 100644 index 00000000..8581a9ea --- /dev/null +++ b/video/src/pingo/render/pixel.c @@ -0,0 +1,88 @@ +#include "pixel.h" + +#ifdef UINT8 + +extern Pixel pixelRandom() { + return (Pixel){(uint8_t)rand()}; +} + +uint8_t pixelToUInt8(Pixel * p) +{ + return p->g; +} + +extern Pixel pixelFromUInt8( uint8_t g){ + return (Pixel){g}; +} + +extern Pixel pixelMul(Pixel p, float f) +{ + return (Pixel){p.g*f}; +} + +extern Pixel pixelFromRGBA( uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (Pixel){((r + g + b) / 3)}; +} +#endif + +#ifdef RGB888 +extern Pixel pixelRandom() { + return (Pixel){(uint8_t)rand(),(uint8_t)rand(),(uint8_t)rand()}; +} + +uint32_t pixelToRGBA(Pixel * p) +{ + uint8_t g = p->g; + uint32_t a = p->r | p->g <<8 | p->b<<16| 255<<24; + return a; +} +#endif + +#ifdef RGBA8888 +extern Pixel pixelRandom() { + return (Pixel){(uint8_t)rand(),(uint8_t)rand(),(uint8_t)rand(),255}; +} + +extern Pixel pixelFromUInt8( uint8_t g){ + return (Pixel){g,g,g, 255}; +} +extern uint8_t pixelToUInt8( Pixel * p){ + return (p->r + p->g + p->b) / 3; +} + +extern Pixel pixelFromRGBA( uint8_t r, uint8_t g, uint8_t b, uint8_t a){ + return (Pixel){r,g,b,a}; +} + +extern Pixel pixelMul(Pixel p, float f) +{ + return (Pixel){p.r*f,p.g*f,p.b*f,p.a}; +} + +#endif + + +#ifdef BGRA8888 +extern Pixel pixelRandom() { + return (Pixel){(uint8_t)rand(),(uint8_t)rand(),(uint8_t)rand(),255}; +} + +extern Pixel pixelFromUInt8( uint8_t g){ + return (Pixel){g,g,g, 255}; +} + +extern uint8_t pixelToUInt8( Pixel * p){ + return (p->r + p->g + p->b) / 3; +} + +extern Pixel pixelFromRGBA( uint8_t r, uint8_t g, uint8_t b, uint8_t a){ + return (Pixel){b,g,r,a}; +} + +extern Pixel pixelMul(Pixel p, float f) +{ + return (Pixel){p.b*f,p.g*f,p.r*f,p.a}; +} + +#endif diff --git a/video/src/pingo/render/pixel.h b/video/src/pingo/render/pixel.h new file mode 100644 index 00000000..2f6847f6 --- /dev/null +++ b/video/src/pingo/render/pixel.h @@ -0,0 +1,70 @@ +#pragma once + +#include +#include + +//What format to use [ UINT8 | RGB565 | RGBA8888 | BGRA8888 | RGB888 ] +#define BGRA8888 + +//Formats definitions: +#ifdef UINT8 +typedef struct Pixel { + uint8_t g; +}Pixel; +#define PIXELBLACK (Pixel){0} +#define PIXELWHITE (Pixel){255} +#endif + +#ifdef RGB565 +typedef struct Pixel { + uint8_t red:5; + uint8_t green:6; + uint8_t blue:5; +}Pixel; +#define PIXELBLACK (Pixel){0} +#define PIXELWHITE (Pixel){255} +#endif + +#ifdef RGB888 +typedef struct Pixel { + uint8_t r; + uint8_t g; + uint8_t b; +} Pixel; + +#define PIXELBLACK (Pixel){0,0,0} +#define PIXELWHITE (Pixel){255,255,255} +#endif + +#ifdef RGBA8888 +typedef struct Pixel { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +} Pixel; + +#define PIXELBLACK (Pixel){0,0,0,255} +#define PIXELWHITE (Pixel){255,255,255,255} +#endif + +#ifdef BGRA8888 +typedef struct Pixel { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; +} Pixel; + +#define PIXELBLACK (Pixel){0,0,0,255} +#define PIXELWHITE (Pixel){255,255,255,255} +#endif + + + +//Interface +extern Pixel pixelRandom(); +extern Pixel pixelFromUInt8( uint8_t); +extern uint8_t pixelToUInt8( Pixel *); +extern Pixel pixelFromRGBA( uint8_t r, uint8_t g, uint8_t b, uint8_t a); +extern Pixel pixelMul( Pixel p, float f); diff --git a/video/src/pingo/render/rasterizer.c b/video/src/pingo/render/rasterizer.c new file mode 100644 index 00000000..3b85e180 --- /dev/null +++ b/video/src/pingo/render/rasterizer.c @@ -0,0 +1,242 @@ +#include "rasterizer.h" +#include "renderer.h" +#include "../math/mat3.h" +#include "../math/mat4.h" + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +Vec2i vec2iClamp(Vec2i in, Vec2i min, Vec2i max) { + in.x = (in.x > max.x-1)? max.x-1 : (in.x < min.x)? min.x : in.x; + in.y = (in.y > max.y-1)? max.y-1 : (in.y < min.y)? min.y : in.y; + return in; +} + +int rasterizer_draw_pixel_perfect(Vec2i off, Renderer *r, Texture * src) { + Texture des = r->frameBuffer; + + //Transform coords on destination (it is only translation so it is easy) + Vec2f a = (Vec2f){off.x,off.y}; + Vec2f b = (Vec2f){off.x+src->size.x,off.y}; + Vec2f c = (Vec2f){off.x,off.y+src->size.y}; + Vec2f d = (Vec2f){off.x+src->size.x,off.y+src->size.y}; + + // .. To find the axis aligned boundig box + int minX = MIN(MIN(a.x,b.x),MIN(c.x,d.x)); + int minY = MIN(MIN(a.y,b.y),MIN(c.y,d.y)); + int maxX = MAX(MAX(a.x,b.x),MAX(c.x,d.x)); + int maxY = MAX(MAX(a.y,b.y),MAX(c.y,d.y)); + + //Then clamp max/min values to destination buffer + maxX = MIN(des.size.x, MAX(maxX, 0)); + maxY = MIN(des.size.y, MAX(maxY, 0)); + minX = MIN(des.size.x, MAX(minX, 0)); + minY = MIN(des.size.y, MAX(minY, 0)); + + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + //Transform the coordinate back to sprite space + Vec2i desPos = {x,y}; + Vec2i srcPosI = {x-off.x,y-off.y}; + Pixel color = texture_read(src, srcPosI); + texture_draw(&des, desPos, color); + } + } + + return 0; +} + +int rasterizer_draw_pixel_perfect_doubled(Vec2i off, Renderer *r, Texture * src) { + Texture des = r->frameBuffer; + + //Transform coords on destination (double the size of the frame) + Vec2f a = (Vec2f){off.x,off.y}; + Vec2f b = (Vec2f){off.x+src->size.x*2,off.y}; + Vec2f c = (Vec2f){off.x,off.y+src->size.y*2}; + Vec2f d = (Vec2f){off.x+src->size.x*2,off.y+src->size.y*2}; + + // .. To find the axis aligned boundig box + int minX = MIN(MIN(a.x,b.x),MIN(c.x,d.x)); + int minY = MIN(MIN(a.y,b.y),MIN(c.y,d.y)); + int maxX = MAX(MAX(a.x,b.x),MAX(c.x,d.x)); + int maxY = MAX(MAX(a.y,b.y),MAX(c.y,d.y)); + + //Then clamp max/min values to destination buffer + maxX = MIN(des.size.x, MAX(maxX, 0)); + maxY = MIN(des.size.y, MAX(maxY, 0)); + minX = MIN(des.size.x, MAX(minX, 0)); + minY = MIN(des.size.y, MAX(minY, 0)); + + for (int y = minY; y < maxY; y+=2) { + for (int x = minX; x < maxX; x=x+2) { + //Transform the coordinate back to sprite space + Vec2i srcPosI = {(x-off.x)/2,(y-off.y)/2}; + Pixel color = texture_read(src, srcPosI); + texture_draw(&des, (Vec2i){x,y}, color); + texture_draw(&des, (Vec2i){x+1,y}, color); + } + for (int x = minX; x < maxX; x=x+2) { + //Transform the coordinate back to sprite space + Vec2i srcPosI = {(x-off.x)/2,(y-off.y)/2}; + Pixel color = texture_read(src, srcPosI); + texture_draw(&des, (Vec2i){x,y+1}, color); + texture_draw(&des, (Vec2i){x+1,y+1}, color); + } + } + + return 0; +} + +int rasterizer_draw_transformed(Mat4 t, Renderer *r, Texture * src) { + Texture des = r->frameBuffer; + + Mat4 inv = mat4Inverse(&t); + + // Transform 4 points of frame to frame buffer space + Vec2f a = (Vec2f){0,0}; + Vec2f b = (Vec2f){src->size.x,0}; + Vec2f c = (Vec2f){0,src->size.y}; + Vec2f d = (Vec2f){src->size.x,src->size.y}; + + a = mat4MultiplyVec2(&a, &t); + b = mat4MultiplyVec2(&b, &t); + c = mat4MultiplyVec2(&c, &t); + d = mat4MultiplyVec2(&d, &t); + + // .. To find the axis aligned boundig box + int minX = MIN(MIN(a.x,b.x),MIN(c.x,d.x)); + int minY = MIN(MIN(a.y,b.y),MIN(c.y,d.y)); + int maxX = MAX(MAX(a.x,b.x),MAX(c.x,d.x)); + int maxY = MAX(MAX(a.y,b.y),MAX(c.y,d.y)); + + //Then clamp max/min values to destination buffer + maxX = MIN(des.size.x, MAX(maxX, 0)); + maxY = MIN(des.size.y, MAX(maxY, 0)); + minX = MIN(des.size.x, MAX(minX, 0)); + minY = MIN(des.size.y, MAX(minY, 0)); + + //Now we can iterate over the pixels of the axis-alignes-bounding-box (AABB) which contain the source frame + for (int y = minY; y <= maxY; y++) { + for (int x = minX; x <= maxX; x++) { + + +#ifdef FILTERING_NEAREST + //Transform the coordinate back to sprite space with the inverse tranform + Vec2i desPos = {x,y}; + Vec2f desPosF = (Vec2f){desPos.x+0.5,desPos.y+0.5}; + Vec2f srcPosF = mat4MultiplyVec2(&desPosF,&inv); + Vec2i srcPosI = vecFtoI(srcPosF); + + //TODO: Improve this check by precalculating start/end coord in loop with line intersection + //We need to check if transformed coord are inside the frame + //Probably there is a faster way of doing this by checking line intersection + //with the sprite transformed quad but I don't care for now because we + //do not use rotations as of now. + if (srcPosF.x < 0) continue; + if (srcPosF.y < 0) continue; + if (srcPosF.x >= src->size.x) continue; + if (srcPosF.y >= src->size.y) continue; + Pixel color = texture_read(src, srcPosI); +#endif +#ifdef FILTERING_BILINEAR + Vec2i desPos = {x,y}; + Vec2f desPosF = (Vec2f){desPos.x+0.5f,desPos.y+0.5f}; + Vec2f srcPosF = mat4Multiply(&desPosF,&inv); + + //TODO: Improve this check by precalculating start/end coord in loop with line intersection + //We need to check if transformed coord are inside the frame + //Probably there is a faster way of doing this by checking line intersection + //with the sprite transformed quad but I don't care for now because we + //do not use rotations as of now. + if (srcPosF.x < 0) continue; + if (srcPosF.y < 0) continue; + if (srcPosF.x >= src->size.x-1) continue; + if (srcPosF.y >= src->size.y-1) continue; + + Pixel color = frameReadBilinear(src, srcPosF); +#endif +#ifdef FILTERING_ANISOTROPIC //4X + Vec2i desPos = {x,y}; + Vec2f desPosF1 = (Vec2f){desPos.x+0.25f,desPos.y+0.25f}; + Vec2f desPosF2 = (Vec2f){desPos.x+0.75f,desPos.y+0.75f}; + Vec2f srcPosF1 = mat4Multiply(&desPosF1,&inv); + Vec2f srcPosF2 = mat4Multiply(&desPosF2,&inv); + + if (srcPosF1.x < 0 && srcPosF2.x < 0) continue; + if (srcPosF1.y < 0 && srcPosF2.y < 0) continue; + if (srcPosF1.x > src->size.x && srcPosF2.x > src->size.x) continue; + if (srcPosF1.y > src->size.y && srcPosF2.y > src->size.y) continue; + + Vec2i srcPosI1 = vec2iClamp((Vec2i) {srcPosF1.x,srcPosF1.y},(Vec2i){0,0},src->size); + Vec2i srcPosI2 = vec2iClamp((Vec2i) {srcPosF1.x,srcPosF2.y},(Vec2i){0,0},src->size); + Vec2i srcPosI3 = vec2iClamp((Vec2i) {srcPosF2.x,srcPosF1.y},(Vec2i){0,0},src->size); + Vec2i srcPosI4 = vec2iClamp((Vec2i) {srcPosF2.x,srcPosF2.y},(Vec2i){0,0},src->size); + + float p1 = src->frameBuffer[(int)(srcPosI1.x + srcPosI1.y * src->size.x)].g; + float p2 = src->frameBuffer[(int)(srcPosI2.x + srcPosI2.y * src->size.x)].g; + float p3 = src->frameBuffer[(int)(srcPosI3.x + srcPosI3.y * src->size.x)].g; + float p4 = src->frameBuffer[(int)(srcPosI4.x + srcPosI4.y * src->size.x)].g; + + Pixel color = {(p1+p2+p3+p4) / 4}; +#endif +#ifdef FILTERING_ANISOTROPICX2 //8X + Vec2i desPos = {x,y}; + Vec2f desPosF1 = (Vec2f){desPos.x+0.125f,desPos.y+0.125f}; + Vec2f desPosF2 = (Vec2f){desPos.x+0.375f,desPos.y+0.375f}; + Vec2f desPosF3 = (Vec2f){desPos.x+0.625f,desPos.y+0.625f}; + Vec2f desPosF4 = (Vec2f){desPos.x+0.875f,desPos.y+0.875f}; + + Vec2f srcPosF1 = mat4MultiplyVec2(&desPosF1,&inv); + Vec2f srcPosF2 = mat4MultiplyVec2(&desPosF2,&inv); + Vec2f srcPosF3 = mat4MultiplyVec2(&desPosF3,&inv); + Vec2f srcPosF4 = mat4MultiplyVec2(&desPosF4,&inv); + + if (srcPosF1.x < 0 && srcPosF2.x < 0 && srcPosF3.x < 0 && srcPosF4.x < 0) continue; + if (srcPosF1.y < 0 && srcPosF2.y < 0 && srcPosF3.y < 0 && srcPosF4.y < 0) continue; + if (srcPosF1.x > src->size.x && srcPosF2.x > src->size.x && + srcPosF3.x > src->size.x && srcPosF4.x > src->size.x) continue; + if (srcPosF1.y > src->size.y && srcPosF2.y > src->size.y && + srcPosF3.y > src->size.y && srcPosF4.y > src->size.y) continue; + + Vec2i srcPosI1 = vec2iClamp((Vec2i) {srcPosF1.x,srcPosF1.y},(Vec2i){0,0},src->size); + Vec2i srcPosI2 = vec2iClamp((Vec2i) {srcPosF1.x,srcPosF2.y},(Vec2i){0,0},src->size); + Vec2i srcPosI3 = vec2iClamp((Vec2i) {srcPosF1.x,srcPosF3.y},(Vec2i){0,0},src->size); + Vec2i srcPosI4 = vec2iClamp((Vec2i) {srcPosF1.x,srcPosF4.y},(Vec2i){0,0},src->size); + Vec2i srcPosI5 = vec2iClamp((Vec2i) {srcPosF2.x,srcPosF1.y},(Vec2i){0,0},src->size); + Vec2i srcPosI6 = vec2iClamp((Vec2i) {srcPosF2.x,srcPosF2.y},(Vec2i){0,0},src->size); + Vec2i srcPosI7 = vec2iClamp((Vec2i) {srcPosF2.x,srcPosF3.y},(Vec2i){0,0},src->size); + Vec2i srcPosI8 = vec2iClamp((Vec2i) {srcPosF2.x,srcPosF4.y},(Vec2i){0,0},src->size); + Vec2i srcPosI9 = vec2iClamp((Vec2i) {srcPosF3.x,srcPosF1.y},(Vec2i){0,0},src->size); + Vec2i srcPosI0 = vec2iClamp((Vec2i) {srcPosF3.x,srcPosF2.y},(Vec2i){0,0},src->size); + Vec2i srcPosI11 = vec2iClamp((Vec2i) {srcPosF3.x,srcPosF3.y},(Vec2i){0,0},src->size); + Vec2i srcPosI12 = vec2iClamp((Vec2i) {srcPosF3.x,srcPosF4.y},(Vec2i){0,0},src->size); + Vec2i srcPosI13 = vec2iClamp((Vec2i) {srcPosF4.x,srcPosF1.y},(Vec2i){0,0},src->size); + Vec2i srcPosI14 = vec2iClamp((Vec2i) {srcPosF4.x,srcPosF2.y},(Vec2i){0,0},src->size); + Vec2i srcPosI15 = vec2iClamp((Vec2i) {srcPosF4.x,srcPosF3.y},(Vec2i){0,0},src->size); + Vec2i srcPosI16 = vec2iClamp((Vec2i) {srcPosF4.x,srcPosF4.y},(Vec2i){0,0},src->size); + + float p1 = src->frameBuffer[(int)(srcPosI1.x + srcPosI1.y * src->size.x)].g; + float p2 = src->frameBuffer[(int)(srcPosI2.x + srcPosI2.y * src->size.x)].g; + float p3 = src->frameBuffer[(int)(srcPosI3.x + srcPosI3.y * src->size.x)].g; + float p4 = src->frameBuffer[(int)(srcPosI4.x + srcPosI4.y * src->size.x)].g; + float p5 = src->frameBuffer[(int)(srcPosI5.x + srcPosI5.y * src->size.x)].g; + float p6 = src->frameBuffer[(int)(srcPosI6.x + srcPosI6.y * src->size.x)].g; + float p7 = src->frameBuffer[(int)(srcPosI7.x + srcPosI7.y * src->size.x)].g; + float p8 = src->frameBuffer[(int)(srcPosI8.x + srcPosI8.y * src->size.x)].g; + float p9 = src->frameBuffer[(int)(srcPosI9.x + srcPosI9.y * src->size.x)].g; + float p0 = src->frameBuffer[(int)(srcPosI0.x + srcPosI0.y * src->size.x)].g; + float p11 = src->frameBuffer[(int)(srcPosI11.x + srcPosI11.y * src->size.x)].g; + float p12 = src->frameBuffer[(int)(srcPosI12.x + srcPosI12.y * src->size.x)].g; + float p13 = src->frameBuffer[(int)(srcPosI13.x + srcPosI13.y * src->size.x)].g; + float p14 = src->frameBuffer[(int)(srcPosI14.x + srcPosI14.y * src->size.x)].g; + float p15 = src->frameBuffer[(int)(srcPosI15.x + srcPosI15.y * src->size.x)].g; + float p16 = src->frameBuffer[(int)(srcPosI16.x + srcPosI16.y * src->size.x)].g; + + Pixel color = pixelFromUInt8((p1+p2+p3+p4+p5+p6+p7+p8+p9+p0+p11+p12+p13+p14+p15+p16) / 16); +#endif + texture_draw(&des, desPos, color); + } + } + + return 0; +} diff --git a/video/src/pingo/render/rasterizer.h b/video/src/pingo/render/rasterizer.h new file mode 100644 index 00000000..be32a764 --- /dev/null +++ b/video/src/pingo/render/rasterizer.h @@ -0,0 +1,28 @@ +#pragma once + +#include "texture.h" +#include "sprite.h" +#include "renderable.h" + +/** + * Defines the type of filtering used when textures are resized and rotated + * by a transformation. Nearest filtering just take 1 texture sample in the + * single pixel which the source coordinate is tranformed to. + * Bilinear filtering takes 4 samples on the source texture to compute a + * weighted average of those 4 values based on the distance of the input + * point. + * Anisotropic filtering takes 4/16 samples from the source image + * distributed uniformly over the area occupied by the destination pixel on + * the source image and makes an average of those values. + */ + +#define FILTERING_NEAREST +//#define FILTERING_BILINEAR +//#define FILTERING_ANISOTROPIC +//#define FILTERING_ANISOTROPICX2 + +int rasterizer_draw_pixel_perfect(Vec2i off, Renderer *r, Texture * src); + +int rasterizer_draw_pixel_perfect_doubled(Vec2i off, Renderer *r, Texture * src); + +int rasterizer_draw_transformed(Mat4 t, Renderer *r, Texture * src); diff --git a/video/src/pingo/render/renderable.c b/video/src/pingo/render/renderable.c new file mode 100644 index 00000000..60841560 --- /dev/null +++ b/video/src/pingo/render/renderable.c @@ -0,0 +1,5 @@ +#include "renderable.h" +#include "renderer.h" + +int (*renderingFunctions[RENDERABLE_COUNT])(Mat4 transform, Renderer *, Renderable); + diff --git a/video/src/pingo/render/renderable.h b/video/src/pingo/render/renderable.h new file mode 100644 index 00000000..24941d9f --- /dev/null +++ b/video/src/pingo/render/renderable.h @@ -0,0 +1,21 @@ +#pragma once + +#include "../math/mat4.h" + +typedef struct Renderer Renderer; + +typedef enum { + RENDERABLE_SCENE =0, + RENDERABLE_SPRITE, + RENDERABLE_OBJECT, + RENDERABLE_COUNT, +} RenderableType; + +typedef struct { + RenderableType renderableType; + void * impl; +} Renderable; + +extern int (*renderingFunctions[RENDERABLE_COUNT])(Mat4 transform, Renderer *, Renderable); + + diff --git a/video/src/pingo/render/renderer.c b/video/src/pingo/render/renderer.c new file mode 100644 index 00000000..02502e66 --- /dev/null +++ b/video/src/pingo/render/renderer.c @@ -0,0 +1,308 @@ +#include +#include +#include "renderer.h" +#include "sprite.h" +#include "pixel.h" +#include "depth.h" +#include "backend.h" +#include "scene.h" +#include "rasterizer.h" +#include "object.h" +/*#include "../backend/ttgobackend.h"*/ + +extern void show_pixel(uint8_t a, uint8_t b, uint8_t g, uint8_t r); + +int renderFrame(Renderer * r, Renderable ren) { + Texture * f = ren.impl; + return rasterizer_draw_pixel_perfect((Vec2i) { 0, 0 }, r, f); +}; + +int renderSprite(Mat4 transform, Renderer * r, Renderable ren) { + Sprite * s = ren.impl; + Mat4 backUp = s->t; + + //Apply parent transform to the local transform + s->t = mat4MultiplyM( & s->t, & transform); + + //Apply camera translation + Mat4 newMat = mat4Translate((Vec3f) { -r->camera.x, -r->camera.y, 0 }); + s->t = mat4MultiplyM( & s->t, & newMat); + + /* + if (mat4IsOnlyTranslation(&s->t)) { + Vec2i off = {s->t.elements[2], s->t.elements[5]}; + rasterizer_draw_pixel_perfect(off,r, &s->frame); + s->t = backUp; + return 0; + } + + if (mat4IsOnlyTranslationDoubled(&s->t)) { + Vec2i off = {s->t.elements[2], s->t.elements[5]}; + rasterizer_draw_pixel_perfect_doubled(off,r, &s->frame); + s->t = backUp; + return 0; + }*/ + + rasterizer_draw_transformed(s->t, r, & s->frame); + s->t = backUp; + return 0; +}; + +void renderRenderable(Mat4 transform, Renderer * r, Renderable ren) { + renderingFunctions[ren.renderableType](transform, r, ren); +}; + +int renderScene(Mat4 transform, Renderer * r, Renderable ren) { + Scene * s = ren.impl; + if (!s->visible) + return 0; + + //Apply hierarchy transfom + Mat4 newTransform = mat4MultiplyM( & s->transform, & transform); + for (int i = 0; i < s->numberOfRenderables; i++) { + renderRenderable(newTransform, r, s->renderables[i]); + } + return 0; +}; + +#define MIN(a, b)(((a) < (b)) ? (a) : (b)) +#define MAX(a, b)(((a) > (b)) ? (a) : (b)) + +int edgeFunction(const Vec2f * a, const Vec2f * b, const Vec2f * c) { + return (c->x - a->x) * (b->y - a->y) - (c->y - a->y) * (b->x - a->x); +} + +float isClockWise(float x1, float y1, float x2, float y2, float x3, float y3) { + return (y2 - y1) * (x3 - x2) - (y3 - y2) * (x2 - x1); +} + +int orient2d( Vec2i a, Vec2i b, Vec2i c) +{ + return (b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x); +} + +void backendDrawPixel (Renderer * r, Texture * f, Vec2i pos, Pixel color, float illumination) { + //If backend spcifies something.. + if (r->backEnd->drawPixel != 0) + r->backEnd->drawPixel(f, pos, color, illumination); + + //By default call this + texture_draw(f, pos, pixelMul(color,illumination)); +} + +int renderObject(Mat4 object_transform, Renderer * r, Renderable ren) { + + const Vec2i scrSize = r->frameBuffer.size; + Object * o = ren.impl; + + // MODEL MATRIX + Mat4 m = mat4MultiplyM( &o->transform, &object_transform ); + + // VIEW MATRIX + Mat4 v = r->camera_view; + Mat4 p = r->camera_projection; + + for (int i = 0; i < o->mesh->indexes_count; i += 3) { + Vec3f * ver1 = &o->mesh->positions[o->mesh->pos_indices[i+0]]; + Vec3f * ver2 = &o->mesh->positions[o->mesh->pos_indices[i+1]]; + Vec3f * ver3 = &o->mesh->positions[o->mesh->pos_indices[i+2]]; + + Vec2f tca = {0,0}; + Vec2f tcb = {0,0}; + Vec2f tcc = {0,0}; + + if (o->material != 0) { + tca = o->mesh->textCoord[o->mesh->tex_indices[i+0]]; + tcb = o->mesh->textCoord[o->mesh->tex_indices[i+1]]; + tcc = o->mesh->textCoord[o->mesh->tex_indices[i+2]]; + } + + Vec4f a = { ver1->x, ver1->y, ver1->z, 1 }; + Vec4f b = { ver2->x, ver2->y, ver2->z, 1 }; + Vec4f c = { ver3->x, ver3->y, ver3->z, 1 }; + + a = mat4MultiplyVec4( &a, &m); + b = mat4MultiplyVec4( &b, &m); + c = mat4MultiplyVec4( &c, &m); + + //Calc Face Normal + Vec3f na = vec3fsubV(*((Vec3f*)(&a)), *((Vec3f*)(&b))); + Vec3f nb = vec3fsubV(*((Vec3f*)(&a)), *((Vec3f*)(&c))); + Vec3f normal = vec3Normalize(vec3Cross(na, nb)); + Vec3f light = vec3Normalize((Vec3f){-8,5,5}); + float diffuseLight = (1.0 + vec3Dot(normal, light)) *0.5; + diffuseLight = MIN(1.0, MAX(diffuseLight, 0)); + + a = mat4MultiplyVec4( &a, &v); + b = mat4MultiplyVec4( &b, &v); + c = mat4MultiplyVec4( &c, &v); + + a = mat4MultiplyVec4( &a, &p); + b = mat4MultiplyVec4( &b, &p); + c = mat4MultiplyVec4( &c, &p); + + + //Triangle is completely behind camera + if (a.z > 0 && b.z > 0 && c.z > 0) + continue; + + // convert to device coordinates by perspective division + a.w = 1.0 / a.w; + b.w = 1.0 / b.w; + c.w = 1.0 / c.w; + a.x *= a.w; a.y *= a.w; a.z *= a.w; + b.x *= b.w; b.y *= b.w; b.z *= b.w; + c.x *= c.w; c.y *= c.w; c.z *= c.w; + + float clocking = isClockWise(a.x, a.y, b.x, b.y, c.x, c.y); + if (clocking >= 0) + continue; + + //Compute Screen coordinates + float halfX = scrSize.x/2; + float halfY = scrSize.y/2; + Vec2i a_s = {a.x * halfX + halfX, a.y * halfY + halfY}; + Vec2i b_s = {b.x * halfX + halfX, b.y * halfY + halfY}; + Vec2i c_s = {c.x * halfX + halfX, c.y * halfY + halfY}; + + int32_t minX = MIN(MIN(a_s.x, b_s.x), c_s.x); + int32_t minY = MIN(MIN(a_s.y, b_s.y), c_s.y); + int32_t maxX = MAX(MAX(a_s.x, b_s.x), c_s.x); + int32_t maxY = MAX(MAX(a_s.y, b_s.y), c_s.y); + + minX = MIN(MAX(minX, 0), r->frameBuffer.size.x); + minY = MIN(MAX(minY, 0), r->frameBuffer.size.y); + maxX = MIN(MAX(maxX, 0), r->frameBuffer.size.x); + maxY = MIN(MAX(maxY, 0), r->frameBuffer.size.y); + + // Barycentric coordinates at minX/minY corner + Vec2i minTriangle = { minX, minY }; + + int32_t area = orient2d( a_s, b_s, c_s); + if (area == 0) + continue; + float areaInverse = 1.0/area; + + int32_t A01 = ( a_s.y - b_s.y); //Barycentric coordinates steps + int32_t B01 = ( b_s.x - a_s.x); //Barycentric coordinates steps + int32_t A12 = ( b_s.y - c_s.y); //Barycentric coordinates steps + int32_t B12 = ( c_s.x - b_s.x); //Barycentric coordinates steps + int32_t A20 = ( c_s.y - a_s.y); //Barycentric coordinates steps + int32_t B20 = ( a_s.x - c_s.x); //Barycentric coordinates steps + + int32_t w0_row = orient2d( b_s, c_s, minTriangle); + int32_t w1_row = orient2d( c_s, a_s, minTriangle); + int32_t w2_row = orient2d( a_s, b_s, minTriangle); + + if (o->material != 0) { + tca.x /= a.z; + tca.y /= a.z; + tcb.x /= b.z; + tcb.y /= b.z; + tcc.x /= c.z; + tcc.y /= c.z; + } + + for (int16_t y = minY; y < maxY; y++, w0_row += B12,w1_row += B20,w2_row += B01) { + int32_t w0 = w0_row; + int32_t w1 = w1_row; + int32_t w2 = w2_row; + + for (int32_t x = minX; x < maxX; x++, w0 += A12, w1 += A20, w2 += A01) { + + if ((w0 | w1 | w2) < 0) + continue; + + float depth = -( w0 * a.z + w1 * b.z + w2 * c.z ) * areaInverse; + if (depth < 0.0 || depth > 1.0) + continue; + + if (depth_check(r->backEnd->getZetaBuffer(r,r->backEnd), x + y * scrSize.x, 1-depth )) + continue; + + depth_write(r->backEnd->getZetaBuffer(r,r->backEnd), x + y * scrSize.x, 1- depth ); + + if (o->material != 0) { + //Texture lookup + + float textCoordx = -(w0 * tca.x + w1 * tcb.x + w2 * tcc.x)* areaInverse * depth; + float textCoordy = -(w0 * tca.y + w1 * tcb.y + w2 * tcc.y)* areaInverse * depth; + + Pixel text = texture_readF(o->material->texture, (Vec2f){textCoordx,textCoordy}); + //show_pixel(text.a, text.b, text.g, text.r); + + backendDrawPixel(r, &r->frameBuffer, (Vec2i){x,y}, text, diffuseLight); + } else { + Pixel pixel; + pixel.a = 255; + pixel.b = 255; + pixel.g = 0; + pixel.r = 255; + backendDrawPixel(r, &r->frameBuffer, (Vec2i){x,y}, pixel, diffuseLight); + } + + } + + } + } + + return 0; +}; + +int rendererInit(Renderer * r, Vec2i size, BackEnd * backEnd) { + renderingFunctions[RENDERABLE_SPRITE] = & renderSprite; + renderingFunctions[RENDERABLE_SCENE] = & renderScene; + renderingFunctions[RENDERABLE_OBJECT] = & renderObject; + + r->scene = 0; + r->clear = 1; + r->clearColor = PIXELBLACK; + r->backEnd = backEnd; + + r->backEnd->init(r, r->backEnd, (Vec4i) { 0, 0, 0, 0 }); + + int e = 0; + e = texture_init( & (r->frameBuffer), size, backEnd->getFrameBuffer(r, backEnd)); + if (e) return e; + + return 0; +} + +int rendererRender(Renderer * r) { + + int pixels = r->frameBuffer.size.x * r->frameBuffer.size.y; + memset(r->backEnd->getZetaBuffer(r,r->backEnd), 0, pixels * sizeof (PingoDepth)); + + r->backEnd->beforeRender(r, r->backEnd); + + //get current framebuffe from backend + r->frameBuffer.frameBuffer = r->backEnd->getFrameBuffer(r, r->backEnd); + + //Clear draw buffer before rendering + if (r->clear) { + memset(r->backEnd->getFrameBuffer(r,r->backEnd), 0, pixels * sizeof (Pixel)); + } + + renderScene(mat4Identity(), r, sceneAsRenderable(r->scene)); + + r->backEnd->afterRender(r, r->backEnd); + + return 0; +} + +int rendererSetScene(Renderer * r, Scene * s) { + if (s == 0) + return 1; //nullptr scene + + r->scene = s; + return 0; +} + +int rendererSetCamera(Renderer * r, Vec4i rect) { + r->camera = rect; + r->backEnd->init(r, r->backEnd, rect); + r->frameBuffer.size = (Vec2i) { + rect.z, rect.w +}; + return 0; +} diff --git a/video/src/pingo/render/renderer.h b/video/src/pingo/render/renderer.h new file mode 100644 index 00000000..4f5244f0 --- /dev/null +++ b/video/src/pingo/render/renderer.h @@ -0,0 +1,32 @@ +#pragma once + +#include "texture.h" +#include "renderable.h" +#include "pixel.h" +#include "../math/vec4.h" + +typedef struct Scene Scene; +typedef struct BackEnd BackEnd; + +typedef struct Renderer{ + Vec4i camera; + Scene * scene; + + Texture frameBuffer; + Pixel clearColor; + int clear; + + Mat4 camera_projection; + Mat4 camera_view; + + BackEnd * backEnd; + +} Renderer; + +extern int rendererRender(Renderer *); + +extern int rendererInit(Renderer *, Vec2i size, struct BackEnd * backEnd); + +extern int rendererSetScene(Renderer *r, Scene *s); + +extern int rendererSetCamera(Renderer *r, Vec4i camera); diff --git a/video/src/pingo/render/scene.c b/video/src/pingo/render/scene.c new file mode 100644 index 00000000..03ed2d44 --- /dev/null +++ b/video/src/pingo/render/scene.c @@ -0,0 +1,26 @@ +#include "scene.h" +#include "renderer.h" + +int sceneAddRenderable(Scene * scene, Renderable renderable) +{ + if (scene->numberOfRenderables >= MAX_SCENE_RENDERABLES) { + return 1; //Too many renderables in this scene + } + + scene->renderables[scene->numberOfRenderables++] = renderable; + return 0; +} + +int sceneInit(Scene * s) +{ + s->transform = mat4Identity(); + s->numberOfRenderables = 0; + s->visible = 1; + + return 0; +} + + +extern Renderable sceneAsRenderable(Scene * scene) { + return (Renderable){.renderableType = RENDERABLE_SCENE, .impl = scene}; +} diff --git a/video/src/pingo/render/scene.h b/video/src/pingo/render/scene.h new file mode 100644 index 00000000..43d4c15f --- /dev/null +++ b/video/src/pingo/render/scene.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include "renderable.h" +#include "../math/mat3.h" +#include "../math/mat4.h" + +#ifdef __cplusplus + extern "C" { +#endif + +#define MAX_SCENE_RENDERABLES 32 + +typedef struct Scene { + uint8_t numberOfRenderables; + Renderable renderables[MAX_SCENE_RENDERABLES]; + Mat4 transform; + uint8_t visible; +} Scene; + +extern int sceneInit(Scene * s); +extern int sceneAddRenderable(Scene * scene, Renderable renderable); + +extern Renderable sceneAsRenderable(Scene * scene); + +#ifdef __cplusplus + } +#endif diff --git a/video/src/pingo/render/sprite.c b/video/src/pingo/render/sprite.c new file mode 100644 index 00000000..b07ac674 --- /dev/null +++ b/video/src/pingo/render/sprite.c @@ -0,0 +1,30 @@ +#include "sprite.h" +#include "../math/mat3.h" + +int spriteInit(Sprite *s, Texture f, Mat4 t) +{ + if (f.frameBuffer == 0) + return 1; + + s->frame = f; + s->t = t; + + return 0; +} + +Renderable spriteAsRenderable(Sprite * s) { + return (Renderable){ .renderableType = RENDERABLE_SPRITE, .impl = s}; +} + +int spriteRandomize(Sprite * s) +{ + + for (int x = 0; x < s->frame.size.x; x++ ) { + for (int y = 0; y < s->frame.size.y; y++ ) { + + texture_draw(&s->frame,(Vec2i){x,y},pixelRandom()); + } + } + + return 0; +} diff --git a/video/src/pingo/render/sprite.h b/video/src/pingo/render/sprite.h new file mode 100644 index 00000000..0dce6a03 --- /dev/null +++ b/video/src/pingo/render/sprite.h @@ -0,0 +1,22 @@ +#pragma once + +#include "texture.h" +#include "renderable.h" +#include "../math/mat4.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef struct Sprite { + Mat4 t; + Texture frame; +} Sprite; + +extern int spriteInit( Sprite * s, Texture f, Mat4 t); +extern int spriteRandomize( Sprite * s); +extern Renderable spriteAsRenderable( Sprite * s); + +#ifdef __cplusplus + } +#endif diff --git a/video/src/pingo/render/texture.c b/video/src/pingo/render/texture.c new file mode 100644 index 00000000..e5e3d826 --- /dev/null +++ b/video/src/pingo/render/texture.c @@ -0,0 +1,39 @@ +#include "texture.h" +#include "math.h" + +int texture_init( Texture *f, Vec2i size, Pixel *buf ) +{ + if(size.x * size.y == 0) + return 1; // 0 sized rect + + if(buf == 0) + return 2; // null ptr buffer + + f->frameBuffer = (Pixel *)buf; + f->size = size; + + return 0; +} + +void texture_draw(Texture *f, Vec2i pos, Pixel color) +{ + f->frameBuffer[pos.x + pos.y * f->size.x] = color; +} + +Pixel texture_read(Texture *f, Vec2i pos) +{ + return f->frameBuffer[pos.x + pos.y * f->size.x]; +} + +Pixel texture_readF(Texture *f, Vec2f pos) +{ + uint16_t x = (uint16_t)(pos.x * f->size.x) % f->size.x; + uint16_t y = (uint16_t)(pos.y * f->size.y) % f->size.x; + uint32_t index = x + y * f->size.x; + Pixel value = f->frameBuffer[index]; + return value; +} + + + + diff --git a/video/src/pingo/render/texture.h b/video/src/pingo/render/texture.h new file mode 100644 index 00000000..02767310 --- /dev/null +++ b/video/src/pingo/render/texture.h @@ -0,0 +1,21 @@ +#pragma once + +#include "pixel.h" +#include "renderable.h" +#include "../math/vec2.h" + +typedef struct Texture { + Vec2i size; + Pixel * frameBuffer; +} Texture; + +extern int texture_init( Texture * f, Vec2i size, Pixel *); + +extern Renderable texture_as_renderable( Texture * s); + +extern void texture_draw(Texture * f, Vec2i pos, Pixel color); + +extern Pixel texture_read(Texture * f, Vec2i pos); + +extern Pixel texture_readF(Texture * f, Vec2f pos); + diff --git a/video/src/samples/BITMAP_64X250_SOLID.BIN b/video/src/samples/BITMAP_64X250_SOLID.BIN new file mode 100644 index 00000000..9a66e783 Binary files /dev/null and b/video/src/samples/BITMAP_64X250_SOLID.BIN differ diff --git a/video/src/samples/BITMAP_64X250_SOLID.BIN.RGB b/video/src/samples/BITMAP_64X250_SOLID.BIN.RGB new file mode 100644 index 00000000..bc99ef84 Binary files /dev/null and b/video/src/samples/BITMAP_64X250_SOLID.BIN.RGB differ diff --git a/video/src/samples/BITMAP_64X250_SOLID.h b/video/src/samples/BITMAP_64X250_SOLID.h new file mode 100644 index 00000000..ce99af8e --- /dev/null +++ b/video/src/samples/BITMAP_64X250_SOLID.h @@ -0,0 +1,519 @@ +// Input Binary File: BITMAP_64X250_SOLID.BIN +// Output Source File: BITMAP_64X250_SOLID.h +// Identifier: BITMAP_64X250_SOLID + +#ifndef _HEX_BITMAP_64X250_SOLID_ +#define _HEX_BITMAP_64X250_SOLID_ + +#ifdef _COMPILE_HEX_DATA_ +// Note: This is a generated source file! + +__root const unsigned char gBITMAP_64X250_SOLIDData[] = +{ +/* 00000000 */ 0x00,0x00,0x00,0x06,0x0A,0x0A,0x0A,0x1A,0x1A,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x06,0x05,0x00,0x06,0x1B, +/* 00000020 */ 0x3F,0x2F,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x16,0x16,0x29,0x29,0x29,0x19,0x06,0x06,0x06,0x06,0x0A,0x0E,0x0A,0x1A,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00000040 */ 0x00,0x00,0x01,0x0A,0x0A,0x1A,0x2A,0x3E,0x3A,0x2A,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x06,0x06,0x07,0x07,0x06,0x01,0x05,0x1B, +/* 00000060 */ 0x3F,0x3F,0x0B,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x16,0x16,0x39,0x3D,0x3D,0x39,0x39,0x39,0x29,0x06,0x06,0x06,0x0A,0x0A,0x0A,0x09,0x0A,0x2F,0x3F,0x3F,0x3F, +/* 00000080 */ 0x00,0x00,0x15,0x2A,0x39,0x39,0x3D,0x3E,0x3E,0x39,0x2A,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x06,0x06,0x06,0x07,0x06,0x05,0x01,0x1B, +/* 000000A0 */ 0x2F,0x3F,0x2B,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x16,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x39,0x05,0x06,0x06,0x0A,0x0B,0x0A,0x05,0x09,0x0A,0x0A,0x2E, +/* 000000C0 */ 0x00,0x00,0x25,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x29,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x05,0x01,0x16, +/* 000000E0 */ 0x1B,0x3F,0x3F,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x16,0x2A,0x39,0x3D,0x3D,0x39,0x39,0x3D,0x3D,0x3D,0x39,0x39,0x05,0x06,0x06,0x0A,0x1F,0x0A,0x05,0x05,0x05,0x19, +/* 00000100 */ 0x00,0x00,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x16,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x05,0x05, +/* 00000120 */ 0x1B,0x2F,0x3F,0x1B,0x06,0x06,0x06,0x06,0x06,0x16,0x2A,0x39,0x3D,0x3D,0x3D,0x3D,0x39,0x3D,0x39,0x3D,0x3D,0x39,0x29,0x05,0x06,0x05,0x3E,0x3F,0x0B,0x05,0x05,0x09, +/* 00000140 */ 0x00,0x00,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x2A,0x16,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x05,0x01, +/* 00000160 */ 0x06,0x1B,0x3F,0x2F,0x06,0x06,0x06,0x06,0x16,0x29,0x39,0x3D,0x3D,0x39,0x3D,0x3D,0x39,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x19,0x06,0x05,0x15,0x39,0x1F,0x0F,0x0A,0x1A, +/* 00000180 */ 0x00,0x00,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x39,0x2A,0x16,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x01, +/* 000001A0 */ 0x16,0x1B,0x2F,0x3F,0x1B,0x06,0x16,0x29,0x39,0x39,0x3D,0x3D,0x39,0x3D,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x29,0x05,0x06,0x05,0x05,0x19,0x2E,0x0F,0x2E, +/* 000001C0 */ 0x00,0x00,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x39,0x39,0x2A,0x16,0x16,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x01, +/* 000001E0 */ 0x05,0x06,0x1B,0x3F,0x2B,0x29,0x39,0x39,0x3D,0x39,0x3D,0x3D,0x39,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x29,0x05,0x05,0x05,0x05,0x15,0x39,0x3E,0x3D, +/* 00000200 */ 0x01,0x00,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x39,0x39,0x29,0x2A,0x2A,0x2A,0x2A,0x15, +/* 00000220 */ 0x01,0x05,0x07,0x3F,0x3F,0x3D,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x05,0x05,0x05,0x05,0x29,0x39,0x39,0x3D, +/* 00000240 */ 0x01,0x00,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x3D,0x39,0x39,0x3D,0x3D,0x25, +/* 00000260 */ 0x01,0x05,0x17,0x1B,0x3F,0x3E,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x05,0x05,0x05,0x19,0x39,0x3D,0x3D,0x3D, +/* 00000280 */ 0x01,0x00,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x25, +/* 000002A0 */ 0x01,0x15,0x16,0x1B,0x2F,0x3F,0x3D,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x29,0x19,0x29,0x39,0x39,0x3D,0x3D,0x3D, +/* 000002C0 */ 0x01,0x01,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x15, +/* 000002E0 */ 0x01,0x01,0x05,0x17,0x1B,0x3F,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000300 */ 0x01,0x01,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x25, +/* 00000320 */ 0x01,0x01,0x05,0x06,0x1B,0x2F,0x3A,0x39,0x39,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000340 */ 0x01,0x05,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x29, +/* 00000360 */ 0x01,0x01,0x15,0x05,0x06,0x1B,0x3F,0x29,0x14,0x15,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000380 */ 0x01,0x05,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x29, +/* 000003A0 */ 0x01,0x01,0x05,0x05,0x05,0x07,0x3F,0x2F,0x05,0x15,0x39,0x39,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 000003C0 */ 0x05,0x05,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x15, +/* 000003E0 */ 0x01,0x01,0x16,0x15,0x01,0x06,0x1B,0x3F,0x1A,0x29,0x39,0x29,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000400 */ 0x05,0x05,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x29,0x01, +/* 00000420 */ 0x01,0x01,0x3A,0x39,0x15,0x06,0x07,0x3F,0x3F,0x19,0x15,0x04,0x04,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000440 */ 0x05,0x01,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x25,0x01, +/* 00000460 */ 0x01,0x15,0x3E,0x3E,0x15,0x01,0x07,0x1B,0x3F,0x2B,0x15,0x05,0x05,0x04,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000480 */ 0x05,0x01,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x15,0x01, +/* 000004A0 */ 0x01,0x26,0x3E,0x29,0x19,0x01,0x06,0x0B,0x3F,0x3F,0x16,0x15,0x05,0x05,0x05,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 000004C0 */ 0x05,0x01,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x15,0x01, +/* 000004E0 */ 0x15,0x16,0x1A,0x05,0x06,0x05,0x01,0x17,0x2F,0x3F,0x2F,0x05,0x05,0x05,0x05,0x19,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000500 */ 0x05,0x01,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x29,0x05,0x05, +/* 00000520 */ 0x15,0x16,0x15,0x00,0x04,0x15,0x01,0x01,0x1B,0x3F,0x3F,0x2B,0x05,0x05,0x05,0x15,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000540 */ 0x05,0x01,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x15,0x06,0x05, +/* 00000560 */ 0x16,0x16,0x05,0x00,0x14,0x39,0x25,0x01,0x01,0x05,0x1A,0x2F,0x1A,0x05,0x05,0x15,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x3D,0x3D,0x3D,0x3D,0x3D, +/* 00000580 */ 0x05,0x01,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x15,0x16,0x05, +/* 000005A0 */ 0x16,0x1A,0x05,0x15,0x39,0x3D,0x39,0x01,0x01,0x16,0x2A,0x2F,0x05,0x05,0x05,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x39,0x3A,0x3E,0x3E,0x3D,0x3D, +/* 000005C0 */ 0x05,0x01,0x15,0x39,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3D,0x3D,0x39,0x3D,0x3D,0x39,0x16,0x3A,0x15, +/* 000005E0 */ 0x15,0x16,0x05,0x25,0x3D,0x3E,0x3D,0x14,0x01,0x2B,0x3F,0x3F,0x1A,0x05,0x15,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x29,0x19,0x2A,0x39,0x39,0x39, +/* 00000600 */ 0x05,0x01,0x01,0x14,0x39,0x39,0x3D,0x3E,0x3D,0x3D,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3D,0x25,0x16,0x39,0x15, +/* 00000620 */ 0x3F,0x2A,0x04,0x15,0x39,0x3E,0x3D,0x39,0x01,0x16,0x3F,0x3F,0x1F,0x04,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x15,0x05,0x15,0x29,0x39, +/* 00000640 */ 0x05,0x01,0x00,0x04,0x14,0x39,0x39,0x3D,0x3E,0x3F,0x3F,0x3B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x2A,0x16, +/* 00000660 */ 0x2A,0x3F,0x14,0x39,0x39,0x39,0x3D,0x39,0x15,0x06,0x2B,0x3F,0x3F,0x29,0x39,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x39,0x29,0x04,0x05,0x05,0x15, +/* 00000680 */ 0x01,0x00,0x29,0x39,0x14,0x00,0x25,0x3A,0x3B,0x3B,0x3B,0x2B,0x2B,0x2B,0x3B,0x2B,0x2B,0x2B,0x2B,0x2B,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 000006A0 */ 0x2B,0x3F,0x39,0x39,0x39,0x39,0x3E,0x3E,0x25,0x01,0x1B,0x3F,0x3F,0x3E,0x3D,0x3D,0x39,0x39,0x39,0x39,0x39,0x39,0x39,0x3D,0x3D,0x3D,0x39,0x29,0x05,0x05,0x05,0x09, +/* 000006C0 */ 0x01,0x00,0x3D,0x3D,0x29,0x15,0x26,0x27,0x27,0x27,0x27,0x2B,0x2B,0x3B,0x2B,0x27,0x2B,0x2B,0x2B,0x2B,0x2B,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 000006E0 */ 0x2F,0x3F,0x3F,0x3F,0x3A,0x39,0x3A,0x3E,0x29,0x01,0x16,0x3F,0x3F,0x3E,0x39,0x39,0x29,0x14,0x15,0x15,0x19,0x29,0x29,0x39,0x3E,0x3E,0x3E,0x2E,0x2F,0x2F,0x2F,0x3F, +/* 00000700 */ 0x01,0x14,0x3E,0x3E,0x39,0x26,0x26,0x16,0x12,0x12,0x17,0x27,0x27,0x27,0x27,0x2B,0x2B,0x27,0x27,0x27,0x2B,0x2B,0x2B,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00000720 */ 0x2F,0x2F,0x3F,0x3F,0x3F,0x2A,0x16,0x2A,0x15,0x01,0x06,0x2F,0x3F,0x3F,0x29,0x29,0x15,0x15,0x15,0x1A,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00000740 */ 0x01,0x15,0x3E,0x3F,0x3A,0x26,0x16,0x16,0x12,0x12,0x12,0x13,0x13,0x13,0x27,0x27,0x27,0x27,0x27,0x17,0x27,0x2B,0x2B,0x2B,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00000760 */ 0x3F,0x2B,0x3F,0x3F,0x3F,0x3F,0x2F,0x16,0x39,0x15,0x02,0x1B,0x3F,0x3F,0x16,0x06,0x05,0x05,0x1A,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00000780 */ 0x01,0x15,0x3E,0x3A,0x26,0x27,0x27,0x27,0x12,0x12,0x12,0x12,0x12,0x12,0x27,0x27,0x27,0x27,0x27,0x2B,0x27,0x27,0x2B,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 000007A0 */ 0x3F,0x17,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2A,0x3A,0x02,0x16,0x3F,0x3F,0x1A,0x05,0x05,0x05,0x1A,0x2F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F,0x3F,0x2F,0x2F,0x2F,0x2F,0x2F, +/* 000007C0 */ 0x01,0x15,0x3A,0x26,0x27,0x27,0x27,0x27,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x17,0x27,0x2B,0x2B,0x2B,0x27,0x27,0x27,0x2B,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 000007E0 */ 0x2F,0x07,0x06,0x3F,0x3F,0x3F,0x3F,0x3F,0x1B,0x17,0x06,0x06,0x2F,0x3F,0x2F,0x05,0x1A,0x1A,0x05,0x0A,0x2F,0x3F,0x3F,0x3F,0x2F,0x2F,0x2F,0x1A,0x1B,0x1B,0x1A,0x1A, +/* 00000800 */ 0x00,0x15,0x2A,0x27,0x27,0x27,0x27,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x27,0x27,0x27,0x27,0x27,0x27,0x2B,0x2B,0x27,0x2B,0x2B,0x3B,0x2B,0x3F,0x3F,0x3F, +/* 00000820 */ 0x2B,0x07,0x02,0x19,0x3F,0x3F,0x3F,0x3F,0x3F,0x06,0x02,0x06,0x1B,0x3F,0x3F,0x1A,0x2F,0x1B,0x06,0x05,0x05,0x0A,0x1F,0x1F,0x2F,0x1F,0x2F,0x1F,0x1B,0x1B,0x1A,0x1A, +/* 00000840 */ 0x00,0x2A,0x2B,0x27,0x27,0x27,0x17,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x16,0x17,0x17,0x27,0x2B,0x2B,0x27,0x27,0x2B,0x2B,0x3B,0x3F,0x3F,0x3F,0x3F,0x2B, +/* 00000860 */ 0x17,0x07,0x06,0x16,0x1A,0x3F,0x3F,0x3F,0x3F,0x1B,0x02,0x06,0x16,0x3F,0x3F,0x2B,0x2F,0x2F,0x1A,0x05,0x06,0x05,0x06,0x06,0x0A,0x0A,0x0A,0x0A,0x06,0x06,0x06,0x06, +/* 00000880 */ 0x01,0x2B,0x27,0x27,0x27,0x27,0x13,0x12,0x12,0x12,0x13,0x13,0x12,0x12,0x16,0x16,0x12,0x12,0x12,0x16,0x27,0x27,0x2B,0x2B,0x2B,0x3B,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B, +/* 000008A0 */ 0x16,0x07,0x07,0x3F,0x1A,0x3F,0x3F,0x3F,0x3F,0x2F,0x06,0x02,0x1B,0x2F,0x3F,0x1B,0x0A,0x1B,0x0A,0x05,0x06,0x06,0x05,0x06,0x05,0x06,0x05,0x05,0x05,0x05,0x05,0x06, +/* 000008C0 */ 0x16,0x2B,0x27,0x27,0x27,0x17,0x13,0x12,0x12,0x12,0x12,0x17,0x17,0x12,0x16,0x16,0x12,0x12,0x16,0x12,0x16,0x17,0x27,0x27,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x17, +/* 000008E0 */ 0x16,0x12,0x17,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x06,0x06,0x06,0x1B,0x3F,0x2F,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x05,0x06,0x0A,0x0A, +/* 00000900 */ 0x1A,0x27,0x27,0x27,0x27,0x16,0x13,0x13,0x12,0x12,0x17,0x17,0x17,0x12,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x17,0x17,0x17,0x27,0x2B,0x2B,0x2B,0x2B,0x3F,0x3F,0x27, +/* 00000920 */ 0x16,0x13,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x06,0x02,0x16,0x17,0x3F,0x3F,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0A,0x0B,0x0F,0x0A, +/* 00000940 */ 0x26,0x27,0x27,0x27,0x27,0x17,0x13,0x12,0x12,0x12,0x17,0x17,0x13,0x16,0x16,0x12,0x12,0x16,0x12,0x12,0x16,0x16,0x16,0x17,0x27,0x2B,0x2B,0x2B,0x2B,0x2B,0x3B,0x17, +/* 00000960 */ 0x02,0x17,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x17,0x02,0x02,0x1B,0x2F,0x3F,0x1A,0x05,0x05,0x06,0x06,0x06,0x0A,0x0A,0x0A,0x0A,0x0A,0x0F,0x0F,0x0F,0x0A,0x05, +/* 00000980 */ 0x27,0x27,0x27,0x27,0x17,0x17,0x17,0x12,0x17,0x12,0x17,0x16,0x17,0x16,0x12,0x12,0x12,0x17,0x12,0x12,0x16,0x16,0x16,0x16,0x16,0x17,0x27,0x27,0x2B,0x2B,0x2B,0x17, +/* 000009A0 */ 0x12,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x06,0x02,0x02,0x1B,0x2F,0x3F,0x2F,0x05,0x05,0x05,0x06,0x0A,0x0F,0x0F,0x0E,0x0F,0x0F,0x0E,0x0A,0x05,0x05,0x05, +/* 000009C0 */ 0x27,0x27,0x17,0x27,0x17,0x17,0x17,0x17,0x16,0x16,0x17,0x16,0x17,0x16,0x16,0x16,0x12,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x17,0x17,0x2B,0x2B,0x2B,0x2B, +/* 000009E0 */ 0x2B,0x3F,0x3F,0x3F,0x3B,0x3B,0x3F,0x3F,0x3F,0x2B,0x06,0x02,0x01,0x02,0x2F,0x3F,0x3F,0x06,0x06,0x0A,0x0E,0x0E,0x0E,0x0E,0x2E,0x3E,0x19,0x05,0x05,0x05,0x05,0x05, +/* 00000A00 */ 0x27,0x2B,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x16,0x16,0x17,0x17,0x17,0x2B,0x2B, +/* 00000A20 */ 0x2B,0x2B,0x2B,0x3F,0x2B,0x3F,0x3F,0x3F,0x3F,0x1B,0x02,0x16,0x2B,0x2F,0x3F,0x3F,0x3F,0x0A,0x0A,0x0E,0x0E,0x1E,0x3E,0x3E,0x3E,0x39,0x19,0x05,0x05,0x05,0x05,0x05, +/* 00000A40 */ 0x17,0x27,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x16,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x02,0x02,0x02,0x17,0x17,0x27,0x2B, +/* 00000A60 */ 0x2B,0x2B,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x2B,0x06,0x06,0x2B,0x2A,0x3F,0x2B,0x3F,0x3F,0x2F,0x1E,0x2E,0x3E,0x3E,0x3A,0x3A,0x2E,0x1F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0A, +/* 00000A80 */ 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x17,0x17,0x2B, +/* 00000AA0 */ 0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,0x3F,0x3F,0x17,0x02,0x1B,0x2F,0x2A,0x3F,0x15,0x1B,0x3F,0x3F,0x3D,0x3D,0x39,0x29,0x19,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0B,0x0B,0x0F, +/* 00000AC0 */ 0x17,0x17,0x17,0x1B,0x1B,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x06,0x16,0x16,0x16,0x06,0x16,0x06,0x02,0x02,0x02,0x06,0x02,0x02,0x02,0x02,0x02,0x03,0x17, +/* 00000AE0 */ 0x2B,0x2B,0x27,0x2B,0x2B,0x2B,0x3F,0x2B,0x06,0x16,0x3F,0x3F,0x3F,0x1A,0x01,0x06,0x2F,0x3F,0x2E,0x15,0x06,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0B, +/* 00000B00 */ 0x27,0x17,0x17,0x17,0x17,0x17,0x17,0x07,0x17,0x17,0x17,0x17,0x17,0x16,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x16,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x17, +/* 00000B20 */ 0x27,0x2B,0x2B,0x2B,0x2B,0x2B,0x2B,0x07,0x06,0x2B,0x3F,0x3F,0x3F,0x3F,0x06,0x06,0x1B,0x3F,0x3F,0x06,0x0A,0x0A,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0A,0x05, +/* 00000B40 */ 0x26,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x06,0x06,0x17,0x17,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x17, +/* 00000B60 */ 0x17,0x17,0x2B,0x2B,0x2B,0x17,0x07,0x06,0x17,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x01,0x07,0x2F,0x3F,0x0B,0x0F,0x0F,0x0E,0x0F,0x0E,0x05,0x05,0x09,0x0A,0x05,0x00,0x09, +/* 00000B80 */ 0x16,0x1B,0x17,0x1B,0x17,0x17,0x17,0x17,0x17,0x17,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x02,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x02, +/* 00000BA0 */ 0x07,0x17,0x17,0x17,0x17,0x03,0x06,0x06,0x17,0x2A,0x3F,0x3F,0x3F,0x3F,0x2B,0x06,0x06,0x1B,0x3F,0x2F,0x0A,0x0F,0x0F,0x1F,0x2E,0x04,0x05,0x05,0x05,0x04,0x09,0x0A, +/* 00000BC0 */ 0x12,0x1B,0x17,0x1B,0x17,0x17,0x17,0x07,0x17,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +/* 00000BE0 */ 0x07,0x17,0x17,0x07,0x03,0x07,0x07,0x07,0x1B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x16,0x01,0x1B,0x3F,0x3F,0x05,0x0A,0x0F,0x3F,0x2A,0x04,0x04,0x05,0x09,0x0A,0x0A,0x1E, +/* 00000C00 */ 0x01,0x17,0x17,0x1B,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x07,0x06,0x02,0x02,0x02,0x02,0x02,0x06,0x02,0x02,0x02,0x06,0x02,0x02,0x02,0x02,0x07, +/* 00000C20 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x2B,0x3F,0x3F,0x2B,0x3F,0x3F,0x3F,0x1A,0x05,0x16,0x2F,0x3F,0x1A,0x05,0x1E,0x2E,0x09,0x04,0x09,0x1E,0x1E,0x1E,0x2F,0x2F, +/* 00000C40 */ 0x01,0x16,0x1B,0x1B,0x1B,0x1B,0x17,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x07,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00000C60 */ 0x07,0x07,0x07,0x06,0x07,0x07,0x07,0x07,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2A,0x15,0x05,0x05,0x1B,0x3F,0x3F,0x1A,0x0E,0x1E,0x05,0x09,0x09,0x0A,0x0A,0x1E,0x2F,0x2F, +/* 00000C80 */ 0x01,0x01,0x17,0x17,0x17,0x1B,0x17,0x07,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00000CA0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3B,0x15,0x15,0x1A,0x01,0x16,0x3F,0x3F,0x09,0x09,0x0A,0x09,0x09,0x09,0x09,0x1E,0x1E,0x1E,0x2E, +/* 00000CC0 */ 0x01,0x00,0x16,0x17,0x1B,0x1B,0x0B,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00000CE0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x2F,0x3F,0x3F,0x3F,0x2B,0x3F,0x1B,0x0A,0x1F,0x2F,0x16,0x06,0x2B,0x3F,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x0A,0x2F,0x1E,0x1E, +/* 00000D00 */ 0x01,0x00,0x01,0x17,0x1B,0x1B,0x0B,0x0B,0x0B,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00000D20 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x3F,0x3F,0x3F,0x2F,0x3F,0x3F,0x2F,0x1F,0x3F,0x3F,0x2A,0x05,0x1B,0x2F,0x04,0x05,0x05,0x05,0x05,0x05,0x2A,0x2B,0x2F,0x2F,0x1E, +/* 00000D40 */ 0x01,0x01,0x00,0x05,0x1B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00000D60 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x2F,0x3F,0x3F,0x2F,0x2F,0x3F,0x3F,0x3F,0x0F,0x1F,0x2F,0x1F,0x05,0x06,0x1A,0x04,0x05,0x04,0x1A,0x1A,0x0A,0x1A,0x1E,0x09,0x0E,0x0E, +/* 00000D80 */ 0x01,0x00,0x00,0x00,0x06,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x06,0x07,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00000DA0 */ 0x0B,0x0B,0x0B,0x07,0x07,0x0B,0x3F,0x3F,0x3F,0x1B,0x1B,0x3F,0x3F,0x1F,0x0F,0x0F,0x0F,0x0F,0x06,0x16,0x05,0x04,0x05,0x0A,0x0A,0x0E,0x0F,0x0F,0x0E,0x0E,0x0E,0x0E, +/* 00000DC0 */ 0x01,0x00,0x00,0x00,0x00,0x06,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x0B,0x07,0x07,0x07,0x07,0x07,0x06,0x05,0x00,0x00,0x00,0x01,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00000DE0 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x2F,0x3F,0x2F,0x1B,0x3F,0x2A,0x0B,0x0B,0x0B,0x0B,0x0F,0x1F,0x1A,0x05,0x05,0x05,0x09,0x0E,0x0E,0x0E,0x0E,0x0A,0x0E,0x0E,0x09,0x0A, +/* 00000E00 */ 0x01,0x00,0x00,0x00,0x00,0x01,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x06,0x06,0x05,0x01,0x00,0x00,0x05,0x06,0x06,0x0B,0x0B,0x07,0x07,0x07,0x0B, +/* 00000E20 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x2B,0x3F,0x2F,0x2B,0x3F,0x1B,0x0B,0x0B,0x1B,0x3F,0x2F,0x1F,0x0A,0x05,0x01,0x2B,0x2F,0x1A,0x09,0x0E,0x1F,0x2F,0x1E,0x09,0x09,0x09, +/* 00000E40 */ 0x01,0x01,0x00,0x00,0x00,0x01,0x01,0x06,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x07,0x06,0x06,0x06,0x05,0x05,0x01,0x05,0x06,0x06,0x06,0x0B,0x0B,0x0B,0x07,0x0B,0x0B, +/* 00000E60 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0A,0x3F,0x3F,0x3F,0x2B,0x1B,0x0A,0x1B,0x2F,0x2F,0x1F,0x0F,0x0F,0x0F,0x06,0x01,0x1B,0x3F,0x3F,0x3F,0x1E,0x1F,0x2F,0x3F,0x2F,0x1E,0x05, +/* 00000E80 */ 0x01,0x01,0x00,0x00,0x00,0x01,0x01,0x06,0x06,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x07,0x06,0x06,0x06,0x05,0x05,0x06,0x06,0x06,0x06,0x06,0x0A,0x0B,0x0B,0x0B,0x0B,0x0B, +/* 00000EA0 */ 0x0B,0x0F,0x0B,0x0B,0x06,0x1A,0x3F,0x3F,0x3F,0x2F,0x2F,0x2F,0x2F,0x0B,0x0B,0x06,0x0B,0x0F,0x0F,0x0A,0x01,0x1A,0x3F,0x3F,0x3F,0x2F,0x07,0x1F,0x2F,0x2F,0x2F,0x1E, +/* 00000EC0 */ 0x01,0x01,0x00,0x00,0x00,0x01,0x05,0x06,0x06,0x06,0x07,0x07,0x0B,0x0B,0x0B,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x0B,0x0B,0x0B, +/* 00000EE0 */ 0x0B,0x0B,0x0A,0x06,0x1B,0x1A,0x3E,0x3F,0x3F,0x3F,0x2F,0x1F,0x1B,0x1B,0x07,0x07,0x06,0x0F,0x0F,0x0B,0x01,0x06,0x2F,0x3F,0x3F,0x3F,0x07,0x07,0x07,0x1F,0x0A,0x05, +/* 00000F00 */ 0x01,0x01,0x00,0x00,0x01,0x01,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x0B,0x0B,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07, +/* 00000F20 */ 0x06,0x0F,0x0F,0x1F,0x1F,0x06,0x1A,0x3F,0x0A,0x1B,0x2F,0x2F,0x1B,0x07,0x0B,0x06,0x05,0x0A,0x0F,0x0F,0x05,0x16,0x3F,0x3F,0x3F,0x3F,0x2F,0x07,0x07,0x07,0x07,0x07, +/* 00000F40 */ 0x01,0x01,0x00,0x00,0x01,0x01,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x2B, +/* 00000F60 */ 0x1F,0x0F,0x0F,0x2F,0x2F,0x0B,0x0B,0x0A,0x1A,0x1F,0x3F,0x3F,0x1B,0x07,0x06,0x05,0x05,0x0A,0x0F,0x0F,0x0A,0x01,0x2F,0x3F,0x2F,0x3F,0x3F,0x17,0x07,0x07,0x07,0x07, +/* 00000F80 */ 0x01,0x00,0x00,0x01,0x01,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x0B,0x0B,0x1B,0x2F,0x2B, +/* 00000FA0 */ 0x1B,0x1F,0x2F,0x3F,0x3F,0x2F,0x2F,0x3F,0x3F,0x3F,0x3F,0x2E,0x0B,0x06,0x05,0x05,0x05,0x06,0x0F,0x0F,0x0F,0x01,0x1B,0x3F,0x3F,0x2F,0x3F,0x2B,0x07,0x07,0x07,0x07, +/* 00000FC0 */ 0x01,0x00,0x00,0x05,0x01,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0A,0x0B,0x1B,0x1B,0x1B,0x2B, +/* 00000FE0 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x1A,0x05,0x01,0x05,0x05,0x06,0x0F,0x0F,0x0F,0x02,0x06,0x3F,0x3F,0x1B,0x3F,0x3F,0x07,0x07,0x07,0x06, +/* 00001000 */ 0x01,0x00,0x00,0x06,0x05,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x2B,0x3B,0x2B,0x3F,0x3F, +/* 00001020 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x06,0x01,0x05,0x06,0x0F,0x0F,0x0B,0x16,0x1B,0x3F,0x3F,0x16,0x2B,0x3F,0x1B,0x07,0x07,0x06, +/* 00001040 */ 0x01,0x00,0x15,0x1A,0x06,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x16,0x2B,0x3B,0x2B,0x3F,0x3F,0x3F, +/* 00001060 */ 0x3F,0x3F,0x3F,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1B,0x05,0x06,0x0F,0x0B,0x0B,0x17,0x16,0x3F,0x3F,0x2F,0x1B,0x3F,0x3F,0x06,0x02,0x17, +/* 00001080 */ 0x00,0x00,0x39,0x3A,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x17,0x2B,0x27,0x2B,0x3B,0x3B,0x3F,0x3F, +/* 000010A0 */ 0x3F,0x2B,0x27,0x3B,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x2B,0x1B,0x2B,0x2F,0x3F,0x3F,0x3F,0x1A,0x0A,0x07,0x0B,0x17,0x06,0x2F,0x3F,0x3F,0x2B,0x3F,0x3F,0x3F,0x16,0x1B, +/* 000010C0 */ 0x00,0x00,0x39,0x3A,0x16,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x06,0x06,0x12,0x12,0x12,0x13,0x27,0x2B,0x2B,0x3B,0x2B, +/* 000010E0 */ 0x27,0x2B,0x3F,0x3F,0x3F,0x2F,0x1B,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x2B,0x3F,0x3F,0x1B,0x07,0x0B,0x1B,0x02,0x1A,0x3F,0x3F,0x1A,0x07,0x3F,0x3F,0x2F,0x17, +/* 00001100 */ 0x00,0x00,0x39,0x3E,0x1A,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x07,0x02,0x12,0x12,0x02,0x02,0x02,0x12,0x17,0x2B,0x27,0x27, +/* 00001120 */ 0x3B,0x3F,0x3F,0x3F,0x2B,0x17,0x13,0x17,0x17,0x27,0x2B,0x27,0x17,0x17,0x17,0x17,0x1B,0x2F,0x3F,0x1B,0x07,0x07,0x06,0x06,0x3F,0x3F,0x1B,0x07,0x07,0x2F,0x1B,0x17, +/* 00001140 */ 0x00,0x00,0x39,0x3E,0x3A,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x0B,0x07,0x02,0x12,0x12,0x02,0x02,0x02,0x02,0x02,0x13,0x13,0x27,0x3B, +/* 00001160 */ 0x3F,0x3F,0x17,0x17,0x17,0x17,0x13,0x17,0x27,0x17,0x17,0x27,0x17,0x17,0x17,0x17,0x2B,0x1B,0x2B,0x3F,0x3F,0x2F,0x07,0x16,0x2F,0x3F,0x1B,0x07,0x07,0x1B,0x1B,0x17, +/* 00001180 */ 0x00,0x00,0x39,0x3E,0x39,0x16,0x06,0x05,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x0B,0x0B,0x02,0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x13,0x27,0x2B, +/* 000011A0 */ 0x2B,0x13,0x13,0x13,0x17,0x27,0x17,0x27,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x2B,0x17,0x2B,0x3F,0x1B,0x07,0x01,0x15,0x05,0x06,0x07,0x07,0x1B,0x27,0x17, +/* 000011C0 */ 0x00,0x00,0x39,0x3E,0x3E,0x39,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x06,0x12,0x12,0x02,0x02,0x02,0x02,0x02,0x12,0x12,0x13,0x13,0x13,0x17, +/* 000011E0 */ 0x13,0x13,0x13,0x13,0x12,0x12,0x17,0x17,0x27,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x2B,0x2B,0x2B,0x1B,0x0B,0x01,0x01,0x01,0x06,0x0B,0x07,0x17,0x17,0x17, +/* 00001200 */ 0x00,0x00,0x39,0x3D,0x3E,0x3E,0x29,0x01,0x01,0x05,0x05,0x05,0x06,0x06,0x06,0x07,0x07,0x06,0x12,0x12,0x12,0x02,0x02,0x02,0x02,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +/* 00001220 */ 0x12,0x13,0x13,0x12,0x13,0x13,0x17,0x17,0x27,0x27,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x2B,0x17,0x01,0x05,0x05,0x01,0x0B,0x07,0x17,0x17,0x17, +/* 00001240 */ 0x01,0x01,0x15,0x29,0x39,0x39,0x25,0x01,0x00,0x00,0x01,0x05,0x05,0x06,0x06,0x06,0x06,0x02,0x12,0x12,0x12,0x02,0x12,0x02,0x12,0x12,0x12,0x12,0x12,0x13,0x12,0x12, +/* 00001260 */ 0x12,0x12,0x12,0x12,0x13,0x17,0x17,0x17,0x27,0x17,0x16,0x27,0x17,0x17,0x17,0x27,0x17,0x17,0x17,0x17,0x17,0x17,0x02,0x01,0x15,0x05,0x00,0x07,0x07,0x17,0x17,0x17, +/* 00001280 */ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x01,0x05,0x05,0x06,0x06,0x12,0x12,0x12,0x12,0x12,0x02,0x12,0x12,0x12,0x12,0x12,0x13,0x13,0x12,0x12, +/* 000012A0 */ 0x12,0x12,0x12,0x13,0x17,0x17,0x17,0x17,0x27,0x16,0x27,0x27,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x16,0x16,0x00,0x15,0x15,0x00,0x00,0x06,0x17,0x17,0x17, +/* 000012C0 */ 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x01,0x06,0x12,0x12,0x12,0x12,0x02,0x02,0x02,0x12,0x12,0x12,0x12,0x12,0x13,0x13,0x12,0x12, +/* 000012E0 */ 0x13,0x12,0x12,0x13,0x17,0x17,0x17,0x17,0x17,0x27,0x27,0x17,0x27,0x27,0x27,0x17,0x17,0x17,0x17,0x17,0x16,0x12,0x12,0x00,0x00,0x00,0x00,0x00,0x06,0x17,0x17,0x17, +/* 00001300 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x00,0x00,0x16,0x13,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x13,0x12,0x12,0x12,0x12,0x12,0x13, +/* 00001320 */ 0x12,0x12,0x12,0x17,0x12,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x27,0x27,0x17,0x27,0x17,0x17,0x17,0x17,0x17,0x12,0x02,0x01,0x00,0x00,0x15,0x00,0x06,0x16,0x17,0x17, +/* 00001340 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x01,0x01,0x16,0x13,0x13,0x17,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +/* 00001360 */ 0x12,0x12,0x13,0x17,0x12,0x17,0x17,0x17,0x17,0x16,0x17,0x27,0x27,0x27,0x27,0x17,0x27,0x17,0x17,0x12,0x12,0x12,0x02,0x01,0x00,0x10,0x00,0x00,0x01,0x06,0x16,0x17, +/* 00001380 */ 0x12,0x12,0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x06,0x17,0x17,0x17,0x12,0x12,0x17,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, +/* 000013A0 */ 0x12,0x02,0x12,0x12,0x12,0x17,0x17,0x13,0x12,0x12,0x27,0x27,0x17,0x27,0x17,0x17,0x27,0x17,0x17,0x17,0x12,0x02,0x12,0x01,0x00,0x10,0x00,0x00,0x06,0x16,0x17,0x17, +/* 000013C0 */ 0x02,0x12,0x12,0x12,0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x06,0x02,0x17,0x17,0x17,0x17,0x16,0x17,0x17,0x17,0x17,0x12,0x12,0x12,0x12,0x12,0x13,0x12,0x12,0x12, +/* 000013E0 */ 0x13,0x12,0x12,0x12,0x12,0x12,0x12,0x17,0x16,0x17,0x17,0x17,0x17,0x27,0x27,0x17,0x17,0x17,0x17,0x12,0x12,0x02,0x02,0x01,0x00,0x10,0x00,0x00,0x06,0x06,0x16,0x17, +/* 00001400 */ 0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x13,0x13,0x07,0x07,0x07,0x06,0x06,0x17,0x17,0x17,0x17,0x16,0x17,0x16,0x16,0x17,0x12,0x12,0x12,0x13,0x13,0x17,0x12,0x12,0x12, +/* 00001420 */ 0x12,0x02,0x12,0x12,0x13,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x27,0x27,0x27,0x27,0x12,0x13,0x12,0x02,0x02,0x01,0x00,0x14,0x15,0x00,0x01,0x16,0x06,0x17, +/* 00001440 */ 0x27,0x2B,0x2B,0x27,0x27,0x17,0x17,0x17,0x17,0x07,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x16,0x12,0x12,0x12,0x17,0x12,0x12,0x12,0x13,0x12, +/* 00001460 */ 0x12,0x12,0x17,0x17,0x02,0x12,0x12,0x16,0x17,0x17,0x17,0x27,0x27,0x17,0x27,0x17,0x17,0x12,0x17,0x12,0x17,0x16,0x01,0x01,0x00,0x10,0x15,0x00,0x00,0x06,0x06,0x17, +/* 00001480 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x2B,0x1B,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x12,0x13,0x17,0x02,0x02,0x02,0x12,0x12, +/* 000014A0 */ 0x12,0x12,0x17,0x17,0x12,0x12,0x12,0x17,0x16,0x17,0x17,0x17,0x17,0x27,0x17,0x17,0x13,0x12,0x17,0x17,0x17,0x17,0x02,0x01,0x00,0x15,0x15,0x00,0x00,0x06,0x06,0x17, +/* 000014C0 */ 0x3B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x12,0x17,0x12,0x17,0x13,0x02,0x02,0x12,0x13,0x12, +/* 000014E0 */ 0x12,0x12,0x02,0x02,0x02,0x02,0x12,0x12,0x12,0x13,0x17,0x17,0x17,0x17,0x13,0x13,0x17,0x12,0x17,0x17,0x12,0x12,0x16,0x01,0x00,0x11,0x15,0x00,0x00,0x01,0x06,0x07, +/* 00001500 */ 0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x16,0x17,0x17,0x17,0x17,0x17,0x16,0x02,0x17,0x17,0x17,0x12,0x02,0x17,0x02,0x02,0x12, +/* 00001520 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x13,0x13,0x17,0x17,0x17,0x17,0x12,0x13,0x17,0x17,0x12,0x12,0x12,0x02,0x01,0x01,0x00,0x11,0x15,0x00,0x00,0x00,0x06,0x17, +/* 00001540 */ 0x3B,0x3B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x16,0x17,0x17,0x17,0x17,0x16,0x17,0x16,0x17,0x17,0x17,0x17,0x17,0x17,0x02,0x17,0x17, +/* 00001560 */ 0x16,0x02,0x02,0x02,0x17,0x02,0x02,0x17,0x02,0x02,0x13,0x17,0x17,0x17,0x13,0x17,0x12,0x12,0x12,0x17,0x02,0x01,0x01,0x01,0x00,0x11,0x15,0x15,0x00,0x00,0x01,0x06, +/* 00001580 */ 0x3B,0x2B,0x3B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x17,0x17,0x17,0x17,0x17,0x16,0x17,0x17,0x17,0x06,0x06,0x17,0x06,0x17,0x17,0x06,0x07, +/* 000015A0 */ 0x06,0x02,0x02,0x06,0x02,0x02,0x02,0x13,0x03,0x13,0x03,0x17,0x02,0x17,0x17,0x13,0x17,0x12,0x17,0x16,0x02,0x02,0x01,0x01,0x00,0x15,0x15,0x15,0x00,0x00,0x01,0x06, +/* 000015C0 */ 0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x06,0x17,0x17,0x06,0x06, +/* 000015E0 */ 0x02,0x02,0x06,0x06,0x02,0x02,0x03,0x02,0x13,0x03,0x17,0x13,0x13,0x17,0x13,0x13,0x13,0x02,0x02,0x12,0x12,0x02,0x01,0x01,0x01,0x15,0x15,0x15,0x00,0x01,0x01,0x01, +/* 00001600 */ 0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x06,0x06,0x06, +/* 00001620 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x17,0x13,0x13,0x13,0x13,0x12,0x17,0x02,0x13,0x13,0x02,0x12,0x02,0x12,0x02,0x01,0x00,0x00,0x11,0x25,0x00,0x05,0x05,0x01, +/* 00001640 */ 0x2B,0x2B,0x2B,0x3B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x1B,0x17,0x07,0x07,0x17,0x17,0x07,0x07,0x07,0x17,0x17,0x17,0x17,0x17,0x17,0x07,0x07,0x07,0x06,0x06,0x06, +/* 00001660 */ 0x07,0x03,0x03,0x07,0x07,0x03,0x02,0x03,0x17,0x17,0x13,0x13,0x13,0x17,0x17,0x13,0x13,0x13,0x02,0x12,0x02,0x02,0x02,0x02,0x01,0x00,0x00,0x25,0x11,0x00,0x09,0x06, +/* 00001680 */ 0x2B,0x2B,0x2B,0x3B,0x3F,0x3F,0x3F,0x2B,0x2B,0x17,0x07,0x03,0x03,0x07,0x07,0x07,0x17,0x07,0x07,0x0B,0x0B,0x1B,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x07, +/* 000016A0 */ 0x07,0x02,0x03,0x07,0x03,0x02,0x03,0x17,0x17,0x17,0x03,0x03,0x13,0x13,0x13,0x03,0x13,0x13,0x13,0x02,0x02,0x02,0x02,0x06,0x06,0x05,0x01,0x25,0x15,0x00,0x09,0x09, +/* 000016C0 */ 0x2B,0x2B,0x3B,0x3F,0x3F,0x2B,0x1B,0x17,0x03,0x03,0x03,0x03,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0B,0x1B,0x07,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x07, +/* 000016E0 */ 0x07,0x07,0x07,0x03,0x03,0x03,0x03,0x17,0x17,0x17,0x03,0x17,0x03,0x03,0x03,0x03,0x17,0x17,0x17,0x02,0x06,0x06,0x06,0x06,0x05,0x01,0x01,0x25,0x25,0x00,0x04,0x09, +/* 00001700 */ 0x2B,0x3B,0x3F,0x3F,0x2B,0x17,0x03,0x03,0x03,0x03,0x03,0x03,0x07,0x07,0x07,0x07,0x07,0x17,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x0B,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00001720 */ 0x07,0x07,0x07,0x07,0x03,0x03,0x07,0x07,0x07,0x07,0x07,0x17,0x13,0x17,0x17,0x17,0x17,0x17,0x07,0x07,0x06,0x06,0x06,0x06,0x05,0x05,0x05,0x15,0x26,0x00,0x00,0x05, +/* 00001740 */ 0x27,0x2B,0x2B,0x17,0x07,0x02,0x03,0x03,0x02,0x02,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0B,0x0A,0x0A,0x0B,0x0B,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00001760 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x03,0x03,0x03,0x07,0x07,0x07,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x06,0x05,0x0A,0x2F,0x00,0x15,0x01,0x00,0x00, +/* 00001780 */ 0x17,0x17,0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x07,0x07,0x07,0x07,0x06,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0B,0x0B,0x0A,0x06,0x0B,0x0B,0x07,0x07,0x07,0x07,0x07, +/* 000017A0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x03,0x07,0x07,0x07,0x07,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x06,0x06,0x0B,0x0A,0x06,0x01,0x26,0x15,0x01,0x05, +/* 000017C0 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x07,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x1B,0x1B,0x0B,0x0B,0x06,0x05,0x01,0x06,0x0B,0x0B,0x07,0x07,0x07, +/* 000017E0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0A,0x0A,0x0B,0x06,0x15,0x25,0x00,0x00, +/* 00001800 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x1B,0x2B,0x1B,0x07,0x0B,0x06,0x01,0x05,0x0B,0x0B,0x0B,0x07,0x07, +/* 00001820 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0A,0x0A,0x0A,0x0F,0x0A,0x15,0x25,0x00,0x2E, +/* 00001840 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x1B,0x2B,0x3B,0x1B,0x0B,0x07,0x06,0x06,0x0A,0x0B,0x0B,0x0B,0x07, +/* 00001860 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0A,0x0A,0x0A,0x0E,0x0B,0x15,0x26,0x15,0x15, +/* 00001880 */ 0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x1B,0x1B,0x2B,0x3F,0x2B,0x07,0x06,0x06,0x0A,0x06,0x06,0x0B,0x0B,0x0B, +/* 000018A0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0F,0x0F,0x0F,0x0F,0x0F,0x2F,0x15,0x25,0x15,0x15, +/* 000018C0 */ 0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x0B,0x1B,0x2B,0x2B,0x3F,0x1B,0x0B,0x07,0x06,0x0B,0x06,0x06,0x07,0x0B,0x0B, +/* 000018E0 */ 0x0B,0x0B,0x0B,0x0B,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x05,0x15,0x25,0x26,0x01, +/* 00001900 */ 0x02,0x02,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x0B,0x1B,0x1B,0x2B,0x3F,0x3F,0x0B,0x0B,0x0B,0x07,0x07,0x07,0x0B,0x07,0x0B,0x0B, +/* 00001920 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0F,0x0F,0x0F,0x0F,0x0E,0x0E,0x0A,0x0A,0x05,0x15,0x01,0x16,0x16, +/* 00001940 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x0B,0x0B,0x1B,0x2B,0x2B,0x3F,0x2B,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x07,0x07,0x0B,0x0B, +/* 00001960 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x0A,0x09,0x0A,0x0A,0x05,0x01,0x05,0x15, +/* 00001980 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x0B,0x0B,0x1B,0x1B,0x2B,0x3F,0x3F,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x07,0x0B,0x0B, +/* 000019A0 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x2B,0x0B,0x0B,0x0F,0x0F,0x0F,0x0F,0x0E,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x11,0x01,0x15, +/* 000019C0 */ 0x06,0x06,0x06,0x06,0x07,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x07,0x0B,0x0B,0x0B,0x1B,0x2B,0x2F,0x3F,0x2B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, +/* 000019E0 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x2F,0x3F,0x3F,0x3F,0x0A,0x0B,0x0F,0x0F,0x0F,0x0A,0x09,0x0A,0x0A,0x0A,0x0A,0x0A,0x15,0x15,0x11, +/* 00001A00 */ 0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x06,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x2B,0x3F,0x2F,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, +/* 00001A20 */ 0x1B,0x1B,0x0B,0x0B,0x0B,0x07,0x0B,0x07,0x0B,0x0B,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2A,0x0A,0x0F,0x0F,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x11,0x15,0x15, +/* 00001A40 */ 0x06,0x06,0x06,0x06,0x06,0x07,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x2B,0x3F,0x3F,0x1B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x3F, +/* 00001A60 */ 0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x2A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x01,0x15,0x15, +/* 00001A80 */ 0x07,0x07,0x06,0x06,0x06,0x07,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x1B,0x2F,0x3F,0x1B,0x0B,0x0B,0x0B,0x0B,0x1B,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00001AA0 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x1A,0x06,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x05,0x25,0x15, +/* 00001AC0 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x2B,0x2F,0x1F,0x0B,0x0B,0x0B,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00001AE0 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x15,0x25,0x11, +/* 00001B00 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1B,0x1B,0x1F,0x0F,0x0F,0x0F,0x1F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00001B20 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3F,0x2B,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0B,0x0B,0x05,0x15,0x15, +/* 00001B40 */ 0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0F,0x0F,0x0F,0x0E,0x1F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x1B,0x17,0x07, +/* 00001B60 */ 0x17,0x17,0x17,0x1B,0x2B,0x2B,0x3B,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3E,0x3F,0x3F,0x1F,0x0B,0x0A,0x0B,0x0B,0x0A,0x0B,0x0B,0x01,0x16,0x3F, +/* 00001B80 */ 0x06,0x0A,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0F,0x2F,0x3F,0x1F,0x0F,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x17,0x03,0x03,0x03,0x07, +/* 00001BA0 */ 0x07,0x07,0x07,0x17,0x17,0x17,0x17,0x26,0x3A,0x3E,0x3E,0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3E,0x3F,0x3F,0x3F,0x3F,0x1F,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x01,0x16,0x3F, +/* 00001BC0 */ 0x06,0x06,0x06,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1F,0x2F,0x1F,0x1F,0x1F,0x1F,0x0B,0x1B,0x2B,0x3F,0x3F,0x3F,0x2B,0x1B,0x17,0x07,0x03,0x1B,0x2F,0x2F,0x1B, +/* 00001BE0 */ 0x1B,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x17,0x2A,0x3A,0x3E,0x3F,0x3F,0x3E,0x3E,0x3D,0x3E,0x3F,0x3F,0x3F,0x3F,0x2F,0x0A,0x0B,0x0B,0x0F,0x0F,0x0B,0x05,0x2B,0x3F, +/* 00001C00 */ 0x06,0x06,0x06,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x1F,0x3F,0x3F,0x3F,0x1F,0x0F,0x0A,0x0B,0x0B,0x07,0x17,0x2B,0x3F,0x1B,0x17,0x1B,0x2B,0x1B,0x2F,0x3F,0x3F,0x3F,0x3F, +/* 00001C20 */ 0x3F,0x2F,0x1B,0x07,0x07,0x07,0x07,0x06,0x06,0x16,0x26,0x3A,0x3A,0x3E,0x3E,0x3E,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x3F,0x2F,0x1F,0x1A,0x29,0x3F, +/* 00001C40 */ 0x06,0x06,0x06,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B,0x3F,0x3F,0x3F,0x1F,0x0F,0x0F,0x0B,0x0B,0x07,0x07,0x07,0x17,0x17,0x17,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00001C60 */ 0x3F,0x3F,0x3F,0x1B,0x07,0x07,0x07,0x06,0x06,0x06,0x16,0x16,0x2A,0x3A,0x3E,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1A,0x2A,0x3F, +/* 00001C80 */ 0x05,0x06,0x0B,0x0B,0x0B,0x0A,0x0A,0x0A,0x0A,0x2F,0x1F,0x0E,0x0F,0x0F,0x0F,0x0B,0x07,0x07,0x07,0x07,0x06,0x07,0x17,0x17,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00001CA0 */ 0x3F,0x3F,0x3F,0x3F,0x2F,0x1B,0x1B,0x07,0x07,0x06,0x06,0x06,0x16,0x26,0x39,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2A,0x06,0x15, +/* 00001CC0 */ 0x00,0x05,0x05,0x05,0x05,0x04,0x1A,0x0A,0x05,0x0A,0x0A,0x0A,0x0F,0x0F,0x0B,0x07,0x07,0x06,0x06,0x06,0x06,0x02,0x07,0x17,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00001CE0 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1B,0x07,0x07,0x06,0x06,0x16,0x26,0x36,0x3A,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2A,0x1A,0x3F, +/* 00001D00 */ 0x05,0x00,0x00,0x00,0x00,0x00,0x05,0x05,0x0A,0x0E,0x0A,0x05,0x0A,0x0F,0x0B,0x07,0x07,0x06,0x02,0x02,0x02,0x02,0x02,0x17,0x1B,0x2B,0x2B,0x2F,0x3F,0x3F,0x3F,0x3F, +/* 00001D20 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x07,0x07,0x07,0x07,0x06,0x06,0x16,0x26,0x2A,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2A,0x15,0x2A, +/* 00001D40 */ 0x06,0x06,0x05,0x05,0x04,0x04,0x05,0x0A,0x1F,0x3F,0x3F,0x0A,0x0B,0x0B,0x07,0x07,0x07,0x06,0x06,0x02,0x02,0x02,0x02,0x07,0x17,0x17,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F, +/* 00001D60 */ 0x3F,0x3F,0x3F,0x3F,0x2F,0x1B,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x17,0x26,0x26,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2A,0x15,0x2F, +/* 00001D80 */ 0x17,0x17,0x07,0x06,0x06,0x05,0x09,0x0B,0x3F,0x3F,0x3F,0x0B,0x0B,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x02,0x02,0x06,0x07,0x07,0x17,0x17,0x1B,0x2B,0x2B,0x3F,0x3F, +/* 00001DA0 */ 0x3F,0x3F,0x3F,0x2B,0x07,0x07,0x07,0x07,0x17,0x17,0x17,0x17,0x17,0x17,0x26,0x26,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2A,0x00,0x3F, +/* 00001DC0 */ 0x16,0x17,0x17,0x17,0x1B,0x06,0x09,0x1A,0x1B,0x1B,0x2F,0x2F,0x0B,0x07,0x07,0x07,0x17,0x17,0x07,0x07,0x07,0x02,0x06,0x07,0x07,0x06,0x07,0x07,0x17,0x2B,0x3F,0x3F, +/* 00001DE0 */ 0x3F,0x2F,0x1B,0x07,0x07,0x07,0x07,0x07,0x17,0x17,0x07,0x06,0x16,0x17,0x26,0x27,0x2F,0x3F,0x3F,0x3E,0x3E,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F,0x2F,0x15,0x15,0x3F, +/* 00001E00 */ 0x16,0x17,0x17,0x17,0x17,0x1B,0x1B,0x1B,0x05,0x1B,0x3F,0x2F,0x0B,0x0B,0x07,0x17,0x17,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x07,0x07,0x1B,0x2B,0x2B, +/* 00001E20 */ 0x2B,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x17,0x06,0x06,0x16,0x17,0x26,0x2B,0x3F,0x3F,0x3F,0x3A,0x2A,0x2E,0x1F,0x1F,0x2F,0x2F,0x1F,0x0A,0x0A,0x05,0x15,0x3F, +/* 00001E40 */ 0x16,0x16,0x16,0x17,0x17,0x1B,0x3F,0x3F,0x1B,0x2F,0x1F,0x0B,0x0B,0x0B,0x07,0x17,0x17,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x17,0x17, +/* 00001E60 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x17,0x06,0x06,0x16,0x17,0x26,0x3F,0x3F,0x3F,0x3F,0x3F,0x2A,0x0E,0x0A,0x0A,0x0E,0x0E,0x0A,0x2F,0x3F,0x15,0x15,0x3F, +/* 00001E80 */ 0x06,0x16,0x17,0x17,0x17,0x1B,0x3F,0x3F,0x3F,0x2F,0x2F,0x0B,0x07,0x07,0x07,0x17,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00001EA0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x17,0x06,0x06,0x16,0x16,0x2B,0x2F,0x2F,0x3F,0x3F,0x3F,0x2E,0x0F,0x05,0x05,0x09,0x1A,0x3F,0x2F,0x1A,0x00,0x15,0x3F, +/* 00001EC0 */ 0x06,0x16,0x17,0x17,0x17,0x17,0x2F,0x3F,0x3F,0x3F,0x2F,0x0B,0x06,0x07,0x07,0x17,0x17,0x17,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00001EE0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x06,0x06,0x16,0x16,0x2B,0x0B,0x0B,0x2F,0x2F,0x2F,0x05,0x0A,0x1A,0x1A,0x1A,0x2A,0x3F,0x1A,0x0A,0x0F,0x00,0x15,0x3F, +/* 00001F00 */ 0x06,0x06,0x16,0x17,0x17,0x17,0x1B,0x3F,0x3F,0x3F,0x0F,0x0A,0x06,0x06,0x07,0x07,0x07,0x17,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00001F20 */ 0x07,0x07,0x07,0x07,0x06,0x07,0x17,0x07,0x07,0x06,0x07,0x16,0x1B,0x1B,0x2F,0x3F,0x3F,0x2F,0x2F,0x1A,0x1F,0x1E,0x09,0x0A,0x05,0x05,0x1A,0x1F,0x0E,0x00,0x2A,0x3F, +/* 00001F40 */ 0x06,0x06,0x16,0x17,0x17,0x1B,0x1B,0x1B,0x3F,0x2F,0x0A,0x05,0x06,0x06,0x06,0x07,0x07,0x17,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00001F60 */ 0x07,0x07,0x07,0x07,0x17,0x1B,0x17,0x07,0x07,0x07,0x06,0x16,0x2F,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2E,0x1E,0x1F,0x1E,0x0A,0x1E,0x04,0x04,0x09,0x1E,0x10,0x15,0x3F, +/* 00001F80 */ 0x16,0x06,0x06,0x16,0x17,0x17,0x17,0x1B,0x3F,0x3F,0x1B,0x06,0x05,0x06,0x06,0x07,0x07,0x07,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07, +/* 00001FA0 */ 0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x02,0x02,0x16,0x2F,0x3F,0x1A,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1E,0x1E,0x1A,0x2F,0x1F,0x05,0x05,0x0E,0x1A,0x25,0x3F, +/* 00001FC0 */ 0x06,0x06,0x06,0x16,0x17,0x17,0x17,0x0B,0x3F,0x3F,0x2F,0x06,0x01,0x05,0x06,0x07,0x07,0x07,0x17,0x17,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x1B,0x1B, +/* 00001FE0 */ 0x1B,0x1B,0x17,0x07,0x07,0x07,0x03,0x07,0x02,0x02,0x16,0x2F,0x2F,0x1F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x0A,0x1F,0x1A,0x1F,0x05,0x0A,0x0A,0x2A,0x3F, +/* 00002000 */ 0x06,0x06,0x06,0x16,0x17,0x17,0x17,0x07,0x2F,0x3F,0x2F,0x06,0x01,0x01,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x17,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00002020 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x1B,0x17,0x2F,0x16,0x06,0x06,0x06,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x1F,0x2F,0x1E,0x2F,0x05,0x0F,0x1A,0x3F, +/* 00002040 */ 0x06,0x06,0x06,0x17,0x17,0x17,0x17,0x07,0x2F,0x3F,0x2F,0x07,0x05,0x01,0x05,0x06,0x06,0x07,0x07,0x07,0x07,0x07,0x07,0x1B,0x3F,0x3F,0x3F,0x2B,0x2B,0x2B,0x2B,0x2B, +/* 00002060 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x15,0x1A,0x2A,0x1A,0x2F,0x3F,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F,0x1F,0x1F,0x0E,0x0F,0x1A,0x2A, +/* 00002080 */ 0x06,0x16,0x16,0x17,0x17,0x17,0x17,0x07,0x2F,0x3F,0x2F,0x0B,0x05,0x01,0x01,0x06,0x06,0x06,0x07,0x07,0x07,0x1B,0x3F,0x3F,0x3B,0x2B,0x27,0x2B,0x2B,0x2B,0x2B,0x2B, +/* 000020A0 */ 0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x2B,0x01,0x01,0x16,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F,0x2F,0x1F,0x1F,0x2F, +/* 000020C0 */ 0x06,0x06,0x16,0x17,0x17,0x17,0x17,0x07,0x2F,0x3F,0x2F,0x0B,0x06,0x01,0x05,0x06,0x06,0x06,0x07,0x07,0x1B,0x2B,0x27,0x27,0x27,0x27,0x17,0x17,0x27,0x27,0x27,0x2B, +/* 000020E0 */ 0x2B,0x2B,0x3F,0x3F,0x2B,0x17,0x03,0x03,0x17,0x2B,0x3F,0x2F,0x2B,0x2A,0x2A,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F,0x1F,0x1F,0x3F, +/* 00002100 */ 0x06,0x06,0x06,0x17,0x17,0x17,0x17,0x0B,0x3F,0x3F,0x1F,0x0B,0x06,0x00,0x05,0x05,0x06,0x06,0x06,0x02,0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x27,0x17,0x27,0x27,0x27, +/* 00002120 */ 0x2B,0x2B,0x2B,0x17,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x17,0x2B,0x3F,0x2F,0x1A,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F,0x2F,0x2F,0x2F, +/* 00002140 */ 0x06,0x16,0x16,0x17,0x17,0x17,0x07,0x0B,0x3F,0x3F,0x1B,0x0B,0x06,0x00,0x05,0x05,0x06,0x06,0x17,0x12,0x12,0x02,0x02,0x13,0x13,0x13,0x17,0x17,0x17,0x17,0x13,0x13, +/* 00002160 */ 0x17,0x17,0x17,0x27,0x2B,0x3F,0x17,0x03,0x13,0x03,0x03,0x03,0x03,0x17,0x2B,0x3F,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F,0x2F, +/* 00002180 */ 0x06,0x06,0x06,0x17,0x17,0x17,0x07,0x2F,0x3F,0x3F,0x0B,0x0B,0x06,0x00,0x05,0x05,0x06,0x17,0x13,0x12,0x02,0x02,0x02,0x02,0x03,0x13,0x13,0x13,0x13,0x13,0x13,0x13, +/* 000021A0 */ 0x17,0x17,0x13,0x2B,0x3F,0x3F,0x2B,0x17,0x03,0x13,0x03,0x03,0x03,0x03,0x03,0x17,0x3F,0x2E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x2F, +/* 000021C0 */ 0x06,0x06,0x06,0x07,0x07,0x07,0x0B,0x3F,0x3F,0x3F,0x0B,0x0B,0x05,0x00,0x05,0x05,0x17,0x13,0x12,0x02,0x02,0x12,0x02,0x02,0x02,0x02,0x13,0x13,0x13,0x13,0x13,0x13, +/* 000021E0 */ 0x13,0x13,0x13,0x27,0x27,0x2B,0x2B,0x3F,0x2B,0x17,0x03,0x03,0x03,0x03,0x03,0x17,0x17,0x1B,0x16,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1A, +/* 00002200 */ 0x06,0x06,0x06,0x07,0x07,0x07,0x2F,0x3F,0x3F,0x2F,0x0B,0x0B,0x05,0x00,0x00,0x06,0x13,0x12,0x12,0x02,0x02,0x02,0x02,0x03,0x03,0x02,0x03,0x03,0x13,0x13,0x13,0x17, +/* 00002220 */ 0x13,0x27,0x17,0x13,0x27,0x2B,0x27,0x2B,0x3F,0x2B,0x17,0x03,0x03,0x03,0x03,0x03,0x17,0x17,0x1B,0x0E,0x1E,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x09, +/* 00002240 */ 0x06,0x06,0x06,0x07,0x07,0x1B,0x3F,0x3F,0x3F,0x1B,0x0B,0x0A,0x05,0x00,0x01,0x17,0x12,0x02,0x02,0x12,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x17,0x13,0x13, +/* 00002260 */ 0x13,0x17,0x13,0x17,0x17,0x13,0x17,0x27,0x3B,0x2B,0x3F,0x2B,0x17,0x03,0x03,0x03,0x17,0x17,0x17,0x0B,0x0E,0x0E,0x1A,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1E,0x0A, +/* 00002280 */ 0x06,0x07,0x06,0x07,0x1B,0x3F,0x3F,0x3F,0x2F,0x0B,0x0B,0x0A,0x00,0x00,0x12,0x13,0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x13,0x03,0x03,0x03,0x13,0x13,0x13, +/* 000022A0 */ 0x17,0x27,0x13,0x17,0x13,0x13,0x27,0x27,0x2B,0x3B,0x3F,0x3F,0x3F,0x2B,0x17,0x03,0x03,0x03,0x06,0x16,0x1B,0x0E,0x09,0x0A,0x0E,0x1E,0x2F,0x2F,0x2E,0x2F,0x06,0x06, +/* 000022C0 */ 0x06,0x06,0x06,0x1B,0x2F,0x3F,0x3F,0x3F,0x0B,0x0B,0x0B,0x06,0x00,0x01,0x17,0x02,0x12,0x12,0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x13, +/* 000022E0 */ 0x17,0x13,0x13,0x13,0x27,0x27,0x17,0x27,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x17,0x03,0x03,0x06,0x16,0x1B,0x0E,0x09,0x0E,0x0A,0x09,0x09,0x0D,0x0A,0x16,0x01, +/* 00002300 */ 0x06,0x06,0x07,0x2F,0x3F,0x3F,0x3F,0x1B,0x06,0x0A,0x0A,0x05,0x00,0x16,0x17,0x02,0x02,0x12,0x13,0x13,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x13,0x13,0x13, +/* 00002320 */ 0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x27,0x2B,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x27,0x17,0x07,0x06,0x1B,0x09,0x0E,0x0A,0x0A,0x0A,0x0E,0x0A,0x05,0x00, +/* 00002340 */ 0x06,0x06,0x1B,0x2F,0x3F,0x3F,0x1B,0x07,0x06,0x0A,0x06,0x00,0x00,0x17,0x17,0x02,0x13,0x13,0x13,0x02,0x13,0x02,0x02,0x02,0x03,0x02,0x03,0x03,0x03,0x13,0x13,0x13, +/* 00002360 */ 0x13,0x13,0x17,0x17,0x13,0x13,0x17,0x2B,0x27,0x27,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x07,0x06,0x1A,0x0E,0x0E,0x0E,0x0E,0x0E,0x0A,0x15,0x00, +/* 00002380 */ 0x06,0x06,0x07,0x1B,0x1B,0x0B,0x07,0x06,0x0A,0x0A,0x05,0x00,0x01,0x17,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x02,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x16,0x13, +/* 000023A0 */ 0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x27,0x13,0x27,0x2B,0x2B,0x2B,0x3B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x02,0x06,0x0E,0x0E,0x0E,0x0E,0x0E,0x1A,0x05,0x05, +/* 000023C0 */ 0x06,0x06,0x06,0x07,0x07,0x06,0x06,0x06,0x0A,0x06,0x00,0x00,0x16,0x17,0x13,0x13,0x17,0x12,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, +/* 000023E0 */ 0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x13,0x13,0x27,0x27,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x16,0x06,0x0E,0x0E,0x0E,0x1F,0x05,0x09,0x09, +/* 00002400 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0A,0x05,0x00,0x00,0x17,0x17,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13, +/* 00002420 */ 0x13,0x13,0x13,0x13,0x17,0x13,0x17,0x13,0x17,0x27,0x27,0x27,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x02,0x0A,0x0E,0x0F,0x09,0x09,0x05,0x01, +/* 00002440 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0A,0x05,0x00,0x00,0x00,0x17,0x17,0x17,0x13,0x13,0x17,0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x13,0x13,0x13,0x13,0x13,0x13,0x13, +/* 00002460 */ 0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x17,0x27,0x27,0x17,0x17,0x27,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x16,0x02,0x05,0x0E,0x1F,0x05,0x01,0x00,0x00, +/* 00002480 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x0A,0x06,0x00,0x00,0x00,0x00,0x1B,0x17,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x13,0x13,0x03,0x02,0x13,0x03,0x13,0x13, +/* 000024A0 */ 0x13,0x13,0x13,0x03,0x03,0x13,0x13,0x17,0x27,0x17,0x17,0x17,0x17,0x17,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x03,0x12,0x05,0x1F,0x05,0x06,0x01,0x00,0x00, +/* 000024C0 */ 0x06,0x06,0x06,0x06,0x0A,0x0A,0x05,0x05,0x00,0x00,0x00,0x00,0x17,0x17,0x17,0x03,0x13,0x03,0x13,0x13,0x13,0x13,0x13,0x17,0x17,0x17,0x13,0x13,0x03,0x13,0x03,0x03, +/* 000024E0 */ 0x13,0x03,0x03,0x03,0x03,0x03,0x13,0x13,0x13,0x17,0x17,0x17,0x17,0x17,0x2B,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x2B,0x13,0x02,0x16,0x05,0x0F,0x05,0x00,0x00,0x00, +/* 00002500 */ 0x0A,0x0A,0x0A,0x0A,0x0A,0x06,0x05,0x04,0x00,0x00,0x00,0x00,0x17,0x17,0x13,0x03,0x03,0x13,0x03,0x03,0x03,0x13,0x03,0x13,0x13,0x13,0x03,0x03,0x03,0x13,0x03,0x03, +/* 00002520 */ 0x03,0x03,0x03,0x03,0x03,0x03,0x13,0x13,0x13,0x13,0x17,0x17,0x17,0x27,0x27,0x2B,0x2B,0x3F,0x3F,0x3F,0x3F,0x3F,0x17,0x03,0x02,0x02,0x05,0x06,0x00,0x00,0x00,0x00, +/* 00002540 */ 0x0A,0x0A,0x0A,0x05,0x05,0x05,0x04,0x05,0x00,0x00,0x00,0x00,0x17,0x17,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x13,0x13,0x13,0x13,0x03,0x03,0x03,0x03,0x03, +/* 00002560 */ 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x13,0x17,0x17,0x13,0x17,0x17,0x17,0x27,0x27,0x2B,0x3F,0x2B,0x3F,0x3F,0x3F,0x03,0x03,0x16,0x02,0x16,0x15,0x00,0x00,0x00,0x00, +/* 00002580 */ 0x0A,0x05,0x05,0x00,0x04,0x05,0x05,0x04,0x00,0x00,0x00,0x00,0x07,0x17,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x13,0x13,0x03,0x03,0x03,0x03, +/* 000025A0 */ 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x13,0x13,0x13,0x13,0x13,0x13,0x13,0x17,0x27,0x2B,0x2B,0x2B,0x2F,0x3F,0x13,0x13,0x12,0x17,0x01,0x11,0x00,0x01,0x00,0x00,0x00, +/* 000025C0 */ 0x05,0x05,0x00,0x00,0x04,0x05,0x05,0x05,0x05,0x00,0x00,0x04,0x07,0x17,0x07,0x02,0x03,0x03,0x02,0x03,0x03,0x03,0x17,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, +/* 000025E0 */ 0x02,0x02,0x03,0x02,0x03,0x03,0x03,0x03,0x03,0x13,0x13,0x17,0x17,0x17,0x17,0x27,0x17,0x17,0x2B,0x3F,0x2B,0x03,0x13,0x16,0x02,0x02,0x01,0x15,0x00,0x01,0x00,0x00, +/* 00002600 */ 0x0A,0x05,0x00,0x00,0x05,0x05,0x05,0x05,0x05,0x01,0x00,0x00,0x0B,0x17,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, +/* 00002620 */ 0x03,0x02,0x02,0x02,0x03,0x02,0x03,0x03,0x03,0x03,0x13,0x17,0x17,0x17,0x17,0x17,0x2B,0x17,0x2B,0x2B,0x03,0x03,0x13,0x02,0x02,0x02,0x01,0x00,0x00,0x01,0x00,0x00, +/* 00002640 */ 0x0F,0x09,0x00,0x00,0x05,0x05,0x05,0x05,0x05,0x01,0x00,0x00,0x06,0x17,0x07,0x03,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02, +/* 00002660 */ 0x03,0x03,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x17,0x17,0x17,0x17,0x17,0x2B,0x2B,0x2B,0x03,0x03,0x03,0x13,0x16,0x02,0x02,0x01,0x05,0x0A,0x00,0x06,0x00, +/* 00002680 */ 0x0F,0x09,0x00,0x00,0x05,0x05,0x05,0x05,0x05,0x05,0x00,0x00,0x05,0x1B,0x07,0x07,0x03,0x03,0x03,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x03,0x03,0x03,0x03, +/* 000026A0 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x13,0x17,0x13,0x17,0x17,0x2B,0x2B,0x17,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x01,0x1F,0x05,0x00,0x00,0x00, +/* 000026C0 */ 0x0E,0x04,0x00,0x00,0x05,0x05,0x05,0x05,0x05,0x05,0x01,0x00,0x05,0x0A,0x07,0x07,0x03,0x03,0x02,0x02,0x02,0x03,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03, +/* 000026E0 */ 0x03,0x02,0x02,0x02,0x02,0x03,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x13,0x17,0x17,0x2B,0x17,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x02,0x01,0x0A,0x05,0x00,0x00,0x00, +/* 00002700 */ 0x0E,0x05,0x00,0x00,0x05,0x05,0x05,0x05,0x09,0x0A,0x05,0x01,0x05,0x05,0x0B,0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03, +/* 00002720 */ 0x03,0x03,0x02,0x02,0x02,0x03,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x13,0x17,0x17,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x01,0x0A,0x00,0x00,0x00,0x00, +/* 00002740 */ 0x0F,0x0E,0x09,0x04,0x05,0x05,0x05,0x05,0x09,0x09,0x0A,0x15,0x05,0x05,0x0B,0x0B,0x06,0x02,0x06,0x02,0x02,0x02,0x02,0x07,0x07,0x02,0x03,0x03,0x03,0x03,0x03,0x02, +/* 00002760 */ 0x03,0x03,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x06,0x02,0x01,0x0A,0x00,0x00,0x00,0x00, +/* 00002780 */ 0x0F,0x0F,0x09,0x04,0x05,0x09,0x05,0x05,0x09,0x09,0x0A,0x05,0x01,0x05,0x05,0x0B,0x07,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x02, +/* 000027A0 */ 0x03,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x02,0x01,0x0F,0x00,0x00,0x00,0x00, +/* 000027C0 */ 0x0F,0x0F,0x09,0x04,0x05,0x09,0x05,0x09,0x09,0x09,0x09,0x05,0x01,0x05,0x05,0x09,0x0B,0x06,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03, +/* 000027E0 */ 0x03,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x01,0x0A,0x0F,0x00,0x00,0x00,0x00, +/* 00002800 */ 0x0F,0x0F,0x09,0x04,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x09,0x0A,0x06,0x06,0x07,0x06,0x06,0x06,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03, +/* 00002820 */ 0x03,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x01,0x01,0x05,0x0A,0x00,0x00,0x00,0x00, +/* 00002840 */ 0x0A,0x0E,0x09,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0A,0x05,0x01,0x05,0x09,0x0A,0x0A,0x0A,0x06,0x0B,0x0B,0x06,0x06,0x06,0x02,0x02,0x03,0x03,0x03,0x03,0x03, +/* 00002860 */ 0x03,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x01,0x00,0x10,0x00,0x00,0x00,0x01,0x00, +/* 00002880 */ 0x09,0x0E,0x0E,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0A,0x05,0x05,0x09,0x05,0x05,0x05,0x0A,0x0A,0x0B,0x06,0x06,0x06,0x06,0x06,0x02,0x03,0x03,0x07,0x03, +/* 000028A0 */ 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000028C0 */ 0x09,0x0E,0x0F,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x0A,0x05,0x1A,0x2F,0x0A,0x05,0x05,0x0A,0x09,0x0A,0x07,0x06,0x06,0x06,0x06,0x06,0x02,0x03,0x02,0x02, +/* 000028E0 */ 0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00002900 */ 0x09,0x0E,0x0F,0x0F,0x0A,0x09,0x09,0x09,0x09,0x05,0x09,0x09,0x0A,0x05,0x1B,0x3F,0x2F,0x0A,0x0A,0x09,0x05,0x05,0x09,0x0A,0x06,0x06,0x06,0x06,0x06,0x06,0x07,0x07, +/* 00002920 */ 0x02,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1A,0x00, +/* 00002940 */ 0x0A,0x0F,0x0F,0x0F,0x0E,0x09,0x09,0x09,0x09,0x05,0x05,0x09,0x09,0x0A,0x0A,0x3F,0x2F,0x0A,0x09,0x15,0x05,0x05,0x09,0x0F,0x0F,0x0A,0x06,0x06,0x06,0x07,0x07,0x07, +/* 00002960 */ 0x06,0x07,0x07,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x01,0x00,0x00,0x04,0x05,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00002980 */ 0x0E,0x0F,0x0F,0x0F,0x0F,0x09,0x09,0x09,0x09,0x09,0x0A,0x0A,0x09,0x09,0x05,0x2F,0x3F,0x0A,0x05,0x0A,0x0E,0x0A,0x0E,0x0F,0x0E,0x09,0x05,0x06,0x06,0x06,0x06,0x07, +/* 000029A0 */ 0x07,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x02,0x02,0x02,0x01,0x00,0x07,0x1B,0x00,0x05,0x00,0x00,0x00,0x11,0x11,0x00, +/* 000029C0 */ 0x0E,0x0F,0x0F,0x0F,0x0E,0x09,0x09,0x09,0x09,0x0E,0x0F,0x0F,0x0F,0x0F,0x0A,0x0A,0x1A,0x05,0x05,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x09,0x05,0x05,0x05,0x05,0x06,0x06, +/* 000029E0 */ 0x06,0x06,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00,0x05,0x06,0x0B,0x01,0x00,0x00,0x00,0x00,0x10,0x15,0x00, +/* 00002A00 */ 0x0F,0x0F,0x0F,0x0F,0x0E,0x09,0x09,0x09,0x09,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0A,0x05,0x05,0x05,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x05,0x05,0x09,0x09,0x05,0x09,0x05, +/* 00002A20 */ 0x06,0x06,0x01,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x01,0x00,0x00,0x01,0x01,0x05,0x06,0x01,0x01,0x01,0x15,0x00,0x00,0x11,0x11, +/* 00002A40 */ 0x0F,0x0F,0x0F,0x0F,0x0A,0x09,0x09,0x09,0x09,0x0A,0x0E,0x0F,0x0F,0x0F,0x0F,0x0A,0x01,0x05,0x05,0x09,0x0E,0x0E,0x0F,0x0F,0x0E,0x05,0x05,0x09,0x09,0x09,0x05,0x00, +/* 00002A60 */ 0x05,0x06,0x00,0x00,0x00,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x05,0x01,0x00,0x00,0x01,0x05,0x05,0x01,0x00,0x00,0x11,0x00,0x00,0x00,0x15,0x10, +/* 00002A80 */ 0x0F,0x0F,0x0F,0x0F,0x09,0x09,0x09,0x09,0x09,0x09,0x0A,0x0A,0x0A,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x0E,0x0F,0x0A,0x05,0x05,0x05,0x09,0x09,0x05,0x05, +/* 00002AA0 */ 0x06,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x05,0x01,0x01,0x00,0x00,0x00,0x00,0x11,0x01,0x00,0x15,0x11,0x15,0x15, +/* 00002AC0 */ 0x0F,0x0F,0x0F,0x0E,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x05,0x05,0x05,0x05,0x09,0x06,0x06, +/* 00002AE0 */ 0x06,0x05,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x05,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x15,0x00,0x05,0x00,0x00,0x00,0x00, +/* 00002B00 */ 0x0A,0x0F,0x0F,0x0A,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x04,0x05,0x05,0x05,0x05,0x05,0x0A,0x06,0x02, +/* 00002B20 */ 0x06,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x04,0x04,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x15,0x15,0x01,0x16,0x01,0x00,0x00,0x00, +/* 00002B40 */ 0x0A,0x0F,0x0F,0x0E,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x0A,0x0A,0x05,0x05,0x04,0x04,0x05,0x05,0x05,0x05,0x1A,0x06,0x02, +/* 00002B60 */ 0x02,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x04,0x04,0x04,0x00,0x01,0x01,0x01,0x01,0x01,0x11,0x15,0x00,0x15,0x16,0x16,0x15,0x00,0x01, +/* 00002B80 */ 0x06,0x0F,0x0F,0x0E,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x0A,0x0A,0x0A,0x09,0x05,0x04,0x05,0x05,0x04,0x06,0x17,0x06,0x02, +/* 00002BA0 */ 0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x16,0x11,0x05,0x01,0x01,0x05,0x16,0x05,0x05,0x12, +/* 00002BC0 */ 0x06,0x0A,0x0F,0x0A,0x09,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x01,0x05,0x0A,0x1A,0x0E,0x0A,0x04,0x04,0x04,0x05,0x17,0x17,0x02,0x02, +/* 00002BE0 */ 0x02,0x02,0x02,0x01,0x01,0x01,0x02,0x02,0x01,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x16,0x00,0x01,0x15,0x01,0x00,0x01,0x01,0x00,0x05,0x05,0x02, +/* 00002C00 */ 0x06,0x06,0x0A,0x0A,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x05,0x05,0x05,0x05,0x0A,0x0F,0x0F,0x09,0x04,0x04,0x05,0x17,0x17,0x02,0x02, +/* 00002C20 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x15,0x01,0x00,0x00,0x01,0x00,0x01,0x02,0x02, +/* 00002C40 */ 0x0A,0x0A,0x0A,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x05,0x01,0x09,0x0A,0x0A,0x0F,0x0E,0x04,0x04,0x06,0x17,0x02,0x02,0x02, +/* 00002C60 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x12,0x02,0x02,0x12,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02, +/* 00002C80 */ 0x06,0x0A,0x0A,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x09,0x05,0x01,0x0A,0x0A,0x0A,0x0A,0x0E,0x09,0x05,0x17,0x07,0x02,0x02,0x02, +/* 00002CA0 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x12,0x02,0x02,0x01,0x01,0x02,0x02,0x01,0x01,0x01,0x01,0x12,0x11,0x11,0x11,0x01,0x01,0x03,0x13, +/* 00002CC0 */ 0x06,0x1A,0x0A,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x09,0x05,0x01,0x05,0x0A,0x09,0x09,0x0A,0x09,0x0A,0x17,0x02,0x02,0x02,0x02, +/* 00002CE0 */ 0x02,0x02,0x06,0x02,0x02,0x02,0x02,0x02,0x12,0x02,0x02,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x11,0x01,0x12,0x16,0x16,0x16,0x16,0x12,0x01,0x05,0x02,0x13,0x13, +/* 00002D00 */ 0x06,0x1A,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x05,0x05,0x0A,0x09,0x09,0x05,0x09,0x0A,0x05,0x01,0x05,0x09,0x09,0x0A,0x09,0x0B,0x17,0x02,0x02,0x02,0x02, +/* 00002D20 */ 0x02,0x02,0x02,0x12,0x12,0x02,0x02,0x12,0x02,0x02,0x12,0x13,0x12,0x12,0x12,0x12,0x16,0x16,0x16,0x11,0x02,0x02,0x16,0x12,0x16,0x12,0x16,0x11,0x01,0x02,0x17,0x13, +/* 00002D40 */ 0x0A,0x1A,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x0A,0x0A,0x05,0x01,0x05,0x09,0x09,0x09,0x0A,0x0B,0x07,0x02,0x02,0x02,0x02, +/* 00002D60 */ 0x02,0x02,0x12,0x12,0x12,0x02,0x13,0x13,0x17,0x17,0x17,0x16,0x12,0x12,0x12,0x05,0x15,0x05,0x04,0x00,0x02,0x01,0x00,0x05,0x16,0x12,0x12,0x11,0x01,0x02,0x13,0x13, +/* 00002D80 */ 0x1A,0x1A,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x0A,0x0A,0x0A,0x05,0x01,0x05,0x09,0x09,0x09,0x09,0x07,0x07,0x02,0x02,0x02,0x02, +/* 00002DA0 */ 0x02,0x02,0x12,0x17,0x2B,0x2B,0x1B,0x2B,0x1B,0x1B,0x1B,0x2B,0x2B,0x1B,0x1B,0x1B,0x1A,0x05,0x05,0x01,0x16,0x00,0x00,0x00,0x00,0x01,0x01,0x15,0x01,0x17,0x17,0x13, +/* 00002DC0 */ 0x1A,0x19,0x05,0x05,0x05,0x05,0x05,0x05,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x05,0x05,0x09,0x09,0x09,0x09,0x07,0x07,0x03,0x02,0x02,0x02, +/* 00002DE0 */ 0x16,0x17,0x17,0x2B,0x2B,0x1B,0x1B,0x1B,0x1B,0x1B,0x2B,0x2B,0x2B,0x2F,0x2F,0x3F,0x3F,0x3F,0x2B,0x17,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x13,0x17,0x17, +/* 00002E00 */ 0x1A,0x15,0x05,0x09,0x0A,0x09,0x05,0x05,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x09,0x09,0x05,0x01,0x05,0x09,0x09,0x0A,0x17,0x17,0x02,0x02,0x02,0x13, +/* 00002E20 */ 0x17,0x17,0x27,0x17,0x17,0x17,0x2B,0x1B,0x1B,0x1B,0x2B,0x2F,0x2F,0x3F,0x3F,0x3F,0x3F,0x17,0x03,0x07,0x17,0x12,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x02,0x17, +/* 00002E40 */ 0x09,0x0A,0x0E,0x0F,0x0E,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x09,0x09,0x09,0x05,0x01,0x05,0x09,0x09,0x0A,0x1B,0x07,0x06,0x02,0x13,0x13, +/* 00002E60 */ 0x13,0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x2B,0x2B,0x2F,0x2F,0x3F,0x3F,0x3F,0x3F,0x13,0x17,0x17,0x06,0x02,0x02,0x02,0x02,0x05,0x00,0x00,0x00,0x00,0x12,0x02,0x17, +/* 00002E80 */ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x09,0x09,0x0A,0x1B,0x17,0x02,0x12,0x02,0x03, +/* 00002EA0 */ 0x13,0x13,0x13,0x17,0x17,0x17,0x2B,0x2B,0x2B,0x2B,0x2F,0x3F,0x3F,0x3F,0x3F,0x17,0x17,0x17,0x17,0x17,0x16,0x12,0x16,0x01,0x01,0x01,0x15,0x00,0x00,0x02,0x02,0x02, +/* 00002EC0 */ 0x0F,0x0F,0x0F,0x0F,0x0E,0x0A,0x09,0x09,0x09,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x01,0x05,0x09,0x09,0x1B,0x16,0x02,0x02,0x02,0x02, +/* 00002EE0 */ 0x13,0x13,0x13,0x13,0x17,0x27,0x17,0x2B,0x2B,0x2F,0x2B,0x3F,0x3F,0x3F,0x17,0x17,0x27,0x17,0x17,0x17,0x16,0x16,0x12,0x02,0x02,0x01,0x01,0x05,0x05,0x01,0x12,0x02, +/* 00002F00 */ 0x0F,0x0F,0x0F,0x0F,0x0E,0x09,0x09,0x09,0x09,0x0A,0x0A,0x09,0x09,0x05,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x01,0x05,0x09,0x06,0x16,0x02,0x02,0x02,0x02,0x02, +/* 00002F20 */ 0x13,0x13,0x13,0x13,0x17,0x17,0x17,0x2B,0x2B,0x2B,0x2B,0x2F,0x2B,0x17,0x17,0x16,0x16,0x17,0x17,0x27,0x16,0x16,0x12,0x11,0x11,0x01,0x01,0x01,0x01,0x01,0x02,0x02, +/* 00002F40 */ 0x0F,0x0F,0x0F,0x0F,0x0E,0x09,0x09,0x09,0x09,0x0A,0x09,0x09,0x05,0x09,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x01,0x05,0x0A,0x17,0x02,0x01,0x02,0x02,0x02,0x02, +/* 00002F60 */ 0x02,0x02,0x02,0x03,0x17,0x17,0x17,0x27,0x2B,0x2B,0x2F,0x2B,0x17,0x17,0x17,0x17,0x16,0x17,0x17,0x16,0x16,0x16,0x12,0x11,0x12,0x01,0x01,0x01,0x00,0x01,0x02,0x02, +/* 00002F80 */ 0x0F,0x0F,0x0F,0x0F,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x09,0x09,0x05,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x01,0x01,0x1B,0x16,0x02,0x12,0x02,0x02,0x02,0x12, +/* 00002FA0 */ 0x02,0x02,0x12,0x02,0x13,0x13,0x17,0x27,0x2B,0x2B,0x2B,0x13,0x17,0x17,0x27,0x17,0x17,0x17,0x16,0x27,0x16,0x12,0x12,0x12,0x11,0x11,0x01,0x01,0x00,0x00,0x01,0x02, +/* 00002FC0 */ 0x0F,0x0F,0x0F,0x0F,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x09,0x09,0x09,0x09,0x09,0x05,0x16,0x17,0x02,0x02,0x02,0x02,0x02,0x12,0x02, +/* 00002FE0 */ 0x02,0x02,0x02,0x02,0x13,0x13,0x17,0x2B,0x2B,0x27,0x13,0x12,0x16,0x16,0x17,0x16,0x17,0x27,0x17,0x26,0x16,0x12,0x12,0x12,0x12,0x11,0x01,0x01,0x00,0x00,0x01,0x02, +/* 00003000 */ 0x0F,0x0F,0x0F,0x0F,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x06,0x17,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +/* 00003020 */ 0x02,0x02,0x02,0x02,0x02,0x13,0x27,0x27,0x17,0x02,0x12,0x17,0x27,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x16,0x12,0x12,0x12,0x12,0x01,0x01,0x01,0x00,0x00,0x00,0x01, +/* 00003040 */ 0x0F,0x0F,0x0F,0x0E,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x09,0x09,0x09,0x09,0x09,0x0B,0x17,0x02,0x02,0x02,0x02,0x12,0x02,0x02,0x02, +/* 00003060 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x17,0x12,0x12,0x12,0x12,0x17,0x16,0x27,0x16,0x16,0x16,0x16,0x26,0x16,0x16,0x12,0x12,0x12,0x01,0x11,0x01,0x01,0x00,0x00,0x01, +/* 00003080 */ 0x0F,0x0E,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x09,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x09,0x0B,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +/* 000030A0 */ 0x02,0x02,0x02,0x12,0x02,0x02,0x12,0x16,0x17,0x12,0x12,0x12,0x12,0x17,0x27,0x16,0x16,0x16,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x01,0x01,0x01,0x00,0x00,0x00, +/* 000030C0 */ 0x09,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x09,0x09,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x17,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x12, +/* 000030E0 */ 0x12,0x02,0x02,0x02,0x02,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x16,0x12,0x12,0x12,0x16,0x12,0x12,0x12,0x01,0x01,0x01,0x00,0x00,0x00, +/* 00003100 */ 0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x09,0x05,0x09,0x09,0x09,0x09,0x09,0x05,0x06,0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12, +/* 00003120 */ 0x12,0x02,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x16,0x16,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x01,0x01,0x01,0x01,0x01,0x00,0x00, +/* 00003140 */ 0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x09,0x09,0x05,0x06,0x17,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +/* 00003160 */ 0x12,0x02,0x02,0x02,0x12,0x02,0x02,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x16,0x16,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x02,0x01,0x01,0x01,0x01,0x01,0x00,0x00, +/* 00003180 */ 0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x05,0x05,0x05,0x0B,0x17,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x02,0x02, +/* 000031A0 */ 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x12,0x12,0x12,0x16,0x16,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x02,0x01,0x01,0x01,0x01,0x01,0x00,0x00, +/* 000031C0 */ 0x0A,0x0A,0x0E,0x1E,0x1F,0x1F,0x2F,0x1F,0x0E,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x1B,0x06,0x02,0x02,0x02,0x02,0x06,0x06,0x02,0x02,0x16, +/* 000031E0 */ 0x12,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x02,0x02,0x02,0x02,0x12,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00, +/* 00003200 */ 0x09,0x0A,0x0E,0x1F,0x2F,0x3F,0x3F,0x2F,0x2F,0x1F,0x0E,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x09,0x09,0x1B,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x06,0x02,0x02, +/* 00003220 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x12,0x02,0x12,0x12,0x12,0x16,0x02,0x02,0x02,0x12,0x12,0x02,0x02,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x00, +/* 00003240 */ 0x0A,0x0B,0x1F,0x2F,0x2F,0x3F,0x2F,0x2F,0x2F,0x1F,0x0E,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x1B,0x06,0x02,0x02,0x02,0x02,0x02,0x06,0x06,0x02,0x02, +/* 00003260 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x02,0x02,0x12,0x12,0x12,0x12,0x12,0x12,0x02,0x02,0x02,0x12,0x02,0x01,0x02,0x12,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +/* 00003280 */ 0x0F,0x1F,0x1F,0x1F,0x2F,0x2F,0x2F,0x2F,0x1F,0x1F,0x0F,0x0A,0x09,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x0A,0x06,0x02,0x02,0x06,0x06,0x02,0x06,0x02,0x02,0x06, +/* 000032A0 */ 0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x12,0x02,0x12,0x02,0x02,0x02,0x12,0x12,0x01,0x02,0x01,0x12,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +/* 000032C0 */ 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x0F,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x19,0x09,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02, +/* 000032E0 */ 0x02,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x02,0x12,0x12,0x01,0x02,0x02,0x12,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +/* 00003300 */ 0x1F,0x1F,0x1F,0x0F,0x1F,0x1F,0x1F,0x1F,0x1F,0x0F,0x0E,0x09,0x04,0x05,0x05,0x05,0x05,0x05,0x05,0x19,0x09,0x05,0x06,0x02,0x02,0x02,0x06,0x02,0x02,0x02,0x02,0x02, +/* 00003320 */ 0x02,0x02,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x12,0x02,0x02,0x02,0x02,0x02,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, +/* 00003340 */ 0x1E,0x1E,0x0E,0x0A,0x2F,0x2F,0x3F,0x3F,0x2F,0x1F,0x0E,0x09,0x05,0x05,0x09,0x05,0x05,0x05,0x05,0x09,0x09,0x05,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x06,0x02,0x06, +/* 00003360 */ 0x02,0x06,0x06,0x06,0x06,0x06,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x01,0x02,0x01,0x01,0x01,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05, +/* 00003380 */ 0x04,0x08,0x09,0x0A,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x1E,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x04,0x09,0x09,0x05,0x05,0x06,0x02,0x02,0x02,0x06,0x02,0x06,0x02,0x02, +/* 000033A0 */ 0x02,0x02,0x06,0x06,0x06,0x06,0x02,0x06,0x02,0x02,0x01,0x01,0x01,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05, +/* 000033C0 */ 0x04,0x04,0x05,0x0A,0x2F,0x3F,0x3F,0x3F,0x3F,0x2F,0x1E,0x09,0x05,0x05,0x04,0x04,0x05,0x05,0x05,0x09,0x09,0x05,0x05,0x06,0x06,0x02,0x06,0x06,0x02,0x06,0x02,0x02, +/* 000033E0 */ 0x06,0x06,0x06,0x02,0x06,0x06,0x02,0x02,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05, +/* 00003400 */ 0x09,0x09,0x09,0x0A,0x1F,0x3F,0x3F,0x3F,0x3F,0x3F,0x1E,0x09,0x05,0x05,0x04,0x04,0x04,0x04,0x04,0x09,0x09,0x09,0x05,0x1A,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x02, +/* 00003420 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05, +/* 00003440 */ 0x09,0x09,0x0A,0x1E,0x1F,0x2F,0x2F,0x2F,0x1F,0x1E,0x1E,0x09,0x05,0x05,0x04,0x04,0x05,0x05,0x05,0x05,0x19,0x09,0x09,0x3F,0x1B,0x06,0x06,0x06,0x06,0x06,0x06,0x06, +/* 00003460 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05,0x05, +/* 00003480 */ 0x09,0x09,0x1E,0x2F,0x2F,0x1F,0x0F,0x0E,0x0E,0x09,0x04,0x04,0x05,0x05,0x05,0x05,0x04,0x09,0x09,0x05,0x09,0x09,0x05,0x2F,0x3F,0x1A,0x06,0x06,0x06,0x06,0x06,0x06, +/* 000034A0 */ 0x06,0x06,0x06,0x02,0x06,0x06,0x02,0x02,0x06,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05,0x05,0x05, +/* 000034C0 */ 0x05,0x05,0x0A,0x2F,0x2F,0x2F,0x0F,0x0E,0x0E,0x09,0x09,0x04,0x04,0x09,0x05,0x05,0x1E,0x2F,0x1E,0x09,0x09,0x09,0x05,0x1A,0x3F,0x2F,0x06,0x06,0x06,0x06,0x06,0x06, +/* 000034E0 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05,0x05,0x05, +/* 00003500 */ 0x05,0x05,0x05,0x0A,0x1F,0x1F,0x0F,0x0E,0x0E,0x09,0x05,0x05,0x04,0x05,0x09,0x1E,0x3F,0x3F,0x3F,0x2F,0x1E,0x1A,0x09,0x05,0x09,0x1E,0x2F,0x0A,0x0A,0x06,0x06,0x06, +/* 00003520 */ 0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05,0x05,0x05, +/* 00003540 */ 0x09,0x0A,0x0A,0x0A,0x0A,0x0A,0x0E,0x0E,0x0A,0x09,0x05,0x05,0x05,0x05,0x09,0x2E,0x3F,0x3F,0x3F,0x3F,0x3F,0x1E,0x09,0x05,0x04,0x09,0x2F,0x1F,0x0A,0x0A,0x0A,0x0A, +/* 00003560 */ 0x0A,0x0A,0x0A,0x06,0x06,0x06,0x06,0x06,0x06,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05,0x05,0x05,0x05,0x05, +/* 00003580 */ 0x0E,0x1E,0x0E,0x0E,0x0E,0x0E,0x0A,0x09,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x2E,0x3F,0x3F,0x2F,0x3F,0x3F,0x1E,0x09,0x09,0x04,0x09,0x2F,0x2F,0x09,0x05,0x0A,0x05, +/* 000035A0 */ 0x05,0x05,0x05,0x05,0x0A,0x06,0x06,0x06,0x06,0x06,0x05,0x01,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05,0x05,0x05,0x05,0x05,0x05, +/* 000035C0 */ 0x2F,0x2F,0x1F,0x0E,0x0F,0x0F,0x0F,0x0A,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x1A,0x09,0x09,0x1A,0x2F,0x09,0x05,0x09,0x05,0x1E,0x3F,0x2F,0x05,0x01,0x2B,0x2F, +/* 000035E0 */ 0x0A,0x0A,0x05,0x05,0x05,0x05,0x0A,0x0A,0x06,0x06,0x06,0x06,0x05,0x05,0x05,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x05,0x05,0x05,0x05,0x05,0x0A,0x06,0x05,0x06, +/* 00003600 */ 0x3F,0x3F,0x2F,0x2F,0x1E,0x0E,0x0E,0x0E,0x0A,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x05,0x05,0x09,0x05,0x05,0x0A,0x2F,0x2F,0x2F,0x0A,0x05,0x05,0x06,0x3F, +/* 00003620 */ 0x2F,0x1A,0x19,0x0A,0x0A,0x09,0x05,0x0A,0x0A,0x0A,0x0A,0x0A,0x06,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x06,0x06,0x2A,0x2A,0x06,0x06,0x06, +/* 00003640 */ 0x3F,0x3F,0x3F,0x2F,0x1E,0x0A,0x0E,0x0E,0x0E,0x0E,0x0A,0x0A,0x05,0x05,0x05,0x05,0x05,0x09,0x05,0x05,0x05,0x05,0x05,0x0A,0x3F,0x3F,0x0A,0x05,0x0A,0x1F,0x05,0x2F, +/* 00003660 */ 0x2E,0x09,0x05,0x0E,0x0F,0x0F,0x0E,0x0A,0x05,0x05,0x0A,0x0A,0x0A,0x0A,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x06,0x1A,0x3D,0x3D,0x3E,0x0A,0x06,0x06, +/* 00003680 */ 0x3F,0x3F,0x3F,0x2F,0x1E,0x05,0x0A,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x05,0x04,0x04,0x04,0x09,0x09,0x05,0x04,0x04,0x04,0x09,0x1F,0x1B,0x01,0x06,0x1A,0x2F,0x0A,0x05, +/* 000036A0 */ 0x09,0x04,0x09,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x0A,0x0A,0x0A,0x0A,0x06,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x0A,0x0A,0x3F,0x3F,0x3D,0x3D,0x3E,0x3E,0x06,0x06, +/* 000036C0 */ 0x3F,0x3F,0x3F,0x2F,0x1A,0x05,0x0A,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x05,0x04,0x04,0x04,0x09,0x05,0x09,0x09,0x04,0x09,0x1A,0x05,0x06,0x06,0x1E,0x3F,0x1F,0x05, +/* 000036E0 */ 0x04,0x05,0x09,0x0E,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x0F,0x0E,0x0A,0x0A,0x0A,0x0A,0x0A,0x09,0x2A,0x3A,0x05,0x05,0x3F,0x3F,0x3E,0x3D,0x3D,0x3E,0x2A,0x06, +/* 00003700 */ 0x3F,0x3F,0x2F,0x1E,0x0A,0x05,0x0A,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x09,0x04,0x04,0x05,0x09,0x3F,0x3F,0x1A,0x1E,0x2F,0x06,0x0B,0x0B,0x2F,0x3F,0x1E,0x00, +/* 00003720 */ 0x15,0x1A,0x1A,0x1B,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x0E,0x0F,0x0F,0x0E,0x09,0x09,0x1A,0x3E,0x3E,0x3E,0x3E,0x19,0x0B,0x1B,0x3F,0x3F,0x3E,0x3D,0x2D,0x2F,0x0A, +/* 00003740 */ 0x3F,0x2F,0x2F,0x1E,0x05,0x06,0x06,0x0B,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x05,0x04,0x04,0x05,0x2F,0x3F,0x2F,0x2F,0x1A,0x06,0x0B,0x0A,0x1E,0x1A,0x05,0x00, +/* 00003760 */ 0x05,0x2B,0x1B,0x1A,0x0A,0x0A,0x09,0x05,0x05,0x05,0x09,0x09,0x0E,0x0E,0x0E,0x0A,0x09,0x19,0x3D,0x3E,0x3E,0x3E,0x2A,0x0F,0x0F,0x2F,0x3F,0x3F,0x3D,0x2A,0x1E,0x1F, +/* 00003780 */ 0x3F,0x2F,0x1F,0x0A,0x06,0x06,0x16,0x17,0x0B,0x0F,0x0F,0x0F,0x0E,0x0E,0x0E,0x1F,0x1E,0x09,0x05,0x05,0x09,0x0A,0x1E,0x1F,0x05,0x0B,0x0B,0x1F,0x1E,0x0A,0x0A,0x05, +/* 000037A0 */ 0x05,0x1B,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x09,0x0A,0x19,0x39,0x3D,0x3D,0x3D,0x3E,0x3F,0x2F,0x1A,0x3F,0x3F,0x3E,0x1A,0x0A,0x0E, +/* 000037C0 */ 0x3F,0x3F,0x2B,0x17,0x06,0x16,0x17,0x17,0x06,0x06,0x09,0x09,0x09,0x09,0x09,0x0E,0x1E,0x0E,0x0A,0x05,0x05,0x05,0x0A,0x0A,0x06,0x1F,0x2F,0x3F,0x3F,0x0E,0x0E,0x09, +/* 000037E0 */ 0x06,0x2F,0x0A,0x05,0x04,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x1E,0x1A,0x05,0x05,0x19,0x19,0x1A,0x2F,0x2E,0x05,0x2F,0x3F,0x2F,0x0A,0x0A,0x0A, +/* 00003800 */ 0x3F,0x3F,0x2B,0x2B,0x16,0x16,0x06,0x06,0x05,0x04,0x04,0x04,0x09,0x09,0x09,0x09,0x09,0x0E,0x0E,0x0A,0x05,0x05,0x0A,0x06,0x0B,0x1F,0x1F,0x2F,0x1E,0x09,0x0E,0x0E, +/* 00003820 */ 0x06,0x2F,0x1F,0x0A,0x05,0x05,0x04,0x04,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x2E,0x2E,0x09,0x04,0x04,0x04,0x09,0x2F,0x1A,0x05,0x0A,0x3F,0x3F,0x0E,0x0A,0x0A, +/* 00003840 */ 0x3F,0x3F,0x3F,0x2B,0x2B,0x06,0x05,0x05,0x04,0x04,0x04,0x04,0x05,0x09,0x09,0x09,0x09,0x0A,0x0E,0x0E,0x09,0x05,0x0A,0x0B,0x2F,0x3F,0x1B,0x1F,0x0F,0x0A,0x09,0x0A, +/* 00003860 */ 0x0A,0x1B,0x3F,0x0E,0x0A,0x0A,0x09,0x04,0x04,0x04,0x05,0x05,0x05,0x04,0x04,0x0A,0x2F,0x2F,0x09,0x04,0x04,0x04,0x09,0x2F,0x1E,0x04,0x05,0x2F,0x3F,0x2F,0x0A,0x0E, +/* 00003880 */ 0x3F,0x3F,0x3F,0x2F,0x2B,0x16,0x05,0x04,0x04,0x04,0x04,0x04,0x05,0x09,0x09,0x09,0x09,0x09,0x0E,0x09,0x09,0x09,0x0A,0x0B,0x1B,0x1B,0x0A,0x0F,0x0F,0x0F,0x0A,0x09, +/* 000038A0 */ 0x09,0x06,0x3F,0x1F,0x0E,0x0E,0x0E,0x09,0x05,0x04,0x04,0x04,0x05,0x05,0x05,0x1A,0x2E,0x2F,0x2E,0x19,0x04,0x04,0x09,0x2F,0x2F,0x04,0x05,0x05,0x3F,0x3F,0x1E,0x1F, +/* 000038C0 */ 0x3F,0x3F,0x3F,0x2F,0x2B,0x1A,0x04,0x04,0x04,0x04,0x04,0x04,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x04,0x09,0x06,0x05,0x06,0x05,0x09,0x0F,0x0F,0x0F,0x0B,0x0A, +/* 000038E0 */ 0x09,0x05,0x2B,0x2F,0x0E,0x0E,0x0E,0x0E,0x0E,0x09,0x04,0x04,0x04,0x05,0x04,0x09,0x19,0x1E,0x2E,0x19,0x04,0x04,0x05,0x1F,0x2F,0x19,0x04,0x05,0x1A,0x3F,0x3F,0x1E, +/* 00003900 */ 0x1F,0x2F,0x3F,0x2F,0x2B,0x0A,0x04,0x04,0x05,0x05,0x04,0x04,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x04,0x04,0x0A,0x06,0x01,0x05,0x05,0x05,0x09,0x0F,0x0F,0x1F,0x0E, +/* 00003920 */ 0x0A,0x05,0x06,0x3F,0x1F,0x0A,0x0A,0x0E,0x0E,0x0E,0x09,0x05,0x04,0x04,0x09,0x1E,0x2F,0x2F,0x1F,0x0A,0x04,0x04,0x04,0x0E,0x3F,0x2E,0x15,0x05,0x05,0x2F,0x3F,0x1A, +/* 00003940 */ 0x0F,0x0F,0x0F,0x1F,0x0B,0x04,0x04,0x05,0x09,0x09,0x05,0x09,0x05,0x09,0x09,0x09,0x05,0x04,0x04,0x04,0x04,0x0A,0x0A,0x05,0x05,0x05,0x0A,0x09,0x09,0x0E,0x1F,0x2F, +/* 00003960 */ 0x1E,0x1A,0x06,0x2F,0x3F,0x1A,0x09,0x0A,0x0A,0x0E,0x0E,0x0E,0x1E,0x1F,0x3F,0x3F,0x3F,0x3F,0x2F,0x1E,0x04,0x00,0x00,0x09,0x2F,0x3F,0x09,0x04,0x05,0x0A,0x3F,0x3F, +/* 00003980 */ 0x0F,0x0F,0x0E,0x0E,0x09,0x04,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x04,0x04,0x04,0x04,0x05,0x1F,0x0F,0x05,0x05,0x05,0x0A,0x0F,0x0A,0x09,0x0A,0x0F, +/* 000039A0 */ 0x2F,0x2E,0x06,0x06,0x3F,0x3F,0x0A,0x0A,0x0A,0x1F,0x2F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x2F,0x1F,0x1F,0x0E,0x05,0x04,0x05,0x0E,0x1F,0x1F,0x0A,0x09,0x05,0x2F,0x3F, +/* 000039C0 */ 0x0F,0x0F,0x0E,0x09,0x05,0x04,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x04,0x04,0x04,0x05,0x0A,0x2F,0x1F,0x05,0x05,0x05,0x05,0x09,0x0E,0x0A,0x05,0x0A, +/* 000039E0 */ 0x0F,0x2F,0x1A,0x06,0x2B,0x3F,0x2F,0x1F,0x2F,0x3F,0x2F,0x2F,0x1E,0x0A,0x09,0x05,0x09,0x0A,0x0E,0x0F,0x0F,0x0F,0x0E,0x0A,0x0E,0x0F,0x0F,0x0F,0x0F,0x0A,0x0A,0x3F, +/* 00003A00 */ 0x0F,0x0F,0x0E,0x09,0x05,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x05,0x04,0x04,0x04,0x1A,0x1F,0x1F,0x0A,0x05,0x05,0x05,0x05,0x05,0x05,0x0E,0x0A,0x09, +/* 00003A20 */ 0x0A,0x1F,0x2B,0x1A,0x2F,0x2F,0x2F,0x2F,0x2F,0x1A,0x09,0x09,0x09,0x09,0x0A,0x09,0x05,0x05,0x05,0x0A,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0A,0x1A, +/* 00003A40 */ 0x0F,0x0E,0x0E,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x04,0x05,0x04,0x04,0x05,0x1B,0x1F,0x1F,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x0E,0x0A, +/* 00003A60 */ 0x05,0x09,0x2F,0x16,0x2F,0x3F,0x2E,0x19,0x09,0x09,0x09,0x09,0x05,0x05,0x05,0x09,0x09,0x05,0x04,0x09,0x0E,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x06, +/* 00003A80 */ 0x0F,0x0E,0x0D,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x04,0x04,0x04,0x05,0x04,0x1A,0x2F,0x1F,0x0F,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x0A,0x0E, +/* 00003AA0 */ 0x09,0x05,0x0A,0x0A,0x2F,0x3F,0x3F,0x3E,0x29,0x19,0x09,0x09,0x09,0x05,0x05,0x05,0x09,0x09,0x09,0x05,0x09,0x0F,0x0E,0x0A,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E, +/* 00003AC0 */ 0x0F,0x0E,0x0D,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x04,0x04,0x04,0x09,0x09,0x2B,0x1F,0x1F,0x0A,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09,0x0F, +/* 00003AE0 */ 0x0A,0x05,0x05,0x05,0x1B,0x3F,0x3F,0x3E,0x3E,0x29,0x19,0x05,0x05,0x05,0x05,0x05,0x09,0x09,0x0E,0x0E,0x0A,0x0E,0x0F,0x0E,0x09,0x09,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F, +/* 00003B00 */ 0x0A,0x0E,0x0E,0x0E,0x0A,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x04,0x04,0x04,0x0A,0x1F,0x2B,0x1F,0x1F,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x0F, +/* 00003B20 */ 0x0E,0x09,0x05,0x05,0x1B,0x3F,0x3F,0x3F,0x3E,0x3E,0x19,0x09,0x05,0x05,0x05,0x05,0x09,0x0A,0x0E,0x0E,0x0E,0x0E,0x0E,0x0F,0x0F,0x0E,0x09,0x09,0x0E,0x0F,0x0F,0x0F, +/* 00003B40 */ 0x09,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x09,0x09,0x09,0x09,0x09,0x05,0x04,0x04,0x04,0x09,0x1F,0x1B,0x2F,0x1A,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x09, +/* 00003B60 */ 0x09,0x05,0x05,0x05,0x1B,0x3F,0x3F,0x3F,0x3F,0x3E,0x2A,0x0A,0x09,0x09,0x09,0x09,0x0A,0x0E,0x0E,0x0E,0x0E,0x0E,0x09,0x0E,0x0F,0x0F,0x0F,0x0A,0x09,0x05,0x0A,0x0F, +/* 00003B80 */ 0x04,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x09,0x09,0x09,0x09,0x04,0x04,0x04,0x04,0x16,0x06,0x07,0x2F,0x1A,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, +/* 00003BA0 */ 0x05,0x05,0x05,0x05,0x0A,0x2F,0x3F,0x3F,0x3F,0x2E,0x1E,0x0A,0x0A,0x0A,0x0A,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0A,0x05,0x05,0x0E,0x0E,0x0F,0x0F,0x0F,0x0A,0x05,0x09, +/* 00003BC0 */ 0x05,0x05,0x0E,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x05,0x04,0x04,0x04,0x05,0x01,0x05,0x2B,0x1A,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, +/* 00003BE0 */ 0x05,0x05,0x05,0x05,0x06,0x2F,0x3F,0x2F,0x0F,0x0F,0x0B,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x09,0x05,0x05,0x05,0x0E,0x0E,0x0E,0x0F,0x0F,0x0E,0x09, +/* 00003C00 */ 0x0A,0x05,0x04,0x04,0x04,0x05,0x05,0x05,0x09,0x09,0x09,0x04,0x00,0x04,0x05,0x00,0x00,0x1A,0x2F,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, +/* 00003C20 */ 0x05,0x05,0x05,0x05,0x06,0x2F,0x3F,0x0F,0x0B,0x0B,0x0B,0x0A,0x0E,0x0F,0x0F,0x0F,0x0F,0x0E,0x0E,0x0E,0x0E,0x09,0x05,0x05,0x05,0x05,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F, +/* 00003C40 */ 0x0E,0x0A,0x09,0x1E,0x1F,0x0E,0x0E,0x09,0x09,0x09,0x04,0x04,0x04,0x04,0x00,0x00,0x01,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, +/* 00003C60 */ 0x05,0x05,0x05,0x09,0x0A,0x1B,0x3F,0x0F,0x0B,0x0B,0x0A,0x0E,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0E,0x0E,0x0A,0x05,0x05,0x05,0x05,0x09,0x0E,0x0E,0x0F,0x0F,0x0F, +/* 00003C80 */ 0x1E,0x1F,0x0E,0x09,0x1E,0x1E,0x1E,0x0E,0x09,0x09,0x04,0x00,0x04,0x00,0x00,0x01,0x06,0x09,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, +/* 00003CA0 */ 0x05,0x05,0x05,0x09,0x0B,0x1B,0x3F,0x1F,0x0B,0x0A,0x0A,0x0E,0x0E,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x09,0x05,0x05,0x05,0x04,0x09,0x0E,0x0E,0x0E,0x0F, +/* 00003CC0 */ 0x1F,0x1F,0x2F,0x0A,0x1E,0x2F,0x1E,0x0E,0x09,0x04,0x04,0x00,0x04,0x00,0x01,0x06,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05, +/* 00003CE0 */ 0x05,0x05,0x05,0x0A,0x0B,0x2F,0x3F,0x2F,0x0A,0x0F,0x0F,0x0E,0x0E,0x0E,0x0F,0x0F,0x0E,0x0E,0x0E,0x0E,0x0F,0x1F,0x09,0x05,0x05,0x05,0x05,0x04,0x0E,0x0E,0x0E,0x0E, +/* 00003D00 */ 0x2F,0x2F,0x2F,0x1F,0x1E,0x1E,0x1E,0x0E,0x09,0x04,0x04,0x04,0x00,0x00,0x06,0x06,0x04,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x04,0x04,0x05,0x05, +/* 00003D20 */ 0x05,0x05,0x05,0x0B,0x0B,0x2F,0x3F,0x3F,0x1F,0x2F,0x1F,0x0F,0x0E,0x0F,0x0F,0x0E,0x0E,0x0E,0x0E,0x0A,0x0F,0x0E,0x05,0x05,0x05,0x04,0x05,0x04,0x09,0x0E,0x0E,0x0E, +/* 00003D40 */ 0x2F,0x2F,0x2F,0x2F,0x1E,0x09,0x09,0x09,0x04,0x04,0x04,0x00,0x00,0x06,0x0B,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x04,0x04,0x05,0x00,0x00,0x01,0x05, +/* 00003D60 */ 0x04,0x05,0x0A,0x0F,0x0B,0x1F,0x3F,0x3F,0x0F,0x0E,0x0E,0x0F,0x0F,0x0F,0x0E,0x0E,0x0E,0x0E,0x0A,0x0E,0x1F,0x09,0x05,0x05,0x04,0x04,0x04,0x05,0x05,0x0E,0x0E,0x0E, +/* 00003D80 */ 0x3F,0x3F,0x3F,0x3F,0x2F,0x0A,0x0A,0x09,0x04,0x00,0x04,0x00,0x01,0x07,0x06,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x04,0x04,0x04,0x04,0x05,0x00,0x05,0x05,0x05, +/* 00003DA0 */ 0x05,0x0A,0x0A,0x0F,0x0A,0x0B,0x2F,0x3F,0x1F,0x0E,0x0E,0x0E,0x0F,0x0E,0x0E,0x0E,0x0E,0x0A,0x0A,0x1F,0x1E,0x09,0x05,0x05,0x04,0x04,0x04,0x04,0x04,0x0A,0x0E,0x0E, +/* 00003DC0 */ 0x3F,0x3F,0x3F,0x3F,0x2F,0x1E,0x1E,0x2F,0x09,0x04,0x04,0x00,0x06,0x06,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x04,0x05,0x0A,0x0A,0x0A, +/* 00003DE0 */ 0x0A,0x0B,0x0F,0x0E,0x0E,0x0A,0x0A,0x2F,0x3F,0x0F,0x0E,0x0E,0x0A,0x0E,0x0E,0x0A,0x0A,0x0A,0x2F,0x2F,0x0E,0x0A,0x09,0x05,0x04,0x04,0x04,0x04,0x04,0x09,0x0E,0x0E, +/* 00003E00 */ 0x2F,0x2F,0x2F,0x2F,0x2F,0x1E,0x09,0x1F,0x0F,0x05,0x00,0x01,0x07,0x05,0x04,0x05,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,0x0A,0x0A,0x0A, +/* 00003E20 */ 0x0A,0x0B,0x0A,0x0E,0x0E,0x0E,0x0A,0x0A,0x2F,0x2F,0x0F,0x0A,0x0A,0x0A,0x0A,0x09,0x09,0x0A,0x2F,0x1F,0x0A,0x09,0x09,0x05,0x00,0x00,0x04,0x04,0x04,0x04,0x0A,0x1F, +/* 00003E40 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, +/* 00003E60 */ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F +}; +#else +extern __root const unsigned char gBITMAP_64X250_SOLIDData[]; +#endif +// total bytes = 0x00003E80 (16000) +#define SIZE_BITMAP_64X250_SOLID 16000 +#endif diff --git a/video/src/samples/BITMAP_64X50_MASKED.BIN b/video/src/samples/BITMAP_64X50_MASKED.BIN new file mode 100644 index 00000000..267821c8 Binary files /dev/null and b/video/src/samples/BITMAP_64X50_MASKED.BIN differ diff --git a/video/src/samples/BITMAP_64X50_MASKED.BIN.RGB b/video/src/samples/BITMAP_64X50_MASKED.BIN.RGB new file mode 100644 index 00000000..1dbc0a2d Binary files /dev/null and b/video/src/samples/BITMAP_64X50_MASKED.BIN.RGB differ diff --git a/video/src/samples/BITMAP_64X50_MASKED.h b/video/src/samples/BITMAP_64X50_MASKED.h new file mode 100644 index 00000000..be3fcd47 --- /dev/null +++ b/video/src/samples/BITMAP_64X50_MASKED.h @@ -0,0 +1,119 @@ +// Input Binary File: BITMAP_64X50_MASKED.BIN +// Output Source File: BITMAP_64X50_MASKED.h +// Identifier: BITMAP_64X50_MASKED + +#ifndef _HEX_BITMAP_64X50_MASKED_ +#define _HEX_BITMAP_64X50_MASKED_ + +#ifdef _COMPILE_HEX_DATA_ +// Note: This is a generated source file! + +__root const unsigned char gBITMAP_64X50_MASKEDData[] = +{ +/* 00000000 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000020 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000040 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000060 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000080 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000000A0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000000C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000000E0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000100 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000120 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000140 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000160 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000180 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000001A0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000001C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0E,0x0F,0x0F,0x0B,0x00,0x00,0x00,0x00,0x08,0x0F,0x0F,0x0B,0x00,0x00,0x00,0x00, +/* 000001E0 */ 0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0B,0x00,0x00,0x00,0x0A,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000200 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0B,0x00,0x00,0x00,0x00, +/* 00000220 */ 0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0B,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000240 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x0F,0x0A,0x0F,0x0B,0x00,0x00,0x00,0x00, +/* 00000260 */ 0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x04,0x0F,0x0F,0x01,0x00,0x0E,0x0F,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000280 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0F,0x0B,0x04,0x0F,0x0B,0x00,0x08,0x0F,0x0B, +/* 000002A0 */ 0x00,0x04,0x0F,0x0B,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x08,0x0F,0x0B,0x00,0x00,0x08,0x0F,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000002C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0F,0x0F,0x0E,0x0F,0x0F,0x0B,0x00,0x00,0x0E,0x0F,0x01,0x04,0x0F,0x0B,0x00,0x00,0x0E,0x0F, +/* 000002E0 */ 0x06,0x0E,0x0F,0x01,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x08,0x0F,0x0B,0x00,0x00,0x08,0x0F,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000300 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x06,0x08,0x0F,0x0B,0x00,0x04,0x0F,0x0B,0x00,0x00,0x04,0x0F, +/* 00000320 */ 0x0F,0x0F,0x0B,0x00,0x00,0x00,0x00,0x00,0x04,0x0F,0x0F,0x02,0x08,0x0F,0x0B,0x00,0x00,0x08,0x0F,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000340 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0F,0x0F,0x00,0x00,0x08,0x0F,0x0B,0x09,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x0E, +/* 00000360 */ 0x0F,0x0F,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x06,0x08,0x0F,0x0B,0x00,0x00,0x08,0x0F,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000380 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x01,0x00,0x09,0x0F,0x0B,0x09,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x08,0x0F, +/* 000003A0 */ 0x0F,0x0F,0x0B,0x00,0x00,0x0A,0x00,0x00,0x04,0x0F,0x0F,0x02,0x04,0x0F,0x0F,0x00,0x00,0x0E,0x0F,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000003C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x02,0x00,0x00,0x00,0x00,0x04,0x0F,0x0B,0x00,0x00,0x0E,0x0F, +/* 000003E0 */ 0x01,0x0E,0x0F,0x02,0x00,0x0F,0x0F,0x0F,0x0F,0x0F,0x0B,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000400 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x02,0x00,0x00,0x00,0x00,0x00,0x04,0x0F,0x0B,0x00,0x09,0x0F,0x0B, +/* 00000420 */ 0x00,0x08,0x0F,0x0B,0x00,0x04,0x0F,0x0F,0x0F,0x0A,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000440 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000460 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000480 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000004A0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000004C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000004E0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000500 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000520 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000540 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000560 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000580 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000005A0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000005C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000005E0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000600 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000620 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000640 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000660 */ 0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000680 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0B,0x00,0x00,0x00,0x00,0x04,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000006A0 */ 0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000006C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000006E0 */ 0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000700 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x06,0x00,0x00,0x00,0x0F,0x0B,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000720 */ 0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000740 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x0A,0x0F,0x0B,0x00,0x00,0x08,0x0F,0x06,0x0E,0x0F,0x01,0x00,0x09,0x0F,0x0F,0x0F,0x0F,0x02,0x00,0x00,0x08,0x0F,0x0F,0x0F, +/* 00000760 */ 0x01,0x00,0x0E,0x0F,0x01,0x00,0x0E,0x0F,0x06,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x02,0x00,0x00,0x00,0x0E,0x0F,0x0F,0x0A,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000780 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x02,0x0E,0x0F,0x02,0x00,0x0E,0x0F,0x01,0x0E,0x0F,0x01,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x00,0x04,0x0F,0x0F,0x0A,0x0E, +/* 000007A0 */ 0x02,0x00,0x0E,0x0F,0x01,0x09,0x0F,0x0B,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000007C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x02,0x09,0x0F,0x0B,0x04,0x0F,0x0B,0x00,0x0E,0x0F,0x01,0x00,0x04,0x00,0x00,0x00,0x0E,0x0F,0x01,0x04,0x0F,0x0F,0x01,0x00, +/* 000007E0 */ 0x00,0x00,0x0E,0x0F,0x0A,0x0F,0x0B,0x00,0x00,0x04,0x0F,0x0F,0x00,0x00,0x09,0x0F,0x06,0x00,0x0F,0x0F,0x01,0x00,0x00,0x0F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000800 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x02,0x00,0x0F,0x0F,0x0A,0x0F,0x02,0x00,0x0E,0x0F,0x01,0x00,0x08,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x09,0x0F,0x0F,0x0F, +/* 00000820 */ 0x01,0x00,0x0E,0x0F,0x0F,0x0F,0x0B,0x00,0x00,0x08,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x06,0x04,0x0F,0x0B,0x00,0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000840 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x02,0x00,0x0E,0x0F,0x0F,0x0F,0x00,0x00,0x0E,0x0F,0x01,0x04,0x0F,0x0B,0x00,0x00,0x0E,0x0F,0x01,0x00,0x00,0x00,0x09,0x0F, +/* 00000860 */ 0x0B,0x00,0x0E,0x0F,0x01,0x0E,0x0F,0x06,0x00,0x04,0x0F,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0x01,0x00,0x00,0x0F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000880 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x02,0x00,0x08,0x0F,0x0F,0x0B,0x00,0x00,0x0E,0x0F,0x01,0x04,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x08,0x0F,0x0A,0x0E,0x0F, +/* 000008A0 */ 0x0B,0x00,0x0E,0x0F,0x01,0x04,0x0F,0x0F,0x01,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000008C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0F,0x02,0x00,0x00,0x0F,0x0F,0x02,0x00,0x00,0x0E,0x0F,0x01,0x00,0x09,0x0F,0x0F,0x0F,0x0A,0x0F,0x01,0x00,0x0F,0x0F,0x0F,0x0B, +/* 000008E0 */ 0x00,0x00,0x0E,0x0F,0x01,0x00,0x08,0x0F,0x0B,0x00,0x00,0x0E,0x0F,0x0F,0x0F,0x0F,0x01,0x00,0x00,0x0E,0x0F,0x0F,0x0A,0x0E,0x0F,0x01,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000900 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000920 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000940 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000960 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000980 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000009A0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000009C0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 000009E0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000A00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000A20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000A40 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000A60 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000A80 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000AA0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000AC0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000AE0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000B00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000B20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000B40 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000B60 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000B80 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000BA0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000BC0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000BE0 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000C00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000C20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000C40 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 00000C60 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 +}; +#else +extern __root const unsigned char gBITMAP_64X50_MASKEDData[]; +#endif +// total bytes = 0x00000C80 (3200) +#define SIZE_BITMAP_64X50_MASKED 3200 +#endif diff --git a/video/src/samples/BITMAP_64X50_SOLID.BIN b/video/src/samples/BITMAP_64X50_SOLID.BIN new file mode 100644 index 00000000..7c21ea03 --- /dev/null +++ b/video/src/samples/BITMAP_64X50_SOLID.BIN @@ -0,0 +1 @@ +                                                                                      \ No newline at end of file diff --git a/video/src/samples/BITMAP_64X50_SOLID.BIN.RGB b/video/src/samples/BITMAP_64X50_SOLID.BIN.RGB new file mode 100644 index 00000000..872b4691 Binary files /dev/null and b/video/src/samples/BITMAP_64X50_SOLID.BIN.RGB differ diff --git a/video/src/samples/BITMAP_64X50_SOLID.h b/video/src/samples/BITMAP_64X50_SOLID.h new file mode 100644 index 00000000..85844365 --- /dev/null +++ b/video/src/samples/BITMAP_64X50_SOLID.h @@ -0,0 +1,119 @@ +// Input Binary File: BITMAP_64X50_SOLID.BIN +// Output Source File: BITMAP_64X50_SOLID.h +// Identifier: BITMAP_64X50_SOLID + +#ifndef _HEX_BITMAP_64X50_SOLID_ +#define _HEX_BITMAP_64X50_SOLID_ + +#ifdef _COMPILE_HEX_DATA_ +// Note: This is a generated source file! + +__root const unsigned char gBITMAP_64X50_SOLIDData[] = +{ +/* 00000000 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000020 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000040 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000060 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000080 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000000A0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000000C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000000E0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000100 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000120 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000140 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000160 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000180 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000001A0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000001C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000001E0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000200 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000220 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000240 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000260 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000280 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000002A0 */ 0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x08,0x0E,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000002C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x18,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000002E0 */ 0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x0C,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000300 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x19,0x18,0x18,0x18,0x08,0x0E,0x0F,0x0E,0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000320 */ 0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000340 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0D,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x1A,0x18, +/* 00000360 */ 0x08,0x0E,0x0F,0x1E,0x18,0x0D,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x0F,0x0F,0x1E,0x18,0x18,0x08,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000380 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x19,0x18,0x18,0x08,0x0F,0x0F,0x19,0x0D,0x0F,0x0F,0x19,0x18,0x18,0x0E,0x0F,0x0F,0x18, +/* 000003A0 */ 0x0D,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x0C,0x0F,0x0F,0x1A,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000003C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x0E,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x19,0x18,0x0E,0x0F,0x1E,0x18,0x0D,0x0F,0x0F,0x19,0x18,0x18,0x0C,0x0F,0x0F,0x0E, +/* 000003E0 */ 0x0F,0x0F,0x1E,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1F,0x18,0x0C,0x0F,0x0F,0x19,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000400 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x0F,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x1E,0x0D,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x19,0x18,0x18,0x18,0x0E,0x0F,0x0F, +/* 00000420 */ 0x0F,0x0F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x19,0x0C,0x0F,0x0F,0x19,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000440 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x0C,0x0F,0x0F, +/* 00000460 */ 0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x19,0x0C,0x0F,0x0F,0x1A,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000480 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x0E,0x0F,0x0F, +/* 000004A0 */ 0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x19,0x08,0x0F,0x0F,0x1E,0x18,0x18,0x08,0x0F,0x0F,0x1A,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000004C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x1A,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x19,0x18,0x18,0x0D,0x0F,0x0F,0x0D, +/* 000004E0 */ 0x0F,0x0F,0x1F,0x18,0x08,0x0F,0x19,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x18,0x08,0x0E,0x0F,0x0F,0x19,0x18,0x0E,0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000500 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x19,0x18,0x08,0x0E,0x0F,0x1E,0x18, +/* 00000520 */ 0x0D,0x0F,0x0F,0x19,0x08,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x19,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000540 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0E,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x19,0x18, +/* 00000560 */ 0x08,0x0E,0x0F,0x1F,0x18,0x08,0x0E,0x0F,0x0F,0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000580 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000005A0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000005C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000005E0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000600 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000620 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000640 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000660 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000680 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000006A0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000006C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000006E0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000700 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000720 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000740 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000760 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000780 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000007A0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000007C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000007E0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000800 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000820 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000840 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x18,0x18,0x08,0x0E,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18, +/* 00000860 */ 0x18,0x08,0x0E,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x0E,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000880 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x0E,0x0F,0x0F,0x0F,0x0F,0x18,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1F,0x18,0x18, +/* 000008A0 */ 0x0C,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1F,0x18,0x08,0x0F,0x1F,0x18,0x0E,0x0F,0x19,0x18,0x18,0x0D,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000008C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x0E,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x19,0x18, +/* 000008E0 */ 0x0E,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x19,0x0C,0x0F,0x1E,0x18,0x0D,0x0F,0x1A,0x18,0x0C,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000900 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x08,0x0F,0x0F,0x1E,0x18,0x18,0x08,0x0F,0x0F,0x1E,0x08, +/* 00000920 */ 0x0F,0x0F,0x1E,0x18,0x18,0x08,0x0F,0x0F,0x1E,0x0C,0x0F,0x1E,0x18,0x0D,0x0F,0x1A,0x08,0x0F,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000940 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x1A,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x0C, +/* 00000960 */ 0x0F,0x0F,0x1A,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x08,0x0F,0x0F,0x18,0x0E,0x0F,0x19,0x0E,0x0F,0x19,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000980 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x19,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x0C, +/* 000009A0 */ 0x0F,0x0F,0x19,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x18,0x0D,0x0F,0x0F,0x0F,0x1A,0x0D,0x0F,0x1A,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 000009C0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x19,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x0C, +/* 000009E0 */ 0x0F,0x0F,0x19,0x18,0x18,0x08,0x0E,0x0F,0x1F,0x18,0x18,0x18,0x18,0x18,0x0D,0x0F,0x1F,0x08,0x0E,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000A00 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x1A,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x0C, +/* 00000A20 */ 0x0F,0x0F,0x1A,0x18,0x18,0x08,0x0E,0x0F,0x1E,0x18,0x18,0x18,0x18,0x08,0x0F,0x0F,0x08,0x0E,0x0F,0x19,0x0D,0x0F,0x1A,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000A40 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x08,0x0F,0x0F,0x1E,0x18,0x18,0x08,0x0F,0x0F,0x1A,0x08, +/* 00000A60 */ 0x0F,0x0F,0x1E,0x18,0x18,0x08,0x0F,0x0F,0x1A,0x18,0x18,0x18,0x08,0x0E,0x0F,0x19,0x08,0x0F,0x1F,0x18,0x0C,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000A80 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0E,0x0F,0x0F,0x18,0x18,0x18,0x08,0x0E,0x0F,0x0F,0x19,0x18,0x0E,0x0F,0x0F,0x19,0x08, +/* 00000AA0 */ 0x0E,0x0F,0x0F,0x19,0x18,0x0E,0x0F,0x0F,0x19,0x18,0x18,0x18,0x0E,0x0F,0x1A,0x18,0x08,0x0F,0x1F,0x18,0x0C,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000AC0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x19,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18, +/* 00000AE0 */ 0x0D,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x0D,0x0F,0x1E,0x18,0x18,0x08,0x0E,0x0F,0x19,0x0D,0x0F,0x1A,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000B00 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x19,0x18,0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18, +/* 00000B20 */ 0x18,0x0D,0x0F,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x0C,0x0F,0x1F,0x18,0x18,0x18,0x18,0x0C,0x0F,0x0F,0x0F,0x1E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000B40 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000B60 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000B80 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000BA0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000BC0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000BE0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000C00 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000C20 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000C40 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +/* 00000C60 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 +}; +#else +extern __root const unsigned char gBITMAP_64X50_SOLIDData[]; +#endif +// total bytes = 0x00000C80 (3200) +#define SIZE_BITMAP_64X50_SOLID 3200 +#endif diff --git a/video/src/samples/bitmap_64x250_solid.png b/video/src/samples/bitmap_64x250_solid.png new file mode 100644 index 00000000..5074eb69 Binary files /dev/null and b/video/src/samples/bitmap_64x250_solid.png differ diff --git a/video/src/samples/bitmap_64x50_masked.png b/video/src/samples/bitmap_64x50_masked.png new file mode 100644 index 00000000..158e8b27 Binary files /dev/null and b/video/src/samples/bitmap_64x50_masked.png differ diff --git a/video/src/samples/bitmap_64x50_solid.png b/video/src/samples/bitmap_64x50_solid.png new file mode 100644 index 00000000..c01bfd37 Binary files /dev/null and b/video/src/samples/bitmap_64x50_solid.png differ diff --git a/video/src/samples/primdemo.bas b/video/src/samples/primdemo.bas new file mode 100644 index 00000000..6a143cbd --- /dev/null +++ b/video/src/samples/primdemo.bas @@ -0,0 +1,485 @@ +5 REM OTF Primitives Demo +6 REM This demo shows various primitives in On-the-Fly mode. +7 REM Each type of primitive is in its own group, for testing purposes, +8 REM although that is not necessary for most of them. Also, the +9 REM program is verbose in order to illustrate concepts. It could +10 REM be leaner, in terms of code lines and variables. +11 CLS: VDU 23,1,0;0;0;0; +12 FREE_ID%=3 +13 FDFLT%=&000F: FGRP%=&000E: FSAME%=&0200 +15 OTF%=&1E17 +16 DIR%=1 +20 GRP_PT% = FN_Points(9,0,10) +30 REM GRP_LIN% = FN_Lines(9,10,10) +40 REM GRP_TRI_OUT% = FN_TriangleOutline(9,20,10) +50 REM GRP_SOL_TRI% = FN_SolidTriangle(9,30,10) +60 REM GRP_TRI_LST_OUT% = FN_TriangleListOutline(9,40,30) +70 REM GRP_SOL_TRI_LST% = FN_SolidTriangleList(9,70,30) +80 REM GRP_TRI_FAN_OUT% = FN_TriangleFanOutline(19,0,20) +90 REM GRP_SOL_TRI_FAN% = FN_SolidTriangleFan(19,20,20) +100 REM GRP_TRI_STR_OUT% = FN_TriangleStripOutline(19,40,30) +110 REM GRP_SOL_TRI_STR% = FN_SolidTriangleStrip(19,70,30) +120 REM GRP_QAD_OUT% = FN_QuadOutline(29,0,10) +130 REM GRP_SOL_QAD% = FN_SolidQuad(29,10,10) +140 REM GRP_QAD_LST_OUT% = FN_QuadListOutline(29,20,20) +150 REM GRP_SOL_QAD_LST% = FN_SolidQuadList(29,40,20) +160 REM GRP_QAD_STR_OUT% = FN_QuadStripOutline(29,60,20) +170 REM GRP_SOL_QAD_STR% = FN_SolidQuadStrip(29,80,20) +180 REM GRP_REC_OUT% = FN_RectangleOutline(39,0,10) +190 REM GRP_SOL_REC% = FN_SolidRectangle(39,10,10) +200 REM GRP_CIR_OUT% = FN_CircleOutline(39,20,10) +210 REM GRP_SOL_CIR% = FN_SolidCircle(39,30,10) +220 REM GRP_ELL_OUT% = FN_EllipseOutline(39,40,10) +230 REM GRP_SOL_ELL% = FN_SolidEllipse(39,50,10) +240 REM GRP_TER_SML% = FN_TerminalSmallFont(39,60,40) +250 REM GRP_SOL_BMP% = FN_SolidBitmap(49,0,10) +260 REM GRP_MSK_BMP% = FN_MaskedBitmap(49,10,10) +270 REM GRP_BMP_FRM% = FN_BitmapFrames(49,20,10) +280 REM GRP_BMP_SCR% = FN_BitmapScroll(49,30,10) +290 REM GRP_GRP_MOV% = FN_GroupMove(49,40,10) +300 REM GRP_TER_BIG% = FN_TerminalBigFont(49,50,50) +310 REM GRP_TRN_BMP% = FN_TransparentBitmaps(69,0,40) +320 REM GRP_SOL_REN% = FN_Solid3DRender(69,40,20) +330 REM GRP_MSK_REN% = FN_Masked3DRender(69,60,20) +340 REM GRP_TRN_REN% = FN_Transparent3DRender(69,80,20) +350 REM ----------- +355 REM ANIMATIONS +357 REM ----------- +400 IF INKEY(0)>=0 THEN GOTO 997 +405 *FX 19 +410 REM Flip bitmap Frames +420 SLICE%=SLICE%+50: IF SLICE%>=250 THEN SLICE%=0 +430 VDU OTF%;123,GRP_BMP_FRM%+2;8;10;SLICE%;50; +440 REM Scroll bitmap +450 SCROLL%=SCROLL%+DIR% +455 IF SCROLL%<0 THEN SCROLL%=0:DIR%=1 +457 IF SCROLL%>200 THEN SCROLL%=200:DIR%=-1 +460 VDU OTF%;123,GRP_BMP_SCR%+2;8;10;SCROLL%;50; +996 GOTO 400 +997 CLS: VDU 23,1,1;0;0;0; +998 END +999 REM ----------- +1000 DEF FN_GetID +1010 ID%=FREE_ID% +1020 FREE_ID%=FREE_ID%+1 +1030 =ID% +1099 REM ----------- +1100 DEF PROC_Title(R%,C%,W%,T$) +1110 PRINT TAB(C%+(W%-LEN(T$))/2,R%);T$; +1120 ENDPROC +1199 REM ----------- +1200 DEF PROC_Title2(R%,C%,W%,T1$,T2$) +1210 PROC_Title(R%-1,C%,W%,T1$) +1220 PROC_Title(R%,C%,W%,T2$) +1230 ENDPROC +1299 REM ----------- +1300 DEF PROC_Title3(R%,C%,W%,T1$,T2$,T3$) +1310 PROC_Title(R%-2,C%,W%,T1$) +1320 PROC_Title(R%-1,C%,W%,T2$) +1330 PROC_Title(R%,C%,W%,T3$) +1330 ENDPROC +1399 REM ----------- +1400 DEF PROC_SetArea(GRP%,R%,C%,W%) +1405 REM PROC_Title(R%-2,C%,W%,STR$(GRP%)) +1410 AreaX1%=C%*8 +1420 AreaY2%=(R%+1)*8+1 +1430 AreaX2%=AreaX1%+W%*8 +1440 IF R%>=50 THEN AreaY1%=AreaY2%-20*8 ELSE AreaY1%=AreaY2%-10*8 +1450 AreaWidth%=AreaX2%-AreaX1% +1460 AreaHeight%=AreaY2%-AreaY1% +1465 VDU OTF%;140,GRP%;0;FGRP%;AreaX1%;AreaY1%;AreaWidth%;AreaHeight%; +1470 ID%=FN_GetID +1480 VDU OTF%;40,ID%;GRP%;FDFLT%;0;0;AreaWidth%;AreaHeight%;&D5 +1490 VDU OTF%;4,ID%; +1498 ENDPROC +1499 REM ----------- +1500 DEF FN_Color +1510 =&C0+RND(62) +1599 REM ----------- +10000 DEF FN_Points(R%,C%,W%) +10010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +10020 PROC_Title(R%,C%,W%,"Point") +10030 FOR I%=0 TO 9 +10040 ID%=FN_GetID +10050 X%=RND(60)+10 +10060 Y%=RND(60)+5 +10070 VDU OTF%;10,ID%;GRP%;FDFLT%;X%;Y%;FN_Color +10080 VDU OTF%;4,ID%; +10090 NEXT I% +10998 =GRP% +10999 REM ----------- +11000 DEF FN_Lines(R%,C%,W%) +11010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +11020 PROC_Title(R%,C%,W%,"Line") +11030 FOR I%=0 TO 9 +11040 ID%=FN_GetID +11050 X1%=RND(60)+10:Y1%=RND(60)+5 +11060 X2%=RND(60)+10:Y2%=RND(60)+5 +11070 VDU OTF%;20,ID%;GRP%;FDFLT%;X1%;Y1%;X2%;Y2%;FN_Color +11080 VDU OTF%;4,ID%; +11090 NEXT I% +11998 =GRP% +11999 REM ----------- +12000 DEF FN_TriangleOutline(R%,C%,W%) +12010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +12020 PROC_Title2(R%,C%,W%,"Triangle","Outline") +12030 FOR I%=0 TO 4 +12040 ID%=FN_GetID +12050 X1%=RND(60)+10:Y1%=RND(60)+5 +12060 X2%=RND(60)+10:Y2%=RND(60)+5 +12070 X3%=RND(60)+10:Y3%=RND(60)+5 +12080 VDU OTF%;30,ID%;GRP%;FDFLT%;FN_Color,X1%;Y1%;X2%;Y2%;X3%;Y3%; +12090 VDU OTF%;4,ID%; +12100 NEXT I% +12998 =GRP% +12999 REM ----------- +13000 DEF FN_SolidTriangle(R%,C%,W%) +13010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +13020 PROC_Title2(R%,C%,W%,"Solid","Triangle") +13030 FOR I%=0 TO 4 +13040 ID%=FN_GetID +13050 X1%=RND(60)+10:Y1%=RND(60)+5 +13060 X2%=RND(60)+10:Y2%=RND(60)+5 +13070 X3%=RND(60)+10:Y3%=RND(60)+5 +13080 VDU OTF%;31,ID%;GRP%;FDFLT%;FN_Color,X1%;Y1%;X2%;Y2%;X3%;Y3%; +13090 VDU OTF%;4,ID%; +13100 NEXT I% +13998 =GRP% +13999 REM ----------- +14000 DEF FN_TriangleListOutline(R%,C%,W%) +14010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +14020 PROC_Title(R%,C%,W%,"Triangle List Outline") +14030 ID%=FN_GetID +14040 VDU OTF%;32,ID%;GRP%;FDFLT%;5;FN_Color +14050 FOR I%=0 TO 4 +14060 X1%=RND(210)+10:Y1%=RND(60)+5 +14070 X2%=RND(210)+10:Y2%=RND(60)+5 +14080 X3%=RND(210)+10:Y3%=RND(60)+5 +14090 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%; +14100 NEXT I% +14110 VDU OTF%;4,ID%; +14998 =GRP% +14999 REM ----------- +15000 DEF FN_SolidTriangleList(R%,C%,W%) +15010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +15020 PROC_Title(R%,C%,W%,"Solid Triangle List") +15030 ID%=FN_GetID +15040 VDU OTF%;33,ID%;GRP%;FDFLT%;5;FN_Color +15050 FOR I%=0 TO 4 +15060 X1%=RND(210)+10:Y1%=RND(60)+5 +15070 X2%=RND(210)+10:Y2%=RND(60)+5 +15080 X3%=RND(210)+10:Y3%=RND(60)+5 +15090 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%; +15100 NEXT I% +15110 VDU OTF%;4,ID%; +15998 =GRP% +15999 REM ----------- +16000 DEF FN_TriangleFanOutline(R%,C%,W%) +16010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +16020 PROC_Title(R%,C%,W%,"Triangle Fan Outline") +16030 ID%=FN_GetID +16040 VDU OTF%;34,ID%;GRP%;FDFLT%;5;FN_Color +16050 SX0%=80: SY0%=65 +16060 SX1%=20: SY1%=20 +16070 VDU SX0%;SY0%;SX1%;SY1%; +16080 FOR I%=0 TO 4 +16090 X%=20+I%*20: Y%=5+(I%*(I% AND 3)) +16100 VDU X%;Y%; +16110 NEXT I% +16120 VDU OTF%;4,ID%; +16998 =GRP% +16999 REM ----------- +17000 DEF FN_SolidTriangleFan(R%,C%,W%) +17010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +17020 PROC_Title(R%,C%,W%,"Solid Triangle Fan") +17030 ID%=FN_GetID +17040 VDU OTF%;35,ID%;GRP%;FDFLT%;5;FN_Color +17050 SX0%=80: SY0%=65 +17060 SX1%=20: SY1%=20 +17070 VDU SX0%;SY0%;SX1%;SY1%; +17080 FOR I%=0 TO 4 +17090 X%=20+I%*20: Y%=5+(I%*(I% AND 3)) +17100 VDU X%;Y%; +17110 NEXT I% +17120 VDU OTF%;4,ID%; +17998 =GRP% +17999 REM ----------- +18000 DEF FN_TriangleStripOutline(R%,C%,W%) +18010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +18020 PROC_Title(R%,C%,W%,"Triangle Strip Outline") +18030 ID%=FN_GetID +18040 VDU OTF%;36,ID%;GRP%;FDFLT%;7;FN_Color +18050 SX0%=20: SY0%=65 +18060 SX1%=25: SY1%=20 +18070 VDU SX0%;SY0%;SX1%;SY1%; +18080 FOR I%=0 TO 6 +18090 X%=30+I%*20: Y%=65-((I% AND 1)*40) +18100 VDU X%;Y%; +18110 NEXT I% +18120 VDU OTF%;4,ID%; +18998 =GRP% +18999 REM ----------- +19000 DEF FN_SolidTriangleStrip(R%,C%,W%) +19010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +19020 PROC_Title(R%,C%,W%,"Solid Triangle Strip") +19030 ID%=FN_GetID +19040 VDU OTF%;37,ID%;GRP%;FDFLT%;7;FN_Color +19050 SX0%=20: SY0%=65 +19060 SX1%=25: SY1%=20 +19070 VDU SX0%;SY0%;SX1%;SY1%; +19080 FOR I%=0 TO 6 +19090 X%=30+I%*20: Y%=65-((I% AND 1)*40) +19100 VDU X%;Y%; +19110 NEXT I% +19120 VDU OTF%;4,ID%; +19998 =GRP% +19999 REM ----------- +20000 DEF FN_QuadOutline(R%,C%,W%) +20010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +20020 PROC_Title2(R%,C%,W%,"Quad","Outline") +20030 ID%=FN_GetID +20040 X1%=20:Y1%=52 +20050 X2%=25:Y2%=5 +20060 X3%=62:Y3%=15 +20070 X4%=55:Y4%=50 +20080 VDU OTF%;60,ID%;GRP%;FDFLT%;FN_Color,X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +20090 VDU OTF%;4,ID%; +20998 =GRP% +20999 REM ----------- +21000 DEF FN_SolidQuad(R%,C%,W%) +21010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +21020 PROC_Title2(R%,C%,W%,"Solid","Quad") +21030 ID%=FN_GetID +21040 X1%=20:Y1%=52 +21050 X2%=25:Y2%=5 +21060 X3%=62:Y3%=15 +21070 X4%=55:Y4%=50 +21080 VDU OTF%;61,ID%;GRP%;FDFLT%;FN_Color,X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +21090 VDU OTF%;4,ID%; +21998 =GRP% +21999 REM ----------- +22000 DEF FN_QuadListOutline(R%,C%,W%) +22010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +22020 PROC_Title(R%,C%,W%,"Quad List Outline") +22030 ID%=FN_GetID +22040 VDU OTF%;62,ID%;GRP%;FDFLT%;3;FN_Color +22050 X1%=20:Y1%=52 +22060 X2%=25:Y2%=9 +22070 X3%=62:Y3%=15 +22080 X4%=55:Y4%=46 +22090 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +22100 X1%=50:Y1%=52 +22110 X2%=65:Y2%=5 +22120 X3%=92:Y3%=15 +22130 X4%=85:Y4%=50 +22140 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +22150 X1%=80:Y1%=52 +22160 X2%=85:Y2%=11 +22170 X3%=122:Y3%=15 +22180 X4%=115:Y4%=48 +22190 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +22200 VDU OTF%;4,ID%; +22998 =GRP% +22999 REM ----------- +23000 DEF FN_SolidQuadList(R%,C%,W%) +23010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +23020 PROC_Title(R%,C%,W%,"Solid Quad List") +23030 ID%=FN_GetID +23040 VDU OTF%;63,ID%;GRP%;FDFLT%;3;FN_Color +23050 X1%=20:Y1%=52 +23060 X2%=25:Y2%=9 +23070 X3%=62:Y3%=15 +23080 X4%=55:Y4%=46 +23090 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +23100 X1%=50:Y1%=49 +23110 X2%=65:Y2%=5 +23120 X3%=92:Y3%=15 +23130 X4%=85:Y4%=50 +23140 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +23150 X1%=80:Y1%=52 +23160 X2%=85:Y2%=11 +23170 X3%=122:Y3%=15 +23180 X4%=115:Y4%=48 +23190 VDU X1%;Y1%;X2%;Y2%;X3%;Y3%;X4%;Y4%; +23200 VDU OTF%;4,ID%; +23998 =GRP% +23999 REM ----------- +24000 DEF FN_QuadStripOutline(R%,C%,W%) +24010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +24020 PROC_Title(R%,C%,W%,"Quad Strip Outline") +24030 ID%=FN_GetID +24040 VDU OTF%;64,ID%;GRP%;FDFLT%;6;FN_Color +24050 SX0%=20: SY0%=65 +24060 SX1%=25: SY1%=20 +24070 VDU SX0%;SY0%;SX1%;SY1%; +24080 FOR I%=0 TO 5 +24090 X1%=30+I%*20: Y1%=10-((I% AND 3)*2) +24100 X2%=30+I%*22: Y2%=65-((I% AND 3)*3) +24110 VDU X1%;Y1%;X2%;Y2%; +24120 NEXT I% +24130 VDU OTF%;4,ID%; +24998 =GRP% +24999 REM ----------- +25000 DEF FN_SolidQuadStrip(R%,C%,W%) +25010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +25020 PROC_Title(R%,C%,W%,"Solid Quad Strip") +25030 ID%=FN_GetID +25040 VDU OTF%;65,ID%;GRP%;FDFLT%;6;FN_Color +25050 SX0%=20: SY0%=65 +25060 SX1%=25: SY1%=20 +25070 VDU SX0%;SY0%;SX1%;SY1%; +25080 FOR I%=0 TO 5 +25090 X1%=30+I%*20: Y1%=10-((I% AND 3)*2) +25100 X2%=30+I%*22: Y2%=65-((I% AND 3)*3) +25110 VDU X1%;Y1%;X2%;Y2%; +25120 NEXT I% +25130 VDU OTF%;4,ID%; +25998 =GRP% +25999 REM ----------- +26000 DEF FN_RectangleOutline(R%,C%,W%) +26010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +26020 PROC_Title2(R%,C%,W%,"Rectangle","Outline") +26030 FOR I%=0 TO 4 +26040 ID%=FN_GetID +26050 X%=RND(30)+10:Y%=RND(30)+5 +26060 W%=RND(20)+10:H%=RND(10)+5 +26070 VDU OTF%;40,ID%;GRP%;FDFLT%;X%;Y%;W%;H%;FN_Color +26080 VDU OTF%;4,ID%; +26090 NEXT I% +26998 =GRP% +26999 REM ----------- +27000 DEF FN_SolidRectangle(R%,C%,W%) +27010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +27020 PROC_Title2(R%,C%,W%,"Solid","Rectangle") +27030 FOR I%=0 TO 4 +27040 ID%=FN_GetID +27050 X%=RND(30)+10:Y%=RND(30)+5 +27060 W%=RND(20)+10:H%=RND(10)+5 +27070 VDU OTF%;41,ID%;GRP%;FDFLT%;X%;Y%;W%;H%;FN_Color +27080 VDU OTF%;4,ID%; +27090 NEXT I% +27998 =GRP% +27999 REM ----------- +28000 DEF FN_CircleOutline(R%,C%,W%) +28010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +28020 PROC_Title2(R%,C%,W%,"Circle","Outline") +28998 =GRP% +28999 REM ----------- +29000 DEF FN_SolidCircle(R%,C%,W%) +29010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +29020 PROC_Title2(R%,C%,W%,"Solid","Circle") +29998 =GRP% +29999 REM ----------- +30000 DEF FN_EllipseOutline(R%,C%,W%) +30010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +30020 PROC_Title2(R%,C%,W%,"Ellipse","Outline") +30998 =GRP% +30999 REM ----------- +31000 DEF FN_SolidEllipse(R%,C%,W%) +31010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +31020 PROC_Title2(R%,C%,W%,"Solid","Ellipse") +31998 =GRP% +31999 REM ----------- +32000 DEF FN_TerminalSmallFont(R%,C%,W%) +32010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +32020 PROC_Title(R%,C%,W%,"Terminal Small Font") +32998 =GRP% +32999 REM ----------- +33000 DEF FN_SolidBitmap(R%,C%,W%) +33010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +33020 PROC_Title2(R%,C%,W%,"Solid","Bitmap") +33030 ID%=FN_GetID +33040 VDU OTF%;120,ID%;GRP%;FDFLT%+FSAME%;64;50; +33050 infile=OPENIN "BITMAP_64X50_SOLID.BIN" +33060 IF infile=0 THEN END +33080 VDU OTF%;132,ID%;0;0;3200; +33090 REPEAT +33100 temp%=BGET#infile +33110 VDU temp%+&C0 +33120 UNTIL EOF#infile +33130 CLOSE#infile +33140 VDU OTF%;1,ID%;8;10; +33150 VDU OTF%;4,ID%; +33998 =GRP% +33999 REM ----------- +34000 DEF FN_MaskedBitmap(R%,C%,W%) +34010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +34020 PROC_Title2(R%,C%,W%,"Masked","Bitmap") +34030 ID%=FN_GetID +34040 VDU OTF%;121,ID%;GRP%;FDFLT%;64;50;&C0 +34050 infile=OPENIN "BITMAP_64X50_MASKED.BIN" +34060 IF infile=0 THEN END +34080 VDU OTF%;133,ID%;0;0;3200; +34090 REPEAT +34100 temp%=BGET#infile +34110 VDU temp%+&C0 +34120 UNTIL EOF#infile +34130 CLOSE#infile +34140 VDU OTF%;1,ID%;8;10; +34150 VDU OTF%;4,ID%; +34998 =GRP% +34999 REM ----------- +35000 DEF FN_BitmapFrames(R%,C%,W%) +35010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +35020 PROC_Title2(R%,C%,W%,"Bitmap","Frames") +35030 ID%=FN_GetID +35040 VDU OTF%;120,ID%;GRP%;FDFLT%+FSAME%;64;250; +35050 infile=OPENIN "BITMAP_64X250_SOLID.BIN" +35060 IF infile=0 THEN END +35080 VDU OTF%;132,ID%;0;0;16000; +35090 REPEAT +35100 temp%=BGET#infile +35110 VDU temp%+&C0 +35120 UNTIL EOF#infile +35130 CLOSE#infile +35140 VDU OTF%;123,ID%;8;10;0;50; +35150 VDU OTF%;4,ID%; +35998 =GRP% +35999 REM ----------- +36000 DEF FN_BitmapScroll(R%,C%,W%) +36010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +36020 PROC_Title2(R%,C%,W%,"Bitmap","Scroll") +36030 ID%=FN_GetID +36040 VDU OTF%;120,ID%;GRP%;FDFLT%+FSAME%;64;250; +36050 infile=OPENIN "BITMAP_64X250_SOLID.BIN" +36060 IF infile=0 THEN END +36080 VDU OTF%;132,ID%;0;0;16000; +36090 REPEAT +36100 temp%=BGET#infile +36110 VDU temp%+&C0 +36120 UNTIL EOF#infile +36130 CLOSE#infile +36140 VDU OTF%;123,ID%;8;10;0;50; +36150 VDU OTF%;4,ID%; +36998 =GRP% +36999 REM ----------- +37000 DEF FN_GroupMove(R%,C%,W%) +37010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +37020 PROC_Title2(R%,C%,W%,"Group","Move") +37998 =GRP% +37999 REM ----------- +38000 DEF FN_TerminalBigFont(R%,C%,W%) +38010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +38020 PROC_Title(R%,C%,W%,"Terminal Large Font") +38998 =GRP% +38999 REM ----------- +39000 DEF FN_TransparentBitmaps(R%,C%,W%) +39010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +39020 PROC_Title(R%,C%,W%,"Transparent Bitmaps") +39998 =GRP% +39999 REM ----------- +40000 DEF FN_Solid3DRender(R%,C%,W%) +40010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +40020 PROC_Title(R%,C%,W%,"Solid 3D Render") +40998 =GRP% +40999 REM ----------- +41000 DEF FN_Masked3DRender(R%,C%,W%) +41010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +41020 PROC_Title(R%,C%,W%,"Masked 3D Render") +41998 =GRP% +41999 REM ----------- +42000 DEF FN_Transparent3DRender(R%,C%,W%) +42010 GRP%=FN_GetID: PROC_SetArea(GRP%,R%,C%,W%) +42020 PROC_Title2(R%,C%,W%,"Transparent","3D Render") +42998 =GRP% +42999 REM ----------- diff --git a/video/src/samples/scroldemo.bas b/video/src/samples/scroldemo.bas new file mode 100644 index 00000000..a3728153 --- /dev/null +++ b/video/src/samples/scroldemo.bas @@ -0,0 +1,55 @@ +10 REM This demo shows horizontal scrolling of a tile array. +20 MODE 32: REM 800x600x64 without text area +30 REM MODE 64: REM 800x600x64 with text area +105 T=TIME +106 IF TIME-T<100 THEN GOTO 106 +100 FDFLT%=&000F: FHIDE%=&000E: FGRP%=&000E: FSAME%=&0200: FSCROLL1%=&0010: OTF%=&1E17 +102 FLEFT%=&0400: FRIGHT%=&0800 +110 columns%=15: rows%=12 +115 bmpWidth%=64: bmpHeight%=50: bmpSize%=bmpWidth%*bmpHeight% +116 rootID%=0: bmpID%=11: chunkLimit%=128: tileArrayID%=10 +120 DIM A% bmpSize% +160 DIM code% 32 +200 REM Create tile array +210 VDU OTF%; 80, tileArrayID%; rootID%; FHIDE%+FSCROLL1%+FLEFT%+FRIGHT%; columns%; rows%; bmpWidth%; bmpHeight%; 800; 600; +220 PROC_LoadBmp("BITMAP_64X50_SOLID.BIN", A%, bmpSize%) +230 VDU OTF%;4,tileArrayID%; +240 FOR r%=0 TO rows%-1 +250 FOR c%=0 TO columns%-1 +260 VDU OTF%; 84, tileArrayID%; c%; r%; bmpID%; +265 REM PRINT "(";r%;",";c%;")"; +270 NEXT c% +280 NEXT r% +300 VDU OTF%; 0, tileArrayID%; FDFLT%; +450 GOTO 450 + +10100 DEF PROC_LoadBmp(filename$, address%, totalBytes%) +10102 T=TIME +10104 IF TIME-T<25 THEN GOTO 10104 +10110 cmd$="load "+filename$+" "+STR$(address%) +10120 REM PRINT cmd$;" (";~totalBytes%;" bytes as bitmap ID ";bmpID%;")" +10130 OSCLI cmd$ +10140 VDU OTF%; 81, tileArrayID%; bmpID%; 0 +10142 bytes%=totalBytes%: count%=0: M%=address% +10144 IF bytes%<=0 THEN GOTO 10160 +10146 IF bytes%>chunkLimit% THEN N%=chunkLimit% ELSE N%=bytes% +10147 PROC_AsmSendChunk: *FX 19 +10148 VDU OTF%; 88, tileArrayID%; bmpID%; count%; 0; N%; +10150 CALL code% +10151 T=TIME +10152 IF TIME-T<10 THEN GOTO 10152 +10153 REM PRINT " copied ";~N%;" from ";~M%;" to ";~count%;" of ";~totalBytes% +10154 bytes%=bytes%-N%: count%=count%+N%: M%=M%+N% +10155 GOTO 10144 +10160 REM PRINT: PRINT "=== ";filename$;" sent ===" +10180 ENDPROC + +10200 DEF PROC_AsmSendChunk +10210 P%=code% +10220 [OPT 2 +10230 LD HL,M% +10240 LD BC,N% +10250 RST.LIL &18 +10260 RET +10270 ] +10280 ENDPROC diff --git a/video/src/samples/slideshow/SLIDE01_320X240.BIN b/video/src/samples/slideshow/SLIDE01_320X240.BIN new file mode 100644 index 00000000..3f30f1a7 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE01_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE01_640X480.BIN b/video/src/samples/slideshow/SLIDE01_640X480.BIN new file mode 100644 index 00000000..4b67f69c Binary files /dev/null and b/video/src/samples/slideshow/SLIDE01_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE02_320X240.BIN b/video/src/samples/slideshow/SLIDE02_320X240.BIN new file mode 100644 index 00000000..9632f33e Binary files /dev/null and b/video/src/samples/slideshow/SLIDE02_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE02_640X480.BIN b/video/src/samples/slideshow/SLIDE02_640X480.BIN new file mode 100644 index 00000000..f9b75966 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE02_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE03_320X240.BIN b/video/src/samples/slideshow/SLIDE03_320X240.BIN new file mode 100644 index 00000000..9632f33e Binary files /dev/null and b/video/src/samples/slideshow/SLIDE03_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE03_640X480.BIN b/video/src/samples/slideshow/SLIDE03_640X480.BIN new file mode 100644 index 00000000..f9b75966 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE03_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE04_320X240.BIN b/video/src/samples/slideshow/SLIDE04_320X240.BIN new file mode 100644 index 00000000..2174beda Binary files /dev/null and b/video/src/samples/slideshow/SLIDE04_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE04_640X480.BIN b/video/src/samples/slideshow/SLIDE04_640X480.BIN new file mode 100644 index 00000000..9f18773e Binary files /dev/null and b/video/src/samples/slideshow/SLIDE04_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE05_320X240.BIN b/video/src/samples/slideshow/SLIDE05_320X240.BIN new file mode 100644 index 00000000..67d80bbd Binary files /dev/null and b/video/src/samples/slideshow/SLIDE05_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE05_640X480.BIN b/video/src/samples/slideshow/SLIDE05_640X480.BIN new file mode 100644 index 00000000..e384889d Binary files /dev/null and b/video/src/samples/slideshow/SLIDE05_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE06_320X240.BIN b/video/src/samples/slideshow/SLIDE06_320X240.BIN new file mode 100644 index 00000000..f1ebded5 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE06_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE06_640X480.BIN b/video/src/samples/slideshow/SLIDE06_640X480.BIN new file mode 100644 index 00000000..8a590237 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE06_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE07_320X240.BIN b/video/src/samples/slideshow/SLIDE07_320X240.BIN new file mode 100644 index 00000000..b32ab587 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE07_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE07_640X480.BIN b/video/src/samples/slideshow/SLIDE07_640X480.BIN new file mode 100644 index 00000000..aee99b39 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE07_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE08_320X240.BIN b/video/src/samples/slideshow/SLIDE08_320X240.BIN new file mode 100644 index 00000000..51ec8915 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE08_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE08_640X480.BIN b/video/src/samples/slideshow/SLIDE08_640X480.BIN new file mode 100644 index 00000000..38e4e0fc Binary files /dev/null and b/video/src/samples/slideshow/SLIDE08_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE09_320X240.BIN b/video/src/samples/slideshow/SLIDE09_320X240.BIN new file mode 100644 index 00000000..7b0906d6 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE09_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE09_640X480.BIN b/video/src/samples/slideshow/SLIDE09_640X480.BIN new file mode 100644 index 00000000..2e348e43 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE09_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE10_320X240.BIN b/video/src/samples/slideshow/SLIDE10_320X240.BIN new file mode 100644 index 00000000..fcd09514 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE10_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE10_640X480.BIN b/video/src/samples/slideshow/SLIDE10_640X480.BIN new file mode 100644 index 00000000..33f09fe2 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE10_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE11_320X240.BIN b/video/src/samples/slideshow/SLIDE11_320X240.BIN new file mode 100644 index 00000000..d6f69343 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE11_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE11_640X480.BIN b/video/src/samples/slideshow/SLIDE11_640X480.BIN new file mode 100644 index 00000000..1786e8b0 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE11_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE12_320X240.BIN b/video/src/samples/slideshow/SLIDE12_320X240.BIN new file mode 100644 index 00000000..a6bfc53d Binary files /dev/null and b/video/src/samples/slideshow/SLIDE12_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE12_640X480.BIN b/video/src/samples/slideshow/SLIDE12_640X480.BIN new file mode 100644 index 00000000..6374046a Binary files /dev/null and b/video/src/samples/slideshow/SLIDE12_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE13_320X240.BIN b/video/src/samples/slideshow/SLIDE13_320X240.BIN new file mode 100644 index 00000000..a9424c9f Binary files /dev/null and b/video/src/samples/slideshow/SLIDE13_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE13_640X480.BIN b/video/src/samples/slideshow/SLIDE13_640X480.BIN new file mode 100644 index 00000000..98fa4456 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE13_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE14_320X240.BIN b/video/src/samples/slideshow/SLIDE14_320X240.BIN new file mode 100644 index 00000000..20a523f7 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE14_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE14_640X480.BIN b/video/src/samples/slideshow/SLIDE14_640X480.BIN new file mode 100644 index 00000000..36155604 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE14_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE15_320X240.BIN b/video/src/samples/slideshow/SLIDE15_320X240.BIN new file mode 100644 index 00000000..dd246431 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE15_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE15_640X480.BIN b/video/src/samples/slideshow/SLIDE15_640X480.BIN new file mode 100644 index 00000000..5e3e7480 Binary files /dev/null and b/video/src/samples/slideshow/SLIDE15_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE16_320X240.BIN b/video/src/samples/slideshow/SLIDE16_320X240.BIN new file mode 100644 index 00000000..18f5b5dc Binary files /dev/null and b/video/src/samples/slideshow/SLIDE16_320X240.BIN differ diff --git a/video/src/samples/slideshow/SLIDE16_640X480.BIN b/video/src/samples/slideshow/SLIDE16_640X480.BIN new file mode 100644 index 00000000..2960c78b Binary files /dev/null and b/video/src/samples/slideshow/SLIDE16_640X480.BIN differ diff --git a/video/src/samples/slideshow/SLIDE320.BAS b/video/src/samples/slideshow/SLIDE320.BAS new file mode 100644 index 00000000..6bd4f5db --- /dev/null +++ b/video/src/samples/slideshow/SLIDE320.BAS @@ -0,0 +1,49 @@ +10 REM OTF Slideshow Demo +20 REM This demo shows various images using On-the-Fly mode. +30 MODE &47: REM OTF 320x240x64, with 40x30 Text Area +40 CLS: VDU 23,1,0;0;0;0; +50 FDFLT%=&000F: FHIDE%=&000E +60 OTF%=&1E17 +70 REM -- Load bitmaps +76 FOR ID%=101 TO 116 +80 READ filename$ +82 PRINT "Loading ";filename$ +84 VDU OTF%;120,ID%;0;FHIDE%;320;240;1: REM Use PSRAM +90 infile=OPENIN filename$ +100 IF infile=0 THEN END +110 FOR Y%=0 TO 239 +120 VDU OTF%;132,ID%;0;Y%;320; +130 FOR X%=0 TO 319 +140 temp%=BGET#infile +150 VDU temp%+&C0 +160 NEXT X% +170 NEXT Y% +180 CLOSE#infile +190 VDU OTF%;4,ID%; +200 NEXT ID% +202 VDU OTF%;3,1;: REM Delete text area +205 REM -- Cycle through loaded bitmaps +210 FOR ID%=101 TO 116 +211 VDU OTF%;0,ID%;FDFLT%; +212 START=TIME +213 IF TIME-START<50 THEN GOTO 213 +214 VDU OTF%;0,ID%;FHIDE%; +227 NEXT ID% +228 GOTO 210 +299 REM -------- +301 DATA "SLIDE01_320x240.BIN" +302 DATA "SLIDE02_320x240.BIN" +303 DATA "SLIDE03_320x240.BIN" +304 DATA "SLIDE04_320x240.BIN" +305 DATA "SLIDE05_320x240.BIN" +306 DATA "SLIDE06_320x240.BIN" +307 DATA "SLIDE07_320x240.BIN" +308 DATA "SLIDE08_320x240.BIN" +309 DATA "SLIDE09_320x240.BIN" +310 DATA "SLIDE10_320x240.BIN" +311 DATA "SLIDE11_320x240.BIN" +312 DATA "SLIDE12_320x240.BIN" +313 DATA "SLIDE13_320x240.BIN" +314 DATA "SLIDE14_320x240.BIN" +315 DATA "SLIDE15_320x240.BIN" +316 DATA "SLIDE16_320x240.BIN" diff --git a/video/src/samples/slideshow/SLIDE640.BAS b/video/src/samples/slideshow/SLIDE640.BAS new file mode 100644 index 00000000..f59dc89b --- /dev/null +++ b/video/src/samples/slideshow/SLIDE640.BAS @@ -0,0 +1,55 @@ +10 REM OTF Slideshow Demo +20 REM This demo shows various images using On-the-Fly mode. +30 MODE &44: REM OTF 640x480x64, with 80x60 Text Area +40 CLS: VDU 23,1,0;0;0;0; +50 FDFLT%=&000F: FHIDE%=&000E +60 OTF%=&1E17 +70 REM -- Load bitmaps +76 FOR ID%=100 TO 115 +78 usePSRAM%=(ID% AND 1) +80 READ filename$ +82 PRINT "Loading ";filename$ +84 VDU OTF%;120,ID%;0;FHIDE%;320;240;usePSRAM% +90 infile=OPENIN filename$ +100 IF infile=0 THEN END +110 FOR Y%=0 TO 239 +120 VDU OTF%;132,ID%;0;Y%;320; +130 FOR X%=0 TO 319 +140 temp%=BGET#infile +150 VDU temp%+&C0 +160 NEXT X% +170 NEXT Y% +180 CLOSE#infile +182 X%=usePSRAM%*320 +184 Y%=(ID% AND 2)*120 +186 VDU OTF%;1,ID%;X%;Y%; +190 VDU OTF%;4,ID%; +200 NEXT ID% +202 VDU OTF%;3,1;: REM Delete text area +205 REM -- Cycle through loaded bitmaps +207 CUR%=4: PRIOR%=0 +208 *FX 19 +209 VDU OTF%;0,PRIOR%+100;FHIDE%; +211 VDU OTF%;0,CUR%+100;FDFLT%; +213 START=TIME +215 IF TIME-START<25 THEN GOTO 215 +217 CUR%=((CUR%+1) AND 15) +219 PRIOR%=((PRIOR%+1) AND 15) +220 GOTO 208 +299 REM -------- +301 DATA "SLIDE01_320x240.BIN" +302 DATA "SLIDE02_320x240.BIN" +303 DATA "SLIDE03_320x240.BIN" +304 DATA "SLIDE04_320x240.BIN" +305 DATA "SLIDE05_320x240.BIN" +306 DATA "SLIDE06_320x240.BIN" +307 DATA "SLIDE07_320x240.BIN" +308 DATA "SLIDE08_320x240.BIN" +309 DATA "SLIDE09_320x240.BIN" +310 DATA "SLIDE10_320x240.BIN" +311 DATA "SLIDE11_320x240.BIN" +312 DATA "SLIDE12_320x240.BIN" +313 DATA "SLIDE13_320x240.BIN" +314 DATA "SLIDE14_320x240.BIN" +315 DATA "SLIDE15_320x240.BIN" +316 DATA "SLIDE16_320x240.BIN" diff --git a/video/src/samples/slideshow/SPLIT640.BAS b/video/src/samples/slideshow/SPLIT640.BAS new file mode 100644 index 00000000..61b60262 --- /dev/null +++ b/video/src/samples/slideshow/SPLIT640.BAS @@ -0,0 +1,47 @@ +10 REM OTF Split Image Demo +20 REM This demo shows an image split between internal and external RAM, using On-the-Fly mode. +30 MODE &44: REM OTF 640x480x64, with 80x60 Text Area +40 CLS: VDU 23,1,0;0;0;0; +50 FDFLT%=&000F +60 OTF%=&1E17 +62 width%=640/4: height%=480/4 +70 REM -- Load bitmaps +80 FOR ID%=100 TO 115 +85 IF (ID% AND 3)=0 THEN usePSRAM%=0 ELSE usePSRAM%=0 +90 VDU OTF%;120,ID%;0;FDFLT%;width%;height%;usePSRAM% +100 NEXT ID% +110 READ filename$ +120 PRINT "Loading ";filename$ +130 infile=OPENIN filename$ +140 IF infile=0 THEN END +150 FOR trow%=0 TO 3 +160 FOR line%=0 TO height%-1 +170 FOR tcol%=0 TO 3 +180 ID%=trow%*4+tcol%+100 +185 PRINT "R:";trow%;" L:";line%;" C:";tcol%;" ID:";ID% +190 VDU OTF%;132,ID%;0;line%;width%; +200 FOR X%=0 TO width%-1 +210 temp%=BGET#infile +220 VDU temp%+&C0 +230 NEXT X% +235 NEXT tcol% +240 NEXT line% +245 NEXT trow% +250 CLOSE#infile + +260 FOR trow%=0 TO 3 +270 Y%=trow%*height% +280 FOR tcol%=0 TO 3 +290 ID%=trow%*4+tcol%+100 +292 X%=tcol%*width% +294 PRINT "R:";trow%;" Y:";Y%;" C:";tcol%;" X:";X% +300 VDU OTF%;1,ID%;X%;Y%; +310 VDU OTF%;4,ID%; +320 NEXT tcol% +330 NEXT trow% +335 T=TIME +336 IF TIME-T<500 THEN GOTO 335 +340 VDU OTF%;3,1;: REM Delete text area +350 GOTO 350 +299 REM -------- +302 DATA "SLIDE01_640x480.BIN" diff --git a/video/updater.h b/video/updater.h index 0849ca3a..afa3a3ef 100644 --- a/video/updater.h +++ b/video/updater.h @@ -4,9 +4,11 @@ #include "vdu_stream_processor.h" #include #include "esp_ota_ops.h" +#include "bdpp/bdp_stream.h" extern void printFmt(const char *format, ...); extern void print(const char * text); +extern void bdpp_initialize_driver(); namespace Updater { static constexpr uint8_t unlockCode[] = "unlock"; diff --git a/video/vdp_protocol.h b/video/vdp_protocol.h index 4ae072bf..f0cb88b0 100644 --- a/video/vdp_protocol.h +++ b/video/vdp_protocol.h @@ -16,6 +16,8 @@ #define VDPSerial Serial2 +extern Stream * default_stream; // Default VDU Stream + void setupVDPProtocol() { VDPSerial.end(); VDPSerial.setRxBufferSize(UART_RX_SIZE); // Can't be called when running @@ -28,17 +30,20 @@ void setupVDPProtocol() { // TODO remove the following - it's only here for cursor.h to send escape key when doing paged mode handling inline void writeByte(uint8_t b) { - VDPSerial.write(b); + default_stream->write(b); } // Send a packet of data to the MOS // void send_packet(uint8_t code, uint16_t len, uint8_t data[]) { + debug_log("@%i\n",__LINE__); writeByte(code + 0x80); writeByte(len); for (int i = 0; i < len; i++) { writeByte(data[i]); } + default_stream->flush(); + debug_log("@%i\n",__LINE__); } #endif // AGON_VDP_PROTOCOL_H diff --git a/video/vdu_buffered.h b/video/vdu_buffered.h index c941e4ad..30ee1fec 100644 --- a/video/vdu_buffered.h +++ b/video/vdu_buffered.h @@ -12,6 +12,11 @@ #include "multi_buffer_stream.h" #include "sprites.h" #include "types.h" +#include "bdpp/bdp_stream.h" +#include "esp_heap_caps.h" +#include "compression.h" + +#define COMPRESSION_OUTPUT_CHUNK_SIZE 1024 // used to extend temporary buffer // VDU 23, 0, &A0, bufferId; command: Buffered command support // @@ -175,6 +180,16 @@ void VDUStreamProcessor::vdu_sys_buffered() { } bufferCopyAndConsolidate(bufferId, sourceBufferIds); } break; + case BUFFERED_GET_DATA_BYTES: { + bufferGetDataBytes(bufferId); + case BUFFERED_COMPRESS: { + auto sourceBufferId = readWord_t(); + bufferCompress(bufferId, sourceBufferId); + } break; + case BUFFERED_DECOMPRESS: { + auto sourceBufferId = readWord_t(); + bufferDecompress(bufferId, sourceBufferId); + } break; case BUFFERED_DEBUG_INFO: { debug_log("vdu_sys_buffered: buffer %d, %d streams stored\n\r", bufferId, buffers[bufferId].size()); if (buffers[bufferId].size() == 0) { @@ -1060,4 +1075,277 @@ void VDUStreamProcessor::bufferCopyAndConsolidate(uint16_t bufferId, std::vector debug_log("bufferCopyAndConsolidate: copied %d bytes into buffer %d\n\r", length, bufferId); } +// VDU 23, 0, &A0, bufferId; &1B, packetIndex, offsetLo; offsetHi; n; : Get data bytes from buffer and return BDPP packet(s) +// Copy data bytes starting at the provided 32-bit offset within the given buffer. +// If the requested number of bytes ("n") is greater than the maximum BDPP packet size (256 bytes), +// this command will return multiple packets, up to the limit of 16 packets (the maximum number of +// app-owned packets allowed by BDPP MOS). Thus, n must range from 1 to 4096. If multiple packets +// are returned, their successive packet indexes will start at the given packetIndex, and increment +// for each packet returned, modulo 16 (i.e., after packet #15 is returned, the next is packet #0). +// +void VDUStreamProcessor::bufferGetDataBytes(uint16_t bufferId) { + if (buffers.find(bufferId) == buffers.end()) { + debug_log("bufferGetDataBytes: buffer %d not found\n\r", bufferId); + return; + } + + auto pkt_idx = readByte_t(); + if (pkt_idx >= BDPP_MAX_APP_PACKETS) { + debug_log("bufferGetDataBytes: packet index %d is invalid\n\r", pkt_idx); + return; + } + + auto off_lo = readWord_t(); + auto off_hi = readWord_t(); + auto offset = (((uint32_t)off_hi) << 16) | ((uint32_t)off_lo); + auto n = readWord_t(); + + if (n == 0 || n > BDPP_MAX_APP_PACKETS*BDPP_MAX_PACKET_DATA_SIZE) { + debug_log("bufferGetDataBytes: byte count of %d is invalid\n\r", n); + return; + } + + auto buffer_stream = buffers[bufferId][0].get(); + auto bs_size = buffer_stream->available(); + buffer_stream->seekTo(offset); + if (n > bs_size) { + debug_log("bufferGetDataBytes: size %d is larger than remaining size %d\n\r", n, bs_size); + return; + } + + uint32_t pkt_size = 0; + uint32_t pkt_offset = 0; + auto grab_remainder = (uint32_t)n; + auto bdpp_stream = (BdppStream*) ((Stream*) outputStream.get()); + bool any_output = false; + + auto bs_remainder = (uint32_t) bs_size; + while (bs_remainder && grab_remainder) { + auto pkt_remainder = BDPP_MAX_PACKET_DATA_SIZE - pkt_offset; + auto count = min(bs_remainder, pkt_remainder); + count = min(count, grab_remainder); + + if (!any_output) { + bdpp_stream->start_app_response_packet(pkt_idx); + any_output = true; + } + + for (auto i = 0; i < count; i++) { + writeByte(buffer_stream->read()); + } + + bs_remainder -= count; + grab_remainder -= count; + pkt_size += count; + if (pkt_size >= BDPP_MAX_PACKET_DATA_SIZE) { + // The stream has now flushed a full packet, and is ready to + // create a new one with the next packet index, if required. + pkt_size = 0; + } + } + + // Make sure the last packet goes out. + if (pkt_size) { + bdpp_stream->flush(); + } +} +// Write compressed output to a temporary buffer +// +static void local_write_compressed_byte(void* p_cd, uint8_t comp_byte) { + CompressionData* cd = (CompressionData*) p_cd; + uint8_t** pp_temp = (uint8_t**) cd->context; + uint8_t* p_temp = *pp_temp; + p_temp[cd->output_count++] = comp_byte; + if (!(cd->output_count & (COMPRESSION_OUTPUT_CHUNK_SIZE-1))) { + // extend the temporary buffer to make room for more output + auto new_size = cd->output_count + COMPRESSION_OUTPUT_CHUNK_SIZE; + uint8_t* p_temp2 = (uint8_t*) ps_malloc(new_size); + if (p_temp2) { + memcpy(p_temp2, p_temp, cd->output_count); + *pp_temp = p_temp2; // use new buffer pointer now + } else { + debug_log("bufferCompress: cannot allocate temporary buffer of %d bytes\n\r", new_size); + *pp_temp = NULL; // indicate failure + } + heap_caps_free(p_temp); + } +} + +// Write decompressed output to a temporary buffer +// +static void local_write_decompressed_byte(void* p_dd, uint8_t orig_data) { + DecompressionData* dd = (DecompressionData*) p_dd; + uint8_t** pp_temp = (uint8_t**) dd->context; + uint8_t* p_temp = *pp_temp; + p_temp[dd->output_count++] = orig_data; + if (!(dd->output_count & (COMPRESSION_OUTPUT_CHUNK_SIZE-1))) { + // extend the temporary buffer to make room for more output + auto new_size = dd->output_count + COMPRESSION_OUTPUT_CHUNK_SIZE; + uint8_t* p_temp2 = (uint8_t*) ps_malloc(new_size); + if (p_temp2) { + memcpy(p_temp2, p_temp, dd->output_count); + *pp_temp = p_temp2; // use new buffer pointer now + } else { + debug_log("bufferDecompress: cannot allocate temporary buffer of %d bytes\n\r", new_size); + *pp_temp = NULL; // indicate failure + } + heap_caps_free(p_temp); + } +} + +// VDU 23, 0, &A0, bufferId; &1C, sourceBufferId; sourceBufferId; ...; 65535; : Compress blocks from buffers +// Compress (blocks from) a list of buffers into a new buffer. +// List is terminated with a bufferId of 65535 (-1). +// Replaces the target buffer with the new one. +// If target buffer is included in the source list it will be skipped. +// +void VDUStreamProcessor::bufferCompress(uint16_t bufferId, uint16_t sourceBufferId) { + buffers[bufferId].clear(); + debug_log("Compressing into buffer %u\n\r", bufferId); + + // create a temporary output buffer, which may be expanded during compression + uint8_t* p_temp = (uint8_t*) ps_malloc(COMPRESSION_OUTPUT_CHUNK_SIZE); + if (p_temp) { + // prepare for doing compression + CompressionData cd; + agon_init_compression(&cd, &p_temp, &local_write_compressed_byte); + + // Output the compression header + CompressionFileHeader hdr; + hdr.marker[0] = 'C'; + hdr.marker[1] = 'm'; + hdr.marker[2] = 'p'; + hdr.type = COMPRESSION_TYPE_TURBO; + hdr.orig_size = 0; + + auto p_hdr_bytes = hdr.marker; + for (int i = 0; i < sizeof(hdr); i++) { + local_write_compressed_byte(&cd, *p_hdr_bytes++); + } + + // loop thru blocks stored against the source buffer ID + uint32_t orig_size = 0; + for (const auto &block : buffers[sourceBufferId]) { + // compress the block into our temporary buffer + auto bufferLength = block->size(); + auto p_data = block->getBuffer(); + orig_size += bufferLength; + debug_log(" from buffer %u [%08X] %u bytes\n\r", sourceBufferId, p_data, bufferLength); + debug_log(" %02hX %02hX %02hX %02hX\n\r", + p_data[0], p_data[1], p_data[2], p_data[3]); + cd.input_count += bufferLength; + while (bufferLength--) { + agon_compress_byte(&cd, *p_data++); + } + } + agon_finish_compression(&cd); + + // make a single buffer with all of the temporary output data + auto bufferStream = make_shared_psram(cd.output_count); + if (!bufferStream || !bufferStream->getBuffer()) { + // buffer couldn't be created + debug_log("bufferCompress: failed to create buffer %d\n\r", bufferId); + return; + } + + auto p_hdr = (CompressionFileHeader*) p_temp; + p_hdr->orig_size = orig_size; + + auto destination = bufferStream->getBuffer(); + debug_log(" %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX\n\r", + p_temp[0], p_temp[1], p_temp[2], p_temp[3], + p_temp[4], p_temp[5], p_temp[6], p_temp[7], + p_temp[8], p_temp[9], p_temp[10], p_temp[11]); + memcpy(destination, p_temp, cd.output_count); + heap_caps_free(p_temp); + buffers[bufferId].push_back(bufferStream); + + uint32_t pct = (cd.output_count * 100) / cd.input_count; + debug_log("Compressed %u input bytes to %u output bytes (%u%%) at %08X\n\r", + cd.input_count, cd.output_count, pct, destination); + } else { + debug_log("bufferCompress: cannot allocate temporary buffer of %d bytes\n\r", COMPRESSION_OUTPUT_CHUNK_SIZE); + } +} + +// VDU 23, 0, &A0, bufferId; &1D, sourceBufferId; sourceBufferId; ...; 65535; : Decompress blocks from buffers +// Decompress (blocks from) a list of buffers into a new buffer. +// List is terminated with a bufferId of 65535 (-1). +// Replaces the target buffer with the new one. +// If target buffer is included in the source list it will be skipped. +// +void VDUStreamProcessor::bufferDecompress(uint16_t bufferId, uint16_t sourceBufferId) { + // Validate the compression header + if (buffers[sourceBufferId][0]->size() < sizeof(CompressionFileHeader)) { + debug_log("bufferDecompress: buffer too small for header\n\r"); + return; + } + + auto p_hdr = (const CompressionFileHeader*) buffers[sourceBufferId][0]->getBuffer(); + if (p_hdr->marker[0] != 'C' || + p_hdr->marker[1] != 'm' || + p_hdr->marker[2] != 'p' || + p_hdr->type != COMPRESSION_TYPE_TURBO) { + debug_log("bufferDecompress: header is invalid\n\r"); + return; + } + auto orig_size = p_hdr->orig_size; + + buffers[bufferId].clear(); + debug_log("Decompressing into buffer %u\n\r", bufferId); + + // create a temporary output buffer, which may be expanded during decompression + uint8_t* p_temp = (uint8_t*) ps_malloc(COMPRESSION_OUTPUT_CHUNK_SIZE); + if (p_temp) { + // prepare for doing compression + DecompressionData dd; + agon_init_decompression(&dd, &p_temp, &local_write_decompressed_byte); + + // loop thru blocks stored against the source buffer ID + uint32_t skip_hdr = sizeof(CompressionFileHeader); + dd.input_count = skip_hdr; + for (const auto &block : buffers[sourceBufferId]) { + // decompress the block into our temporary buffer + auto bufferLength = block->size() - skip_hdr; + auto p_data = block->getBuffer(); + debug_log(" from buffer %u [%08X] %u bytes\n\r", sourceBufferId, p_data, bufferLength); + debug_log(" %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX %02hX\n\r", + p_data[0], p_data[1], p_data[2], p_data[3], + p_data[4], p_data[5], p_data[6], p_data[7], + p_data[8], p_data[9], p_data[10], p_data[11]); + p_data += skip_hdr; + skip_hdr = 0; + dd.input_count += bufferLength; + while (bufferLength--) { + agon_decompress_byte(&dd, *p_data++); + } + } + + // make a single buffer with all of the temporary output data + auto bufferStream = make_shared_psram(dd.output_count); + if (!bufferStream || !bufferStream->getBuffer()) { + // buffer couldn't be created + debug_log("bufferDecompress: failed to create buffer %d\n\r", bufferId); + return; + } + auto destination = bufferStream->getBuffer(); + debug_log(" %02hX %02hX %02hX %02hX\n\r", + p_temp[0], p_temp[1], p_temp[2], p_temp[3]); + memcpy(destination, p_temp, dd.output_count); + heap_caps_free(p_temp); + buffers[bufferId].push_back(bufferStream); + + uint32_t pct = (dd.output_count * 100) / dd.input_count; + debug_log("Decompressed %u input bytes to %u output bytes (%u%%) at %08X\n\r", + dd.input_count, dd.output_count, pct, destination); + + if (dd.output_count != orig_size) { + debug_log("Decompressed buffer size %u does not equal original size %u\r\n", + dd.output_count, orig_size); + } + } else { + debug_log("bufferDecompress: cannot allocate temporary buffer of %d bytes\n\r", COMPRESSION_OUTPUT_CHUNK_SIZE); + } +} + #endif // VDU_BUFFERED_H diff --git a/video/vdu_stream_processor.h b/video/vdu_stream_processor.h index eb7bc9d9..d4fabfa8 100644 --- a/video/vdu_stream_processor.h +++ b/video/vdu_stream_processor.h @@ -50,12 +50,13 @@ class VDUStreamProcessor { void sendColour(uint8_t colour); void sendTime(); void vdu_sys_video_time(); - void sendKeyboardState(); void vdu_sys_keystate(); void vdu_sys_mouse(); void vdu_sys_scroll(); void vdu_sys_cursorBehaviour(); void vdu_sys_udg(char c); + void vdu_sys_bdpp(); + void vdu_sys_otf(); void vdu_sys_audio(); void sendAudioStatus(uint8_t channel, uint8_t status); @@ -99,12 +100,17 @@ class VDUStreamProcessor { void bufferReverse(uint16_t bufferId, uint8_t options); void bufferCopyRef(uint16_t bufferId, std::vector sourceBufferIds); void bufferCopyAndConsolidate(uint16_t bufferId, std::vector sourceBufferIds); + void bufferGetDataBytes(uint16_t bufferId); + void bufferCompress(uint16_t bufferId, uint16_t sourceBufferId); + void bufferDecompress(uint16_t bufferId, uint16_t sourceBufferId); void vdu_sys_updater(); void unlock(); void receiveFirmware(); void switchFirmware(); + void bdppEcho(); + public: uint16_t id = 65535; @@ -127,6 +133,7 @@ class VDUStreamProcessor { void send_packet(uint8_t code, uint16_t len, uint8_t data[]); void sendMouseData(MouseDelta * delta); + void sendKeyboardState(); void processAllAvailable(); void processNext(); @@ -268,11 +275,17 @@ int16_t VDUStreamProcessor::peekByte_t(uint16_t timeout = COMMS_TIMEOUT) { // Send a packet of data to the MOS // void VDUStreamProcessor::send_packet(uint8_t code, uint16_t len, uint8_t data[]) { + //debug_log("Send Pkt @%i: ",__LINE__); + //debug_log(" %02hX", code + 0x80); + //debug_log(" %02hX", len); writeByte(code + 0x80); writeByte(len); for (int i = 0; i < len; i++) { writeByte(data[i]); + //debug_log(" %02hX", data[i]); } + //debug_log("\n"); + outputStream->flush(); } void VDUStreamProcessor::sendMouseData(MouseDelta * delta = nullptr) { diff --git a/video/vdu_sys.h b/video/vdu_sys.h index 2a8d90c6..452d9a76 100644 --- a/video/vdu_sys.h +++ b/video/vdu_sys.h @@ -14,6 +14,7 @@ #include "vdu_buffered.h" #include "vdu_sprites.h" #include "updater.h" +#include "version.h" extern void startTerminal(); // Start the terminal extern void setConsoleMode(bool mode); // Set console mode @@ -113,6 +114,9 @@ void VDUStreamProcessor::vdu_sys() { case 0x1C: { // VDU 23, 28 vdu_sys_hexload(); } break; + case 0x1E: { // VDU 23, 30, ... + vdu_sys_otf(); + } break; } } // @@ -241,6 +245,9 @@ void VDUStreamProcessor::vdu_sys_video() { case VDP_UPDATER: { // VDU 23, 0, &A1, command, vdu_sys_updater(); } break; + case VDP_BDPP: { // VDU 23, 0, &A2, command, + vdu_sys_bdpp(); + } break; case VDP_LOGICALCOORDS: { // VDU 23, 0, &C0, n auto b = readByte_t(); // Set logical coord mode if (b >= 0) { @@ -280,10 +287,25 @@ void VDUStreamProcessor::sendGeneralPoll() { debug_log("sendGeneralPoll: Timeout\n\r"); return; } - uint8_t packet[] = { - (uint8_t) (b & 0xFF), - }; + + // If the EZ80 supports BDPP, we respond with the upper bit set, + // and turn on ESP32 CTS usage (RTS is already on). + // + // If the EZ80 does not support BDPP, we respond with the old echo. + uint8_t response = (uint8_t)b; + if (b >= 0x04 && b <= 0x0F) { + response |= 0x80; // indicates that ESP32 supports BDPP + } + debug_log("sendGeneralPoll: response %02hX\n\r", response); + + uint8_t packet[] = { response }; send_packet(PACKET_GP, sizeof packet, packet); + + if (b >= 0x04 && b <= 0x0F) { + delay(10); // wait for the packet to go out + VDPSerial.setHwFlowCtrlMode(HW_FLOWCTRL_CTS_RTS, 64); + } + initialised = true; } @@ -659,4 +681,132 @@ void VDUStreamProcessor::vdu_sys_udg(char c) { redefineCharacter(c, buffer); } +// VDU 23, 0, &A2, command, +// +// VDU 23, 0, &A2, 0 - enable BDPP by initializing its driver +// VDU 23, 0, &A2, 1, pkt_idx, echo_data - echo a single byte back to the EZ80 +// VDU 23, 0, &A2, 2, pkt_idx, n, caps0; caps1; ... - get amount of free ESP32 RAM with given capabilties +// VDU 23, 0, &A2, 3, pkt_idx, addr_lo; addr_hi; n; - get ESP32 RAM contents as bytes (8 bits each) +// VDU 23, 0, &A2, 4, pkt_idx, addr_lo; addr_hi; n; - get ESP32 RAM contents as words (16 bits each) +// VDU 23, 0, &A2, 5, pkt_idx, addr_lo; addr_hi; n; - get ESP32 RAM contents as dwords (32 bits each) +// VDU 23, 0, &A2, 6, pkt_idx - get VDP version information +// +void VDUStreamProcessor::vdu_sys_bdpp() { + auto bdpp_stream = (BdppStream*) ((Stream*) outputStream.get()); + auto cmd = readByte_t(); + switch(cmd) { + // VDU 23, 0, &A2, 0 - enable BDPP by initializing its driver + case 0: { + bdpp_initialize_driver(); + } break; + + // VDU 23, 0, &A2, 1, pkt_idx, echo_data - echo a single byte back to the EZ80 + case 1: { + auto pkt_idx = readByte_t(); + bdpp_stream->start_app_response_packet(pkt_idx); + auto echo_data = readByte_t(); + writeByte(echo_data); + bdpp_stream->flush(); + } break; + + // VDU 23, 0, &A2, 2, pkt_idx, n, caps0; caps1; ... - get amount of free ESP32 RAM with given capabilties + case 2: { + auto pkt_idx = readByte_t(); + bdpp_stream->start_app_response_packet(pkt_idx); + auto n = readByte_t(); + while (n--) { + auto caps = readWord_t(); + auto size = heap_caps_get_free_size(caps); + auto data = (const uint8_t*) ∩︀ + for (int i = 0; i < sizeof(caps); i++) { + writeByte(data[i]); + } + } + bdpp_stream->flush(); + } break; + + // VDU 23, 0, &A2, 3, pkt_idx, addr_lo; addr_hi; size; - get ESP32 RAM contents as bytes (8 bits each) + case 3: { + auto pkt_idx = readByte_t(); + bdpp_stream->start_app_response_packet(pkt_idx); + auto addr_lo = readWord_t(); + auto addr_hi = readWord_t(); + auto n = readWord_t(); + if (n <= BDPP_MAX_PACKET_DATA_SIZE) { + auto bytes = (const uint8_t*)((((uint32_t)addr_hi) << 16) | ((uint32_t)addr_lo)); + while (n--) { + writeByte(*bytes++); + } + } + bdpp_stream->flush(); + } break; + + // VDU 23, 0, &A2, 4, pkt_idx, addr_lo; addr_hi; size; - get ESP32 RAM contents as words (16 bits each) + case 4: { + auto pkt_idx = readByte_t(); + bdpp_stream->start_app_response_packet(pkt_idx); + auto addr_lo = readWord_t(); + auto addr_hi = readWord_t(); + auto n = readWord_t(); + if (n*sizeof(uint16_t) <= BDPP_MAX_PACKET_DATA_SIZE) { + auto words = (const uint16_t*)((((uint32_t)addr_hi) << 16) | ((uint32_t)addr_lo)); + while (n--) { + auto word = *words++; + auto data = (const uint8_t*) &word; + writeByte(data[0]); + writeByte(data[1]); + } + } + bdpp_stream->flush(); + } break; + + // VDU 23, 0, &A2, 5, pkt_idx, addr_lo; addr_hi; size; - get ESP32 RAM contents as dwords (32 bits each) + case 5: { + auto pkt_idx = readByte_t(); + bdpp_stream->start_app_response_packet(pkt_idx); + auto addr_lo = readWord_t(); + auto addr_hi = readWord_t(); + auto n = readWord_t(); + if (n*sizeof(uint32_t) <= BDPP_MAX_PACKET_DATA_SIZE) { + auto dwords = (const uint32_t*)((((uint32_t)addr_hi) << 16) | ((uint32_t)addr_lo)); + while (n--) { + auto dword = *dwords++; + auto data = (const uint8_t*) &dword; + writeByte(data[0]); + writeByte(data[1]); + writeByte(data[2]); + writeByte(data[3]); + } + } + bdpp_stream->flush(); + } break; + + // VDU 23, 0, &A2, 6, pkt_idx - get VDP version information + case 6: { + auto pkt_idx = readByte_t(); + bdpp_stream->start_app_response_packet(pkt_idx); + writeByte(VERSION_MAJOR); + writeByte(VERSION_MINOR); + writeByte(VERSION_PATCH); + writeByte(VERSION_CANDIDATE); + + const char* data = VERSION_TYPE; + do { + writeByte(*data); + } while (*data++); + + data = VERSION_VARIANT; + do { + writeByte(*data); + } while (*data++); + bdpp_stream->flush(); + } break; + } +} + +// VDU 23, 30, ... +void VDUStreamProcessor::vdu_sys_otf() { + // placeholder for future OTF support +} + #endif // VDU_SYS_H diff --git a/video/video.ino b/video/video.ino index 53df596f..f76726b5 100644 --- a/video/video.ino +++ b/video/video.ino @@ -6,7 +6,7 @@ // Igor Chaves Cananea (vdp-gl maintenance) // Steve Sims (Audio enhancements, refactoring, bug fixes) // Created: 22/03/2022 -// Last Updated: 12/09/2023 +// Last Updated: 14/02/2024 // // Modinfo: // 11/07/2022: Baud rate tweaked for Agon Light, HW Flow Control temporarily commented out @@ -44,12 +44,14 @@ // 05/09/2023: + New audio enhancements, improved mode change code // 12/09/2023: + Refactored // 17/09/2023: + Added ZDI mode +// 03/01/2024: CW Support early version of OTF. +// 14/02/2024: CW Add support for BDPP streams #include #include #include -#define DEBUG 0 // Serial Debug Mode: 1 = enable +#define DEBUG 1 // Serial Debug Mode: 1 = enable #define SERIALBAUDRATE 115200 HardwareSerial DBGSerial(0); @@ -70,9 +72,14 @@ bool controlKeys = true; // Control keys enabled #include "vdp_protocol.h" // VDP Protocol #include "vdu_stream_processor.h" #include "hexload.h" +#include "on_the_fly.h" // Access to On-the-Fly (OTF mode) +#include "bdpp/bdp_stream.h" // BDPP Stream support std::unique_ptr Terminal; // Used for CP/M mode -VDUStreamProcessor * processor; // VDU Stream Processor +VDUStreamProcessor * processor; // VDU Stream Processor +BdppStream bdpp_stream[BDPP_MAX_STREAMS]; // Set of BDPP data streams +VDUStreamProcessor * bdpp_processor[BDPP_MAX_STREAMS]; // Set of BDPP stream processors +Stream * default_stream; // Default VDU Stream #include "zdi.h" // ZDI debugging console @@ -83,6 +90,7 @@ void setup() { copy_font(); set_mode(1); setupVDPProtocol(); + default_stream = &VDPSerial; processor = new VDUStreamProcessor(&VDPSerial); initAudio(); processor->wait_eZ80(); @@ -90,6 +98,11 @@ void setup() { resetMousePositioner(canvasW, canvasH, _VGAController.get()); processor->sendModeInformation(); boot_screen(); + + // Get ready in case BDPP gets activated. + for (uint8_t s = 0; s < BDPP_MAX_STREAMS; s++) { + bdpp_stream[s].set_stream_index(s); + } } // The main loop @@ -97,6 +110,7 @@ void setup() { void loop() { bool drawCursor = false; auto cursorTime = millis(); + auto bdpp_active = false; while (true) { if (processTerminal()) { @@ -113,19 +127,59 @@ void loop() { do_keyboard(); do_mouse(); - if (processor->byteAvailable()) { - if (drawCursor) { - do_cursor(); + if (bdpp_is_initialized()) { + if (!bdpp_active) { + // Setup the BDPP stream processors. + bdpp_active = true; + //delete processor; + for (uint8_t s = 0; s < BDPP_MAX_STREAMS; s++) { + bdpp_processor[s] = new VDUStreamProcessor(&bdpp_stream[s]); + } + processor = bdpp_processor[0]; + default_stream = &bdpp_stream[0]; } - processor->processNext(); - if (drawCursor || !cursorFlashing) { - drawCursor = true; - do_cursor(); + + // Handle incoming data on all BDPP streams. + for (uint8_t s = 0; s < BDPP_MAX_STREAMS; s++) { + auto bdpp_proc = bdpp_processor[s]; + bdpp_proc->processAllAvailable(); + } + } else { + // For legacy, use Serial2. + if (processor->byteAvailable()) { + if (drawCursor) { + do_cursor(); + } + processor->processNext(); + if (drawCursor || !cursorFlashing) { + drawCursor = true; + do_cursor(); + } } } } } +// Determine whether stream data is available (for OTF) +bool stream_byte_available() { + return processor->byteAvailable(); +} + +// Get a byte from the incoming stream (for OTF) +uint8_t stream_read_byte() { + return processor->readByte(); +} + +// Send the keyboard state (for OTF) +void stream_send_keyboard_state() { + processor->sendKeyboardState(); +} + +// Send the mode information (for OTF) +void stream_send_mode_information() { + processor->sendModeInformation(); +} + // Handle the keyboard: BBC VDU Mode // void do_keyboard() {