Home | SCI Documentation | SCI Tutorials | SCI Tools | SCI Wiki | Community

The Sierra Creative Interpreter

PrevChapter 3. The Graphics subsystemNext
 

The SCI0 and SCI01 PIC Resource

The pic (background picture) resource format used in SCI0 is rather complex in comparison to the other graphical resource formats. It is best described as a sequence of drawing operations on a set of four 320x200 canvases, three of which are later used in the game (visual, priority, and control), and one of which is used during the drawing process for auxiliary purposes[1]

In order to describe the process, we will first need to define a set of operations we base them on:

FUNCTION peek_input(): Byte; /* returns the byte pointed to by the input pointer */
FUNCTION get_input(): Byte; /* works like peek_input(), but also increminates the 
                            ** input pointer  */
FUNCTION skip_input(x): Byte; /* skips x input bytes */
      
Using these pre-defined functions, we will now define additional helper functions used for reading specifically encoded data tuples:
FUNCTION GetAbsCoordinates(): (Integer, Integer)
VAR
	x, y, coordinate_prefix : Integer;
BEGIN
	coordinate_prefix := get_input();
	x := get_input();
	y := get_input();
	x |= (coordinate_prefix & 0xf0) << 4;
	y |= (coordinate_prefix & 0x0f) << 8;

	RETURN (x,y)
END


FUNCTION GetRelCoordinates(x : Integer, y: Integer): (Integer, Integer)
VAR
	input : Integer;
BEGIN
	input := get_input();
	IF (input & 0x80) THEN
	        x -= (input >> 4);
	ELSE
		x += (input >> 4);
	FI

	IF (input & 0x08) THEN
		y -= (input & 0x7);
	ELSE
		y += (input & 0x7);
	FI

	RETURN (x,y)
END

      
We also need some data types based on EGACOLOR and PRIORITY, which can be thought of as integers:
TYPE Palette = ARRAY[0..39] of EGACOLOR[0..1]
TYPE Priority_Table = ARRAY[0..39] of PRIORITY

Palette default_palette =
     <(0,0), (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7),
      (8,8), (9,9), (a,a), (b,b), (c,c), (d,d), (e,e), (8,8),
      (8,8), (0,1), (0,2), (0,3), (0,4), (0,5), (0,6), (8,8),
      (8,8), (f,9), (f,a), (f,b), (f,c), (f,d), (f,e), (f,f),
      (0,8), (9,1), (2,a), (3,b), (4,c), (5,d), (6,e), (8,8)>;

#define DRAW_ENABLE_VISUAL   1
#define DRAW_ENABLE_PRIORITY 2
#define DRAW_ENABLE_CONTROL  4

#define PATTERN_FLAG_RECTANGLE 0x10
#define PATTERN_FLAG_USE_PATTERN 0x20
      
And now for the actual algorithm:
FUNCTION DrawPic (cumulative, fill_in_black : Boolean; default_palette: Integer; visual_map, priority_map, control_map, aux_map : Map): Map^4
VAR
	palette : Array [0..3] of Palette;
	drawenable, priority, col1, col2, pattern_nr, pattern_code : Integer;
BEGIN
	palette := (default_palette × 4);
	drawenable := DRAW_ENABLE_VISUAL | DRAW_ENABLE_PRIORITY
	priority := 0;
	col1 := col2 := 0;
	pattern_nr := 0;
	pattern_code := 0;

	IF (!cumulative) THEN BEGIN
		visual_map := (0xf × 320 × 200);
		map control := map priority := map aux := (0 × 320 × 200);
	END

	FOREVER DO BEGIN

		opcode := get_input();

		COND opcode:
			0xf0 → /* PIC_OP_SET_COLOR */
				code := get_input();
				(col1, col2) := palette[default_palette + (code / 40)][code % 40];
				drawenable |= DRAW_ENABLE_VISUAL;

			0xf1 → /* PIC_OP_DISABLE_VISUAL */
				drawenable &= ~DRAW_ENABLE_VISUAL;

			0xf2 → /* PIC_OP_SET_PRIORITY */
				code := get_input();
				priority := code & 0xf;
				drawenable |= DRAW_ENABLE_PRIORITY;

			0xf3 → /* PIC_OP_DISABLE_PRIORITY */
				drawenable &= ~DRAW_ENABLE_PRIORITY;

			0xf4 → /* PIC_OP_RELATIVE_PATTERNS */
				IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
					pattern_nr := (get_input() >> 1) & 0x7f
				FI

				(x,y) := GetAbsCoordinates();

				DrawPattern(x, y, col1, col2, priority, control, drawenable,
						 pattern_code & PATTERN_FLAG_USE_PATTERN,
						 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);

				WHILE (peek_input() < 0xf0) DO BEGIN
					IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
						pattern_nr := (get_input() >> 1) & 0x7f
					FI
					(x,y) =  GetRelCoordinates(x,y);
					DrawPattern(x, y, col1, col2, priority, control, drawenable,
							 pattern_code & PATTERN_FLAG_USE_PATTERN,
							 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);
				END

			0xf5 → /* PIC_OP_RELATIVE_MEDIUM_LINES */
				(oldx, oldy) := GetAbsCoordinates();
				WHILE (peek_input() < 0xf0) DO BEGIN
					temp := get_input();
					IF (temp & 0x80) THEN
						y := oldy - (temp & 0x7f)
					ELSE
						y := oldy + temp
					FI
					x = oldx + get_input();
					 DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);
					(oldx, oldy) := (x, y);
				END

			0xf6 → /* PIC_OP_RELATIVE_LONG_LINES */
				(oldx, oldy) :=  GetAbsCoordinates()
				WHILE (peek_input() < 0xf0) DO BEGIN
					(x, y) := GetAbsCoordinates();
					DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);
					(oldx, oldy) := (x, y);
				END

			0xf7 → /* PIC_OP_RELATIVE_SHORT_LINES */
				(oldx, oldy) =  GetAbsCoordinates()
				WHILE (peek_input() < 0xf0) DO BEGIN
					(x, y) := GetRelCoordinates(oldx, oldy);
					DitherLine(oldx, oldy, x, y, col1, col2, priority, special, drawenable);
					(oldx, oldy) := (x, y);
				END

			0xf8 → /* PIC_OP_FILL */
				IF (fill_in_black) THEN
					(oldc1, oldc2) := (c1, c2);
				FI

				WHILE (peek_unput() < 0xf0) DO BEGIN
					(x, y) := GetAbsCoordinates();
					DitherFill(x, y, col1, col2, priority, special, drawenable);
				END

				IF (fill_in_black) THEN
					(c1, c2) := (oldc1, oldc2);
				FI

			0xf9 → /* PIC_OP_SET_PATTERN */
				pattern_code := get_input() & 0x37;
				pattern_size := pattern_code & 0x7;

			0xfa → /* PIC_OP_ABSOLUTE_PATTERNS */
				WHILE (peek_input() < 0xf0) DO
					IF (pattern_code & PATTERN_FLAG_USE_PATTERN)
						pattern_nr := (get_input() >> 1) & 0x7f
					FI
					(x, y) := GetAbsCoordinates();
					DrawPattern(x, y, col1, col2, priority, control, drawenable,
							 pattern_code & PATTERN_FLAG_USE_PATTERN,
							 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);
					END

			0xfb → /* PIC_OP_SET_CONTROL */
				control := get_input() & 0x0f;
				drawenable |= DRAW_ENABLE_CONTROL;

			0xfc → /* PIC_OP_DISABLE_CONTROL */
				drawenable &= ~DRAW_ENABLE_CONTROL;

			0xfd → /* PIC_OP_RELATIVE_MEDIUM_PATTERNS */
				IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
					pattern_nr := (get_input() >> 1) & 0x7f;
				FI

				(oldx, oldy) := GetAbsCoordinates();

				DrawPattern(x, y, col1, col2, priority, control, drawenable,
						 pattern_code & PATTERN_FLAG_USE_PATTERN,
						 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);

				WHILE (peek_input() < 0xf0) DO BEGIN
					IF (pattern_code & PATTERN_FLAG_USE_PATTERN) THEN
						pattern_nr := (get_input() >> 1) & 0x7f;
					FI
			
					temp := get_input();
					IF (temp & 0x80)
						y := oldy - (temp & 0x7f)
					ELSE
						y := oldy + temp
					FI
					x := oldx + get_input();
					DrawPattern(x, y, col1, col2, priority, control, drawenable,
							 pattern_code & PATTERN_FLAG_USE_PATTERN,
							 pattern_size, pattern_nr, pattern_code & PATTERN_FLAG_RECTANGLE);
				END

			0xfd → /* PIC_OP_OPX */
				COND get_input():
					0x00 → /* PIC_OPX_SET_PALETTE_ENTRY */
						WHILE peek_input() < 0xf0 DO BEGIN
							index := get_input();
							color := get_input();
							palette[index / 40][color % 40] := color;
						END

					0x01 → /* PIC_OPX_SET_PALETTE */
						palette_number := get_input();
						FOR i := 0 TO 39 DO
							palette[palette_number][i] := get_input();
						OD

					0x02 → /* PIC_OPX_MONO0 */
						skip_input(41);

					0x03 → /* PIC_OPX_MONO1 */
						skip_input(1);

					0x04 → /* PIC_OPX_MONO2 */
					0x05 → /* PIC_OPX_MONO3 */
						skip_input(1);

					0x06 → /* PIC_OPX_MONO4 */
					0x07 → /* PIC_OPX_EMBEDDED_VIEW */ /* SCI01 operation */
					0x08 → /* PIC_OPX_SET_PRIORITY_TABLE */ /* SCI01 operation */

			0xff → return (visual, control, priority, aux);
		END OF COND
      END
END
      
This algorithm uses three auxiliary algorithms, DrawPattern, DitherLine, and DitherFill, which are sketched below. All of these functions are supposed to take the four maps as implicit parameters.
PROCEDURE DrawPattern(x, y, col1, col2, priority, control, drawenable : Integer;  solid : Boolean ;  pattern_size, pattern_nr : Integer; rectangle : Boolean)

Alters (x,y) so that 0 <= (x - pattern_size), 319 >= (x + pattern_size), 189 >= (y + pattern_size) and
0 <= (y - pattern_size), then draws a rectangle or a circle filled with col1, col2, priority, control,
as determined by drawenable.
If rectangle is not set, it will draw a rectangle, otherwise a circle of size pattern_size.
pattern_nr is used to specify the start index in the random bit table (256 random bits)



PROCEDURE DitherLine(x, y, xend, yend, color1, color2, priority, control, drawenable : Integer)

Draws a dithered line between (x, y+10) and (xend, yend+10). If the appropriate drawenable flags
are set, it draws 'priority' to the priority map, 'control' to the control map, and 'color1' and 'color2'
(alternating) to the visual map. The auxiliary map is bitwise-or'd with the drawenable flag while this is
done.



PROCEDURE DitherFill(x, y, col0, col1, priority, control, drawenable : Integer)
Fills all layers for which drawenable is set with the appropriate content.
Diagonal filling is not allowed.
Boundaries are determined as follows:
x<0, x>319, y<10, y>199 are hard boundaries. We now determine the
'boundary map' bound_map and the allowed color legal_color.
If bound_map[coordinates] = legal_color, then the pixel may be filled.

IF (drawenable & DRAW_ENABLE_VISUAL)
	bound_map = visual;
	legal_color = 0xf;
ELSIF (drawenable & DRAW_ENABLE_PRIORITY)
	bound_map = priority;
	legal_color = 0;
ELSIF (drawenable & DRAW_ENABLE_CONTROL)
	bound_map = control;
	legal_color = 0;
ELSE
	return;
FI
      

Notes

[1] Due to the vector graphics nature of these drawing operations, they are inherently more scaleable than pixmaps.


Prev - The SCI Font ResourceHomeNext - Windows, Dialogs and Controls
 

by helping to defray some of the costs of hosting this site. If it has been of help to you, please consider contributing to help keep it online.
Thank you.
pixe
Top

© 2013 to present The Sierra Help Pages. All rights reserved. All Sierra games, artwork and music © Sierra.