Code archives/3D Graphics - Misc/Test if cubemaps are *truly* supported.
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
[Edit] Markcw has now added some more useful code to further extend the test. Also includes demo now. GFXDriverCaps3D() is a useful function, or, it would be if graphics drivers reported their abilities correctly. After spending a long while bored and toying with the old B3D (it's been a looong time...) I made this snippet to test if a cubemap is rendered correctly. It tests if the cubemap texture is pixel perfect with what was rendered on the back buffer. If the backbuffer and the texture do not match, the function returns false. You might want to alter the texture size to work on a texture the same size as your cubemaps in game to be sure. Marks code was placed here as apparently my method still did not work on all machines. (it did work on the machines i tested it on... but who knows about other variations of machines!..) Also, This can be optimised- the test doesn't technically need to render to set up a cubemap and test. Since you only need to call it after initing the graphics window, its hardly going to be slow anyway. | |||||
;TestCubeMap function example (fixed by markcw) ;setup scene Graphics3D 320,240,0,2 SetBuffer BackBuffer() camera=CreateCamera() light=CreateLight() RotateEntity light,90,0,0 ;sky sphere sky=CreateSphere(16) ScaleEntity sky,500,500,500 FlipMesh sky EntityFX sky,1 skytex=CreateSkyTexture(256,256) EntityTexture sky,skytex,0,0 ;cubemapped cube cube=CreateCube() PositionEntity cube,0,0,5 tex=CreateTexture(32,32,1+128+256) For face=0 To 5 If face=0 Then RotateEntity camera,0,90,0 ;left If face=1 Then RotateEntity camera,0,0,0 ;front If face=2 Then RotateEntity camera,0,-90,0 ;right If face=3 Then RotateEntity camera,0,180,0 ;back If face=4 Then RotateEntity camera,-90,0,0 ;up If face=5 Then RotateEntity camera,90,0,0 ;down SetCubeFace tex,face RenderWorld CopyRect 0,0,32,32,0,0,BackBuffer(),TextureBuffer(tex) Next RotateEntity camera,0,0,0 EntityTexture cube,tex cubemapsupport=TestCubeMap(camera) caps=GfxDriverCaps3D() ;main loop While Not KeyDown(1) pitch#=0 : yaw#=0 If KeyDown(208) Then pitch#=-1 If KeyDown(200) Then pitch#=1 If KeyDown(203) Then yaw#=-1 If KeyDown(205) Then yaw#=1 TurnEntity cube,pitch#,yaw#,0 RenderWorld Text 0,0,"cubemapsupport="+cubemapsupport Text 0,12,"caps="+caps Flip Wend Function CreateSkyTexture(Xsize,Ysize) ;Create a sky sphere texture of given dimensions Local hpal,hmap,htex,ix,iy,ip hpal=CreatePalette(256,100,160,230,255,255,255) ;cyan gradient hmap=CreateHeightMap(hpal,Xsize,Ysize,8,2,1,16,2,0,1,48,0) htex=CreateTexture(Xsize,Ysize) ;set all heightmap points LockBuffer(TextureBuffer(htex)) For iy=0 To Ysize-1 For ix=0 To Xsize-1 ip=PeekByte(hmap,ix+(iy*Xsize)) ;index=x+(y*width) WritePixelFast ix,iy,PeekInt(hpal,ip*4),TextureBuffer(htex) Next Next UnlockBuffer(TextureBuffer(htex)) FreeBank hmap FreeBank hpal Return htex ;texture handle End Function Function CreatePalette(ncol,rmin,gmin,bmin,rmax,gmax,bmax) ;Create a palette for a heightmap of given size and color range Local hpal,ic,red,green,blue hpal=CreateBank(ncol*4) For ic=0 To ncol-1 red=(ic*(rmax-rmin)/ncol)+rmin green=(ic*(gmax-gmin)/ncol)+gmin blue=(ic*(bmax-bmin)/ncol)+bmin PokeInt hpal,ic*4,(red Shl 16)+(green Shl 8)+blue Next Return hpal ;palette bank handle End Function Function CreateHeightMap(hpal,Xdm,Ydm,Xps,Yps,Bps,Blr,Wpr,Mcv,Bcv,Bxs,Bys) ;From "lands.bas" by Per Larsson (www.programmersheaven.com) ;Xps/Yps/Bps=X/Y/Blur pixel step, Blr=blur (smoothing) amount, ;Wpr=water probability (not 0), Mcv=minimum color value, ;Bcv=border color value (0 for none), Bxs/Bys=border X/Y size Local hmap,hnewmap,ix,iy,ystep,xstep,val,ptx,pty,ib,lf,rt,up,dn SeedRnd MilliSecs() ;randomize seed hmap=CreateBank(Xdm*Ydm) hnewmap=CreateBank(Xdm*Ydm) ;make random 2-colors map For iy=0 To Ydm-1 If ystep=0 ;instead of using Step, for variable steps For ix=0 To Xdm-1 If xstep=0 val=Rand(0,Wpr) ;water probability If val=1 : val=BankSize(hpal)-1 : Else : val=1 : EndIf ;set 2-colors If Bcv>0 ;draw border around map If ix<Bys Or ix>=Xdm-Bys Then val=Bcv If iy<Bxs Or iy>=Ydm-Bxs Then val=Bcv EndIf ;set heightmap points, and boxfill in-between points For ptx=0 To Xps-1 For pty=0 To Yps-1 PokeByte hmap,(ix+ptx)+((iy+pty)*Xdm),val ;calculate x,y offset Next Next EndIf xstep=xstep+1 : If xstep>=Xps Then xstep=0 Next EndIf ystep=ystep+1 : If ystep>=Yps Then ystep=0 Next If Blr=0 Then CopyBank hmap,0,hnewmap,0,Xdm*Ydm ;copy 2-colors map ;blur smooth map by pixel steps, average out 2-colors map For ib=1 To Blr For iy=0 To Ydm-1 If ystep=0 For ix=0 To Xdm-1 If xstep=0 ;get surrounding points, and wrap overlapping points lf=ix-Bps : If lf<0 Then lf=Xdm-Bps rt=ix+Bps : If rt>Xdm-Bps Then rt=0 up=iy-Bps : If up<0 Then up=Ydm-Bps dn=iy+Bps : If dn>Ydm-Bps Then dn=0 ;calculate average of current point, blur ;color=(up+lf+rt+down+(pt*2)+lfup+rtup+lfdown+rtdown)/10 val=PeekByte(hmap,ix+(up*Xdm))+PeekByte(hmap,lf+(iy*Xdm)) val=val+PeekByte(hmap,rt+(iy*Xdm))+PeekByte(hmap,ix+(dn*Xdm)) val=val+(PeekByte(hmap,ix+(iy*Xdm))*2) val=val+PeekByte(hmap,lf+(up*Xdm))+PeekByte(hmap,rt+(up*Xdm)) val=val+PeekByte(hmap,lf+(dn*Xdm))+PeekByte(hmap,rt+(dn*Xdm)) val=val/10 If val<Mcv Then val=Mcv ;set minimum color If ib>1 Then PokeByte hmap,ix+(iy*Xdm),val ;set smoothed average ;Set actual heightmap points, in pixel steps For ptx=0 To Bps-1 For pty=0 To Bps-1 PokeByte hnewmap,(ix+ptx)+((iy+pty)*Xdm),val Next Next EndIf xstep=xstep+1 : If xstep>=Bps Then xstep=0 Next EndIf ystep=ystep+1 : If ystep>=Bps Then ystep=0 Next Next FreeBank hmap Return hnewmap ;heightmap bank handle End Function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;ACTUAL FUNCTION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Function TestCubeMap(maincamera) ;This function tests if a card truely does support cubemapping. ;Unfortunately some cards report that they do when they in fact do not. ;This results in garbled output. To test properly, we render some ;cubemaps and check if the texture matches what was rendered to the BackBuffer. ;Function by Damien Sturdy AKA Cygnus, Modified by MarkCW for accuracy. ;returns true or false. true if the test succeeded. If GfxDriverCaps3D()<>110 Then Return 0 Local camera,tex,texsize=32 Local clr[5],badpixels,tolerance=10 Local ok=1,x,y,face,p1,p2 camera=CreateCamera() CameraProjMode maincamera,0 CameraViewport camera,0,0,texsize,texsize tex=CreateTexture(texsize,texsize,1+128+256) For face=0 To 5 If face=0 Then RotateEntity camera,0,90,0 ;left If face=1 Then RotateEntity camera,0,0,0 ;front If face=2 Then RotateEntity camera,0,-90,0 ;right If face=3 Then RotateEntity camera,0,180,0 ;back If face=4 Then RotateEntity camera,-90,0,0 ;up If face=5 Then RotateEntity camera,90,0,0 ;down SetCubeFace tex,face RenderWorld CopyRect 0,0,texsize,texsize,0,0,BackBuffer(),TextureBuffer(tex) For x=1 To texsize-2 For y=1 To texsize-2 p1=ReadPixel(x,y,BackBuffer()) And $FFFFFF p2=ReadPixel(x,y,TextureBuffer(tex)) And $FFFFFF clr[0]=((p1 And $FF0000)/$FF00)/16 clr[3]=((p2 And $FF0000)/$FF00)/16 clr[1]=((p1 And $00FF00)/$FF)/16 clr[4]=((p2 And $00FF00)/$FF)/16 clr[2]=(p1 And $0000FF)/16 clr[5]=(p2 And $0000FF)/16 If clr[0]<>clr[3] And clr[1]<>clr[4] And clr[2]<>clr[5] badpixels=badpixels+1 EndIf Next Next ;Print " " : Delay(500) Next If badpixels<(((6*texsize*texsize)/100)*tolerance) Then ok=1 CameraProjMode maincamera,1 FreeEntity camera FreeTexture tex Return ok End Function |
Comments
| ||
http://dictionary.reference.com/search?q=truly |
| ||
Was that really needed?... (I'm sorry for not bothering to proof read my text. I could have, you know, not bothered to share the code too.) Fixed. (Why can you edit the titles here but not in the forums?) |
| ||
No offense meant. That's just a common misspelling that really bugs me. ;) |
| ||
Okiedoke :-) not sure why I was even so uptight about it hehe. |
| ||
I was curious to see if this worked so I set up a small scene to apply the cubemap test to and it didn't work! This is a good idea if some cards don't work like you say. It's badly realized however. First you check the edges of the texture which is not going to be pixel perfect because of bleeding. Second your pixel perfect approach is no use to anyone really, so I changed it to check red, green and blue are similar in value. Also instead of rejecting cubemap support if some pixels are wrong, I added a bad pixel count and if it's above a certain tolerance then it rejects cubemap support. Also, you weren't rotating the camera so your cubemap was rendering the same view each time. |
| ||
@Mark, ok, thanks for testing this- It worked here but I only had access to three machines. The function worked accurately on these three. Also, you weren't rotating the camera so your cubemap was rendering the same view each time. You're supposed to call it after Graphics3D, in place of your DriverCaps test. Since when you call it after graphics3D, you wont have a scene to render, no rotation is necesary. in fact, you could skip calling render completely and just cls to a certain colour. The test it to simply see if the texture comes out correct. Therefore there is no need to rotate the camera- this was missed on purpose. Saying that, I suppose there is a possibility that a non-compliant card filles a cubemap with black, therefore making a false pass? can't say i've seen that before though. ALthough, thanks for updating. I hoped people would do this! :-) You do have a better method here, and your bad pixel count is a great idea- if a few pixels are missing then it won't normally affect the whole scene so doesnt necesarily mean they are useless. I hope you don't mind me updating the original post with your code so that people get the most up to date version? |
| ||
Well, rendering a plain color isn't really a proper test, better to render an actual scene. The bad pixel method wasn't actually necessary to get it working. Once I avoided checking the pixels on the very edge I could do a pixel perfect check, but I think it's better to be a little generous since some cards may be a little poor. Of course not. |
| ||
Cygnus, I just noticed a little error, actually this explains something I couldn't understand. Your code here was wrong:CopyRect 0,0,texsize-1,texsize-1,0,0,BackBuffer(),TextureBuffer(tex) You were copying texsize-1 for width and height, so when you checked those pixels they were always wrong. This is why it didn't work. So I thought it was bleeding but it was just this error. Still, there's no harm in avoiding the edges anyway. Code updated. |
| ||
Oof! In which case I actually put old code up! I initially did that because as a Max user i'm used to things being 0-31. (a 32x32 texture would be 0-31,0-31 here.) but the code I have here actually doesn't have the -1,-1. I updated the initial post. I was going to comment on your texture comment as I wasn't sure how a texture buffer could "wrap" or blur. I should check my code more! ;-) |
| ||
Hi, well if you hadn't made that little mistake I wouldn't have improved your code. I think it's essential to actually render a scene properly, if you just render a single color maybe a card could do that but not do a proper scene. Yeah, I couldn't understand why it wouldn't work so I just assumed it was because of bleeding but you only get that when you render to texture. Edit: also, you missed my other edit here: CopyRect 0,0,32-1,32-1,0,0,BackBuffer(),TextureBuffer(tex) |
| ||
updated. Lol, I recognise that heightmap code- used it in a few Qbasic projects back in the day! :-) think it's essential to actually render a scene properly, if you just render a single color maybe a card could do that but not do a proper scene. I was pondering on this too, but the machines i tested it on when failed, just put garbage on the texture, rather than managed the single colour. still, better to be sure eh! Mostly its the Intel chipsets that fail. certainly this 945 chipset with latest drivers fails. My old Nvidia fails too but that one is clearly a driver bug. The function is good because it detects both lack of hardware support and if a driver is buggy. Thanks for your tweaks BTW, it's even more useful now. |
Code Archives Forum