Author Topic: [now tuto] 8 level gray in Axe - with masks  (Read 3882 times)

0 Members and 1 Guest are viewing this topic.

Offline pimathbrainiac

  • Occasionally I make projects
  • Members
  • LV10 31337 u53r (Next: 2000)
  • **********
  • Posts: 1731
  • Rating: +136/-23
  • dagaem
    • View Profile
[now tuto] 8 level gray in Axe - with masks
« on: August 22, 2013, 01:39:41 pm »
I have successfully created a (far from perfect) 8 level Axe grayscale program (by far from perfect, I mean that I'm waiting for my crystal timer interrupt library (*cough* Runer112 *cough) to make it great)

But for now, here is the first screenie from wabbit: This is an old screenie. The new, smoother version uses Full, and wabbit is not emulating the Full command, even when I have the appropriate box checked :P



(That is a fanart pic for Crystal Maiden from the game DOTA 2, btw).

I am not releasing source or conversion utilities just yet, as I am waiting for that interrupt library (*cough* Runer112 again *cough*)

I used masks, given to me by thepengin77 (he also told me his way of doing grayscale without masks, but to me, the masks look better).

So anyway, I'll release a version and a tuto when that library is finished (*cough* Runer112 a third time *cough*)

tuto at: http://ourl.ca/19443/358571;topicseen#new

(still waiting on that library (*cough* Runer112 a fourth time *cough*))
« Last Edit: August 23, 2013, 09:11:48 am by pimathbrainiac »
I am Bach.

Offline DJ Omnimaga

  • Clacualters are teh gr33t
  • CoT Emeritus
  • LV15 Omnimagician (Next: --)
  • *
  • Posts: 55943
  • Rating: +3154/-232
  • CodeWalrus founder & retired Omnimaga founder
    • View Profile
    • Dream of Omnimaga Music
Re: 8 level gray in Axe - with masks
« Reply #1 on: August 22, 2013, 03:31:19 pm »
Wait I didn't know that Wabbit didn't emulate the Full command ???
Anyway I am curious about how fast this runs at full speed and with proper Wabbitemu screenshot settings.

Offline pimathbrainiac

  • Occasionally I make projects
  • Members
  • LV10 31337 u53r (Next: 2000)
  • **********
  • Posts: 1731
  • Rating: +136/-23
  • dagaem
    • View Profile
Re: 8 level gray in Axe - with masks
« Reply #2 on: August 23, 2013, 09:08:12 am »
Imma release a few versions of the source right now, because I feel nice. :D

This is all four possible versions that I've come up with (other than the original screenie, because these are better and because real calcs only), with lines commented out to separate the versions.

Imma also attach the necessary files to run. (uses Full, so SE only)

Version 1: (masks, no interrupts)

Code: [Select]
:.GR8GRAY
:
:Full
:
:.[8140201008040281]→Pic2
:.[2291482412894422]→Pic3
:.[F7FBFD7EBFDFEFF7]→Pic4
:[0281402010080402]→Pic2
:[4824128944229148]→Pic3
:[B55AAD56ABD56AB5]→Pic4
:
:0→A→B→C→T→J→K→M→N→O
:
:1→Q
:
:GetCalc("prgmCRYS")→R
:
:det(768,0)→E
:det(768,0)→F
:det(768,0)→G
:
:For(H,0,11)
:For(I,0,63)
:(I*12)+H→K
:{2+(K*3)+R}→{K+G}
:{2+(K*3)+1+R}→{K+F}
:{2+(K*3)+2+R}→{K+E}
:End
:End
:
:ClrDraw
:
:.FnOff
:.FnInt(D,0)
:
:While 1
:If (J<7)
:J++
:Else
:1→J
:End
:.If (Q=1)
:.FnOff
:For(I,0,63)
:If (J<7)
:J++
:Else
:1→J
:End
:{J+Pic2}→M
:{J+Pic3}→N
:{J+Pic4}→O
:For(H,0,11)
:(I*12)+H→K
:.((({K+E} xor {K+G} xor M) and ({K+F} xor {K+G} xor N) and O) xor {K+G})→{K+{L6}}
:(({K+E} and M) xor ({K+F} and N) xor ({K+G} and O))→{K+{L6}}
:End
:End
:.0→Q
:.FnOn
:.End
:DispGraph
:EndIf (getKey(15))
:.FnOff
:.LnReg {^r}
:Return
:
:Lbl D
:!If (T++^10)
:If (J<7)
:J++
:Else
:1→J
:End
:1→Q
:DispGraph
:End
:Return

Version 2: (masks, yes interrupts)

Code: [Select]
:.GR8GRAY
:
:Full
:
:.[8140201008040281]→Pic2
:.[2291482412894422]→Pic3
:.[F7FBFD7EBFDFEFF7]→Pic4
:[0281402010080402]→Pic2
:[4824128944229148]→Pic3
:[B55AAD56ABD56AB5]→Pic4
:
:0→A→B→C→T→J→K→M→N→O
:
:1→Q
:
:GetCalc("prgmCRYS")→R
:
:det(768,0)→E
:det(768,0)→F
:det(768,0)→G
:
:For(H,0,11)
:For(I,0,63)
:(I*12)+H→K
:{2+(K*3)+R}→{K+G}
:{2+(K*3)+1+R}→{K+F}
:{2+(K*3)+2+R}→{K+E}
:End
:End
:
:ClrDraw
:
:FnOff
:FnInt(D,0)
:
:While 1
:If (J<7)
:J++
:Else
:1→J
:End
:.If (Q=1)
:FnOff
:For(I,0,63)
:If (J<7)
:J++
:Else
:1→J
:End
:{J+Pic2}→M
:{J+Pic3}→N
:{J+Pic4}→O
:For(H,0,11)
:(I*12)+H→K
:.((({K+E} xor {K+G} xor M) and ({K+F} xor {K+G} xor N) and O) xor {K+G})→{K+{L6}}
:(({K+E} and M) xor ({K+F} and N) xor ({K+G} and O))→{K+{L6}}
:End
:End
:0→Q
:FnOn
:End
:.DispGraph
:EndIf (getKey(15))
:FnOff
:LnReg {^r}
:Return
:
:Lbl D
:!If (T++^10)
:If (J<7)
:J++
:Else
:1→J
:End
:1→Q
:DispGraph
:End
:Return

Version 3: (thepenguin77's method, no interrupts)

Code: [Select]
:.GR8GRAY
:
:Full
:
:[8140201008040281]→Pic2
:[2291482412894422]→Pic3
:[F7FBFD7EBFDFEFF7]→Pic4
:.[0281402010080402]→Pic2
:.[4824128944229148]→Pic3
:.[B55AAD56ABD56AB5]→Pic4
:
:0→A→B→C→T→J→K→M→N→O
:
:1→Q
:
:GetCalc("prgmCRYS")→R
:
:det(768,0)→E
:det(768,0)→F
:det(768,0)→G
:
:For(H,0,11)
:For(I,0,63)
:(I*12)+H→K
:{2+(K*3)+R}→{K+G}
:{2+(K*3)+1+R}→{K+F}
:{2+(K*3)+2+R}→{K+E}
:End
:End
:
:ClrDraw
:
:.FnOff
:.FnInt(D,0)
:
:While 1
:If (J<7)
:J++
:Else
:1→J
:End
:.If (Q=1)
:.FnOff
:For(I,0,63)
:If (J<7)
:J++
:Else
:1→J
:End
:{J+Pic2}→M
:{J+Pic3}→N
:{J+Pic4}→O
:For(H,0,11)
:(I*12)+H→K
:((({K+E} xor {K+G} xor M) and ({K+F} xor {K+G} xor N) and O) xor {K+G})→{K+{L6}}
:.(({K+E} and M) xor ({K+F} and N) xor ({K+G} and O))→{K+{L6}}
:End
:End
:.0→Q
:.FnOn
:.End
:DispGraph
:EndIf (getKey(15))
:.FnOff
:.LnReg {^r}
:Return
:
:Lbl D
:!If (T++^10)
:If (J<7)
:J++
:Else
:1→J
:End
:1→Q
:DispGraph
:End
:Return

Version 1: (thepenguin77's method, yes interrupts)

Code: [Select]
:.GR8GRAY
:
:Full
:
:[8140201008040281]→Pic2
:[2291482412894422]→Pic3
:[F7FBFD7EBFDFEFF7]→Pic4
:.[0281402010080402]→Pic2
:.[4824128944229148]→Pic3
:.[B55AAD56ABD56AB5]→Pic4
:
:0→A→B→C→T→J→K→M→N→O
:
:1→Q
:
:GetCalc("prgmCRYS")→R
:
:det(768,0)→E
:det(768,0)→F
:det(768,0)→G
:
:For(H,0,11)
:For(I,0,63)
:(I*12)+H→K
:{2+(K*3)+R}→{K+G}
:{2+(K*3)+1+R}→{K+F}
:{2+(K*3)+2+R}→{K+E}
:End
:End
:
:ClrDraw
:
:FnOff
:FnInt(D,0)
:
:While 1
:If (J<7)
:J++
:Else
:1→J
:End
:If (Q=1)
:FnOff
:For(I,0,63)
:If (J<7)
:J++
:Else
:1→J
:End
:{J+Pic2}→M
:{J+Pic3}→N
:{J+Pic4}→O
:For(H,0,11)
:(I*12)+H→K
:((({K+E} xor {K+G} xor M) and ({K+F} xor {K+G} xor N) and O) xor {K+G})→{K+{L6}}
:.(({K+E} and M) xor ({K+F} and N) xor ({K+G} and O))→{K+{L6}}
:End
:End
:0→Q
:FnOn
:End
:.DispGraph
:EndIf (getKey(15))
:FnOff
:LnReg {^r}
:Return
:
:Lbl D
:!If (T++^10)
:If (J<7)
:J++
:Else
:1→J
:End
:1→Q
:DispGraph
:End
:Return

So, I need to explain the differences in the comments.

Make these changes from version 1:

To enable interrupts, comment, the DispGraph in the main loop and uncomment all the interrupt stuff and anything involving Q. (no really specific blocks to uncomment here, all spread out).

To change to thepenguin77's method, filp the commenting here:

Code: [Select]
:.[8140201008040281]→Pic2
:.[2291482412894422]→Pic3
:.[F7FBFD7EBFDFEFF7]→Pic4
:[0281402010080402]→Pic2
:[4824128944229148]→Pic3
:[B55AAD56ABD56AB5]→Pic4

and here:

Code: [Select]
:.((({K+E} xor {K+G} xor M) and ({K+F} xor {K+G} xor N) and O) xor {K+G})→{K+{L6}}
:(({K+E} and M) xor ({K+F} and N) xor ({K+G} and O))→{K+{L6}}

That's how to change versions. The version 1 source and the prgmCRYS image are attached.

Now to explain the version 1 source (minus all the commented out stuff (as if it weren't there)):

Code: [Select]
:.GR8GRAY
:
:Full
:
:.[8140201008040281]→Pic2
:.[2291482412894422]→Pic3
:.[F7FBFD7EBFDFEFF7]→Pic4
:[0281402010080402]→Pic2
:[4824128944229148]→Pic3
:[B55AAD56ABD56AB5]→Pic4
:
:0→A→B→C→T→J→K→M→N→O
:
:1→Q

In the above snippet, you set up the masks. The masks are 8 bits, and each byte pointed to is a rotated version, for ease. You also set up the variables.

Code: [Select]
:GetCalc("prgmCRYS")→R
:
:det(768,0)→E
:det(768,0)→F
:det(768,0)→G
:
:For(H,0,11)
:For(I,0,63)
:(I*12)+H→K
:{2+(K*3)+R}→{K+G}
:{2+(K*3)+1+R}→{K+F}
:{2+(K*3)+2+R}→{K+E}
:End
:End

The above snippet places the bytes of the the program CRYS (must be unarchived) in buffers, for speed and ease.

Code: [Select]
:ClrDraw
:
:.FnOff
:.FnInt(D,0)
:
:While 1
:If (J<7)
:J++
:Else
:1→J
:End
:.If (Q=1)
:.FnOff
:For(I,0,63)
:If (J<7)
:J++
:Else
:1→J
:End
:{J+Pic2}→M
:{J+Pic3}→N
:{J+Pic4}→O

The above snippet sets the pointed byte for each mask.

Code: [Select]
:For(H,0,11)
:(I*12)+H→K
:.((({K+E} xor {K+G} xor M) and ({K+F} xor {K+G} xor N) and O) xor {K+G})→{K+{L6}}
:(({K+E} and M) xor ({K+F} and N) xor ({K+G} and O))→{K+{L6}}
:End
:End
:.0→Q
:.FnOn
:.End
:DispGraph
:EndIf (getKey(15))
:.FnOff
:.LnReg {^r}
:Return

The above snippet masks the buffers and displays the masked image. (Standard masking used. (& the masks, then xor the masks together))

Code: [Select]
:Lbl D
:!If (T++^10)
:If (J<7)
:J++
:Else
:1→J
:End
:1→Q
:DispGraph
:End
:Return

The above snippet is all interrupt stuff

So, the interrupt stuff and thepenguin's method have not been explained. The interrupt stuff you can probably figure out, and here's a quote from a PM thepenguin sent me explaining his method:

Quote
Essentially, the way I do 8 level is by shifting patterns across the screen. These patterns sample each of the 3 layers (low, medium, and high) so that the amount of time that a pixel is darkened is equal to the value of the underlying layers.

I hope you understand this as it's pretty simple when it comes to grayscale. With 8 colors, you essentially have a pattern that has to repeat every 7 frames. Here are the fractions:

0 = 0/7
1 = 1/7
2 = 2/7
3 = 3/7
4 = 4/7
5 = 5/7
6 = 6/7
7 = 7/7

Those are pretty obvious, but I just have them there for good measure.

Now, as far as translating those fractions to a pattern. Here are the patterns that each of the different shades need to display:

0: 0000000 
1: 1000000 
2: 0010001 
3: 0101010 
4: 1010101
5: 1101110
6: 0111111 
7: 1111111 

But of course, the question is, how do you make those patterns? The answer is that it's tough. I spent a long time trying to figure this out. The issue is that since these patterns are 7 bits wide, they are really annoying to work with. I don't know how you want to go about doing it, but here's how I did it.

h = high byte (the very back layer (I think it's back, it might be front though. It has a value of 4))
m = middle byte (value = 2)
l = low byte (value = 1)
^ = xor
& = bitwise and

((l ^ h ^ 1000000) & (m ^ h ^ 0010001) & 1111011) ^ h

This will get you the value to display. You literally apply this function with those constants rotated to every single byte and you will get the values that you should display to the screen.

To finish rotating those values, you basically just imagine what the pattern should look like and take a subsection of it. For example:

1000000 - if this continued on forever it would be: 1000000100000010000001000000
So you get masks 10000001, 01000000, 00100000, 00010000, 00001000, 00000100, 00000010, 10000001

That's about it. Good luck, and happy grayscale!

EDIT: G8.8xp does not compile in its current state. Go in, and change the .GR8(bad symbols) to whatever you want (an error on SourceCoder's part)
« Last Edit: August 23, 2013, 12:54:10 pm by pimathbrainiac »
I am Bach.

Offline pimathbrainiac

  • Occasionally I make projects
  • Members
  • LV10 31337 u53r (Next: 2000)
  • **********
  • Posts: 1731
  • Rating: +136/-23
  • dagaem
    • View Profile
Re: [now tuto] 8 level gray in Axe - with masks
« Reply #3 on: August 28, 2013, 08:50:51 am »
Bump!

I thought I'd let you know that I found a link to Runer's pastebin that had the necessary code to do the crystal timer interrupts. Expect more soon!
I am Bach.