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
AndyC
Dynamite Dan
Posts: 1388
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: 2042
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