diff --git a/examples/gfx_rletsprite/autotester.json b/examples/gfx_rletsprite/autotester.json new file mode 100644 index 000000000..a1e391896 --- /dev/null +++ b/examples/gfx_rletsprite/autotester.json @@ -0,0 +1,30 @@ +{ + "rom": "84pce_515.rom", + "transfer_files": [ + "bin/DEMO.8xp" + ], + "target": { + "name": "DEMO", + "isASM": true + }, + "sequence": [ + "action|launch", + "hashWait|1", + "key|enter", + "hashWait|2" + ], + "hashes": { + "1": { + "description": "Make sure the sprites are displayed properly", + "start": "vram_start", + "size": "vram_8_size", + "expected_CRCs": [ "7C9ADADE" ] + }, + "2": { + "description": "Back to the home screen (exit check)", + "start": "vram_start", + "size": "vram_16_size", + "expected_CRCs": [ "FFAF89BA", "101734A5", "9DA19F44" ] + } + } +} diff --git a/examples/gfx_rletsprite/makefile b/examples/gfx_rletsprite/makefile new file mode 100644 index 000000000..68392f3f1 --- /dev/null +++ b/examples/gfx_rletsprite/makefile @@ -0,0 +1,33 @@ +# ---------------------------- +# Set NAME to the program name +# Set DEBUGMODE to "DEBUG" to use debug functions +# Set ICON to the png icon file name +# Set DESCRIPTION to display within a compatible shell +# Set COMPRESSED to "YES" to create a compressed program +# ** Add all shared library names to L ** +# ---------------------------- + +NAME ?= DEMO +DEBUGMODE ?= NDEBUG +COMPRESSED ?= NO +ICON ?= iconc.png +DESCRIPTION ?= "C SDK Demo" + +L ?= graphx + +# ---------------------------- +# Specify source and output locations +# ---------------------------- + +SRCDIR ?= src +OBJDIR ?= obj +BINDIR ?= bin +GFXDIR ?= src/gfx + +# ---------------------------- +# Use OS helper functions (Advanced) +# ---------------------------- + +USE_FLASH_FUNCTIONS ?= YES + +include $(CEDEV)/include/.makefile diff --git a/examples/gfx_rletsprite/readme.md b/examples/gfx_rletsprite/readme.md new file mode 100644 index 000000000..b0c8df70e --- /dev/null +++ b/examples/gfx_rletsprite/readme.md @@ -0,0 +1,10 @@ +### GraphX RLETSprite Demo + +Draws a sprite with RLE transparency in many clipping scenarios and converts to +and from a normal sprite with transparency. Created for testing. + +![Screenshot](screenshot.png) + +--- + +This demo is a part of the C SDK Toolchain for use on the CE. diff --git a/examples/gfx_rletsprite/screenshot.png b/examples/gfx_rletsprite/screenshot.png new file mode 100644 index 000000000..92350105b Binary files /dev/null and b/examples/gfx_rletsprite/screenshot.png differ diff --git a/examples/gfx_rletsprite/src/gfx/convpng.ini b/examples/gfx_rletsprite/src/gfx/convpng.ini new file mode 100644 index 000000000..bac699c26 --- /dev/null +++ b/examples/gfx_rletsprite/src/gfx/convpng.ini @@ -0,0 +1,5 @@ +#GroupC : logo_gfx +#Style : rlet +#TransparentColor : 255,255,255 +#PNGImages : + ubuntu diff --git a/examples/gfx_rletsprite/src/gfx/logo_gfx.c b/examples/gfx_rletsprite/src/gfx/logo_gfx.c new file mode 100644 index 000000000..a0b5a4be8 --- /dev/null +++ b/examples/gfx_rletsprite/src/gfx/logo_gfx.c @@ -0,0 +1,204 @@ +// Converted using ConvPNG +#include +#include "logo_gfx.h" + +uint16_t logo_gfx_pal[198] = { + 0xFFFF, // 00 :: rgba(255,255,255,255) + 0xFFE0, // 01 :: rgba(255,255,0,255) + 0x7C00, // 02 :: rgba(255,0,0,255) + 0x001F, // 03 :: rgba(0,0,255,255) + 0xFFFF, // 04 :: rgba(255,254,254,255) + 0xFFFF, // 05 :: rgba(255,255,254,255) + 0x83E0, // 06 :: rgba(0,255,0,255) + 0x6800, // 07 :: rgba(212,0,0,255) + 0x7E20, // 08 :: rgba(251,139,0,255) + 0x7920, // 09 :: rgba(244,72,0,255) + 0x6800, // 10 :: rgba(212,2,2,255) + 0xE821, // 11 :: rgba(213,11,11,255) + 0x7E20, // 12 :: rgba(251,139,2,255) + 0x7E20, // 13 :: rgba(251,139,1,255) + 0xFE20, // 14 :: rgba(251,140,4,255) + 0xFFFF, // 15 :: rgba(255,253,253,255) + 0xFFFF, // 16 :: rgba(255,254,253,255) + 0xFECC, // 17 :: rgba(252,182,97,255) + 0x7A90, // 18 :: rgba(249,163,128,255) + 0x7FDC, // 19 :: rgba(254,244,231,255) + 0xF985, // 20 :: rgba(245,100,40,255) + 0x7F9A, // 21 :: rgba(253,225,213,255) + 0x7FDD, // 22 :: rgba(253,242,242,255) + 0x6D6B, // 23 :: rgba(226,90,90,255) + 0xFFBC, // 24 :: rgba(254,239,233,255) + 0xF921, // 25 :: rgba(244,77,7,255) + 0x7EED, // 26 :: rgba(252,187,107,255) + 0xFF99, // 27 :: rgba(254,231,203,255) + 0xFFFE, // 28 :: rgba(255,253,250,255) + 0xFF16, // 29 :: rgba(251,199,177,255) + 0xF921, // 30 :: rgba(244,78,8,255) + 0x7F31, // 31 :: rgba(253,204,143,255) + 0xF18C, // 32 :: rgba(229,102,102,255) + 0x7FDD, // 33 :: rgba(252,241,241,255) + 0xFE87, // 34 :: rgba(251,164,56,255) + 0xFF76, // 35 :: rgba(253,221,181,255) + 0x7B5A, // 36 :: rgba(247,212,212,255) + 0x7652, // 37 :: rgba(236,145,145,255) + 0xF652, // 38 :: rgba(237,151,151,255) + 0xE800, // 39 :: rgba(212,3,3,255) + 0x6D29, // 40 :: rgba(224,74,74,255) + 0x718C, // 41 :: rgba(228,98,98,255) + 0xFF54, // 42 :: rgba(253,214,165,255) + 0xFB7B, // 43 :: rgba(250,224,224,255) + 0x7EEC, // 44 :: rgba(252,185,102,255) + 0x7FFF, // 45 :: rgba(254,252,252,255) + 0x7FBA, // 46 :: rgba(254,234,211,255) + 0xFF77, // 47 :: rgba(253,224,187,255) + 0x7F75, // 48 :: rgba(253,218,175,255) + 0x7FFE, // 49 :: rgba(254,249,249,255) + 0xFF32, // 50 :: rgba(252,205,148,255) + 0xE842, // 51 :: rgba(215,20,20,255) + 0xFFFF, // 52 :: rgba(255,253,251,255) + 0x6CC6, // 53 :: rgba(219,48,48,255) + 0x7EED, // 54 :: rgba(252,188,109,255) + 0xF652, // 55 :: rgba(237,149,149,255) + 0x7673, // 56 :: rgba(237,153,153,255) + 0x7FBD, // 57 :: rgba(252,236,236,255) + 0x7EA8, // 58 :: rgba(251,169,68,255) + 0xFAF4, // 59 :: rgba(250,190,165,255) + 0xFE87, // 60 :: rgba(251,167,61,255) + 0xECA5, // 61 :: rgba(218,43,43,255) + 0x7AD2, // 62 :: rgba(250,179,149,255) + 0xFAF7, // 63 :: rgba(243,189,189,255) + 0xFAF7, // 64 :: rgba(244,192,192,255) + 0x7B9B, // 65 :: rgba(250,225,225,255) + 0x7B7B, // 66 :: rgba(249,220,220,255) + 0xED09, // 67 :: rgba(224,70,70,255) + 0x6D08, // 68 :: rgba(222,63,63,255) + 0xF1AD, // 69 :: rgba(229,109,109,255) + 0xED08, // 70 :: rgba(223,69,69,255) + 0x76D6, // 71 :: rgba(242,178,178,255) + 0x6D4A, // 72 :: rgba(225,82,82,255) + 0xECC6, // 73 :: rgba(220,51,51,255) + 0x718C, // 74 :: rgba(228,97,97,255) + 0x76D6, // 75 :: rgba(242,179,179,255) + 0xFFDD, // 76 :: rgba(254,246,235,255) + 0xFFBC, // 77 :: rgba(254,239,234,255) + 0xFF77, // 78 :: rgba(253,223,187,255) + 0x6863, // 79 :: rgba(216,26,26,255) + 0x7AB1, // 80 :: rgba(249,169,136,255) + 0xFF9C, // 81 :: rgba(251,230,230,255) + 0xE843, // 82 :: rgba(215,21,21,255) + 0xF9A6, // 83 :: rgba(245,108,51,255) + 0x7942, // 84 :: rgba(244,81,13,255) + 0xFE21, // 85 :: rgba(251,143,11,255) + 0x7F97, // 86 :: rgba(253,225,189,255) + 0x7FBA, // 87 :: rgba(254,236,215,255) + 0x7FBC, // 88 :: rgba(251,234,234,255) + 0x7F9A, // 89 :: rgba(253,227,217,255) + 0x76D6, // 90 :: rgba(242,177,177,255) + 0xFB18, // 91 :: rgba(245,197,197,255) + 0x7AB1, // 92 :: rgba(249,171,139,255) + 0xFFBB, // 93 :: rgba(254,239,221,255) + 0xFAB2, // 94 :: rgba(249,176,144,255) + 0xF694, // 95 :: rgba(240,167,167,255) + 0x71AD, // 96 :: rgba(229,106,106,255) + 0x7FDE, // 97 :: rgba(253,243,243,255) + 0x7FDD, // 98 :: rgba(254,242,237,255) + 0x6842, // 99 :: rgba(214,16,16,255) + 0xE801, // 100 :: rgba(213,5,5,255) + 0xE822, // 101 :: rgba(214,14,14,255) + 0x6D29, // 102 :: rgba(223,71,71,255) + 0x7672, // 103 :: rgba(237,152,152,255) + 0x7A8F, // 104 :: rgba(249,161,124,255) + 0xF694, // 105 :: rgba(239,165,165,255) + 0x7FBB, // 106 :: rgba(253,233,224,255) + 0xFFBC, // 107 :: rgba(254,238,231,255) + 0xFEAA, // 108 :: rgba(251,175,80,255) + 0x7FFE, // 109 :: rgba(255,251,247,255) + 0xFA6F, // 110 :: rgba(249,159,121,255) + 0x7694, // 111 :: rgba(239,163,163,255) + 0xF920, // 112 :: rgba(244,75,4,255) + 0x7694, // 113 :: rgba(239,161,161,255) + 0xFF76, // 114 :: rgba(253,222,183,255) + 0x7A8F, // 115 :: rgba(249,160,123,255) + 0x7F0E, // 116 :: rgba(253,193,117,255) + 0xFB39, // 117 :: rgba(247,208,208,255) + 0xFF55, // 118 :: rgba(253,215,169,255) + 0xFFBA, // 119 :: rgba(254,237,216,255) + 0xFF7A, // 120 :: rgba(253,224,213,255) + 0xFF32, // 121 :: rgba(253,207,151,255) + 0x7631, // 122 :: rgba(235,138,138,255) + 0xFB7B, // 123 :: rgba(250,223,223,255) + 0x7B38, // 124 :: rgba(246,201,201,255) + 0x7AF3, // 125 :: rgba(250,186,160,255) + 0x7FFF, // 126 :: rgba(254,251,251,255) + 0xF16C, // 127 :: rgba(227,95,95,255) + 0x7FDB, // 128 :: rgba(254,241,224,255) + 0xFE87, // 129 :: rgba(251,165,60,255) + 0xFA6F, // 130 :: rgba(249,159,122,255) + 0xFE87, // 131 :: rgba(251,164,57,255) + 0x7F0E, // 132 :: rgba(252,193,119,255) + 0xFF9B, // 133 :: rgba(253,229,219,255) + 0x7A2B, // 134 :: rgba(247,138,92,255) + 0x7E42, // 135 :: rgba(251,146,19,255) + 0x7FDC, // 136 :: rgba(254,243,230,255) + 0x7963, // 137 :: rgba(244,89,24,255) + 0x7E41, // 138 :: rgba(251,144,12,255) + 0x7F79, // 139 :: rgba(252,220,207,255) + 0xFF33, // 140 :: rgba(252,208,154,255) + 0x7F36, // 141 :: rgba(251,202,182,255) + 0xFA6E, // 142 :: rgba(249,157,119,255) + 0xFFDD, // 143 :: rgba(254,245,240,255) + 0xF964, // 144 :: rgba(245,95,32,255) + 0x7920, // 145 :: rgba(244,74,3,255) + 0xF921, // 146 :: rgba(244,76,6,255) + 0xFFDE, // 147 :: rgba(254,246,243,255) + 0xFAD3, // 148 :: rgba(250,183,155,255) + 0x7B18, // 149 :: rgba(245,195,195,255) + 0x7FFE, // 150 :: rgba(255,252,250,255) + 0xFAD3, // 151 :: rgba(250,182,154,255) + 0x6800, // 152 :: rgba(212,1,1,255) + 0x7FFE, // 153 :: rgba(255,251,250,255) + 0xF985, // 154 :: rgba(245,103,44,255) + 0x7EA8, // 155 :: rgba(251,169,69,255) + 0xFEAA, // 156 :: rgba(251,176,82,255) + 0x7ECB, // 157 :: rgba(251,179,87,255) + 0x7AD2, // 158 :: rgba(250,178,148,255) + 0x6D08, // 159 :: rgba(222,65,65,255) + 0x71EF, // 160 :: rgba(231,120,120,255) + 0xFAD3, // 161 :: rgba(250,181,153,255) + 0x7A4D, // 162 :: rgba(248,147,106,255) + 0xFB5A, // 163 :: rgba(248,216,216,255) + 0x7FDE, // 164 :: rgba(253,244,244,255) + 0x7F15, // 165 :: rgba(251,196,173,255) + 0x7F79, // 166 :: rgba(253,220,206,255) + 0xFFDD, // 167 :: rgba(254,246,242,255) + 0x7652, // 168 :: rgba(236,146,146,255) + 0xF9E9, // 169 :: rgba(246,126,76,255) + 0xFB39, // 170 :: rgba(247,206,206,255) + 0xFF37, // 171 :: rgba(252,208,190,255) + 0xF942, // 172 :: rgba(244,83,16,255) + 0x7F31, // 173 :: rgba(252,201,137,255) + 0xFAB2, // 174 :: rgba(250,176,145,255) + 0xF9C8, // 175 :: rgba(246,116,62,255) + 0xFF9B, // 176 :: rgba(253,232,224,255) + 0xFF10, // 177 :: rgba(252,198,131,255) + 0x7A6E, // 178 :: rgba(248,155,117,255) + 0xFFBB, // 179 :: rgba(254,240,221,255) + 0xFE21, // 180 :: rgba(251,143,10,255) + 0xFEA9, // 181 :: rgba(251,174,78,255) + 0x7E87, // 182 :: rgba(251,163,54,255) + 0xFF54, // 183 :: rgba(253,213,164,255) + 0xF9E9, // 184 :: rgba(247,127,77,255) + 0x79E8, // 185 :: rgba(246,120,67,255) + 0xFE21, // 186 :: rgba(251,141,6,255) + 0xFFDD, // 187 :: rgba(254,248,240,255) + 0xFF58, // 188 :: rgba(252,213,197,255) + 0x7FDC, // 189 :: rgba(254,243,229,255) + 0x7F53, // 190 :: rgba(253,210,155,255) + 0xFE87, // 191 :: rgba(251,164,58,255) + 0x7920, // 192 :: rgba(244,74,2,255) + 0x7F57, // 193 :: rgba(252,210,193,255) + 0xC3E0, // 194 :: rgba(128,255,0,255) + 0x7E00, // 195 :: rgba(255,128,0,255) + 0x0210, // 196 :: rgba(0,128,128,255) + 0x4030, // 197 :: rgba(128,8,128,255) +}; \ No newline at end of file diff --git a/examples/gfx_rletsprite/src/gfx/logo_gfx.h b/examples/gfx_rletsprite/src/gfx/logo_gfx.h new file mode 100644 index 000000000..17ded7bb6 --- /dev/null +++ b/examples/gfx_rletsprite/src/gfx/logo_gfx.h @@ -0,0 +1,14 @@ +// Converted using ConvPNG +// This file contains all the graphics sources for easier inclusion in a project +#ifndef __logo_gfx__ +#define __logo_gfx__ +#include + +#define logo_gfx_transparent_color_index 0 + +extern uint8_t ubuntu_data[552]; +#define ubuntu ((gfx_rletsprite_t*)ubuntu_data) +#define sizeof_logo_gfx_pal 396 +extern uint16_t logo_gfx_pal[198]; + +#endif diff --git a/examples/gfx_rletsprite/src/gfx/ubuntu.c b/examples/gfx_rletsprite/src/gfx/ubuntu.c new file mode 100644 index 000000000..1a9d0a869 --- /dev/null +++ b/examples/gfx_rletsprite/src/gfx/ubuntu.c @@ -0,0 +1,26 @@ +// Converted using ConvPNG +#include +#include "logo_gfx.h" + +// 8 bpp image +uint8_t ubuntu_data[552] = { + 32,32, // width,height + 0x00,0x04,0xC2,0x01,0x01,0x01,0x18,0x04,0x01,0x01,0x01,0xC3,0x00,0x01,0x06,0x1E,0x01,0x02,0x00,0x01,0x06,0x15,0x04,0x0F,0x47,0x25,0x42,0x05,0x01,0x02,0x00,0x01, + 0x06,0x14,0x06,0x04,0x17,0x07,0x07,0x0B,0x40,0x04,0x01,0x02,0x0E,0x0D,0x04,0x59,0x3B,0x50,0x12,0x94,0x18,0xA3,0x07,0x07,0x07,0x07,0x28,0x05,0x0D,0x0E,0x8D,0x14, + 0x09,0x09,0x09,0x09,0x09,0xA5,0xAA,0x07,0x07,0x07,0x07,0x46,0x05,0x0B,0x01,0x88,0x01,0x0E,0x85,0x19,0x09,0x09,0x09,0x09,0x09,0xA2,0x04,0x9F,0x07,0x07,0x98,0x5A, + 0x05,0x0A,0x03,0x8C,0x87,0x13,0x01,0x0C,0x8E,0x09,0x09,0x09,0x09,0x09,0x19,0xA6,0xA4,0xA8,0xA0,0x95,0x06,0x09,0x04,0x76,0x0D,0x08,0x11,0x01,0x0E,0x8F,0x89,0x70, + 0x90,0x9A,0x1E,0x09,0xAC,0xA1,0xA7,0x99,0x15,0x5C,0x04,0x04,0x08,0x06,0x5D,0x55,0x08,0x08,0x0C,0x1B,0x01,0x03,0x78,0x62,0x05,0x01,0x09,0x96,0xAB,0xA9,0x09,0x09, + 0x92,0x09,0x09,0x3E,0x04,0x07,0x07,0x05,0x9C,0x08,0x08,0x08,0x08,0x84,0x07,0x08,0x04,0x97,0x91,0x09,0x09,0x09,0x54,0x4D,0x03,0x07,0x07,0xB3,0x0D,0x08,0x08,0x08, + 0x81,0x1C,0x09,0x06,0x5E,0x09,0x09,0x09,0x09,0x12,0x03,0x07,0x06,0xB7,0x08,0x08,0x08,0x0C,0x57,0x0A,0x07,0x04,0x53,0x09,0x09,0x09,0x14,0x04,0x02,0x03,0x09,0x93, + 0xAE,0xB2,0xC1,0x05,0x1A,0x08,0x08,0x9B,0x0C,0x06,0x7D,0x09,0x09,0x09,0x09,0x18,0x02,0x02,0x0A,0x10,0xAF,0x09,0x09,0xC0,0x1D,0xBB,0xB4,0x08,0xB1,0x0C,0x06,0x6B, + 0x68,0x73,0x82,0x6E,0x6A,0x02,0x02,0x06,0x8B,0x09,0x09,0x09,0x09,0xB9,0x01,0x03,0xBF,0x08,0xBE,0x14,0x02,0x06,0x15,0x09,0x09,0x09,0x09,0xB8,0x01,0x03,0xB6,0x08, + 0xAD,0x0C,0x06,0x61,0x71,0x6F,0x69,0x5F,0x58,0x02,0x02,0x0A,0x04,0x86,0x09,0x09,0x1E,0xBC,0xBD,0xBA,0x08,0x9D,0x0C,0x06,0x4B,0x07,0x07,0x07,0x07,0x51,0x02,0x03, + 0x0A,0x10,0x1D,0x9E,0xB0,0x1C,0xB5,0x08,0x08,0x8A,0x4C,0x0B,0x06,0x48,0x07,0x07,0x07,0x4F,0x0F,0x02,0x07,0x07,0x1B,0x08,0x08,0x08,0x08,0x2C,0x05,0x09,0x06,0x3F, + 0x0A,0x07,0x07,0x07,0x45,0x03,0x07,0x07,0x04,0x83,0x08,0x08,0x08,0x08,0x32,0x08,0x07,0x75,0x52,0x07,0x07,0x07,0x27,0x24,0x03,0x08,0x06,0x4E,0x08,0x08,0x08,0x08, + 0x30,0x01,0x02,0x31,0x04,0x03,0x08,0x16,0x7A,0x0B,0x07,0x07,0x07,0x07,0x20,0x04,0x08,0x14,0x05,0x36,0x08,0x08,0x3A,0x04,0x2D,0x35,0x49,0x4A,0x60,0x66,0x65,0x07, + 0x07,0x0A,0x0B,0x07,0x3D,0x21,0x04,0x09,0x04,0x34,0x11,0x0E,0x2E,0x01,0x0D,0x37,0x07,0x07,0x07,0x07,0x07,0x07,0x63,0x67,0x16,0x7E,0x7B,0x41,0x05,0x0A,0x02,0x05, + 0x2F,0x01,0x0D,0x39,0x33,0x07,0x07,0x07,0x07,0x07,0x64,0x7C,0x6D,0x79,0x74,0x56,0x06,0x0D,0x0E,0x38,0x0A,0x07,0x07,0x07,0x07,0x07,0x7F,0x04,0x6C,0x08,0x08,0x0D, + 0x2A,0x05,0x0E,0x0D,0x2B,0x26,0x29,0x43,0x44,0x17,0x5B,0x80,0x08,0x08,0x08,0x08,0x22,0x05,0x15,0x06,0x13,0x0C,0x08,0x08,0x08,0x3C,0x05,0x00,0x01,0x06,0x15,0x05, + 0x1A,0x08,0x08,0x0E,0x72,0x04,0x01,0x02,0x00,0x01,0x06,0x15,0x04,0x05,0x23,0x1F,0x77,0x05,0x01,0x02,0x00,0x01,0x06,0x1E,0x01,0x02,0x00,0x04,0xC4,0x03,0x03,0x03, + 0x18,0x04,0x03,0x03,0x03,0xC5, +}; diff --git a/examples/gfx_rletsprite/src/gfx/ubuntu.png b/examples/gfx_rletsprite/src/gfx/ubuntu.png new file mode 100644 index 000000000..fa650306f Binary files /dev/null and b/examples/gfx_rletsprite/src/gfx/ubuntu.png differ diff --git a/examples/gfx_rletsprite/src/main.c b/examples/gfx_rletsprite/src/main.c new file mode 100644 index 000000000..ec011aa87 --- /dev/null +++ b/examples/gfx_rletsprite/src/main.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* Include the sprite data */ +#include "gfx/logo_gfx.h" + +#define xmin 64 +#define ymin 24 +#define xmax 256 +#define ymax 216 + +#define xmin2 180 +#define ymin2 92 +#define xmax2 204 +#define ymax2 116 + +/* For testing conversions */ +gfx_UninitedSprite(ubuntu_normal, 32, 32); +gfx_UninitedRLETSprite(ubuntu_uninited, 33 * 32); + +void main(void) { + /* For testing conversions */ + gfx_rletsprite_t *ubuntu_malloc; + + /* Initialize the 8bpp graphics */ + gfx_Begin(gfx_8bpp); + + /* Set up the palette for our sprites */ + gfx_SetPalette(logo_gfx_pal, sizeof logo_gfx_pal, 0); + gfx_palette[255] = gfx_RGBTo1555(192, 192, 192); + + /* Set a centered 192*192 clip region, bordered by gray and filled with color index 0 */ + gfx_FillScreen(255); + gfx_SetColor(0); + gfx_FillRectangle_NoClip(xmin, ymin, xmax - xmin, ymax - ymin); + gfx_SetClipRegion(xmin, ymin, xmax, ymax); + + /* Test no clipping */ + gfx_RLETSprite_NoClip(ubuntu, xmin + 48, ymin + 64); + gfx_RLETSprite(ubuntu, xmin + 80, ymin + 64); + + /* Test top clipping */ + gfx_RLETSprite(ubuntu, xmin + 32, ymin); + gfx_RLETSprite(ubuntu, xmin + 64, ymin - 31); + gfx_RLETSprite(ubuntu, xmin + 96, ymin - 32); + gfx_RLETSprite(ubuntu, xmin + 128, INT_MIN); + + /* Test bottom clipping */ + gfx_RLETSprite(ubuntu, xmin + 128, ymax - 32); + gfx_RLETSprite(ubuntu, xmin + 96, ymax - 1); + gfx_RLETSprite(ubuntu, xmin + 64, ymax); + gfx_RLETSprite(ubuntu, xmin + 32, INT_MAX); + + /* Test right clipping */ + gfx_RLETSprite(ubuntu, xmax - 32, ymin + 32); + gfx_RLETSprite(ubuntu, xmax - 1, ymin + 64); + gfx_RLETSprite(ubuntu, xmax, ymin + 96); + gfx_RLETSprite(ubuntu, INT_MAX, ymin + 128); + + /* Test left clipping */ + gfx_RLETSprite(ubuntu, xmin, ymin + 128); + gfx_RLETSprite(ubuntu, xmin - 31, ymin + 96); + gfx_RLETSprite(ubuntu, xmin - 32, ymin + 64); + gfx_RLETSprite(ubuntu, INT_MIN, ymin + 32); + + /* Test corner clipping */ + gfx_RLETSprite(ubuntu, xmin - 31, ymin - 31); + gfx_RLETSprite(ubuntu, xmax - 1, ymin - 31); + gfx_RLETSprite(ubuntu, xmax - 1, ymax - 1); + gfx_RLETSprite(ubuntu, xmin - 31, ymax - 1); + + /* Set a centered 16*16 clip region, bordered by gray and filled with color index 0 */ + gfx_SetColor(255); + gfx_FillRectangle_NoClip(xmin2 - 4, ymin2 - 4, xmax2 - xmin2 + 8, ymax2 - ymin2 + 8); + gfx_SetColor(0); + gfx_FillRectangle_NoClip(xmin2, ymin2, xmax2 - xmin2, ymax2 - ymin2); + gfx_SetClipRegion(xmin2, ymin2, xmax2, ymax2); + + /* Test all-around clipping */ + gfx_RLETSprite(ubuntu, xmin2 - 4, ymin2 - 4); + + /* Test conversions */ + gfx_SetTransparentColor(0); + gfx_ConvertFromRLETSprite(ubuntu, ubuntu_normal); + gfx_TransparentSprite_NoClip(ubuntu_normal, xmin + 48, ymin + 96); + gfx_ConvertToRLETSprite(ubuntu_normal, ubuntu_uninited); + gfx_RLETSprite_NoClip(ubuntu_uninited, xmin + 80, ymin + 96); + ubuntu_malloc = gfx_ConvertMallocRLETSprite(ubuntu_normal); + gfx_RLETSprite_NoClip(ubuntu_malloc, xmin + 112, ymin + 96); + + /* Wait for a key to be pressed */ + while (!os_GetCSC()); + + /* Close the graphics */ + gfx_End(); +} diff --git a/examples/gfx_sprite_compress/src/main.c b/examples/gfx_sprite_compress/src/main.c index e9853adaf..5a6ad4a86 100644 --- a/examples/gfx_sprite_compress/src/main.c +++ b/examples/gfx_sprite_compress/src/main.c @@ -18,32 +18,28 @@ void main(void) { /* Define our sprite */ gfx_sprite_t *apple; - - /* This is just here so that the malloc function is compiled into the binary */ - malloc(0); - + /* Allocate space for the decompressed sprite */ apple = gfx_MallocSprite(220, 240); - + /* Decompress the sprite */ dzx7_Standard(apple_compressed, apple); // or dzx7_Turbo - + /* Initialize the 8bpp graphics */ gfx_Begin(gfx_8bpp); - + /* Set up the palette */ gfx_SetPalette(all_gfx_pal, sizeof all_gfx_pal, 0); gfx_FillScreen(0); - + /* Draw the decompressed sprite */ gfx_Sprite(apple, (320 - 220) / 2, (240 - 240) / 2); - + /* Wait for a key */ while (!os_GetCSC()); - + /* Please, don't forget to free the apple image memory :) */ free(apple); - + gfx_End(); } - diff --git a/examples/gfx_tilemap_compress/src/main.c b/examples/gfx_tilemap_compress/src/main.c index ab7ffc05a..b65502f53 100644 --- a/examples/gfx_tilemap_compress/src/main.c +++ b/examples/gfx_tilemap_compress/src/main.c @@ -42,15 +42,16 @@ void main(void) { unsigned int y_offset = 0; gfx_sprite_t *tmp_ptr; gfx_tilemap_t tilemap; - + /* Decompress the tiles */ for (i = 0; i < sizeof(tileset_tiles)/sizeof(gfx_sprite_t*) ; i++) { tmp_ptr = gfx_MallocSprite(TILE_WIDTH, TILE_HEIGHT); dzx7_Turbo(tileset_tiles_compressed[i], tmp_ptr); // or dzx7_Standard, but in this case we have a lot of tiles tileset_tiles[i] = tmp_ptr; } + dzx7_Turbo(tilemap_compressed, tilemap_map); - + /* Initialize the tilemap structure */ tilemap.map = tilemap_map; tilemap.tiles = tileset_tiles; @@ -64,23 +65,23 @@ void main(void) { tilemap.width = TILEMAP_WIDTH; tilemap.y_loc = Y_OFFSET; tilemap.x_loc = X_OFFSET; - + /* Initialize the graphics scene */ gfx_Begin(); - + /* Set up the palette */ gfx_SetPalette(tiles_gfx_pal, sizeof tiles_gfx_pal, 0); gfx_SetColor(gfx_white); - + /* Draw to buffer to avoid tearing */ gfx_SetDrawBuffer(); - + /* Set monospace font with width of 8 */ gfx_SetMonospaceFont(8); /* Wait for the enter key to quit */ while ((key = os_GetCSC()) != sk_Enter) { - + /* Draw tilemap and coords */ gfx_Tilemap(&tilemap, x_offset, y_offset); gfx_FillRectangle(0, 0, 320, 16); @@ -88,7 +89,7 @@ void main(void) { gfx_PrintUInt(x_offset, 4); gfx_PrintString(" y offset:"); gfx_PrintUInt(y_offset, 4); - + /* Do something based on the keypress */ switch (key) { case sk_Down: @@ -112,8 +113,7 @@ void main(void) { } gfx_SwapDraw(); } - + /* Close the graphics */ gfx_End(); } - diff --git a/src/graphx/graphx.asm b/src/graphx/graphx.asm index 1b8c0599e..0e2aa5291 100644 --- a/src/graphx/graphx.asm +++ b/src/graphx/graphx.asm @@ -3,7 +3,7 @@ .libraryAppVar "GRAPHX" ; Name of library on the calc .libraryName "graphx" ; Name of library - .libraryVersion 5 ; Version information (1-255) + .libraryVersion 6 ; Version information (1-255) ;------------------------------------------------------------------------------- ; v1 functions - Can no longer move/delete @@ -104,6 +104,15 @@ .function "gfx_SetFontHeight",_SetFontHeight .function "gfx_ScaleSprite",_ScaleSprite .function "gfx_FloodFill",_FloodFill +;------------------------------------------------------------------------------- +; v6 functions - Can no longer move/delete +;------------------------------------------------------------------------------- + .function "gfx_RLETSprite",_RLETSprite + .function "gfx_RLETSprite_NoClip",_RLETSprite_NoClip + .function "gfx_ConvertFromRLETSprite",_ConvertFromRLETSprite + .function "gfx_ConvertToRLETSprite",_ConvertToRLETSprite + .function "gfx_ConvertToNewRLETSprite",_ConvertToNewRLETSprite + .beginDependencies .endDependencies @@ -122,6 +131,7 @@ DEFAULT_TEXT_TP_COLOR equ 255 ; Useful Macros #define mIsHLLessThanDE() or a,a \ sbc hl,de \ add hl,hl \ jp po,$+5 \.r \ ccf \ #define mIsHLLessThanBC() or a,a \ sbc hl,bc \ add hl,hl \ jp po,$+5 \.r \ ccf \ +#define s8(x) 1*((x)|(((x)&80h)<<1)) ;------------------------------------------------------------------------------- ;------------------------------------------------------------------------------- @@ -313,6 +323,7 @@ _SetTransparentColor: ld (TColor_SMC_2),a \.r ld (TColor_SMC_3),a \.r ld (TColor_SMC_4),a \.r + ld (TColor_SMC_5),a \.r jr _SetColor_Ret ;------------------------------------------------------------------------------- @@ -4377,6 +4388,576 @@ ff_stacktop_smc =$+1 pop ix ret +;------------------------------------------------------------------------------- +_RLETSprite: +; Draws a sprite with RLE transparency with clipping. +; Arguments: +; arg0 : pointer to sprite structure +; arg1 : x-coordinate +; arg2 : y-coordinate +; Returns: +; None + ld iy,0 + lea bc,iy ; bc = 0 + add iy,sp ; iy = frame +; Clip bottom + ld hl,(iy+3) ; hl = sprite struct + ld c,(hl) ; bc = height + ld hl,(_ymax) \.r ; hl = ymax + ld de,(iy+9) ; de = y + sbc hl,de ; hl = ymax-y + ret m ; m ==> ymax < y || y ~ int_min ==> fully off-screen + ret z ; z ==> ymax == y ==> fully off-screen + sbc hl,bc ; hl = ymax-y-height = -(height off-screen) + jr nc,_RLETSprite_SkipClipBottom ; nc ==> height-off-screen <= 0 ==> fully on-screen + add hl,bc ; hl = ymax-y = height on-screen + ld c,l ; bc = height on-screen +_RLETSprite_SkipClipBottom: +; ymax-y did not overflow ==> y-ymin will not overflow +; Clip top + ld hl,(_ymin) \.r ; hl = ymin + ex de,hl ; de = ymin + ; hl = y + xor a,a + sbc hl,de ; hl = y-ymin + jp p,_RLETSprite_SkipClipTop \.r ; p ==> y >= ymin ==> fully on-screen + add hl,bc ; hl = y-ymin+height = height on-screen + ret nc ; nc ==> height on-screen < 0 ==> fully off-screen + ld a,l ; a = height on-screen + or a,a + ret z ; z ==> height on-screen == 0 ==> fully off-screen + ld a,c + sub a,l ; a = height off-screen + ld b,a ; b = height off-screen + ld c,l ; c = height on-screen + sbc hl,hl ; y = ymin (after add hl,de) +_RLETSprite_SkipClipTop: + ld (_RLETSprite_Heights_SMC),bc \.r + add hl,de ; hl = y (clipped) + ld (iy+9),l ; write back clipped y +; de = ymin => d = deu = 0 +; Clip left + ld hl,(iy+3) ; hl = sprite struct + inc hl + ld e,(hl) ; de = width + ld hl,(iy+6) ; hl = x + ld bc,(_xmin) \.r ; bc = xmin + sbc hl,bc ; hl = x-xmin + ret pe ; v ==> x ~ int_min ==> fully off-screen + jp p,_RLETSprite_SkipClipLeft \.r ; p ==> x >= xmin ==> fully on-screen + add hl,de ; hl = x-xmin+width = width on-screen + ret nc ; nc ==> width on-screen < 0 ==> fully off-screen + ld a,l ; a = width on-screen + or a,a + ret z ; z ==> width on-screen == 0 ==> fully off-screen + ld h,a ; h = width on-screen + ld a,e ; a = width + ld e,h ; de = width on-screen + sub a,l ; a = width - width on-screen = width off-screen + ld (_RLETSprite_ClipLeft_Width_SMC),a \.r + inc d ; d[0] = 1 + sbc hl,hl ; x = xmin (after add hl,bc) +_RLETSprite_SkipClipLeft: +; x >= xmin ==> x >= 0 +; Clip right + add hl,bc ; hl = x (clipped) + ld (iy+6),hl ; write back clipped x + ld bc,(_xmax) \.r ; bc = xmax + sbc hl,bc ; hl = x-xmax + ret nc ; nc ==> x >= xmax ==> fully off-screen + ld a,d ; a[0] = clip left? + ld d,0 ; de = width + add hl,de ; hl = x-xmax+width = width off-screen + ld d,a ; d[0] = clip left? + jr nc,_RLETSprite_SkipClipRight ; nc ==> width off-screen < 0 ==> fully on-screen + ld a,l ; a = width off-screen + or a,a + jr z,_RLETSprite_SkipClipRight ; z ==> width off-screen == 0 ==> fully on-screen + ld (_RLETSprite_ExitRight_Opaque_Width_SMC),a \.r + ld (_RLETSprite_ExitRight_Trans_Width_SMC),a \.r + ld a,e ; a = width + sub a,l ; a = width - width off-screen = width on-screen + ld e,a ; e = width on-screen + set 1,d ; d[1] = 1 +_RLETSprite_SkipClipRight: +; Calculate the pointer to the top-left corner of the sprite in the buffer + ld hl,(currDrawBuffer) + ld bc,(iy+6) ; bc = x (clipped) + add hl,bc + ld c,(iy+9) ; c = y (clipped) + ld b,lcdWidth/2 + mlt bc ; bc = y*160 + add hl,bc + add hl,bc +; Get the pointer to the start of the sprite data, clipping the top if necessary + push hl ; (sp) = top-left corner of sprite in buffer + push de ; (sp) = (x clip bits)<<8|(width on-screen) + ld bc,0 ; b = height off-screen (top), c = height on-screen +_RLETSprite_Heights_SMC = $-3 + ld d,c + push de ; (sp) = (height on-screen)<<8|(width on-screen) + ld hl,(iy+3) ; hl = sprite struct + inc hl + xor a,a ; a = 0 + ld d,a ; d = deu = 0 + or a,b ; a = height off-screen + jr z,_RLETSprite_ClipTop_End ; z => height off-screen == 0 + ld c,(hl) ; c = width +_RLETSprite_ClipTop_Row: + ld a,c ; a = width +_RLETSprite_ClipTop_Trans: + inc hl + sub a,(hl) ; a = width remaining after trans run + jr z,_RLETSprite_ClipTop_RowEnd ; z ==> width remaining == 0 +_RLETSprite_ClipTop_Opaque: + inc hl + ld e,(hl) ; de = opaque run length + sub a,e ; a = width remaining after opaque run + add hl,de ; skip opaque run + jr nz,_RLETSprite_ClipTop_Trans ; nz ==> width remaining != 0 +_RLETSprite_ClipTop_RowEnd: + djnz _RLETSprite_ClipTop_Row ; decrement height remaining off-screen, + ; nz => still off-screen +_RLETSprite_ClipTop_End: ; a = 0 + inc hl ; hl = start of (clipped) sprite data +; Do stuff + pop iy ; iyh = height on-screen, iyl = width on-screen + pop bc ; bcu = 0, b = x clip bits + pop de ; de = buffer + dec de ; decrement buffer pointer (negate inc) + or a,b + ld a,iyl ; a = width on-screen + jp z,_RLETSprite_NoClip_Begin \.r + cpl ; a = 255-(width on-screen) + add a,lcdWidth-255 ; a = (lcdWidth-(width on-screen))&0FFh + rra ; a = (lcdWidth-(width on-screen))/2 + dec b + jr z,_RLETSprite_ClipLeftMiddle + ld (_RLETSprite_ClipRight_HalfRowDelta_SMC),a \.r + sbc a,a + djnz _RLETSprite_ClipLeftMiddleClipRight +_RLETSprite_MiddleClipRight: + sub a,s8(_RLETSprite_ClipRight_LoopJr_SMC+1-_RLETSprite_Middle_Row_WidthEven) + ld (_RLETSprite_ClipRight_LoopJr_SMC),a \.r +_RLETSprite_Middle_Row_WidthOdd: + inc de ; increment buffer pointer +_RLETSprite_Middle_Row_WidthEven: + ld a,iyl ; a = width on-screen + jr _RLETSprite_Middle_Trans +_RLETSprite_Middle_OpaqueCopy_: + inc hl +_RLETSprite_Middle_OpaqueCopy: + ldir ; copy opaque run +_RLETSprite_Middle_Trans: + ld c,(hl) ; bc = trans run length + sub a,c ; a = width remaining on-screen after trans run + ex de,hl ; de = sprite, hl = buffer + jr c,_RLETSprite_ExitRight_Trans ; c ==> width remaining on-screen < 0 + inc de +_RLETSprite_Middle_TransSkip: + add hl,bc ; skip trans run + ex de,hl ; de = buffer, hl = sprite +_RLETSprite_Middle_Opaque: + ld c,(hl) ; bc = opaque run length + sub a,c ; a = width remaining on-screen after opqaue run + jr nc,_RLETSprite_Middle_OpaqueCopy_ ; nc ==> width remaining on-screen >= 0 +_RLETSprite_ExitRight_Opaque: + add a,c + ld c,a ; bc = width remaining on-screen before opaque run + ld a,(hl) + inc hl + sub c + ldir ; copy on-screen part of opaque run + ld c,a ; bc = opaque run length off-screen + ld a,0 ; a = width off-screen +_RLETSprite_ExitRight_Opaque_Width_SMC = $-1 + jr _RLETSprite_ClipRight_OpaqueSkip + +_RLETSprite_ExitRight_Trans: + add a,c ; a = width remaining on-screen before trans run + ld c,a ; bc = width remaining on-screen before trans run + add hl,bc ; skip on-screen part of trans run + ex de,hl ; de = buffer, hl = sprite + add a,0 ; a = width remaining on-screen before trans run + width off-screen +_RLETSprite_ExitRight_Trans_Width_SMC = $-1 +_RLETSprite_ClipRight_Trans: + sub a,(hl) ; a = width remaining off-screen after trans run + inc hl + jr z,_RLETSprite_ClipRight_RowEnd ; z ==> width remaining off-screen == 0 +_RLETSprite_ClipRight_Opaque: + ld c,(hl) ; bc = opaque run length + inc hl +_RLETSprite_ClipRight_OpaqueSkip: + sub a,c ; a = width remaining off-screen after opaque run + add hl,bc ; skip opaque run + jr nz,_RLETSprite_ClipRight_Trans ; nz ==> width remaining off-screen != 0 +_RLETSprite_ClipRight_RowEnd: + ex de,hl ; de = sprite, hl = buffer + ld c,0 ; c = (lcdWidth-(width on-screen))/2 +_RLETSprite_ClipRight_HalfRowDelta_SMC = $-1 + add hl,bc ; advance buffer to next row + add hl,bc + ex de,hl ; de = buffer, hl = sprite + dec iyh ; decrement height remaining + jr nz,_RLETSprite_Middle_Trans ; nz ==> height remaining != 0 +_RLETSprite_ClipRight_LoopJr_SMC = $-1 + ret + +_RLETSprite_ClipLeftMiddleClipRight: + dec b ; b = 0 + sub a,s8(_RLETSprite_ClipRight_LoopJr_SMC+1-_RLETSprite_ClipLeft_Row_WidthEven) + ld (_RLETSprite_ClipRight_LoopJr_SMC),a \.r + ld a,s8(_RLETSprite_Middle_OpaqueCopy-(_RLETSprite_EnterLeft_Opaque_Jr_SMC+1)) + ld c,s8(_RLETSprite_Middle_TransSkip-(_RLETSprite_EnterLeft_Trans_Jr_SMC+1)) + jr _RLETSprite_ClipLeftMiddle_DoSMC + +_RLETSprite_ClipLeftMiddle: + ld (_RLETSprite_NoClip_HalfRowDelta_SMC),a \.r + sbc a,a + sub a,s8(_RLETSprite_NoClip_LoopJr_SMC+1-_RLETSprite_ClipLeft_Row_WidthEven) + ld (_RLETSprite_NoClip_LoopJr_SMC),a \.r + ld a,s8(_RLETSprite_NoClip_OpaqueCopy-(_RLETSprite_EnterLeft_Opaque_Jr_SMC+1)) + ld c,s8(_RLETSprite_NoClip_TransSkip-(_RLETSprite_EnterLeft_Trans_Jr_SMC+1)) +_RLETSprite_ClipLeftMiddle_DoSMC: + ld (_RLETSprite_EnterLeft_Opaque_Jr_SMC),a \.r + ld a,c + ld (_RLETSprite_EnterLeft_Trans_Jr_SMC),a \.r +_RLETSprite_ClipLeft_Row_WidthOdd: + inc de ; increment buffer pointer +_RLETSprite_ClipLeft_Row_WidthEven: + ld a,0 ; a = width off-screen +_RLETSprite_ClipLeft_Width_SMC = $-1 + jr _RLETSprite_ClipLeft_Trans +_RLETSprite_ClipLeft_OpaqueSkip: + ld c,(hl) ; bc = opaque run length + inc hl + add hl,bc ; skip opaque run +_RLETSprite_ClipLeft_Trans: + sub a,(hl) ; a = width remaining off-screen after trans run + inc hl + jr c,_RLETSprite_EnterLeft_Trans ; c ==> partially on-screen +_RLETSprite_ClipLeft_Opaque: + ld c,a ; bc = width remaining off-screen before opaque run + sub a,(hl) ; a = width remaining off-screen after opaque run + jr nc,_RLETSprite_ClipLeft_OpaqueSkip ; nc ==> still off-screen +_RLETSprite_EnterLeft_Opaque: + inc hl + add hl,bc ; skip off-screen part of opaque run + neg + ld c,a ; bc = opaque run length on-screen + ld a,iyl ; a = width on-screen + sub a,c ; a = width remaining on-screen after opaque run + jr _RLETSprite_NoClip_OpaqueCopy +_RLETSprite_EnterLeft_Opaque_Jr_SMC = $-1 + +_RLETSprite_EnterLeft_Trans: + neg + ld c,a ; bc = opaque run length on-screen + ld a,iyl ; a = width on-screen + sub a,c ; a = width remaining on-screen after opaque run + ex de,hl ; de = sprite, hl = buffer + jr _RLETSprite_NoClip_TransSkip +_RLETSprite_EnterLeft_Trans_Jr_SMC = $-1 + +;------------------------------------------------------------------------------- +_RLETSprite_NoClip: +; Draws a sprite with RLE transparency without clipping. +; Arguments: +; arg0 : pointer to sprite structure +; arg1 : x-coordinate +; arg2 : y-coordinate +; Returns: +; None + ld iy,0 + add iy,sp +; Calculate the pointer to the top-left corner of the sprite in the buffer. + ld hl,(currDrawBuffer) + ld bc,(iy+6) ; bc = x + add hl,bc + ld c,(iy+9) ; c = y + ld b,lcdWidth/2 + mlt bc ; bc = y*160 + add hl,bc + add hl,bc + ex de,hl ; de = top-left corner of sprite in buffer +; Read the sprite width and height. + ld hl,(iy+3) ; hl = sprite struct + ld iy,(hl) ; iyh = height, iyl = width + ld a,(hl) ; a = width + inc hl + inc hl ; hl = sprite data +; Initialize values for looping. + ld b,0 ; b = 0 + dec de ; decrement buffer pointer (negate inc) +_RLETSprite_NoClip_Begin: +; Generate the code to advance the buffer pointer to the start of the next row. + cpl ; a = 255-width + add a,lcdWidth-255 ; a = (lcdWidth-width)&0FFh + rra ; a = (lcdWidth-width)/2 + ld (_RLETSprite_NoClip_HalfRowDelta_SMC),a \.r + sbc a,a + sub a,s8(_RLETSprite_NoClip_LoopJr_SMC+1-_RLETSprite_NoClip_Row_WidthEven) + ld (_RLETSprite_NoClip_LoopJr_SMC),a \.r +; Row loop (if sprite width is odd) +_RLETSprite_NoClip_Row_WidthOdd: + inc de ; increment buffer pointer +; Row loop (if sprite width is even) { +_RLETSprite_NoClip_Row_WidthEven: + ld a,iyl ; a = width +;; Data loop { +_RLETSprite_NoClip_Trans: +;;; Read the length of a transparent run and skip that many bytes in the buffer. + ld c,(hl) ; bc = trans run length + inc hl + sub a,c ; a = width remaining after trans run + ex de,hl ; de = sprite, hl = buffer +_RLETSprite_NoClip_TransSkip: + add hl,bc ; skip trans run +;;; Break out of data loop if width remaining == 0. + jr z,_RLETSprite_NoClip_RowEnd ; z ==> width remaining == 0 + ex de,hl ; de = buffer, hl = sprite +_RLETSprite_NoClip_Opaque: +;;; Read the length of an opaque run and copy it to the buffer. + ld c,(hl) ; bc = opaque run length + inc hl + sub a,c ; a = width remaining after opqaue run +_RLETSprite_NoClip_OpaqueCopy: + ldir ; copy opaque run +;;; Continue data loop while width remaining != 0. + jr nz,_RLETSprite_NoClip_Trans ; nz ==> width remaining != 0 + ex de,hl ; de = sprite, hl = buffer +;; } +_RLETSprite_NoClip_RowEnd: +;; Advance buffer pointer to the next row (minus one if width is odd). + ld c,0 ; c = (lcdWidth-width)/2 +_RLETSprite_NoClip_HalfRowDelta_SMC = $-1 + add hl,bc ; advance buffer to next row + add hl,bc + ex de,hl ; de = buffer, hl = sprite +;; Decrement height remaining. Continue row loop while not zero. + dec iyh ; decrement height remaining + jr nz,_RLETSprite_NoClip_Row_WidthEven ; nz ==> height remaining != 0 +_RLETSprite_NoClip_LoopJr_SMC = $-1 +; } +; Done. + ret + +;------------------------------------------------------------------------------- +_ConvertFromRLETSprite: +; Converts a sprite with RLE transpareny to a sprite with normal transparency. +; Arguments: +; arg0 : pointer to gfx_rletsprite_t input +; arg1 : pointer to gfx_sprite_t output +; Returns: +; arg1 : pointer to gfx_sprite_t output + pop bc + pop de ; de = gfx_rletsprite_t *input + ex (sp),hl ; hl = gfx_sprite_t *output + push de + push bc + ex de,hl ; de = output, hl = input +; Save output to return. + push de +; Read and copy the sprite width and height. + ld iy,(hl) ; iyh = height, iyl = width + ldi ; output height = height + ldi ; output width = width, hl = input data +; Initialize values for looping. + inc.s bc ; bcu = 0 +; Row loop { +_ConvertFromRLETSprite_Row: + ld a,iyl ; a = width +;; Data loop { +_ConvertFromRLETSprite_Trans: +;;; Read the length of a transparent run. + ld b,(hl) ; b = trans run length + inc hl + inc b + dec b +;;; Skip the transparent run if the length is zero. + jr z,_ConvertFromRLETSprite_Opaque ; z ==> trans run length == 0 +;;; Write zeros to the output. + sub a,b ; a = width remaining after trans run + ld c,0 ; c = trans color +TColor_SMC_5 = $-1 + ex de,hl ; de = input data, hl = output data +_ConvertFromRLETSprite_TransLoop: + ld (hl),c ; write trans color to output + inc hl + djnz _ConvertFromRLETSprite_TransLoop ; decrement trans run length remaining, + ; nz ==> trans run length remaining != 0 + ex de,hl ; de = output data, hl = input data +;;; Break out of data loop if width remaining == 0. + jr z,_ConvertFromRLETSprite_RowEnd ; z ==> width remaining == 0 +_ConvertFromRLETSprite_Opaque: +;;; Read the length of an opaque run and copy it to the output. + ld c,(hl) ; bc = opaque run length + inc hl + sub a,c ; a = width remaining after opqaue run + ldir ; copy opaque run +;;; Continue data loop while width remaining != 0. + jr nz,_ConvertFromRLETSprite_Trans ; nz ==> width remaining != 0 +;; } +_ConvertFromRLETSprite_RowEnd: +;; Decrement height remaining. Continue row loop while not zero. + dec iyh ; decrement height remaining + jr nz,_ConvertFromRLETSprite_Row ; nz ==> height remaining != 0 +; } +; Return output. + pop hl ; hl = output + ret + +;------------------------------------------------------------------------------- +_ConvertToNewRLETSprite: +; Converts a sprite with normal transpareny to a sprite with RLE transparency, +; allocating the exact amount of necessary space for the converted sprite. +; Arguments: +; arg0 : pointer to gfx_sprite_t input +; arg1 : pointer to malloc +; Returns: +; arg1 : pointer to gfx_rletsprite_t output + pop bc + pop de ; de = gfx_sprite_t *input + ex (sp),hl ; hl = malloc + push de + push bc + ld (_ConvertToNewRLETSprite_Malloc_SMC),hl \.r + ex de,hl ; hl = input +; Save input to copy after allocating output. + push hl +; Read the sprite width and height. + ld iy,(hl) ; iyh = height, iyl = width + inc hl ; hl = -1 +; Initialize values for looping. + inc.s bc ; bcu = 0 + ld de,2 ; de = 2 = output size + ld a,(TColor_SMC_5) \.r ; a = trans color +; Row loop { +_ConvertToNewRLETSprite_Row: + ld b,iyl ; b = width + inc de ; increment output size for first trans run +;; Transparent loop { +_ConvertToNewRLETSprite_TransLoop: + inc hl + cp a,(hl) ; compare an input pixel to trans color + inc de ; increment output size for potential opaque run + jr nz,_ConvertToNewRLETSprite_OpaquePixel ; nz ==> not transparent + dec de ; revert output size, not opaque run +_ConvertToNewRLETSprite_TransPixel: +;;; Continue while width remaining != 0. + djnz _ConvertToNewRLETSprite_TransLoop ; decrement width remaining, + ; nz ==> width remaining != 0 +;; } +;; Finish row. + jr _ConvertToNewRLETSprite_RowEnd +;; Opaque loop { +_ConvertToNewRLETSprite_OpaqueLoop: + inc hl + cp a,(hl) ; compare an input pixel to trans color +_ConvertToNewRLETSprite_OpaquePixel: + inc de ; increment output length + jr z,_ConvertToNewRLETSprite_TransPixel ; z ==> transparent +;;; Continue while width remaining != 0. + djnz _ConvertToNewRLETSprite_OpaqueLoop ; decrement width remaining, + ; nz ==> width remaining != 0 +;; } +_ConvertToNewRLETSprite_RowEnd: +;; Decrement height remaining. Continue row loop while not zero. + dec iyh ; decrement height remaining + jr nz,_ConvertToNewRLETSprite_Row ; nz ==> height remaining != 0 +; } +; Allocate output. + push de + call 0 ; malloc(output size), hl = output +_ConvertToNewRLETSprite_Malloc_SMC = $-3 + pop de +; Convert sprite. + pop de ; de = input + jr _ConvertToRLETSprite_ASM + +;------------------------------------------------------------------------------- +_ConvertToRLETSprite: +; Converts a sprite with normal transpareny to a sprite with RLE transparency. +; Arguments: +; arg0 : pointer to gfx_sprite_t input +; arg1 : pointer to gfx_rletsprite_t output +; Returns: +; arg1 : pointer to gfx_rletsprite_t output + pop bc + pop de ; de = gfx_sprite_t *input + ex (sp),hl ; hl = gfx_rletsprite_t *output + push de + push bc +_ConvertToRLETSprite_ASM: + ex de,hl ; de = output, hl = input +; Save output to return. + push de +; Read and copy the sprite width and height. + ld iy,(hl) ; iyh = height, iyl = width + ldi ; output height = height + ldi ; output width = width, hl = input data +; Initialize values for looping. + inc.s bc ; bcu = 0 + ld a,(TColor_SMC_5) \.r ; a = trans color +; Row loop { +_ConvertToRLETSprite_Row: + ld b,iyl ; b = width +;; Data loop { +_ConvertToRLETSprite_Trans: +;;; Calculate the length of a transparent run. + ld c,0 ; c = 0 = trans run length +;;; Transparent loop { +_ConvertToRLETSprite_TransLoop: + cp a,(hl) ; compare an input pixel to trans color + jr nz,_ConvertToRLETSprite_TransEnd ; nz ==> not transparent + inc hl + inc bc ; increment trans run length +;;;; Continue transparent loop while width remaining != 0. + djnz _ConvertToRLETSprite_TransLoop ; decrement width remaining, + ; nz ==> width remaining != 0 +;;; } +;;; Write the length of the transparent run to the output. +_ConvertToRLETSprite_TransEnd: + ex de,hl ; de = input data, hl = output data + ld (hl),c ; write trans run length + inc hl + ex de,hl ; de = output data, hl = input data +;;; Break out of data loop if width remaining == 0. + jr z,_ConvertToRLETSprite_RowEnd ; z ==> last pixel was transparent + ; ==> width remaining == 0 +;;; Copy an opaque run to the output. +_ConvertToRLETSprite_Opaque: + ld c,0 ; c = 0 = opaque run length + push de ; (sp) = location to write opaque run length + inc de +;;; Opaque loop { +_ConvertToRLETSprite_OpaqueLoop: + cp a,(hl) ; compare an input pixel to trans color + jr z,_ConvertToRLETSprite_OpaqueEnd ; z ==> transparent + inc bc ; cancel dec bc from upcoming ldi + ldi ; copy opaque pixel + inc bc ; increment opaque run length +;;;; Continue opaque/data loop while width remaining != 0. + djnz _ConvertToRLETSprite_OpaqueLoop ; decrement width remaining, + ; nz ==> width remaining != 0 +_ConvertToRLETSprite_OpaqueEnd: + ex (sp),hl ; (sp) = input data, hl = location to write opaque run length + ld (hl),c ; write opaque run length + pop hl ; hl = input data +;;; Continue data loop if width remaining != 0. + jr z,_ConvertToRLETSprite_Trans ; z ==> last pixel was transparent + ; ==> width remaining != 0 +;;; } +;; } +_ConvertToRLETSprite_RowEnd: +;; Decrement height remaining. Continue row loop while not zero. + dec iyh ; decrement height remaining + jr nz,_ConvertToRLETSprite_Row ; nz ==> height remaining != 0 +; } +; Return output. + pop hl ; hl = output + ret + ;------------------------------------------------------------------------------- ; Inner library routines ;------------------------------------------------------------------------------- diff --git a/src/graphx/graphx.h b/src/graphx/graphx.h index c39ae7061..2e2cb7ed0 100644 --- a/src/graphx/graphx.h +++ b/src/graphx/graphx.h @@ -18,7 +18,26 @@ extern "C" { #endif /** - * @brief Defines an image type with which to create sprites + * @brief Sprite (image) type. + * + * Whether or not a sprite includes transparency is not explicitly encoded, and + * is determined only by usage. If used with transparency, transparent pixels + * are those with a certain color index, which can be set with + * gfx_SetTransparentColor(). + * + * @attention + * Displaying a gfx_rletsprite_t (which includes transparency) is significantly + * faster than displaying a gfx_sprite_t with transparency, and should be + * preferred. However, gfx_rletsprite_t does not support transformations, such + * as flipping and rotation. Such transformations can be applied to a + * gfx_sprite_t, which can then be converted to a gfx_rletsprite_t for faster + * display using gfx_ConvertToNewRLETSprite() or gfx_ConvertToRLETSprite(). + * + * @remarks + * Create at compile-time with a tool like + * convpng. + * Create at runtime (with uninitialized data) with gfx_MallocSprite(), + * gfx_UninitedSprite(), or gfx_TempSprite(). */ typedef struct { uint8_t width; /**< Width of the image */ @@ -26,6 +45,27 @@ typedef struct { uint8_t data[1]; /**< Image data array */ } gfx_sprite_t; +/** + * @brief Sprite (image) type with RLE transparency. + * + * @attention + * Displaying a gfx_rletsprite_t (which includes transparency) is significantly + * faster than displaying a gfx_sprite_t with transparency, and should be + * preferred. However, gfx_rletsprite_t does not support transformations, such + * as flipping and rotation. Such transformations can be applied to a + * gfx_sprite_t, which can then be converted to a gfx_rletsprite_t for faster + * display using gfx_ConvertToNewRLETSprite() or gfx_ConvertToRLETSprite(). + * + * @remarks + * Create at compile-time with a tool like + * convpng. + */ +typedef struct { + uint8_t width; /**< Width of the image */ + uint8_t height; /**< Height of the image */ + uint8_t data[1]; /**< Image data array */ +} gfx_rletsprite_t; + /** * @brief A simple structure for working with 2D points */ @@ -43,54 +83,167 @@ typedef enum { } gfx_mode_t; /** - * Allocates memory for a sprite + * Dynamically allocates memory for a sprite. + * + * Allocates the memory with \p malloc_routine. \p width and \p height will be + * set in the allocated sprite. Returns \c NULL upon allocation failure. + * + * @note + * If not used in a dynamic context and \p width and \p height are static, + * consider statically allocating the sprite instead with gfx_UninitedSprite() + * or gfx_TempSprite(). * - * Returns NULL upon failure to allocate space, otherwise a pointer to the sprite structure. - * Note that if you use the system malloc routine, it must be used elsewhere in your program - * otherwise it will not be linked correctly. - * @param width Width of the requested sprite - * @param height Height of the requested sprite - * @param malloc_routine Routine used to allocate memory + * @remarks + * If using \c malloc as the \p malloc_routine, gfx_MallocSprite() can be used + * as a shortcut. + * + * @param width sprite width + * @param height sprite height + * @param malloc_routine malloc implementation to use + * @return pointer to the allocated sprite */ -gfx_sprite_t *gfx_AllocSprite(uint8_t width, uint8_t height, void *malloc_routine); +gfx_sprite_t *gfx_AllocSprite(uint8_t width, uint8_t height, void *(*malloc_routine)(size_t)); /** - * Allocates memory for a sprite + * Dynamically allocates memory for a sprite using \c malloc. + * + * \p width and \p height will be set in the sprite. Returns \c NULL upon + * allocation failure. + * + * @note + * If not used in a dynamic context and \p width and \p height are static, + * consider statically allocating the sprite instead with gfx_UninitedSprite() + * or gfx_TempSprite(). * - * Works the same as gfx_AllocSprite but uses internal malloc routine for allocation. - * @param width Width of the requested sprite - * @param height Height of the requested sprite + * @param width sprite width + * @param height sprite height + * @return pointer to the allocated sprite * @see gfx_AllocSprite */ #define gfx_MallocSprite(width, height) \ -gfx_AllocSprite(width, height, (void*)malloc) +gfx_AllocSprite(width, height, malloc) /** - * Allocates memory for a sprite + * Statically allocates unitialized memory for a sprite. * - * This routine is intended for global variables. - * Note that you will have to initialize the width and height of the sprite manually. - * @param name Name of new sprite - * @param max_width Maximum width sprite will eventually be - * @param max_height Maximum height sprite will eventually be + * Declares a gfx_sprite_t * with the given \p name pointing to the + * allocated memory. \p width and \p height will \b not be set in the sprite, + * unlike gfx_TempSprite(). + * + * @warning + * If used outside of a function body, the memory will be allocated in the + * global unitialized data segment (BSS). If used inside a function body, the + * memory will be allocated on the stack. If the sprite is sufficiently large, + * usage inside a function body will overflow the stack, so it is recommended + * that this normally be used outside of a function body. + * + * @param name name of declared gfx_sprite_t * + * @param width sprite width + * @param height sprite height + * @see gfx_MallocSprite */ -#define gfx_UninitedSprite(name, max_width, max_height) \ -uint8_t name##_data[2 + (max_width) * (max_height)]; \ +#define gfx_UninitedSprite(name, width, height) \ +uint8_t name##_data[2 + (width) * (height)]; \ gfx_sprite_t *name = (gfx_sprite_t *)name##_data - + /** - * Allocates memory for a sprite + * Statically allocates memory for a sprite. * - * This routine is intended for small local variables. - * Note that you will have to initialize the width and height of the sprite manually. - * @param name Name of new sprite - * @param width Width of allocated sprite - * @param height Height of allocated sprite + * Declares a gfx_sprite_t * with the given \p name pointing to the + * allocated memory. \p width and \p height will be set in the sprite, unlike + * gfx_UninitedSprite(). + * + * @attention + * Due to \p width and \p height being set, the memory will be allocated in the + * initialized data segment. If the compiled program is not compressed, then + * this could be a serious source of bloat and gfx_UninitedSprite() should be + * preferred. + * + * @param name name of declared gfx_sprite_t * + * @param width sprite width + * @param height sprite height + * @see gfx_MallocSprite */ #define gfx_TempSprite(name, width, height) \ uint8_t name##_data[2 + (width) * (height)] = { (width), (height) }; \ gfx_sprite_t *name = (gfx_sprite_t *)name##_data +/** + * Dynamically allocates memory for a sprite with RLE transpareny. + * + * Allocates the memory with \p malloc_routine. Returns \c NULL upon allocation + * failure. + * + * \p data_size is the maximum predicted/calculated size of the sprite data + * (excuding the width and height bytes) that will be stored in the allocated + * sprite. Sprite data size could be up to (width + 1) * height * 3 / 2 + * bytes in the worst case, in which pixels horizontally alternate between + * non-transparent and transparent and each row begins with a non-transparent + * pixel. But if the average length of a horizontal transparent run is at least + * 2, then the sprite data will be no larger than (width + 1) * height + * bytes. The exact data size necessary is 2 * + * num_horizontal_transparent_runs + num_non_transparent_pixels + + * num_rows_beginning_with_non_transparent_pixel - + * num_rows_ending_with_transparent_pixel bytes. + * + * @note + * If not used in a dynamic context and \p data_size is static, consider + * statically allocating the sprite instead with gfx_UninitedRLETSprite() or + * gfx_TempRLETSprite(). + * + * @remarks + * If using \c malloc as the \p malloc_routine, gfx_MallocRLETSprite() can be + * used as a shortcut. + * + * @param data_size (maximum) sprite data size + * @param malloc_routine malloc implementation to use + * @return pointer to the allocated sprite + */ +#define gfx_AllocRLETSprite(data_size, malloc_routine) \ +(gfx_rletsprite_t *)(malloc_routine)(data_size) + +/** + * Dynamically allocates memory for a sprite with RLE transparency using \c + * malloc. + * + * \p data_size is the size to allocate for sprite data; see + * gfx_AllocRLETSprite() for information. Returns \c NULL upon allocation + * failure. + * + * @note + * If not used in a dynamic context and \p data_size is static, consider + * statically allocating the sprite instead with gfx_UninitedRLETSprite() or + * gfx_TempRLETSprite(). + * + * @param data_size (maximum) sprite data size + * @return pointer to the allocated sprite + * @see gfx_AllocRLETSprite + */ +#define gfx_MallocRLETSprite(data_size) \ +gfx_AllocRLETSprite(data_size, malloc) + +/** + * Statically allocates unitialized memory for a sprite with RLE transparency. + * + * Declares a gfx_rletsprite_t * with the given \p name pointing to the + * allocated memory. \p data_size is the size to allocate for sprite data; see + * gfx_AllocRLETSprite() for information. + * + * @warning + * If used outside of a function body, the memory will be allocated in the + * global unitialized data segment (BSS). If used inside a function body, the + * memory will be allocated on the stack. If the sprite is sufficiently large, + * usage inside a function body will overflow the stack, so it is recommended + * that this normally be used outside of a function body. + * + * @param name name of declared gfx_rletsprite_t * + * @param data_size (maximum) sprite data size + * @see gfx_MallocRLETSprite + */ +#define gfx_UninitedRLETSprite(name, data_size) \ +uint8_t name##_data[2 + (data_size)]; \ +gfx_rletsprite_t *name = (gfx_rletsprite_t *)name##_data + /** * Initializes the graphics library setup * @param mode Mode to start the library in @@ -335,7 +488,7 @@ void gfx_ZeroScreen(void); /** * Sets a pixel to the global color index * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * Pixels are only clipped within the screen boundaries * @param x X coordinate location * @param y Y coordinate location @@ -346,7 +499,7 @@ void gfx_SetPixel(uint24_t x, uint8_t y); /** * Gets a pixel's color index * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * Pixels are only clipped within the screen boundaries * @param x X coordinate location * @param y Y coordinate location @@ -356,7 +509,7 @@ uint8_t gfx_GetPixel(uint24_t x, uint8_t y); /** * Draws a line * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x0 First X coordinate * @param y0 First Y coordinate * @param x1 Second X coordinate @@ -367,7 +520,7 @@ void gfx_Line(int x0, int y0, int x1, int y1); /** * Draws an unclipped line * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x0 First X coordinate * @param y0 First Y coordinate * @param x1 Second X coordinate @@ -378,7 +531,7 @@ void gfx_Line_NoClip(uint24_t x0, uint8_t y0, uint24_t x1, uint8_t y1); /** * Clips the points in a window region * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x0 First X coordinate * @param y0 First Y coordinate * @param x1 Second X coordinate @@ -390,7 +543,7 @@ bool gfx_CohenSutherlandClip(int *x0, int *y0, int *x1, int *y1); /** * Draws a horizontal line * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * Performs faster than using @c gfx_Line * @param x X coordinate * @param y Y coordinate @@ -401,7 +554,7 @@ void gfx_HorizLine(int x, int y, int length); /** * Draws an unclipped horizontal line * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * Performs faster than using @c gfx_Line * @param x X coordinate * @param y Y coordinate @@ -412,7 +565,7 @@ void gfx_HorizLine_NoClip(uint24_t x, uint8_t y, uint24_t length); /** * Draws a vertical line * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * Performs faster than using @c gfx_Line * @param x X coordinate * @param y Y coordinate @@ -423,7 +576,7 @@ void gfx_VertLine(int x, int y, int length); /** * Draws an unclipped vertical line * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * Performs faster than using @c gfx_Line * @param x X coordinate * @param y Y coordinate @@ -434,7 +587,7 @@ void gfx_VertLine_NoClip(uint24_t x, uint8_t y, uint24_t length); /** * Draws a rectangle outline * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param width Width of rectangle @@ -445,7 +598,7 @@ void gfx_Rectangle(int x, int y, int width, int height); /** * Draws an unclipped rectangle outline * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param width Width of rectangle @@ -456,7 +609,7 @@ void gfx_Rectangle_NoClip(uint24_t x, uint8_t y, uint24_t width, uint8_t height) /** * Draws a filled rectangle * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param width Width of rectangle @@ -467,7 +620,7 @@ void gfx_FillRectangle(int x, int y, int width, int height); /** * Draws an unclipped filled rectangle * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param width Width of rectangle @@ -478,7 +631,7 @@ void gfx_FillRectangle_NoClip(uint24_t x, uint8_t y, uint24_t width, uint8_t hei /** * Draws a circle outline * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param radius The radius of the circle @@ -488,7 +641,7 @@ void gfx_Circle(int x, int y, unsigned radius); /** * Draws a filled circle * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param radius The radius of the circle @@ -498,7 +651,7 @@ void gfx_FillCircle(int x, int y, unsigned radius); /** * Draws an unclipped filled circle * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param radius The radius of the circle @@ -508,7 +661,7 @@ void gfx_FillCircle_NoClip(uint24_t x, uint8_t y, unsigned radius); /** * Draws an unclipped circle outline * - * This is measured from the top left origin of the screen. + * This is measured from the top left origin of the screen. * @param x X coordinate * @param y Y coordinate * @param radius The radius of the circle @@ -519,7 +672,7 @@ gfx_Circle((x), (y), (radius)) /** * Draws a polygon outline * - * Points are measured from the top left origin of the screen. + * Points are measured from the top left origin of the screen. * @code * int points[6] = { * 160, 1, // (x0, y0) @@ -537,7 +690,7 @@ void gfx_Polygon(int *points, unsigned num_points); /** * Draws an unclipped polygon outline * - * Points are measured from the top left origin of the screen. + * Points are measured from the top left origin of the screen. * @code * int points[6] = { * 160, 1, // (x0, y0) @@ -666,14 +819,14 @@ void gfx_SetTextScale(uint8_t width_scale, uint8_t height_scale); /** * Prints a character * - * Outputs a character at the current cursor position. + * Outputs a character at the current cursor position. * @param c Character to print * @note By default, no text clipping is performed (configurable with gfx_SetTextConfig) */ void gfx_PrintChar(const char c); /** - * Prints a signed integer + * Prints a signed integer * * Outputs at the current cursor position. * @param n Integer to print @@ -926,9 +1079,9 @@ gfx_sprite_t *gfx_RotateSpriteHalf(gfx_sprite_t *sprite_in, gfx_sprite_t *sprite gfx_sprite_t *gfx_ScaleSprite(gfx_sprite_t *sprite_in, gfx_sprite_t *sprite_out); /** - * Creates a temporary character sprite - * - * This may be useful for performing rotations and other + * Creates a temporary character sprite + * + * This may be useful for performing rotations and other * operations on characters. The sprite returned is always 8x8 pixels. * @param c Character to generate */ @@ -951,7 +1104,7 @@ void gfx_SetFontSpacing(uint8_t *spacing); /** * Sets the height in pixels of each character - * + * * The default value is 8 pixels * @param height New font height in pixels * @returns Previous height of font in pixels @@ -976,7 +1129,7 @@ unsigned int gfx_GetStringWidth(const char *string); /** * Get pixel width of a character - * + * * @param c Character to get width of * @returns Width in pixels of character * @note Takes into account monospacing flag @@ -1036,7 +1189,7 @@ void gfx_ShiftRight(uint24_t pixels); /** * Lightens a given 1555 color; useful for palette color conversions. - * + * * @param color Original color input in 1555 format * @param amount Amount to lighten by * @returns Darkened color @@ -1046,7 +1199,7 @@ uint16_t gfx_Lighten(uint16_t color, uint8_t amount); /** * Darkens a given 1555 color; useful for palette color conversions. - * + * * @param color Original color input in 1555 format * @param amount Amount to darken by * @returns Darkened color @@ -1056,7 +1209,7 @@ uint16_t gfx_Darken(uint16_t color, uint8_t amount); /** * Fills an area with a color - * + * * @param x X coordinate to begin filling at * @param y Y coordinate to begin filling at * @param color New color to fill with @@ -1065,6 +1218,119 @@ uint16_t gfx_Darken(uint16_t color, uint8_t amount); */ void gfx_FloodFill(unsigned int x, uint8_t y, uint8_t color); +/** + * Draws a sprite with RLE transparency. + * + * @param sprite sprite to draw + * @param x x-coordinate + * @param y y-coordinate + */ +void gfx_RLETSprite(gfx_rletsprite_t *sprite, int x, int y); + +/** + * Draws an unclipped sprite with RLE transparency. + * + * @param sprite sprite to draw + * @param x x-coordinate + * @param y y-coordinate + */ +void gfx_RLETSprite_NoClip(gfx_rletsprite_t *sprite, uint24_t x, uint8_t y); + +/** + * Converts a sprite with RLE transpareny to a sprite with normal transparency. + * + * Width and height will be set in the converted sprite. + * + * The transparent color index in the converted sprite is controlled by + * gfx_SetTransparentColor(). + * + * @attention + * The output sprite must have been allocated with a large enough \c data field + * to hold the converted sprite data, which will be width * height + * bytes large. + * + * @param[in] sprite_in input sprite with RLE transparency + * @param[out] sprite_out converted sprite with normal transparency + * @returns the converted sprite + * @see gfx_ConvertMallocRLETSprite + * @see gfx_ConvertToRLETSprite + */ +gfx_sprite_t *gfx_ConvertFromRLETSprite(gfx_rletsprite_t *sprite_in, gfx_sprite_t *sprite_out); + +/** + * Converts a sprite with normal transpareny to a sprite with RLE transparency. + * + * Width and height will be set in the converted sprite. + * + * The transparent color index in the input sprite is controlled by + * gfx_SetTransparentColor(). + * + * @attention + * The output sprite must have been allocated with a large enough data field to + * hold the converted sprite data; see gfx_AllocRLETSprite() for information. + * + * @note + * To avoid needing to predict the output size and risking either the prediction + * being too high and wasting space, or being too low and corrupting memory, + * gfx_ConvertMallocRLETSprite() can be used instead to allocate the exact + * amount of necessary space for the converted sprite. + * + * @param[in] sprite_in input sprite with normal transparency + * @param[out] sprite_out converted sprite with RLE transparency + * @returns the converted sprite + * @see gfx_ConvertFromRLETSprite + */ +gfx_rletsprite_t *gfx_ConvertToRLETSprite(gfx_sprite_t *sprite_in, gfx_rletsprite_t *sprite_out); + + +/** + * Converts a sprite with normal transpareny to a sprite with RLE transparency, + * allocating the exact amount of necessary space for the converted sprite. + * + * Allocates the memory with \p malloc_routine. Width and height will be set in + * the converted sprite. Returns \c NULL upon allocation failure. + * + * The transparent color index in the input sprite is controlled by + * gfx_SetTransparentColor(). + * + * @remarks + * If using \c malloc as the \p malloc_routine, gfx_ConvertMallocRLETSprite() + * can be used as a shortcut. + * + * @remarks + * A gfx_sprite_t can be converted into an appropriately large, + * already-allocated gfx_rletsprite_t using gfx_ConvertToRLETSprite(). + * + * @param sprite_in input sprite with normal transparency + * @param malloc_routine malloc implementation to use + * @returns a newly allocated converted sprite with RLE transparency + * @see gfx_ConvertFromRLETSprite + */ +gfx_rletsprite_t *gfx_ConvertToNewRLETSprite(gfx_sprite_t *sprite_in, void *(*malloc_routine)(size_t)); + +/** + * Converts a sprite with normal transpareny to a sprite with RLE transparency, + * allocating the exact amount of necessary space for the converted sprite using + * \c malloc. + * + * Width and height will be set in the converted sprite. Returns \c NULL upon + * allocation failure. + * + * The transparent color index in the input sprite is controlled by + * gfx_SetTransparentColor(). + * + * @remarks + * A gfx_sprite_t can be converted into an appropriately large, + * already-allocated gfx_rletsprite_t using gfx_ConvertToRLETSprite(). + * + * @param sprite_in input sprite with normal transparency + * @param malloc_routine malloc implementation to use + * @returns a newly allocated converted sprite with RLE transparency + * @see gfx_ConvertFromRLETSprite + */ +#define gfx_ConvertMallocRLETSprite(sprite_in) \ +gfx_ConvertToNewRLETSprite(sprite_in, malloc) + /** * Converts an RGB value to a palette color *