DEMO.DESIGN
Frequently Asked Questions
 
оглавление | demo party в ex-СССР | infused bytes e-mag | новости от ib/news | другие проекты | письмо | win koi lat

следующий фpагмент (2)
- Usenet echoes (21:200/1) -------------------------- COMP.GRAPHICS.ALGORITHMS - Msg : 22 of 26 From : more@stekt.oulu.fi 2:5030/144.99 16 Apr 94 13:13:46 To : All 17 Apr 94 23:03:16 Subj : Re: Raster rotation - source enclosed -------------------------------------------------------------------------------- Your innerloop did not contain all the optimizations that should be included. I tried to include some more. However, I did not compile it :-) void rotate_row(unsigned long x, unsigned long y, long dx, long dy, char *p, int width) { // precalculate 1.0/width and run a multiplication at this stage. // propably the ix and iy should be directly the parameters... ??? long ix = (dx + (width >> 1)) / width; long iy = (dy + (width >> 1)) / width; while (width--) { if (x < mapwidth16 && y < mapheight16) *p++ = map[(y >> 16) * mapwidth + (x >> 16)]; else *p++ = 0; x += ix; y += iy; } } mapwidth16 and mapheight16 are mapwidth << 16 and mapheight << 16, precalculated. -- Jyrki Alakuijala - Hanhitie 17FB9, 90150 Oulu, Finland, +358-815307473
следующий фpагмент (3)|пpедыдущий фpагмент (1)
- Usenet echoes (21:200/1) -------------------------- COMP.GRAPHICS.ALGORITHMS - Msg : 24 of 26 From : henry@prog.demon.co.uk 2:5030/144.99 16 Apr 94 10:10:34 To : All 17 Apr 94 23:03:18 Subj : Re: Raster rotation - source enclosed -------------------------------------------------------------------------------- Lee Lorenz (llorenz@delphi.com) wrote: : Christer Weinigel <wingel@lysator.liu.se> writes: This seems to have turned into a discussion on the use of this newsgroup, but here's my thoughts on Raster Rotation/Scaling. The SNES does a Matrix Multiply in hardware for each pixel on the screen. This is easily accomplished in software ( I've tried it on my Amiga 4000, and it worked fine - anybody wants a demo, mail me) Here's the basic outline. X A B P \/ _ /\ _ Y C D Q So, (and this isn't source, OK?) FOR Y = 0 TO HEIGHT FOR X = 0 TO WIDTH P=(X*A)+(Y*C) (I THINK this is how you do a matrix multiply ? Q=(X*B)+(Y*D) (I've forgotten exactly....) COPY PIXEL FROM (P,Q) IN SOURCE BITMAP TO SCREEN AT (X,Y) NEXT X NEXT Y The Matrix should be: COS*scale SIN*scale SIN*scale COS*scale You can do shears, or just about any transformation you want by fooling about with the matrix.... Charlie Skilbeck (henry@prog.demon.co.uk)
следующий фpагмент (4)|пpедыдущий фpагмент (2)
- Usenet echoes (21:200/1) -------------------------- COMP.GRAPHICS.ALGORITHMS - Msg : 30 of 35 From : lsellers@brbbs.com 2:5030/315 04 Oct 95 04:23:08 To : All 03 Oct 95 23:06:59 Subj : Re: Help needed on BMP rotation -------------------------------------------------------------------------------- X-RealName: Lewis A. Sellers In article <s9512391.39.812220785@cosine.up.ac.za> s9512391@cosine.up.ac.za wri > > In article <NEWTNews.13342.811730527.us002088@interramp.com> cci@interramp.co > writes: > > > >Can someone recommend a fast and accurate alogrithm for rotating a BMP > >image? (any random angle) > > Here is one : [ x' ] = [ cos(a) -sin(a) ] [ x ] > [ y' ] [ sin(a) cos(a) ] [ y ] Here's another one. This is not exactly what you wanted... but it's close enough that it might be helpful. Compiles in Borland C for the IBM platform (old real-mode, 16 bits) but with a little tweaking you can port it. It's the skeleton of a routine I was prototyping in C before converting it to asm. //rott3 by lewis sellers -- minimalist/TMG/grail //based in part on a code fragment by someone called dave. :) //bmp must be 256 colors, with a 320 width and AT LEAST 200 pixels high #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <time.h> #include <dos.h> #include <math.h> #include <alloc.h> #define FAILURE 0 #define SUCCESS 1 typedef unsigned char byte; typedef unsigned int word; typedef unsigned long dword; #define PI 3.14159 char far *base_screen=(char far *)MK_FP(0xA000,0); char far *buffer; int far *y320; void SetGraphicsMode(void) { asm mov ax,0x13 asm int 0x10 outp(0x3c2,0xe3); } void SetTextMode(void) { asm mov ax,0x03 asm int 0x10; } int LoadTestImage(char *name) { FILE *source; int n,x,y; word si; word bmppos=(200-1)*320; word base_screenpos=0; byte far *palette; byte far *thrash; source=fopen(name,"rb"); if(source==NULL) return FAILURE; fseek(source,54,0); //from b-g-r-unused dword format to proper RGB 3byte. palette=(byte *)farmalloc(1024L); fread(palette,1024,1,source); outportb(0x3c6,0xff); outp(0x3c8,0); for(si=0,n=0;n<=255;n++,si+=4) { outportb(0x3c9,palette[si+2]>>2); outportb(0x3c9,palette[si+1]>>2); outportb(0x3c9,palette[si]>>2); } farfree(palette); // thrash the dumb MS format... thrash=(byte far *)farmalloc(64000L); fread(thrash,64000U,1,source); for(y=0;y<200;y++) { for(x=0;x<320;x++) buffer[base_screenpos+x]=thrash[bmppos+x]; bmppos-=320; base_screenpos+=320; } farfree(thrash); fclose(source); return SUCCESS; } void Rotate(int x_off,int y_off, //the offsets, or top-left of box int Nx, int Ny, //width and height float scale, //the scaling factor int x_cent,int y_cent, //rotation around this point float ang) //the rotation angle { long sscale=sin(ang)*65536L/scale; long cscale=cos(ang)*65536L/scale; long xc=((long)x_cent<<16) - ((Nx>>1)*(cscale+sscale)); long yc=((long)y_cent<<16) - ((Ny>>1)*(cscale-sscale)); char far *scn=base_screen+x_off+y_off*320; for (int y=0;y<Ny;y++) { long xlong=xc; long ylong=yc; for (int x=0;x<Nx;) { register int tempx=xlong>>16; register int tempy=ylong>>16; if( (tempx<0) || (tempx>=320) || (tempy<0) || (tempy>=200) ) scn[x++]=0; else scn[x++]=buffer[tempx+y320[tempy]]; xlong+=cscale; ylong-=sscale; } scn+=320; xc+=sscale; yc+=cscale; } } void WideRotate(int x_off,int y_off, //the offsets, or top-left of box int Nx, int Ny, //width and height float scale, //the scaling factor int x_cent,int y_cent, //rotation around this point float ang) //the rotation angle { long sscale=sin(ang)*65536L/scale; long cscale=cos(ang)*65536L/scale; long xc=((long)x_cent<<16) - ((Nx>>1)*(cscale+sscale)); long yc=((long)y_cent<<16) - ((Ny>>1)*(cscale-sscale)); char far *scn=base_screen+x_off+y_off*320; for (int y=0;y<Ny;y++) //normally from 0 to 199 { long xlong=xc,ylong=yc; //init x/ylong to topleft of square for (int x=0;x<Nx;) //normally from 0 to 319 { register int tempx=xlong>>16; register int tempy=ylong>>16; if(tempx>=320) tempx=tempx%320; if(tempx<0) tempx=319-((-tempx)%320); if(tempy>=200) tempy=tempy%200; if(tempy<0) tempy=199-((-tempy)%200); scn[x++]=buffer[tempx+y320[tempy]]; xlong+=cscale;ylong-=sscale; } scn+=320; xc+=sscale;yc+=cscale; } } void FastWideRotate(float scale, //the scaling factor float ang) //the rotation angle { long xscale=sin(ang)*65536L/scale; long yscale=cos(ang)*65536L/scale; long xc=160L*65536L - (160*(yscale+xscale)); long yc=100L*65536L - (100*(yscale-xscale)); char far *scn=base_screen; for (int y=0;y<200;y++) //normally from 0 to 199 { long xlong=xc,ylong=yc; //init x/ylong to topleft of square for (int x=0;x<320;) //normally from 0 to 319 { register int tempx=xlong>>16; register int tempy=ylong>>16; if(tempx>=320) tempx=tempx%320; if(tempx<0) tempx=319-((-tempx)%320); if(tempy>=200) tempy=tempy%200; if(tempy<0) tempy=199-((-tempy)%200); scn[x++]=buffer[tempx+y320[tempy]]; xlong+=yscale;ylong-=xscale; } scn+=320; xc+=xscale;yc+=yscale; } } void FastRotate(float scale, //the scaling factor float ang) //the rotation angle { long xscale=sin(ang)*65536L/scale; long yscale=cos(ang)*65536L/scale; long xc=160L*65536L - (160*(yscale+xscale)); long yc=100L*65536L - (100*(yscale-xscale)); char far *scn=base_screen; for (int y=0;y<200;y++) //normally from 0 to 199 { long xlong=xc,ylong=yc; //init x/ylong to topleft of square for (int x=0;x<320;) //normally from 0 to 319 { register int tempx=xlong>>16; register int tempy=ylong>>16; if( (tempx<0) || (tempx>=320) || (tempy<0) || (tempy>=200) ) scn[x++]=0; else scn[x++]=buffer[tempx+y320[tempy]]; xlong+=yscale;ylong-=xscale; } scn+=320; xc+=xscale;yc+=yscale; } } int main(int argc,char *argv[]) { float angle=0; //PI; float scale=1.0; //2.0; int n; if(argc!=2) { printf("Use: ROTT3 'bmp filename'\n"); return 1; } buffer=(char far *)farmalloc(64000L); y320=(int far *)farmalloc(2L*200L); for(n=0;n<200;n++) y320[n]=n*320; SetGraphicsMode(); if(LoadTestImage(argv[1])==FAILURE) { SetTextMode(); printf("File [%s] does not exist.\n",argv[1]); return 2; } while (!kbhit()) { // WideRotate(0,0,320,200,scale,160,100,angle); FastWideRotate(scale,angle); // Rotate(0,0,320,200,scale,160,100,angle); // FastRotate(scale,angle); scale-=0.01; angle+=PI/128; } SetTextMode(); farfree(y320); farfree(buffer); return 0; }
следующий фpагмент (5)|пpедыдущий фpагмент (3)
- [22] Usenet echoes (21:200/1) --------------------- COMP.GRAPHICS.ALGORITHMS - Msg : 14 of 27 From : wingel@lysator.liu.se 2:5030/144.99 14 Apr 94 00:27:00 To : All Subj : Re: Raster rotation - source enclosed -------------------------------------------------------------------------------- Lee Lorenz <llorenz@delphi.com> writes: > >Well, I gave it some more thought, and I was thinking... couldn't you >shoot a Bresenham Line through the source bitmap, pulling the pixels if >we are inside the map. Now, how about some quick and dirty 386 asm code? > > Lee Lorenz > This is more or less what I've done. What follows is a quick port of some 386-assembler I wrote a couple of days ago. The function rotate_row "draws" a line in the source bitmap and copies bytes into an array which can then be copied to the screen. rotate contains the outer loop, which calls rotate_row for each line of output. The files try.c and mstry.c are just some simple test programs for linux and Microsoft C under MS-Dos respectively. I hope the source is readable, I wrote this between midnight and two o'clock this morning, but I hope I haven't done anything stupid. If you have any questions, or want the assembler source, just drop me a line as y93chrwe@und.ida.liu.se (someone has managed to fill the root partition on that machine so I had to use this account instead. Mail will get to me here too, but might take a little longer). (I have been off the internet for a while, so a little question on netiquette: Is it ok to post ~1000 lines of source in a discussion group like this? I would like to post the assembler source for these routines (optimized and obfuscated to give a speed of about 20-40 frames/second at 320x200) but I hesitate as I don't know what is considered 'good behaviour'.) Just a thought. There really isn't anything in rotate_row which requires the source or destination to be a rectangle. As long as the output image can be decomposed into rows which correspond to a straight line in the source bitmap just go ahead and do it. As usual, try this at your own risk. Enjoy. /Christer /********************************************************/ /* file: rot.c */ #undef max #define max(x, y) ((x) > (y) ? (x) : (y)) /* map contains a pointer to the bitmap to rotate */ /* mapwidth and mapheight is the size of the bitmap */ char *map; int mapwidth, mapheight; /* Draw one row */ /* (x, y) is the starting coordinate */ /* (dx, dy) is the vector which is going to be drawn */ /* p is the pointer to the output data, len is the length of the output */ void rotate_row(long x, long y, long dx, long dy, char *p, int width) { long ix, iy; int mapx, mapy; /* Calculate increments for the coordinates in the source bitmap */ ix = dx / width; iy = dy / width; while (width--) { /* Convert from fixed point to integer coordinates */ mapx = x >> 16; mapy = y >> 16; /* transfer data if the point is inside the source bitmap */ if (mapx >= 0 && mapx < mapwidth && mapy >= 0 && mapy < mapheight) *p++ = map[mapy * mapwidth + mapx]; else *p++ = 0; /* Increment coordinates */ x += ix; y += iy; } } /* Draw the screen * (x, y) is the starting coordinate * (dx, dy) is a vector along the top of the rectangle to draw * p is the pointer to the output data * width, height is the size of the output rectangle */ void rotate(long x, long y, long dx, long dy, char *p, int width, int height) { long ix, iy; /* Calculate increments for the coordinates in the source bitmap * since what we want is the left edge of the rectangle, * ix and iy are perpendicular to dx and dy */ /* TODO: This is a good place to add calculatons for aspect ratios */ ix = -dy / height; iy = dx / height; while (height--) { /* Draw each line */ rotate_row(x, y, dx, dy, p, width); /* Increment coordinates */ x += ix; y += iy; /* Go the next row in the output */ p += width; } } /********************************************************/ /* file: try.c */ #include <stdio.h> #include <stdlib.h> #include <vga.h> #include <vgagl.h> #include <math.h> void rotate_row(long x, long y, long dx, long dy, char *p, int width); void rotate(long x, long y, long dx, long dy, char *p, int width, int height); extern char *map; extern int mapwidth, mapheight; /* setup the targa palette */ void usepal(char *p) { Palette pal; int i; for (i = 0; i < 256; i++) { pal.color[i].red = p[i*3+2] >> 2; pal.color[i].green = p[i*3+0] >> 2; pal.color[i].blue = p[i*3+1] >> 2; } gl_setpalette(&pal); } /* targa file header (I just stupidly assume uncompressed 8-bit images, * and hopefully the format looks the same from most programs) */ struct targa { short dummy[6]; short x; short y; short dummy2; char palette[256*3]; }; int loadimage(const char *fn, char **buf, int *width, int *height) { FILE *fp; struct targa t; char *p; int i; if ((fp = fopen(fn, "r")) == NULL) { perror(fn); return -1; } /* read the file header */ fread(&t, 1, sizeof(t), fp); *width = t.x; *height = t.y; /* set up the palette */ usepal(t.palette); printf("%s: imagesize %d x %d\n", fn, t.x, t.y); /* under a real 32-bit operating system this works.. */ /* don't try this with a bitmap larger than 64k under dos */ if ((*buf = malloc(t.x * t.y)) == NULL) { perror("malloc"); return -1; } /* targa files have the rows written in reverse order */ for (i = 0; i < t.y; i++) { p = *buf + (t.y - i - 1) * t.x; fread(p, 1, t.x, fp); } fclose(fp); } #define TRIES 100 void try(void) { char *screen; int n; screen = vga_getgraphmem(); /* try large model and screen = (char *)0xa0000000l under dos */ for (n = 0; n < TRIES; n++) { double v; double scale; int x, y; int dx, dy; v = 4 * 3.14159265 * (n+1) / TRIES; scale = mapwidth; dx = cos(v) * scale * 0x10000; dy = sin(v) * scale * 0x10000; x = mapwidth * 0x08000 - dx/2 + dy/2; y = mapheight * 0x08000 - dy/2 - dx/2; rotate(x, y, dx, dy, screen, 320, 200); } } void main(int argc, char *argv[]) { int VGAMODE = G320x200x256; vga_init(); vga_setmode(VGAMODE); gl_setcontextvga(VGAMODE); gl_setrgbpalette(); /* set RGB palette */ if (loadimage("test.tga", &map, &mapwidth, &mapheight)) goto bug; try(); getchar(); bug: vga_setmode(TEXT); exit(0); } /********************************************************/ /* file: mstry.c */ #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <math.h> void rotate_row(long x, long y, long dx, long dy, char *p, int width); void rotate(long x, long y, long dx, long dy, char *p, int width, int height); extern char *map; extern int mapwidth, mapheight; /* targa file header (I just stupidly assume uncompressed 8-bit images, * and hopefully the format looks the same from most programs) */ struct targa { short dummy[6]; short x; short y; short dummy2; char palette[256*3]; }; int loadimage(const char *fn, char **buf, int *width, int *height) { FILE *fp; struct targa t; char *p; int i; if ((fp = fopen(fn, "r")) == NULL) { perror(fn); return -1; } /* read the file header */ fread(&t, 1, sizeof(t), fp); *width = t.x; *height = t.y; printf("%s: imagesize %d x %d\n", fn, t.x, t.y); /* under a real 32-bit operating system this works.. */ /* don't try this with a bitmap larger than 64k under dos */ if ((*buf = malloc(t.x * t.y)) == NULL) { perror("malloc"); return -1; } /* targa files have the rows written in reverse order */ for (i = 0; i < t.y; i++) { p = *buf + (t.y - i - 1) * t.x; fread(p, 1, t.x, fp); } fclose(fp); } #define TRIES 100 void try(void) { char far *screen = (char far *)0xa0000000l; int n; for (n = 0; n < TRIES; n++) { double v; double scale; long x, y; long dx, dy; v = 4 * 3.14159265 * (n+1) / TRIES; scale = mapwidth; dx = cos(v) * scale * 0x10000; dy = sin(v) * scale * 0x10000; x = mapwidth * 0x08000 - dx/2 + dy/2; y = mapheight * 0x08000 - dy/2 - dx/2; rotate(x, y, dx, dy, screen, 320, 200); } } void main(int argc, char *argv[]) { _asm { mov ax,0x013 int 0x10 } if (loadimage("test.tga", &map, &mapwidth, &mapheight)) goto bug; try(); getch(); bug: _asm { mov ax,0x04 int 0x10 } exit(0); }

Всего 4 фpагмент(а/ов) |пpедыдущий фpагмент (4)

Если вы хотите дополнить FAQ - пожалуйста пишите.

design/collection/some content by Frog,
DEMO DESIGN FAQ (C) Realm Of Illusion 1994-2000,
При перепечатке материалов этой страницы пожалуйста ссылайтесь на источник: "DEMO.DESIGN FAQ, http://www.enlight.ru/demo/faq".