FB II Compiler

PG PRO

Debugging

Memory

System

Mathematics

Resources

Disk I/O

Windows

Controls

Menus

Mouse

Keyboard

Text

Fonts

Drawing

Sound

Clipboard

Printing

Communication

ASM

Made with FB

DRAWING

Rotate a picture


This is a sample code for rotate bitmap images. I wrote this when I don't know how to use assembly labels, so this may be poor.

If you needed full color high speed image rotation code, let me know.

COMPILE 0,_macsBugLabels_dimmedVarsOnly
LOCAL FN rr(srcPtr&,dstPtr&)
  DIM x%,y%
  srcPtr& = srcPtr& + 32
  ` movem d1 / a0 - a1, - (sp)
  ` movea.l ^dstPtr&,a0
  FOR y% = 0 TO 15
    ` clr.w d1
    ` swap d1
    ` movea.l ^srcPtr&,a1
    FOR x% = 0 TO 15
      ` move.w - (a1),d1
      ` add.l d1,d1
      ` move.w d1,(a1)
    NEXT
    ` swap d1
    ` move.w d1,(a0) + ;
  NEXT
  ` movem (sp) + ,d1 / a0 - a1
END FN

LOCAL FN xrr(srcPtr&,dstPtr&)
  DIM x%,y%
  srcPtr& = srcPtr& + 32
  ` movem d1 - d2 / a0 - a1, - (sp)
  ` move.l ^dstPtr&,a0
  FOR y% = 0 TO 15
    ` clr.w d1
    ` move.l ^srcPtr&,a1
    FOR x% = 0 TO 15
      ` move.w - (a1),d2
      ` add.w d2,d2
      ` addx.w d1,d1
      ` move.w d2,(a1)
    NEXT
    ` move.w d1,(a0) + ;
  NEXT
  ` movem (sp) + ,d1 - d2 / a0 - a1
END FN

LOCAL FN showPattern(srcPtr&)
  DIM y%

  FOR y% = 0 TO 15
    PRINT BIN$({srcPtr& + y% + y%})
  NEXT
END FN

LOCAL FN test
  DIM s$,d$ '"256byes work area
  DIM i%

  WINDOW #1,"TEST"
  TEXT _Monaco,9

  FOR i% = 0 TO 15
    % @s$ + i% + i%,1<<i%
  NEXT

  FN showPattern(@s$)
  PRINT "Hit anykey"
  DO
  UNTIL INKEY$<>""
  CLS

  FN rr(@s$,@d$)
  FN showPattern(@d$)

  PRINT "Hit anykey to quit...."
  DO
  UNTIL INKEY$<>""
END FN

FN test

It's been a quiet week on the list, with few juicy code examples. In view of the recent discussion of picture rotation I thought I would post a 90-degree rotation method with two advantages: (1) It works in _any_ color depth. (2) It will use up many spare leisure hours while you try to understand it
' Adapted from C to FutureBasic by Robert Purves,  February, 1999
' and enhanced for colour pictures, by courtesy of GWorlds

' Originally written by:
' Robert B. Denny, Alisa Systems, Inc.  September, 1985
' Copyright (C) 1985, MacTutor Magazine
' Permission granted to use only for non-commercial purposes.
' This notice must be included in any copies made hereof.
' All rights otherwise reserved.

LOCAL FN WeirdRotate(scrnDev&,sGW&,mGW&,tGW&,rectPtr&,dlayPrm)
 DIM fullWidth, halfWidth,err,nowHalf, xRect.8, yRect.8, rect.8
 BLOCKMOVE rectPtr&,@rect,8
 fullWidth=rect.right
 halfWidth=fullWidth>>1
 err=FN LOCKPIXELS(FN GETGWORLDPIXMAP(mGW&))
 err=FN LOCKPIXELS(FN GETGWORLDPIXMAP(tGW&))
 ' Paint starting mask into mask GWorld
 CALL SETGWORLD(mGW&,0)
 CALL ERASERECT(rect)
 CALL SETRECT (xRect,0,0,halfWidth,halfWidth)' Upper left quadrant
 COLOR=_zBlack
 CALL PAINTRECT (xRect)
 CALL SETGWORLD(sGW&,scrnDev&)
 nowHalf=halfWidth
 WHILE (nowHalf)	   ' Main loop
  xRect=rect
  yRect=rect
'Phase 1 - swap left and right cell halves
  CALL COPYBITS (#mGW&+2, #tGW&+2, xRect, xRect, _srcCopy, 0)
  CALL OFFSETRECT (yRect, 0, nowHalf)
  CALL COPYBITS (#mGW&+2, #tGW&+2, xRect, yRect, _srcOr, 0)
  CALL COPYBITS (#sGW&+2, #tGW&+2, rect, xRect, _notSrcBic, 0)
  CALL COPYBITS (#tGW&+2, #sGW&+2, xRect, rect, _srcXor, 0)
  CALL OFFSETRECT (yRect, -nowHalf, -nowHalf)
  CALL COPYBITS (#sGW&+2, #tGW&+2, rect, yRect, _srcXor, 0)
  CALL COPYBITS (#sGW&+2, #sGW&+2, rect, yRect, _srcOr, 0)
  CALL OFFSETRECT (yRect, nowHalf << 1, 0)
  CALL COPYBITS (#tGW&+2, #sGW&+2, xRect, yRect, _srcXor, 0)
'Phase 2 - Exchange lower-right and upper-left  cell quadrants
  CALL COPYBITS (#sGW&+2, #tGW&+2, rect, xRect, _srcCopy, 0)
  CALL OFFSETRECT (yRect, -(nowHalf << 1), -nowHalf)
  CALL COPYBITS (#sGW&+2, #tGW&+2, rect, yRect, _srcXor, 0)
  CALL COPYBITS (#mGW&+2, #tGW&+2, xRect, xRect, _notSrcBic, 0)
  CALL COPYBITS (#tGW&+2, #sGW&+2, xRect, rect, _srcXor, 0)
  CALL OFFSETRECT (yRect, nowHalf << 1, nowHalf<< 1)
  CALL COPYBITS (#tGW&+2, #sGW&+2, xRect, yRect, _srcXor, 0)
'Phase 3 - Refine mask for next smaller cell size
  CALL SETRECT (xRect, 0, 0,  halfWidth,  halfWidth)
  CALL SETRECT (yRect, 0,  halfWidth,  halfWidth, fullWidth)
  CALL COPYBITS (#mGW&+2, #mGW&+2, rect, xRect, _srcCopy, 0)
  CALL COPYBITS (#mGW&+2, #mGW&+2, xRect, yRect, _srcCopy, 0)
  CALL SETRECT (xRect, 0, 0,  halfWidth, fullWidth)
  CALL SETRECT (yRect,  halfWidth, 0, fullWidth, fullWidth)
  CALL COPYBITS (#mGW&+2, #mGW&+2, xRect, yRect, _srcCopy, 0)
  nowHalf=nowHalf>>1 ' Reduce cell size by 1/2
  DELAY (dlayPrm) ' allow viewing
 WEND
 CALL UNLOCKPIXELS(FN GETGWORLDPIXMAP(mGW&))
 CALL UNLOCKPIXELS(FN GETGWORLDPIXMAP(tGW&))
END FN

LOCAL FN DrawStuff(sqSize)
 DIM j, rect.8, s$
 CALL SETRECT(rect,0,0,sqSize/2,sqSize/2)
 COLOR=_zCyan: CALL PAINTRECT(rect)
 CALL OFFSETRECT(rect,sqSize/2,0)
 COLOR=_zYellow: CALL PAINTRECT(rect)
 CALL OFFSETRECT(rect,0,sqSize/2)
 COLOR=_zGreen: CALL PAINTRECT(rect)
 CALL OFFSETRECT(rect,-sqSize/2,0)
 COLOR=_zBlue: CALL PAINTRECT(rect)
 CALL SETRECT(rect,sqSize/16, sqSize*7/16,sqSize*15/16, sqSize*9/16)
 CALL ERASEOVAL(rect)
 CALL PENSIZE(1,3)
 FOR j=1 TO sqSize/8
  LONG COLOR 255*RND(256),0,255*RND(256)
  IF (j AND 3) =3 THEN COLOR=_zWhite
  CALL FRAMEOVAL(rect)
  CALL INSETRECT(rect,-1,-3)
 NEXT
 COLOR=_zBlack
 CALL TEXTSIZE(sqSize/10)
 s$="Weird Rotation"
 PRINT%(sqSize/2-FN STRINGWIDTH(s$)/2,sqSize*17/32) s$
END FN

DIM scrnGW&,scrnDev&, maskGW&, tempGW&,theWidth, theRect.8
IF SYSTEM(_scrnHeight)>520 THEN theWidth=512 ELSE theWidth=256'power of 2
CALL SETRECT(theRect,0,0,theWidth,theWidth)
WINDOW 1,"Strange",@theRect,5
CALL GETGWORLD(scrnGW&,scrnDev&)
IF FN NEWGWORLD(maskGW&,0,#@theRect,0,0,0)<>_noErr THEN STOP
IF FN NEWGWORLD(tempGW&,0,#@theRect,0,0,0)<>_noErr THEN STOP
FN DrawStuff(theWidth)  ' put up some pretty rubbish to rotate
DO: UNTIL FN BUTTON
FN WeirdRotate(scrnDev&,scrnGW&,maskGW&,tempGW&, @theRect,1200)
DO: UNTIL FN BUTTON
CALL DISPOSEGWORLD(maskGW&)
CALL DISPOSEGWORLD(tempGW&)
How does it work?
The series of masked and shifted COPYBITS calls in FN WeirdRotate rotates the 4 quadrants of the picture. Each iteration then refines the mask to subdivide each quadrant into 4, until finally the 4x4 pixel sub-sub-sub.. quadrants are the last to be rotated, all at once (you can see this as "de-fuzzing" on the last iteration). I think of it as a 2-dimensional generalisation of the old trick to exchange two variables:-

y=y XOR x
x=x XOR y
y=y XOR x
Robert