Omnimaga

Calculator Community => TI Calculators => ASM => Topic started by: thepenguin77 on March 07, 2011, 11:58:14 pm

Title: Perfect Grayscale - Tutorial
Post by: thepenguin77 on March 07, 2011, 11:58:14 pm
With my recent work on Chess, people have been asking me how I make my grayscale so perfect. So here is a tutorial!

First, a little background, most of it can be read in this topic (http://ourl.ca/4866/101502). A while ago, I made a program that displayed 16 level grayscale pictures. It worked pretty well, but it was clearly not flickerless, it had major scrolling patterns and some spots literally flickered. Then I thought, if I can do 16 with 120 refreshes per frame, why not do 64 level grayscale with 100,000 refreshes per frame. This was accomplished using z-addressing and I put 1 pixels in the first column, 2 in the second, 3 in the third, and so on until the screen was full. Then I scrolled that at 100,000 fps. What I noticed was that at certain frequencies, the images would slow down, stop, then reverse direction and go back into oblivion. After a little bit of playing with it, I figured out that the LCD actually has a refresh rate. And that rate is 60Hz.

This little refresh rate is what causes all of the problems with the LCD. Lets say that you quickly change the screen color, if you've used your calculator long enough, you know that there is a diagonal line going up your calculator for a split second while it is clearing. This is caused when you and the LCD driver are updating the screen at the same time.

The LCD driver has two parts, and each part works independently of the other. First you have the LCD ram, which is just like regular ram. And then there is the LCD driver which updates the screen 60 times per second, at a speed of about 100 pixels / (1/60 second) from top to bottom. In common practice, the LCD ram is filled one column at a time, starting at the left, and working your way across. This operation takes about 1/120 second. What can happen is that while you are updating the LCD ram, the LCD driver decides that it is going to start displaying the screen. It displays 1 row at a time, and as it falls down the rows, it displays whatever is currently in ram. So you can see that if you are updating the screen while it is reading it, there will be some spots where you as the writer will cross over what the driver is displaying, effectively making the driver display part of two different frames.

For your average game, this is no problem, a minor graphical glitch that is only present for about 1/60 second and that only happens about 1 time per second. But grayscale is an entirely different case. This graphical glitch is very obvious because it screws up your careful pixel timing. Instead of ON ON OFF ON ON OFF, sometimes you will have ON OFF ON ON OFF ON, which spread over the whole screen, just looks bad. Also, let's say that you don't know about this whole refresh thing and you update the screen at either 80 fps or 40 fps. At 80 fps, some of your frames are never going to even make it to the LCD, you are updating it so fast that you will update it again before the driver has time to display it. And at 40 fps, some of your frames are displayed twice.


After hearing that, I'm sure there are a few of you that could go out and write your own display routines, but there are also those who can't. Here is an example of what we don't want.
(http://img.removedfromgame.com/imgs/bad%20grayscale.gif)
You can see that the LCD driver and the displayer are not in sync and scan lines are clearly present. (Technically since that is in wabbitemu, I had to do something entirely different to get that effect, but you get the drift.)

Now, to get away from this, you have to learn the way of the LCD driver, and try to basically run away from its display line. First off, it displays rows, not columns. So we will obviously have to write a 07 to port (10h), and work horizontally across the screen. This does have some speed drawbacks, but that's just how grayscale goes.

Now that that is out of the way, you will notice that your grayscale routine actually looks a lot better, but we're not done yet. The next step is to get in sync with the driver, which is accomplished with the crystal timers. Our goal is around 60 Hz, so the timer that gives us the most flexibility around this range is timer 40h, it runs at 10922.667 Hz. Then you have to apply your multiplier to it 10922/60 = 182, so a counter of 182 will get you 60 Hz. I of course prefer 178 as that is what my calculator is synced to, but to each his own. (The typical range is about 160-180). To put this into code. 40h to (30h), 0 or 2 to (31h), and 178 to (32h).

That's it, do that and you will have perfect grayscale.

And why did I mention 100 pixels / (1/60 seconds)? That's because you can't perfectly match the frequency of the driver and there will always be a small glitch line. But if you do it right, the line is off screen for 1/3 of the time.

Here's an example of implementing what I just talked about. It's commented quite nicely, but I left it up to you to make your own calibration screen (I don't want all the games to look the same ;))
Title: Re: Perfect Grayscale - Tutorial
Post by: ralphdspam on March 08, 2011, 12:00:08 am
O.O Thank you, Thank you Thank you!!!!!
From now on, you shall be known as the grayscale master!
:w00t:
Title: Re: Perfect Grayscale - Tutorial
Post by: DJ Omnimaga on March 08, 2011, 12:02:37 am
Nice tutorial. I think I'll move this to the ASM help sub-forum, though, since it's ASM-related. Hopefully it should be helpful for grayscale game programmers. I myself unfortunately didn't mess with grayscale much, as I mostly did TI-BASIC and never went far with Axe. The only grayscale games I made are Reuben Quest series and the RickRoll Tunnels. :P
Title: Re: Perfect Grayscale - Tutorial
Post by: thepenguin77 on March 08, 2011, 05:36:39 pm
Nice tutorial. I think I'll move this to the ASM help sub-forum, though, since it's ASM-related. Hopefully it should be helpful for grayscale game programmers. I myself unfortunately didn't mess with grayscale much, as I mostly did TI-BASIC and never went far with Axe. The only grayscale games I made are Reuben Quest series and the RickRoll Tunnels. :P

Ok, I put it in the Other calculator discussion and news because I thought it might also be useful for Axe. But I don't really know enough about Axe to implement this.
Title: Re: Perfect Grayscale - Tutorial
Post by: yunhua98 on March 08, 2011, 05:38:46 pm
I guess Quigibo could Update his greyscale routine, but unless we use Hex, theres really no way Axe could change its greyscale...

speaking of which, you should learn Axe, thepenguin, you'd release games way faster that way.  ;)
IMO, games don't take as long to make in Axe.  but thats just me.  :P
Title: Re: Perfect Grayscale - Tutorial
Post by: thepenguin77 on March 08, 2011, 06:24:01 pm
I'm a die hard asm programmer. I don't plan to ever learn Axe. I like to do things my own way without relying on other people, which is where some of my programs came from. (Chess, tetrisM, StpWatch, 8 lvl gray, BluTooth usb driver, truSound, I even use my own flash unlocking code.)

I've also just begun to think in asm. I often get annoyed at C++ when I want to treat unsigned chars as chars and such. I like to work without rules where you can do whatever you want. In asm, nothing is restricting you. Everything is based in asm, so everything that can ever be done, is possible.

Asm can also be faster than axe if you want, I can write lightning fast routines if need be. The control over hardware is also very important for me; if I used axe, you would never see this kind of grayscale. I would have also never put any work into usb work or OS mods because they are out of sight and out of mind.

Lastly, Axe is written on the calculator and is an artificial language. The on-calc part means that the files are likely to get erased and it is very hard to work on large projects. I like to have all my files on my computer where they are relatively safe. Also, editing stuff on the calculator limits your view of the code and doesn't let you get a real feel for what is going on. And since Axe gets compiled, it is much harder to debug if things go wrong, whereas with asm wabbitemu looks exactly the same as notepad.

As far as speed goes, I've gotten to the point that asm doesn't slow me down that much. The first night I started working on chess, I put out 1000 lines of code in about 4 hours. While yes, axe would be fewer lines, asm gives me more flexibility in the fine tuning stuff.


Wow, I've never actually put that all into words. It feels good to actually say it though. And sorry if I offend anyone who likes axe, axe is great, it's given power to the people, I just prefer asm.
Title: Re: Perfect Grayscale - Tutorial
Post by: DJ Omnimaga on March 08, 2011, 06:39:29 pm
Yeah I agree with Thepenguin. I personally prefer higher level languages, but if someone is pretty good at ASM and likes its freedom, it's gonna be hard to go back to higher level languages afterward.
Title: Re: Perfect Grayscale - Tutorial
Post by: coolrudski on March 08, 2011, 06:45:26 pm
well with programming its either you have quicker programs but longer code or slower but easier to code programs but slower (little ironic in a way huh?). but i mean assembly definitely gives you more flexibility and if you are good with it and almost productive as a person in say c good for you! i on the other hand have to program in c i dabble in assembly but i dont have the patience. so i respect that and that sort of work and dedication.
Title: Re: Perfect Grayscale - Tutorial
Post by: DJ Omnimaga on March 08, 2011, 06:47:14 pm
Yeah in TI-BASIC you got slower code, but for new programmers it's easier to get used to and you can do some stuff easier like using floating points. Same goes with ASM libs, but I think xLIB syntax is hard to memorize, so on the spriting side I find Axe easier to use (although tilemaps can be harder in some cases)
Title: Re: Perfect Grayscale - Tutorial
Post by: TIfanx1999 on March 09, 2011, 06:30:52 am
Cool tutorial. That's also a good explanation of your language of choice. =)
Title: Re: Perfect Grayscale - Tutorial
Post by: calcdude84se on March 09, 2011, 07:53:46 am
Nice explanation :D At some point I'll have to implement that.
Title: Re: Perfect Grayscale - Tutorial
Post by: JustCause on March 09, 2011, 09:55:45 am
Very nice. I did figure out how to do this in Axe, but never really understood the technical aspect. Now it makes a lot more sense. Thanks!
Title: Re: Perfect Grayscale - Tutorial
Post by: Deep Toaster on March 09, 2011, 06:30:08 pm
Wow, I've never actually put that all into words. It feels good to actually say it though. And sorry if I offend anyone who likes axe, axe is great, it's given power to the people, I just prefer asm.

I agree. All languages have their good points and bad, and just because someone likes one language doesn't mean it's the one for everyone else. And different languages suit different situations: BASIC is slow, but it's great (nice and small and compatible) for less intensive programs; Axe is fast and really easy to use, but it has its own problems, like with all languages; and ASM is ... well, once you get it it just feels good to program in, partly because you know it's your own code that you made yourself. Plus it lets you have complete control of everything, and power is nice >:D

IMO the best language to use is just the one you're comfortable with that works best in that particular situation :)

Anyway, this is a great tutorial! We seem to be lacking in advanced ASM tutorials that go beyond the stuff in 28 Days.
Title: Re: Perfect Grayscale - Tutorial
Post by: willrandship on March 09, 2011, 07:02:31 pm
In that case, nspire needs python :P
Title: Re: Perfect Grayscale - Tutorial
Post by: DJ Omnimaga on March 10, 2011, 06:19:38 pm
Yeah a tutorial about advanced tricks would be nice. :D
Title: Re: Perfect Grayscale - Tutorial
Post by: AngelFish on March 10, 2011, 07:38:34 pm
well with programming its either you have quicker programs but longer code or slower but easier to code programs but slower (little ironic in a way huh?). but i mean assembly definitely gives you more flexibility and if you are good with it and almost productive as a person in say c good for you! i on the other hand have to program in c i dabble in assembly but i dont have the patience. so i respect that and that sort of work and dedication.

Generally speaking. Of course, some people (like me) are freaks of nature and can't understand high level computer languages like C.* I'm not nearly as fast as thePenguin at ASM though. I don't think I've ever written 1000 lines in four hours in any language.

I've actually had to slow down more programs than I've had to speed up, though. Not sure if too many languages other than Hex and ASM have the problem :p
Title: Re: Perfect Grayscale - Tutorial
Post by: DJ Omnimaga on March 11, 2011, 02:55:43 am
Lol yeah in Axe sometimes I felt the stuff I tried just ran way too fast for my needs. I worried that if I ever made a RPG that it would be filled with pauses. X.x
Title: Re: Perfect Grayscale - Tutorial
Post by: ztrumpet on March 13, 2011, 12:09:15 pm
I don't think I've ever written 1000 lines in four hours in any language.
I think I've only ever wrote more than 1000 lines of code once, on Exodus (and to get that I had to add the lines of Exodus with the lines from its level editor).   ::)

I never had the time to read this until now, but it's an incredible tutorial.  Thanks, Brian! ;D
Title: Re: Perfect Grayscale - Tutorial
Post by: Deep Toaster on March 13, 2011, 12:19:39 pm
I don't think I've ever written 1000 lines in four hours in any language.
I think I've only ever wrote more than 1000 lines of code once, on Exodus (and to get that I had to add the lines of Exodus with the lines from its level editor).   ::)

Back when I had time to kill I made >2000-line programs in a single sitting, deleted them immediately, and recoded them again. If only I had that kind of time right now :P
Title: Re: Perfect Grayscale - Tutorial
Post by: ZippyDee on March 24, 2011, 07:27:29 am
I don't think I've ever written 1000 lines in four hours in any language.
I think I've only ever wrote more than 1000 lines of code once, on Exodus (and to get that I had to add the lines of Exodus with the lines from its level editor).   ::)

Back when I had time to kill I made >2000-line programs in a single sitting, deleted them immediately, and recoded them again. If only I had that kind of time right now :P

....................That's just insane. I have a BASIC program I wrote a few years ago that's 5k+ bytes, but I'm not sure how many lines. It was a calculator version of the game Sim Cinema, a surprisingly awesome game that only ever came out for Mac...even worse, for OS9X so the newer Macs can't even run it :\
Title: Re: Perfect Grayscale - Tutorial
Post by: ralphdspam on May 17, 2011, 10:42:58 pm
Can someone help me port this to an Axiom?  When I added a couple of commands, it started displaying glitch lines.  

I think it is because the index registers take too many clock cycles.  :\
Code: [Select]
intReturn:
ex af, af'
exx
ei
ret
initInterrupt: ;double label just for good measure

goodInterrupt:
ld a, $40
out ($30), a ;10922 Hz
ld a, 2
out ($31), a
ld a, 178 ;<- this is the number you change for delay
out ($32), a

ld hl, plotsscreen ;use axe buffers
ld ix, appbackupscreen ;\
call grayCopy
jr intReturn



;###################################
grayCopy:
DWAIT
ld a, 7
out ($10), a ;row major


ld a, (grayCarry)
rra
ld a, (grayMask) ;9 bit cycle
push af

ld e, $80
outerGray:
DWAIT
ld a, $20 ;always start on left
out ($10), a

DWAIT
ld a, e
cp $C0 ;quit at row 64
jr nz, notDoneYet

pop af
ld (grayMask), a
ld a, 0
rla
ld (grayCarry), a
DWAIT
ld a, 5 ;back to column major for
out ($10), a ;good measure
ret
notDoneYet:
out ($10), a

ld b, 12

grayLoop:
pop af
rra
push af
ld d, a
and (hl) ;get dark byte
ld c, a
inc hl
ld a, d
cpl
and (ix) ;get light byte
inc ix  ;;=========When I changed this, it started glitching up.
;and (hl)
;inc hl

or c

ld c, a
DWAIT
ld a, c
out ($11), a
djnz grayLoop

pop af
rla
push af

inc e
jr outerGray



grayCarry:
.db 1
grayMask: ;9 bit cycle
.db %01101101
Title: Re: Perfect Grayscale - Tutorial
Post by: Hot_Dog on August 29, 2011, 10:05:28 pm
This is an excellent tutorial, and it certainly helped me make MY grayscale flickerless :D
Title: Re: Perfect Grayscale - Tutorial
Post by: Spenceboy98 on March 19, 2012, 08:32:23 pm
Okay, so this makes grayscale flickerless? I don't know how to use this tutorial. How?
Title: Re: Perfect Grayscale - Tutorial
Post by: Darl181 on March 19, 2012, 08:43:56 pm
This is for Asm coders, and would be next to impossible to implement properly with Axe, even as an axiom.

Tho afaict the general theory is this:
Basically to get rid of the flickering you write to the screen (in Axe that's what DispGraph does) at the same rate that the physical screen displays what's written to it.  It's around 60 times a second, but it varies from calc to calc.
You can kind of do this in Axe by putting a Pause 40 or something like that if there's nothing else but DispGraph^* in the loop, but don't expect it to be perfect ;)
Title: Re: Perfect Grayscale - Tutorial
Post by: leafy on March 19, 2012, 09:24:45 pm
I found that using Pause 9 for 4-shade works well when your game is speedy.
Title: Re: Perfect Grayscale - Tutorial
Post by: parserp on March 20, 2012, 05:30:40 pm
How would I use interrupts to make greyscale more flickerless in Axe?
Title: Re: Perfect Grayscale - Tutorial
Post by: NanoWar on March 24, 2012, 11:17:52 am
What needs to be changed that it works on a TI83Plus? There's no fast mode and I'm not sure about the $83 ram page, could you explain that?
Title: Re: Perfect Grayscale - Tutorial
Post by: Eiyeron on March 24, 2012, 12:26:23 pm
What does Dispgraph^*
Title: Re: Perfect Grayscale - Tutorial
Post by: Xeda112358 on March 24, 2012, 01:46:55 pm
What needs to be changed that it works on a TI83Plus? There's no fast mode and I'm not sure about the $83 ram page, could you explain that?
Yeah, I am still not sure why page 83 is needed (which isn't available on the 83+).
Title: Re: Perfect Grayscale - Tutorial
Post by: thepenguin77 on March 24, 2012, 08:47:17 pm
What needs to be changed that it works on a TI83Plus? There's no fast mode and I'm not sure about the $83 ram page, could you explain that?

You'll have a great deal of trouble get perfect grayscale on an 83+BE in the true sense with this method because there are several things at work against you.
1. Without fast mode, you're going to have to make a very optimized routine, this is totally possible
2. You don't need the extra ram page, it just makes things much cleaner for my grayscale routine. Writing your own routine would allow you to use whatever ram you want, (probably two $300 byte buffers) but if you insist on using mine, you can clear out the first $600 bytes of ram through some hackery (though, TI-OS won't work in this state.)
3. Finally, probably the one that really strikes down this method, is the fact that the 83+ does not have crystal timers. The best you could do on it (if you plan to do things besides display pictures) is to use the regular interrupts which default run at 118Hz. For very specific cases, you could use every other interrupt for grayscale, but this will only work at a screen refresh of exactly 59Hz. Most likely, you're going to want to go with the interrupts running at 560Hz. Using this method, you'd have to use variable skips and delays to ensure the grayscale draws occur at the proper time. This is possible with enough thought, but it would be very difficult.
(4). Combining problems 1 and 3, anything that runs with perfect grayscale is going to run very slow. The step 3 delay design is going to burn a lot of t-states waiting for the proper time to go. Then, since it's only running in 6Mhz mode, you can get way less done when the actual program is running.

So, verdict. Possible - in theory. Difficulty - high. To give you an idea, this ranks up there with calc84's sound routines in ti-boy.
Title: Re: Perfect Grayscale - Tutorial
Post by: Darl181 on March 24, 2012, 10:40:27 pm
What does Dispgraph^*
It's a random shorthand for DispGraph^[whatever].  So, either Dispgraphr (DispGraph^r) or DispGraphrr .
Just made it up off the top of my head, there's prolly some better way :P