Colorizing a specific area on the screen.

BlitzMax Forums/BlitzMax Programming/Colorizing a specific area on the screen.

Trader3564(Posted 2008) [#1]
Hi, first of all thanks to all those who have kindly supported/replied on my previous topics.
This time I got stuck trying to make a colorizer thigy for my game. Any tips/tricks/examples maybe, are most welcome. Thank you!


Perturbatio(Posted 2008) [#2]
Perhaps you could elaborate a little more on "colorizer thingy"? :)


Trader3564(Posted 2008) [#3]
haha, okey then. sorry.

It for an RPG. The screen is build up like this:

[_|]

Where on the left i have the tiled map 32x32 tiles, and on the right the game-menu.

So what is need, is a function, or command, or whatever it is, that allows me to recoller all that is visable on the left. (Includes the map, players, animals, etc...)


ImaginaryHuman(Posted 2008) [#4]
Use SetColor before you draw the objects and set the color to whatever `tint` you want them drawn with?


Trader3564(Posted 2008) [#5]
Ah, i think what i meen is colorizing as in changing the RGB levels.

R -100% to +100%
G -100% to +100%
B -100% to +100%


Perturbatio(Posted 2008) [#6]
do you mean:



?


Trader3564(Posted 2008) [#7]
Thank you :) but no, this overrides all the colors.

Here, i made an example:
[img]http://www.fantasaar.com/rgbhsl.jpg[/img]


Derron(Posted 2008) [#8]
If you only want to colorize specific colors of the tiles/sprites - dont use it realtime, precompute the sprites.

How to achieve? Use search function within the blitzmax programming section - I did post it a while ago: ColorizeImage, ColorizeTImage.


bye
MB


CS_TBL(Posted 2008) [#9]
Like this?

Graphics 640,480

Type Tsq
	Field x:Int=Rnd(640),y:Int=Rnd(480),xd:Int=Rnd(-4,4),yd:Int=Rnd(-4,4)
	Field r:Int=Rnd(255),g:Int=Rnd(255),b:Int=Rnd(255)
	Method update()
		x:+xd+640;	y:+yd+480;	x:Mod 640;	y:Mod 480
	End Method
	Method draw()
		SetColor r,g,b
		DrawRect x,y,20,20
	End Method
End Type

Local sq:Tsq[40]
For Local t:Int=0 To 39;sq[t]=New Tsq;Next
Local timer:ttimer=CreateTimer(25)
Repeat
	WaitEvent()
	If EventSource()=timer
		Cls	
		SetBlend SOLIDBLEND		
		SetColor 255,255,255		
		For t=0 To 39
			sq[t].update;sq[t].draw
		Next
		
		SetBlend SHADEBLEND
		SetColor 32,32,32
		DrawRect 512,0,128,480
		SetBlend LIGHTBLEND
		SetColor 160,144,128
		DrawRect 512,0,128,480
		
		SetColor 255,255,255
		DrawText "HP : 142/150",530,20
		DrawText "EXP: 045/100",530,30
		DrawText "MP : 005/50",530,40
		
		SetBlend SOLIDBLEND
		SetColor 255,0,0;DrawRect 530,60,24,24
		SetColor 0,255,0;DrawRect 560,60,24,24
		SetColor 0,0,255;DrawRect 590,60,24,24
		Flip		
	EndIf
Until KeyHit(KEY_ESCAPE)




Trader3564(Posted 2008) [#10]
CS_TBL, it comes closer, but it is not what i ment.

Let me try and explain it another time, but written:

Purple is made out of red and blue.
Yellow out of red and green.

So if i want to make this purple ball yellow, i substract blue, and add green.
What i dont want is have this done pre-computed, as i changed it realtime.

Basicly, i ill use it for effects such as:
Nightfall
Sunrise
Drakredish looking caves
Brightblueish looking water
etc....

The SetColor function, only takes the light & darkness, and forces all colors to turn red.

What i need is (as shown in the picture)
[img="http://www.fantasaar.com/rgbhsl.jpg"]

Is a function that ADDS or SUBSTRACTS blue, or red, or green, or both TO and FROM an area on the screen, in real-time.

In addition i would like to know if it is possible to ADD and SUBSTRACT anything at all?
Like, if i where on top of the colorization to add a darker layer or effect, like a vail, that only lights up when i have a torch. (which i then would want to have a yellowish looking radius but not make ALL look pure yellow, just by adding a bit green and red for that zone.)

What i expect, is that i have to render the whole backbuffer, lock it, apply the effects, unlock it, draw the HUD (which will not be effected) and FLIP it.

Thank you.


nawi(Posted 2008) [#11]
You can do it with pixmaps pixel by pixel, but I'm afraid that is too slow for realtime. Precompute them (I don't think the night/day etc changes every frame).


Dreamora(Posted 2008) [#12]
In realtime? No not possible.
Simply because you have to do it for every pixel manually and you can not use images, only pixmaps / backbuffer.

The only way having such an effect in realtime is using shaders and let the GPU doing it straight "on the data" instead of working on a RAM replica of it that need to be reuploaded again.

What you can do thought is not use a 3 channel picture at all :)
Use 3 images. One for each channel, filled with grayscale values where the color shall be drawn and by what amount and masked out the rest. Now just draw them and use the SetColor to colorize them with the final color you want them to be drawn.
That indeed would work realtime and depending on what you wanted to do, it will even work very good.
But you see that your media must be created for this special use.


Trader3564(Posted 2008) [#13]
I see. Hmm...
Aint it possible to seperate these channels on loading?

It is odd tough, i thoughd that BMAX would be graphicly more powerfull then Multimedia Fustion of ClickTeam. Their software does actualy all that with a snap. But the core there lays in C++
Also i thoughd Visual Basic has no problems with seperating RGB chanels.
Isn't BMAX hardware accelerated?


Dreamora(Posted 2008) [#14]
This has nothing to do with that. MMF is 2D and does everything through CPU. This is nice but damned slow when you want alpha, rotation and scaling.

BM does 2D through 3D acceleration. This is very powerfull in above aspects. But on the other hand, you have to drop many of the "2D tricks" as they just don't work anymore on 3D or not on a usefull performance.

You can seperate the channels on loading if you want to. Load the image as Pixmap and read out the needed data into 3 seperate pixmaps. Thats actually quite simple by just going through all pixels and filter out the 3 colors and write them into a new pixmaps (where you set that color for R, B and G if you want to color it afterwards through SetColor, otherwise its not grayscale)


BM does not do that because its something not done normally, a 3D card takes a 4 component texture so why send 4 single textures if you can send 1 which already contains all 4 channels? It would make it considerably slower, tripple to quadruple the VRAM usage (which is already an issue if you want to target 4-6 year old trash systems ... thought thats near impossible anyway, if you target them, use BlitzPlus which is 2D through DirectX7 DirectDraw and thus has no alpha, realtime scale / rotation therefor)


Perturbatio(Posted 2008) [#15]
I wonder if you could achieve a similar effect by creating alpha masks so that some portions of the image retain their colour when applied over the base colour?

Some experimentation may be necessary.

*EDIT*
Another alternative would of course be to create different graphics for each scene and have them loaded as TAnimImages, you could then advance through the animation to determine the mood (not great for file size or memory but an alternative nonetheless)


Trader3564(Posted 2008) [#16]
Hah, some creative ideas :) i see there i lots of tricks to try. ill do my best and i guess post an update when i found the solution.

@Dreamora "This has nothing to do with that. MMF is 2D and does everything through CPU. This is nice but damned slow when you want alpha, rotation and scaling."
Actualy, it is now Hardware Accelerated. I beleive it uses both. 2D todo 2D, and what can be done, or faster in HWA, is done on HWA.

Thinks i do not really need are: Realtime scaling/Rotation. Alpha, however (like PNG) is really great to have supported.
I will look into BlitzPlus. I do question if its powerfull enough. It is after all a very old product.


PantsOn(Posted 2008) [#17]
i think this is what your after...
this is a very unoptimised replace olour technique.
usage
i:tpixmap = loadpixmap("image.png")

' replace all exact white occurances with bright purple
p:tpixmap = replacecolour(i:tpixamp,$ffffff,$ff00ff)

' replace all nearly white occurances with bright purple
p:tpixmap = replacecolour(i:tpixamp,$ffffff,$ff00ff,10)


functions
Function replacecolour:TPixmap(p:TPixmap,old_rgb:Int,new_rgb:Int,threshold:Int)
	Local w:Int = PixmapWidth(p)
	Local h:Int = PixmapHeight(p)
	Local x:Int,y:Int
	Local b1:Byte Ptr
	Local b2:Byte Ptr
	Local n:TPixmap = CreatePixmap(w,h,pf_BGRA8888)
	
	Local r:Int = (old_rgb Shr 16) & 255
	Local g:Int = (old_rgb Shr 8) & 255
	Local b:Int = (old_rgb Shr 0) & 255
	
	Local p1:TPixmap = ConvertPixmap(p,PF_BGRA8888)
	
	' scan through image
	x  =0
	While x < w
		y = 0
		While y < h
			b1 = PixmapPixelPtr(p1,x,y)
			b2 = PixmapPixelPtr(n,x,y)
			
			If threshold_check(r,b1[2],threshold) And threshold_check(g,b1[1],threshold) And threshold_check(b,b1[0],threshold)
				b2[0] = (new_rgb Shr 0) & 255
				b2[1] = (new_rgb Shr 8) & 255
				b2[2] = (new_rgb Shr 16) & 255
				b2[3] = $ff
			Else
				b2[0] = b1[0]
				b2[1] = b1[1]
				b2[2] = b1[2]
				b2[3] = b1[3]
			EndIf
			
			y:+1
		Wend
		x:+1
	Wend
	
	Return n
End Function

Function threshold_check:Int(v1:Int,v2:Int,t:Int)
	If (v1 > v2-t) And (v1 < v2+t+1) Then Return True
	
	Return False
End Function




PantsOn(Posted 2008) [#18]
or if you want to dirrectly affect the pixels in the pixmap without creating a new pixmap
Function replacecolour2:Int(p:TPixmap,old_rgb:Int,new_rgb:Int,threshold:Int)
	Local w:Int = PixmapWidth(p)
	Local h:Int = PixmapHeight(p)
	Local x:Int,y:Int
	Local c:Int
	Local r1:Int,g1:Int,b1:Int
		
'	Local n:TPixmap = CreatePixmap(w,h,pf_BGRA8888)
	
	Local r:Int = (old_rgb Shr 16) & 255
	Local g:Int = (old_rgb Shr 8) & 255
	Local b:Int = (old_rgb Shr 0) & 255
	
'	Local p1:TPixmap = ConvertPixmap(p,PF_BGRA8888)
	
	' scan through image
	x  =0
	While x < w
		y = 0
		While y < h
			c = ReadPixel(p,x,y)
			r1 = (c Shr 16) & 255 
			g1 = (c Shr 8) & 255 
			b1 = (c Shr 0) & 255 
			
			If threshold_check(r,r1,threshold) And threshold_check(g,g1,threshold) And threshold_check(b,b1,threshold)
				WritePixel p,x,y,new_rgb
			EndIf
			
			y:+1
		Wend
		x:+1
	Wend

	Return True	
End Function




if you have an image you can call the routines with
image.pixmaps[frame]

this gets the pixmap for the relevant frame in the image


Derron(Posted 2008) [#19]
@PantsOn - thats what my suggestion uses too.

Instead of using a yellow ball - you make a gray one - then all colorcombinations are possible - and because you have one standard for the sprites (gray parts), you can easily cut the function call down to "new colors" (instead of oldcol and newcol).

I remember to have grayalien given a code-snippet which also allowed lightness to be modified (so you can use fixed values for color, but dynamical usage of how hard it is melt together and so on).


Depending on how much differently colored sprites of the same base you need the same time you can use precalculated sprites (one dark, one day, one rainy ...).

Its not suitable for "rainbow-colorchanging balls" - therefor you need to experiment with the SetAlpha-Commands and effectsprites.


bye
MB