// This tutorial is part of a series that explains the basic concepts of the APRON simulation system.
// Please ensure you have read and understood any previous tutorial examples.
//
// © David R W Barr 2009
//
// Name: 		MASK REGISTERS
// Description:	This tutorial details how to use masks to program
//				spatially independent element operations
// Usage:		Please RUN this algorithm in the simulator.


// Always include this line for an APRON simulation. This file includes many pre-defined
// types and functions that are used in a standard APRON simulation.
!include('apron.aps')

!define(RW, 128)
!define(RH, 128)

!create_reg('a', RW, RH) 
!create_reg('b', RW, RH) 
!create_reg('c', RW, RH) 
!create_reg('d', RW, RH)


// Show some useful registers for this tutorial
showreg(r[a]) 
showreg(r[b])

tile


// MASKS
// ~~~~~
//
// A register holds numerical information OR mask information. Masks are used to 
// selectively disable write permissions to individual elements of a register. When
// a register is used to store mask information, it is numerically meaningless and 
// should not be operated upon, except when using mask operations.

// This tutorial uses the code from T4_FileInputAndOutput.aps, and uses masks to
// isolate elements that are in the range 50 to 60, and colour them red!




sample = 0
#loop

	// Load the sample image, using the variable 'sample' appended to the filename
	r[a] = input(IO_IMAGE, 'tut_resources\sample_', sample, 'bmp')
	
	// Masks are made based upon conditions. This statement tests if each element of r[a] is >50. If it is
	// then the corresponding element in r[c] is set to true (implying also that r[c] is now a 'mask register')
	// or false if the condition is not true.
	
	r[c] = mask(r[a], >, 50) // Mask all elements with a value >50
	r[d] = mask(r[a], <, 60) // Mask all elements with a value <60
	
	// There are three mask operations to choose from, that are effectively logic operations
	// mask_and, mask_or and mask_not. As mask regsiters contain boolean information, the 
	// appropriate operation is calculated. Here we AND the two mask registers together, which
	// in effect should only be the elements in the range 50 - 60
	r[c] = mask_and(r[c], r[d])
	
	// The purpose of this algorithm is to invert all the elements which lie in a specified range.
	// We shall use r[b] as the output register
	
	// First copy over the contents of r[a], we will view the input and output images simultaneously
	r[b] = r[a]
	
	// Enable the mask - only one mask is active at a time
	maskon(r[c])
	
		// All subsequent operations are now influenced by the mask register r[c]. So 
		// here only those elements that are enabled by the corresponding mask element
		// being true are affected by the operation
		r[b] = r[a] * -1
		
		// Disable the mask
	maskoff
	
	
	// IMPORTANT!!
	// Registers r[c] and r[d] still contain mask information. Using these registers in normal
	// numerical operations may result in undesirable operation. Before reading from these
	// registers for non-mask operations, you must assign to them first.
	


	// Show the input and output images
	simshow(r[a])
	simshow(r[b])

	sample = sample + 1
	jumpif(sample, <, 236,  #loop)

	// Repeat indefinitely
	sample = 0
	jump(#loop)


end