Draw image with a solid color

BlitzMax Forums/BlitzMax Beginners Area/Draw image with a solid color

Remember in those old 8-bit and 16-bit games where, for example, when you hit an enemy, his sprite changed to a solid red color then faded back to the normal colors? Is there any easy way to do this?

All I could think of is creating a new image that is just a white "shadow" of the sprite, and drawing it on top of the main one using setalpha.

This can almost definitely be optimised but...

Graphics 800,600,0,0

Global img:TImage = LoadImage("image.png")
Global mask:TPixmap = LoadPixmap("image.png")

Local pixPoint:Byte Ptr
Local w:Int = ImageWidth(img)
Local h:Int = ImageHeight(img)

Global maskTarget:TImage = CreateImage(w, h)
Local map:TPixmap = LockImage(maskTarget)



For Local x:Int = 0 To w-1
	For Local y:Int = 0 To h-1
		pixPoint = PixmapPixelPtr(mask,x,y)
		If (pixPoint[3] < 1) Then
			WritePixel(map, x, y, $00FF0000)
		Else
			WritePixel(map, x, y, $FFFF0000)
		EndIf
	Next
Next

UnlockImage(maskTarget)
DrawImage(maskTarget, 100, 100)

SetClsColor 255,255,255
While Not KeyDown(KEY_ESCAPE)

	If MouseDown(1) Then
		DrawImage maskTarget, MouseX(), MouseY()
	Else
		DrawImage img, MouseX(), MouseY()
	End If
	
	Flip
	Cls
	
Wend
End


you could as well make an "object class" which has 2 images actually in. the regular one and an effect image. the effect image is a grayscale version of the regular one (can be computed on load through similar way as above).

What you then do on an effect is draw the regular image and set blend to alphablend afterwards with an alpha of 0.5 - 0.7.
Now you set the color to the desired one (can change over time) and draw the effect image above the regular one.

Nice blend effect.

Unless you naturally don't want the original colors to be visible at all then you don't draw the regular one and just the effect picture :)

SetBlend LightBlend
SetColor $FF,$00,$00

then draw an all-white version of the object over the top of the full-color one that you already drew.

Perturbatio: Thanks, I'll try it out and see how it goes.

Dreamora and AngelDaniel: Thanks, but that kinda was my original plan already. I just thought maybe there was a better way to do it :)

Edit: Just a bug I think, I tried it out with an image from my game, and it draws a single column of pixels at the end instead of the original position. It is swapped from somewhere else in the image. Also a question, how can I set it to work with different mask colors?

This includes source from sswift for both gl/dx

Perturbatio: I did some research and testing, and I modified your code a bit :P It works flawlessly here for me, I'm going to post here to make sure I didn't do anything wrong, or if anyone has any idea to optimize it.

Method CreateShape()
	Local mask:TPixmap = CopyPixmap(Img.pixmaps[0])
	Local w:Int = ImageWidth(Img)
	Local h:Int = ImageHeight(Img)
	Local target:TPixmap = CreatePixmap(w, h, PF_BGRA8888)
	Local pointer:Byte Ptr
	
	For Local x:Int = 0 To w - 1
		For Local y:Int = 0 To h - 1
			pointer = PixmapPixelPtr(mask, x, y)
			
			'if its transparent, write transparent pixel.
			'else write white pixel.
			If pointer[3] < 1 Then
				WritePixel(target, x, y, $00000000)
			Else
				WritePixel(target, x, y, $FFFFFFFF)
			End If
		Next
	Next
	
	'loads final pixmap inside the image
	Shape = LoadImage(target)
End Method


Img is the object's main image, and Shape is the all-white image. Working flawlessly so far.

not so much an optimization, but if you change Img to be a function parameter and return the result of the LoadImage function rather than assigning it directly, you have yourself a reusable function

CreateShapeFromMask:TImage(img:TImage)()
End Function

myPlayer.DamageImage = CreateShapeFromMask(playerImage)
Monster1.DamageImage = CreateShapeFromMask(monsterImage1)

(actually code may vary)

Good idea :) If I need this outside the building class, I'll change it.

@mothmanbr, I don't understand why you're not using SSwift's code from the link I gave :
SetGraphicsDriver GLMax2DDriver()


Graphics 800,600


image:TImage=LoadImage("max.png")
n:Float=0.4
    SetBlend ALPHABLEND

While Not KeyHit(key_escape)
  Cls
    	
	SetAlpha 1.0
	DrawImage image,100,100
	
	SolidColorOn(0, 0, 255)	
	SetAlpha n
	DrawImage image,100,100
	SolidColorOff()
	
    n:+0.01
    If n>1.0 n=0.1

  Flip
Wend


' -----------------------------------------------------------------------------------------------------------------------------------------------------------
' This function enables solid color rendering.
'
' When rendering with solid colors, the color channels of the images you blit will be overridden with the solid color specified.  The alpha channel will
' remain intact however.
'
' This allows you to render a solid color sprite, white for example, with alpha, over the original, to make it appear to glow. 
' You can vary the strength of the effect by using SetAlpha() before you blit the second pass.
' -----------------------------------------------------------------------------------------------------------------------------------------------------------

	Function SolidColorOn(R%=255, G%=255, B%=255)

		Local TexColorArray#[4]

		SetColor(R, G, B)

		?Win32
			If TD3D7Max2DDriver(_max2dDriver) ' If we are currently rendering with DirectX...
			
				d3d7graphicsdriver().direct3ddevice7().SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_SELECTARG2)
				d3d7graphicsdriver().direct3ddevice7().SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE)
			
			Else ' We are using one of the OpenGL drivers.
		?		
				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND)
				
				TexColorArray[0] = R
				TexColorArray[1] = G
				TexColorArray[2] = B
			
				glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, TexColorArray)
		?Win32		
			EndIf	
		?
		
	End Function


' -----------------------------------------------------------------------------------------------------------------------------------------------------------
' This function disables solid color rendering.
' -----------------------------------------------------------------------------------------------------------------------------------------------------------

	Function SolidColorOff()

		Local TexColorArray#[4]
	
		SetColor(255, 255, 255)
	
		?Win32
			If TD3D7Max2DDriver(_max2dDriver)
				d3d7graphicsdriver().direct3ddevice7().SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE)
				d3d7graphicsdriver().direct3ddevice7().SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE)
			Else
		?	
				glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
				glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, TexColorArray)
		?Win32		
			EndIf
		?
	
	End Function 

<edit> updated for 1.24

tonyg, I don't understand why either :P I'll test it today, must be way better.

Edit: I don't know anything about DX or GL, where do I declare this "PrimaryDevice" and what should it be? Or maybe do I need to import a module?

Ooops. Sorry Bmax core code has changed since then so I have updated the code above to work on 1.24

Awesome, thanks