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
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: 1387
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