From cb35371aa117f11ad9310e0476bb81336bbafd33 Mon Sep 17 00:00:00 2001 From: Adam Greenwood-Byrne Date: Sat, 20 Mar 2021 20:50:40 +0000 Subject: [PATCH] Added wspr.c and examples/wgt22.c to exercise the new sprite library --- part12-wgt/Makefile | 7 +- part12-wgt/bin/invader.spr | Bin 0 -> 2160 bytes part12-wgt/examples/wgt22.c | 126 +++++++ part12-wgt/wgtspr.h | 67 ++++ part12-wgt/wspr.c | 687 ++++++++++++++++++++++++++++++++++++ 5 files changed, 885 insertions(+), 2 deletions(-) create mode 100644 part12-wgt/bin/invader.spr create mode 100644 part12-wgt/examples/wgt22.c create mode 100644 part12-wgt/wgtspr.h create mode 100644 part12-wgt/wspr.c diff --git a/part12-wgt/Makefile b/part12-wgt/Makefile index d0d9137..a025352 100644 --- a/part12-wgt/Makefile +++ b/part12-wgt/Makefile @@ -23,11 +23,14 @@ bin/lettersspr.o: bin/letters.spr bin/spacespr.o: bin/space.spr $(LLVMPATH)/llvm-objcopy -I binary -O elf64-littleaarch64 -B aarch64 $< $@ +bin/invaderspr.o: bin/invader.spr + $(LLVMPATH)/llvm-objcopy -I binary -O elf64-littleaarch64 -B aarch64 $< $@ + %.o: %.c $(LLVMPATH)/clang --target=aarch64-elf $(CLANGFLAGS) -c $< -o $@ -kernel8.img: boot/boot.o $(OFILES) bin/wgt1pal.o bin/wgt1blk.o bin/wgt2blk.o bin/lettersspr.o bin/spacespr.o - $(LLVMPATH)/ld.lld -m aarch64elf -nostdlib boot/boot.o $(OFILES) bin/wgt1pal.o bin/wgt1blk.o bin/wgt2blk.o bin/lettersspr.o bin/spacespr.o -T boot/link.ld -o kernel8.elf +kernel8.img: boot/boot.o $(OFILES) bin/wgt1pal.o bin/wgt1blk.o bin/wgt2blk.o bin/lettersspr.o bin/spacespr.o bin/invaderspr.o + $(LLVMPATH)/ld.lld -m aarch64elf -nostdlib boot/boot.o $(OFILES) bin/wgt1pal.o bin/wgt1blk.o bin/wgt2blk.o bin/lettersspr.o bin/spacespr.o bin/invaderspr.o -T boot/link.ld -o kernel8.elf $(LLVMPATH)/llvm-objcopy -O binary kernel8.elf kernel8.img clean: diff --git a/part12-wgt/bin/invader.spr b/part12-wgt/bin/invader.spr new file mode 100644 index 0000000000000000000000000000000000000000..49151f328c68491b9eb0f767b731f0251de5c90f GIT binary patch literal 2160 zcmeH{Npm7c5QRU)4q_2v2SKwm&C(zt1VX6cSqDaQ(7_S@4Re?X9~=(n@y+F$z(DXiy1+qNN`|x zV0&P5;O@Zfftv&K1G58@J>DL7&tOk)PiIeiPjgRwPc@(%Pzopn40QFG%%71 z&<<_U2CdK%U86agqA?nwA?l$nxO?pG>p5&Iq1MwZPM{^y{_CyXQQs#|tIAb3ri18R_m*64EHpP9KO@?)ryK`1K zZu2Y)+!VRKU{PXziC<<`VOnKUV_e5;Flyqq7`7Q)(eKdf;y84BboyKkXb)+*G)FW% z>SJmXs#7X6%08EKN((NoDc(?6lD{Rl;{1;6n#_juJ*h3p2NFBtkHkzq_M9Dv*wdT5 zC?cInQ7ItAQhzxsU%%WWvL=nrJ7Wi8d6hgNp0y$>PTJ5 zk$O^J8c0LQl}3^$jire+m1dGJ&83BOE!{{<=~h}vchXwgNcYlKdXRR~V_5IOd_Fhz z{5uhnq-@njtbu4~Bhh3yh}$j_Pp0!`ChY7WbDodJ6DiY0%(jH7^BZLmQIDSWjs) z`%ifKO5bQ(M^@j)F@HP4~RHH|KqGe`5a~_r}rb_BKW#em;H+8uzF9@4mg! zIR!s-6b3&;hBtZmCOpwLfhPDTg})Gdv*R`QCv}_qFYpbW*1YmxvF~engKv^w>g!9T Mopk^2{^JPz0ZX6pe*gdg literal 0 HcmV?d00001 diff --git a/part12-wgt/examples/wgt22.c b/part12-wgt/examples/wgt22.c new file mode 100644 index 0000000..33c0516 --- /dev/null +++ b/part12-wgt/examples/wgt22.c @@ -0,0 +1,126 @@ +#include "wgtspr.h" +#include "include/mem.h" + +// ######## REQUIRED FUNCTIONS ######## + +unsigned long state0 = 1000; +unsigned long state1 = 2000; + +unsigned long rand(void) +{ + unsigned long s1 = state0; + unsigned long s0 = state1; + + state0 = s0; + s1 ^= s1 << 23; + s1 ^= s1 >> 17; + s1 ^= s0; + s1 ^= s0 >> 26; + state1 = s1; + + return state0 + state1; +} + +void wait_msec(unsigned int n) +{ + register unsigned long f, t, r; + + // Get the current counter frequency + asm volatile ("mrs %0, cntfrq_el0" : "=r"(f)); + // Read the current counter + asm volatile ("mrs %0, cntpct_el0" : "=r"(t)); + // Calculate expire value for counter + t+=((f/1000)*n)/1000; + do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r= WGT_SYS.xres) + tempx1 = WGT_SYS.xres - 1; + + if (tempy1 < ty) /* Y1 */ + tempy1 = ty; + else + if (tempy1 >= WGT_SYS.yres) + tempy1 = WGT_SYS.yres - 1; + + if (tempx2 < tx) /* X2 */ + tempx2 = tx; + else + if (tempx2 >= WGT_SYS.xres) + tempx2 = WGT_SYS.xres - 1; + + if (tempy2 < ty) /* Y2 */ + tempy2 = ty; + else + if (tempy2 >= WGT_SYS.yres) + tempy2 = WGT_SYS.yres - 1; + + s[number].x = x; /* Set up the coords */ + s[number].y = y; + s[number].num = image; + s[number].on = 1; + + s[number].ox = tempx1; /* Set the dirty rectangle location */ + s[number].oy = tempy1; + s[number].ox2 = tempx2; + s[number].oy2 = tempy2; +} + + + +void spriteoff (short number) +/* Turns a sprite off */ +{ + if (s[number].on == 1) + s[number].on = 2; /* Signals sprite is to be taken off */ +} + + + +void erase_sprites (void) +/* Erases all sprites from background screen by copying the dirty + rectangles */ +{ +short i; +block curscreen; +short osx, osy; + +sprite_object *spriteptr; +int x, y, x2, y2; + +curscreen = abuf; +osx = WGT_SYS.xres; +osy = WGT_SYS.yres; + + wsetscreen (spritescreen); /* Go to background screen */ + + spriteptr = s; + + for (i = 0; i <= maxsprite; i++) /* Loop through all sprites */ + { + if (spriteptr->on == 1) /* If sprite is on */ + { + x = spriteptr->ox; /* Get the old dirty rectangle coordinates */ + y = spriteptr->oy; + x2 = spriteptr->ox2; + y2 = spriteptr->oy2; + + if (x < tx) /* Clip them, but don't change the original */ + x = tx; /* values, because we need them later */ + else if (x > bx) + x = bx; + if (y < ty) + y = ty; + else if (y > by) + y = by; + + wcopyscreen (x, y, x2, y2, backgroundscreen, x, y, spritescreen); + } + spriteptr++; /* Next sprite */ + } + + abuf = curscreen; + WGT_SYS.xres = osx; + WGT_SYS.yres = osy; +} + + + +void expand_dirty_rectangle (int x, int y, int x2, int y2) +/* Find boundaries of the old and new sprite rectangle */ +{ + if (x < tempx1) /* Compare with */ + tempx1 = x; + if (x2 > tempx2) + tempx2 = x2; + if (y < tempy1) + tempy1 = y; + if (y2 > tempy2) + tempy2 = y2; + + if (tempx1 < tx) /* Compare with clipping boundaries */ + tempx1 = tx; + + if (tempx2 > bx) + tempx2 = bx; + + if (tempy1 < ty) + tempy1 = ty; + + if (tempy2 > by) + tempy2 = by; +} + + +void copy_sprites (void) +{ +int i; +sprite_object *spriteptr; +int x, y, x2, y2; + + spriteptr = s; + for (i = 0; i <= maxsprite; i++) + { + if (spriteptr->on > 0) /* If sprite is on */ + { + if (spriteptr->on == 2) + spriteptr->on = 0; + + + /* Store these values because they are used more than once */ + x = spriteptr->x; + y = spriteptr->y; + x2 = x + wgetblockwidth (sprite_images[spriteptr->num]) - 1; + y2 = y + wgetblockheight (sprite_images[spriteptr->num]) - 1; + + /* Set the dirty rectangle to the current position of the sprite */ + tempx1 = x; + tempy1 = y; + tempx2 = x2; + tempy2 = y2; + + expand_dirty_rectangle (spriteptr->ox, spriteptr->oy, + spriteptr->ox2, spriteptr->oy2); + + wcopyscreen (tempx1, tempy1, tempx2, tempy2, spritescreen, tempx1, tempy1, + NULL); + + spriteptr->ox = x; + spriteptr->oy = y; + spriteptr->ox2 = x2; + spriteptr->oy2 = y2; + + } + spriteptr++; + } +} + + + + +void draw_sprites (int movement_multiplier) +/* Draw the sprites on the sprite screen */ +{ +short i; +block curscreen; +short osx, osy; +sprite_object *spriteptr; +int move; + + curscreen = abuf; + osx = WGT_SYS.xres; + osy = WGT_SYS.yres; + + wsetscreen (spritescreen); /* Go to sprite screen */ + + + for (move = 0; move < movement_multiplier; move++) + { + spriteptr = s; + for (i = 0; i <= maxsprite; i++) /* Loop through all sprites */ + { + if (spriteptr->on == 1) /* If sprite is on */ + { + if (spriteptr->movex_on == 1) /* X movement on */ + { + if (spriteptr->movex_count != 0)/* Delay Count not reached 0? */ + spriteptr->movex_count--; /* Decrease count */ + else /* Get the next move */ + { + spriteptr->current_movex_number++; /* Increase # of times moved */ + if (spriteptr->current_movex_number == + spriteptr->movex_number[spriteptr->current_movex]) + /* Moved the right number of times yet? */ + { + spriteptr->current_movex++; /* Increase ptr in move array */ + if (spriteptr->movex_number[spriteptr->current_movex] == - 1) + /* Repeat move */ + spriteptr->current_movex = 0; + else if (spriteptr->movex_number[spriteptr->current_movex] + == - 2) /* End move */ + { + spriteptr->current_movex--; + spriteptr->movex_on = 0; /* Turn off movement */ + } + spriteptr->current_movex_number = 0; + /* Reset number of times moved */ + } + spriteptr->movex_count = spriteptr->movex_speed + [spriteptr->current_movex]; /* Get delay */ + spriteptr->x += spriteptr->movex_distance + [spriteptr->current_movex]; /* Update X coord */ + } + } + + + if (spriteptr->movey_on == 1) /* Y movement on */ + { + if (spriteptr->movey_count != 0)/* Delay Count not reached 0? */ + spriteptr->movey_count--; /* Decrease count */ + else /* Get the next move */ + { + spriteptr->current_movey_number++; /* Increase # of times moved */ + if (spriteptr->current_movey_number == + spriteptr->movey_number[spriteptr->current_movey]) + /* Moved the right number of times yet? */ + { + spriteptr->current_movey++; /* Increase ptr in move array */ + if (spriteptr->movey_number[spriteptr->current_movey] == - 1) + /* Repeat move */ + spriteptr->current_movey = 0; + else if (spriteptr->movey_number[spriteptr->current_movey] + == - 2) /* End move */ + { + spriteptr->current_movey--; + spriteptr->movey_on = 0; /* Turn off movement */ + } + spriteptr->current_movey_number = 0; + /* Reset number of times moved */ + } + spriteptr->movey_count = spriteptr->movey_speed + [spriteptr->current_movey]; /* Get delay */ + spriteptr->y += spriteptr->movey_distance + [spriteptr->current_movey]; /* Update Y coord */ + } + } + + + + if (spriteptr->animon == 1) /* update animation */ + { + if (spriteptr->animation_count != 0) /* Delay count at 0? */ + spriteptr->animation_count--; /* No, so decrease by one. */ + else /* Otherwise animate the sprite */ + { + spriteptr->current_animation++; /* Increase animation ptr */ + if (spriteptr->animation_images[spriteptr->current_animation] + == - 1) /* Repeat animation */ + spriteptr->current_animation = 0; + + if (spriteptr->animation_images[spriteptr->current_animation] + == - 2) /* End animation */ + { + spriteptr->current_animation--; + spriteptr->animon = 0; /* Turn off animation */ + } + + spriteptr->num = spriteptr->animation_images + [spriteptr->current_animation]; /* Change sprite number */ + spriteptr->animation_count = spriteptr->animation_speeds + [spriteptr->current_animation]; /* Reset delay count */ + } + } + + } + spriteptr++; + } + } + + + for (i = 0; i <= maxsprite; i++) /* Loop through all sprites */ + if ((s[i].on == 1) && (sprite_images[ s[i].num ] != NULL)) + wputblock (s[i].x, s[i].y, sprite_images[ s[i].num ], 1); + + abuf = curscreen; + WGT_SYS.xres = osx; + WGT_SYS.yres = osy; + copy_sprites (); +} + + + + + +void initialize_sprites (block *sprite_blocks) +/* Set up everything for the sprite engine */ +{ +short i; + + maxsprite = MAX_SPRITES - 1; + + sprite_images = sprite_blocks; + + for (i = 0; i < MAX_SPRITES; i++) /* Turn off the sprites */ + s[i].on = 0; + + + if (spritescreen == NULL) + spritescreen = wnewblock (0, 0, WGT_SYS.xres - 1, WGT_SYS.yres - 1); + /* Make a virtual screen for the work buffer */ + + if (backgroundscreen == NULL) + backgroundscreen = wnewblock (0, 0, WGT_SYS.xres - 1, WGT_SYS.yres - 1); + /* Make a virtual screen for the background screen */ + +} + + + +void deinitialize_sprites (void) +{ +short i; + + for (i = 0; i < MAX_SPRITES; i++) + s[i].on = 0; + + wfreeblock (spritescreen); + spritescreen = NULL; + + wfreeblock (backgroundscreen); + backgroundscreen = NULL; +} + + + +void animate (short spnum, char *str) +/* Parse animation string and put the data into an array */ +{ +short c, temp1; +short x, in, len, minus; +short change; + + s[spnum].current_animation = 0; /* Reset current animation ptr */ + s[spnum].animation_count = s[spnum].animation_speeds[ + s[spnum].current_animation]; /* Reset delay count */ + + x = 0; + in = 0; + + len = strlen (str); + + /* Parse animation string */ + + do { + + do {/* Find the first bracket */ + c = str[x]; + x++; + } while (c != '('); + + change = 0; + do { + temp1 = 0; + minus = 0; + do { + c = str[x]; + if ((c != ',') && (c != 'R') && (c != '-') && (c != ')')) + temp1 = (temp1 * 10) + (c - 48); + if (c == '-') + minus = 1; + x++; + } while ((x != len) && (c != ',') && (c != 'R') && (c != ')')); + + if (minus == 1) + temp1 = - temp1; + if (change == 0) + s[spnum].animation_images[in] = temp1; + else + s[spnum].animation_speeds[in] = temp1; + change++; + } while (c != ')'); /* Until the last bracket */ + + in++; + if (in >= MAX_ANIMATION) + in = MAX_ANIMATION-1; + + s[spnum].animation_images[in] = - 2; + + c = str[x]; + if (c == 'R') + { + x = len; + s[spnum].animation_images[in] = - 1; + } + } while (x != len); +} + + +void animon (short spnum) +/* Turns animation for a sprite on */ +{ + s[spnum].animon = 1; +} + + +void animoff (short spnum) +/* Turns animation for a sprite off */ +{ + s[spnum].animon = 0; +} + + +/* X movements */ + +void movexon (short spnum) +/* Turns a sprite's x movement on */ +{ + s[spnum].movex_on = 1; +} + + +void movexoff (short spnum) +/* Turns a sprite's x movement off */ +{ + s[spnum].movex_on = 0; +} + + +void movex (short spnum, char *str) +/* Parses a movement string and places data into movement arrays */ +{ +short c, temp1; +short x, in, len, minus; +short change; + + s[spnum].current_movex = 0; /* First x movement */ + s[spnum].movex_count = s[spnum].movex_speed[s[spnum].current_movex]; + s[spnum].current_movex_number = 0; /* First time it moved */ + + x = 0; + in = 0; + + len = strlen (str); + + do { + do { + c = str[x]; + x++; + } while (c != '('); + change = 0; + + do { + temp1 = 0; + minus = 0; + do { + c = str[x]; + if ((c != ',') && (c != 'R') && (c != '-') && (c != ')')) + temp1 = (temp1*10) + (c - 48); + if (c == '-') + minus = 1; + x++; + } while ((x != len) && (c != ',') && (c != 'R') && (c != ')')); + + if (minus == 1) + temp1 = - temp1; + if (change == 0) + s[spnum].movex_distance[in] = temp1; + else if (change == 1) + s[spnum].movex_number[in] = temp1; + else + s[spnum].movex_speed[in] = temp1; + + change++; + } while (c != ')'); + in++; + + if (in == MAX_MOVE) + x = len; + s[spnum].movex_number[in] = - 2; + c = str[x]; + if (c == 'R') + { + x = len; + s[spnum].movex_number[in] = - 1; + } + } while (x != len); + +} + + + + +/* Y movements */ + +void moveyon (short spnum) +/* Turns a sprite's y movement on */ +{ + s[spnum].movey_on = 1; +} + + +void moveyoff (short spnum) +/* Turns a sprite's y movement off */ +{ + s[spnum].movey_on = 0; +} + + +void movey (short spnum, char *str) +/* Parses a movement string and places data into movement arrays */ +{ +short c, temp1; +short x, in, len, minus; +short change; + + s[spnum].current_movey = 0; /* First x movement */ + s[spnum].movey_count = s[spnum].movey_speed[s[spnum].current_movey]; + s[spnum].current_movey_number = 0; /* First time it moved */ + + x = 0; + in = 0; + + len = strlen (str); + + do { + do { + c = str[x]; + x++; + } while (c != '('); + change = 0; + + do { + temp1 = 0; + minus = 0; + do { + c = str[x]; + if ((c != ',') && (c != 'R') && (c != '-') && (c != ')')) + temp1 = (temp1*10) + (c - 48); + if (c == '-') + minus = 1; + x++; + } while ((x != len) && (c != ',') && (c != 'R') && (c != ')')); + + if (minus == 1) + temp1 = - temp1; + if (change == 0) + s[spnum].movey_distance[in] = temp1; + else if (change == 1) + s[spnum].movey_number[in] = temp1; + else + s[spnum].movey_speed[in] = temp1; + + change++; + } while (c != ')'); + in++; + + if (in == MAX_MOVE) + x = len; + s[spnum].movey_number[in] = - 2; + c = str[x]; + if (c == 'R') + { + x = len; + s[spnum].movey_number[in] = - 1; + } + } while (x != len); + +} + + + +short overlap (short s1, short s2) +/* Tests if two sprites overlap + Not pixel precise, just checks rectangles */ +{ +short n1, n2; +short width1, height1; +short width2, height2; + + if ((s[s2].on == 1) && (s[s1].on == 1)) // Make sure both are on + { + n1 = s[s1].num; // For easier reading + n2 = s[s2].num; + + width1 = wgetblockwidth (sprite_images[n1]); + width2 = wgetblockwidth (sprite_images[n2]); + height1 = wgetblockheight (sprite_images[n1]); + height2 = wgetblockheight (sprite_images[n2]); + + if (( s[s2].x >= s[s1].x - width2 ) && + ( s[s2].x <= s[s1].x + width1 ) && + ( s[s2].y >= s[s1].y - height2 ) && + ( s[s2].y <= s[s1].y + height1 )) + return 1; /* Collision! */ + } + return 0; /* No collision */ +} +