Archive
Blast from the past
Wow, look what I just found on an old source-disk. A mini paint program I wrote in Delphi (something) ages ago. It’s all one single component, fully ownerdrawn (notice the scrollbars are not exactly modern) and supports both layers, brushes and undo. Sort of a “bare bone” paint program. I never got around adding filters to it, but you can draw with different effects though. It could be fun to raise it from the dead and give it the pixelrage overhaul.
Fun with RTTI
Havent really had time to play with RTTI at all (it’s on my “check it out” list), but today i got inspired by the many cool examples out there and had to give it a go. First stop, dumping an object’s method names. Wish I had this 10 years ago when I made the basic bytecode compiler and 2D game engine GDX. It would have saved me weeks of COM hell.
function getMethodNames(Const aInstance:TObject):TStringList; var mContext: TRttiContext; mEntry: TRttiType; x: Integer; mText: String; mMethods: TArray<TRttiMethod>; const CNT_CLS_PREFIX: Array[Boolean] of string = ('','Class '); CNT_MTD_NAME: Array[Boolean] of string = ('function ','procedure '); begin result:=TStringList.Create; if aInstance<>NIl then begin mEntry := mContext.GetType(aInstance.ClassType); if mEntry<>NIL then Begin mMethods:=mEntry.GetMethods; for x:=low(mMethods) to high(mMethods) do begin mtext:=CNT_CLS_PREFIX[mMethods[x].IsClassMethod]; mText:=mtext + CNT_MTD_NAME[mMethods[x].ReturnType<>NIL]; mtext:=mText + mMethods[x].Name + '()'; if mMethods[x].ReturnType<>NIL then mText:=mText + ':' + mMethods[x].ReturnType.QualifiedName; mtext:=mText + ';'; result.Append(mText); end; end; end; end;
Also make sure you checkout some of the more interesting posts about RTTI out there, this article on Delphi sorcery caught my eye, and also this wiki post on Embarcadero’s servers. Attributes is definitively something I have sorely missed from C#. In a couple of weeks I’ll finally have time to read a book again – and will catch up.
This is going to simplify finishing off my tcp/ip remoting system radically. Mapping directly to loaded packages will give better performance than going via exported interfaces. Hm.. (wheels turning)
Adjustable clipping for pixelrage
This is an experimental clipping routine for pixelrage I wrote long ago. The idea being to have standard helper functions that are universal and that can be used anywhere, in this case it applies as much to pixelrage as it does TBitmap.
Pixel clipping
When copying graphics (blitting) to a surface that has a cliprect installed, there are several steps that needs to be taken (pixelrage takes care of these things for you naturally):
- If the source rectangle is larger or overlaps the cliprect, it must be adjusted
- the difference between source x1,y1 and target x1,y1 must be added to x1,y1
- the difference between source x2,y2 and target x2,y2 must be subtracted from source
- Once correctly adjusted, the input and output codec’s must be pre-fetched
- Copy over each scanline using codec->read to codec->write
When stretching however, the ordeal becomes somewhat different. You still have to adjust the source and target regions, but if the source is smaller than the target your copy routine must be smart enough to apply a fixed math scale factor (which basically means, some pixels will be read more than once in order for scaling to occur).
And clipping for all
I never really got to finish this one, so I release it into the wild (together with pixelrage and byterage). I use these libraries in various older products but I don’t mind sharing and giving back to the community. Hopefully people can re-cycle some of my work, or perhaps use it as inspiration for something better.
Function StretchClip(var srcRect:TRect;var targetRect:TRect; targetClip:TRect):Boolean; var srcWD: Integer; srcHD: Integer; dstWD: Integer; dstHD: Integer; clpWD: Integer; clpHD: Integer; xOff: Integer; yOff: Integer; Begin result:=False; srcWD:=srcRect.right-srcrect.left; srcHD:=srcRect.bottom-srcRect.Top; if (srcWD>0) and (srcHD>0) then begin dstWD:=targetRect.right-targetRect.left; dstHD:=targetRect.bottom-targetRect.Top; if (dstWD>0) and (dstHD>0) then begin clpWD:=targetClip.right-targetClip.left; clpHD:=targetClip.bottom-targetClip.Top; if (clpWD>0) and (clpHD>0) then Begin inc(srcWD); inc(srcHD); inc(dstWD); inc(dstHD); inc(clpWD); inc(clpHD); (* Check of target is within extreme Right and left of clip *) if (targetRect.left<targetClip.Right) and (targetRect.top<targetClip.Bottom) then Begin (* Clip LEFT *) if targetrect.Left<targetclip.Left then Begin (* X Offset by how much? *) xOff:=abs(targetclip.Left - targetrect.Left); (* Is it off by less than the whole width? *) if xoff<srcWD then Begin srcRect.Left:=srcRect.left + xoff; targetRect.Left:=targetclip.Left; dec(dstWD,xoff); dec(srcWD,xoff); end else exit; end; (* CLIP TOP *) if targetrect.Top<targetclip.top then Begin (* Y offset by how much? *) yOff:=abs(targetclip.Top - targetrect.Top); (* is it off by less than the whole height? *) if yOff<srcHD then Begin srcRect.top:=srcRect.top + yOff; targetRect.top:=targetClip.Top; dec(dstHD,yoff); dec(srcHD,yoff); end else exit; end; (* CLIP RIGHT *) if (targetrect.right > targetClip.right) then Begin xOff:=abs(targetrect.right - targetClip.right); if xoff<srcWD then Begin srcRect.Right := srcRect.Right - xoff; targetRect.right:=targetClip.Right; dec(dstWD,xoff); dec(srcWD,xoff); end else exit; end; (* CLIP BOTTOM *) if (targetrect.bottom > targetClip.bottom) then Begin yOff:=abs(targetrect.bottom - targetClip.bottom); if yoff<srcHD then Begin srcRect.bottom := srcRect.bottom - yOff; targetRect.bottom:=targetClip.bottom; dec(dstHD,yOff); dec(srcHD,yOff); end else exit; end; (* Final verdict *) result:=(srcWD>0) and (srcHD>0) and (dstWD>0) and (dstHD>0) and (clpWD>0) and (clpHD>0); end; end; end; end; end;
When we apply our clipper on two unsuspecting rectangles passing by my lab on their way to a square dance, we see that it calculates the correct offset’s and adjusts the buffer values as expected. Now you can feed the adjusted source and target rectangles to your blitter without having to test each scanline or accidentally writing beyond the memory buffer.
Pixels are fun 🙂
procedure TfrmTest.testClip; var srcRect, dstRect,Clip:TRect; begin Clip:=Rect(10,10,109,109); srcRect:=Rect(10,10,60,60); dstRect:=Rect(0,0,115,40); DrawOriginalCords(srcRect,dstRect,clip); if StretchClip(srcRect,dstRect,Clip) then Begin LogToMemo('Clip successfull:'); LogtoMemo('Source = ' + pxlrage.TPXRRect.toString(srcRect)); LogtoMemo('Target = ' + pxlrage.TPXRRect.toString(dstRect)); DrawClippedCords(srcRect,dstRect,clip); end else logToMemo('Clipping resulted in no activity'); end;
Pixelrage released on google code
My personal graphics library, Pixelrage, was today released into the wild on google code
About Pixelrage
PXR is a slim, easy to use and innovative graphics library that represents a foundation for further, more advanced libraries. As such SL does not implement everything under the sun, but aims to provide a rock-solid basis that can be easily extended. By default the unit implements a RAW surface, which is basically a surface held in RAM without any device context. It also provides a Windows DIB implementation that does have a context and can thus be used with blitting and Delphi canvas operations.
PXR is not about the latest cool feature. It is about providing a platform independent foundation, assembly free, that other more advanced libraries can be based.
Features
- 8, 15, 16, 24 and 32 bit pixelbuffers
- Fast native blitter between pixel formats (e.g copy from 32bpp -> 8bpp)
- Palette handling
- Clipping
- Basic primitives (circle, ellipse, rectangle)
- Fill mechanism
- Alpha blending
- Transparency
- DIB implementation
- UNI implementation
Dependencies
As a part of the “rage” group of projects, pixelrage depends on byterage for memory manipulation.
Byterage released on google code
One of my personal units for working with memory, files and buffers in general: byterage, was today released into the wild on Google code (SVN only).
Project description
Byterage is an object pascal class library designed to remove some of the limitations of streams, as well as simplify memory allocation and manipulation. It provides an abstract baseclass with storage agnostic mechanisms for allocating, scaling, inserting, removing and otherwise manipulate a data buffer. In other words, the same API applies to both memory, disk and stream storage. All derived buffer types supports the same flexible methods:
- Push
- Poll
- Insert
- Remove
- ExportTo
- ImportFrom
- FillByte
- FillWord
- FillTriple
- FillLong
- Search
- Zero
- Fill
- Append
- Read
- Write
- Empty
A typical example of use is if you need to insert large amounts of data into an already existing file or buffer, or indeed remove a chunk of data at any given offset. Byterage has been used in a wide variety of scenarios: a flat-file database, a file archiver, a drawing program (for fetching pixel data from files larger than maximum DIB size) and various experiments.
Byterage does not use assembler but is rather object pascal native. It makes full use of loop reduction to gain very high data transfer rates. It also use int64 for data length to avoid problems with large files. Since it’s written in vanilla object pascal (Delphi 7) it should also be compatible with freepascal / Lazarus and modern Delphi compilers (tested on Delphi XE2 without problems).
To make it easy to use byterage with ordinary object pascal streams I have provided a stream adapter class. This will allow you to consume a byterage buffer as a stream, and consequently copy, read and write to or from the buffer via the TStream interface.
Plugins
Byterage is an auxiliary library (yet standalone) of filerage. Filerage offers the same native object pascal API but targets file IO over a broad spectrum of storage devices: local disk, ftp, zip archive, automatically mapped network drive and more. Filerage comes with adapters for Remobjects Remoting Framework but runs faster visa its own “to the metal” remoting system.
You must be logged in to post a comment.