xref: /inferno-os/appl/lib/print/scaler.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1implement Scaler;
2
3include "sys.m";
4	sys: Sys;
5include "draw.m";
6include "print.m";
7include "scaler.m";
8
9DEBUG := 0;
10
11# Scaler initialisation
12
13init(debug: int, WidthInPixels, ScaleFactorMultiplier, ScaleFactorDivisor: int): ref RESSYNSTRUCT
14{
15	DEBUG = debug;
16	ScaleFactor := real ScaleFactorMultiplier / real ScaleFactorDivisor;
17	ScaleBound := int ScaleFactor;
18	if  (ScaleFactor > real ScaleBound) ScaleBound++;
19	ResSynStruct := ref RESSYNSTRUCT (
20					WidthInPixels+2,	# add 2 for edges
21					ScaleFactorMultiplier,
22					ScaleFactorDivisor,
23					ScaleFactor,
24					int ((real WidthInPixels / real ScaleFactorDivisor))*ScaleFactorMultiplier + 1,
25					ScaleFactorMultiplier != ScaleFactorDivisor,
26					ScaleFactor < 2.0,
27					(ScaleFactorMultiplier * 256 / ScaleFactorDivisor)
28										  -  ((ScaleFactorMultiplier/ScaleFactorDivisor) * 256),
29					0,
30					0,
31					array[NUMBER_RASTERS] of array of int,
32					array[ScaleBound] of array of int,
33					0,
34					0
35				);
36	if (ResSynStruct.ScaleFactor > real ScaleBound) ScaleBound++;
37	for (i:=0; i<len ResSynStruct.Buffer; i++) ResSynStruct.Buffer[i] = array[WidthInPixels*NUMBER_RASTERS] of int;
38	for (i=0; i<len ResSynStruct.oBuffer; i++) ResSynStruct.oBuffer[i] = array[ResSynStruct.iOutputWidth] of int;
39	return ResSynStruct;
40}
41
42
43# Input a raster line to the scaler
44
45rasterin(rs: ref RESSYNSTRUCT, inraster: array of int)
46{
47	if (!rs.scaling) {		# Just copy to output buffer
48		if (inraster == nil) return;
49		rs.oBuffer[0] = inraster;
50		rs.nready = 1;
51		rs.ndelivered = 0;
52		return;
53	}
54
55	if (rs.ReplicateOnly) {	# for scaling between 1 and 2
56#		for (i:=0; i<len inraster; i++) rs.oBuffer[0][i] = inraster[i];
57		rs.oBuffer[0][:] = inraster[0:];
58		create_out(rs, 1);
59		return;
60	}
61
62	if (rs.RastersinBuffer == 0) {	# First time through
63		if (inraster == nil) return;
64		for (i:=0; i<2; i++) {
65			rs.Buffer[i][0] = inraster[0];
66#			for (j:=1; j<rs.Width-1; j++) rs.Buffer[i][j] = inraster[j-1];
67			rs.Buffer[i][1:] = inraster[0:rs.Width-2];
68			rs.Buffer[i][rs.Width-1] = inraster[rs.Width-3];
69		}
70		rs.RastersinBuffer = 2;
71		return;
72	}
73
74	if (rs.RastersinBuffer == 2) {	# Just two buffers in so far
75		if (inraster != nil) {
76			i := 2;
77			rs.Buffer[i][0] = inraster[0];
78#			for (j:=1; j<rs.Width-1; j++) rs.Buffer[i][j] = inraster[j-1];
79			rs.Buffer[i][1:] = inraster[0:rs.Width-2];
80			rs.Buffer[i][rs.Width-1] = inraster[rs.Width-3];
81			rs.RastersinBuffer = 3;
82		} else {	# nil means end of image
83			rez_synth(rs, rs.oBuffer[0], rs.oBuffer[1]);
84			create_out(rs, 0);
85		}
86		return;
87	}
88	if (rs.RastersinBuffer == 3) {	# All three buffers are full
89		(rs.Buffer[0], rs.Buffer[1], rs.Buffer[2]) = (rs.Buffer[1], rs.Buffer[2], rs.Buffer[0]);
90		if (inraster != nil) {
91			i := 2;
92			rs.Buffer[i][0] = inraster[0];
93#			for (j:=1; j<rs.Width-1; j++) rs.Buffer[i][j] = inraster[j-1];
94			rs.Buffer[i][1:] = inraster[0:rs.Width-2];
95			rs.Buffer[i][rs.Width-1] = inraster[rs.Width-3];
96		} else {	# nil means end of image
97#			for (j:=0; j<len rs.Buffer[1]; j++) rs.Buffer[2][j] = rs.Buffer[1][j];
98			rs.Buffer[2][:] = rs.Buffer[1];
99			rs.RastersinBuffer = 0;
100
101		}
102		rez_synth(rs, rs.oBuffer[0], rs.oBuffer[1]);
103		create_out(rs, 0);
104	}
105
106}
107
108
109# Get a raster output line from the scaler
110
111rasterout(rs: ref RESSYNSTRUCT): array of int
112{
113	if (rs.nready-- > 0) {
114		return rs.oBuffer[rs.ndelivered++][:rs.iOutputWidth-1];
115	} else return nil;
116}
117
118
119
120# Create output raster
121
122create_out(rs: ref RESSYNSTRUCT, simple: int)
123{
124	factor: int;
125	if (simple) factor = 1;
126	else factor = 2;
127
128	out_width := (rs.Width-2) * rs.ScaleFactorMultiplier / rs.ScaleFactorDivisor;
129	number_out := rs.ScaleFactorMultiplier / rs.ScaleFactorDivisor;
130	if (number_out == 2 && !(rs.ScaleFactorMultiplier % rs.ScaleFactorDivisor) ) {
131		rs.nready = 2;
132		rs.ndelivered = 0;
133		return;
134	}
135
136	if (rs.ScaleFactorMultiplier % rs.ScaleFactorDivisor)
137	{
138		rs.Remainder = rs.Remainder + rs.Repeat;
139
140		if (rs.Remainder >= 256)	# send extra raster
141		{
142			number_out++;
143			rs.Remainder = rs.Remainder - 256;
144		}
145	}
146	# set up pointers into the output buffer
147	output_raster := array[number_out] of array of int;
148	output_raster[:] = rs.oBuffer[0:number_out];
149
150	ScaleFactorMultiplier := rs.ScaleFactorMultiplier;
151	ScaleFactorDivisor := rs.ScaleFactorDivisor;
152	sf := factor * ScaleFactorDivisor;
153
154	# Convert the input data by starting at the bottom right hand corner and move left + up
155	for (i:=(number_out-1); i>=0; i--) {
156		y_index := i*sf/ScaleFactorMultiplier;
157		orast_i := output_raster[i];
158		orast_y := output_raster[y_index];
159		for (lx := out_width-1; lx>=0; --lx) {
160			x_index := lx*sf/ScaleFactorMultiplier;
161			orast_i[lx] = orast_y[x_index];
162		}
163	}
164
165	rs.nready = number_out;
166	rs.ndelivered = 0;
167	return;
168}
169
170
171# Synthesise raster line
172
173rez_synth(rs: ref RESSYNSTRUCT, output_raster0, output_raster1: array of int)
174{
175
176	i := 1;
177	Buffer := rs.Buffer[i];
178	h_offset := 0;
179	for (j:=1; j<rs.Width-1; j++) {
180		rgb := Buffer[j];
181		output_raster0[h_offset] = rgb;
182		output_raster1[h_offset++] = rgb;
183		output_raster0[h_offset] = rgb;
184		output_raster1[h_offset++] = rgb;
185	}
186}
187