Author Topic: Image color swap?  (Read 1396 times)

0 Members and 1 Guest are viewing this topic.

Offline Craz1000

  • Forum Regular
  • Posts: 111
  • I'm OK
    • Craz1000.net
Image color swap?
« on: March 07, 2020, 01:12:17 pm »
So i am creating another sprite based game. And i have gotten to a point to where i can have an excessive amount of sprites loaded or do a color swap.

my question is... if i have for example
PlayerSprite& = _LOADIMAGE("Images\Player1.png")

If player 1 is blue in color and i want player 2 to be green, am I able just swap blue to green on PlayerSprite& or am i going to have to have 2 different sprites?

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Re: Image color swap?
« Reply #1 on: March 07, 2020, 05:12:47 pm »
Hi, 2 different image handle, but you can do this 2 handle from one image. As show this easy example:

Code: QB64: [Select]
  1.  
  2. 'this do image (the same as load it from harddrive)
  3. UniversalSprite& = _NEWIMAGE(320, 240, 32)
  4. _DEST UniversalSprite&
  5. CLS , Yellow
  6. LINE (20, 20)-(300, 220), Blue, BF
  7.  
  8. SCREEN _NEWIMAGE(800, 600, 32)
  9. Sprite1 = _COPYIMAGE(UniversalSprite&, 32)
  10. Sprite2 = swapcolor(UniversalSprite&, Blue, Red)
  11.  
  12. _PUTIMAGE (50, 100), Sprite1
  13. _PUTIMAGE (430, 100), Sprite2
  14.  
  15. FUNCTION swapcolor (handle, oldcolor~&, newcolor~&)
  16.     DIM m AS _MEM, c AS _UNSIGNED LONG
  17.     swapcolor = _COPYIMAGE(handle, 32)
  18.     m = _MEMIMAGE(swapcolor)
  19.     DO UNTIL a& = m.SIZE - 4
  20.         a& = a& + 4
  21.         c~& = _MEMGET(m, m.OFFSET + a&, _UNSIGNED LONG)
  22.         IF c~& = oldcolor~& THEN _MEMPUT m, m.OFFSET + a&, newcolor~&
  23.     LOOP
  24.     _MEMFREE m
  25.  

you use two handle - Sprite1 and Sprite2, in this example is Sprite1 original image - the same as UniversalSprite and Sprite2 is created from UniversalSprite in red color. So, if your image is easy, you can do it in this way from one source image.

Offline Craz1000

  • Forum Regular
  • Posts: 111
  • I'm OK
    • Craz1000.net
Re: Image color swap?
« Reply #2 on: March 07, 2020, 06:20:42 pm »
Images are very small, probably 50 pixels at most, and have very limited colors. this should do nicely... thank you

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
Re: Image color swap?
« Reply #3 on: March 07, 2020, 08:26:42 pm »
The _MEM approach that Petr shows is probably the easiest way to do that. Testing for specific values and swapping them.

It's funny to me that it is Petr that answered this, as I had the same issue with one of his routines that I used in my project. I wanted to be able the change the colors of the characters in his character image system that he shared at:

https://www.qb64.org/forum/index.php?topic=498.msg3458#msg3458

which makes a handy way to resize text in a graphics screen.

I ended up trying the following after studying Steve's _MEM tutorials (great stuff BTW):

Code: QB64: [Select]
  1. SUB AscAlter2 (var AS _UNSIGNED LONG)
  2.  
  3.     'Changes color/alpha of Petr's character image system- call before Prnt to set desired colors
  4.     'var carries color value
  5.  
  6.     DIM m AS _MEM
  7.     c = 0
  8.     DO '                                                        iterate through character set
  9.         x = 0
  10.         m = _MEMIMAGE(chr_img(c))
  11.         DO '                                                    iterate through character image
  12.             IF _MEMGET(m, m.OFFSET + x, _UNSIGNED LONG) = &H00000000 THEN 'originals must be in _PRINTMODE _KEEPBACKGROUND
  13.                 'make no change
  14.             ELSE '                                              change color of character pixels
  15.                 _MEMPUT m, m.OFFSET + x, var
  16.             END IF
  17.             x = x + 4 '                                         step to next long value memory location
  18.         LOOP UNTIL x >= m.SIZE - 4
  19.         c = c + 1 '                                             advance to next character image
  20.     LOOP UNTIL c = 256
  21.     _MEMFREE m
  22.  
  23. END SUB 'AscAlter2
  24.  

It worked quite well, but after doing a speed test, I found that redefining the set with his original routine was actually about 5 times faster on average. My assumption is that the two nested loops were creating more overhead than _MEM commands were saving. For your application, running through a single loop on a small sprite, it should be fine.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Re: Image color swap?
« Reply #4 on: March 08, 2020, 04:48:34 am »
Quote
OldMoses wrote:

It's funny to me that it is Petr that answered this, as I had the same issue with one of his routines that I used in my project. I wanted to be able the change the colors of the characters in his character image system that he shared

I am almost sure that, due to my poor knowledge of English, I did not understand your question. Now that I understand it, I would follow so:

Code: QB64: [Select]
  1. 'use  IDE 1.4
  2.  
  3. DIM SHARED chars(255) AS LONG
  4. SCREEN _NEWIMAGE(800, 600, 32)
  5.  
  6. FOR Ascii = 0 TO 255
  7.     chars(Ascii) = _NEWIMAGE(10, 20, 32)
  8.     _DEST chars(Ascii)
  9.     _PRINTSTRING (0, 0), CHR$(Ascii), chars(Ascii)
  10. NEXT Ascii
  11.  
  12. Prnt "What you think? Something this?", 1, 10, 10, 20, 15
  13. Prnt "You have many options in QB64...", 2, 10, 500, 20, -15
  14.  
  15.  
  16.  
  17. SUB Prnt (text AS STRING, size AS INTEGER, StartX AS INTEGER, StartY AS INTEGER, Xspace AS INTEGER, Yspace AS INTEGER)
  18.     x = StartX
  19.     y = StartY
  20.     FOR f = 1 TO LEN(text)
  21.         ch = ASC(text, f)
  22.         x = x + Xspace
  23.         IF x MOD 5 = 0 THEN y = y + Yspace
  24.         'colorize character:
  25.  
  26.         ColoredChar = swapcolor(chars(ch), White, _RGB32(RND * 255, RND * 255, RND * 255))
  27.         _PUTIMAGE (x, y)-(x + (size * 16), y + (size * (8 * f))), ColoredChar, 0
  28.         _FREEIMAGE ColoredChar
  29.         _DELAY .1
  30.     NEXT
  31.  
  32. FUNCTION swapcolor (handle, oldcolor~&, newcolor~&)
  33.     DIM m AS _MEM, c AS _UNSIGNED LONG
  34.     swapcolor = _COPYIMAGE(handle, 32)
  35.     m = _MEMIMAGE(swapcolor)
  36.     DO UNTIL a& = m.SIZE - 4
  37.         a& = a& + 4
  38.         c~& = _MEMGET(m, m.OFFSET + a&, _UNSIGNED LONG)
  39.         IF c~& = oldcolor~& THEN _MEMPUT m, m.OFFSET + a&, newcolor~&
  40.     LOOP
  41.     _MEMFREE m
  42.  

This code was added here because the original thread is locked. Is used the same function as in the previous case in this thread.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
Re: Image color swap?
« Reply #5 on: March 08, 2020, 06:42:51 am »
It is likely that SwapColor, as it is, is too sharply focused on a particular color. Compressing images into JPG and PNG formats scatters colors into colors of similar value. This can then cause nasty artifacts. That's why I created a better version here that will recolor pixels with some overlap from the specified color.

I planted the program for use with motion pictures. It's just a quick version that can withstand many improvements and fixes ... but I don't have time for that right now.

Code: QB64: [Select]
  1. 'use  IDE 1.4
  2.  
  3. DIM SHARED chars(255) AS LONG
  4. REDIM Sprites(0) AS LONG, NSprites(0) AS LONG, N2Sprites(0) AS LONG
  5. SCREEN _NEWIMAGE(900, 600, 32)
  6. 'GOTO lspr
  7.  
  8.  
  9. FOR Ascii = 0 TO 255
  10.     chars(Ascii) = _NEWIMAGE(10, 20, 32)
  11.     _DEST chars(Ascii)
  12.     _PRINTSTRING (0, 0), CHR$(Ascii), chars(Ascii)
  13. NEXT Ascii
  14.  
  15. Prnt "What you think? Something this?", 1, 10, 10, 20, 15
  16. Prnt "You have many options in QB64...", 2, 10, 500, 20, -15
  17.  
  18. 'lspr:
  19.  
  20. LOADSPRITE Sprites(), "penguin.jpg", 55, 100, 10, 0, 477
  21. COPYIMAGEARRAY Sprites(), NSprites()
  22. COPYIMAGEARRAY Sprites(), N2Sprites()
  23. ReColor NSprites(), _RGB32(209, 70, 91), 20, 20, 20, -50, 80, -90
  24. ReColor N2Sprites(), _RGB32(209, 60, 81), 30, 30, 30, -110, 110, 80
  25.     f = f + 1
  26.     IF f > 10 THEN f = 1
  27.  
  28.     _PUTIMAGE (80 * (f - 1), 100), Sprites(f)
  29.     _PRINTSTRING (80 * (f - 1), 100), STR$(f)
  30.  
  31.     _PUTIMAGE (100, 200), Sprites(f)
  32.     _PUTIMAGE (100, 300), NSprites(f)
  33.     _PUTIMAGE (100, 400), N2Sprites(f)
  34.     _DISPLAY
  35.     _LIMIT 20
  36.  
  37.  
  38. SUB Prnt (text AS STRING, size AS INTEGER, StartX AS INTEGER, StartY AS INTEGER, Xspace AS INTEGER, Yspace AS INTEGER)
  39.     x = StartX
  40.     y = StartY
  41.     FOR f = 1 TO LEN(text)
  42.         ch = ASC(text, f)
  43.         x = x + Xspace
  44.         IF x MOD 5 = 0 THEN y = y + Yspace
  45.         'colorize character:
  46.  
  47.         ColoredChar = swapcolor(chars(ch), White, _RGB32(RND * 255, RND * 255, RND * 255))
  48.         _PUTIMAGE (x, y)-(x + (size * 16), y + (size * (8 * f))), ColoredChar, 0
  49.         _FREEIMAGE ColoredChar
  50.         _DELAY .1
  51.     NEXT
  52.  
  53. FUNCTION swapcolor (handle, oldcolor~&, newcolor~&)
  54.     DIM m AS _MEM, c AS _UNSIGNED LONG
  55.     swapcolor = _COPYIMAGE(handle, 32)
  56.     m = _MEMIMAGE(swapcolor)
  57.     DO UNTIL a& = m.SIZE - 4
  58.         a& = a& + 4
  59.         c~& = _MEMGET(m, m.OFFSET + a&, _UNSIGNED LONG)
  60.         IF c~& = oldcolor~& THEN _MEMPUT m, m.OFFSET + a&, newcolor~&
  61.     LOOP
  62.     _MEMFREE m
  63.  
  64. SUB ReColor (arr() AS LONG, oldcolor~&, zoneR AS _UNSIGNED _BYTE, zoneG AS _UNSIGNED _BYTE, zoneB AS _UNSIGNED _BYTE, AddtoR AS _UNSIGNED _BYTE, AddtoG AS _UNSIGNED _BYTE, AddtoB AS _UNSIGNED _BYTE)
  65.     Ro = _RED32(oldcolor~&): Go = _GREEN32(oldcolor~&): Bo = _BLUE32(oldcolor~&): Ao = _ALPHA32(oldcolor~&): DIM Cn AS _UNSIGNED LONG
  66.  
  67.     DO UNTIL complete = UBOUND(arr) - 1
  68.         complete = complete + 1
  69.  
  70.         m = _MEMIMAGE(arr(complete))
  71.         h = 0
  72.         DO UNTIL h = m.SIZE - 4
  73.             h = h + 4
  74.             _MEMGET m, m.OFFSET + h, c~&
  75.             R = _RED32(c~&)
  76.             G = _GREEN32(c~&)
  77.             B = _BLUE32(c~&)
  78.             A = _ALPHA32(c~&)
  79.  
  80.             IF ABS(Ro - R) <= zoneR THEN
  81.                 IF ABS(Go - G) <= zoneG THEN
  82.                     IF ABS(Bo - B) <= zoneB THEN
  83.                         Cn~& = _RGB32(R + AddtoR, G + AddtoG, B + AddtoB)
  84.                         _MEMPUT m, m.OFFSET + h, Cn~&
  85.                     END IF
  86.                 END IF
  87.             END IF
  88.         LOOP
  89.     LOOP
  90.  
  91. SUB COPYIMAGEARRAY (sourceArr() AS LONG, newArr() AS LONG)
  92.     REDIM newArr(LBOUND(sourcearr) TO UBOUND(sourcearr)) AS LONG
  93.     FOR c = LBOUND(sourcearr) TO UBOUND(sourcearr)
  94.         newArr(c) = _COPYIMAGE(sourceArr(c), 32)
  95.     NEXT
  96.  
  97. SUB LOADSPRITE (frames() AS LONG, sourcefile AS STRING, lenght AS INTEGER, height AS INTEGER, frames_total AS INTEGER, Xstart_offset AS INTEGER, ystartoffset AS INTEGER)
  98.     IF _FILEEXISTS(sourcefile) THEN
  99.         handle = _LOADIMAGE(sourcefile, 32)
  100.         REDIM frames(frames_total) AS LONG
  101.         FOR LoadSprte = 1 TO frames_total
  102.             frames(LoadSprte) = _NEWIMAGE(lenght, height, 32)
  103.             predest = _DEST
  104.             _DEST frames(LoadSprte): CLS: _DEST predest
  105.             _PUTIMAGE (0, 0), handle, frames(LoadSprte), (Xstart_offset + (LoadSprte * lenght), ystartoffset)-(Xstart_offset + (LoadSprte * 2 * lenght), ystartoffset + height)
  106.             REM  _CLEARCOLOR White, frames(LoadSprte)
  107.         NEXT
  108.     END IF
  109.  

You need attached sprite image Penguin.jpg for this code.

Offline OldMoses

  • Seasoned Forum Regular
  • Posts: 469
Re: Image color swap?
« Reply #6 on: March 08, 2020, 06:50:44 am »
Excellent! I never thought of swapping colors of just the copy of the character used at the Prnt, I was just redefining the entire set each time.

BTW, it probably has more to do with MY poor English, and it's my first language. My composition is nearly as ham handed as my coding. ;)