IGNORED

# IntyBASIC Foreground Black All?

## Recommended Posts

Masters of POKE and/or GRAM, what is a way to set the foreground color of all 64 items in GRAM to foreground color of black? Hmmm how to do it to the GROM Items as well? In Color Stack mode.

I dont want to change the foreground color of every item displayed on BACKTAB (eg I dont want to for...next from 0 to 239) because that wont give the effect I'm going for.

Bonus ask - how to read the foreground color of any given BACKTAB tile?

Thanks!

Edited by First Spear
##### Share on other sites

Sorry, recursive is the way to go unfortunately... I had to do it with Mad Bomber to change the foreground pixel of the building. For and next of course. \$200 is the backtab address, I don't use the constant.bas since I don't want to remember how to spell the words.

for x=0 to 239
#Mcard= peek (\$200+x) 'get the backtab card information
#Mcard=#Mcard/8 'delete the first 3 bits
#Mcard=#Mcard*8 'add the 3 zero to the first 3 bits
poke(\$200+x,#Mcard) 'write the result back to the backtab

next x

This is for the entire screen. If you need to trim part of the screen, then

for x=0 to 199
#Mcard= peek (\$200+40+x) 'get the backtab card information
#Mcard=#Mcard/8 'delete the first 3 bits
#Mcard=#Mcard*8 'add the 3 zero to the first 3 bits
poke(\$200+40+x,#Mcard) 'write the result back to the backtab
next x

Just add 40 or whatever you need. Just make sure to stay in the backtab range 0-239, otherwise it'll overwrite the stack. I'm sure someone here who a master of bitmask can give you another solution than mine.

Of course for one item on screen. Remove for and next, then replace 40 with a variable.

changetoblack=40 'give argument to changetiletoblack

gosub changetiletoblack 'call routine

changetiletoblack:procedure
#Mcard= peek (\$200+changetoblack) 'get the backtab card information
#Mcard=#Mcard/8 'delete the first 3 bits
#Mcard=#Mcard*8 'add the 3 zero to the first 3 bits
poke(\$200+changetoblack,#Mcard) 'write the result back to the backtab
end

This should work with GROM that are on screen.

EDIT: Oh yeah, somehow you have to turn the colorstack bit off for the tiles that uses the pastel color. Master of bitmask can help you with that. Look up bitmask and see to use AND/OR/NOT bitmask to get the result you need to set the 4 bits to zero. Possibly this one to set the bits you need to 0 &0001000000000111

#Mcard = peek(\$200+changetoblack+x)
#Mcard = #Mcard AND &0001000000000111(??)
poke (\$200+changetiletoblack, #Mcard)

EDIT 2: Change bit in &0001000000000111, Kiwi need caffeine badly.

Edited by Kiwi
##### Share on other sites

What if one uses Color Stack mode and inverts all graphics, so your background becomes foreground and vice versa? Can you change the contents of the color stack in one go, and all characters painted with that colour will change? I've never got the hang of CS mode so I don't know, but I imagine it works like a paletted mode.

Obviously it would only work with GRAM that you can modify, not GROM which already has its pixels set and cleared.

Edited by carlsson
##### Share on other sites

If you really do want to set the foreground color of all tiles in BACKTAB that correspond to GRAM tiles, then I'd personally recommend assembly language. A FOR loop will be too slow. (GRAM itself has no color information; all the color information is in BACKTAB.)

The loop itself would look something like this, assuming color stack:

.

```        MVII    #\$0200, R5              ; BACKTAB address
MVII    #\$0800, R4              ; GRAM/GROM bit
MVII    #\$EFF8, R3              ; FG color mask
MVII    #\$F0,   R2              ; number of BACKTAB cards
B       @@clr_gram_to_blk_1     ; skip first decrement
@@clr_gram_to_blk:
DECR    R2                      ; decrement remaining cards
BEQ     @@clr_gram_to_blk_done  ; leave when zero
@@clr_gram_to_blk_1:
MVI@    R5,     R0              ; get card
MOVR    R0,     R1              ; \
ANDR    R4,     R1              ;  |- don't touch if GRAM bit is 0
BEQ     @@clr_gram_to_blk       ; /

ANDR    R3,     R1              ; Clear fg color bits from card
DECR    R5                      ; \_ put on the screen
MVO@    R1,     R5              ; /

DECR    R2                      ; \_ decrement remaining card count
BNEQ    @@clr_gram_to_blk_1     ; /
@@clr_gram_to_blk:
```

.

Even that loop will take longer than 1 frame time in the worst case.

You can get back some of the cycles by unrolling. Decrement/branch is 15 cycles. Of the ~15200 cycles in the loop above, 3600 are just decrement/branch. Unrolling by a factor of 2 would give a ~10% speedup. The same loop as a FOR loop w/ #BACKTAB[] or PEEK/POKE would be rather more expensive (something like 4x).

To drop this into IntyBASIC, slather it in ASM directives as needed, or make it CALLable and CALL it.

##### Share on other sites

```        MVII    #\$0200, R5              ; BACKTAB address
MVII    #\$0800, R4              ; GRAM/GROM bit
MVII    #\$EFF8, R3              ; FG color mask
MVII    #\$F0,   R2              ; number of BACKTAB cards
B       @@clr_gram_to_blk_1     ; skip first decrement
@@clr_gram_to_blk:
DECR    R2                      ; decrement remaining cards
BEQ     @@clr_gram_to_blk_done  ; leave when zero
@@clr_gram_to_blk_1:
MVI@    R5,     R0              ; get card
MOVR    R0,     R1              ; \
ANDR    R4,     R1              ;  |- don't touch if GRAM bit is 0
BEQ     @@clr_gram_to_blk       ; /

ANDR    R3,     R1              ; Clear fg color bits from card
DECR    R5                      ; \_ put on the screen
MVO@    R1,     R5              ; /

DECR    R2                      ; \_ decrement remaining card count
BNEQ    @@clr_gram_to_blk_1     ; /
@@clr_gram_to_blk:
```

Question about DECR R5. Would we need to increase R5 instead of decreasing by doing INCR R5 since backtab starts at \$200? I think it would work if R5 is \$200+\$EF

##### Share on other sites

Hmmm... perhaps I am misunderstanding and oversimplifying your question, going by the more complex answers of others, but if you are using Color Stack mode and you are just looking to change the background color of all cards in the BACKTAB... just update the colors in the stack.

If your entire background uses only one Color Stack slot (i.e., no cards have the "Advance" flag set), then you just need to update the first slot of the stack. Otherwise, you'll have to update all four slots in the stack.

It seems that the solutions offered before were for Foreground/Background mode, where the background color is stored on the cards themselves; but you did say you are using Color Stack mode, right?

What if one uses Color Stack mode and inverts all graphics, so your background becomes foreground and vice versa? Can you change the contents of the color stack in one go, and all characters painted with that colour will change? I've never got the hang of CS mode so I don't know, but I imagine it works like a paletted mode.

That's exactly how it works in Color Stack mode, which is what I thought First Spear asked. It works the same for both GRAM and GROM (like intvnut mentioned, there is no color information on the graphics card, it's all in the BACKTAB; and in the case of Color Stack mode, no background information is there either: it's in the stack).

Bonus ask - how to read the foreground color of any given BACKTAB tile?

Thanks!

You just PEEK it from from the BACKTAB card and decode it. The Color Stack data in BACKTAB is a 13-bit bitmap encoded as follows:

```    13   12    11   10    9    8    7    6    5    4    3    2    1    0
+----+-----+----+----+----+----+----+----+----+----+----+----+----+----+
|Adv.|FG   |GRAM|           GRAM/GROM Card #            |   FG Color   |
|col |Bit3/|GROM|    (0-255 for GROM, 0-63 for GRAM)    |   Bits 0-2   |
|stck|     |    |                                       |              |
+----+-----+----+----+----+----+----+----+----+----+----+----+----+----+

```

For Foreground/Background Mode, the encoding is as follows:

```    13   12   11   10    9    8    7    6    5    4    3    2    1    0
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
|BG  |BG  |GRAM|BG  |BG  |      GRAM/GROM Card #       |   FG Color   |
|Bit2|Bit3|GROM|Bit1|Bit0|          (0 - 63)           |   Bits 0-2   |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+

```

In the case of the Color Stack, the color happens to be spread amongst two fields: bits 0-2, and bit 12, but these values should be exposed as color constants in the "CONSTANTS.BAS" file (I know we put them there), you just need to isolate them (a simple "AND" with a mask will do). The constants are pre-pended with "CS_" in their names.

Here is an example in my best IntyBASIC impersonation (it's like speaking in "mock-tongues," but in programming languages ):

```' Fake IntyBASIC-ish pseudo-code.

IF (MyColor = CS_WHITE) THEN
PRINT "The color is white!!!"
END IF
```
##### Share on other sites

Hi. I am only using Color Stack Mode for this. The background color for all tiles is black only, only color 0 is on the stack.

I wanted the fastest way in IntyBASIC to (1) detect the foreground color of a given tile and (2) change the foreground color of any given BACKTAB tile to another color.

There is a lot of great help here on this thread. Thanks everyone! I dont quite have the quick-and-easy IntyBASIC Procedure yet, but am working on it.

##### Share on other sites

Hi. I am only using Color Stack Mode for this. The background color for all tiles is black only, only color 0 is on the stack.

I wanted the fastest way in IntyBASIC to (1) detect the foreground color of a given tile and (2) change the foreground color of any given BACKTAB tile to another color.

There is a lot of great help here on this thread. Thanks everyone! I dont quite have the quick-and-easy IntyBASIC Procedure yet, but am working on it.

Aha! I just re-read your first post and realized that I misunderstood it. For some reason I thought you were talking about changing the background color of all tiles at once. What others posted will do what you want.

To detect the foreground color use the code I posted: it's only a PEEK and AND with mask.

-dZ.

##### Share on other sites

And I thought you wanted to change ALL cards which had one particular foreground colour to another foreground color on the fly, which is why I discussed using only GRAM and define those in inverted mode so you change the behavior of Color Stack mode to having 4 fixed "foreground" colours and then setting the "background" individually on every card, with the benefit you can do just that, changing all cards of a given "foreground" by just altering the stack contents.

##### Share on other sites

How would it have to be edited to make it CALLable?

If you really do want to [snip]

To drop this into IntyBASIC, slather it in ASM directives as needed, or make it CALLable and CALL it.

##### Share on other sites

```        MVII    #\$0200, R5              ; BACKTAB address
MVII    #\$0800, R4              ; GRAM/GROM bit
MVII    #\$EFF8, R3              ; FG color mask
MVII    #\$F0,   R2              ; number of BACKTAB cards
B       @@clr_gram_to_blk_1     ; skip first decrement
@@clr_gram_to_blk:
DECR    R2                      ; decrement remaining cards
BEQ     @@clr_gram_to_blk_done  ; leave when zero
@@clr_gram_to_blk_1:
MVI@    R5,     R0              ; get card
MOVR    R0,     R1              ; \
ANDR    R4,     R1              ;  |- don't touch if GRAM bit is 0
BEQ     @@clr_gram_to_blk       ; /

ANDR    R3,     R1              ; Clear fg color bits from card
DECR    R5                      ; \_ put on the screen
MVO@    R1,     R5              ; /

DECR    R2                      ; \_ decrement remaining card count
BNEQ    @@clr_gram_to_blk_1     ; /
@@clr_gram_to_blk:
```

Question about DECR R5. Would we need to increase R5 instead of decreasing by doing INCR R5 since backtab starts at \$200? I think it would work if R5 is \$200+\$EF

R5 is an auto-increment register. MVI@ R5 will increment it. The DECR "rewinds" R5 so that the MVO@ will overwrite the value we just read.

How would it have to be edited to make it CALLable?

Wrap it like so:

.

```MYCODE:  PROC
PSHR R5

;;; stuff

PULR PC
ENDP
```

.

The label "MYCODE" is the name you'll use to CALL it. IIRC, it needs to be ALLCAPS.

Aha! I just re-read your first post and realized that I misunderstood it. For some reason I thought you were talking about changing the background color of all tiles at once. What others posted will do what you want.

To detect the foreground color use the code I posted: it's only a PEEK and AND with mask.

It's a bit more than that. The original question only wanted to apply this to cards coming from GRAM. So, it's a PEEK, then AND with one mask to see if it's GRAM, and then conditionally AND with a different mask for the value to conditionally POKE back.

Although the request in #7 is different: For all tiles of a particular color, change the color. That requires reading memory, masking the the color bits, doing a comparison, and then conditionally merging the new color bits in (likely XORing here is cheapest).

##### Share on other sites

First Spear: While I don't know for which purpose you need this routine, remember that in case you are planning to enter the ongoing IntyBASIC contest, you may not use machine code routines so in that case only the slower method using IntyBASIC natively will be allowed. Of course if that is not your intention, you don't have that restriction to worry about.

##### Share on other sites

It's a bit more than that. The original question only wanted to apply this to cards coming from GRAM. So, it's a PEEK, then AND with one mask to see if it's GRAM, and then conditionally AND with a different mask for the value to conditionally POKE back.

Well, the last bit of my comment was responding to this question in the first post:

Bonus ask - how to read the foreground color of any given BACKTAB tile?

For any given BACKTAB tile, just PEEK and AND.

-dZ.

##### Share on other sites

I coded up (but haven't tested) a more general purpose routine that should be CALLable from BASIC. You specify 4 parameters:

• Match mask. This is the set of bits you want to compare against.
• Match value: This is the bit pattern you're looking for to consider a "match".
• Modification mask: This is the set of bits that will remain unchanged before applying the modification.
• Modification value: This is the value that'll get XORed in to change the card.

For example, if you want to find all of the red cards and change them to blue cards: CALL MaskMod(\$1007, \$0002, \$EFF8, \$0001)

.

```;; ======================================================================== ;;
;;  Modify all cards matching a masked pattern.                             ;;
;;                                                                          ;;
;;      R1  Match value                                                     ;;
;;      R3  Modification value (XOR)                                        ;;
;;                                                                          ;;
;;  From IntyBASIC, call as:                                                ;;
;;                                                                          ;;
;;                                                                          ;;
;;  If (Card AND MatchMask) == MatchValue Then                              ;;
;;      Card = (Card AND ModMask) XOR ModValue                              ;;
;;                                                                          ;;
;;  This is applied to the entire BACKTAB.                                  ;;
;; ======================================================================== ;;
PSHR    R5

MOVR    R3,         R4
MVII    #\$200,      R3

@@loop:
MOVR    R0,         R5          ;   6 \_ Mask value in memory
AND@    R3,         R5          ;   8 /
CMPR    R1,         R5          ;   6 Is it equal?
BNEQ    @@next                  ;   7(9)  No: Skip

MOVR    R2,         R5          ;   6
AND@    R3,         R5          ;   8
XORR    R4,         R5          ;   6
MVO@    R5,         R3          ;   9
@@next:
INCR    R3                      ;   6
CMPI    #\$2F0,      R3          ;   8
BNEQ    @@loop                  ;   9(7)
;----
;  79 (worst case)

; 79 * 240 = 18960 for the main loop worst case.

PULR    PC
ENDP
```

.

It's slightly longer than a single frame time on NTSC in the worst case, and only about 6500 cycles faster in the best case, so it's still kinda expensive. The code is pretty straightforward, though, and so if you want a different operation with the same general structure, it shouldn't be hard to tweak it.

For the original example of setting all the GRAM cards to black: CALL MaskMod(\$0800, \$0800, \$EFF8, \$0000).

If you wanted a finer-grain filter (such as "GRAM cards in the range 16-31"), you could use a different mask value. I'm sure folks could find a creative use for this routine.

Now, applying this to the full BACKTAB seems like a heavy hammer. To pass more than 4 args to the function, you'd need to use VARPTR and an array somewhere (or DATA statements) to set up the arguments. For example, I could imagine instead specifying a rectangle to apply this to as opposed to the whole BACKTAB.

Unrolling could help the performance a bit. There's about 4080 cycles spent in the looping branch alone.

##### Share on other sites

• 3 weeks later...

Slightly chaning the subject, what is a smart way to read the GRAM shape that is occupying BACKTAB #66, for example? I want to temporarily save the GRAM value for that is there, change it to something, and then change it back later.

Thanks.

Sorry, recursive is the way to go unfortunately... I had to do it with Mad Bomber to change the foreground pixel of the building. For and next of course. \$200 is the backtab address, I don't use the constant.bas since I don't want to remember how to spell the words.

for x=0 to 239
#Mcard= peek (\$200+x) 'get the backtab card information
#Mcard=#Mcard/8 'delete the first 3 bits
#Mcard=#Mcard*8 'add the 3 zero to the first 3 bits
poke(\$200+x,#Mcard) 'write the result back to the backtab

next x

This is for the entire screen. If you need to trim part of the screen, then

for x=0 to 199
#Mcard= peek (\$200+40+x) 'get the backtab card information
#Mcard=#Mcard/8 'delete the first 3 bits
#Mcard=#Mcard*8 'add the 3 zero to the first 3 bits
poke(\$200+40+x,#Mcard) 'write the result back to the backtab
next x
[snip]

##### Share on other sites

Slightly chaning the subject, what is a smart way to read the GRAM shape that is occupying BACKTAB #66, for example? I want to temporarily save the GRAM value for that is there, change it to something, and then change it back later.

Thanks.

The easiest way is the PEEK() the value at the BACKTAB address and then AND it with a mask for the card. That gives you the card number, shifted three bits to the left.

-dZ.

##### Share on other sites

The easiest way is the PEEK() the value at the BACKTAB address and then AND it with a mask for the card. That gives you the card number, shifted three bits to the left.

-dZ.

Or use the built-in BACKTAB# array, which is more self-documenting and doesn't require you to know the address of BACKTAB.

##### Share on other sites

To clarify, you only want to read which card number is at a given place in the BACKTAB, temporarily save it, put a different card there and restore it?

At first I thought you wanted to read the GRAM definition, store those 8 bytes (or 4 words) elsewhere, redefine the GRAM in place and later restore it.

##### Share on other sites

Or use the built-in BACKTAB# array, which is more self-documenting and doesn't require you to know the address of BACKTAB.

Err, #BACKTAB.

I've been looking at a bunch of signal names at \$DAYJOB that are spelled FOO#.

Depending on what exactly you're trying to do, you will either want to mask, or mask and shift, to extract the card number from the value in BACKTAB. If you're looking for a specific card # in BACKTAB (say "47"), it's slightly more efficient to say something like this:

.

```IF (#BACKTAB[66] AND \$FF8) = (47* THEN ...
```

.

than it is to do something like this:

.

```IF ((#BACKTAB[66] AND \$FF8) /  = 47 THEN ...
```

.

That's because IntyBASIC will compute 47*8 at compile time, and that's saves you shifting by 3. (14 cycles)

Likewise, if you want to save/restore the original contents of #BACKTAB[66], you can save the original "unmolested" value to restore later, while still doing some masking to generate the temporary replacement:

.

```' Temporarily put card 42 at #BACKTAB[66], while remembering previous contents.
' Do something special if card 47 was there.
#save = #BACKTAB[66]
#BACKTAB[66] = (#save AND \$F007) + (42* ' The Answer

IF (#save AND \$FF8) = (47* THEN  '... Do Everything Interesting
#orly = \$FE1F
END IF

' ... time passes

' Restore the previous contents of BACKTAB[66]:
#BACKTAB[66] = #save
```

.

Make sense?

Note that GRAM card numbers are in the range \$100 - \$13F, so my example numbers of 42 and 47 above are really GROM card numbers.

##### Share on other sites

If all you want to do is store the GRAM value, presumably to restore it later, you may not want to shift it back and forth -- just mask it and save it. To restore it on the BACKTAB, just do the opposite mask (to clear the bitfield) and add it back.

Something like this (in my pidgin IntyBASIC-ish parlance):

```' Save it...
#saved = #BACKTAB[idx] AND \$F8

' Do work...

' Restore it...
#BACKTAB[idx] = (#BACKTAB[idx] AND (NOT \$F8)) + #saved

```

If you can be confident that the actual BACKTAB cell does not change at all (other than the card number) between the moments you save and restore, then you can save yourself even more processing by just saving the entire BACKTAB value and restoring it wholesale.

-dZ.

##### Share on other sites

• 1 year later...
On 7/12/2018 at 5:37 AM, intvnut said:

I coded up (but haven't tested) a more general purpose routine that should be CALLable from BASIC. You specify 4 parameters:

• Match mask. This is the set of bits you want to compare against.
• Match value: This is the bit pattern you're looking for to consider a "match".
• Modification mask: This is the set of bits that will remain unchanged before applying the modification.
• Modification value: This is the value that'll get XORed in to change the card.

For example, if you want to find all of the red cards and change them to blue cards: CALL MaskMod(\$1007, \$0002, \$EFF8, \$0001)

.

```
;; ======================================================================== ;;
;;  Modify all cards matching a masked pattern.                             ;;
;;                                                                          ;;
;;      R1  Match value                                                     ;;
;;      R3  Modification value (XOR)                                        ;;
;;                                                                          ;;
;;  From IntyBASIC, call as:                                                ;;
;;                                                                          ;;
;;                                                                          ;;
;;  If (Card AND MatchMask) == MatchValue Then                              ;;
;;      Card = (Card AND ModMask) XOR ModValue                              ;;
;;                                                                          ;;
;;  This is applied to the entire BACKTAB.                                  ;;
;; ======================================================================== ;;
PSHR    R5

MOVR    R3,         R4
MVII    #\$200,      R3

@@loop:
MOVR    R0,         R5          ;   6 \_ Mask value in memory
AND@    R3,         R5          ;   8 /
CMPR    R1,         R5          ;   6 Is it equal?
BNEQ    @@next                  ;   7(9)  No: Skip

MOVR    R2,         R5          ;   6
AND@    R3,         R5          ;   8
XORR    R4,         R5          ;   6
MVO@    R5,         R3          ;   9
@@next:
INCR    R3                      ;   6
CMPI    #\$2F0,      R3          ;   8
BNEQ    @@loop                  ;   9(7)
;----
;  79 (worst case)

; 79 * 240 = 18960 for the main loop worst case.

PULR    PC
ENDP```

.

It's slightly longer than a single frame time on NTSC in the worst case, and only about 6500 cycles faster in the best case, so it's still kinda expensive. The code is pretty straightforward, though, and so if you want a different operation with the same general structure, it shouldn't be hard to tweak it.

For the original example of setting all the GRAM cards to black: CALL MaskMod(\$0800, \$0800, \$EFF8, \$0000).

If you wanted a finer-grain filter (such as "GRAM cards in the range 16-31"), you could use a different mask value. I'm sure folks could find a creative use for this routine.

Now, applying this to the full BACKTAB seems like a heavy hammer. To pass more than 4 args to the function, you'd need to use VARPTR and an array somewhere (or DATA statements) to set up the arguments. For example, I could imagine instead specifying a rectangle to apply this to as opposed to the whole BACKTAB.

Unrolling could help the performance a bit. There's about 4080 cycles spent in the looping branch alone.

Where are the magic numbers defined so I would know what mask parameters to use to change one to another?

Thanks!

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.