realyime image scaling

Blitz3D Forums/Blitz3D Beginners Area/realyime image scaling

MadsNy(Posted 2004) [#1]
This might seem a bit stupied hehe.. but i've ran into a little problem..

it's simple, i just want an easy way of scaling and image on the scene without loosing it's data.. i want to grab the screen image and place it on on the screen but in like 320*240 or so... like a little window thingie..

trust me. i've been testing all the graphics commands and non of them are good in real time.. ??... do i really have to make an pixel scaling function for this...


BlackD(Posted 2004) [#2]
None of those commands work in real time. The fastest is TFormImage so see what you can do with that. You won't be able to write any faster routine in Blitz, as anything you'd be doing (taking every 2nd pixel or whatver, and writing it to a new image that's half the size) is exactly what Blitz is already doing as fast as it can. ReadPixelFast and WritePixelFast commands are the author's attempt at a joke. ;) J/k :)

The only way to get realtime image resizing (and even it won't be superfast) is to have the images as textures in 3D and let DirectX handle the scaling. You can do this by either:
a) Write a DLL in C which takes an image, converts it to a texture, resizes it, and returns the image to new image handle in Blitz.
b) (recommended) Use a system like sswift's pixel-perfect sprite system to handle your images. This way they're already textures. JimB adapted the system to create the "Sprite Control" library which will do pretty much exactly what you want, though it'd mean re-writing a large portion of your program. You can find it here: http://homepage.ntlworld.com/config/spritecontrol/spritecontrol.htm

Just had a thought, ANOTHER way to do it, is to (again) use Skidracers Pixie code ( http://www.blitzbasic.co.nz/codearcs/codearcs.php?code=773 ). Then:
1. Grab a copy of the scene you want.
2. Convert it to a sprite using "Pixies" on a 3D camera scene, taking up the full screen.
3. Set the cameraviewport to the area where you want to draw the resized image.
4. FLIP - DirectX has handled the sizing of the "scene" in the 3D view in realtime. The thing is, the entire scene is filled with your original image (cause you used Pixie code to position it perfectly at 1:1 pixel:texel ratio), but its now the new, small size.

After that you could even simply "grab" the resized image then free that camera entity so it doesn't interfere with any other 3D that you're doing at the same time. Remember to free the pixie sprite as well. :)

This method should work fine in realtime. It'll require a little re-writing, but you could do it all in an external function so once you've written it, you can just call it with a command like: DrawResized(image,x,y,width,height)

Hope this helps.
+BlackD


MadsNy(Posted 2004) [#3]
hmmmmm. i like the speed of blitz but what i don't like about blitz is that it is it's lack of commands written in ASM or such... perhaps i just don't understand the program good enough, and should learn dll manipulations some more, it just seem's like a giant work for such little tast that some one should have implemented it like in java, lingo, flash, processing....

and i sooooooo much miss OOP......

anyway..---------------------------------
-----------------------------------------

well i going the 3D sprite way... but have a few questions for that one...

1. how to make a sprite on top of the screen all time (like rendering it at the end or so)

2. how to have a sprite in the size of the screen size,, like 800*600, so when i move the sprite 10 px in the x cordinat the sprite will ONLY move 10 px......
i was thinking, a sprite is 1*1 unit long right. ?.. so if we found a ratio for it's Z we could make the sprite 1*1 pixel and hopla we have a nice "image"...

3. are sprites affected by light...

4. is this crazy. hehe


thanks..


BlackD(Posted 2004) [#4]
This is why I recommend using the Pixie system. Go read the code. :)
It handles all of the above by:
1. Setting the zorder to like -99999 so it always draws on top.
2. Figures out the ratio based on the screen width/screen height and positions it pefectly accordingly.
3. Sets EntityFX,1 so its full-bright - unaffected by lights.
4. But it works. ;)

+BlackD


Ross C(Posted 2004) [#5]
There is a real time scaling code aviable. It uses copyrect i think. I used it. I'll try and find it. I'm sure it's on blitzcoder showcase :o)


MadsNy(Posted 2004) [#6]
Thanks. works nicely.

only bug is when using more than one "pixie" (sprite) they flicker when overlapping, just if anyone want to use it aswell....

i think i will be inspired buy the code and make my owne with mesh (quad) and a few functions for making kewl things. hehe.thanks.


Ross C(Posted 2004) [#7]
Ok, this is ripped from a project i did. The image scaling is not mine, but it's fast enough for real time usage, with adding libs.

The scaled image will end up in the handle "final_backround"

Function DrawSizeImage(image,x%,y%,w%,h%) ; x, y, width, height you want scaled too.

     Local ih%=ImageHeight(image)
     Local iw%=ImageWidth(image)

     Local sw%=Abs(w)
     Local sh%=Abs(h)
     
     Local xr#=(Float(iw)/Float(sw))
     Local yr#=(Float(ih)/Float(sh))
     
     fromimg=ImageBuffer(image)
     toimg=ImageBuffer(scratch)
     
     Local vf=-1+((h>0)*2)
     
     Local fw=(w<0)*w
     Local fh=(h<0)*h
     
     If w>=0
          For ix=0 To sw
               CopyRect ix*xr,0,1,ih,ix,0,fromimg,toimg
          Next
     Else
          For ix=0 To sw
               CopyRect ix*xr,0,1,ih,sw-ix,0,fromimg,toimg
          Next
     EndIf
     
     For iy=0 To sh
          CopyRect 0,iy*yr,sw,1,x+fw,y+(iy*vf),toimg,BackBuffer()
     Next

	 CopyRect 0,0,800,600,0,0,BackBuffer(),ImageBuffer(final_backround)
	
End Function



MadsNy(Posted 2004) [#8]
I've change a bit in the pixie code so you now can use image objects, might not be the most pretty way of doing it but it works out nicely.....

but there is one borring problem, when 2 objects overlay they flicker, how to make a layer render stack without messing with the Z cord ???.. if anyone have a good idea for this please post it. would be a super nice tool then...
THANKS for all you help..

; pixies.bb
; by skidracer

; pixies are pixel perfect sprite overlays

; LoadPixie(camera,imagefile$)

; returns a sprite parented to a camera 
; with following features 
;  1:1 pixel-texel scale for zero filtered sharp overlays
;  position pixies in screen coordinates

; 20.8.2003 untested with odd sized sprites
; 21.8.2003 modified to handle odd textures
;
; ADDED BY MADS LARSEN
; 31.10.2004 use image objects as well as image files, change state, 1=obj, 2=file

displaywidth=1024
displayheight=768

Graphics3D displaywidth,displayheight  

cam=CreateCamera() 
CameraRange cam,.1,1000 

;image
img = CreateImage(300,300)
For i=0 To 1000
	
	SetBuffer ImageBuffer(img)
	Plot Rnd(300), Rnd(300)
Next
SetBuffer BackBuffer()


pixie=CreatePixie(cam,img,1)
pixie2=CreatePixie(cam, "D:\blitz3D_max test code\alpha.jpg", 2)

While Not KeyHit(1) 
	PositionEntity pixie,MouseX(),MouseY(),0
	PositionEntity pixie2, 50,50,0
	;ScaleEntity pixie, 100,50, 0
	
	RenderWorld 
	UpdateWorld 
	TurnEntity cam,1,2,0	;test texel drift
	Flip 
	Wend 
End 

Function CreatePixie(camera,file$, state) ; state 1=file, 2=imgObj
; load squared texture
	If state = 1 Then
		;IMAGE
		image = file
		iwidth=ImageWidth(file)
		iheight=ImageHeight(file)
		;TEX	
		texture = CreateTexture(iwidth, iheight)
		width=TextureWidth(texture)
		height=TextureHeight(texture)
	Else	
		texture=LoadTexture(file)
		width=TextureWidth(texture)
		height=TextureHeight(texture)
		image=LoadImage(file)
		iwidth=ImageWidth(image)
		iheight=ImageHeight(image)
	End If
	
	If iwidth<>width Or iheight<>height
		buffer=TextureBuffer(texture)
		ibuffer=ImageBuffer(image)
		For y=0 To height-1
			For x=0 To width-1
				WritePixel x,y,ReadPixel(x,y,ibuffer),buffer
			Next
		Next
		ScaleTexture texture,Float(width)/iwidth,Float(height)/iheight ; will blitzmax need float()?
		width=iwidth
		height=iheight
	EndIf
	FreeImage image
; change these for viewports
	viewwidth=GraphicsWidth()
	viewheight=GraphicsHeight()
; find existing pixiespace parented to camera
	magic=0
	n=CountChildren(camera)
	For i=1 To n
		If EntityName(GetChild(camera,i))="pixiespace" 
			magic=GetChild(GetChild(camera,i),1)
		EndIf
	Next
	If magic=0
		magic=CreatePivot(camera) 
		NameEntity(magic,"pixiespace")
		aspect#=Float(viewheight)/viewwidth
		PositionEntity magic,-1,aspect,1
		scale#=2.0/viewwidth 
		ScaleEntity magic,scale,-scale,-scale 
		magic=CreatePivot(magic)
		PositionEntity magic,-.5,-.5,0
	EndIf
; create sprite from texture as child of magic overlay	
	sprite=CreateSprite()
	EntityParent sprite,magic		;cludge for blitz bug in createsprite(parent)
	brush=CreateBrush()
	BrushFX brush,1
	BrushTexture brush,texture
	PaintEntity sprite,brush
	FreeBrush brush
	SpriteViewMode sprite,2 
	scale#=1.0/viewwidth 
	ScaleSprite sprite,width*scale,height*scale
	Return sprite
End Function



MadsNy(Posted 2004) [#9]
Okay i was playing around with this for some while now...
worked witht the PIXIE code and loved it. but there is a few bugs with it......
eks. rememper to set the Z pos of the entity to something like 0.0001 and change it for each of the objects you make, in this way the flickering stops....

but just to finish my topic i've made a little something something.. hope this will help more newbies. :) hehe
again thanks to mr. Ross C and the pixie guy's.

; another way of using the pixicode...
; ------------------------------------
; this is an example for beginners on
; how to make a copy of the scene in 
; a scaled version on top of the stage
; in exact pixel ratio...

; thanks to Ross C, Pixie
; Mads Larsen - 2. nov. 2004.
; sorry for the bad spelling.

Graphics3D 800,600,32,2 
SetBuffer BackBuffer() 
SeedRnd MilliSecs()

;cam
camera=CreateCamera() 
MoveEntity camera, 0,0,-10
CameraRange camera, 1, 5000
CameraFogMode camera, 1
CameraFogColor camera, 0,155,155
CameraFogRange camera,1300, 3000


;light
L1=CreateLight() 
PositionEntity L1, -200,100,-150



;-------------------- PIXIE or sprite(the real name for it)
; it's always a good idea to make a square pixie, meaning placing a square
; texture/image into it, if you are planning to scale it to a precise
; pixel size later on....
; if you used an non square texture you could end up with a strange
; mid calcualtion for getting eks. a 320*240 sized pixie/entity...

scr_dumb = CreateImage(600,600)

; put a 1 at the end to tell the function that it's an image object and not a file
Pixie= CreatePixie(camera, scr_dumb,1)

; we can now safly used the right pixel size of our entity
ScaleEntity pixie, 320,240,0







;--------------------Texture for the pixie

; creating the texture, remember that blitz only works with square textures
; which means if you in this case create an 800*600 texture, it will inside
; the computer create an 1024*1024 texture automatic, whic is cool but give 
; you a scaling problem...

; if you want to change the texture in realtime it's best that you let
; blitz keep the texture in the Video ram,, VRAM, therefor the 256...
; look up createtexture for more info's

pixTexture = CreateTexture(800,600,256)

;placing the texture on our pixie object (a 3D sprite)
EntityTexture pixie, pixTexture





;-------------------- Scaling the texture properly
; since we are using a smaller image that the texture size we need to scale
; the texture to fit the 1024*1024 texture(remember that blitz automatically make
; the texture into an square 1024*1024 texture....

; so we need a scale ratio.. this is easy to calculate thou...
; our texture is 1024*1024 and the image is 800*600 and we want the 800*600
;pixels to strech out in the 1024*1024 plane.... therefor...

;scale x => 1024/800 = 1.28
;scale y => 1024/600 = 1.7

; and now applying them to the command...
ScaleTexture pixTexture, 1.28,   1.7; X , Y

;if you use smaller texture, well then change the 1024 value.



; ------------------------ building some 3D stuff.
obj1 = CreateCube()
obj2 = CreateCube()
obj3 = CreateCube()
obj4 = CreateCube()

PositionEntity obj1, Rnd(0,2), Rnd(0,2), -8
PositionEntity obj2, Rnd(0,2), Rnd(0,2), -8
PositionEntity obj3, Rnd(0,2), Rnd(0,2), -8
PositionEntity obj4, Rnd(0,2), Rnd(0,2), -8

num = 0
PointEntity camera, obj1


While Not KeyDown( 1 ) 
	num = num +1
	; simple rotation calc.
	RotateEntity obj1, num/0.43,num, num/1.43
	RotateEntity obj2, num/1.43,num, num/1.63
	RotateEntity obj3, num/0.63,num, num/2.43
	RotateEntity obj4, num/0.33,num, num/0.43
	
	; we don't want to draw our "mirrow" image,,, try without, looks cool
	HideEntity pixie
	; draw the wtuff to the buffer so we can copy it later on
	RenderWorld	
	; this is the magic, here we copy the backbuffer to the texture itself
	; look up the copyrect for more info's.
	CopyRect 0,0,800,600,0,0,BackBuffer(),TextureBuffer(pixTexture)
	; show our screen captured image on the screen again.
	ShowEntity pixie
	
	
	
	PositionEntity pixie,MouseX(),MouseY(),-0.01
	RenderWorld 

Flip 
Wend 

End



Function CreatePixie(camera,file$, state) ; state 1=file, 2=imgObj
; load squared texture
	If state = 1 Then
		;IMAGE
		image = file
		iwidth=ImageWidth(file)
		iheight=ImageHeight(file)
		;TEX	
		texture = CreateTexture(iwidth, iheight)
		width=TextureWidth(texture)
		height=TextureHeight(texture)
	Else	
		texture=LoadTexture(file)
		width=TextureWidth(texture)
		height=TextureHeight(texture)
		image=LoadImage(file)
		iwidth=ImageWidth(image)
		iheight=ImageHeight(image)
	End If
	
	If iwidth<>width Or iheight<>height
		buffer=TextureBuffer(texture)
		ibuffer=ImageBuffer(image)
		For y=0 To height-1
			For x=0 To width-1
				WritePixel x,y,ReadPixel(x,y,ibuffer),buffer
			Next
		Next
		ScaleTexture texture,Float(width)/iwidth,Float(height)/iheight ; will blitzmax need float()?
		width=iwidth
		height=iheight
	EndIf
;	FreeImage image
; change these for viewports
	viewwidth=GraphicsWidth()
	viewheight=GraphicsHeight()
; find existing pixiespace parented to camera
	magic=0
	n=CountChildren(camera)
	For i=1 To n
		If EntityName(GetChild(camera,i))="pixiespace" 
			magic=GetChild(GetChild(camera,i),1)
		EndIf
	Next
	If magic=0
		magic=CreatePivot(camera) 
		NameEntity(magic,"pixiespace")
		aspect#=Float(viewheight)/viewwidth
		PositionEntity magic,-1,aspect,1
		scale#=2.0/viewwidth 
		ScaleEntity magic,scale,-scale,-scale 
		magic=CreatePivot(magic)
		PositionEntity magic,-.5,-.5,0
	EndIf
; create sprite from texture as child of magic overlay	
	sprite=CreateSprite()
	EntityParent sprite,magic		;cludge for blitz bug in createsprite(parent)
	brush=CreateBrush()
	BrushFX brush,1
	BrushTexture brush,texture
	PaintEntity sprite,brush
	FreeBrush brush
	SpriteViewMode sprite,2 
	scale#=1.0/viewwidth 
	ScaleSprite sprite,width*scale,height*scale
	Return sprite
End Function