128x192 with 4 levels compatible

Propose new game/software design concepts or new game/software ideas. They can be as whimsical as you like, just be careful you don't ask someone to make it for you...
Post Reply
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

128x192 with 4 levels compatible

Post by 4thRock »

Ok, another one of my crazy ideas, just for the fun of it!

Thinking about a way to have a new screen-mode, 128x192 with 4 levels + attributes, and be compatible with standard Spectrums.

4 levels image:
Image

ZX Compatible image:
Image


If we take two consecutive pixels:
0 0 = 0
0 1 = 1
1 0 = 2
1 1 = 3

We can store two intermediate "gray scale" values that way.
On normal screens, the user would see a vertical dither pattern. Not that pretty, but not that different from many CGA or Apple II games.

But on an emulator that decodes the pixels patterns, the extra tones would be visible.
Of course, attributes and bright would still behave as before, with a two levels of mixing between paper and ink.

:D
AndyC
Dynamite Dan
Posts: 1386
Joined: Mon Nov 13, 2017 5:12 am

Re: 128x192 with 4 levels compatible

Post by AndyC »

Would be similar to the Amstrad CPC Mode 1 and suffer a similar issue with the sheer amount of memory you have to start pushing around to draw screens (if anything it would be worse since you'd need separate planar layouts to remain compatible rather than storing all the bits for a pixel within a given byte). With any display mode that pushes much past about the 7K memory limit you really start to need hardware assistance to shift things around, which is where the CPC and SAM Coupe really suffered. If you really wanted more colours on screen without losing resolution a character-based mode like the C64 would make a lot more sense (and potentially use less memory) but that's difficult to work with unless you have hardware scrolling and sprites.
User avatar
Ersh
Manic Miner
Posts: 480
Joined: Mon Nov 13, 2017 1:06 pm

Re: 128x192 with 4 levels compatible

Post by Ersh »

I think the idea behind 4throck's screenmode is that it takes exactly the same amount of memory as a usual 6912 screen just at the cost of horizontal resolution. Much the same way the multicolour modes work on the C64 (not including colour RAM etc).
User avatar
Seven.FFF
Manic Miner
Posts: 735
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: 128x192 with 4 levels compatible

Post by Seven.FFF »

This is Radastan mode on the ZX-Uno, except that you can have 16 colours per pixel rather than 4 greyscale, taken from a user-specified quarter of the GGGRRRBB ULA+ palette.

Jimistan mode on the Spectrum Next works similarly, except it uses the Timex shadow screen as well, interleaving a byte from each screen, allowing 256 colours per pixel taken freely from a ULA Enhanced palette of 512 colours (because the Next palettes are 9-bit RRRGGGBBB).

ZEsarUX emulates both Radastan and Jimistan modes.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: 128x192 with 4 levels compatible

Post by 4thRock »

The idea is to only use the standard ZX spectrum screen memory, and to display images that are 100% compatible with a standard Spectrum.
So no extra memory, and all extra gray levels must translate to dithering.

Simple pixel averaging from 256x192 to 128x192 will get you a gray tone, but my proposal stores 2 gray levels ;)
00 = black
01 = grey 1
10 = grey 2
11 = white
User avatar
Seven.FFF
Manic Miner
Posts: 735
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: 128x192 with 4 levels compatible

Post by Seven.FFF »

OK, I see now! Nice :)
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: 128x192 with 4 levels compatible

Post by RMartins »

I'm just curious, how an emulator would know that it should do this conversion ?

Something for the user to select by hand ?
User avatar
Seven.FFF
Manic Miner
Posts: 735
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: 128x192 with 4 levels compatible

Post by Seven.FFF »

Or maybe a ZXI port to turn it on and off, why not?
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: 128x192 with 4 levels compatible

Post by 4thRock »

I don't know much about hardware, but how about OUT 255 like the extra Timex modes ?
But since the idea is to be retro compatible, then yes, something that the user could select would be ideal.
Just select whatever mode works best for a given game / software.


I have a second idea: limit the effect to only certain attribute combinations (only bright for example).
This would allow full resolution text or detailed graphics as needed.
User avatar
Joefish
Rick Dangerous
Posts: 2041
Joined: Tue Nov 14, 2017 10:26 am

Re: 128x192 with 4 levels compatible

Post by Joefish »

I don't really think it's worth it trying to make it visible on ordinary displays. The dithered image looks terrible; no-one would play a game like that.

There's some merit, I suppose, in mimicking the modes of other 8-bit computers - in this case the C64. I don't like the blocky look myself, but if you're going to do it, why not go the whole way and use the attribute byte to set two colours of the four available in each character cell?

You could even use the byte in a 2+3+3 bit fashion to select three of the colours, with the remaining background colour being common across the whole screen. Might as well then use something like ULA+ on top to define separate 4/8/8 colour palettes for each part of that colour byte. Or if the attribute just sets two colours, use a 16-colour palette that can be similarly redefined.

Personally I'd rather see the pixels paired up vertically to gain the extra bits for colour indexing. It's a little harder to make text readable, but I think it works far better for designing sprites, particularly upright humanoid figures, trees, buildings etc.

What I'd like to see is a character-mapped mode like the MSX has, where you can redraw character cells by writing one byte, but there's enough character data that you can put a different character in each cell, then treat the character definition RAM as a completely bitmapped screen.
hikoki
Manic Miner
Posts: 576
Joined: Thu Nov 16, 2017 10:54 am

Re: 128x192 with 4 levels compatible

Post by hikoki »

I cannot understad this. Is it about automatic dithering? If so it would be interesting to achieve any blending of colours which is a trick used to simulate oranges for example interleaving ditherings in red and yellow. Automatic dithering in colours, not only for greys, might Not be "ugly". I don't think dithering is ugly in general. Just plain flat colours don't help to tell bright and dimmed colours, besides a bit of noise is interesting to suggest volumes and shades.
User avatar
Joefish
Rick Dangerous
Posts: 2041
Joined: Tue Nov 14, 2017 10:26 am

Re: 128x192 with 4 levels compatible

Post by Joefish »

No, the original idea was for an extra screen mode that still looks OK if you don't have the modified hardware to display it properly.
I don't think it's really worth trying, because the fallback image doesn't look good enough. There were a few games converted from the C64 and amstrad to the Spectrum that just used dithers in place of colours for lazy ports of the graphics, and they all looked terrible.

Image Image Image

Mind you, Gobots looked crap on the Amstrad in the first place...

Maybe if you could get the dithers to swap places on alternate rows so you got proper chessboard stipples, like Mr Heli there, but then it'd be an immense pain to program the 4-colour versions as the bit order would be reversed on alternate rows. Fine I suppose if you stick to 2-pixel movements of sprites as then the bits are always in the same positions...
hikoki
Manic Miner
Posts: 576
Joined: Thu Nov 16, 2017 10:54 am

Re: 128x192 with 4 levels compatible

Post by hikoki »

what about something really subtle? just enough to make you believe there are more colours
something subtler than this
Image
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: 128x192 with 4 levels compatible

Post by 4thRock »

That works but you only get one intermediate tone (3 levels).
The advantage of using the pixel order is to have 2 intermediate tones (4 levels).

I agree that the fallback image is not nice.

So lets consider changing the pixel order on alternate lines 8-)
That way, we could still use the normal chessboard dithering....

I really need to write a converter (or try to mod an emulator), but if I'm not mistaken, we would get this:
Original
Image
Converted
Image

So it would be:

Even lines
00 = black
01 = grey 1
10 = grey 2
11 = white

Odd lines
00 = black
10 = grey 1
01 = grey 2
11 = white
hikoki
Manic Miner
Posts: 576
Joined: Thu Nov 16, 2017 10:54 am

Re: 128x192 with 4 levels compatible

Post by hikoki »

Off-topic

This : https://commons.m.wikimedia.org/wiki/Fi ... hering.png
See? you'd make your graphics as usual and the engine would change small chameleon-esque ditherings for you on the fly! :shock:
User avatar
Joefish
Rick Dangerous
Posts: 2041
Joined: Tue Nov 14, 2017 10:26 am

Re: 128x192 with 4 levels compatible

Post by Joefish »

You need large shaded or blended areas for all those different dithers to look any good. Even then, the pixels are pretty big and distinct, so it only really works for blending similar colours.

Within the usual size of Speccy game graphics, anything more than 01/10 dithering is too complicated. And you sometimes have to invert the stipple pattern (or move it by 1 pixel) when putting it next to the solid or clear parts of your design.
hikoki
Manic Miner
Posts: 576
Joined: Thu Nov 16, 2017 10:54 am

Re: 128x192 with 4 levels compatible

Post by hikoki »

This is the idea! It was already invented around 2009 by Gasman ?
It's called Chunkypaint 53c :

http://chunkypaint.zxdemo.org

http://events.retroscene.org/53c

http://53c.verve.space

There are some works from parties on zx-art, pouet, demozoo, etc

https://demozoo.org/parties/1779/

http://www.pouet.net/prod.php?which=61392

Dunno if this would be possible to make games or it's just useful for lower resolution loading screens.
Last edited by hikoki on Fri Apr 06, 2018 6:43 pm, edited 1 time in total.
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: 128x192 with 4 levels compatible

Post by 4thRock »

hikoki, those examples are different. They use dithering to simulate a 50% mix between paper and ink.

The point here it to try to use dithering in a way that:
- still looks decent on a normal spectrum
- encodes two values, so you can have 33% and 66% mixing (on compatible "hardware")
hikoki
Manic Miner
Posts: 576
Joined: Thu Nov 16, 2017 10:54 am

Re: 128x192 with 4 levels compatible

Post by hikoki »

Good luck 4thRock. Hope someone will help you mod some emulator.
Anyways I like the idea of painting with a virtual extended palette like and the paint editor makes all the dithering for you. This might be a nice feature suggestion for ZXPaintBrush. According to Joefish this is not feasible to make games? Please let me know if there is some game using this technique intensively.
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: 128x192 with 4 levels compatible

Post by 4thRock »

OK, wrote a simple Javascript image converter and got some results

Standard image
Image

Decoded
Image

Not horrible on a standard display.

I'll share the code latter.
AndyC
Dynamite Dan
Posts: 1386
Joined: Mon Nov 13, 2017 5:12 am

Re: 128x192 with 4 levels compatible

Post by AndyC »

Using a different encoding on different scanlines would be pretty much unworkable for moving images, so you'd really be limiting the use to static screens.
User avatar
Joefish
Rick Dangerous
Posts: 2041
Joined: Tue Nov 14, 2017 10:26 am

Re: 128x192 with 4 levels compatible

Post by Joefish »

Not really. Because of the drop in resolution, things would only move horizontally in 2-pixel steps, so it would be reasonable for things to move vertically in 2-pixel steps too, thus preserving the stipple alignment.
User avatar
4thRock
Manic Miner
Posts: 415
Joined: Thu Nov 09, 2017 9:35 am
Location: Portugal

Re: 128x192 with 4 levels compatible

Post by 4thRock »

Copy this into a HTML file and you have an encoder / decoder.
The JS code is quite basic and not optimized, so it's very simple to understand.

You can see it working here:
http://4throckworld.com/dev/128x192/

Of course, for better results it's better to start with images already converted to 4 levels.
The converter will only do straight brightness level mapping.

Attributes are completely ignored.

Code: Select all

<!DOCTYPE html>
<html>
<head>
<script>

function draw(img) {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  img.style.display = 'none';
  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  var data = imageData.data;
    
  var Encode = function() {
     for (var i = 0; i < data.length; i += 8) {
	
	//get average value
    var avg = (data[i] + data[i + 1] + data[i + 2] + data[i + 4] + data[i + 5] + data[i + 6]) /  6;

	var lineNumber =  Math.round( (i/4)/256 );
	var oddLine = lineNumber % 2 
	
	
	// 00
	if  ( avg <	64) {var avg_a = 0 ;  var avg_b = 0};
	// 01
	if  ( (avg >	64)  && (avg < 127) ) { if ( oddLine == 0 ) { var avg_a = 0 ;  var avg_b = 255}  else { avg_a = 255 ; avg_b = 0}  };
	// 10
	if  ( (avg >	127) && (avg < 191) ) { if ( oddLine == 0 ) { var avg_a = 255 ; var avg_b = 0}  else { avg_a = 0 ; avg_b = 255}  };
	// 11
	if  ( avg >	191 ) { var avg_a = 255 ;  var avg_b = 255};
	  
	  
		  
      data[i]     = avg_a; // red
      data[i + 1] = avg_a; // green
      data[i + 2] = avg_a; // blue
	  //data[i + 3 ]     = 255; // red
	  
      data[i + 4] = avg_b; // green
      data[i + 5] = avg_b; // blue
	  data[i + 6] = avg_b; // green
      //data[i + 7] = 255; // blue
	  
    }
    ctx.putImageData(imageData, 0, 0);
  };

  var Decode = function() {
    for (var i = 0; i < data.length; i += 8) {
	
	//get average values of two consecutive pixels
    var avg_a = (data[i] + data[i + 1] + data[i + 2] ) /  3;
	var avg_b = (data[i + 4] + data[i + 5] + data[i + 6] ) /3;

	var lineNumber =  Math.round( (i/4)/256 );
	var oddLine = lineNumber % 2 
	
	
	// 00
	if  ( (avg_a <	85) && (avg_b < 85) ) {avg = 0};
	// 01
	if  ( (avg_a <	85) && (avg_b > 170) ) { if ( oddLine == 0 ) { avg = 85}  else { avg = 170}  };
	// 10
	if  ( (avg_a >	170) && (avg_b < 85) ) { if ( oddLine == 0 ) { avg = 170}  else { avg = 85}  };
	// 11
	if  ( (avg_a >	170) && (avg_b > 170) ) {avg = 255};
	  
	  
		  
      data[i]     = avg; // red
      data[i + 1] = avg; // green
      data[i + 2] = avg; // blue
	  //data[i + 3 ]     = 255; // red
	  
      data[i + 4] = avg; // green
      data[i + 5] = avg; // blue
	  data[i + 6] = avg; // green
      //data[i + 7] = 255; // blue

    }
    ctx.putImageData(imageData, 0, 0);
  };

  var Encodebtn = document.getElementById('Encodebtn');
  Encodebtn.addEventListener('click', Encode);
  var Decodebtn = document.getElementById('Decodebtn');
  Decodebtn.addEventListener('click', Decode);
}

function handleImage(e){
    var reader = new FileReader();
		
	var img = new Image();
//img.src = 'heli.png';

	
    reader.onload = function(event){
		
				img.src = event.target.result;
				img.onload = function() {
  draw(this);
};
			}
    reader.readAsDataURL(e.target.files[0]);     
}

function readImage() {
    if ( this.files && this.files[0] ) {
        var FR= new FileReader();
        FR.onload = function(e) {
           //var img = new Image();
           img.addEventListener("load", function() {
             ctx.drawImage(img, 0, 0);
           });
           img.src = e.target.result;
        };       
        FR.readAsDataURL( this.files[0] );
    }
}



function pageLoaded() {
var imageLoader = document.getElementById('fileUpload');
imageLoader.addEventListener('change', handleImage);



var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');


}
</script>
</head>
<body onload = "pageLoaded();">
<label>Loads a 256x192 image.<br> Encodes / decodes a 192x192 4 bit level image using 1 bit dithering. <br>Bit order is reversed on each line for better visual quality on the undecoded image.</label><br/>
<hr>
<input type='file' id="fileUpload" />
<canvas id="canvas" width="256" height="192"></canvas>
<div>
  <input id="Decodebtn" value="Decode" type="button">
  <input id="Encodebtn" value="Encode" type="button">
</div>
</body>
</html>
chernandezba
Microbot
Posts: 168
Joined: Tue Nov 28, 2017 7:39 am

Re: 128x192 with 4 levels compatible

Post by chernandezba »

Seems some of the video modes of machine ZX Prism from Jeff Braine
https://youtu.be/Jrge4HtnqPI
Minute 5.37
You can test it on ZEsarUX ;)
hikoki
Manic Miner
Posts: 576
Joined: Thu Nov 16, 2017 10:54 am

Re: 128x192 with 4 levels compatible

Post by hikoki »

I've found this demo in Basic, somewhat related with 53c, which tried to emulate 128 different colours, Rainbird
Post Reply