Open main menu

Difference between revisions of "AGI/Specifications/View"

m
colour -> color
m (colour -> color)
 
(2 intermediate revisions by one other user not shown)
Line 6: Line 6:
==Introduction==
==Introduction==


VIEW resources contain some of the graphics for the game. Unlike the picture resources which are full-screen background images, view resources are smaller sprites used in the game, such as animations and objects. They are also stored as bitmaps, whereas pictures are stored in vector format.
VIEW resources contain some of the graphics for the game. Unlike the picture resources which are full-screen background images, view resources are smaller ''sprites'' used in the game, such as animations and objects. They are also stored as bitmaps, whereas pictures are stored in vector format.


Each view resource consists of one or more loops. Each loop in the resource consists of one or more cels (frames). Thus several animations can be stored in one view, or a view can just be used for a single image. The maximum number of loops supported by the interpreter is 255 (0-254) and the maximum number of cels in each is 255 (0-254).
Each view resource consists of one or more loops. Each loop in the resource consists of one or more ''cels'' (frames). Thus several animations can be stored in one view, or a view can just be used for a single image. The maximum number of loops supported by the interpreter is 255 (0-254) and the maximum number of cels in each is 255 (0-254).


Note: Except when noted otherwise, 16 bit data is stored in little endian format (i.e. the value has the least significant byte stored first, and the most significant byte stored second). Most word values in AGI are stored like this, but not all.
Note: Except when noted otherwise, 16 bit data is stored in little endian format (i.e. the value has the least significant byte stored first, and the most significant byte stored second). Most word values in AGI are stored like this, but not all.
Line 14: Line 14:
<span id="ViewFormat"></span>
<span id="ViewFormat"></span>
==VIEW resource format==
==VIEW resource format==
Following tables show the format of the view, loop
and cel headers.
The first four bits of the last byte of the cel header tell the
interpreter how to handle the mirroring of this cel (explained later).
The last four bits represent the transparent color. When the cel is
drawn on the screen, any pixels of this color will show through to the
background. All cels have a transparent color, so if you want an
opaque cel then you must set the transparent color to one that is
not used in the cel.
===View header (7+ bytes)===
===View header (7+ bytes)===


Line 32: Line 44:


Note: Two of these loop references CAN point to the same place. This is done when you want to use mirroring (more on this later).
Note: Two of these loop references CAN point to the same place. This is done when you want to use mirroring (more on this later).
===Loop header (3+ bytes)===
===Loop header (3+ bytes)===


Line 58: Line 71:
</pre>
</pre>


The first four bits of this byte tell the interpreter how to handle the mirroring of this cel (explained later).
===Cel data===


The last four bits represent the transparent color. When the cel is drawn on the screen, any pixels of this color will show through to the background.
The actual image data for each cel is stored using RLE (run length encoding) compression. This means that instead of having one byte for each single pixel (or 1/2 byte as you would use for 16 colors), each byte specifies how many pixels there are to be in a row and what color they are. I will refer to these groups of pixels as "chunks".
 
All cels have a transparent color, so if you want an opaque cel then you must set the transparent color to one that is not used in the cel.
Cel data
 
The actual image data for each cel is stored using RLE (run length encoding) compression. This means that instead of having one byte for each single pixel (or 1/2 byte as you would use for 16 colors), each byte specifies how many pixels there are to be in a row and what colour they are. I will refer to these groups of pixels as "chunks".


This method of compression is not very efficient if there is a lot of single pixels in the image (e.g. a view showing static on a TV screen), but in most cases it does save a fair amount of space.
This method of compression is not very efficient if there is a lot of single pixels in the image (e.g. a view showing static on a TV screen), but in most cases it does save a fair amount of space.


Each line (not to be confused with a chunk) in the cel consists of several bytes of pixel data, then a 0 to end the line. Each byte of pixel data represents one chunk. The first four bits determine the colour, and the last four bits determine the number of pixels in the chunk.
Each line (not to be confused with a chunk) in the cel consists of several bytes of pixel data, then a 0 to end the line. Each byte of pixel data represents one chunk. The first four bits determine the color, and the last four bits determine the number of pixels in the chunk.


Example: AX BY CZ 00
Example: AX BY CZ 00
Line 75: Line 83:
This line will have:
This line will have:


* X pixels of colour A (AX)
* X pixels of color A (AX)
* Y pixels of colour B (BY)
* Y pixels of color B (BY)
* Z pixels of colour C (CZ)
* Z pixels of color C (CZ)
* (then that will be the end of the line) (00)
* (then that will be the end of the line) (00)


If the color of the last chunk on the line is the transparent color, there is no need to store this. For example, if C was the transparent color in the above example, you could just write AX BY 00. This also saves some space.
If the color of the last chunk on the line is the transparent color, there is no need to store this. For example, if C was the transparent color in the above example, you could just write AX BY 00. This also saves some space.
Mirroring
 
===Mirroring===


Mirroring is when you have one loop where all the cels are a mirror image of the corresponding cels in another loop. Although you could do this manually by drawing one loop and then copying and pasting all the cels to another loop and flipping them horizontally, AGI views provide the ability to have this done automatically -- you can draw one loop, and have another loop which is set as a mirror of this loop. Thus, when you change one loop you change the other. This is useful if you have an animation of a character walking left and right -- you just draw the right-walking animation and have another loop a mirror of this which will have the left-walking animation. Another advantage of cel mirroring is to save space -- it doesn't make much difference these days, but back when AGI was written the games were designed to run on 256K systems which meant that memory had to be used as efficiently as possible.
Mirroring is when you have one loop where all the cels are a mirror image of the corresponding cels in another loop. Although you could do this manually by drawing one loop and then copying and pasting all the cels to another loop and flipping them horizontally, AGI views provide the ability to have this done automatically -- you can draw one loop, and have another loop which is set as a mirror of this loop. Thus, when you change one loop you change the other. This is useful if you have an animation of a character walking left and right -- you just draw the right-walking animation and have another loop a mirror of this which will have the left-walking animation. Another advantage of cel mirroring is to save space -- it doesn't make much difference these days, but back when AGI was written the games were designed to run on 256K systems which meant that memory had to be used as efficiently as possible.
Line 104: Line 113:


It seems that not all versions of the interpreter require this, however -- I was working with version 2.917 when I was testing this out, but I noticed that version 2.440 did not require this. I will attempt to try this with all different interpreters and provide a list of which ones use this in a future version of this document. But it is best to put these bytes in just in case, as the views will still work regardless.
It seems that not all versions of the interpreter require this, however -- I was working with version 2.917 when I was testing this out, but I noticed that version 2.440 did not require this. I will attempt to try this with all different interpreters and provide a list of which ones use this in a future version of this document. But it is best to put these bytes in just in case, as the views will still work regardless.
Description
 
===Description===


All the views in the game that are used as close-ups of inventory items have a description. When a player "examines" these (in some games you can select "see object" from the menu), they will see the first cel of the first loop of this view and the description of the object they are examining. This is brought up using the show.obj command.
All the views in the game that are used as close-ups of inventory items have a description. When a player "examines" these (in some games you can select "see object" from the menu), they will see the first cel of the first loop of this view and the description of the object they are examining. This is brought up using the show.obj command.
Line 212: Line 222:
There are four LOGIC test commands that are to do with VIEWS. These are:
There are four LOGIC test commands that are to do with VIEWS. These are:


<pre>
<syntax type="C++">
     obj.in.box()
     obj.in.box()
     posn()
     posn()
     right.posn()
     right.posn()
     centre.posn()
     centre.posn()
</pre>
</syntax>


All of these commands are for testing whether a VIEW object is within a given rectangle on the screen. All of them take the same parameters and apart from a slight change in each case, they do exactly the same thing and even share about 95% of their code. The general form is the following:
All of these commands are for testing whether a VIEW object is within a given rectangle on the screen. All of them take the same parameters and apart from a slight change in each case, they do exactly the same thing and even share about 95% of their code. The general form is the following:


<pre>
<syntax type="C++">
     command(VIEW object num, left, top, right, bottom)
     command(VIEW object num, left, top, right, bottom)
</pre>
</syntax>


A VIEW has a position stored in its VIEW table entry that says where abouts on the screen the view object is at the present time. The problem with this position is saying which pixel is the position pixel for an object that takes up usually over a hundred pixels. Okay, you might say that most views are actors or props that sit on the ground and therefore the bottom row of pixels will give you a y position. This is a good argument, but now you need to say which of these pixels in the bottom row is the actual position. Sierra must have faced this problem or they wouldn't have provided four commands for achieving essentially the same thing.
A VIEW has a position stored in its VIEW table entry that says where abouts on the screen the view object is at the present time. The problem with this position is saying which pixel is the position pixel for an object that takes up usually over a hundred pixels. Okay, you might say that most views are actors or props that sit on the ground and therefore the bottom row of pixels will give you a y position. This is a good argument, but now you need to say which of these pixels in the bottom row is the actual position. Sierra must have faced this problem or they wouldn't have provided four commands for achieving essentially the same thing.
Line 229: Line 239:
By default the position hot spot in a VIEW is the bottom left pixel.
By default the position hot spot in a VIEW is the bottom left pixel.


<pre>
     .........
     .........
     .........
     .........
Line 237: Line 246:
     .........
     .........
     X........
     X........
</pre>


This is the location that gets stored in the VIEW object table. The difference between the test commands given above is how they adjust the x position before testing it against the rectangle border lines. posn Leaves the x position as it is (left side). right.posn adds (xsize-1) to the x position giving the right side. center.posn adds (xsize/2) to the x position giving the centre. obj.in.box tests both the left and right sides which essentially tests whether the whole bottom row of pixels is in the "box".
This is the location that gets stored in the VIEW object table. The difference between the test commands given above is how they adjust the x position before testing it against the rectangle border lines. posn Leaves the x position as it is (left side). right.posn adds (xsize-1) to the x position giving the right side. center.posn adds (xsize/2) to the x position giving the centre. obj.in.box tests both the left and right sides which essentially tests whether the whole bottom row of pixels is in the "box".
Line 243: Line 251:
The test is TRUE if
The test is TRUE if


<pre>
<syntax type="C++">
     (X1 >= left) && (y >= top) && (X2 <= right) && (y <= bottom).
     (X1 >= left) && (y >= top) && (X2 <= right) && (y <= bottom).
</pre>
</syntax>


<span id="Sample"></span>
<span id="Sample"></span>
==Sample code==
==Sample code==


2,051

edits