TICT TUTORIAL SERIES 1 - Part VII | (c) TI-Chess Team 2001 |
Fast Pixel Access Macros and Line Drawing v1.10 |
This tutorial isn't a real tutorial, but a code demonstration. It shows how to implement the Bresenham line drawing algorithm in C using the TIGCC environment. My english is not good enough to explain the details of the algorithm, but looking on the code should be explanatory enough. If you need such a routine in one of your projects, feel free to copy-and-paste in your source. It's speed gain in comparison to the AMS routine is almost 300% (11150/3800 => 2.93 on a HW1 calculator). So I think it's worth using it if you do a lot of line drawing in your program.
Line drawing, cycle drawing and similar routines have at least one point in common: each of them manipulate single pixels and these manipulations have to be done as fast as possible.
Manipulating single pixels is a little bit cumbersome on the TIs (as well as slow), because 8 pixels are packed into each single byte of the graphics buffer. The following macros are the fasted way I know to access and manipulate single pixels.
Note that using "(y<<5)-(y<<1)" as replacement of "y*30" is even much faster than using a lookup table.#define PIXOFFSET(x,y) (((y)<<5)-((y)<<1)+((x)>>3)) #define PIXADDR(p,x,y) (((unsigned char*)(p))+PIXOFFSET(x,y)) #define PIXMASK(x) ((unsigned char)(0x80 >> ((x)&7))) #define GETPIX(p,x,y) (!(!(*PIXADDR(p,x,y) & PIXMASK(x)))) #define SETPIX(p,x,y) (*PIXADDR(p,x,y) |= PIXMASK(x)) #define CLRPIX(p,x,y) (*PIXADDR(p,x,y) &= ~PIXMASK(x)) #define XORPIX(p,x,y) (*PIXADDR(p,x,y) ^= PIXMASK(x))Stephan Effelsberg (b012414@dvz.fh-koeln.de) has suggested additionally macros to prevent the recalculation of pixel addresses and their masks when it is not really necessary like in the line drawing algorithm for example.
//----------------------------------------------------------------------------- // a == address of a pixel (calculated with PIXADDR macro) // m == mask of a pixel (calculated with PIXMASK macro) //----------------------------------------------------------------------------- #define SETPIX_AM(a,m) (*(a) |= (m)) #define CLRPIX_AM(a,m) (*(a) &= ~(m)) #define XORPIX_AM(a,m) (*(a) ^= (m)) //----------------------------------------------------------------------------- // manipulate pixel address to point to the pixel above or below the current // one //----------------------------------------------------------------------------- #define PIXUP(a) ((a)-=30) #define PIXDOWN(a) ((a)+=30) //----------------------------------------------------------------------------- // manipulate pixel address and offset to point to the pixel to the right or // left (using inline ASM improves this task heavily) //----------------------------------------------------------------------------- #define PIXLEFT(a,m) asm("rol.b #1,%0;bcc.s 0f;subq.l #1,%1;0:"\ : "=d" (m), "=g" (a) : "0" (m), "1" (a)) #define PIXRIGHT(a,m) asm("ror.b #1,%0;bcc.s 0f;addq.l #1,%1;0:"\ : "=d" (m), "=g" (a) : "0" (m), "1" (a))
If you want to use a backbuffer which is not 240 pixels (30 bytes) wide, just modify the first macro which calculates the pixel offset. The rest of macros can be used as they are.
For example: suppose you have a backbuffer which is only 160 pixels (20 bytes) wide. The corresponding PIXOFFSET macro looks like this:#define PIXOFFSET(x,y) (((y)<<4)+((y)<<2)+((x)>>3))
If you want to mix backbuffers of different sizes you can to this by writting two complete separate sets of macros or by using #undef and #define to redefine just macro PIXOFFSET for a specific routine or block of code. Suppose you have defined the macros as above somewhere at the beginning of your sourcecode. By default the macros will now handle buffers which are 240 pixels wide. The following sourcecode shows how to use #undef and #define to redefine the PIXOFFSET macro just for one routine (or a couple of routines), so that the macros will handle "temporary" another buffer width:#undef PIXOFFSET #define PIXOFFSET(x,y) (((y)<<4)+((y)<<2)+((x)>>3)) // now pixel access macros handles 160 pixel wide buffers ... void RoutineWhichOperatesOn160PixelWideBuffer() { // some code ... } #undef PIXOFFSET #define PIXOFFSET(x,y) (((y)<<5)-((y)<<1)+((x)>>3)) // now pixel access macros handles again 240 pixel wide buffers ...Of course this way of re-defining macros is not the best style of programming, but sometimes it very handy.
Check the TICT HQ Website at http://tict.ticalc.org for more tutorials and software.More useful tips, tricks and hints can be found at our Messageboard at: http://pub26.ezboard.com/btichessteamhq.
Suggestions, bug reports and similar are VERY welcome (use our Messageboard for this!!).
Like Xavier from the Doors Team I like it to get postcards from all over the world. If you want to thank me, just send me a postcard with greetings on it. Thats enough.
My snail mail address is:Thomas Nussbaumer Heinrichstrasse 112a A-8010 Graz Austria... and please: no mail bombs if one of my programs had crashed your calculator!
This program may be distributed by any other website for non-commercial use only.
DISTRIBUTIONS ON ANY OTHER MEDIUM (Disc,CD-ROM,DVD etc.) are PROHIBITED without separate allowance of the author.
The author makes no representations or warranties about the suitability of the software and/or the data files, either express or implied. The author shall not be liable for any damages suffered as a result of using or distributing this software and/or data files.
You are free to re-use any part of the sourcecode in your products as long as you give credits including a reference to the TICT-HQ (http://tict.ticalc.org/).