Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Runer112

Pages: 1 ... 7 8 [9] 10 11 ... 153
121
ASM / Re: School of Grayscale
« on: August 24, 2015, 04:59:42 pm »
Grayscale 201

Prerequisites: Grayscale 101, z80 Assembly 101

Before we move on to implementation specifics, there's one more global grayscale quality improvement that you should be aware of. It turns out that the LCD's update direction is left-to-right followed by top-to-bottom, and artifacts appear when your LCD update routine's write position intersects with the LCD's update position. So, to minimize artifacts, your LCD update routine should also go left-to-right followed by top-to-bottom. This unfortunately means more LCD port writes to move the write position around, but unless you're desparate to squeeze out more speed, it's still recommended.

Now that that's out of the way, let's talk more about how to actually implement grayscale in a program. I have identified three important pieces:
  • Image representation/drawing
  • Update routine
  • Update timing

Image representation/drawing

To actually represent grayscale imagery, you're going to need more than 1bpp (bit per pixel). To be precise, you'll need ?log2(shades)?bpp. That comes out to 2bpp for 3- to 4-level grayscale, 3bpp for 5- to 8-level grayscale, 4bpp for 9- to 16-level grayscale, etc. There are two common approaches to storing grayscale image buffers: as separate 1bpp buffers or as one byte-interleaved buffer. The former has the advantages that monochrome drawing routines can be simply be used on each buffer instead of needing dedicated grayscale drawing routines and that the buffers don't need to occupy a contiguous section of memory. The latter has the advantage that routines designed for it, whether drawing or LCD update, are generally faster. But since the way in which you represent grayscale imagery isn't actually integral to how it's displayed on the LCD, we'll end this piece here.

Update routine

The update routine is almost certainly the hardest piece to create, especially at higher levels of grayscale. Specifically, dithering is what makes it hard. A good dithering pattern of course needs to be good at temporal dithering, so each pixel is black/white for the correct percentage of updates. But perhaps harder, especially in combination with the former, is that it should also be good at spatial dithering, so each individual update most accurately approximates the grayscale image.

For 3- and 4-level grayscale, the optimal dithering patterns are rather trivially obvious. Assuming an interleaved buffer pointer in hl with MSB bytes coming immediately after LSB bytes, the inner loop to display dithered 3-level grayscale should look something like the following:

Code: [Select]
loop:
loop:
        rrc     c               ; rotate mask with pattern %10101010
        ld      a,(hl)          ; read a byte of LSB's
        inc     hl
        and     c               ; select half of them
        or      (hl)            ; read a byte of MSB's; set bit -> black
        inc     hl
        out     ($11),a         ; output the dithered byte
        djnz    loop

And, for 4-level grayscale should look something like the following:

Code: [Select]
loop:
        rr      c               ; rotate mask with pattern %100100100
        push    af
        ld      a,(hl)          ; read a byte of LSB's
        inc     hl
        xor     (hl)            ; mux byte of LSB's with byte of MSB's
        and     c
        xor     (hl)
        inc     hl
        out     ($11),a         ; output the dithered byte
        pop     af
        djnz    loop

But past that, the visually best dithering patterns aren't so obvious, and neither are the ways to generate them efficiently in code. Perhaps the best attempt to go further beyond is by the same man who helped out in Grayscale 101. thepenguin77's allGray is an open source demo program that showcases all levels of grayscale from the ultra trivial of 1 up to the far less trivial 8. There are also some somewhat hidden works by tr1p1ea, which simulate 7-, 8-, and [url=http://tr1p1ea.net/files/downloads/ANLVL.8XP]9-level grayscale, but they're unfortunately compiled code only. I defer to both of these individual's work on this matter because they have put in more work into actual implementation, while I've worked more on theory. Speaking of which, I theorycrafted up this chart of what seemed to me to be the best dithering patterns for all levels of grayscale from 1 to 8.


I could certainly believe that there are better patterns. For a number of levels, I provided multiple options becuase I'm not sure which is better visually and/or implementation-wise. In particular, the asterisk in the black color for 7-level grayscale indicates that I don't even think the masking logic for the previous shades works out to produce black. I would wholeheartedly welcome feedback on these!

As an interesting side note, when putting in the actual grays next to the dithered grays for comparison, I noticed that a dither pattern in which x percent of pixels are black does not actually produce x% gray. Upon researching this and other topics, I stumbled across this dithering article, in which appendix 1 is espeically of interest. It corroborates this finding and, furthermore, suggests a formula for how to calculate between the two figures. Combined with some individual's past perceptions that grayscale on a physical calculator does not evenly distribute the shades of gray, this is a topic that I believe requires more research. If one wanted more shade-accurate 4-level grayscale, for instance, perhaps that could be better achieved by selectively using 2 shades of gray from a higher level of grayscale.

Update timing

This topic was pretty well covered in thepenguin77's perfect grayscale tutorial, but I'll repeat the important results. You'll want the grayscale update frequency to be tunable by the user, but it should be roughly around 60Hz. A good way to achieve a roughly 60Hz timer is with the crystal timers on the 83+SE/84+(SE). Write 03h to a timer's loop control port, write 40h to a timer's on/off port for the best base frequency of 10922.667Hz, and write the counter value (start with a value of around 182) to the timer's counter port. Each interrupt, make sure to rewrite 03h to a timer's loop control port! For a sample interrupt handler installer, consider checking out this WikiTI page, although make sure to use the crystal timer as an interrupt source instead of the hardware timer!

122
ASM / Re: School of Grayscale
« on: August 24, 2015, 04:59:36 pm »
Grayscale 101

Disclaimer: The update artifacts depicted on my emulator may be fairly different from those on a real calculator, but the concepts of what causes them and how to correct them are roughly the same.

As previously mentioned, grayscale can be simulated on a monochrome screen by rapidly flashing pixels between black and white to simulate a shade of gray. But that's a terribly vague description, and not at all one that you could devise any reasonable grayscale display algorithm from. So let's go into more detail about what makes up an average grayscale display algorithm. For simplicity's sake, we'll consider the simplest depth of grayscale: 3-level grayscale. That means there are only 3 shades available: white, gray (50%), and black.

Obviously, to display a white or black pixel, you simply... display a white or black pixel. So let's focus on the interesting part: gray. As the "gray (50%)" name may suggest, this shade should be 50% black and 50% white. But since you can't actually make a pixel 50% black and 50% white at the same time, let's make it 50% black and 50% white over a period of time. The simplest way to do this is to make a pixel black for one unit of time, then white for one unit of time, and repeat.

But what's a good unit of time? Let's see what happens if we alternate the whole screen between black and white for different units of time.

Spoiler For Strobing gray:
2Hz
4Hz
8Hz
16Hz
32Hz
64Hz

So it started off pretty blatantly altering between black and white, but eventually got up to looking like a somewhat flickery gray that's got strange artifacts in it. For now, let's see what we can do to improve the gray quality across any frequency. And it turns out there's a pretty good method: combining flashing pixels on and off, which one could call dithering in time, with the much more traditional dithering in space. That way, each individual frame should look a lot more like gray and should hopefully help to fool our eyes/the LCD. So let's see what these look like using a checkerboard pixel pattern, alternating which pixels are black and white each frame.

Spoiler For Strobing gray (dithered):
2Hz
4Hz
8Hz
16Hz
32Hz
64Hz

That's definitely a lot better, isn't it! It seems like anything in the range of 32-64Hz would probably be acceptable, and that's about as far as widely used grayscale methods got. But if you look really closely at the 32Hz and 64Hz images and compare them to their non dithered counterparts, you can see that the artifacts scroll across the screen in approximately the same shape. These artifacts are the result of the pixels in the range being black and white for an uneven amount of time. If you want a really good explanation of what's going on here, which is where I learned it, check out thepenguin77's perfect grayscale tutorial. But the gist of it is that the LCD has a constant update frequency, roughly 60Hz, and if you send frames at any frequency that doesn't evenly divide this, the pixels in each frame you send won't appear on the LCD for the same amount of time. And which pixels experience this effect and to what degree depends on where they are in the frame and the order in which the LCD updates its pixels.

So the solution to these artifacts is to match your update frequency to the LCD's update frequency. Which it turns out is impossible to do perfectly, unfortunately, because the LCD update frequency isn't exposed as a signal anywhere that can be synchronized with. But the next best thing is to start with a frequency of around 60Hz and let the user slightly adjust the frequency up or down manually, where getting closer to the LCD's update frequency should noticeably reduce the level of artifacting. When that's all said and done, you'll hopefully get (nearly) perfect grayscale!


I promise it's not just a still image.

123
ASM / Re: School of Grayscale
« on: August 24, 2015, 04:59:30 pm »
History of Grayscale

Since the dawn of a long time ago, man has tried to use technology to make cool stuff. In the TI graphing calculator programming community, that often means making games to play in math class (note: not actually recommended to do this!). For instance, let's briefly look at the top 83+/84+ programs from 2004, as rated by ticalc.org's 2004 POTY (program of the year).

First place went to Acelgoyobis, the first (and as far as I know, the only good) pinball game created for the platform. The reviews rave about the crispness and fluidity of the graphics and spectacular physics, making it feel very nearly like a real pinball table, minus the quarters.


Acelgoyobis

Looking at the graphics, they do indeed look quite crisp. But it's clear that sacrifices had to be made to work with the very limited graphical hardware of the calculator: a monochrome 96x64 screen. The lack of any shades other than black or white and the tiny resolution are quite restrictive. But what if these restrictions could be lifted, at least partially?

The resolution restriction is pretty hard and fast. But the fourth place program from the previous year's POTY push backs against the color restriction. The highest-placing non-game, the Grayscale Programming Package provides code to simulate four-level grayscale with the monochrome screen by rapidly flashing pixels between black and white to simulate a shade of gray. ticalc.org's news article states that "the demos cast aside any flickers of doubt regarding the viability of grayscale on the 83+." But do they, really?

Returning back to the 2004 POTY, second place went to Desolate, an adventure RPG with a great story and, largely thanks in part to the Grayscale Programming Package, revolutionary graphics for the platform.


Desolate

Looks quite flickerless!... But this was recorded using an emulator, and while an emulator can easily accurately emulate a digital process, it's much harder to accurately emulate a physical process like LCD updates, which rely on the action of the liquid crystal molecules that liquid crystal displays depend on. And in this case, the emulator is pretty far off from the real result. Here's a sample of what the game looks like when run on a much newer and more accurate (but still not perfect) emulator.


A more accurate emulation of Desolate

The next novel development to show up in a popular game showed up in Chip's Challenge, a recreation of a classic puzzle game and the second place winner of the 2009 POTY. The Grayscale Programming Package and all the games that used it dobuled the amount of available shades, from 2 to 4. So... let's double it again, to 8!


A reasonably accurate emulation of Chip's Challenge

Once again, a rolling flickering effect is visible. It turns out there are a number of obstacles in the way of fighting this flickering effect and achieving flickerless grayscale, and it has taken many years since the appearance of the first popular grayscale package/games to finally start ironing them out. I would like to take all of the currently available knowledge, and some of my own developments, to fully establish the extent to which these obstacles can be overcome.

124
ASM / School of Grayscale
« on: August 24, 2015, 04:59:21 pm »
Reserved for future use.

125
OmnomIRC Development / Color code bug
« on: August 23, 2015, 01:58:02 pm »
It seems that some recent change has introduced a bug in color code parsing. It appears that using a color code immediately followed by another color/formatting code results in the color code's number being printed instead of being used as a color.

For example: "{color}7{bold}test" appears as "7test" instead of the correct "test". This bug can also be noticed in most of RunerBot's output, which is where it was noticed.

In case it's a browser-specific issue, I see the issue on Chrome 44.

126
As Art_of_Camelot said, that's simply what happens when you try to downscale a 160x144 image to a 96x64 screen, especially with very little processing power available.

For reference, I personally prefer playing on the CSE just because of the much better graphics. The speed is definitely worse, but you can somewhat make up for it in games where framerate isn't very important (like Pokemon) by setting a high frameskip value (settable from 0-9 with the 0-9 buttons). I often use 7 or 8. And make sure to experiment with the two "zoom" modes on the CSE as well. One does no upscaling and is faster, but may be a bit of a strain on the eyes.

127
Axe / Re: Windows XP in Axe
« on: August 13, 2015, 04:16:07 pm »
That's because Axe's order of operations is simply left-to-right. So that's being evaluated like (getKey(15) and Y)≠1. Try adding parentheses, like getKey(15) and (Y≠1), or switching the order, like Y≠1 and getKey(15).

128
TI Z80 / Re: Really fast 9-level grayscale
« on: August 03, 2015, 05:33:30 pm »
A screenshot would be nice. In all cases I've seen, the higher number of shades you go the less difference there are between them. Ie, the darkes shades tend to look too similar to one another as do the light ones. I think about 6 shades seem to be the most discernible.

I don't trust emulators to accurately reproduce 3- or 4-level grayscale, let alone 9-level grayscale. A picture/video of a physical device would probably be more accurate. But I'm not sure even that would be totally accurate, because cameras often have their own time-blending that's different than the human eye.

I guess that just means we need to try it for ourselves!

129
Gaming Discussion / Re: SGDQ 2015
« on: July 28, 2015, 09:57:46 pm »
Speedruns abuse tons of glitches to skip parts of the game to get the ludicrous times. When showing off speedruns, though, runners have to consider the speed/entertainment tradeoff. So I'm hopeful that whatever glitches used don't make the run too trivial and boring. I'm fairly certain there are some out of bounds glitches that could be used to complete Oblivion in around 10 minutes, but such glitches have been disallowed to hopefully result in a more entertaining run, estimated to take 55 minutes.

130
Gaming Discussion / SGDQ 2015
« on: July 28, 2015, 09:41:14 pm »
For those of you who may not know, SGDQ (Summer Games Done Quick) is a big annual speedrunning event. It started on Sunday and will be running through the rest of the week. The best speedrunners from around the world come together to show off their 1337 skillz. If you like games at all, or even if you don't, I'd highly recommend you check it out. And it's also a charity event, so consider donating!

So, which runs have you watched so far? How awesome were they? Which runs are you planning on watching and would recommend others watch?

I've looked at their schedule and already picked out the runs I really want to see. They're mostly games I've played, really enjoyed, and feel I'd most appreciate and understand seeing be brutalized. And then there's the TASBot block, none of the games in which I've played, but TASes are usually awesome to watch, especially when commentated.
  • The Legend of Zelda: Twilight Princess (completed)
  • Halo 3
  • The Legend of Zelda: Ocarina of Time
  • Fallout 3
  • Elder Scrolls IV: Oblivion
  • Super Mario: Sunshine
  • TASBot plays Mega Man
  • TASBot plays Sonic Advance
  • TASBot plays Ikaruga
  • Super Mario 64

If anyone is interested in watching the stream with a much less crazy chat, and possibly with others from the community (like me!), I'll be hosting the stream on my twitch channel.

By the way, if you're picking games out of the schedule that you want to watch ahead of time, be warned that blocks often run long and push the whole schedule back a bit over time. So make sure to check back with the schedule when the block you want to see is closer to get a better estimate of when it will begin.

131
Gaming Discussion / Re: Hearthstone
« on: July 18, 2015, 11:46:31 pm »
Yes, it's an online card game, made by Blizzard. I hesitate to call it a trading card game, though, because you can't actually trade cards.

At it's core, it's kind of a simplified (I'd argue in a good way) version of MTG. I've never played MTG, but I played Yu-Gi-Oh (not at any serious level) for years, and I find the rules and cards of Hearthstone make it a better game. It also helps that you always have someone to play against, and that you can opt out of the pay to win model by completing daily quests and/or doing well in the arena (randomized draft). It certainly takes a long time to collect a good enough base of cards to do well in constructed games if you don't buy packs with real money, but it's satisfying.

132
Gaming Discussion / Hearthstone
« on: July 18, 2015, 06:45:29 pm »
Do you play it? Do you want to connect with others here who play it? Do you think it sucks? Talk about it here!

I've played it for on and off for about a year now. I can't quite remember, but I've either never spent a dime of real money on it or I spent like $5 once for some limited-time thing, so I'm fairly happy that I haven't fallen into the pay-to-win trap. I mainly play to complete daily quests and arenas, the gold from which fund packs or adventures. Between playing and watching lots of Hearthstone videos (mainly Trump), I think I'm actually pretty good now; top 25%, anyways.

Anyone want to let me spectate them to knock out the quest for a free pack? :) I've never been able to complete this because my friends list is very lonely... Would also be nice to have someone to chat or play casually with once in a while. My tag is Runer112#1930.

133
The Axe Parser Project / Re: Features Wishlist
« on: July 07, 2015, 06:31:46 pm »
It's impossible to safely return by multiple levels at once because anything can be on the stack, not just return pointers. So the nth return pointer could be n stack entries deep, n+1 stack entries deep, or n+100 stack entries deep. It's also just pretty gross from a language design standpoint.

In cases like this, I think you should consider using return codes as signals, or a code reorganization to avoid the "need" for multi-level returns in the first place.

134
The Axe Parser Project / Re: Axe Parser
« on: July 07, 2015, 11:56:11 am »
hello, i tried axe 1.3.0 and the speed is amazing, no bugs, great job !

Thanks for testing it out! Looks like "no bugs" isn't exactly true, though. :P

The only thing is that the auto backup doesn't work (it can be on or off, it doesn't change anything).

I rewrote how backup stuff is handled, so that's certainly a possibility. I should be able to fix that easily enough.

I saw that you've done an update on July 1 so I used it to compile my tunnel game but I have something very weird: the programs compiled with axe 1.2.2 or axe 1.3.0 (first version) is 6877 bytes tall but the program compiled with axe 1.3.0 (2nd version) is only 6670 bytes, the source code is the same on each time with 5409 bytes.
And the result is bugged but it doesn't crash.
I don't know at all what happened but I hope you can fix it.

I'm not sure what could be causing this. Could you provide the source program so I can debug what goes wrong during compilation? If you're not comfortable posting it publicly, you can send it to me using the site's messaging system, or via email to the address on my profile page. The latter may be easier as it would allow attaching the source program directly.

135
The Axe Parser Project / Re: Features Wishlist
« on: July 01, 2015, 12:40:38 pm »
Types are definitely something I want eventually, but I think it's going to have to be an Axe 2.0 thing. Even if I could flag variables as different types in the compiler, values being 16 bits large and stored in the hl register is ingrained throughout the compiler.

Pages: 1 ... 7 8 [9] 10 11 ... 153