Idea: DrawPadding and CreateTransparentPadding
Monkey Targets Forums/Desktop/Idea: DrawPadding and CreateTransparentPadding
| ||
I've got the following problem: Keeping a padding in the texture still gives jaggies on rotated sprites. No matter if the padding was copied exactly or with alpha = 0. And it's not depending on texture sizes and clamping either, the filter simply makes jaggies on all sides of a rotated Image. ---------------- This is the (4x enlarged) output of the code below: ![]() It looks the same on Intel HD Graphics 4600, ATI Radeon 5450 and Nvidia FX 5500. I don't know what OpenGL modes I might be missing, the filtering is actually there, just not on polygon edges. DrawImageRect a... does the same (see Mojo code) as using XYPadding with even 4 pixels of copied padding, still it's jaggy. DrawImageRect b... draws it with the transparent padding. #MOJO_IMAGE_FILTERING_ENABLED = True Import mojo Class Test Extends App Field a:Image Field b:Image Method OnCreate() a = LoadImage("20x20_red.png") b = LoadImage("8x8_red_on_20x20_transparent.png") End Method OnUpdate() End Method OnRender() Cls 255,255,255 DrawImageRect a, 100.0, 100.0, 4, 4, 12, 12, 25.0, 1.0, 1.0, 0 DrawImageRect b, 140.0, 98.0, 0, 0, 20, 20, 25.0, 1.0, 1.0, 0 End End Function Main() New Test() End https://www.sendspace.com/file/fku58k ---------------- What fixes it is drawing padded images at x-1, y-1 with their padding, which therefore needs to have alpha = 0. So, if you don't use XYPadding you will need one pixel padding, if you use XYPadding you will need two pixels of padding. No matter what, it's not good this way, you would need to work with modified coordinates and dimensions and can't simply design your game without knowing about this or creating some helper class. So it would be very nice if Mojo could do this for me. I mean, there should be flag called Image.DrawPadding that makes DrawImage draw the image with the padding at the extended coordinates. Another thing is, I don't want to keep the padding in the image files myself. XYPadding is ok the way it is and it can't be changed to work differently anyway. But in general, when you export images from a graphics software (e.g. Xara), they don't contain a padding, yet I want it to look nice. So if you could give Mojo a flag called Image.CreateTransparentPadding, that would be neat. Mojo would then create a transparent padding at LoadImage. ---------------- So here are two patches for Mojo GLFW and I would be glad if you could consider implementing this or something simmilar. This is the patch for the DrawPadding flag. In modules/mojo/graphics.monkey: At the consts add: ... Const DrawPadding=8 At the fields add: ... Field px#,py# The beginning of ApplyFlags must be this: ... flags=iflags If flags & DrawPadding px = 2 py = 2 Endif SetHandle Method must be this: ... Method SetHandle( tx#,ty# ) Self.tx=tx+px*0.5 Self.ty=ty+px*0.5 Self.flags=Self.flags & ~MidHandle End HandleX and HandleY must be this: ... Method HandleX#() Return tx-px*0.5 End Method HandleY#() Return ty-py*0.5 End Width and Height must be this: ... Method Width() Return width-px End Method Height() Return height-py End The end of ApplyFlags must be: ... If flags & Image.MidHandle SetHandle (width-px)/2.0,(height-py)/2.0 Endif If frames.Length=1 And frames[0].x=0 And frames[0].y=0 And width=surface.Width And height=surface.Height And Not (flags & DrawPadding) flags|=FullFrame Endif End And the modified DrawSurface2 calls will must be, from first to last occurance: 1) ... renderDevice.DrawSurface2 image.surface,x-image.tx,y-image.ty,f.x,f.y,image.width,image.height 2) ... renderDevice.DrawSurface2 image.surface,0,0,f.x,f.y,image.width,image.height 3) ... renderDevice.DrawSurface2 image.surface,-image.tx+x,-image.ty+y,srcX+f.x,srcY+f.y,srcWidth+image.px,srcHeight+image.py 4) ... renderDevice.DrawSurface2 image.surface,0,0,srcX+f.x,srcY+f.y,srcWidth+image.px,srcHeight+image.py ---------------------- This is the patch for CreateTransparentPadding for GLFW In graphics.monkey: At the Image consts, add the new flag: ... Const CreateTransparentPadding=16 The LoadImage functions must be this: ... Function LoadImage:Image( path$,frameCount=1,flags=Image.DefaultFlags ) #If TARGET = "glfw" Local createTransparentPadding% = 0 If flags & Image.CreateTransparentPadding createTransparentPadding = 2 Endif Local surf:=device.LoadSurface( FixDataPath(path), createTransparentPadding, frameCount ) #Else Local surf:=device.LoadSurface( FixDataPath(path) ) #Endif If surf Return (New Image).Init( surf,frameCount,flags ) End Function LoadImage:Image( path$,frameWidth,frameHeight,frameCount,flags=Image.DefaultFlags ) #If TARGET = "glfw" Local surf:=device.LoadSurface( FixDataPath(path), 0, 0 ) #Else Local surf:=device.LoadSurface( FixDataPath(path) ) #Endif If surf Return (New Image).Init( surf,0,0,frameWidth,frameHeight,frameCount,flags,Null,0,0,surf.Width,surf.Height ) End In graphicsdevice.monkey the declaration must be this: ... #If TARGET = "glfw" Method LoadSurface:Surface( path$, createTransparentPadding#, frameCount# ) #Else Method LoadSurface:Surface( path$ ) #Endif In mojo.glfw.cpp: The declarations must be this: ... virtual gxtkSurface *LoadSurface( String path,int createTransparentPadding,int frameCount ); virtual gxtkSurface *CreateSurface( int width,int height ); virtual bool LoadSurface__UNSAFE__( gxtkSurface *surface,String path,int createTransparentPadding,int frameCount ); The new function and modified LoadSurface methods must be this: ... static void _createTransparentPadding( unsigned char **_data,int *_width,int *_height,int depth,int padding,int frameCount ){ if(padding==0) return; if(frameCount==0) return; unsigned char* data = *_data; int width = *_width; int height = *_height; int frameWidth = width / frameCount; int paddedFrameWidth = frameWidth + padding; int paddedWidth = frameCount * paddedFrameWidth; int paddedHeight = height + padding; unsigned char* paddedData = (unsigned char*) calloc(1, paddedWidth * paddedHeight * depth); int srcStride = width * depth; int dstStride = paddedWidth * depth; for(int frame=0; frame<frameCount; ++frame) { unsigned char *src = data + (frame * frameWidth) * depth; unsigned char *dst = paddedData + (padding/2 * paddedWidth + padding/2 + frame * paddedFrameWidth) * depth; for(int y=0; y<height; ++y) { memcpy(dst, src, frameWidth*depth); src += srcStride; dst += dstStride; } } *_data = paddedData; free(data); *_width = paddedWidth; *_height = paddedHeight; } bool gxtkGraphics::LoadSurface__UNSAFE__( gxtkSurface *surface,String path,int createTransparentPadding,int frameCount ){ int width,height,depth; unsigned char *data=BBGlfwGame::GlfwGame()->LoadImageData( path,&width,&height,&depth ); if( !data ) return false; _createTransparentPadding(&data,&width,&height,depth,createTransparentPadding,frameCount); surface->SetData( data,width,height,depth ); return true; } gxtkSurface *gxtkGraphics::LoadSurface( String path,int createTransparentPadding,int frameCount ){ gxtkSurface *surf=new gxtkSurface(); if( !LoadSurface__UNSAFE__( surf,path,createTransparentPadding,frameCount ) ) return 0; surf->Bind(); return surf; } ---------------------- Usage: ... Local image = LoadImage("unpadded.png", 1, Image.DrawPadding | Image.CreateTransparentPadding) |