[comp.sys.cbm] Sprite rotation

shavlul@ucscb.ucsc.edu (60231000) (12/12/90)

In response to your question about rotating sprites, i decided to try to
write something like it.  Since I haven't used my commodore 64 in a while
I would probably make too many mistakes trying to translate the following 
to commodore basic without trying it out.  The following does work on standard 
unix C.  Since commodore sprites are 24x24, you'd have to adjust the 4.5's to
11.5 (equidistant from 0 and 23), 5.0's to 12.0, and the size of sprite and
sprite2.  The method used is to write into the new sprite (never overwrite the
original sprite data or you'll lose resolution FAST) pixel by pixel, looking at
the pixel at same distance and angle (original angle-ph) from the center of the
sprite.  floor () is equivalent to BASIC's INT.  Why was 4.5 used in one place
and 5.0 in another?  The 5.0 is actually because it is floor(4.5+ ... +0.5),
same as INT(X+.5) to round numbers properly.  This code acts strange when
rounding isn't working in a fair manner.  In case you don't know C, the
derivation is at the end of this post.

(I apologize for not sending mail- this machine is very flaky with bitnet)

+/* This is only a test */

+#include <stdio.h>
+#include <math.h>

+char sprite[11][11] =
+{    "....AB....",
+     "....CD....",
+     "....EF....",
+     "....GH....",
+     "....IJ....",
+     "....KL....",
+     "....MN....",
+     "....OP....",
+     "....QR....",
+     "....ST...."
+};

+char sprite2[11][11];
+char readspr();
+void writespr();

+main ()

+{     int i,j,x,y;
+      double th,ph,cx,cy;

+      for (i=0; i<10; ++i)
+        puts(sprite[i]);
+      
+      scanf ("%lf",&ph);
+      printf ("Confirming %lf\n",ph);
+      ph=ph*(3.1415926535897932384626433832795028843/180.);
+      for (x=0; x<10; ++x)
+      { cx=(double)x-4.5;
+        for (y=0; y<10; ++y)
+        {    
+              cy=(double)y-4.5;
+              writespr(x,y,
+                 readspr( (int)floor(5.0+( (cx*cos(ph))+(cy*sin(ph)) )) ,
+                          (int)floor(5.0+( (cy*cos(ph))-(cx*sin(ph)) )) ));
+        }
+      }
+      for (i=0; i<10; ++i)
+        puts(sprite2[i]);
+}
+
+char readspr(x,y)
+     int x; int y;
+
+{    printf ("%d %d\n",x,y);
+     if ((x<10)&&(y<10)&&(x>=0)&&(y>=0))
+       return (sprite[x][y]);
+     return ('.');
+} 
+
+void writespr(x,y,c)
+     int x; int y; char c;
+
+{    if ((x<10)&&(y<10)&&(x>=0)&&(y>=0))
+       sprite2[x][y]=c;
+}
+
+#ifdef JUNK
+th=original angle of (x,y) relative to center of sprite (theta)
+ph=angle of rotation (phi)
+centerx, centery=coordinates of center of sprite (4.5, 4.5) or (11.5, 11.5)
+cx, cy   distance from center horizontally, vertically
+
+distance from center=sqrt((x-centerx)^2 + (y-centery)^2)
+th=arccos(cx/distance from center)   ..or..
+   arcsin(cx/distance from center)      (one of these is right, the other may
+                                         have to be negated to be corrected)
+newx=(centerx)+(distance from center*cos(th-ph)
+newy=(centery)+(distance from center*sin(th-ph)
+
+cos (a-b) = cosacosb+sinasinb
+costhcosph+sinthsinph
+((cx/d) cos ph) + ((cy/d) sin ph)    <- notice how cos(arccos(...))=cx/d, etc.
+
+sin (a-b) = sina cosb - cosa sinb
+((cy/d) cos ph) - ((cx/d) sin ph)
+
+therefore newx=(centerx)+((cx*(cos ph))+(cy*(sin ph)))
+          newy=(centery)+((cy*(cos ph))+(cx*(sin ph)))
+#endif