diff --git a/cpctelera/src/macros/allmacros.h.s b/cpctelera/src/macros/allmacros.h.s index cc2010584..956570562 100644 --- a/cpctelera/src/macros/allmacros.h.s +++ b/cpctelera/src/macros/allmacros.h.s @@ -20,6 +20,7 @@ .include "macros/cpct_opcodeConstants.h.s" .include "macros/cpct_reverseBits.h.s" .include "macros/cpct_undocumentedOpcodes.h.s" +.include "macros/cpct_luts.h.s" ;;////////////////////////////////////////////////////////////////////// ;; Group: General Useful Macros diff --git a/cpctelera/src/macros/cpct_luts.h.s b/cpctelera/src/macros/cpct_luts.h.s new file mode 100644 index 000000000..1747d4680 --- /dev/null +++ b/cpctelera/src/macros/cpct_luts.h.s @@ -0,0 +1,79 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- + +;; +;; File: LUTs (Look-Up-Tables) +;; +;; Useful macros for accessing and managing Look-Up-Tables +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Macro: cpctm_lutget8 +;; +;; Gets a value from a 256-byte-max 8-bit table into A register +;; +;; Parameters: +;; Table - Memory address where the 256-byte-max table starts. It can be +;; either an hexadecimal, decimal or octal address, or a symbol (the table name). +;; TR1 - An 8-bits register from the set {B, D, H} +;; TR2 - An 8-bits register from the set {C, E, L}. This register must +;; match TR1 to form a valid 16-bits register (BC, DE or HL), as the register TR1'TR2 +;; will be loaded with the address of the table, to be the base pointer. +;; +;; Input Registers: +;; A - Index in the LUT to be accessed. +;; +;; Return Value: +;; A - Value got from the LUT ( table[TR1'TR2 + A] ) +;; +;; Details: +;; This macro gets a value from a table into the A register. The process is simple: +;; +;; 1. It loads the address of the table in the 16-bits register TR1'TR2 +;; 2. It adds the index (A) to TR1'TR2 (TR1'TR2 += A) +;; 3. It loads into A register the byte pointed by TR1'TR2 +;; +;; Modified Registers: +;; AF, TR1, TR2 +;; +;; Required memory: +;; 9 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs(us) | CPU Cycles +;; ------------------------------------ +;; Any | 10 | 40 +;; ------------------------------------ +;; (end code) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.macro cpctm_lutget8 Table, TR1, TR2 + ld TR1'TR2, #Table ;; [3] TR1_TR2 points to the LUT + + ;; Compute TR1'TR2 += A + add TR2 ;; [1] | TR2 += A + ld TR2, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc TR1 ;; [1] | TR1 += Carry + ld TR1, a ;; [1] | + + ;; A = *(TR1_TR2 + A) + ld a, (TR1'TR2) ;; [2] A = Value stored at given index from the LUT +.endm + diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0.asm b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0.asm new file mode 100644 index 000000000..a40ef9e87 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0.asm @@ -0,0 +1,203 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_drawSpriteColorizeM0 +;; +;; Directly replace a color and draw a sprite to video memory. +;; +;; C Definition: +;; void (void* *sprite*, void* *memory*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (8 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') memory - Destination video memory pointer +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L ) oldColor - Color to replace +;; (1B H ) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_drawSpriteColorizeM0_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be *width* x *height*. +;; * *memory* could be any place in memory, inside or outside current video memory. It +;; will be equally treated as video memory (taking into account CPC's video memory +;; disposition). This lets you copy sprites to software or hardware backbuffers, and +;; not only video memory. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 0 : 1 byte = 2 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 15) to replace +;; * *newColor* must be the index of the new color (0 to 15) +;; +;; Known limitations: +;; * This function does not do any kind of boundary check or clipping. If you +;; try to draw sprites on the frontier of your video memory or screen buffer +;; if might potentially overwrite memory locations beyond boundaries. This +;; could cause your program to behave erratically, hang or crash. Always +;; take the necessary steps to guarantee that you are drawing inside screen +;; or buffer boundaries. +;; * As this function receives a byte-pointer to memory, it can only +;; draw byte-sized and byte-aligned sprites. This means that the box cannot +;; start on non-byte aligned pixels (like odd-pixels, for instance) and +;; their sizes must be a multiple of a byte (2 in mode 0, 4 in mode 1 and +;; 8 in mode 2). +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 118 bytes +;; ASM-bindings - 108 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 29 + (62 + 23W)H | 116 + (248 + 92W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 1757 | 7028 +;; W=4,H=32 | 4957 | 19828 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes, HH = [(H-1)/8] +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode0_ct + +;; Macro to convert Pixel to xAxC xBxD format +.macro convertPixel + ;; From cpct_px2byteM0 + ld bc, #dc_mode0_ct ;; [3] BC points to conversion table (dc_mode0_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : xAxC xBxD + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : xAxC xBxD + + ld c, #0x55 ;; [2] C = Mask to get pixel A : xAxC xBxD + + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld (startLine), de ;; [6] Store DE start line (DestMem) + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABAB ABAB + and c ;; [2] A |= C (C = 0x55) : xBxB xBxB + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +;; Pixel Mode 0 = ABAB ABAB +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : xBxB xBxB + ld a, l ;; [1] L = A current Byte of sprite : ABAB ABAB + rrca ;; [1] A (current byte of sprite) >> 1 : ABAB ABAB -> xABA BABA + and c ;; [2] A |= Mask (0x55) : xAxA xAxA + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rlca ;; [1] A = xAxA xAxA << 1 : AxAx AxAx + or h ;; [1] A |= H (xBxB xBxB) : ABAB ABAB + + exx ;; [1] Switch to Alternate registers + +drawByte: + ld (de), a ;; [2] Update current sprite byte with pixels + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if B != 0 goto lineLoop + + dec c ;; [1] Decrement C (Height) + jr z, end ;; [2/3] If C == O goto end + +startLine = .+1 ;; Placeholder for the Start line adress + ld de, #0000 ;; [3] DE = Start Line + + ld a, d ;; [1] Start of next pixel line normally is 0x0800 bytes away. + add #0x08 ;; [2] so we add it to DE (just by adding 0x08 to D) + ld d, a ;; [1] + and #0x38 ;; [2] We check if we have crossed memory boundary (every 8 pixel lines).. + + jr nz, convertLoop ;; [2/3] .. by checking the 4 bits that identify present memory line. + ;; .... If 0, we have crossed boundaries + +dms_sprite_8bit_boundary_crossed: + ld a, e ;; [1] DE = DE + 0xC050h + add #0x50 ;; [2] -- Relocate DE pointer to the start of the next pixel line: + ld e, a ;; [1] -- DE is moved forward 3 memory banks plus 50 bytes (4000h * 3) + ld a, d ;; [1] -- which effectively is the same as moving it 1 bank backwards and then + adc #0xC0 ;; [2] -- 50 bytes forwards (which is what we want to move it to the next pixel line) + ld d, a ;; [1] -- Calculations are made with 8 bit maths as it is faster than other alternatives here + + jr convertLoop ;; [3] Jump to continue with next pixel line + +end: + ;; Return is included in bindings + + diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0_asmbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0_asmbindings.s new file mode 100644 index 000000000..073609b70 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2017 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_drawSpriteColorizeM0_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +;;.include /cpct_drawSpriteColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0_cbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0_cbindings.s new file mode 100644 index 000000000..f4ad4b2f5 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteColorizeM0_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2017 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 33 us, 10 bytes +;; +_cpct_drawSpriteColorizeM0:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Memory + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_drawSpriteColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0.asm b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0.asm new file mode 100644 index 000000000..981c21ab2 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0.asm @@ -0,0 +1,215 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.globl dc_mode0_ct + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_drawSpriteMaskedAlignedColorizeM0 +;; +;; Directly replace a color and draw a sprite Masked Aligned to video memory. +;; +;; C Definition: +;; void (void* *sprite*, void* *memory*, *width*, *height*, +;; *oldColor*, *newColor*, *pmasktable*) __z88dk_callee; +;; +;; Input Parameters (10 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') memory - Destination video memory pointer +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B E ) oldColor - Color to replace +;; (1B D ) newColor - New color +;; (2B HL) pmasktable - Pointer to the aligned mask table used to create transparency +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_drawSpriteMaskedAlignedColorizeM0_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be *width* x *height*. +;; * *memory* could be any place in memory, inside or outside current video memory. It +;; will be equally treated as video memory (taking into account CPC's video memory +;; disposition). This lets you copy sprites to software or hardware backbuffers, and +;; not only video memory. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 0 : 1 byte = 2 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 15) to replace +;; * *newColor* must be the index of the new color (0 to 15) +;; +;; Known limitations: +;; * This function does not do any kind of boundary check or clipping. If you +;; try to draw sprites on the frontier of your video memory or screen buffer +;; if might potentially overwrite memory locations beyond boundaries. This +;; could cause your program to behave erratically, hang or crash. Always +;; take the necessary steps to guarantee that you are drawing inside screen +;; or buffer boundaries. +;; * As this function receives a byte-pointer to memory, it can only +;; draw byte-sized and byte-aligned sprites. This means that the box cannot +;; start on non-byte aligned pixels (like odd-pixels, for instance) and +;; their sizes must be a multiple of a byte (2 in mode 0, 4 in mode 1 and +;; 8 in mode 2). +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 112 bytes +;; ASM-bindings - 96 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 32 + (58 + 20W)H | 128 + (232 + 80W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 1600 | 6400 +;; W=4,H=32 | 4448 | 17792 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes, HH = [(H-1)/8] +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Macro to convert Pixel to xAxC xBxD format +.macro convertPixel + ;; From cpct_px2byteM0 + ld bc, #dc_mode0_ct ;; [3] BC points to conversion table (dc_mode0_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : xAxC xBxD + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld b, d + ld d, a ;; [1] | D = A old color : xAxC xBxD + + ld c, #0x55 ;; [2] C = Mask to get pixel A : xAxC xBxD + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + push de ;; [4] Store DE start line (DestMem) + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABAB ABAB + and c ;; [2] A |= C (C = 0x55) : xBxB xBxB + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +;; Pixel Mode 0 = ABAB ABAB +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : xBxB xBxB + ld a, l ;; [1] L = A current Byte of sprite : ABAB ABAB + rrca ;; [1] A (current byte of sprite) >> 1 : ABAB ABAB -> xABA BABA + and c ;; [2] A |= Mask (0x55) : xAxA xAxA + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rlca ;; [1] A = xAxA xAxA << 1 : AxAx AxAx + or h ;; [1] A |= H (xBxB xBxB) : ABAB ABAB + +drawByte: + ld h, b ;; [1] H = B (Masked table adress High Byte) + ld l, a ;; [1] Access mask table element (table must be 256-byte aligned) + exx ;; [1] Switch to Alternate registers + + ld a, (de) ;; [2] Get the value of the byte of the screen where we are going to draw + exx ;; [1] Switch to Default registers + + and (hl) ;; [2] Erase background part that is to be overwritten (Mask step 1) + or l ;; [1] Add up background and sprite information in one byte (Mask step 2) + exx ;; [1] Switch to Alternate registers + + ld (de), a ;; [2] Save modified background + sprite data information into memory + + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if B != 0 goto lineLoop + + dec c ;; [1] Decrement C (Height) + jr z, end ;; [2/3] If C == O goto end + + pop de ;; [3] Restore DE start line (DestMem) + + ld a, d ;; [1] Start of next pixel line normally is 0x0800 bytes away. + add #0x08 ;; [2] so we add it to DE (just by adding 0x08 to D) + ld d, a ;; [1] + and #0x38 ;; [2] We check if we have crossed memory boundary (every 8 pixel lines).. + + jr nz, convertLoop ;; [2/3] .. by checking the 4 bits that identify present memory line. + ;; .... If 0, we have crossed boundaries + +dms_sprite_8bit_boundary_crossed: + ld a, e ;; [1] DE = DE + 0xC050h + add #0x50 ;; [2] -- Relocate DE pointer to the start of the next pixel line: + ld e, a ;; [1] -- DE is moved forward 3 memory banks plus 50 bytes (4000h * 3) + ld a, d ;; [1] -- which effectively is the same as moving it 1 bank backwards and then + adc #0xC0 ;; [2] -- 50 bytes forwards (which is what we want to move it to the next pixel line) + ld d, a ;; [1] -- Calculations are made with 8 bit maths as it is faster than other alternatives here + + jr convertLoop ;; [3] Jump to continue with next pixel line + +end: + pop de ;; [3] Empty stack by getting last element (DestMem) + ;; Return is included in bindings + + diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0_asmbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0_asmbindings.s new file mode 100644 index 000000000..f566e8fc5 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2017 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_drawSpriteMaskedAlignedColorizeM0_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +.include /cpct_drawSpriteMaskedAlignedColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0_cbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0_cbindings.s new file mode 100644 index 000000000..f8953c60b --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedAlignedColorizeM0_cbindings.s @@ -0,0 +1,52 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2017 Arnaud Bouche (Arnaud6128) +;; Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 39 us, 16 bytes +;; +_cpct_drawSpriteMaskedAlignedColorizeM0:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx ;; [1] Switch to Alternate registers + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Memory + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + + exx ;; [1] Switch to Default registers + pop de ;; [3] DE = (D = newColor, E = oldColor) + + ex (sp), hl ;; [6] HL = Table Mask address + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + + ex de, hl ;; [1] HL <-> DE + +.include /cpct_drawSpriteMaskedAlignedColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0.asm b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0.asm new file mode 100644 index 000000000..8f63f4c99 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0.asm @@ -0,0 +1,216 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2017 Arnaud Bouche +;; Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.globl dc_mode0_ct + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_drawSpriteMaskedColorizeM0 +;; +;; Directly replace a color and draw a sprite Masked to video memory. +;; +;; C Definition: +;; void (void* *sprite*, void* *memory*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (8 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') memory - Destination video memory pointer +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L ) oldColor - Color to replace +;; (1B H ) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_drawSpriteMaskedColorizeM0_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format +;; along with mask data. Each mask byte will contain enabled bits as those that should +;; be picked from the background (transparent) and disabled bits for those that will +;; be printed from sprite colour data. Each mask data byte must precede its associated +;; colour data byte. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be +;; 2 x *width* x *height* (mask data doubles array size). +;; * *memory* could be any place in memory, inside or outside current video memory. It +;; will be equally treated as video memory (taking into account CPC's video memory +;; disposition). This lets you copy sprites to software or hardware backbuffers, and +;; not only video memory. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 0 : 1 byte = 2 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 15) to replace +;; * *newColor* must be the index of the new color (0 to 15) +;; +;; Known limitations: +;; * This function does not do any kind of boundary check or clipping. If you +;; try to draw sprites on the frontier of your video memory or screen buffer +;; if might potentially overwrite memory locations beyond boundaries. This +;; could cause your program to behave erratically, hang or crash. Always +;; take the necessary steps to guarantee that you are drawing inside screen +;; or buffer boundaries. +;; * As this function receives a byte-pointer to memory, it can only +;; draw byte-sized and byte-aligned sprites. This means that the box cannot +;; start on non-byte aligned pixels (like odd-pixels, for instance) and +;; their sizes must be a multiple of a byte (2 in mode 0, 4 in mode 1 and +;; 8 in mode 2). +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 115 bytes +;; ASM-bindings - 102 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; Best | 29 + (50 + 36W)H | 116 + (200 + 144W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 1981 | 7924 +;; W=4,H=32 | 6237 | 24948 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes, HH = [(H-1)/8] +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Macro to convert Pixel to xAxC xBxD format +.macro convertPixel + ;; From cpct_px2byteM0 + ld bc, #dc_mode0_ct ;; [3] BC points to conversion table (dc_mode0_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : xAxC xBxD + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : xAxC xBxD + + ld c, #0x55 ;; [2] C = Mask to get pixel A : xAxC xBxD + + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld (startLine), de ;; [6] Store DE start line (DestMem) + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + inc hl ;; [2] Next byte sprite Color source + ld a, (hl) ;; [2] A = (HL) current Byte of sprite Color + dec hl ;; [2] Previous byte sprite Mask source + + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABAB ABAB + and c ;; [2] A |= C (C = 0x55) : xBxB xBxB + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +;; Pixel Mode 0 = ABAB ABAB +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : xBxB xBxB + ld a, l ;; [1] L = A current Byte of sprite : ABAB ABAB + rrca ;; [1] A (current byte of sprite) >> 1 : ABAB ABAB -> xABA BABA + and c ;; [2] A |= Mask (0x55) : xAxA xAxA + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rlca ;; [1] A = xAxA xAxA << 1 : AxAx AxAx + or h ;; [1] A |= H (xBxB xBxB) : ABAB ABAB + +drawByte: + exx ;; [1] Switch to Alternate registers + ld (sprite_color), a ;; [4] sprite_color = A (Sprite Byte) + + ld a, (de) ;; [2] Get next background byte into A + and (hl) ;; [2] Erase background part that is to be overwritten (Mask step 1) + inc hl ;; [3] HL += 1 => Point HL to Sprite Colour information +sprite_color = .+1 ;; Placeholder for the Sprite Color computed + or #00 ;; [2] Add up background and sprite information in one byte (Mask step 2) + ld (de), a ;; [2] Save modified background + sprite data information into memory + + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte Dest Memory + djnz lineLoop ;; [3] Decrement B (Width) if B != 0 goto lineLoop + + dec c ;; [1] Decrement C (Height) + jr z, end ;; [2/3] If C == O goto end + +startLine = .+1 ;; Placeholder for the Start line adress + ld de, #0000 ;; [3] DE = Start Line + + ld a, d ;; [1] Start of next pixel line normally is 0x0800 bytes away. + add #0x08 ;; [2] so we add it to DE (just by adding 0x08 to D) + ld d, a ;; [1] + and #0x38 ;; [2] We check if we have crossed memory boundary (every 8 pixel lines).. + + jr nz, convertLoop ;; [2/3] .. by checking the 4 bits that identify present memory line. + ;; .... If 0, we have crossed boundaries + +dms_sprite_8bit_boundary_crossed: + ld a, e ;; [1] DE = DE + 0xC050h + add #0x50 ;; [2] -- Relocate DE pointer to the start of the next pixel line: + ld e, a ;; [1] -- DE is moved forward 3 memory banks plus 50 bytes (4000h * 3) + ld a, d ;; [1] -- which effectively is the same as moving it 1 bank backwards and then + adc #0xC0 ;; [2] -- 50 bytes forwards (which is what we want to move it to the next pixel line) + ld d, a ;; [1] -- Calculations are made with 8 bit maths as it is faster than other alternatives here + + jr convertLoop ;; [3] Jump to continue with next pixel line + +end: + ;; Return is included in bindings \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0_asmbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0_asmbindings.s new file mode 100644 index 000000000..48bc1ef3c --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_drawSpriteMaskedColorizeM0_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +.include /cpct_drawSpriteMaskedColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0_cbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0_cbindings.s new file mode 100644 index 000000000..18f336eb5 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_drawSpriteMaskedColorizeM0_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 33 us, 13 bytes +;; +_cpct_drawSpriteMaskedColorizeM0:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Memory + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_drawSpriteMaskedColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f.asm b/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f.asm new file mode 100644 index 000000000..b87415992 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f.asm @@ -0,0 +1,98 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_setSpriteColourizeM0_f +;; +;; Sets the concrete colour that will be replaced by when called. +;; +;; C Definition: +;; void ( *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (1B L ) oldColor - Colour to be replaced (Palette Index, 0-15) +;; (1B H ) newColor - New colour (Palette Index, 0-15) +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_setSpriteColourizeM0_f_asm +;; +;; Parameter Restrictions: +;; * *oldColor* must be the palette index of the colour to be replaced (0 to 15). +;; * *newColor* must be the palette index of the new colour (0 to 15). +;; +;; Known limitations: +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; +;; Details: +;; +;; +;; Destroyed Register values: +;; A, BC, HL +;; +;; Required memory: +;; C-bindings - 37 bytes +;; ASM-bindings - 35 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; Any | 52 | 208 +;; ---------------------------------------------------------------- +;; Asm saving | -9 | -36 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode0_ct ;; Look-Up-Table to convert Palette Indexes to 4-bits pixel 1 screen format patterns +.include "macros/cpct_luts.h.s" ;; Macros to easily access the Look-Up-Table +;; Symbols for placeholders inside the Colourize function +.globl cpct_spriteColourizeM0_px1_newval +.globl cpct_spriteColourizeM0_px0_newval +.globl cpct_spriteColourizeM0_px1_oldval +.globl cpct_spriteColourizeM0_px0_oldval + + ;; Use Look-Up-Table to convert palette index colour to screen pixel format + ;; This conversion is for the Pixel 1 into the two pixels each byte has in mode 0 [0,1] + ;; Therefore, only bits x0x2x1x3 will be produced. + + ;; Convert newColour to pixel format + ld a, h ;; [1] A = H new colour index + cpctm_lutget8 dc_mode0_ct, b, c ;; [10] Get from Look-Up-Table dc_mode0_ct[BC + A] + ld (cpct_spriteColourizeM0_px1_newval), a ;; [4] Write Pixel 1 format (x0x2x1x3) into Colourize function code + rlca ;; [1] Convert Pixel 1 format to Pixel 0, shifting bits to the left + ld (cpct_spriteColourizeM0_px0_newval), a ;; [4] Write Pixel 0 format (0x2x1x3x) into Colourize function code + + ;; Convert oldColour to pixel format + ld a, l ;; [1] A = L old colour index + cpctm_lutget8 dc_mode0_ct, b, c ;; [10] Get from Look-Up-Table dc_mode0_ct[BC + A] + ld (cpct_spriteColourizeM0_px1_oldval), a ;; [4] Write Pixel 1 format (x0x2x1x3) into Colourize function code + rlca ;; [1] Convert Pixel 1 format to Pixel 0, shifting bits to the left + ld (cpct_spriteColourizeM0_px0_oldval), a ;; [4] Write Pixel 0 format (0x2x1x3x) into Colourize function code + +ret ;; [3] Return to the caller diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f_asmbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f_asmbindings.s new file mode 100644 index 000000000..5db953ec9 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f_asmbindings.s @@ -0,0 +1,28 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_setSpriteColourizeM0_f_asm:: ;; Assembly entry point + +.include /cpct_setSpriteColourizeM0_f.asm/ diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f_cbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f_cbindings.s new file mode 100644 index 000000000..7abe81e14 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_setSpriteColourizeM0_f_cbindings.s @@ -0,0 +1,35 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 9 us, 2 bytes +;; +_cpct_setSpriteColourizeM0_f:: + ;; GET Parameters from the stack + pop hl ;; [3] HL = Return Address + ex (sp), hl ;; [6] H = newColour, L = oldColour + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_setSpriteColourizeM0_f.asm/ diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0.asm b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0.asm new file mode 100644 index 000000000..f319db09c --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0.asm @@ -0,0 +1,166 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_spriteColorizeM0 +;; +;; Replace a color in a sprite and copy to another or the same sprite. +;; +;; C Definition: +;; void (void* *sprite*, void* *spriteColor*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') spriteColor - Destination Sprite Pointer (can be also the Source Sprite) (array of pixel data) +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L ) oldColor - Color to replace +;; (1B H ) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_spriteColorizeM0_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be *width* x *height*. +;; * *spriteColor* must be an array containing the new sprite's pixels data with the new color. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 0 : 1 byte = 2 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 15) to replace +;; * *newColor* must be the index of the new color (0 to 15) +;; +;; Known limitations: +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 81 bytes +;; ASM-bindings - 67 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 29 + (6 + 33W)H | 116 + (24 + 132W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 1181 | 4724 +;; W=4,H=32 | 4445 | 17780 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode0_ct + +;; Macro to convert Pixel to xAxC xBxD format +.macro convertPixel + ;; From cpct_px2byteM0 + ld bc, #dc_mode0_ct ;; [3] BC points to conversion table (dc_mode0_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : xAxC xBxD + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : xAxC xBxD + + ld c, #0x55 ;; [2] C = Mask to get pixel A : xAxC xBxD + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABAB ABAB + and c ;; [2] A |= C (C = 0x55) : xBxB xBxB + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +;; Pixel Mode 0 = ABAB ABAB +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : xBxB xBxB + ld a, l ;; [1] L = A current Byte of sprite : ABAB ABAB + rrca ;; [1] A (current byte of sprite) >> 1 : ABAB ABAB -> xABA BABA + and c ;; [2] A |= Mask (0x55) : xAxA xAxA + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rlca ;; [1] A = xAxA xAxA << 1 : AxAx AxAx + or h ;; [1] A |= H (xBxB xBxB) : ABAB ABAB + +setByte: + exx ;; [1] Switch to Alternate registers + + ld (de), a ;; [2] Update current sprite byte with pixels + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if != 0 goto lineLoop + +nextLine: + dec c ;; [1] Decrement C (Height) + jr nz, convertLoop ;; [2/3] If != O goto convertLoop + +end: + ;; Return is included in bindings + diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0_asmbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0_asmbindings.s new file mode 100644 index 000000000..3339b8ea5 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_spriteColorizeM0_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +.include /cpct_spriteColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0_cbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0_cbindings.s new file mode 100644 index 000000000..27d164918 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColorizeM0_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 33 us, 14 bytes +;; +_cpct_spriteColorizeM0:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Sprite color + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_spriteColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f.asm b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f.asm new file mode 100644 index 000000000..472cafb3a --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f.asm @@ -0,0 +1,137 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_spriteColourizeM0_f +;; +;; Replace one concrete colour of a sprite by a different one. This function +;; does the replacement, use to pick up colours. +;; +;; C Definition: +;; void ( *width*, *height*, void* *sprite*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (2B HL) sprite - Source Sprite Pointer (array of pixel data) +;; (1B C ) height - Sprite Height in bytes (>0) +;; (1B B ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_spriteColourizeM0_f_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be a pointer to the start of an array containing sprite's pixels data +;; in screen pixel format. Sprite must be rectangular and all bytes in the array must be +;; consecutive pixels, starting from top-left corner and going left-to-right, top-to-bottom +;; down to the bottom-right corner. Total amount of bytes in pixel array should be *width* x *height*. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; +;; Details: +;; +;; +;; Known limitations: +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL +;; +;; Required memory: +;; C-bindings - 38 bytes +;; ASM-bindings - 35 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; Best Case | 21 + (5 + 27W)H | 84 + (20 + 108W)H +;; Worst Case | 21 + (5 + 29W)H | 84 + (20 + 116W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 965 / 1029 | 3860 / 4116 +;; W=4,H=32 | 3637 / 3893 | 14548 / 15572 +;; ---------------------------------------------------------------- +;; Asm saving | -12 | -48 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Save width value to restore it after each line +ld a, b ;; [1] A = width +ld (w_restore), a ;; [4] Save width into its restore place + +;; As E register is free, use it as a cache for Pixel 1 Pattern of the colour to be replaced +px1_oldval = .+1 +ld e, #00 ;; [2] E = Pixel 1 4-bit Pattern of the colour to be replaced (x0x2x1x3) + +;; Loop through all the bytes of the sprite, replacing colours that have the same +;; 4-bit pattern of the colour we want to replace. +loop: + ;; Check and replace Pixel 1 + ld a, (hl) ;; [2] A = Byte with 2 Mode 0 Pixels to be replaced + and #0b01010101 ;; [2] A ^= 0x55. Left out only the 4 bits of the Pixel 1 (x0x2x1x3) + ld d, a ;; [1] D = holds a copy of Pixel 1 bits, just in case we don't have to replace it + cp e ;; [1] A == E? Check if A is equal to the Pixel 1 Pattern of the colour we want to replace + jr nz, notpx1 ;; [2/3] If it is not equal, just continue to check pixel 0 + px1_newval = .+1 + ld d, #00 ;; [2] Perform replacement of Pixel 1. D holds the 4 bits of the new colour. #00 is a placeholder + notpx1: + + ;; Check and replace Pixel 0 + ld a, (hl) ;; [2] A = Restore the value of the byte with the 2 Mode 0 pixels to be replaced + and #0b10101010 ;; [2] A ^= 0xAA. Left out only the 4 bits of the Pixel 0 (0x2x1x3x) + px0_oldval = .+1 + cp #00 ;; [2] Check if A is equal to the Pixel 0 Pattern of the colour we want to replace. #00 is a placeholder + jr nz, notpx0 ;; [2/3] If it is not equal, just continue to mix both output values + px0_newval = .+1 + ld a, #00 ;; [2] Perform replacement of Pixel 0. A holds the 4 bits of the new colour. #00 is a placeholder + notpx0: + + ;; Mix both replacements and save + or d ;; [1] A |= C. A and C hold replacements for pixels 0 and 1. This mixes them into A. + ld (hl), a ;; [2] Write byte with colours replaced + inc hl ;; [2] HL++ Move to next byte of the sprite + + djnz loop ;; [3/4] B--. Continue looping if there are more bytes left in this sprite line (B!=0) + + w_restore=.+1 + ld b, #00 ;; [2] B = width (restore value). #00 is a placeholder + dec c ;; [1] C-- (One less line of the sprite to process) + jr nz, loop ;; [2/3] Continue looping if there are more lines left + + ret ;; [3] Return to caller + +;; +;; Global symbols to be used by external functions to set placeholders +;; +cpct_spriteColourizeM0_px0_oldval == px0_oldval +cpct_spriteColourizeM0_px1_oldval == px1_oldval +cpct_spriteColourizeM0_px0_newval == px0_newval +cpct_spriteColourizeM0_px1_newval == px1_newval diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f_asmbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f_asmbindings.s new file mode 100644 index 000000000..00053edc2 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f_asmbindings.s @@ -0,0 +1,28 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_spriteColourizeM0_f_asm:: ;; Assembly entry point + +.include /cpct_spriteColourizeM0_f.asm/ diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f_cbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f_cbindings.s new file mode 100644 index 000000000..c382388de --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteColourizeM0_f_cbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 12 us, 3 bytes +;; +_cpct_spriteColourizeM0_f:: + ;; GET Parameters from the stack + pop hl ;; [3] HL = Return Address + pop bc ;; [3] B = Width, C = Height + ex (sp), hl ;; [6] HL = Pointer to the sprite + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_spriteColourizeM0_f.asm/ diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0.asm b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0.asm new file mode 100644 index 000000000..37a32f02e --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0.asm @@ -0,0 +1,175 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_spriteMaskedColorizeM0 +;; +;; Replace a color in a Masked sprite and copy to another or the same sprite. +;; +;; C Definition: +;; void (void* *sprite*, void* *spriteColor*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') spriteColor - Destination Sprite Pointer (can be also the Source Sprite) (array of pixel data) +;; (1B C') height - Sprite Height in bytes (>0) +;; (1B B') width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L) oldColor - Color to replace +;; (1B H) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_spriteMaskedColorizeM0_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format +;; along with mask data. Each mask byte will contain enabled bits as those that should +;; be picked from the background (transparent) and disabled bits for those that will +;; be printed from sprite colour data. Each mask data byte must precede its associated +;; colour data byte. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be +;; 2 x *width* x *height* (mask data doubles array size). +;; * *spriteColor* must be an array containing the new sprite's pixels data with the new color. +;; Total amount of bytes in pixel array should be 2 x *width* x *height* (mask data doubles array size). +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 0 : 1 byte = 2 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 15) to replace +;; * *newColor* must be the index of the new color (0 to 15) +;; +;; Known limitations: +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 87 bytes +;; ASM-bindings - 73 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 29 + (41 + 6W)H | 116 + (164 + 24W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 2109 | 8436 +;; W=4,H=32 | 877 | 3508 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes, HH = [(H-1)/8] +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode0_ct + +;; Macro to convert Pixel to xAxC xBxD format +.macro convertPixel + ;; From cpct_px2byteM0 + ld bc, #dc_mode0_ct ;; [3] BC points to conversion table (dc_mode0_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : xAxC xBxD + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : xAxC xBxD + + ld c, #0x55 ;; [2] C = Mask to get pixel A : xAxC xBxD + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite Mask + ld (de), a ;; [2] (DE) = A Copy of sprite Mask + inc hl ;; [2] Next byte sprite Color source + inc de ;; [2] Next byte sprite Color destination + ld a, (hl) ;; [2] A = (HL) current Byte of sprite Color + + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABAB ABAB + and c ;; [2] A |= C (C = 0x55) : xBxB xBxB + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +;; Pixel Mode 0 = ABAB ABAB +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : xBxB xBxB + ld a, l ;; [1] L = A current Byte of sprite : ABAB ABAB + rrca ;; [1] A (current byte of sprite) >> 1 : ABAB ABAB -> xABA BABA + and c ;; [2] A |= Mask (0x55) : xAxA xAxA + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rlca ;; [1] A = xAxA xAxA << 1 : AxAx AxAx + or h ;; [1] A |= H (xBxB xBxB) : ABAB ABAB + +setByte: + exx ;; [1] Switch to Alternate registers + + ld (de), a ;; [2] Update current sprite byte with pixels + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if != 0 goto lineLoop + + dec c ;; [1] Decrement C (Height) + jr nz, convertLoop ;; [2/3] If C == O goto end + +end: + ;; Return is included in bindings \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0_asmbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0_asmbindings.s new file mode 100644 index 000000000..04b8fcf88 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_spriteMaskedColorizeM0_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +.include /cpct_spriteMaskedColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0_cbindings.s b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0_cbindings.s new file mode 100644 index 000000000..3dad1ae84 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M0/cpct_spriteMaskedColorizeM0_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "../../../macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 33 us, 14 bytes +;; +_cpct_spriteMaskedColorizeM0:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Sprite color + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_spriteMaskedColorizeM0.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1.asm b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1.asm new file mode 100644 index 000000000..639f3ced5 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1.asm @@ -0,0 +1,228 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_drawSpriteColorizeM1 +;; +;; Directly replace a color and draw a sprite to video memory. +;; +;; C Definition: +;; void (void* *sprite*, void* *memory*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') memory - Destination video memory pointer +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L ) oldColor - Color to replace +;; (1B H ) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_drawSpriteColorizeM1_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be *width* x *height*. +;; * *memory* could be any place in memory, inside or outside current video memory. It +;; will be equally treated as video memory (taking into account CPC's video memory +;; disposition). This lets you copy sprites to software or hardware backbuffers, and +;; not only video memory. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 1 : 1 byte = 4 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 3) to replace +;; * *newColor* must be the index of the new color (0 to 3) +;; +;; Known limitations: +;; * This function does not do any kind of boundary check or clipping. If you +;; try to draw sprites on the frontier of your video memory or screen buffer +;; if might potentially overwrite memory locations beyond boundaries. This +;; could cause your program to behave erratically, hang or crash. Always +;; take the necessary steps to guarantee that you are drawing inside screen +;; or buffer boundaries. +;; * As this function receives a byte-pointer to memory, it can only +;; draw byte-sized and byte-aligned sprites. This means that the box cannot +;; start on non-byte aligned pixels (like odd-pixels, for instance) and +;; their sizes must be a multiple of a byte (2 in mode 0, 4 in mode 1 and +;; 8 in mode 2). +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 116 bytes +;; ASM-bindings - 103 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 29 + (36 + 61W)H | 116 + (144 + 244W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 2557 | 10228 +;; W=4,H=32 | 8989 | 35956 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode1_ct + +;; Macro to convert color to pixel Mode1 : Axxx Axxx +.macro convertPixel ;; From cpct_px2byteM1 + ld bc, #dc_mode1_ct ;; [3] BC points to conversion table (dc_mode1_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : Axxx Axxx + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : Axxx Axxx + + ld c, #0x88 ;; [2] C = Mask to get pixel A : Axxx Axxx + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld (startLine), de ;; [6] Store DE start line (DestMem) + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABCD ABCD + and c ;; [2] A |= C (C = 0x88) : Axxx Axxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : Axxx Axxx + + sla l ;; [2] L (current byte of sprite) << 1 : ABCD ABCD -> BCDx BCDx + ld a, l ;; [1] A = L : BCDx BCDx + and c ;; [2] A |= Mask (0x88) : Bxxx Bxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + or h ;; [1] A |= H (color byte) : Axxx Axxx + ld h, a ;; [1] H = A : ABxx ABxx + + sla l ;; [2] L ( BCDx BCDx) << 1 : CDxx CDxx + ld a, l ;; [1] A = L : CDxx CDxx + and c ;; [1] A |= C (C = 0x88) : Cxxx Cxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelC ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelC: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xxCx xxCx << 1 : xxCx xxCx + or h ;; [1] A |= H (ABxx ABxx) : ABCx ABCx + ld h, a ;; [1] H = A : ABCx ABCx + + sla l ;; [2] L (BCDx BCDx) << 1 : Dxxx Dxxx + ld a, l ;; [1] A = L : Dxxx Dxxx + and c ;; [1] A |= C (C = 0x88) : Dxxx Dxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelD ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelD: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xBxx xBxx >> 1 : xxCx xxCx + rrca ;; [1] A = xxCx xxxx >> 1 : xxxD xxxD + or h ;; [1] A |= H (ABCx ABCx) : ABCD ABCD + + exx ;; [1] Switch to Alternate registers + + ld (de), a ;; [2] Update current sprite byte with pixels + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if B != 0 goto lineLoop + + dec c ;; [1] Decrement C (Height) + jr z, end ;; [2/3] If C == O goto end + +startLine = .+1 ;; Placeholder for the Start line adress + ld de, #0000 ;; [3] DE = Start Line + + ld a, d ;; [1] Start of next pixel line normally is 0x0800 bytes away. + add #0x08 ;; [2] so we add it to DE (just by adding 0x08 to D) + ld d, a ;; [1] + and #0x38 ;; [2] We check if we have crossed memory boundary (every 8 pixel lines).. + + jr nz, convertLoop ;; [2/3] .. by checking the 4 bits that identify present memory line. + ;; .... If 0, we have crossed boundaries + +dms_sprite_8bit_boundary_crossed: + ld a, e ;; [1] DE = DE + 0xC050h + add #0x50 ;; [2] -- Relocate DE pointer to the start of the next pixel line: + ld e, a ;; [1] -- DE is moved forward 3 memory banks plus 50 bytes (4000h * 3) + ld a, d ;; [1] -- which effectively is the same as moving it 1 bank backwards and then + adc #0xC0 ;; [2] -- 50 bytes forwards (which is what we want to move it to the next pixel line) + ld d, a ;; [1] -- Calculations are made with 8 bit maths as it is faster than other alternatives here + + jr convertLoop ;; [3] Jump to continue with next pixel line + +end: + ;; Return is included in bindings + diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1_asmbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1_asmbindings.s new file mode 100644 index 000000000..cf9a0b239 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1_asmbindings.s @@ -0,0 +1,35 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_drawSpriteColorizeM1_asm:: ;; Assembly entry point + +;; GET Parameters from the stack +ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + +.include /cpct_drawSpriteColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1_cbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1_cbindings.s new file mode 100644 index 000000000..b7908d4f7 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteColorizeM1_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 31 us, 13 bytes +;; +_cpct_drawSpriteColorizeM1:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Memory + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_drawSpriteColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1.asm b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1.asm new file mode 100644 index 000000000..3abd98527 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1.asm @@ -0,0 +1,239 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_drawSpriteMaskedAlignedColorizeM1 +;; +;; Directly replace a color and draw a sprite Masked Aligned to video memory. +;; +;; C Definition: +;; void (void* *sprite*, void* *memory*, *width*, *height*, +;; *oldColor*, *newColor*, *pmasktable*) __z88dk_callee; +;; +;; Input Parameters (10 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') memory - Destination video memory pointer +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B E ) oldColor - Color to replace +;; (1B D ) newColor - New color +;; (2B HL) pmasktable - Pointer to the aligned mask table used to create transparency +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_drawSpriteMaskedAlignedColorizeM1_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be *width* x *height*. +;; * *memory* could be any place in memory, inside or outside current video memory. It +;; will be equally treated as video memory (taking into account CPC's video memory +;; disposition). This lets you copy sprites to software or hardware backbuffers, and +;; not only video memory. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 0 : 1 byte = 4 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 3) to replace +;; * *newColor* must be the index of the new color (0 to 3) +;; +;; Known limitations: +;; * This function does not do any kind of boundary check or clipping. If you +;; try to draw sprites on the frontier of your video memory or screen buffer +;; if might potentially overwrite memory locations beyond boundaries. This +;; could cause your program to behave erratically, hang or crash. Always +;; take the necessary steps to guarantee that you are drawing inside screen +;; or buffer boundaries. +;; * As this function receives a byte-pointer to memory, it can only +;; draw byte-sized and byte-aligned sprites. This means that the box cannot +;; start on non-byte aligned pixels (like odd-pixels, for instance) and +;; their sizes must be a multiple of a byte (2 in mode 0, 4 in mode 1 and +;; 8 in mode 2). +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 133 bytes +;; ASM-bindings - 117 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 32 + (33 + 75W)H | 128 + (132 + 300W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 2960 | 11840 +;; W=4,H=32 | 10688 | 42752 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes, HH = [(H-1)/8] +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode1_ct + +;; Macro to convert color to pixel Mode1 : Axxx Axxx +.macro convertPixel ;; From cpct_px2byteM1 + ld bc, #dc_mode1_ct ;; [3] BC points to conversion table (dc_mode1_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by HL +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : Axxx Axxx + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : Axxx Axxx + + ld c, #0x88 ;; [2] C = Mask to get pixel A : Axxx Axxx + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + push de ;; [4] Store DE start line (DestMem) + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite Mask + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABCD ABCD + and c ;; [2] A |= C (C = 0x88) : Axxx Axxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : Axxx Axxx + + sla l ;; [2] L (current byte of sprite) << 1 : ABCD ABCD -> BCDx BCDx + ld a, l ;; [1] A = L : BCDx BCDx + and c ;; [2] A |= Mask (0x88) : Bxxx Bxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + or h ;; [1] A |= H (color byte) : Axxx Axxx + ld h, a ;; [1] H = A : ABxx ABxx + + sla l ;; [2] L ( BCDx BCDx) << 1 : CDxx CDxx + ld a, l ;; [1] A = L : CDxx CDxx + and c ;; [1] A |= C (C = 0x88) : Cxxx Cxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelC ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelC: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xxCx xxCx << 1 : xxCx xxCx + or h ;; [1] A |= H (ABxx ABxx) : ABCx ABCx + ld h, a ;; [1] H = A : ABCx ABCx + + sla l ;; [2] L (BCDx BCDx) << 1 : Dxxx Dxxx + ld a, l ;; [1] A = L : Dxxx Dxxx + and c ;; [1] A |= C (C = 0x88) : Dxxx Dxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelD ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelD: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xBxx xBxx >> 1 : xxCx xxCx + rrca ;; [1] A = xxCx xxxx >> 1 : xxxD xxxD + or h ;; [1] A |= H (ABCx ABCx) : ABCD ABCD + + exx ;; [1] Switch to Alternate registers + +drawByte: + push hl ;; [4] Store HL (current byte sprite source) + ld h, b ;; [1] H = B (Masked table adress High Byte) + ld l, a ;; [1] Access mask table element (table must be 256-byte aligned) + ld a, (de) ;; [2] Get the value of the byte of the screen where we are going to draw + and (hl) ;; [2] Erase background part that is to be overwritten (Mask step 1) + or l ;; [1] Add up background and sprite information in one byte (Mask step 2) + ld (de), a ;; [2] Save modified background + sprite data information into memory + pop hl ;; [3] Recover HL (current byte sprite source) + + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if B != 0 goto lineLoop + + dec c ;; [1] Decrement C (Height) + jr z, end ;; [2/3] If C == O goto end + + pop de ;; [3] Restore DE start line (DestMem + + ld a, d ;; [1] Start of next pixel line normally is 0x0800 bytes away. + add #0x08 ;; [2] so we add it to DE (just by adding 0x08 to D) + ld d, a ;; [1] + and #0x38 ;; [2] We check if we have crossed memory boundary (every 8 pixel lines).. + + jr nz, convertLoop ;; [2/3] .. by checking the 4 bits that identify present memory line. + ;; .... If 0, we have crossed boundaries + +dms_sprite_8bit_boundary_crossed: + ld a, e ;; [1] DE = DE + 0xC050h + add #0x50 ;; [2] -- Relocate DE pointer to the start of the next pixel line: + ld e, a ;; [1] -- DE is moved forward 3 memory banks plus 50 bytes (4000h * 3) + ld a, d ;; [1] -- which effectively is the same as moving it 1 bank backwards and then + adc #0xC0 ;; [2] -- 50 bytes forwards (which is what we want to move it to the next pixel line) + ld d, a ;; [1] -- Calculations are made with 8 bit maths as it is faster than other alternatives here + + jr convertLoop ;; [3] Jump to continue with next pixel line + +end: + pop de ;; [3] Empty stack by getting last element (DestMem) + ;; Return is included in bindings + diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1_asmbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1_asmbindings.s new file mode 100644 index 000000000..e2c4f6f9d --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_drawSpriteMaskedAlignedColorizeM1_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +.include /cpct_drawSpriteMaskedAlignedColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1_cbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1_cbindings.s new file mode 100644 index 000000000..531ee8094 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedAlignedColorizeM1_cbindings.s @@ -0,0 +1,53 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2017 Arnaud Bouche (Arnaud6128) +;; Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 39 us, 16 bytes +;; +_cpct_drawSpriteMaskedAlignedColorizeM1:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx ;; [1] Switch to Alternate registers + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Memory + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + + exx ;; [1] Switch to Default registers + pop de ;; [3] DE = (D = newColor, E = oldColor) + + ex (sp), hl ;; [6] HL = Table Mask address + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + + ex de, hl ;; [1] HL <-> DE + + +.include /cpct_drawSpriteMaskedAlignedColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1.asm b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1.asm new file mode 100644 index 000000000..c49b89f33 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1.asm @@ -0,0 +1,246 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_drawSpriteMaskedColorizeM1 +;; +;; Directly replace a color and draw a sprite Masked to video memory. +;; +;; C Definition: +;; void (void* *sprite*, void* *memory*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (8 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') memory - Destination video memory pointer +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L ) oldColor - Color to replace +;; (1B H ) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_drawSpriteMaskedColorizeM1_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format +;; along with mask data. Each mask byte will contain enabled bits as those that should +;; be picked from the background (transparent) and disabled bits for those that will +;; be printed from sprite colour data. Each mask data byte must precede its associated +;; colour data byte. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be +;; 2 x *width* x *height* (mask data doubles array size). +;; * *memory* could be any place in memory, inside or outside current video memory. It +;; will be equally treated as video memory (taking into account CPC's video memory +;; disposition). This lets you copy sprites to software or hardware backbuffers, and +;; not only video memory. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 0 : 1 byte = 4 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 3) to replace +;; * *newColor* must be the index of the new color (0 to 3) +;; +;; Known limitations: +;; * This function does not do any kind of boundary check or clipping. If you +;; try to draw sprites on the frontier of your video memory or screen buffer +;; if might potentially overwrite memory locations beyond boundaries. This +;; could cause your program to behave erratically, hang or crash. Always +;; take the necessary steps to guarantee that you are drawing inside screen +;; or buffer boundaries. +;; * As this function receives a byte-pointer to memory, it can only +;; draw byte-sized and byte-aligned sprites. This means that the box cannot +;; start on non-byte aligned pixels (like odd-pixels, for instance) and +;; their sizes must be a multiple of a byte (2 in mode 0, 4 in mode 1 and +;; 8 in mode 2). +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 142 bytes +;; ASM-bindings - 129 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 29 + (36 + 93W)H | 116 + (144 + 372W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 3581 | 14324 +;; W=4,H=32 | 13085 | 52340 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode1_ct + +;; Macro to convert color to pixel Mode1 : Axxx Axxx +.macro convertPixel ;; From cpct_px2byteM1 + ld bc, #dc_mode1_ct ;; [3] BC points to conversion table (dc_mode1_ct) + + ;; Compute BC += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | B += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : Axxx Axxx + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : Axxx Axxx + + ld c, #0x88 ;; [2] C = First Mask to get pixel A : Axxx Axxx + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld (startLine), de ;; [6] Store DE start line (DestMem) + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + inc hl ;; [2] Next byte sprite Color source + ld a, (hl) ;; [2] A = (HL) current Byte of sprite Color + dec hl ;; [2] Previous byte sprite Mask source + + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABCD ABCD + + and c ;; [2] A |= C (C = 0x88) : Axxx Axxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : Axxx Axxx + + sla l ;; [2] L (current byte of sprite) << 1 : ABCD ABCD -> BCDx BCDx + ld a, l ;; [1] A = L : BCDx BCDx + and c ;; [2] A |= Mask (0x88) : Bxxx Bxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + or h ;; [1] A |= H (color byte) : Axxx Axxx + ld h, a ;; [1] H = A : ABxx ABxx + + sla l ;; [2] L ( BCDx BCDx) << 1 : CDxx CDxx + ld a, l ;; [1] A = L : CDxx CDxx + and c ;; [1] A |= C (C = 0x88) : Cxxx Cxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelC ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelC: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xxCx xxCx << 1 : xxCx xxCx + or h ;; [1] A |= H (ABxx ABxx) : ABCx ABCx + ld h, a ;; [1] H = A : ABCx ABCx + + sla l ;; [2] L (BCDx BCDx) << 1 : Dxxx Dxxx + ld a, l ;; [1] A = L : Dxxx Dxxx + and c ;; [1] A |= C (C = 0x88) : Dxxx Dxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelD ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelD: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xBxx xBxx >> 1 : xxCx xxCx + rrca ;; [1] A = xxCx xxxx >> 1 : xxxD xxxD + or h ;; [1] A |= H (ABCx ABCx) : ABCD ABCD + + exx ;; [1] Switch to Alternate registers + +drawByte: + ld (sprite_color), a ;; [4] sprite_color = A (Sprite Byte) + + ld a, (de) ;; [2] Get next background byte into A + and (hl) ;; [2] Erase background part that is to be overwritten (Mask step 1) + inc hl ;; [3] HL += 1 => Point HL to Sprite Colour information +sprite_color = .+1 ;; Placeholder for the Sprite Color computed + or #00 ;; [2] Add up background and sprite information in one byte (Mask step 2) + ld (de), a ;; [2] Save modified background + sprite data information into memory + + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte Dest Memory + djnz lineLoop ;; [3] Decrement B (Width) if B != 0 goto lineLoop + + dec c ;; [1] Decrement C (Height) + jr z, end ;; [2/3] If C == O goto end + +startLine = .+1 ;; Placeholder for the Start line adress + ld de, #0000 ;; [3] DE = Start Line + + ld a, d ;; [1] Start of next pixel line normally is 0x0800 bytes away. + add #0x08 ;; [2] so we add it to DE (just by adding 0x08 to D) + ld d, a ;; [1] + and #0x38 ;; [2] We check if we have crossed memory boundary (every 8 pixel lines).. + + jr nz, convertLoop ;; [2/3] .. by checking the 4 bits that identify present memory line. + ;; .... If 0, we have crossed boundaries + +dms_sprite_8bit_boundary_crossed: + ld a, e ;; [1] DE = DE + 0xC050h + add #0x50 ;; [2] -- Relocate DE pointer to the start of the next pixel line: + ld e, a ;; [1] -- DE is moved forward 3 memory banks plus 50 bytes (4000h * 3) + ld a, d ;; [1] -- which effectively is the same as moving it 1 bank backwards and then + adc #0xC0 ;; [2] -- 50 bytes forwards (which is what we want to move it to the next pixel line) + ld d, a ;; [1] -- Calculations are made with 8 bit maths as it is faster than other alternatives here + + jr convertLoop ;; [3] Jump to continue with next pixel line + +end: + ;; Return is included in bindings + diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1_asmbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1_asmbindings.s new file mode 100644 index 000000000..097551a0f --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_drawSpriteMaskedColorizeM1_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +.include /cpct_drawSpriteMaskedColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1_cbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1_cbindings.s new file mode 100644 index 000000000..c497bdf07 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_drawSpriteMaskedColorizeM1_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 33 us, 13 bytes +;; +_cpct_drawSpriteMaskedColorizeM1:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Memory + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_drawSpriteMaskedColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1.asm b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1.asm new file mode 100644 index 000000000..282449e43 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1.asm @@ -0,0 +1,194 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_spriteColorizeM1 +;; +;; Replace a color in a sprite and copy to another or the same sprite. +;; +;; C Definition: +;; void (void* *sprite*, void* *spriteColor*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') spriteColor - Destination Sprite Pointer (can be also the Source Sprite) (array of pixel data) +;; (1B C' ) height - Sprite Height in bytes (>0) +;; (1B B' ) width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L ) oldColor - Color to replace +;; (1B H ) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_spriteColorizeM1_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be *width* x *height*. +;; * *spriteColor* must be an array containing the new sprite's pixels data with the new color. +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 1 : 1 byte = 4 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 3) to replace +;; * *newColor* must be the index of the new color (0 to 3) +;; +;; Known limitations: +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 73 bytes +;; ASM-bindings - 60 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 29 + (6 + 61W)H | 116 + (24 + 244W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 2077 | 8308 +;; W=4,H=32 | 8029 | 32116 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +.globl dc_mode1_ct + +;; Macro to convert color to pixel Mode1 : Axxx Axxx +.macro convertPixel ;; From cpct_px2byteM1 + ld bc, #dc_mode1_ct ;; [3] BC points to conversion table (dc_mode1_ct) + + ;; Compute HL += A + add c ;; [1] | C += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | L += Carry + ld b, a ;; [1] | + + ;; A = *(BC + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by BC +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : Axxx Axxx + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : Axxx Axxx + + ld c, #0x88 ;; [2] C = First Mask to get pixel A : Axxx Axxx + + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABCD ABCD + and c ;; [2] A |= C (C = 0x88) : Axxx Axxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : Axxx Axxx + + sla l ;; [2] L (current byte of sprite) << 1 : ABCD ABCD -> BCDx BCDx + ld a, l ;; [1] A = L : BCDx BCDx + and c ;; [2] A |= Mask (0x88) : Bxxx Bxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + or h ;; [1] A |= H (color byte) : Axxx Axxx + ld h, a ;; [1] H = A : ABxx ABxx + + sla l ;; [2] L ( BCDx BCDx) << 1 : CDxx CDxx + ld a, l ;; [1] A = L : CDxx CDxx + and c ;; [1] A |= C (C = 0x88) : Cxxx Cxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelC ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelC: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xxCx xxCx << 1 : xxCx xxCx + or h ;; [1] A |= H (ABxx ABxx) : ABCx ABCx + ld h, a ;; [1] H = A : ABCx ABCx + + sla l ;; [2] L (BCDx BCDx) << 1 : Dxxx Dxxx + ld a, l ;; [1] A = L : Dxxx Dxxx + and c ;; [1] A |= C (C = 0x88) : Dxxx Dxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelD ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelD: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xBxx xBxx >> 1 : xxCx xxCx + rrca ;; [1] A = xxCx xxxx >> 1 : xxxD xxxD + or h ;; [1] A |= H (ABCx ABCx) : ABCD ABCD + +setByte: + exx ;; [1] Switch to Alternate registers + + ld (de), a ;; [2] Update current sprite byte with pixels + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if != 0 goto lineLoop + +nextLine: + dec c ;; [1] Decrement C (Height) + jr nz, convertLoop ;; [2/3] If != O goto convertLoop + +end: + ;; Return is included in bindings + diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1_asmbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1_asmbindings.s new file mode 100644 index 000000000..067488591 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1_asmbindings.s @@ -0,0 +1,35 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_spriteColorizeM1_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + +.include /cpct_spriteColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1_cbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1_cbindings.s new file mode 100644 index 000000000..2b2e810b7 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteColorizeM1_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 33 us, 13 bytes +;; +_cpct_spriteColorizeM1:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Sprite color + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_spriteColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1.asm b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1.asm new file mode 100644 index 000000000..2da556b00 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1.asm @@ -0,0 +1,205 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_spriteMaskedColorizeM1 +;; +;; Replace a color in a Masked sprite and copy to another or the same sprite. +;; +;; C Definition: +;; void (void* *sprite*, void* *spriteColor*, *width*, *height*, *oldColor*, *newColor*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (2B HL') sprite - Source Sprite Pointer (array of pixel data) +;; (2B DE') spriteColor - Destination Sprite Pointer (can be also the Source Sprite) (array of pixel data) +;; (1B C') height - Sprite Height in bytes (>0) +;; (1B B') width - Sprite Width in *bytes* (Beware, *not* in pixels!) +;; (1B L) oldColor - Color to replace +;; (1B H) newColor - New color +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_spriteMaskedColorizeM1_asm +;; +;; Parameter Restrictions: +;; * *sprite* must be an array containing sprite's pixels data in screen pixel format +;; along with mask data. Each mask byte will contain enabled bits as those that should +;; be picked from the background (transparent) and disabled bits for those that will +;; be printed from sprite colour data. Each mask data byte must precede its associated +;; colour data byte. +;; Sprite must be rectangular and all bytes in the array must be consecutive pixels, +;; starting from top-left corner and going left-to-right, top-to-bottom down to the +;; bottom-right corner. Total amount of bytes in pixel array should be +;; 2 x *width* x *height* (mask data doubles array size). +;; * *spriteColor* must be an array containing the new sprite's pixels data with the new color. +;; Total amount of bytes in pixel array should be 2 x *width* x *height* (mask data doubles array size). +;; * *width* must be the width of the sprite *in bytes*. Always remember that the width must be +;; expressed in bytes and *not* in pixels. +;; The correspondence is mode 1 : 1 byte = 4 pixels +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; There is no practical upper limit to this value. Height of a sprite in +;; bytes and pixels is the same value, as bytes only group consecutive pixels in +;; the horizontal space. +;; * *oldColor* must be the index of color (0 to 3) to replace +;; * *newColor* must be the index of the new color (0 to 3) +;; +;; Known limitations: +;; * This function *will not work from ROM*, as it uses self-modifying code. +;; * This function requires the CPC firmware to be DISABLED. Otherwise, random crashes might happen due to side effects. +;; +;; Destroyed Register values: +;; AF, BC, DE, HL, BC', DE', HL', IX +;; +;; Required memory: +;; C-bindings - 110 bytes +;; ASM-bindings - 97 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; | 29 + (6 + 71W)H | 116 + (24 + 284W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 2397 | 9588 +;; W=4,H=32 | 9309 | 37236 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes +;; +;; Credits: +;; Original routine optimized by @Docent and discussed in CPCWiki : +;; http://www.cpcwiki.eu/forum/programming/cpctelera-colorize-sprite/ +;; +;; Thanks to all of them for their help and support. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +.globl dc_mode1_ct + +;; Macro to convert color to pixel Mode1 : Axxx Axxx +.macro convertPixel ;; From cpct_px2byteM1 + ld bc, #dc_mode1_ct ;; [3] HL points to conversion table (dc_mode1_ct) + + ;; Compute HL += A + add c ;; [1] | L += A + ld c, a ;; [1] | + sub a ;; [1] A = 0 (preserving Carry Flag) + adc b ;; [1] | H += Carry + ld b, a ;; [1] | + + ;; A = *(HL + A) + ld a, (bc) ;; [2] A = Value stored at the table pointed by HL +.endm + + ;; Convert newColor to pixel format (E) + ld a, h ;; [1] A = H new color index + convertPixel ;; [10] | Convert into A + ld e, a ;; [1] | E = A new color : Axxx Axxx + + ;; Convert oldColor to pixel format (D) + ld a, l ;; [1] A = L old color index + convertPixel ;; [10] | Convert into A + ld d, a ;; [1] | D = A old color : Axxx Axxx + + ld c, #0x88 ;; [2] C = First Mask to get pixel A : Axxx Axxx + + exx ;; [1] Switch to Alternate registers + + ld__ixl_c ;; [1] IXL = C (Width) + ld c, b ;; [1] C = B (Height) + +convertLoop: + ld__b_ixl ;; [2] B = IXL (Sprite Width) + +lineLoop: + ld a, (hl) ;; [2] A = (HL) current Byte of sprite Mask + ld (de), a ;; [2] (DE) = A Copy of sprite Mask + inc hl ;; [2] Next byte sprite Color source + inc de ;; [2] Next byte sprite Color destination + ld a, (hl) ;; [2] A = (HL) current Byte of sprite Color + + exx ;; [1] Switch to Default registers + + ld l, a ;; [1] L = A current Byte of sprite : ABCD ABCD + + and c ;; [2] A |= C (C = 0x88) : Axxx Axxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelA ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelA: + ld h, a ;; [1] H = A (current colorized sprite) : Axxx Axxx + + sla l ;; [2] L (current byte of sprite) << 1 : ABCD ABCD -> BCDx BCDx + ld a, l ;; [1] A = L : BCDx BCDx + and c ;; [2] A |= Mask (0x88) : Bxxx Bxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelB ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelB: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + or h ;; [1] A |= H (color byte) : Axxx Axxx + ld h, a ;; [1] H = A : ABxx ABxx + + sla l ;; [2] L ( BCDx BCDx) << 1 : CDxx CDxx + ld a, l ;; [1] A = L : CDxx CDxx + and c ;; [1] A |= C (C = 0x88) : Cxxx Cxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelC ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelC: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xxCx xxCx << 1 : xxCx xxCx + or h ;; [1] A |= H (ABxx ABxx) : ABCx ABCx + ld h, a ;; [1] H = A : ABCx ABCx + + sla l ;; [2] L (BCDx BCDx) << 1 : Dxxx Dxxx + ld a, l ;; [1] A = L : Dxxx Dxxx + and c ;; [1] A |= C (C = 0x88) : Dxxx Dxxx + + cp d ;; [1] Test if pixel (A) is the old colour to be replaced (D) + jr nz, readPixelD ;; [2/3] If not equal go to next pixel + ld a, e ;; [1] else A = new colour to set (E) + +readPixelD: + rrca ;; [1] A = Axxx Axxx >> 1 : xBxx xBxx + rrca ;; [1] A = xBxx xBxx >> 1 : xxCx xxCx + rrca ;; [1] A = xxCx xxxx >> 1 : xxxD xxxD + or h ;; [1] A |= H (ABCx ABCx) : ABCD ABCD + +setByte: + exx ;; [1] Switch to Alternate registers + + ld (de), a ;; [2] Update current sprite byte with pixels + inc hl ;; [2] Next byte sprite source + inc de ;; [2] Next byte sprite colorized + djnz lineLoop ;; [3] Decrement B (Width) if != 0 goto lineLoop + +nextLine: + dec c ;; [1] Decrement C (Height) + jr nz, convertLoop ;; [2/3] If != O goto convertLoop + +end: + ;; Return is included in bindings \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1_asmbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1_asmbindings.s new file mode 100644 index 000000000..c9884cea5 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1_asmbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; ASM bindings for +;; +cpct_spriteMaskedColorizeM1_asm:: ;; Assembly entry point + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + +.include /cpct_spriteMaskedColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1_cbindings.s b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1_cbindings.s new file mode 100644 index 000000000..c47007c43 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/M1/cpct_spriteMaskedColorizeM1_cbindings.s @@ -0,0 +1,48 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche (@Arnaud6128) +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +.include "macros/cpct_undocumentedOpcodes.h.s" + +;; +;; C bindings for +;; +;; 33 us, 13 bytes +;; +_cpct_spriteMaskedColorizeM1:: + + ;; GET Parameters from the stack + ld (dms_restore_ix + 2), ix ;; [6] Save IX to restore it before returning + pop hl ;; [3] HL = Return Address + + exx + pop hl ;; [3] HL' = Source address (Sprite) + pop de ;; [3] DE' = Destination Sprite color + pop bc ;; [5] BC' = (B = Sprite Height, C = Width) + exx + + ex (sp), hl ;; [6] HL = (H = newColor, L = oldColor) + ;; ... and leave Return Address at (SP) as we don't need to restore + ;; ... stack status because callin convention is __z88dk_callee + +.include /cpct_spriteMaskedColorizeM1.asm/ + +dms_restore_ix: + ld ix, #0000 ;; [4] Restore IX before returning + ret ;; [3] Return to caller \ No newline at end of file diff --git a/cpctelera/src/sprites/colorReplace/colorReplace.h b/cpctelera/src/sprites/colorReplace/colorReplace.h new file mode 100644 index 000000000..d5675f624 --- /dev/null +++ b/cpctelera/src/sprites/colorReplace/colorReplace.h @@ -0,0 +1,49 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2018 Arnaud Bouche (Arnaud6128) +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------- + +//##################################################################### +//### MODULE: Sprites +//### SUBMODULE: ColorReplace +//##################################################################### +//### This module contains routines to replace colors in sprites +//##################################################################### +// + +#ifndef CPCT_COLORREPLACE_H +#define CPCT_COLORREPLACE_H + +// Functions to replace a color in sprite M0 +extern void cpct_spriteColorizeM0(u8* sprite, u8* spriteColor, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; +extern void cpct_spriteMaskedColorizeM0(u8* sprite, u8* spriteColor, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; + +// Functions to draw a sprite M0 with a color replaced +extern void cpct_drawSpriteColorizeM0(u8* sprite, u8* destMem, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; +extern void cpct_drawSpriteMaskedColorizeM0(u8* sprite, u8* destMem, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; +extern void cpct_drawSpriteMaskedAlignedColorizeM0(u8* sprite, u8* destMem, u8 width, u8 height, u8 oldColor, u8 newColor, const u8* maskTable) __z88dk_callee; + +// Functions to replace a color in sprite M1 +extern void cpct_spriteColorizeM1(u8* sprite, u8* spriteColor, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; +extern void cpct_spriteMaskedColorizeM1(u8* sprite, u8* spriteColor, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; + +// Functions to draw a sprite M1 with a color replaced +extern void cpct_drawSpriteColorizeM1(u8* sprite, u8* destMem, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; +extern void cpct_drawSpriteMaskedColorizeM1(u8* sprite, u8* destMem, u8 width, u8 height, u8 oldColor, u8 newColor) __z88dk_callee; +extern void cpct_drawSpriteMaskedAlignedColorizeM1(u8* sprite, u8* destMem, u8 width, u8 height, u8 oldColor, u8 newColor, const u8* maskTable) __z88dk_callee; + +#endif \ No newline at end of file diff --git a/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite.asm b/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite.asm new file mode 100644 index 000000000..5c8920ae8 --- /dev/null +++ b/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite.asm @@ -0,0 +1,187 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud BOUCHE +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Function: cpct_getScreenToSprite +;; +;; Copies sprite data from screen video memory to a linear array (a sprite) +;; +;; C Definition: +;; void (void* *memory*, void* *sprite*, *width*, *height*) __z88dk_callee; +;; +;; Input Parameters (6 bytes): +;; (2B HL) memory - Source Screen Address (Video memory location) +;; (2B DE) sprite - Destination Sprite Address (Sprite data array) +;; (1B C ) width - Sprite Width in *bytes* (>0) (Beware, *not* in pixels!) +;; (1B B ) height - Sprite Height in bytes (>0) +;; +;; Assembly call (Input parameters on registers): +;; > call cpct_getScreenToSprite_asm +;; +;; Parameter Restrictions: +;; * *memory* could be any place in memory, inside or outside current video memory. It +;; will be equally treated as video memory (taking into account CPC's video memory +;; disposition). This lets you copy software or hardware backbuffers, and +;; not only video memory. +;; * *sprite* must be a pointer to the start of a linear array that will be filled +;; up with sprite pixel data got from *memory*. +;; * *width* must be the width of the screen to capture *in bytes*, and +;; must be greater than 0. A 0 as *width* parameter will be considered as 65536, +;; making this function overwrite the whole memory, making your program crash. +;; * *height* must be the height of the sprite in bytes, and must be greater than 0. +;; A 0 as *height* parameter will be considered as 256 (the maximum value). +;; Height of a sprite in bytes and pixels is the same value, as bytes only group +;; consecutive pixels in the horizontal space. +;; +;; Known limitations: +;; * This function does not do any kind of boundary check or clipping. If you +;; get data beyond your video memory or screen buffer the sprite will also contains +;; not video data. +;; * This function uses self-modifying code, so it cannot be used from ROM. +;; +;; Details: +;; Reads screen video memory data at *memory* and copies it to a linear array (a *sprite*). +;; The copy takes into account CPC's video memory disposition, which is comprised of character +;; lines made by 8-pixel lines each. The copy converts this disposition to linear, putting +;; each sprite line contiguous to the previous one in the resulting *sprite* array. After +;; this copy, *sprite* can be used as any other normal sprite through sprite drawing functions +;; like . +;; +;; Next example shows how to use this function, +;; (start code) +;; // All enemies will be of the same size +;; #define ENEMY_WIDTH 6 +;; #define ENEMY_HEIGHT 10 +;; +;; // Struct Enemy +;; // Contains all enemy information: position, velocity, sprite and background data buffer. +;; // The background data buffer will contain the background screen pixel data behind the +;; // enemy sprite. This will be used to erase the enemy sprite restoring the background. +;; typedef struct Enemy { +;; u8 x, y; // Enemy location +;; u8 vx, vy; // Enemy velocity +;; u8* sprite; // Enemy sprite +;; u8 background[ ENEMY_WIDTH * ENEMY_HEIGHT ]; // Background pixel data +;; } Enemy; +;; +;; ////////////////////////////////////////////////////////////////////////////////////////// +;; // Moves an Enemy and redraws it afterwards +;; // +;; void MoveAndRedrawEnemy(Enemy* enemy) { +;; u8* pvmem; // Temporal pointer to video memory for drawing sprites (will be used later) +;; +;; // --- Calculations previous to moving the enemy --- +;; +;; // Get a pointer to the start of the Enemy sprite in video memory +;; // previous to moving. Background will need to be restored at this +;; // precise location to erase the Enemy before drawing it in its next location +;; u8* pvmem_enemyBg = cpct_getScreenPtr(CPCT_VMEM_START, enemy->x, enemy->y); +;; +;; // Move the enemy adding velocity to position +;; enemy->x += enemy->vx; +;; enemy->y += enemy->vy; +;; +;; // Get a pointer to the Screen Video Memory location where +;; // Enemy will be drawn next (in its new location after movement) +;; pvmem = cpct_getScreenPtr(CPCT_VMEM_START, enemy->x, enemy->y); +;; +;; // Wait for VSync and draw background and Enemy +;; cpct_waitVSYNC(); +;; +;; //--- ENEMY REDRAWING --- +;; +;; // Erase ENEMY at its previous location by drawing background over it +;; cpct_drawSprite(enemy->background, pvmem_enemyBg, ENEMY_WIDTH, ENEMY_HEIGHT); +;; +;; // Before drawing ENEMY at its new location, copy the background there +;; // to enemy->background buffer. This will let us restore it next time the ENEMY moves. +;; cpct_getScreenToSprite(pvmem, enemy->background, ENEMY_WIDTH, ENEMY_HEIGHT); +;; +;; // Draw ENEMY at its new location +;; cpct_drawSpriteMasked(enemy->sprite, pvmem, ENEMY_WIDTH, ENEMY_HEIGHT); +;; } +;; (end code) +;; +;; +;; Destroyed Register values: +;; AF, BC, DE, HL +;; +;; Required memory: +;; C-bindings - 39 bytes +;; ASM-bindings - 34 bytes +;; +;; Time Measures: +;; (start code) +;; Case | microSecs (us) | CPU Cycles +;; ---------------------------------------------------------------- +;; Best | 30 + 8HH + (19 + 6W)H | 120 + 32HH + (76 + 24W)H +;; Worst | 38 + 8HH + (19 + 6W)H | 152 + 32HH + (76 + 24W)H +;; ---------------------------------------------------------------- +;; W=2,H=16 | 534 / 542 | 2136 / 2168 +;; W=4,H=32 | 1430 / 1438 | 5720 / 5752 +;; ---------------------------------------------------------------- +;; Asm saving | -16 | -64 +;; ---------------------------------------------------------------- +;; (end code) +;; W = *width* in bytes, H = *height* in bytes, HH = integer((*H*-1)/8) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + ld a, c ;; [1] A = sprite width + ld (restore_width), a ;; [4] Modify sprite with in the code for the loop + + sub c ;; [1] | A = c - c - c = -c + sub c ;; [1] | A contains negative width + ld (neg_width), a ;; [4] Modify negative sprite width in the calculation code + + ld a, b ;; [1] A = sprite height + +next_line: +restore_width=.+1 + ld bc, #0x0000 ;; [3] 0000 is a placeholder for the width of a sprite line + ldir ;; [6*W-1] Copy one complete sprite line + + dec a ;; [1] 1 less sprite line to end + ret z ;; [2/4] If no lines left, return + + ;; Make HL Point to next line start +neg_width=.+1 + ld bc, #0x0700 ;; [3] 0700 will be modified to be 07xx, with xx being negative width of the sprite + add hl, bc ;; [3] HL += 0x800 - sprite width + + ;; Check for memory boundaries + ld b, a ;; [1] Save the value of A into B (we need it for next loop iteration) + ld a, h ;; [1] A=H (to test bits 12,13 and 14 of the new video memory address) + and #0x38 ;; [2] We get the 3 bits (12,13 and 14) to test if we have crossed 8-line character boundary + ld a, b ;; [1] Restore A value (previously saved into B) + jr nz, next_line ;; [2/3] If bits 12,13 and 14 are 0, we are at the first line of a character + ;; .... which means we have crossed character boundaries and memory address will + ;; .... be incorrect. Else, we have not, so we can safely proceed to next_line + +_8line_character_boundary_crossed: + ;; Our address has moved out of the 16K memory bank of video memory. As memory addresses + ;; are 16-bits long (4 16K banks), in order to make it cycle to the start of the 16K bank + ;; we were located, we need to "jump" over the other 3 banks, which means adding 48K (0xC000). + ;; As we also want to jump to the next character line, which is 0x50 bytes away, we need + ;; to add 0xC050 in total. + ld bc, #0xC050 ;; [3] Value to be added to make HL point to next pixel line in video memory + add hl, bc ;; [3] HL += 0xC050 + jr next_line ;; [3] Continue with next pixel line + diff --git a/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite_asmbindings.s b/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite_asmbindings.s new file mode 100644 index 000000000..71603285d --- /dev/null +++ b/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite_asmbindings.s @@ -0,0 +1,26 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;; +;; ASM bindings for +;; +cpct_getScreenToSprite_asm:: ;; Assembly entry point + +.include /cpct_getScreenToSprite.asm/ \ No newline at end of file diff --git a/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite_cbindings.s b/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite_cbindings.s new file mode 100644 index 000000000..ed7efa8fa --- /dev/null +++ b/cpctelera/src/sprites/screenToSprite/cpct_getScreenToSprite_cbindings.s @@ -0,0 +1,36 @@ +;;-----------------------------LICENSE NOTICE------------------------------------ +;; This file is part of CPCtelera: An Amstrad CPC Game Engine +;; Copyright (C) 2018 Arnaud Bouche +;; Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +;; +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU Lesser General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU Lesser General Public License for more details. +;; +;; You should have received a copy of the GNU Lesser General Public License +;; along with this program. If not, see . +;;------------------------------------------------------------------------------- +.module cpct_sprites + +;; +;; C bindings for +;; +;; 16 us, 5 bytes +;; +_cpct_getScreenToSprite:: + ;; GET Parameters from the stack + pop af ;; [3] AF = Return Address + pop hl ;; [3] HL = Source Screen Address (Video memory location) + pop de ;; [3] DE = Destination Sprite Address (Sprite data array) + pop bc ;; [3] BC = Height/Width (B = Height, C = Width) + + push af ;; [4] Put returning address in the stack again + ;; as this function uses __z88dk_callee convention + +.include /cpct_getScreenToSprite.asm/ \ No newline at end of file diff --git a/cpctelera/src/sprites/screenToSprite/screenToSprite.h b/cpctelera/src/sprites/screenToSprite/screenToSprite.h new file mode 100644 index 000000000..4b5646fc7 --- /dev/null +++ b/cpctelera/src/sprites/screenToSprite/screenToSprite.h @@ -0,0 +1,36 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// Copyright (C) 2018 Arnaud Bouche +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------- + +//##################################################################### +//### MODULE: Sprites +//### SUBMODULE: Screen To Sprite +//##################################################################### +//### This module contains specialized functions to read video memory +//### and copy it to linear arrays (sprites) in order to be used +//### later on as normal sprites. +//##################################################################### +// + +#ifndef CPCT_SCREEN2SPRITE_H +#define CPCT_SCREEN2SPRITE_H + +// Capture Video Memory area to buffer +extern void cpct_getScreenToSprite(u8* memory, u8* sprite, u8 width, u8 height) __z88dk_callee; + +#endif \ No newline at end of file diff --git a/cpctelera/src/sprites/sprites.h b/cpctelera/src/sprites/sprites.h index 45e3ec054..1ec3becac 100644 --- a/cpctelera/src/sprites/sprites.h +++ b/cpctelera/src/sprites/sprites.h @@ -1,6 +1,6 @@ //-----------------------------LICENSE NOTICE------------------------------------ // This file is part of CPCtelera: An Amstrad CPC Game Engine -// Copyright (C) 2014-2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by @@ -31,9 +31,11 @@ #include "sprite_types.h" #include "transparency_table_macros.h" #include "drawToSpriteBuffer/drawToSpriteBuffer.h" +#include "screenToSprite/screenToSprite.h" #include "drawTile/drawTile.h" #include "flipping/flipping.h" #include "blending/blending.h" +#include "colorReplace/colorReplace.h" // Functions to transform firmware colours for a group of pixels into a byte in screen pixel format extern u8 cpct_px2byteM0 (u8 px0, u8 px1) __z88dk_callee; diff --git a/cpctelera/src/video/videomode.h b/cpctelera/src/video/videomode.h index 761a3c9a6..771913e8e 100644 --- a/cpctelera/src/video/videomode.h +++ b/cpctelera/src/video/videomode.h @@ -1,6 +1,6 @@ //-----------------------------LICENSE NOTICE------------------------------------ // This file is part of CPCtelera: An Amstrad CPC Game Engine -// Copyright (C) 2014-2016 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by diff --git a/examples/medium/colorReplace/.gitignore b/examples/medium/colorReplace/.gitignore new file mode 100644 index 000000000..f9e0cbe8a --- /dev/null +++ b/examples/medium/colorReplace/.gitignore @@ -0,0 +1 @@ +src/sprites/ diff --git a/examples/medium/colorReplace/Makefile b/examples/medium/colorReplace/Makefile new file mode 100644 index 000000000..184f61b39 --- /dev/null +++ b/examples/medium/colorReplace/Makefile @@ -0,0 +1,38 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2015 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +########################################################################### +## CPCTELERA ENGINE ## +## Main Building Makefile for Projects ## +##-----------------------------------------------------------------------## +## This file contains the rules for building a CPCTelera project. These ## +## These rules work generically for every CPCTelera project. ## +## Usually, this file should be left unchanged: ## +## * Project's build configuration is to be found in build_config.mk ## +## * Global paths and tool configuration is located at $(CPCT_PATH)/cfg/## +########################################################################### + +## +## PROJECT CONFIGURATION (you may change things there to setup this project) +## +include cfg/build_config.mk + +## +## USE GLOBAL MAKEFILE (general rules for building CPCtelera projects) +## +include $(CPCT_PATH)/cfg/global_main_makefile.mk diff --git a/examples/medium/colorReplace/cfg/build_config.mk b/examples/medium/colorReplace/cfg/build_config.mk new file mode 100644 index 000000000..9a25a157e --- /dev/null +++ b/examples/medium/colorReplace/cfg/build_config.mk @@ -0,0 +1,161 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2015 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +########################################################################### +## CPCTELERA ENGINE ## +## Build configuration file ## +##-----------------------------------------------------------------------## +## This file is intendend for you to be able to config the way in which ## +## you would like to build this example of use of the CPCtelera Engine. ## +## Below you will find several configuration sections with the macros ## +## available to configure the build, along with explanation comments to ## +## help you understand what they do. Please, change everything you want. ## +########################################################################### + +## CPCTELERA MAIN PATH +## Sets CPCTelera main path for accessing tools and configuration. This +## variable must point to the folder where source and tools are contained. +## Setup creates and environment variable that will be generally used. +## However, when environment variable is not available, this variable +## should have the correct value for the project to compile. +## If you change folder structure, CPCT_PATH should reflect this change. +## This variable should always have the absolute path value. +## +#>> Uses environment variable $(CPCT_PATH) + +#### +## SECTION 1: Project configuration +## +## This section establishes source and object subfolders and the binary objects to +## be built. Normally, you want to change the OBJ files you want to be built, selecting +## only the ones that contain the actual code that will be used by you in your application. +##### + +# Name of the project (without spaces, as it will be used as filename) +# and Z80 memory location where code will start in the generated binary +PROJNAME := color +Z80CODELOC := 0x40 + +## +## Folders +## +## SRCDIR = Source files for the project +## DSKFILESDIR = Input files to be added to the final DSK production +## OBJDIR = Object files generated on compilation +## +SRCDIR := src +DSKFILESDIR := dsk_files +OBJDIR := obj + +## +## File extensions +## +## C_EXT = C source files that will be automatically compiled +## ASM_EXT = ASM source files that will be automatically compiled +## BIN_EXT = Binary files that will be automatically converted to C source files for compilation +## OBJ_EXT = Object files generated after compilation +## DSKINC_EXT = Flag object files generated after file inclusion into DSK (to signal that a file has been included) +## +C_EXT := c +ASM_EXT := s +BIN_EXT := bin +OBJ_EXT := rel +DSKINC_EXT := dskinc + +## +## Output Binaries Configuration +## +## IHXFILE = Binary file that SDCC produces after compilation and linkage +## BINFILE = Binary file that is finally included in DSK and CDT (produced by Hex2Bin) +## CDT = CDT file produced +## DSK = DSK file produced +## DSKINC = Flag object file produced to signal DSK already has all include files in it +## +IHXFILE := $(OBJDIR)/$(PROJNAME).ihx +BINFILE := $(OBJDIR)/$(PROJNAME).bin +CDT := $(PROJNAME).cdt +DSK := $(PROJNAME).dsk +DSKINC := $(OBJDIR)/$(DSK).$(DSKINC_EXT) + +## +## TARGETs generated by Makefile: remove those you don't want to be generated +## +## $(CDT): Generates the CDT file with main binary +## $(DSK): Generates the DSK file with main binary +## $(DSKINC): Includes all files from DSKFILESDIR into DSK as binaries +## +TARGET := $(CDT) $(DSK) $(DSKINC) + +## +## OBJS2CLEAN: Additional objects to be removed when running "make clean" +## +OBJS2CLEAN := + +#### +## SECTION 2: TOOL PATH CONFIGURATION +## +## Paths are configured in the global_paths.mk configuration file included +## here. You may overwrite the values of path variables after the include +## if you wanted specific configuration for this project. +#### +include $(CPCT_PATH)/cfg/global_paths.mk + +#### +## SECTION 3: COMPILATION CONFIGURATION +## +## Flags used to configure the compilation of your code. They are usually +## fine for most of the projects, but you may change them for special uses. +##### +Z80CCFLAGS := +Z80ASMFLAGS := -l -o -s +Z80CCINCLUDE := -I$(CPCT_SRC) +Z80CCLINKARGS := -mz80 --no-std-crt0 -Wl-u \ + --code-loc $(Z80CODELOC) \ + --data-loc 0 -l$(CPCT_LIB) +#### +## SECTION 4: CALCULATED FOLDERS, SUBFOLDERS AND FILES +## +## These macros calculate code subfolders, get all the source files and generate +## the corresponding subfolders and files in the object directory. All subfolders +## and files with source extension found are added, up to 1 level of depth in +## folder structure inside the main source directory. +#### +include $(CPCT_PATH)/cfg/global_functions.mk + +# Convert images and tilemaps +include cfg/image_conversion.mk + +# Calculate all subdirectories +SUBDIRS := $(filter-out ., $(shell find $(SRCDIR) -type d -print)) +OBJDSKINCSDIR := $(OBJDIR)/$(DSKFILESDIR) +OBJSUBDIRS := $(OBJDSKINCSDIR) $(foreach DIR, $(SUBDIRS), $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(DIR))) + +# Calculate all source files +CFILES := $(foreach DIR, $(SUBDIRS), $(wildcard $(DIR)/*.$(C_EXT))) +CFILES := $(IMGCFILES) $(filter-out $(IMGCFILES), $(CFILES)) +ASMFILES := $(foreach DIR, $(SUBDIRS), $(wildcard $(DIR)/*.$(ASM_EXT))) +BIN2CFILES := $(foreach DIR, $(SUBDIRS), $(wildcard $(DIR)/*.$(BIN_EXT))) +DSKINCSRCFILES := $(wildcard $(DSKFILESDIR)/*) + +# Calculate all object files +BIN_OBJFILES := $(patsubst %.$(BIN_EXT), %.$(C_EXT), $(BIN2CFILES)) +CFILES := $(filter-out $(BIN_OBJFILES), $(CFILES)) +C_OBJFILES := $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(patsubst %.$(C_EXT), %.$(OBJ_EXT), $(BIN_OBJFILES) $(CFILES))) +ASM_OBJFILES := $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(patsubst %.$(ASM_EXT), %.$(OBJ_EXT), $(ASMFILES))) +DSKINCOBJFILES := $(foreach FILE, $(DSKINCSRCFILES), $(patsubst $(DSKFILESDIR)/%, $(OBJDSKINCSDIR)/%, $(FILE)).$(DSKINC_EXT)) +OBJFILES := $(C_OBJFILES) $(ASM_OBJFILES) diff --git a/examples/medium/colorReplace/cfg/image_conversion.mk b/examples/medium/colorReplace/cfg/image_conversion.mk new file mode 100644 index 000000000..185e4dbab --- /dev/null +++ b/examples/medium/colorReplace/cfg/image_conversion.mk @@ -0,0 +1,74 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2016 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +############################################################################ +## CPCTELERA ENGINE ## +## Automatic image conversion file ## +##------------------------------------------------------------------------## +## This file is intended for users to automate image conversion from JPG, ## +## PNG, GIF, etc. into C-arrays. ## +## ## +## Macro used for conversion is IMG2SPRITES, which has up to 9 parameters:## +## (1): Image file to be converted into C sprite (PNG, JPG, GIF, etc) ## +## (2): Graphics mode (0,1,2) for the generated C sprite ## +## (3): Prefix to add to all C-identifiers generated ## +## (4): Width in pixels of each sprite/tile/etc that will be generated ## +## (5): Height in pixels of each sprite/tile/etc that will be generated ## +## (6): Firmware palette used to convert the image file into C values ## +## (7): (mask / tileset /) ## +## - "mask": generate interlaced mask for all sprites converted ## +## - "tileset": generate a tileset array with pointers to all sprites ## +## (8): Output subfolder for generated .C/.H files (in project folder) ## +## (9): (hwpalette) ## +## - "hwpalette": output palette array with hardware colour values ## +## (10): Aditional options (you can use this to pass aditional modifiers ## +## to cpct_img2tileset) ## +## ## +## Macro is used in this way (one line for each image to be converted): ## +## $(eval $(call IMG2SPRITES,(1),(2),(3),(4),(5),(6),(7),(8),(9), (10))) ## +## ## +## Important: ## +## * Do NOT separate macro parameters with spaces, blanks or other chars.## +## ANY character you put into a macro parameter will be passed to the ## +## macro. Therefore ...,src/sprites,... will represent "src/sprites" ## +## folder, whereas ..., src/sprites,... means " src/sprites" folder. ## +## ## +## * You can omit parameters but leaving them empty. Therefore, if you ## +## wanted to specify an output folder but do not want your sprites to ## +## have mask and/or tileset, you may omit parameter (7) leaving it empty ## +## $(eval $(call IMG2SPRITES,imgs/1.png,0,g,4,8,$(PAL),,src/)) ## +############################################################################ + +## Example firmware palette definition as variable in cpct_img2tileset format + +PALETTE={13 1 2 3 6 4 5 8 17 9 18 15 24 0 11 26} + +## Example image conversion +## This example would convert img/example.png into src/example.{c|h} files. +## A C-array called pre_example[24*12*2] would be generated with the definition +## of the image example.png in mode 0 screen pixel format, with interlaced mask. +## The palette used for conversion is given through the PALETTE variable and +## a pre_palette[16] array will be generated with the 16 palette colours as +## hardware colour values. + +$(eval $(call IMG2SPRITES,img/baloon.png,0,g,0,0,$(PALETTE),,src/sprites,hwpalette)) +$(eval $(call IMG2SPRITES,img/square.png,0,g,0,0,$(PALETTE),,src/sprites,)) +$(eval $(call IMG2SPRITES,img/star_trans.png,0,g,0,0,$(PALETTE),mask,src/sprites,)) +$(eval $(call IMG2SPRITES,img/circle_trans.png,0,g,0,0,$(PALETTE),mask,src/sprites,)) +$(eval $(call IMG2SPRITES,img/roof.png,0,g,0,0,$(PALETTE),,src/sprites,)) +$(eval $(call IMG2SPRITES,img/cloud.png,0,g,0,0,$(PALETTE),,src/sprites,)) \ No newline at end of file diff --git a/examples/medium/colorReplace/img/baloon.png b/examples/medium/colorReplace/img/baloon.png new file mode 100644 index 000000000..04314b1fa Binary files /dev/null and b/examples/medium/colorReplace/img/baloon.png differ diff --git a/examples/medium/colorReplace/img/circle_trans.png b/examples/medium/colorReplace/img/circle_trans.png new file mode 100644 index 000000000..ac705c412 Binary files /dev/null and b/examples/medium/colorReplace/img/circle_trans.png differ diff --git a/examples/medium/colorReplace/img/cloud.png b/examples/medium/colorReplace/img/cloud.png new file mode 100644 index 000000000..36edaeaa7 Binary files /dev/null and b/examples/medium/colorReplace/img/cloud.png differ diff --git a/examples/medium/colorReplace/img/roof.png b/examples/medium/colorReplace/img/roof.png new file mode 100644 index 000000000..e43e5d1b0 Binary files /dev/null and b/examples/medium/colorReplace/img/roof.png differ diff --git a/examples/medium/colorReplace/img/square.png b/examples/medium/colorReplace/img/square.png new file mode 100644 index 000000000..0bb9c43f8 Binary files /dev/null and b/examples/medium/colorReplace/img/square.png differ diff --git a/examples/medium/colorReplace/img/star_trans.png b/examples/medium/colorReplace/img/star_trans.png new file mode 100644 index 000000000..e136dc302 Binary files /dev/null and b/examples/medium/colorReplace/img/star_trans.png differ diff --git a/examples/medium/colorReplace/src/declarations.h b/examples/medium/colorReplace/src/declarations.h new file mode 100644 index 000000000..939375d67 --- /dev/null +++ b/examples/medium/colorReplace/src/declarations.h @@ -0,0 +1,90 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2017 Arnaud BOUCHE +// Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------ + +#ifndef _DECLARATIONS_H_ +#define _DECLARATIONS_H_ + +///////////////////////////////////////////////////////////////////////////////// +// INCLUDES +#include + +// Sprites +#include "sprites/baloon.h" +#include "sprites/roof.h" +#include "sprites/cloud.h" +#include "sprites/square.h" +#include "sprites/star_trans.h" +#include "sprites/circle_trans.h" + +// Other modules +#include "manageVideoMem.h" +#include "drawing.h" + +///////////////////////////////////////////////////////////////////////////////// +// USEFUL MACROS AND CONSTANTS +// + +// Memory location definition +enum +{ + VIDEO_MEM, + BUFFER_MEM, + NB_BUFFERS +}; + +// Boolean definition +#define BOOL u8 +#define TRUE 1 +#define FALSE 0 + +// Double buffer location +#define SCREEN_BUFF 0x8000 +#define VMEM_SIZE 0x4000 + +// Mask table location +#define MASK_TABLE_LOC (SCREEN_BUFF - 0x100) // 0x100 = Size of Mask Table + +// New stack location +#define NEW_STACK_LOC (MASK_TABLE_LOC - 0x100) // 0x100 = Size of Stack + +// Screen size +#define SCREEN_CY 200 +#define SCREEN_CX 80 + +#define VIEW_TOP 0 +#define VIEW_DOWN SCREEN_CY - 20 + +#define POS_CLOUD_X 0 +#define POS_CLOUD_Y 20 + +#define NB_BALOONS 8 +#define BALOON_TRAIL 8 + +#define BALOON_ACTIVE 1 +#define BALOON_INACTIVE 0 + +#define NB_STARS 10 +#define NB_COLORS_STAR 7 + +///////////////////////////////////////////////////////////////////////////////// +// Mask Table Definition for Mode 0 +// +cpctm_declareMaskTable(gMaskTable); + +#endif \ No newline at end of file diff --git a/examples/medium/colorReplace/src/drawing.c b/examples/medium/colorReplace/src/drawing.c new file mode 100644 index 000000000..414450594 --- /dev/null +++ b/examples/medium/colorReplace/src/drawing.c @@ -0,0 +1,371 @@ + +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2018 Bouche Arnaud (@Arnaud6128) +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------ + +#include "declarations.h" + +///////////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +u8 gSpriteColorized[G_BALOON_W*G_BALOON_H]; // Array for sprite to color +u8 gBackGroundColor; // Background color +u8 gBaloonColor; // Current color baloon +u8 gPosCloud; // Position of cloude + +///////////////////////////////////////////////////////////////////////////////// +// STRUCTURES DEFINITION +typedef struct TBaloon // Baloon structure +{ + i16 posY; // Absolute Baloon PosY (can be outside screen) + u8 posX; // Absolute Baloon PosX + + u8 drawPosY; // In screen Baloon PosY + u8 drawCY; // In screen Baloon Height + + u8 speed; // Baloon speed + u8 color; // Baloon color drawn + + u8 status; // Baloon status ACTIVE / INACTIVE +} SBaloon; + +typedef struct TBaloons // All baloons structure +{ + u8 nb; // Nb baloons in screen + SBaloon baloons[NB_BALOONS]; // Array of baloon +} SBaloons; + +SBaloons gBaloons; // Baloons to draw + +typedef struct TStar // Lighting star structure +{ + u8 posX; // Screen PosX + u8 posY; // Screen PosY + + u8 color; // Star color drawn +} SStar; + +typedef struct TStars // All stars structure +{ + SStar stars[NB_STARS]; // Array of stars +} SStars; + +SStars gStars; // Stars to draw + +/////////////////////////////////////////////////////// +/// GET RANDOM FROM 0 TO MAX-1 +/// +u8 GetRand(u8 max) +{ + return cpct_rand()%max; +} + +/////////////////////////////////////////////////////// +/// CHANGE TWO COLORS OF BALOON SPRITE +/// +void ColorSprite(u8 color) +{ + // Replace the two colors 1 and 2 of sprite baloon + cpct_spriteColorizeM0(g_baloon, gSpriteColorized, G_BALOON_W, G_BALOON_H, 1, color); // Colors are consecutives + cpct_spriteColorizeM0(gSpriteColorized, gSpriteColorized, G_BALOON_W, G_BALOON_H, 2, color + 1); +} + +/////////////////////////////////////////////////////// +/// CLEAR BALOON BACKGROUND +/// +void ClearBaloon(SBaloon* baloon) +{ + // If baloon in visible part of view + if (baloon->drawPosY < VIEW_DOWN) + { + u8* pvmem; + + // Compute size to be filled with background color + u8 clearCY = baloon->drawCY + BALOON_TRAIL; + + // Compute position to clear + u8 posDownClearY = baloon->drawPosY + clearCY; + if (posDownClearY > VIEW_DOWN) + clearCY = VIEW_DOWN - baloon->drawPosY; + + // Draw the box with background color to clear + pvmem = GetBackBufferPtr(baloon->posX, baloon->drawPosY); + cpct_drawSolidBox(pvmem, gBackGroundColor, G_BALOON_W, clearCY); + } +} + +/////////////////////////////////////////////////////// +/// DELETE BALOON +/// +void DeleteBaloons(SBaloon* baloons, SBaloon* baloonToDel, u8* nb) +{ + // Get last baloon in array + // Decrement number of remaining baloons in array + const SBaloon* lastBaloon = &baloons[--*nb]; + + // Replace baloon to be deleted with last baloon (if they are not the same) + if (baloonToDel != lastBaloon) + cpct_memcpy(baloonToDel, lastBaloon, sizeof(SBaloon)); +} + +/////////////////////////////////////////////////////// +/// UPDATE BALOONS +/// +void UpdateBaloons() +{ + SBaloon* itBaloon = gBaloons.baloons; + u8 i; + + // Test if we can add a new baloon + if (gBaloons.nb < NB_BALOONS) + { + // Add new baloon at end of array + // Increment number of baloons in array + SBaloon* newBaloon = &gBaloons.baloons[gBaloons.nb++]; + + // Get random positions X and Y + newBaloon->posX = GetRand(SCREEN_CX - G_BALOON_W); + newBaloon->posY = SCREEN_CY - GetRand(40); + + // Get random speed + newBaloon->speed = GetRand(3) + 2; + + // Get circular next color 2 by 2 until 12 + gBaloonColor = (gBaloonColor + 2) % 12; + newBaloon->color = gBaloonColor + 1; + + // Set baloon ACTIVE + newBaloon->status = BALOON_ACTIVE; + } + + // Update all baloons + for (i = 0; i < gBaloons.nb; i++) + { + // If baloon active move and draw it + if (itBaloon->status == BALOON_ACTIVE) + { + // Test if whole baloon outside view + if (itBaloon->posY + G_BALOON_H < VIEW_TOP) + { + // Set baloon inactive + itBaloon->status = BALOON_INACTIVE; + // Clear baloon background + ClearBaloon(itBaloon); + } + else + { + // Move baloon to up according its speed + i16 posY = itBaloon->posY - itBaloon->speed; + itBaloon->posY = posY; + + // Baloon outside view by top + if (posY < VIEW_TOP) + { + itBaloon->drawPosY = 0; + itBaloon->drawCY = G_BALOON_H + posY; + } + else + // Baloon outside view by down + if (posY + G_BALOON_H > VIEW_DOWN) + { + itBaloon->drawPosY = posY; + itBaloon->drawCY = VIEW_DOWN - posY; + } + // Baloon all in view + else + { + itBaloon->drawPosY = posY; + itBaloon->drawCY = G_BALOON_H; + } + } + } + // If inactive delete baloon + else + { + // Clear baloon background + ClearBaloon(itBaloon); + + // Delete baloon from list + DeleteBaloons(gBaloons.baloons, itBaloon, &gBaloons.nb); + } + + // Get next baloon pointer + itBaloon++; + } +} + +/////////////////////////////////////////////////////// +/// DRAW BALOON +/// +void DrawBaloon(SBaloon* baloon, const u8* spriteBaloon) +{ + i16 posY = baloon->posY; + + // If baloon in view + if (posY + G_BALOON_H > VIEW_TOP && posY < VIEW_DOWN) + { + // Get VMem pointer of current baloon position + u8* pvmem = GetBackBufferPtr(baloon->posX, baloon->drawPosY); + const u8* sprite = (u8*)spriteBaloon; + + // Baloon partialy outside view by top + if (posY < VIEW_TOP) + { + // Compute Y position + u8 y = -posY; + + // Compute sprite offset + sprite = (u8*)spriteBaloon + G_BALOON_W * y; + } + + cpct_drawSpriteMaskedAlignedTable(sprite, pvmem, G_BALOON_W, baloon->drawCY, gMaskTable); + } +} + +/////////////////////////////////////////////////////// +/// DRAW STARS +/// +void DrawStars() +{ + // Static stars color + const static u8 sColorStar[NB_COLORS_STAR] = { 2, 4, 7, 8, 10, 11, 12 }; + static u8 color = 0; + + u8 i; + for (i = 0; i < NB_STARS; i++) + { + // Get video pointer of each star to be drawn + u8* pvmem = GetBackBufferPtr(gStars.stars[i].posX, gStars.stars[i].posY); + u8 color = gStars.stars[i].color++; + + // Use different drawing color methods + if (i < NB_STARS/3) + { + // Color and draw masked sprite in video memory + cpct_drawSpriteMaskedColorizeM0(g_star_trans, pvmem, G_STAR_TRANS_W, G_STAR_TRANS_H, 15, sColorStar[color]); + } + else if (i > NB_STARS/3 && i < 2*NB_STARS/3) + { + // Color and draw masked aligned sprite in video memory + cpct_drawSpriteMaskedAlignedColorizeM0(g_square, pvmem, G_SQUARE_W, G_SQUARE_H, 15, sColorStar[color], gMaskTable); + } + else + { + // Color and copy masked sprite in temporary array + u8 circleColor[G_CIRCLE_TRANS_W * G_CIRCLE_TRANS_H * 2]; + cpct_spriteMaskedColorizeM0(g_circle_trans, circleColor, G_CIRCLE_TRANS_W, G_CIRCLE_TRANS_H, 15, sColorStar[color]); + + // Draw masked Sprite from temporary array + cpct_drawSpriteMasked(circleColor, pvmem, G_CIRCLE_TRANS_W, G_CIRCLE_TRANS_H); + } + + // If all colors palette used restart from 0 + if (color == NB_COLORS_STAR - 1) + gStars.stars[i].color = 0; + } +} + +/////////////////////////////////////////////////////// +/// DRAW CLOUD +/// +void DrawCloud() +{ + // Draw cloud at fixed place + u8* pvmem = GetBackBufferPtr(0, POS_CLOUD_Y); + cpct_drawSprite(g_cloud, pvmem, G_CLOUD_W, G_CLOUD_H); +} + +/////////////////////////////////////////////////////// +/// DRAW SCENE WITH ALL BALOONS +/// +void DrawSceneBaloons() +{ + u8 i; + + // Clear background for all baloons + SBaloon* itBaloon = gBaloons.baloons; // Get first baloon pointer + for (i = 0; i < gBaloons.nb; i++) + { + ClearBaloon(itBaloon); + itBaloon++; + } + + // Draw sprite cloud + DrawCloud(); + + // Draw all baloons + itBaloon = gBaloons.baloons; // Get first baloon pointer + for (i = 0; i < gBaloons.nb; i++) + { + const u8* sprite = g_baloon; // Default baloon sprite (blue) + + // Test if sprite have colors to change + if (itBaloon->color > 1) // Color 0 (white) is transparent color + { + ColorSprite(itBaloon->color); // Change colors of ballon + sprite = gSpriteColorized; // Sprite to draw is colorized baloon + } + + DrawBaloon(itBaloon, sprite); // Draw baloon sprite + itBaloon++; // Get next baloon + } +} + +/////////////////////////////////////////////////////// +/// DRAW BACKGROUND BLUE SKY AND ROOF +/// +void DrawBackground() +{ + u8* pvmem; + + // Fill video buffer with background color + cpct_memset((u8*)SCREEN_BUFF, gBackGroundColor, VMEM_SIZE); + + // Draw left part of Roof + pvmem = GetBackBufferPtr(0, SCREEN_CY-G_ROOF_H); + cpct_drawSprite(g_roof, pvmem, G_ROOF_W, G_ROOF_H); + + // Draw right part of Roof + pvmem += G_ROOF_W; + cpct_drawSprite(g_roof, pvmem, G_ROOF_W, G_ROOF_H); + + // Copy Same background on both buffers + cpct_memcpy(CPCT_VMEM_START, (u8*)SCREEN_BUFF, VMEM_SIZE); +} + +///////////////////////////////////////////////////////////////////////////////// +/// INITIALIZE DRAWING +/// +/// Initializes global variables and general status for drawing functions +/// +void InitializeDrawing() +{ + u8 dx = SCREEN_CX / NB_STARS; // Compute space between stars + + u8 i; + for (i = 0; i < NB_STARS; i++) + { + gStars.stars[i].posX = dx * i + 5; // Constant space beetween stars + gStars.stars[i].posY = GetRand(10) + 175; // Random Y position from 175 to 184 + gStars.stars[i].color = GetRand(NB_COLORS_STAR); // Random color from 0 to NB_COLORS_STAR-1 + } + + gBackGroundColor = cpct_px2byteM0(14, 14); // Get byte color of background for M0 + gBaloons.nb = 0; // No baloon to draw at start + + DrawBackground(); // Set background on both buffers +} diff --git a/examples/medium/colorReplace/src/drawing.h b/examples/medium/colorReplace/src/drawing.h new file mode 100644 index 000000000..f4ad6f644 --- /dev/null +++ b/examples/medium/colorReplace/src/drawing.h @@ -0,0 +1,31 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2018 Bouche Arnaud (@Arnaud6128) +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------ + +#ifndef _DRAWING_H_ +#define _DRAWING_H_ + +//////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTION DECLARATIONS +// +void InitializeDrawing(); +void UpdateBaloons(); +void DrawSceneBaloons(); +void DrawStars(); + +#endif \ No newline at end of file diff --git a/examples/medium/colorReplace/src/main.c b/examples/medium/colorReplace/src/main.c new file mode 100644 index 000000000..19489081e --- /dev/null +++ b/examples/medium/colorReplace/src/main.c @@ -0,0 +1,69 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2017 Arnaud BOUCHE (@Arnaud6128) +// Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------ + +#include "declarations.h" + +///////////////////////////////////////////////////////////////////////////////// +// Mask Table Definition for Mode 0 +// +cpctm_createTransparentMaskTable(gMaskTable, MASK_TABLE_LOC, M0, 0); + +/////////////////////////////////////////////////////// +/// INITIALIZATION +/// +// Initializes the CPC and all systems before starting the main loop +// +void Initialization() +{ + // We need to disable firmware in order to set the palette and + // to be able to use a second screen between 0x8000 and 0xBFFF + cpct_disableFirmware(); + cpct_setVideoMode(0); // Set mode 0 + cpct_setPalette(g_palette, 16); // Set the palette + cpct_setBorder(HW_SKY_BLUE); // Set the border color with Hardware color + + InitializeVideoMemoryBuffers(); // Initialize video buffers + InitializeDrawing(); // Initialize drawing elements +} + +/////////////////////////////////////////////////////// +/// MAIN PROGRAM +/// +void main(void) +{ + // Change stack location before any call. We will be using + // memory from 0x8000 to 0xBFFF as secondary buffer, so + // the stack must not be there or it will get overwritten + cpct_setStackLocation((u8*)NEW_STACK_LOC); + + // Initialize everything + Initialization(); + + // Main Loop + while (TRUE) + { + UpdateBaloons(); + DrawSceneBaloons(); + DrawStars(); + + // Flip buffers to display the present back buffer + // and stop displaying the current video memory + FlipBuffers(); + } +} diff --git a/examples/medium/colorReplace/src/manageVideoMem.c b/examples/medium/colorReplace/src/manageVideoMem.c new file mode 100644 index 000000000..3a14b2d28 --- /dev/null +++ b/examples/medium/colorReplace/src/manageVideoMem.c @@ -0,0 +1,88 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2018 Bouche Arnaud (@Arnaud6128) +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------ + +#include "declarations.h" + +///////////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +// +u8 gVMem; // Current video mem + +///////////////////////////////////////////////////////////////////////////////// +// INITITALIZE VIDEO MEMORY BUFFERS +// Initializes tracking of video memory buffers +// +void InitializeVideoMemoryBuffers() { + gVMem = VIDEO_MEM; +} + +///////////////////////////////////////////////////////////////////////////////// +// FLIPBUFFERS +// Interchanges present screen video memory for the present buffer memory. +// This change is made instantly, so all the contents of screen buffer are shown +// at once at the screen. Present screen memory now becomes the new screen +// buffer and viceversa, hence the name "FlipBuffer". +// In order to prevent intermediate flickering, this function waits until +// VSYNC signal is up before flipping both buffers +// +void FlipBuffers() { + cpct_waitVSYNC(); // Wait until VSYNC is up + + // Depending on present video memory, flip from + // Video to Buffer or from Buffer to Video + if (gVMem == BUFFER_MEM) { + cpct_setVideoMemoryPage(cpct_pageC0); + gVMem = VIDEO_MEM; + } else { + cpct_setVideoMemoryPage(cpct_page80); + gVMem = BUFFER_MEM; + } +} + +///////////////////////////////////////////////////////////////////////////////// +// GET SCREEN PTR +// Gets a pointer to a (x,y) location in the current video memory +// +u8* GetScreenPtr(u8 xPos, u8 yPos) { + u8* screenStart; + + // Screen video memory start depends on which hardware + // buffer is currently being used as video memory + if (gVMem == VIDEO_MEM) screenStart = (u8*)CPCT_VMEM_START; + else screenStart = (u8*)SCREEN_BUFF; + + // Calculate and return screen pointer + return cpct_getScreenPtr(screenStart, xPos, yPos); +} + +///////////////////////////////////////////////////////////////////////////////// +// GET BACK BUFFER PTR +// Gets a pointer to a (x,y) location in the present hardware back buffer +// +u8* GetBackBufferPtr(u8 xPos, u8 yPos) { + u8* backBufferStart; + + // Hardware back buffer memory start depends on which hardware + // buffer is currently being used as video memory + if (gVMem == VIDEO_MEM) backBufferStart = (u8*)SCREEN_BUFF; + else backBufferStart = (u8*)CPCT_VMEM_START; + + // Calculate and return screen pointer + return cpct_getScreenPtr(backBufferStart, xPos, yPos); +} \ No newline at end of file diff --git a/examples/medium/colorReplace/src/manageVideoMem.h b/examples/medium/colorReplace/src/manageVideoMem.h new file mode 100644 index 000000000..b508f294b --- /dev/null +++ b/examples/medium/colorReplace/src/manageVideoMem.h @@ -0,0 +1,47 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2018 Bouche Arnaud (@Arnaud6128) +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------ + +//////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// +// MANAGE VIDEO MEMORY +// +// This module groups functions and variables that control video memory. These functions +// take care of which memory is being used as screen video memory and which as hardware +// back buffer. They also switch both buffers on demand. +// This module also controls the function tu perform drawing from a sprite back buffer +// to video memory. When all drawings are finished, and after waiting to VSYNC signal, +// the Sprite Back Buffer is then drawn as one big sprite to screen. This final unique +// operation is fast enough to avoid being caught by raster, then avoiding flickering. +//////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef _MANAGEVIDEOMEM_H_ +#define _MANAGEVIDEOMEM_H_ + +#include + +//////////////////////////////////////////////////////////////////////////////////////////// +// PUBLIC FUNCTION DECLARATIONS +// +void InitializeVideoMemoryBuffers (); +u8* GetScreenPtr (u8 xPos, u8 yPos); +u8* GetBackBufferPtr (u8 xPos, u8 yPos); +void FlipBuffers (); + +#endif \ No newline at end of file diff --git a/examples/medium/colorReplace/src/sprites/sprites_gen.txt b/examples/medium/colorReplace/src/sprites/sprites_gen.txt new file mode 100644 index 000000000..e69de29bb diff --git a/examples/medium/screenCapture/.gitignore b/examples/medium/screenCapture/.gitignore new file mode 100644 index 000000000..f9e0cbe8a --- /dev/null +++ b/examples/medium/screenCapture/.gitignore @@ -0,0 +1 @@ +src/sprites/ diff --git a/examples/medium/screenCapture/.vscode/tasks.json b/examples/medium/screenCapture/.vscode/tasks.json new file mode 100644 index 000000000..0285f7abe --- /dev/null +++ b/examples/medium/screenCapture/.vscode/tasks.json @@ -0,0 +1,58 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2017 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------{ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format +{ + "version": "0.1.0" + , "command": "make" + , "isShellCommand": true + , "args": [] + , "showOutput": "always" + , "suppressTaskName": true + , "tasks": [ + { + "taskName": "make" + , "args": [] + , "isBuildCommand": true + , "problemMatcher": { + "owner": "base" + , "fileLocation": ["relative", "${workspaceRoot}"] + , "pattern": { + "regexp": "^(.*):(\\d+):\\s+(warning|error|syntax error)[^:]*:\\s+(.*)$" + , "file": 1 + , "line": 2 + , "severity": 3 + , "message": 4 + } + } + } + , { + "taskName": "clean" + , "args": ["clean"] + } + , { + "taskName": "cleanall" + , "args": ["cleanall"] + } + , { + "taskName": "run" + , "command": "cpct_winape" + , "args": [ "-a" ] + } + ] +} \ No newline at end of file diff --git a/examples/medium/screenCapture/Makefile b/examples/medium/screenCapture/Makefile new file mode 100644 index 000000000..184f61b39 --- /dev/null +++ b/examples/medium/screenCapture/Makefile @@ -0,0 +1,38 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2015 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +########################################################################### +## CPCTELERA ENGINE ## +## Main Building Makefile for Projects ## +##-----------------------------------------------------------------------## +## This file contains the rules for building a CPCTelera project. These ## +## These rules work generically for every CPCTelera project. ## +## Usually, this file should be left unchanged: ## +## * Project's build configuration is to be found in build_config.mk ## +## * Global paths and tool configuration is located at $(CPCT_PATH)/cfg/## +########################################################################### + +## +## PROJECT CONFIGURATION (you may change things there to setup this project) +## +include cfg/build_config.mk + +## +## USE GLOBAL MAKEFILE (general rules for building CPCtelera projects) +## +include $(CPCT_PATH)/cfg/global_main_makefile.mk diff --git a/examples/medium/screenCapture/cfg/build_config.mk b/examples/medium/screenCapture/cfg/build_config.mk new file mode 100644 index 000000000..101220652 --- /dev/null +++ b/examples/medium/screenCapture/cfg/build_config.mk @@ -0,0 +1,167 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2015 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +########################################################################### +## CPCTELERA ENGINE ## +## Build configuration file ## +##-----------------------------------------------------------------------## +## This file is intendend for you to be able to config the way in which ## +## you would like to build this example of use of the CPCtelera Engine. ## +## Below you will find several configuration sections with the macros ## +## available to configure the build, along with explanation comments to ## +## help you understand what they do. Please, change everything you want. ## +########################################################################### + +## CPCTELERA MAIN PATH +## Sets CPCTelera main path for accessing tools and configuration. This +## variable must point to the folder where source and tools are contained. +## Setup creates and environment variable that will be generally used. +## However, when environment variable is not available, this variable +## should have the correct value for the project to compile. +## If you change folder structure, CPCT_PATH should reflect this change. +## This variable should always have the absolute path value. +## +#>> Uses environment variable $(CPCT_PATH) + +#### +## SECTION 1: Project configuration +## +## This section establishes source and object subfolders and the binary objects to +## be built. Normally, you want to change the OBJ files you want to be built, selecting +## only the ones that contain the actual code that will be used by you in your application. +##### + +# Name of the project (without spaces, as it will be used as filename) +# and Z80 memory location where code will start in the generated binary +PROJNAME := screenCapture +Z80CODELOC := 0x4000 + +## +## Folders +## +## SRCDIR = Source files for the project +## DSKFILESDIR = Input files to be added to the final DSK production +## OBJDIR = Object files generated on compilation +## +SRCDIR := src +DSKFILESDIR := dsk_files +OBJDIR := obj + +## +## File extensions +## +## C_EXT = C source files that will be automatically compiled +## ASM_EXT = ASM source files that will be automatically compiled +## BIN_EXT = Binary files that will be automatically converted to C source files for compilation +## OBJ_EXT = Object files generated after compilation +## DSKINC_EXT = Flag object files generated after file inclusion into DSK (to signal that a file has been included) +## +C_EXT := c +ASM_EXT := s +BIN_EXT := bin +OBJ_EXT := rel +DSKINC_EXT := dskinc + +## +## Output Binaries Configuration +## +## IHXFILE = Binary file that SDCC produces after compilation and linkage +## BINFILE = Binary file that is finally included in DSK and CDT (produced by Hex2Bin) +## CDT = CDT file produced +## DSK = DSK file produced +## DSKINC = Flag object file produced to signal DSK already has all include files in it +## +IHXFILE := $(OBJDIR)/$(PROJNAME).ihx +BINFILE := $(OBJDIR)/$(PROJNAME).bin +CDT := $(PROJNAME).cdt +DSK := $(PROJNAME).dsk +DSKINC := $(OBJDIR)/$(DSK).$(DSKINC_EXT) + +## +## TARGETs generated by Makefile: remove those you don't want to be generated +## +## $(CDT): Generates the CDT file with main binary +## $(DSK): Generates the DSK file with main binary +## $(DSKINC): Includes all files from DSKFILESDIR into DSK as binaries +## +TARGET := $(CDT) $(DSK) $(DSKINC) + +## +## OBJS2CLEAN: Additional objects to be removed when running "make clean" +## +OBJS2CLEAN := + +#### +## SECTION 2: TOOL PATH CONFIGURATION +## +## Paths are configured in the global_paths.mk configuration file included +## here. You may overwrite the values of path variables after the include +## if you wanted specific configuration for this project. +#### +include $(CPCT_PATH)/cfg/global_paths.mk + +#### +## SECTION 3: COMPILATION CONFIGURATION +## +## Flags used to configure the compilation of your code. They are usually +## fine for most of the projects, but you may change them for special uses. +##### +Z80CCFLAGS := +Z80ASMFLAGS := -l -o -s +Z80CCINCLUDE := -I$(CPCT_SRC) -I$(SRCDIR) +Z80CCLINKARGS := -mz80 --no-std-crt0 -Wl-u \ + --code-loc $(Z80CODELOC) \ + --data-loc 0 -l$(CPCT_LIB) +#### +## SECTION 4: CALCULATED FOLDERS, SUBFOLDERS AND FILES +## +## These macros calculate code subfolders, get all the source files and generate +## the corresponding subfolders and files in the object directory. All subfolders +## and files with source extension found are added, up to 1 level of depth in +## folder structure inside the main source directory. +#### +include $(CPCT_PATH)/cfg/global_functions.mk + +# Convert images and tilemaps +include cfg/image_conversion.mk +include cfg/tilemap_conversion.mk +include cfg/music_conversion.mk + +# Calculate all subdirectories +SUBDIRS := $(filter-out ., $(shell find $(SRCDIR) -type d -print)) +OBJDSKINCSDIR := $(OBJDIR)/$(DSKFILESDIR) +OBJSUBDIRS := $(OBJDSKINCSDIR) $(foreach DIR, $(SUBDIRS), $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(DIR))) + +# Calculate all source files +CFILES := $(foreach DIR, $(SUBDIRS), $(wildcard $(DIR)/*.$(C_EXT))) +CFILES := $(filter-out $(IMGCFILES), $(CFILES)) +ASMFILES := $(foreach DIR, $(SUBDIRS), $(wildcard $(DIR)/*.$(ASM_EXT))) +ASMFILES := $(filter-out $(IMGASMFILES), $(ASMFILES)) +BIN2CFILES := $(foreach DIR, $(SUBDIRS), $(wildcard $(DIR)/*.$(BIN_EXT))) +DSKINCSRCFILES := $(wildcard $(DSKFILESDIR)/*) + +# Calculate all object files +BIN_OBJFILES := $(patsubst %.$(BIN_EXT), %.$(C_EXT), $(BIN2CFILES)) +CFILES := $(filter-out $(BIN_OBJFILES), $(CFILES)) +GENC_OBJFILES := $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(patsubst %.$(C_EXT), %.$(OBJ_EXT), $(IMGCFILES))) +GENASM_OBJFILES:= $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(patsubst %.$(ASM_EXT), %.$(OBJ_EXT), $(IMGASMFILES))) +C_OBJFILES := $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(patsubst %.$(C_EXT), %.$(OBJ_EXT), $(BIN_OBJFILES) $(CFILES))) +ASM_OBJFILES := $(patsubst $(SRCDIR)%, $(OBJDIR)%, $(patsubst %.$(ASM_EXT), %.$(OBJ_EXT), $(ASMFILES))) +DSKINCOBJFILES := $(foreach FILE, $(DSKINCSRCFILES), $(patsubst $(DSKFILESDIR)/%, $(OBJDSKINCSDIR)/%, $(FILE)).$(DSKINC_EXT)) +OBJFILES := $(C_OBJFILES) $(ASM_OBJFILES) +GENOBJFILES := $(GENC_OBJFILES) $(GENASM_OBJFILES) diff --git a/examples/medium/screenCapture/cfg/image_conversion.mk b/examples/medium/screenCapture/cfg/image_conversion.mk new file mode 100644 index 000000000..6c4a775ae --- /dev/null +++ b/examples/medium/screenCapture/cfg/image_conversion.mk @@ -0,0 +1,64 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2016 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +############################################################################ +## CPCTELERA ENGINE ## +## Automatic image conversion file ## +##------------------------------------------------------------------------## +## This file is intended for users to automate image conversion from JPG, ## +## PNG, GIF, etc. into C-arrays. ## +## ## +## Macro used for conversion is IMG2SPRITES, which has up to 9 parameters:## +## (1): Image file to be converted into C sprite (PNG, JPG, GIF, etc) ## +## (2): Graphics mode (0,1,2) for the generated C sprite ## +## (3): Prefix to add to all C-identifiers generated ## +## (4): Width in pixels of each sprite/tile/etc that will be generated ## +## (5): Height in pixels of each sprite/tile/etc that will be generated ## +## (6): Firmware palette used to convert the image file into C values ## +## (7): (mask / tileset /) ## +## - "mask": generate interlaced mask for all sprites converted ## +## - "tileset": generate a tileset array with pointers to all sprites ## +## (8): Output subfolder for generated .C/.H files (in project folder) ## +## (9): (hwpalette) ## +## - "hwpalette": output palette array with hardware colour values ## +## (10): Aditional options (you can use this to pass aditional modifiers ## +## to cpct_img2tileset) ## +## ## +## Macro is used in this way (one line for each image to be converted): ## +## $(eval $(call IMG2SPRITES,(1),(2),(3),(4),(5),(6),(7),(8),(9), (10))) ## +## ## +## Important: ## +## * Do NOT separate macro parameters with spaces, blanks or other chars.## +## ANY character you put into a macro parameter will be passed to the ## +## macro. Therefore ...,src/sprites,... will represent "src/sprites" ## +## folder, whereas ..., src/sprites,... means " src/sprites" folder. ## +## ## +## * You can omit parameters but leaving them empty. Therefore, if you ## +## wanted to specify an output folder but do not want your sprites to ## +## have mask and/or tileset, you may omit parameter (7) leaving it empty ## +## $(eval $(call IMG2SPRITES,imgs/1.png,0,g,4,8,$(PAL),,src/)) ## +############################################################################ + +## Firmware palette definition as variable in cpct_img2tileset format +PALETTE={13 1 2 3 6 9 10 11 15 19 20 21 24 25 26 0} + +## Automatic conversion for UFO and Buildings sprites for Mode0 pixel format +$(eval $(call IMG2SPRITES,img/ufo.png,0,g,32,0,$(PALETTE),mask,src/sprites,hwpalette)) +$(eval $(call IMG2SPRITES,img/building_1.png,0,g,0,0,$(PALETTE),,src/sprites,)) +$(eval $(call IMG2SPRITES,img/building_2.png,0,g,0,0,$(PALETTE),,src/sprites,)) +$(eval $(call IMG2SPRITES,img/building_3.png,0,g,0,0,$(PALETTE),,src/sprites,)) \ No newline at end of file diff --git a/examples/medium/screenCapture/cfg/music_conversion.mk b/examples/medium/screenCapture/cfg/music_conversion.mk new file mode 100644 index 000000000..f86085c7d --- /dev/null +++ b/examples/medium/screenCapture/cfg/music_conversion.mk @@ -0,0 +1,53 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2016 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +############################################################################ +## CPCTELERA ENGINE ## +## Automatic image conversion file ## +##------------------------------------------------------------------------## +## This file is intended for users to automate music conversion from ## +## original files (like Arkos Tracker .aks) into data arrays. ## +## ## +## Macro used for conversion is AKS2C, which has up to 5 parameters: ## +## (1): AKS file to be converted to data array ## +## (2): C identifier for the generated data array (will have underscore ## +## in front in ASM) ## +## (3): Output folder for .s and .h files generated (Default same folder)## +## (4): Memory address where music data will be loaded ## +## (5): Aditional options (you can use this to pass aditional modifiers ## +## to cpct_aks2c) ## +## ## +## Macro is used in this way (one line for each image to be converted): ## +## $(eval $(call AKS2C,(1),(2),(3),(4),(5)) ## +## ## +## Important: ## +## * Do NOT separate macro parameters with spaces, blanks or other chars.## +## ANY character you put into a macro parameter will be passed to the ## +## macro. Therefore ...,src/music,... will represent "src/music" ## +## folder, whereas ..., src/music,... means " src/sprites" folder. ## +## * You can omit parameters by leaving them empty. ## +## * Parameter (5) (Aditional options) is optional and generally not ## +## required. ## +############################################################################ + +## Convert music/song.aks to src/music/song.s and src/music/song.h +## This file contains a music created with Arkos Tracker. This macro +## will convert the music into a data array called g_mysong that will be +## placed at the 0x42A0 memory address in an absolue way. +## +#$(eval $(call AKS2C,music/song.aks,g_mysong,src/music/,0x42A0)) \ No newline at end of file diff --git a/examples/medium/screenCapture/cfg/tilemap_conversion.mk b/examples/medium/screenCapture/cfg/tilemap_conversion.mk new file mode 100644 index 000000000..21f7d929b --- /dev/null +++ b/examples/medium/screenCapture/cfg/tilemap_conversion.mk @@ -0,0 +1,66 @@ +##-----------------------------LICENSE NOTICE------------------------------------ +## This file is part of CPCtelera: An Amstrad CPC Game Engine +## Copyright (C) 2016 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +## +## This program is free software: you can redistribute it and/or modify +## it under the terms of the GNU Lesser General Public License as published by +## the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public License +## along with this program. If not, see . +##------------------------------------------------------------------------------ + +############################################################################ +## CPCTELERA ENGINE ## +## Automatic image conversion file ## +##------------------------------------------------------------------------## +## This file is intended for users to automate tilemap conversion from ## +## original files (like Tiled .tmx) into C-arrays. ## +## ## +## Macro used for conversion is TMX2C, which has up to 4 parameters: ## +## (1): TMX file to be converted to C array ## +## (2): C identifier for the generated C array ## +## (3): Output folder for C and H files generated (Default same folder) ## +## (4): Bits per item (1,2,4 or 6 to codify tilemap into a bitarray). ## +## Blanck for normal integer tilemap array (8 bits per item) ## +## (5): Aditional options (aditional modifiers for cpct_tmx2csv) ## +## ## +## Macro is used in this way (one line for each image to be converted): ## +## $(eval $(call TMX2C,(1),(2),(3),(4),(5))) ## +## ## +## Important: ## +## * Do NOT separate macro parameters with spaces, blanks or other chars.## +## ANY character you put into a macro parameter will be passed to the ## +## macro. Therefore ...,src/sprites,... will represent "src/sprites" ## +## folder, whereas ..., src/sprites,... means " src/sprites" folder. ## +## * You can omit parameters by leaving them empty. ## +## * Parameters (4) and (5) are optional and generally not required. ## +############################################################################ + +## Conversion Examples +## + +## Convert img/tilemap.tmx to src/tilemap.c and src/tilemap.h +## This file contains a tilemap created with Tiled that uses tiles +## in img/tiles.png. This macro will convert the tilemap into a C-array +## named g_tilemap, containing all the IDs of the tiles that are located +## at each given location of the C-array. +## + +#$(eval $(call TMX2C,img/tilemap.tmx,g_tilemap,src/,4)) + +## Convert img/level0b.tmx to src/levels/level0b.c and src/levels/level0b.h +## This file contains another tilemap created with Tiled. This macro +## will convert the tilemap into a C bitarray of 4-bits per item. The array +## will be named g_level0_4bit. For each tile ID included into the final +## bitarray, only 4 bits will be used. Therefore, each byte of the array +## will contain 2 tile IDs. +## + +#$(eval $(call TMX2C,img/level0b.tmx,g_level0_4bit,src/levels/,4)) \ No newline at end of file diff --git a/examples/medium/screenCapture/img/building_1.png b/examples/medium/screenCapture/img/building_1.png new file mode 100644 index 000000000..a5e0d14f1 Binary files /dev/null and b/examples/medium/screenCapture/img/building_1.png differ diff --git a/examples/medium/screenCapture/img/building_2.png b/examples/medium/screenCapture/img/building_2.png new file mode 100644 index 000000000..574200112 Binary files /dev/null and b/examples/medium/screenCapture/img/building_2.png differ diff --git a/examples/medium/screenCapture/img/building_3.png b/examples/medium/screenCapture/img/building_3.png new file mode 100644 index 000000000..235018de3 Binary files /dev/null and b/examples/medium/screenCapture/img/building_3.png differ diff --git a/examples/medium/screenCapture/img/ufo.png b/examples/medium/screenCapture/img/ufo.png new file mode 100644 index 000000000..91af7df33 Binary files /dev/null and b/examples/medium/screenCapture/img/ufo.png differ diff --git a/examples/medium/screenCapture/src/main.c b/examples/medium/screenCapture/src/main.c new file mode 100644 index 000000000..9b39ada61 --- /dev/null +++ b/examples/medium/screenCapture/src/main.c @@ -0,0 +1,245 @@ +//-----------------------------LICENSE NOTICE------------------------------------ +// This file is part of CPCtelera: An Amstrad CPC Game Engine +// Copyright (C) 2018 Arnaud Bouche +// Copyright (C) 2018 ronaldo / Fremos / Cheesetea / ByteRealms (@FranGallegoBR) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +//------------------------------------------------------------------------------ + +///////////////////////////////////////////////////////////////////////////////// +// INCLUDES +#include + +///////////////////////////////////////////////////////////////////////////////// +// SPRITES +#include "sprites/ufo.h" +#include "sprites/building_1.h" +#include "sprites/building_2.h" +#include "sprites/building_3.h" + +///////////////////////////////////////////////////////////////////////////////// +// USEFUL MACROS AND CONSTANTS +// +#define BOOL u8 +#define TRUE 1 +#define FALSE 0 + +#define SCREEN_CY 200 +#define SCREEN_CX 80 +#define VMEM_SIZE 0x4000 + +#define UFO_Y 120 +#define UFO_INIT_X 0 +#define GRADIENT_CY 10 + +///////////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES + +// This array will contain a copy of the background in the video memory region that +// we will be overwritting with the UFO sprite. This copy will let us erase the +// UFO sprite restoring the previous background. +u8 gScreenCapture[ G_UFO_0_H * G_UFO_0_W ]; + +///////////////////////////////////////////////////////////////////////////////// +// INITIALIZATION +// +void Initialization() { + cpct_disableFirmware(); // Disable firmware to take full control of the CPC + cpct_setVideoMode(0); // Set mode 0 + cpct_setPalette (g_palette, 16); // Set the palette + cpct_setBorder(HW_BLACK); // Set the border color with Hardware color + + // Fill screen with color index 4 (Red) + cpct_memset(CPCT_VMEM_START, cpct_px2byteM0(4, 4), VMEM_SIZE); +} + +///////////////////////////////////////////////////////////////////////////////// +// GET UFO CURRENT ANIMATION SPRITE +// +u8* GetUfoSprite() { + // Private UFO Animation-Status Data + static u8 anim = 0; // Currently selected animation sprite + static u8* const ufoSprite[] = { + g_ufo_0, g_ufo_1, g_ufo_2, g_ufo_3 // Array of all four animation sprites + }; + + // Just get next animation sprite and return it + return ufoSprite[anim++ % 4]; +} + +///////////////////////////////////////////////////////////////////////////////// +// DRAW UFO +// +void DrawUFO() { + // Private data to control UFO location and status + static BOOL moveRight; // Keep move direction + static u8 posX; // Keep position X + + // Get a pointer to the start of the UFO sprite in video memory + // previous to moving. Background will need to be restored at this + // precise location to erase UFO before drawing it in its next location + u8* pvmem_ufoBg = cpct_getScreenPtr(CPCT_VMEM_START, posX, UFO_Y); + + // Temporal pointer to videomemory for drawing sprites (will be used later) + u8* pvmem; + + // UFO Moves towards right or left + // When border is reached, movement direction changes + if (moveRight) { + // If right border reached go to left border + if (posX == SCREEN_CX - G_UFO_0_W) + moveRight = FALSE; // Change direction + else + posX++; // Move to right + } else { + // If left border reached go to right border + if (posX == 0) moveRight = TRUE; // Change direction + else posX--; // Move to left + } + + // Get a pointer to the Screen Video Memory location where + // UFO will be drawn next (in its new location after movement) + pvmem = cpct_getScreenPtr(CPCT_VMEM_START, posX, UFO_Y); + + // Wait for VSync and draw background and UFO + // This drawing operation is fast enough not to be caught by the raster, and does not produce + // any flickering. In other case you have to use double-buffer to prevent this. + cpct_waitVSYNC(); + + //--- UFO REDRAWING + + // Erase UFO at its previous location by drawing background over it + cpct_drawSprite(gScreenCapture, pvmem_ufoBg, G_UFO_0_W, G_UFO_0_H); + + // Before drawing UFO at its new location, copy the background there + // to gScreenCapture buffer. This will let us restore it next time + // the UFO moves. + cpct_getScreenToSprite(pvmem, gScreenCapture, G_UFO_0_W, G_UFO_0_H); + + // Draw UFO at its new location + cpct_drawSpriteMasked(GetUfoSprite(), pvmem, G_UFO_0_W, G_UFO_0_H); +} + +///////////////////////////////////////////////////////////////////////////////// +// FILL LINE OF COLOR +// +void FillLine(u8 pixColor, u8 lineY) { + // Get a pointer to the start of line Y of screen video memory + // and fill it with given colour + u8* pvmem = cpct_getScreenPtr(CPCT_VMEM_START, 0, lineY); + cpct_memset(pvmem, pixColor, SCREEN_CX); +} + +///////////////////////////////////////////////////////////////////////////////// +// DRAW SKY PART FILLED WITH GRADIENT +// +u8 DrawSkyGradient(u8 cy, u8 posY, u8 colorFront, u8 colorBack) { + u8 i, j; + + // Get Mode 0 screen pixel colour representations for front and back colours + u8 pixFront = cpct_px2byteM0(colorFront, colorFront); + u8 pixBack = cpct_px2byteM0(colorBack, colorBack); + + // Draw gradient zone + for (j = 0; j < cy; j++) { + // If end of screen reached stop drawing + if (posY == SCREEN_CY - 2) + break; + + // Draw lines of color + for (i = 0; i < cy - j; i++) { + FillLine(pixFront, posY++); + } + FillLine(pixBack, posY++); + } + + // Return ending line colorized + return posY; +} + +///////////////////////////////////////////////////////////////////////////////// +// DRAW SKY WITH GRADIENT ZONES FOR BACKGROUND +// +void DrawSky() { + // Define color of gradient sky parts + static const u8 colors[] = { 2, 15, 2, 7, 10, 13, 8, 4 }; + + // Current line filled with color + u8 startLine = 0; + + // Screen is divided into gradient zone + u8 i; + for (i = 1; i < sizeof(colors); i++) + startLine = DrawSkyGradient(GRADIENT_CY - i, startLine, colors[i], colors[i - 1]); +} + +///////////////////////////////////////////////////////////////////////////////// +// DRAW CITY WITH ALL BUILDING FOR BACKGROUND +// +void DrawCity() { + u8* pvmem; + + // As all locations of buildings are constant, we use cpctm_screenPtr that + // will calculate screen video memory pointers during compile time (as it + // is a macro). Resulting assembly code will be shorter and faster, as + // it will only contain exact video memory values for pointers, instead of + // code for calculating them. + pvmem = cpctm_screenPtr(CPCT_VMEM_START, 10, SCREEN_CY - G_BUILDING_1_H); + cpct_drawSprite(g_building_1, pvmem, G_BUILDING_1_W, G_BUILDING_1_H); + + pvmem = cpctm_screenPtr(CPCT_VMEM_START, 30, SCREEN_CY - G_BUILDING_2_H); + cpct_drawSprite(g_building_2, pvmem, G_BUILDING_2_W, G_BUILDING_2_H); + + pvmem = cpctm_screenPtr(CPCT_VMEM_START, 40, SCREEN_CY - G_BUILDING_1_H); + cpct_drawSprite(g_building_1, pvmem, G_BUILDING_1_W, G_BUILDING_1_H); + + pvmem = cpctm_screenPtr(CPCT_VMEM_START, 67, SCREEN_CY - G_BUILDING_2_H); + cpct_drawSprite(g_building_2, pvmem, G_BUILDING_2_W, G_BUILDING_2_H); + + pvmem = cpctm_screenPtr(CPCT_VMEM_START, 60, SCREEN_CY - G_BUILDING_3_H); + cpct_drawSprite(g_building_3, pvmem, G_BUILDING_3_W, G_BUILDING_3_H); +} + +///////////////////////////////////////////////////////////////////////////////// +// INITIALIZE FIRST BACKGROUND CAPTURE +// +void InitCapture() { + // Get Screen Video Memory pointer of default UFO location + // and make a copy of the background pixel data there to gScreenCapture buffer + u8* pvmem = cpctm_screenPtr(CPCT_VMEM_START, UFO_INIT_X, UFO_Y); + cpct_getScreenToSprite(pvmem, gScreenCapture, G_UFO_0_W, G_UFO_0_H); +} + +///////////////////////////////////////////////////////////////////////////////// +// DRAW BACKGROUND WITH GRADIENT SKY AND BUILDING +// +void DrawBackground() { + DrawSky(); + DrawCity(); + + InitCapture(); +} + +/////////////////////////////////////////////////////// +/// MAIN PROGRAM +/// +void main(void) { + Initialization(); // Initialize everything + DrawBackground(); // Draw background with sky and buildings + + // Main Loop: Permanently move and draw the UFO + while(1) { + DrawUFO(); + } +} diff --git a/examples/medium/screenCapture/src/sprites/sprites_gen.txt b/examples/medium/screenCapture/src/sprites/sprites_gen.txt new file mode 100644 index 000000000..5f563f4d3 --- /dev/null +++ b/examples/medium/screenCapture/src/sprites/sprites_gen.txt @@ -0,0 +1 @@ +Sprites generation directory \ No newline at end of file