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