Part of an update series on FFcrt. See also:
Yes: if emulating CRT monitors the slow way wasn't your thing, now you can sluggishly simulate various types of old flat-panel displays, too! All with the same FFmpeg script - which is still named FFcrt, in the grand old tradition of expanding a project's scope so that its name no longer reflects what it does! Makes it feel all mature and stuff.
But first, a bit about some other changes that have made it into the script:
Aspect correction is now entirely unrelated to input pre-scaling. Previously, both were taken care of in one nearest-neighbor scaling stage. If you were going for a pixel aspect of say 5/6, your input scaling factors had to be multiples of that - X*5 and Y*6, or X*10 and Y*12, and so on. Problem is, as the factors get larger, the "so on" part starts chewing up RAM like candy.
Now there's just a single PRESCALE_BY factor (which controls nearest-neighbor scaling of both X and Y), and a separate PX_ASPECT setting which is applied afterwards to X alone, using bilinear filtering. A little slower, but more flexible and easier on your RAM; also, nothing's stopping you now from having pixel aspects like 117/125 (PAL Commodore 64), or some other such atrocity. Rejoice!
Aliasing artifacts should now be history, after a couple of tweaks to the lenscorrection filter usage. Curved bezel edges don't get the jaggies anymore, and scanline-induced moiré patterns are also gone (for any sane resolution, at least). The boring details mean that the curvature steps will have to stay separate, against my earlier hope of unifying them for the sake of efficiency, but we'll live with that.
Also, the console output isn't a huge mess anymore, and there are a couple of other minor changes that do improve efficiency. But you can look those up in the commit log, so let's get to the point.
Flat-Panel Display Options
There are some fresh new parameters in the sample .cfg presets: additional options for MONITOR_COLOR, and a new section for "NON-CRT/
This lets FFcrt mimic three major types of flat panels, as common in older portable PCs - monochrome/grayscale LCDs (of various types and forergound/
As you might expect, the general type is determined by what you set as the MONITOR_COLOR, which now accepts these values in addition to the old ones:
PLASMA: emulates the type of orange flat panels using neon plasma cells, as seen in portables like the later Toshiba T-series (T3100, T3200, T5100...), the Compaq Portable III and 386, and the IBM PS/2 models P70/
P75. The original plasma displays dating back to PLATO terminals were 1-bit, but by the time they started cropping up in portables, they generally sported multiple shades (brightness levels) of orange.
ELD: electroluminescent displays (as opposed to LCD displays that simply used electroluminescent backlighting). These uses phosphors for light emission, but unlike CRTs the phosphor resides in a thin layer between two electrodes in a matrix, and its electrons are directly manipulated by high-voltage AC power. Most commonly yellow (AKA "golden") and strictly 1-bit; seen e.g. in some GRiD Compass and GRiDCASE models, later Data General/One laptops, and a few other portables.
LCD: cheaper and much more common, at the cost of contrast, viewing angle and pixel response time (latency). This option aims to reproduce the baseline variety, a twisted-nematic (later Supertwist) monochrome LCD with a bluish-gray foreground color, a pale green background and no backlight.
LCD-LITE: similar to the above, but with a brighter green backround for extra range and contrast. Can be used to simulate backlit versions of the more common monochrome LCD panels.
LCD-LWHITE: this one simulates later monochrome LCD panels with a grayish foreground and a white backlight, typically with better contrast; very common in later laptops before color LCD panels started becoming a thing.
LCD-LBLUE: less commonly, some backlit LCD panels had a vivid blue tint to their activated pixels. As seen in the final revision of the IBM PC Convertible (5140), but also the Compaq LTE and LTE/286, the NEC Ultralite, and probably a few others.
That doesn't really cover everything: early flat panels (especially LCDs) came in a big and confusing bunch of colors and lighting technologies, as you can see in the adjoining PC Magazine comparison. To vary the contrast range (and sometimes the hue, a little bit) you can play with the BRIGHTEN and BLACKPOINT configuration parameters.
Sizes and aspect ratios were similarly all over the place, and that's where you can play with PX_ASPECT (the pixel aspect ratio) and OASPECT (the output, AKA display aspect ratio) to achieve just about any of them. The emulated storage aspect ratio (SAR) is already determined by the resolution of the input.
Given the nature of these early LCDs, "on" pixels were dark and "off" pixels allowed light through, so the image was typically the inverse of what a CRT, plasma or ELD display would show. A lot of laptop LCDs did let you flip the signal and get light-on-dark instead, so FFcrt lets you do both, with the INVERT_INPUT parameter. Of course, these things wouldn't be the same without pixel response times that bordered on the criminal, and that's what the LATENCY option is for.
There's just one more thing to tackle: as mentioned, some of these flat-panel displays were strictly 1-bit - pixels were either on or off, without such decadent luxuries as true greyscale shading. That goes for ELDs (probably all of them) and a lot of early LCD panels. But as simulated in the images/video above, many of them could still fake it well enough, and I've added an quick-n'-dirty extra tool for that.
Simulated Grayscale "Shading" on 1-Bit Monochrome Displays
Sim-rgbi1bpp (yet another batch file in the FFcrt repository) approximates the methods used by certain display controllers to show RGBI video (AKA the 16 IBM PC colors) on true monochrome displays. It's intended to process your input before you feed it to FFcrt; use it only if you really want to simulate such a setup - for true grayscale, this is not needed.
These hardware solutions typically replaced each RGBI color with a modulated dot-pattern, either static ("bit-dithered") or dynamic (cycling across frames, a sort of refresh rate-limited PWM). Obviously, this is very different from what you get with dither algorithms intended for image processing, so this script twists FFmpeg's arm a little bit and uses brute-force (read: slow) color replacement to implement this.
Such trickery often relied on the fact that the target display had (at least) twice the resolution of the video mode in question, so 200-scanline modes were doubled to 400. If required, sim-rgbi1bpp will likewise upscale the input before it applies the effect.
You can see the readme for usage directions, but while we're here, it might be helpful to show some examples. First we have the static methods, which can be used for still images as well as video:
"4x1a" is the simplest method, which basically interprets CGA mode 4 as if it were mode 6 (640x200 mono); this is similar to running SIMCGA on a Hercules Graphics Card, and I believe this is what the IBM 5140 does. The HP 100/200LX palmtops use similar methods: "4x1a" also corresponds to HP's shading mode 00b (bit-dithered), and "4x1b" to shading mode 11b. The other methods above are basically made up, but the principle is similar.
The 't' methods add a temporal component, by modulating the bit-patterns on successive frames. That means they're video-only, and won't work with still images:
Of course, these methods introduces massive flicker; but in the real world, this approach was mostly used on monochrome LCD panels, with enough pixel latency to make it less of a problem. For instance, frame-based shading mode 11b on the HP 100/200LX is pretty much the same as "t4x1". When feeding the results to FFcrt, use the LATENCY parameter to mimic that - this is what I did in the video.
As a counter-example, the GRiDCASE 1537's electroluminescent display had no such mitigating factors (video sample) - the flicker there actually looks much worse than any of the above methods, but that might just be a frame-rate mismatch in that particular video.
Anyway, none of these methods duplicate the exact implementation used by a specific type of video hardware, just the general principle. The HP 100/200LX is the only machine for which I was able to find precise implementation details. If you have the technical documentation on any other real-world examples, let me know.