From a512a48ff3ea6c92de388e43ad4078d66fc766c1 Mon Sep 17 00:00:00 2001 From: Martin Haye Date: Sat, 5 Oct 2013 11:52:30 -0700 Subject: [PATCH] Finished fleshing out text for part 1. --- Docs/Tutorials/BigBlue/TaleOfBigBlue.md | 163 ++++++++++++++---- Docs/Tutorials/BigBlue/packing.png | Bin 0 -> 32802 bytes .../outlaweditor/apple/AppleImageEditor.java | 4 +- .../tools/PackMap/src/org/demo/PackMap.groovy | 4 +- 4 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 Docs/Tutorials/BigBlue/packing.png diff --git a/Docs/Tutorials/BigBlue/TaleOfBigBlue.md b/Docs/Tutorials/BigBlue/TaleOfBigBlue.md index a560628b..03818795 100644 --- a/Docs/Tutorials/BigBlue/TaleOfBigBlue.md +++ b/Docs/Tutorials/BigBlue/TaleOfBigBlue.md @@ -39,11 +39,9 @@ Finally he created the image we saw earlier, by picking a color, picking a drawi ... ``` -If you're familiar with the actual bytes that form high-res graphics on the Apple II you may recognize some of these values. I think Big bBue is actually two of the bits in "A885D5" but that's not terribly important. What is important is that the pixels are stored here in a format that can be easily read by other programs. How did those bits get in the file? Let's take a very brief look at the code. +If you're familiar with the actual bytes that form high-res graphics on the Apple II you may recognize some of these values. I think Big Blue is actually two of the bits somewhere in "A885D5" but it's not terribly important. What is important is that the pixels are stored here in a format that can be easily read by other programs. How did those bits get in the file? Let's take a very brief look at the code. -Outlaw Editor is written in Java, and here's the Java code that actually twiddles the bits: - -[Direct code link](https://github.com/badvision/lawless-legends/search?q=BigBlue1_10) +Outlaw Editor is written in Java, and here's the Java code that actually twiddles the bits. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue1_10) ```Java public void set(boolean on, int x, int y) { @@ -56,6 +54,111 @@ Outlaw Editor is written in Java, and here's the Java code that actually twiddle } ``` +It gets called by ``plot`` which figures out based on the X and Y coordinates where on the current pattern it should get the bits. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue1_20) + +```Java + public void plot(int x, int y, int[] pattern, boolean hiBitMatters) { + if (x < 0 || y < 0 || x >= getWidth() * 7 || y >= getHeight()) { + return; + } + int pat = pattern[(y % 16) * 4 + ((x / 7) % 4)]; + set((pat & (1 << (x % 7))) != 0, x, y); +``` + +That in turn got called by ``performAction`` that interprets the mouse click. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue1_30) + +```Java + public boolean performAction(boolean alt, boolean released, int x, int y) { + ... + switch (currentDrawMode) { + ... + case Pencil1px: + if (canSkip) { + return false; + } + plot(x, y, currentFillPattern, hiBitMatters); + redrawScanline(y); + ... +``` + +We looked at the XML data which is great for portability but not very compact -- it's 96 kbytes! What we need to do is pack that data down into an efficient format for use on the Apple II. For that we have another Java program called PackMap. We run it from the command-line and here's how it goes. ![Packing the data](packing.png) + +It reads in all the images, does some fancy manipulation of them, then writes them out to a little file (only 8 Kbytes now) and formed of tightly packed bytes. + +``` +0000000 4d 11 11 21 01 00 00 00 00 04 06 04 03 00 00 00 +0000010 00 00 00 05 00 00 00 04 05 04 00 00 00 00 05 04 +0000020 01 04 03 02 00 04 00 06 00 00 00 02 01 06 00 00 +0000030 00 00 00 00 04 00 03 00 03 00 00 00 04 00 05 00 +0000040 00 00 00 04 00 00 00 04 00 00 04 00 00 00 05 04 +0000050 00 00 00 00 03 01 04 00 06 00 00 02 00 04 00 00 +0000060 06 00 00 00 00 02 00 06 00 01 00 06 00 00 01 02 +... +0000120 00 00 00 00 00 00 54 55 05 33 33 33 33 33 33 33 +0000130 33 33 31 30 30 30 30 30 30 30 30 30 30 30 30 30 +0000140 30 30 30 30 30 30 30 30 30 33 33 33 33 33 33 33 +0000150 33 33 39 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c +0000160 3c 3c 3c 3c 3c 3c 3c 3c 3c 33 33 33 33 33 33 33 +0000170 33 33 39 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c +0000180 3c 3c 3c 3c 3c 3c 3c 3c 3c 33 33 33 33 33 33 33 +0000190 33 33 39 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 3c 33 33 +... +``` + +The first part has a header, then the map tiles (just numbers now, not names), followed by all the texture data. + +The code for PackMap is in a dialect of Java called Groovy. It's kind of like Java on steroids. It goes through each image and parses the bits and turns them back into a representation of pixels. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue1_40) + +```Groovy + def pixelize(dataEl) + { + ... + return (0.. + ... + for (def byteNum in 0..>8) & 0xFF) + + // After the header comes the raw data + rows.each { row -> + row.each { tile -> + stream.write(names.findIndexOf { it == tile?.@name } + 1) + } + } + } +``` + +That's it for part one. In the next part of the story we'll talk about how we figure out where to show Big Blue on the screen. + Part 2: Casting Rays -------------------- @@ -81,20 +184,20 @@ The basic idea is that shoot a bunch of virtual "rays" from the player's eye in Let's take a brief look at the code to do this. This is written in Javascript, making it easy to test changes to it before porting them to the Apple II. -The player has a position, X and Y, and a direction, shown in the code marked [BigBlue2a](https://github.com/badvision/lawless-legends/search?q=BigBlue2a). +The player has a position, X and Y, and a direction, shown in the code marked [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue2a). ```javascript -// Player attributes [ref BigBlue2a] +// Player attributes var player = { x : 11.0, // current x, y position y : 10.5, dir : 0, // the direction that the player is turning, either -1 for left or 1 for right. ``` -For efficiency we perform as much math as possible at startup and stick the results into tables, that's done here. Lots of trigonometric functions and square roots so it's good to do this once instead of each time we have to draw the screen. You don't have to understand the math, this is just so you can get a feel for where it is and what it looks like. [BigBlue2b](https://github.com/badvision/lawless-legends/search?q=BigBlue2b) +For efficiency we perform as much math as possible at startup and stick the results into tables, that's done here. Lots of trigonometric functions and square roots so it's good to do this once instead of each time we have to draw the screen. You don't have to understand the math, this is just so you can get a feel for where it is and what it looks like. code link](https://github.com/badvision/lawless-legends/search?q=BigBlue2b) ```javascript -// Set up data tables prior to rendering [ref BigBlue2b] +// Set up data tables prior to rendering function initCast() { var i; @@ -103,19 +206,19 @@ function initCast() precastData = []; ``` -When you press a key, like to move forward, this code gets called and decides that to do, like update the player's X/Y coordinate or direction. [BigBlue2c](https://github.com/badvision/lawless-legends/search?q=BigBlue2c) +When you press a key, like to move forward, this code gets called and decides that to do, like update the player's X/Y coordinate or direction. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue2c) ```javascript - switch (e.keyCode) { // which key was pressed? [ref BigBlue2c] + switch (e.keyCode) { // which key was pressed? case 38: // up, move player forward, ie. increase speed player.speed = 1; ``` -Then this code cycles through each ray and draws it. [BigBlue2d](https://github.com/badvision/lawless-legends/search?q=BigBlue2d) +Then this code cycles through each ray and draws it. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue2d) ```javascript -// Cast all the rays from the player position and draw them [ref BigBlue2d] +// Cast all the rays from the player position and draw them function castRays(force) { // If we're already showing this location and angle, no need to re-do it. @@ -123,11 +226,10 @@ function castRays(force) player.x == prevX && ``` -The complicated math is handled in a separate function. This code traces an individual ray from the player's eye until it hits something on the map. [BigBlue2e](https://github.com/badvision/lawless-legends/search?q=BigBlue2e) +The complicated math is handled in a separate function. This code traces an individual ray from the player's eye until it hits something on the map. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue2e) ```javascript // Cast one ray from the player's position through the map until we hit a wall. -// [ref BigBlue2e] // This version uses only integers, making it easier to port to the 6502. function intCast(x) { @@ -138,10 +240,10 @@ function intCast(x) var wRayPosX = sword(player.x * 256); ``` -The results of all this math for a given horizontal coordinate are: (1) the wall type, the coordinate left-to-right on that wall's texture, and the height of the column to draw. [BigBlue2f](https://github.com/badvision/lawless-legends/search?q=BigBlue2f) +The results of all this math for a given horizontal coordinate are: (1) the wall type, the coordinate left-to-right on that wall's texture, and the height of the column to draw. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue2f) ```javascript - // Wrap it all in a nice package. [ref BigBlue2f] + // Wrap it all in a nice package. return { wallType: map[bMapY][bMapX], textureX: bWallX / 256.0, height: lineHeight }; @@ -160,10 +262,10 @@ Let's do some pixel calisthenics! In part 3 we're going to see how all that ray- So I showed you a bunch of ray casting code in Javascript. Let's take a quick look at the 6502 assembly language code that does the same stuff. You don't have to understand it all, but it's good to know where it is and roughly what it does. First, we set up the player's position and direction. We store each coordinate in two bytes: the low byte is the fractional part (0..255, so $80 = 128 = 0.5), and the high byte is the whole part (1, 2, etc.). -[BigBlue3_10](https://github.com/badvision/lawless-legends/search?q=BigBlue3_10) +[code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_10) ```Assembly -; Establish the initial player position and direction [ref BigBlue3_10] +; Establish the initial player position and direction setPlayerPos: ; X=1.5 lda #1 @@ -181,10 +283,10 @@ setPlayerPos: rts ``` -Remember those logarithm tables we created in the Javascript code? And the table of vectors for each possible angle? They're just encoded directly here rather than computed on the 6502. [BigBlue3_20](https://github.com/badvision/lawless-legends/search?q=BigBlue3_20) +Remember those logarithm tables we created in the Javascript code? And the table of vectors for each possible angle? They're just encoded directly here rather than computed on the 6502. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_20) ```Assembly -; Table to translate an unsigned byte to 3+5 bit fixed point log2 [ref BigBlue3_20] +; Table to translate an unsigned byte to 3+5 bit fixed point log2 tbl_log2_b_b: .byte $00,$00,$00,$00,$00,$07,$0C,$11,$15,$19,$1C,$1F,$22,$24,$27,$29 .byte $2B,$2D,$2E,$30,$32,$33,$34,$36,$37,$38,$3A,$3B,$3C,$3D,$3E,$3F @@ -192,12 +294,12 @@ tbl_log2_b_b: ;...etc... ``` -[BigBlue3_30](https://github.com/badvision/lawless-legends/search?q=BigBlue3_30) +[code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_30) ```Assembly ; Precalculated ray initialization parameters. One table for each of the 16 angles. ; Each angle has 63 rays, and each ray is provided with 4 parameters (one byte each param): -; dirX, dirY, deltaX, deltaY. [ref BigBlue3_30] +; dirX, dirY, deltaX, deltaY. precast_0: .byte $72,$C7,$3E,$7C .byte $72,$C9,$3D,$7E @@ -212,10 +314,10 @@ precast_1: ;...etc... ``` -Here's the code to process a keypress from the player. [BigBlue3_40](https://github.com/badvision/lawless-legends/search?q=BigBlue3_40) +Here's the code to process a keypress from the player. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_40) ```Assembly - ; Dispatch the keypress [ref BigBlue3_40] + ; Dispatch the keypress : cmp #'W' ; 'W' for forward bne :+ jsr moveForward @@ -233,11 +335,10 @@ Here's the code to process a keypress from the player. [BigBlue3_40](https://git ``` When we need to re-draw, this code steps through each ray, calculating the texture number, coordinate, and height, then drawing it. -[BigBlue3_50](https://github.com/badvision/lawless-legends/search?q=BigBlue3_50) +[code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_50) ```Assembly ; Calculate the height, texture number, and texture column for one ray - ; [ref BigBlue3_50] @oneCol: stx pMap ; set initial map pointer for the ray sty pMap+1 @@ -253,11 +354,11 @@ When we need to re-draw, this code steps through each ray, calculating the textu ``` And finally there's a whole bunch of code that does all that complicated math we don't understand. I'm not going to explain all the code in depth, other than to say it does the same thing the Javascript code did... just using a lot more lines! -[BigBlue3_60](https://github.com/badvision/lawless-legends/search?q=BigBlue3_60) +[code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_60) ```Assembly ;------------------------------------------------------------------------------- -; Cast a ray [ref BigBlue3_60] +; Cast a ray ; Input: pRayData, plus Y reg: precalculated ray data (4 bytes) ; playerX, playerY (integral and fractional bytes of course) ; pMap: pointer to current row on the map (mapBase + playerY{>}*height) @@ -290,10 +391,10 @@ You may have watched an image being loaded onto the Apple II hi-res screen. You' We don't want weird and complex, we need simple and fast. So our we throw some smarts at the problem to isolate all the complexity to a small part of our program, so the rest of the program doesn't have to worry about it. We use a technique called "unrolling". That's a little program that writes a big repetetive program into memory. In our case the unrolled routine has a block of code for every line on the screen, and each block contains an instruction or two for each kind of bit pair on that line. Code outside simply sticks the pixels in very regular and easy-to-calculate places, then calls the unrolled loop to blast everything onto the screen at high speed. In programming circles we call that blasting process a "bit blit" (stands for Bit-Level Block Transfer). -Here's the template for one block of the blit. This template gets copied and repeated for each line on the screen, substituting different addresses for the screen lines. [BigBlue3_70](https://github.com/badvision/lawless-legends/search?q=BigBlue3_70) +Here's the template for one block of the blit. This template gets copied and repeated for each line on the screen, substituting different addresses for the screen lines. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_70) ```Assembly -; Template for blitting code [ref BigBlue3_70] +; Template for blitting code blitTemplate: ; comments show byte offset lda decodeTo57 ; 0: pixel 3 asl ; 3: save half of pix 3 in carry @@ -311,7 +412,7 @@ blitTemplate: ; comments show byte offset ; 29 bytes total ``` -All those ``lda`` and ``ora`` instructions are actually performing table lookups. The tables are aligned so that the low byte of the address is the actual value to look up. Here are the table addresses in memory, and the address of the unrolled code. [BigBlue3_75](https://github.com/badvision/lawless-legends/search?q=BigBlue3_75) +All those ``lda`` and ``ora`` instructions are actually performing table lookups. The tables are aligned so that the low byte of the address is the actual value to look up. Here are the table addresses in memory, and the address of the unrolled code. [code link](https://github.com/badvision/lawless-legends/search?q=BigBlue3_75) ```Assembly ; Main-mem tables and buffers diff --git a/Docs/Tutorials/BigBlue/packing.png b/Docs/Tutorials/BigBlue/packing.png new file mode 100644 index 0000000000000000000000000000000000000000..97dbb752015fdf1114f516c13db3f6ea25f6815b GIT binary patch literal 32802 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 W35APl@ZfH5*qaFNSoC*brIS zd`c41?#KF~i;haFky6LmJ7O0A<;O!)GP;L862J1^BS(jb>d;_d>cjKPi4)$YKWvc< z!mdoxU?v?uGvij*wFRv7BS!2!C)_2E_?-b>9!v-KehQb{@8<39qL9CDX&i3xl`9-k z;eDG_a$s@#4KbcNF%v8Q-89DZqTFlu{Qo%#I*}>OU1QH2%vR_917o;{@ zo?3MDi#pPZNi9ttBagLCBDOBpj!C4Nwydf>z2PXQ`G=7rq0qjrNKj>Xi*R~n*$Tu` zk&6e^B*`m#WS&|eJM&V0H7rhN(c^B0azVwivApg^P7u~#ZN1{Zz@jhI`NivIogKj0zW?a7{R|eOq-IB_!Tdc z-tl#AiAdbpwvv|eG1eTeYVz3LlKfjL(LP9PKna{+HrBuKVAwr5IpSrkHs2WhH;dg9 z$zFZqDD}>tYR{KP7xdIQzZCm3mNKnSgk2|WkCaZF*Yv*Rx0N3Saa9rj!51A`)omr- z$z9yH@^C5&d|O=0*(LD$+;g=UW zkH_(CUEaH%nn8n1+>=M%V7oL%;sKJAH_x~3TfNNmI|p}fJ$Zy3JFEHZPsuneJMpoa zrk_N*#}UN(U06D6jr>|ZJ)Y}lN(P52Z!X$Yh${Uz3}3WBUtXcNvc56pa5hjVY)9Lv z%h-2O^3D_Xy9td>eoXOVb)-O2x4$v+8Q}9Py8ys1&M1*(5BvIv5zBaabBU&qZQEas zc{j2ED-0E!r|cnj`@-A1qRn{sI-wTZH4mIzYXu;`+UR-&4`I`FYq~Udhay!oue__$ zg3hKu9GvHMH*)if%I(jSX1mPenm)~5T=+xUPU4dXf*!Pl`&<2V!VR@Q0VeCZLULIA zzmZPr@e~37I!QnjLV`=;JEM_<``V7e3~li`$QsIdO7|0cz1A^5H_MmOYHK0$7r5ao zg!=~9>KtCZ^7pBw?$9tbLpf4u3GJv>p`3y~B3GL0sx?X(rF?5$QOqJn&oXgx@UaQk zHN3z1LO$!)){6j?UbfgbmxU%xen9|aNei-p+FO6IO74HLO2%7yMIrNTy28B-xf$EO zGs!q@OoSCntE_))jlguLa^H~T7;q8p>qm1CHUJTG^5!C$>l-7Or4^44dLVEJbyfW@ z3H*WN*!&Tl%Qg1rwpgA=?`o!!8zFq)@YaH8c15huv33AlzA<@q7O>JYsP8P+?RGuG zifn0$B4+Lq;<4 z_gornL~q&NxrYD9L*r)GCX@X+govk~wA9Y~^%fySh*&4bkp|F|@v$)oZNA2bAF7U9 zVRCDogS2$l#Y2nJ)~`S5?Y_pNh?=MRNfn{pYn4szJQ(q!FCNO~bhLenH2r}pVcJ%lbns2-W>qT|z& z)w;gmpKtLg#hD*VN?nmSfJ+dEbN5UOOJJsyvGmYjJK?pVNzJ442F|o$G@W3;j~_4i zkGaR(PqC%1&RB0Fwfy=Q?c@I*?^yCT5cuWP$Y=i&N-Er;zgDB&weaV4({UxnEIh+X zpc+4@lfZsm<07XoYx%l%&gSB=ABe>D+>en{H2A%Gfb?o-7jN0zL8!)~j!wB7t_fGB zD5fI{{K={E;&3%zM4EpKrg3rk#IG5F^n5{ornc!)Gmza%2MImxfn(Tz4oJXa9v&LVo<8KwEw8#5YA&@>ISdNN3 z06$#nX)sk`u6{9c&!i*5;07qe}XJO7^(t=rO{MEm(qqMfEQCV-Gq zIF}6vRQE_f!$>rdWgz)3ILFsT%yOgW;Ol3l<@ujrQJQa0T@Tzj@dx&&<0eBJXWo!> zyDj)a^b-C&{1nwoS2Edr!-wMv>N(&AYVjH3of3qe4rnT$O zslFVn^-N_2by}4&=rm>qjaMM0ja6DFU)5enwJE@Fc{V^bDGcM`>$|Pr(-q`sj@Khq z`;=bxO)w=)@E^7c@@tmolB(6YTQU% zz>OU|kGz$a2?p|AT-4jL7Yp-ht@KwN_zuv}n>3QXjJ@rA-XNO({_EL&fXv;yc;>3cgOAHMO0QVP{fp)pjM51WA9^))eh2)f2NDodzLMYMQFVbSFhbzR~~AM>9~5>-js1~2@spAb~D$T zYDmM#w|0E?wCD;3rHjnXc@4ECv`Y&<|~3RE8jTKp{E&*Y41`68o<6A<%)aJ`=?(fz$bYN%LM zvNFC~E0a3pxh`qG^dFq!v{rhe#y)7=rf~Cmdc8F{uGwPZ#umxgRrddz#v-KZ+Chyw#$lgJcs6bZ!?#Av|!w65w zl@w_O|LVLZmc!p<6OUHe`~sQS$l*vLj#JC2DCr4k-ZR{#ZTLF4c@-O-E_K9!ojKf@ z_;{Lwv1WTJCKSrYcqzeeN9nRkGs-d*gSCg(ziqsc#tv9?$iXkvevet4x(Z;`Kt8_a zOe&lE8zUGF+GY<=G*QsaG&Xqk1B92Rec23txA>a4wo>L+-h%y-kh<|SAdtR3k-4;i z+MP(Qpsdb?z3~Rb20VJta$DG0sCaegmDQ%IW%V3?UrK$j>cMq_=#Co3K;+!!hpQxU z5qO*=*j$i7FAe@!q9$uJ>~#e22IjDwrabyfLuwS9G^1O!kEIu9{*cg^{C<7hoL)k~ zH@9g+Y?a{UfA$v!YLjwgHLP$1lsl88n*?7FY%Z(iDL|sd0$x+)JBls#UIZ;w@%o-H zmyb@6-J($OJ;+HO*7{PtBm(P<@6)EdgRmfc7v&)RuwiK;=5uNASmFJ9A38&A$;ijW z{nN|6>dvS$f!FpZ&s%tLK@Y~(SU*g;qla)v> zWPfbjf@i|3lXL0T`JaG9$>iUFq(uF1Kw^UFVE7*aiM0^(M8%oD+IpkuH_^^fz&c6f z@A(AuUM1S|* zNuE|nHNGR8?iLMGd%6wBVqLta&*gS^!HabD`OaryZ}*DDKM>}o-|p`kAMeXTX|8qf zo|@`cD>n(15u^VR!|aIiBCY=B17>jN-h+Pa85C=}xSM3N%3U>P?9@ED^065bot&bQ z{|i*C303{4_Qc_tG5~_`C{rWPdjRrGJ;@sRzeTL2pRbW0nrrat5zRO6(8)e!mA-fQ z+ALwJ(M0*dz9QRKxY)OOzlP~#Dv6wh4VeW`dAM{<^;E%x(y3%d*JiIz-DPrn;^ zMx$Qdu}Sgb72D0ohCkK4$q|^~yKN1B(AZo4m+>g2p$KiC56x%{L~5!@R)IG@nd{Qr z_I0EHvAo+uVH(y1?0@x#;Neh3rmKJBX-}l5`Nmr3ll3PCdvILG&?X1+(|{kBeUx`l}BKk^g}d-3g0H*MurrdXvI831!1q6fpT->Z7o8JwF%N_o#){Z;aV&y=7=51KQG{|Mha0}94^sHP~iEoXMPIkVZ z`MrB-ke6-0p@zkvrS8L4fxIzsu2q88tO=AGDVAT`dj^!XcI{Y?HVLjx$GV;(t zwDvJ{FeF1ZxT;4FBi#@oxH``V?=xA&Stt_D7QJRM%;_E{AH=%|7GidZcc)V`gV^(CVkUzXriJm z?bW-4Vn|wKA+L!`asQf=QRn)<*V_XBUwd1~ zo@SMr=aY`D-rU&jt|V;T7S6)KT}9Y;Qs%Fon~)woq>dm+mKo!xppDv6KT{EiHiwoT zpKmDBL*CpGj=R}cnUeJl7j>JeV>`a4O4q}sm0reg!C=+dvV>!EiTUB5fVuws|BKpi zpiem$Pb8U@b>F&l^AxS7ZRX<`fXX>(5mcb;80Ur9r|W^5-M8F6HP;>Gt7-9pGV3xm zw2H8>_uSu=TKyyMG^MK#qQ2x(yi2F| zDFm6lb;hjfH70(44b6dRxdaHa#Rklaf3gXAznoaB+1ul)PAQIERrk3{pXH~zfXgeT zd`WOhx(H;uSLaWleq>UJjQMdG&r24Boy!e<+M3{LdEt$7JeCSF>cu*;5=pi5f;2=1 z&FJ35Xg?{E;_m-1Y&5f83`1t6F8+}5^491FZC84U0Hf!!LVN=Mm*69U(@vaP_e1%w+h^~OqCNDD*q&B4%UT?{ zJO4lBopo4L+uQyJkWlH629ZXP5=I&YK|o4cO1h*Q=`KM+x7&oE_Ju3N7?L;A5E6P1`L^_LwO% z++~;!j(fE-lpM(OcPPL@o>|rA2@#d~QtFW-c^J#uW zDBHW_Zk^Kc`##BK(hX`v+04l+v;#EDRgL3waQFPd(+7BJvb)aX8nZV7eMT9TBH*>1 z>dN-BqRflo)c7oP>#~%V%x`@@ibUkpye#_!ap~iW=y$qSq`4381?VBN;PEpDCUu)R zdb<`SW4azXQL4~SbW{v?d^WPuk2OgyRg=)9LH`!&LU(sSo9bii6AmiR{H>cRFhtx} zucJ`kq6_skYjY^-_4yt=A}O0}z>-v|Ca$Zg9Xl{P$yI|dP8=gdjLXI*t3pdrn_%F| z-YWUqOq*=N>NzBxr}6JjzY;#}8;1{u9n)V0yhQjYjzA}h#$+1k#Kq#QPKKk9NvnJ; zQ{(em?)9ln9A-sYSg{tztB0DW4mkcgnyQG7>#~Xx^88} zIVmr7dX-M)j8r4#CvI0;ih}&5!=4beE>%WtI$|8&ijf+aw>%U_#);q74U3xX^f2V6 zH|j3Ct^2y~SCkjvUn7WS3Je(&VmL2QUf=$n>LPq6Csj5a1tPqxorS0Nym}~TOp}P2 zqSs1KRpag7F*Bz?s`bnvJyIlSI|3T?8uJhA^NXSNILqqZr++8`NyYGemw*C{h_OE! z>mc7&cZ#H|QFL~F9T4$;VL&e1Pq|HktGBOPr7Wn@JQ(Ayd}C(&_368D(^AjcpE`rb z&{lTs=Y^{tCvf{M^3ovGwlgqkDK8uKlcnoDK8b{Cg?Y-Nc zN{~YI&99J3#+)yw$dro10CiS$@p~lK4~8h{uEn=KdA_^(2M?@Q?!UB>ukwKF-&kzi z6C)CZY30*Z+K@x#h{E-GN!t8uI-sy^*i>Y8sXLT=4XoM>HgA2qfWZM#2UvHQ8j*}E zdkZ0txdbV?8seWyq8z!B5vl}$ z82yYCHvvfTZ?&S1RJ|`pyzLl?Dz z!ifT(#wDsDpd}oJoR{3=)(7Wy1=Khpfu@*;Zqx>aS&%-HcuTS6Jv@RbOBi@O$3}Sj zUXi`+ZVZfBQ^C=bl5}j{!`n4W?u=3f_Qua@9mENz2BgrEsy_{-k>xFMJAf)9yiIfsuWX36u{X|b=4>CK zY=@8EFoocR#x6Q@AoE-NOf7QpzF7|8wMO`G8cXK^{ox8xE>`lOA%{Xc1e0Kcu z%L`J42_RLZDz*(KA=Yfy-94hpX^^z`F^Wz*ydoD6KN4cCDxKy~TTL=Oi=Q?N%$;bTRK9~a5v+FmV@>% zD;9n`{D-32K6rAb2p8>2o6h!^(wP~7;xVng3+veo+7ofh3@5lqTNQ}A?`%Ygc*>Q` zp-%u_+o2>NN(oNd?7RK2EP=`(?|0;LrVVk_IqO$TWN3_Y$-28q1Nh>vJ3|>9W5qJq za1ZLQ9xV&l-Q#*&9VOXY6vU_<;Hw&xwt%NRX6gYQ(M5#$63Xh=U*vfP9@Wzv)5Xrx z*)iF%Xq|=Y2b*d(c)GdV7>OrIgr41Lb)afH@tUdo{+<_07&Y14*;S$wyx?@_I;T5e zn&Vq9BNObrGTl%&UZ8)!WX}WN01NsNNt5qac3u9CL?-AG@`E`jJHE(w81II#7YNXa z>MOSRK~zG8jwZpb!|QQ9K!BTmbA976*)Q5(9@bPsjrsSEPs(3jzVc~SzSU@*QcTK1 zhn%JBg?zNIj@A$2t`zNvU3q7tx5R8kA@G{yv;p!4HNyMVQz?=2szRQ}QxHI;npEyg zwe3GWk4E>E-?iy=&@J4IeQ2zw5EBCi=aFe9)#F^ghgHk5neo4?`8CQN#1Jab60(4( zKXunEN7(CfLL@W6ZF{7A<4A9xhQu+hu>cMqIq83&G{i7wzGU1)x37|mNOW9o|E=ef zwf^!EGLu6EqmUDiP&hZc-ZhhJ=~>)xuB)%ekiT4CTu<=|lgkrSSB+p`@IZYSr6vMDjGDozFCSdqQYHC1h_A z1(&3qo@YOC0j9L0HU$uzJAc57FTl*xm|T#^C*Gzc>CoQjI%AF?o+*gK96w9lS)3pp zDI{NA&CDq2b&Y&dd(r-4zsITwBS-0_a-NIo>WYJ?cx;K5$pVQbPP5KwQi9Iowsb~m z>#`c~G;mSuCU`^s)ib1=cF*br9bMaAD=--0cR*wpnd&EkacxzvgfDbi46!muHO_Ty zteCY<6uoB7cHCFZ1Zf??$lrO|6r-TArvT!mg3*2y15tWO=)JqTI_?NvYmXo6O1OzS9oMKxMv zNz*&XdMAPnu-r$?TgREpyotBHGVOVX;haPe$YIma*~A;Y=Qy#QWq^he`*SB}&ah_P zB={i8E3C$Pv}SI6@CeK&^Tst7sRDHUq#B)Z`&;Drx|egs>`4vh;FGtdFf{lZDDe1* z>3fdu`~&r_K|8bcIr4cr^_G1taEDM$$S9SYn2V@}_HQL2Eew#(0KrX=sRGiAg{u{= z?jMIl3bQv?`#lJjvmFr;(>Or>3!TDeQFYdV##>n+3Etzce2tqN(*WTGU}GCz=MCUB_}}mv zkbikRNxmA{U_@5z(J{*aqrlArCeKVDgaxg8KUM%mMj&7oa+v{CNH=LfM7nZiP#}(v^&6vE)weS9Db!zge|>`#+t~}1l7C5Uqe@B%!cJ1l@iS=Yy}Nn4 zjWZt06=MPeVM>x;%0_tn47S1C@m)B?QVQa1HSbyb;f6B(+lTUC@Q??W zomH7()oKeA2?*=!IE)k5;s7T04q-f!>K+2^=BXRChl_jGpX(z&wSYPVa=dK-UF}8w7WOu*93! zPy_sRkszN19ps1lDAsWZB=}8kG-}md-EG%&x%2!^S&IsUMXgj>=Pg{H?S%o%|H+dv zb@IU<++c{h{+fbo7Tj#jpE<#o<6r{>H)ybGq_O$>6|)Q8Lv8)(T!9*}Ub8;zuk&$!6+&;tvD$N0(bxNEz@3>37avC*kLPx#+?Dd3Tn2hGc5w3D}WzXU2KlA?mU-7lH1LJ8(+7!DKFc zz`q_zU$Do6B9uhs!)EH_*T>Vj1hXRguKvW!o%`EfVh22^*lWBm8yjE7aNuU z!*2G0R|JFt3#CAF&RRQHUkU8ojM4g$Q|!n({I#=a)Wo(|{*e?JE+LA3EV67k$+Jnk z6B}(H@Ru%ER;Fk#%@yr-7TwYMJxV)CYSU(mRfnd{)<>fy2@RfX6qMOy23kVZU>4|% z)m2!D;RhoWe9)Ml*X$emXI*HfBL3s65Pt&yR%@C#ZZm86uZ=Rp6_eSGnT~F<`cdti zNpsgg9>81&i+x`3>C=d~=%~$;FVCr9$NuM*M4e>`4+_zZ=fvqUuZf5UR&{iI>y)Vu zN{nUHU6Vp!G9G8j#c`?Uv)Zch^g9Ga-p+eE$Pxp|=+y8oCuQ6yL!#+Ood0HiYAi&( zHu`Jl5}RaKK}dr4Lhm2`E4AM{q(Cpf^n2#)FpO32dU+8I!7SNBaHWX`+@?H5&|lYu zX7EbI3Z#^i_EB9am!F;Tdrf~M+}N`htzF5gGpwpbO~P_;~1M^V}X-!+an2{MDRQn@GBkC_-yU~Seb@0e?H2ZU$T zWs$i>hl<+4rY1RK|NIH=gtl9?y=|^Oiz07)XB8FPah+|c=~^iJ>ZbaE5zDPrJCS*9 z+cc@mN!|QJ>0f7xbgQZ!@3*0U;z536s1~pTXT_5h-DJcrZ}xn5;~RWzb_pN%z^fIj%3;tL~c80h^lIxx}mMxY`riI z!ZV5HB|sDahkRj%EXYHDY?)0uirM`)$V0n%ecFu=|mc#*;_x=&e z_I+FTW0^HWo=UcVE)V^s078BkgecNsyo{4lSrD(s&PZX^Ll|`;P#9OpT8Y6l&H}5O z^d9DSrXyEq1*G4P0yjvTfWU96Pr*3DH*(Z||CVemz2cSQR=Dhw@pzm7Sp9~C!w*p$ zi`F|fIogi>oA{(Ue(%^5>9|sby?IzeYE^C;5pt_C!D<}|4;n4D$KlOp-O?;=wJ4Tg z8pPdc%BKCV(1)63u$w)ZOjjhgOPiyQ1CE|gL=4OrV!UtL?kCbRIx)T!d>)M3{QpuY zt=p9-@}+F%xZSB{^nBQij&TkBQ^hbIRgn_G&)#>Q?ina(RQ7E7qgTOQk&f7`1yE16 zi*UynX*!G@02zS?#MV2zFDs=(KZpP^JqlT2Qs}9Z(FI zZn${oQbCR*>0e%3+}g#(l!`K0qNnenoO6}o< zPC09PK%(ahM?JBLEvHXDC+0u*(9!_1hq29RmNJUKx0s=hCOqk#;W*k7 z+N9haWKgbvH`6dmz*L@D=76PVN>C(>7frQNfZ+X>9obX zT-#HjUA_U1cC&-IMpayxcSi+31a;lN{~MZmVcDMjpZC&|dJ=O^p#|F&;iXwW12{;J;2JhNL^%`D7Z_{nRHcK9Aruj*a-(2OC}4qyK4|nWQPyIqIoSVA{j`XX$78ob^=2g) zsQd1#ZXxwAJkeFM+4g@om&2$%AM8GS?Mn7x_* zF6Q|6#8DXh`NBkLa?7(LE6$S`n)F)+DCU?y%o&#)iw`GftfcPE{`Xm0}Ubw;A4Wkx+4)0kC z`Aywa2d@qU7W@&eEIyObvM}_qrR&4~U3OzYQ;LM?P}uxnF=t-$XroCk`)G4WY5OV5 z$!-_;fK=I(;;Rk3BkdyfrzKnjDjgs(fNve;dOLv59#-+9*gstCh`;ye>Pg}p?axl_ z-x|IC5RRmn1e~r|@1)75bTkw5Gb78D5O3=^)onk;<9&fOVqgTMdQkBm$#m-9mLA)V z+ng0!$hv<0{DbEMVQ^CDg!!t7sG@+OJjU~1Ter{UWys$ahZX2?;d9J4jM*=WLRXj& zgXNF$os0gc=~<}+)5G{HZbots7gmQr$OxQxxuss0)Dh5|=`(kNTbc?$W@@6`F%p;l*5C? zpNl6Y#o#(F0Lf0BlLeUUO`_t|LTGG|G|xq95Uqi-;(LA0$>ZCyBg{N3Yteql3$RLK z)5}*cnrk|hHmG9fl9l;>bZH#qC;YyrV6v4k_si=b;7|)6mJ56NAM`A-v^FCTtsShkIqzcLbB!Hiy6J6t{sm#q z={2@fRX|tJ5Yt_nxbRHLt01%AG z^{t^56qk8FQ-bO>C5tJ5SVr*eAJnORzyNXivW3JitRc}xOo_G_5BDs6v)h7UUQ+0=SpfW zyT=UCm$4xm0c@~8EpHceQ2S-p$Hg|I1dK`$m2cVR{f8?cz4MNDI&xDz zydXS+yu#LJWBdl=vzZ5o*r^io@G z)}*Li!R`GkwAnIeq+)XZ-({R-z5ZjqYKy0YjxosWXy8YD7{&qFTe2XBPU5a-1D=!% zUZrAo%hf&~<_pbkP#A+72%-!62aV4^nE6+vT(`muKN!IS35?kOGj5 znFD*D0P&d~?NEMpiKBY}DyXBwtzL#SL{fPAF7=d{#rGTI^Uzs+^JEmw(Z2e&QaYY- z%O!=5O*|={rEk$+o+YYlRrA%*uf}&w@&~J@%pTwYt%9&WAMT#tc_$W$YUTTNKpvvXA@s!_9Y=}Cb_8dxXj{=%4@{Pc=4_-$H=>*lm^tbmYs?Q z>@Ordb$ULi`5a`u$M*btx;vu5=%k!UGuDQ){_Bo1Pamn>=bgePqR3T^yXr&NqcWs) zAm&vRR3~7w7HM+rd%{9x*Bbkvq)|X*Rm<3F1dDl+$EB}28Eu?}r}uyUo`nZ%JTfs-`Y*k?f3@Nk=aROS-7qJ`wRoRteP%VtyOy5V4f3X` zQM8N+t{!|=VejS{3GvV&oQGMzyf;odHV8xRmAzoHFr<(SvJf)ed!`#2L+t~Y_W`Fy zn&67t`+#$P!EW?B*bzy#I}0s3c`RL_!WTwWUBtPEC@y?Tft^ZzLrkU!GJ+B_w#Z+u z>Ka&NNvN&edf@bWJev;T=C9&Nk?K53)!)=_b@v4x48EViKpdQ3l`gp#a&R=&Ls;vW zoA=o(e4YCpLEZe0q12>ggL16WbK2a#Qy8Sr!FkQ-OLLEcRQ)v80=W)gq(*rPUYd5A0)Q;FGWbg$)8fcsS>rCZ;Uu( z{7yNPTE}GlnubWXCAz8AMT(aJ@`BK_SlEPx7R872#4-?@gT3jT%#7J`%n#wn@wgje zYuU$qh%Kh(^xt84sZ-Flc}R_SPk1|AqAke~>)nlzzlK(13~>Gd4Yb{7c5kkCOUI6Q zyze$jbZg=)ik&QqIL#`_)rfy(chdqDDe$Q#v63_+5`3n}3ui*0@%sxdK;#qyug5JG zQ>#S+Q=(py)U3`<0L>K^(a1_dV*k`Sgf+9L>a==pKMBu`E-rT$4c_h-5o7d2PG4ny zzF@@6sC(>Qu~Dl_1&8o!%?YO`3J+%0_Gs)hLq?C4#!Vl%T1-MZ*u_pSyfX^8SSk!! zFaB8fQi6W7(p~$QYQn`ntPfiCd`h@pUvw*3=+1P2g{5AH$o{RVHJM^UrOP>I_N4h- zBK8|ZS;7H#8J%&5;fxHM|NFCjB@1*HR%5Q28ShYYoyC$G!OTiuwT7yfw-j`-g(95W zyk|ySNknx3#WTQpi;sNo2-3<4Z+`jkr*_4Z)I-ER;C*0d!|{eBY3md}!>?Mf7G*Eu zi9fHS7v)&Hi{4^Fanq2_c`gW_h*#;lD2^#RKFw{O-i3{D24F8rS!tEm)qa-bS?JwAtR`{dezb)oXsKKuj6g@TrVpT=WHx z)c^yFhVIwoZRLZ9-|}P)l{RL_7wWQ8hKdTdrXV$*9FPvpG!0~U-WSb|0@w;*Tu@-4 z9*3MA4r1HY%741cQm@|@{;cLi(VboJ!Mbnaw17^p$qgY1trT@8OZDrz$Bb0WhIN=m z2`gBe7%M1|mXn$mS>-oI!(1SAn!7>d+=Y&q)uO0r&P#pBLd}rpDt#}xiTGV2=1L=q zOUE94GOir&;7&DITC-uihA>5lggx=0A>oTgUh5{Z%I&Th3M?eKGk?mN{FHKV9dwMK zYS^Z&%Lm0fPHy8o0_Wj_^tfXgU;B${cvr&)-Z^B?vvNS;3S!hWFuP~k1iLRh{2U+W zVhMXZeADnEkycN+d|cqrHa=7YEz)9YV$}}`5)`lW@G&xq&*q0uTqqhMpd25QuQ4Sh z{3G_tN5#WHDw^`#&6|b{w1h5_(+UHGY3q`aZeaEu^W(g0HYT1d?nD(FphZRCEQ%&GspjB@fY8 zz{#7pFMYqhW9hL&AFbQvySgxFZV!R3>81xKNt}oKe>^IIqw$W;qb+#!=oBw!ezUi7 zGjyop<|?a9jF+th8+bxL}Ldt%er%csjuRLU=kVjhHjzr5{xx&K02`g9r zNUq0l7PDVl;T@~m)kPNYE2~lYbN;_3@4}ZMTxr-?*dI9ug~$8!6PJrX?7+*UY3R&N zL8oJl%cMC}%u3=acF#yRHjsPIZD7JDOK#sZePQ8agzxskV=?qqimqC5ZZX%Nx!LYh ze#^G}tf{boM~_CuM-sg30PWK z{PMZ>qJ1NzXb@}C1TSC0jTH#bC7;%JmKb9ozYCb0Z~nT)Fv??j+XzUexbC}^MK%Y{ z$@6K|T!0 zwI<<4rpdU_-Z*h?UcE5YBY_{1(U_NkWHi?^{$V(Q?AIJ$rpWP)UMe@gK2X6-+K9Dh%iGXiAU{%RpU>F zrM!p&kWvc~jh}WZ#44i6z3LPxQ5EHL255IFt#bWs-!TV-;plZCHwpLakcgZTd1p^+ zMhUXQF2l>HU0-OF+S5sI%cWzJCRs;ch3SB^C)3a{7zgUEu4|Grvk6Cd)eZp|Ve0GL zXpyV^aUIWGOv=69gfxgt&sgoU_#7DD+O!&LgwcAiwdHv{UQhgZsv!QST|# zd%pqL7x!kJCWg4Xd!zR5RY&()Fw@AO8wx_L=BVb4=k9Wz3{>}5h1%}m1$vPC)|#WO z9SqP$vMw*G=-xTl(0X@rG9oLtKezjV9%AkQ0!f|RFh&cDU1I-YI;Syao=>Rf!4jdx zYZLTEi*|C>%7m>mjVE5vL2}c)Vtc=+5kp;8fQJK|&CSUo#m6*yx_Q2LS|n z74`M>H7vKz4*1uwAzHu%lvWQFt+X|)bU3vvbbucq7A9s^24*G(CN^1SW=__-oJ?Q_ zCNL)x6RbCy(@z%|n`#^A+W+DL_R9+fvMa2C3ve&q!OB2ams8`pnZ5?d+C;6==a8tYhD7-)f>2tO#eDKZ5d ozw!OJg{iG2gPD#6gC%f^8Hg3UPBHKqI0Gc|P(m>G!87-N0~tyKJpcdz literal 0 HcmV?d00001 diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/apple/AppleImageEditor.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/apple/AppleImageEditor.java index e31f90a1..da69ed6c 100644 --- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/apple/AppleImageEditor.java +++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/apple/AppleImageEditor.java @@ -241,7 +241,7 @@ public class AppleImageEditor extends ImageEditor implements EventHandler= getWidth() * 7 || y >= getHeight()) { return; } - int pat = pattern[(y % 16) * 4 + ((x / 7) % 4)]; + int pat = pattern[(y % 16) * 4 + ((x / 7) % 4)]; // [ref BigBlue1_20] set((pat & (1 << (x % 7))) != 0, x, y); if (hiBitMatters) { setHiBit(pat >= 128, x, y); diff --git a/Platform/Apple/tools/PackMap/src/org/demo/PackMap.groovy b/Platform/Apple/tools/PackMap/src/org/demo/PackMap.groovy index 0e6b3e00..fd90560a 100644 --- a/Platform/Apple/tools/PackMap/src/org/demo/PackMap.groovy +++ b/Platform/Apple/tools/PackMap/src/org/demo/PackMap.groovy @@ -42,7 +42,7 @@ class PackMap def pos = (lineNum*nBytes + byteNum) * 2 // two hex chars per byte def val = Integer.parseInt(hexStr[pos..pos+1], 16) for (def bitNum in 0..6) { - if (pixBits == 0) + if (pixBits == 0) // [ref BigBlue1_40] pix = (val & 0x80) ? 4 : 0 // grab high bit of first byte of pix if (val & (1<