-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblorb-2.0.4.txt
1328 lines (973 loc) · 58.7 KB
/
blorb-2.0.4.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Blorb: An IF Resource Collection Format Standard
Version 2.0.4
Andrew Plotkin <erkyrath@eblong.com>
This is a formal specification for a common format for storing resources
associated with an interactive fiction game file. Resources are data which
the game can invoke, such as sounds and pictures. In addition, the
executable game file may itself be a resource in a resource file. This is a
convenient way to package a game and all its resources together in one file.
Blorb was originally designed solely for the Z-machine, which is capable of
playing sounds (Z-machine versions 3 and up) and showing images (the V6
Z-machine). However, it has been extended for use with other IF systems.
The Glk portable I/O library uses Blorb as a resource format, and therefore
so does the Glulx virtual machine. (See <http://eblong.com/zarf/glk/> and
<http://eblong.com/zarf/glulx/>.) ADRIFT 5 (see
<http://www.adrift.org.uk/>) also uses Blorb, albeit with an extended
format list.
This format is named "Blorb" because it wraps your possessions up in a box,
and because the common save file format was at one point named "Gnusto".
That has been changed to "Quetzal", but I'm not going to let that stop me.
This proposal is longer than I would have liked. However, a large
percentage of it is optional stuff -- optional for either the interpreter
writer, the game author, or both. That may make you feel better. I've also
put in lots of examples, explication, and self-justification.
0: Overall Structure
The overall format will be a new IFF type. The FORM type is 'IFRS'.
The first chunk in the FORM must be a resource index (chunk type 'RIdx'.)
This lists all the resources stored in the IFRS FORM. There must be exactly
one resource index chunk.
The resources are stored in the FORM as chunks; each resource is one chunk.
They do not need to be in any particular order, since the resource index
contains all the information necessary to find a particular resource.
There are several optional chunks which may appear in the file: the release
number (chunk type 'RelN'), the game identifier (chunk type 'IFhd'), and
others defined hereafter. They may occur anywhere in the file after the
resource index.
Several optional chunks may also appear by convention in any IFF FORM: '(c)
', 'AUTH', and 'ANNO'. These may also appear anywhere in the file after the
resource index.
1: Contents of the Resource Index Chunk
4 bytes 'RIdx' chunk ID
4 bytes n chunk length (4 + num*12)
4 bytes num number of resources
num*12 bytes ... index entries
There is one index entry for each resource. (But not for the optional
chunks.) Each index entry is 12 bytes long:
4 bytes usage resource usage
4 bytes number number of resource
4 bytes start starting position of resource
The index entries should be in the same order as the resource chunks in the
file.
The usage field tells what kind of resource is being described. There are
currently four values defined:
* 'Pict': Picture resource
* 'Snd ': Sound resource
* 'Data': Data file resource
* 'Exec': Code resource
The number field tells which resource is being described, from the game's
point of view. For example, when a Z-code game calls @draw_picture with an
argument of 3, the interpreter would find the index entry whose usage is
'Pict' and whose number is 3. For code chunks (usage 'Exec'), the number
should contain 0.
The start field tells where the resource chunk begins. This value is an
offset, in bytes, from the start of the IFRS FORM (that is, from the start
of the resource file.)
Note that the start field must refer to the beginning of a chunk. It is not
strictly required for each resource to refer to a different chunk.
2: Picture Resource Chunks
Each picture is stored as one chunk, whose content is a PNG file, a JPEG
(JFIF) file, or a placeholder rectangle. (Note that these are various
possible formats for a single resource. It is not possible to have a PNG
image and a JPEG image with the same image resource number.)
2.1: PNG Pictures
A PNG resource has a chunk type of 'PNG '.
PNG is a lossless image compression format. The PNG file format is
available at
<http://www.libpng.org/pub/png/>
2.2: JPEG Pictures
A JPEG resource has a chunk type of 'JPEG'.
JPEG is a lossy image compression format, developed for photograph-like
images. For information on JPEG, see
<http://www.jpeg.org/jpeg/>
2.3: Placeholder Pictures
A third form of picture resource is a placeholder rectangle. A rectangle
has only size, but no contents. This format exists to describe the legacy
behavior of some V6 Infocom games (Zork Zero, Shogun, and Arthur). Its
support in interpreters is optional, and its use is strongly discouraged
for any purpose other than conversions of Infocom graphics.
4 bytes 'Rect' chunk ID
4 bytes 8 chunk length
4 bytes width rectangle width
4 bytes height rectangle height
Either or both of the width and height may be zero.
In a Z-code game, a rectangle exists for the purposes of @picture_data and
@erase_picture, but its use in @draw_picture or @picture_table is an error.
The behavior of rectangles in Glulx and other game files is not defined.
[[Thanks to Kevin Bracey for this extension.]]
3: Sound Resource Chunks
Each sound is stored as one chunk, whose content is either an AIFF file, an
Ogg file, a MOD file, or a song file. (Note that these are various possible
formats for a single resource. It is not possible to have an AIFF sound and
a MOD sound with the same sound resource number.)
On the Z-machine, we must consider the problems of how the game knows the
interpreter can play music, and how sampled sounds are played over music.
See the section "Z-Machine Compatibility Issues" later in this document.
(These issues are not relevant to Glk and Glulx.)
3.1: AIFF Sounds
An AIFF (Audio IFF) file has chunk type 'FORM', and formtype 'AIFF'. AIFF
is an uncompressed digital-sample format developed in the late 1980s. The
AIFF format is available at these locations:
<http://www.digitalpreservation.gov/formats/fdd/fdd000005.shtml>
<http://eblong.com/zarf/ftp/aiff-c.9.26.91.ps>
3.2: Ogg Sounds
An Ogg Vorbis file has chunk type 'OGGV'. This is a high-quality (but
lossy) audio compression format, comparable to MP3 (but without the patent
concerns that encumber MP3). The Ogg format is available at:
<http://www.vorbis.com/>
3.3: MOD Sounds
MOD is an Amiga-originated format for music synthesized from note samples.
Over the years, other formats of this type -- generally called "tracker" or
"module music" formats -- have arisen. Blorb supports four: original ".MOD"
files, ImpulseTracker (".IT"), FastTracker 2 Extended (".XM"), and
ScreamTracker 3 (".S3M").
Because tracker-playing libraries typically handle many formats, it is most
practical for Blorb to lump them all together. *Regardless of which tracker
format is used,* the chunk type will be 'MOD '.
The formats are described here:
<http://www.digitalpreservation.gov/formats/fdd/fdd000126.shtml>
This spec does not attempt to distinguish variations within the four
supported formats. (".MOD" is particularly ill-defined, although I have
saved comments on the original MOD format at
<http://eblong.com/zarf/blorb/mod-spec.txt>.) Instead, we recommend that C
implementations embed libmodplug, a public-domain tracker-playing library.
Its home page is:
<http://modplug-xmms.sourceforge.net/>
However, some bug fixes are included in the version packaged with Windows
Glk:
<http://ifarchive.org/if-archive/programming/glk/implementations/>
(Note that it may be safer to compile libmodplug with the
MODPLUG_BASIC_SUPPORT option, which eliminates many obscure tracker formats
that Blorb does not support.)
Where libmodplug is not practical, implementations should use whatever
tracker-playing library claims to support the four formats in question. We
trust, perhaps beyond reason, that implementation differences will not lead
game creators to their doom.
3.4: Song Sounds
*The song file format is deprecated, as of Blorb 2.0.* It is complicated,
non-standard, and hard to use. Its support in interpreters should be
considered optional. However, it will continue to be documented here.
A song file has chunk type 'SONG'. This is similar to a MOD file, but with
no built-in sample data. The samples are instead taken from AIFF sounds in
the resource file. For each sample, the 22-byte sample-name field in the
song should contain the string "SND1" to refer to sound resource 1,
"SND953" to refer to sound resource 953, and so on. Any sound so referred
to must be an AIFF, not a MOD or song. (You can experiment with fractal
recursive music on your own time.)
Each sample record in a MOD or song contains six fields: sample name,
sample length, finetune value, volume, repeat start, repeat length. In a
MOD file, the sample name is ignored by Blorb (it is traditionally used to
store a banner or comments from the author.) In a song file, the sample
name contains a resource reference as described above; but the sample
length, repeat start, and repeat length fields are ignored. These values
are inferred from the AIFF resource. (The repeat start and repeat length
are taken from the sustainLoop of the AIFF's instrument chunk. If there is
no instrument chunk, or if sustainLoop.playMode is NoLooping, there is no
repeat; the repeat start and length values are then considered zero.)
Note that an AIFF need not contain 8-bit sound samples, as a sound built
into a MOD would. A clever sound engine may take advantage of this to
generate higher-quality music. An unclever one can trim (or pad) the AIFF's
data to 8 bits before playing the song. In the worst case, it is always
possible to trim the AIFF data to 8 bits, append it to the song data, fill
in the song's sample records (with the appropriate lengths, etc, from the
AIFF data); the result is a complete MOD file, which can then be played by
a standard MOD engine.
The intent of allowing song files is both to allow higher quality, and to
save space. Note samples are the largest part of a MOD file, and if the
samples are stored in resources, they can be shared between songs.
(Typically note samples will be given high resource numbers, so that they
do not conflict with sounds used directly by the game. However, it is legal
for the game to use a note sample as a sampled-sound effect, if it wants.)
4: Data Resource Chunks
Each data file is stored as one chunk, with chunk type 'TEXT' or 'BINA'
(denoting text or binary data). The format and contents are up to the game
to interpret.
This feature was designed to support Glulx, but data resources can be
accessed by any game format if the interpreter supports them.
For Glulx games (and any other game format which uses the Glk API), the
data format must follow the conventions described in the Glk spec.
(<http://eblong.com/zarf/glk/>, "Resource Streams".)
[[To summarize: if the data file is opened via glk_stream_open_resource(),
then it will be read as a stream of bytes; text will be assumed to be
encoded as Latin-1. If it is opened via glk_stream_open_resource_uni(),
then a 'TEXT' chunk will be assumed to be a stream of characters encoded as
UTF-8; 'BINA' will be assumed to be a stream of big-endian four-byte
integers. If read by lines (glk_get_line_stream(), etc), resource text
should use Unix line breaks in all cases.]]
5: Executable Resource Chunks
There should at most one chunk with usage 'Exec'. [[But see below.]] If
present, its number must be zero. Its content is a VM or game executable.
Its chunk type describes its format:
* 'ZCOD': Z-code
* 'GLUL': Glulx
* 'TAD2': TADS 2
* 'TAD3': TADS 3
* 'HUGO': Hugo
* 'ALAN': Alan
* 'ADRI': ADRIFT
* 'LEVE': Level 9
* 'AGT ': AGT
* 'MAGS': Magnetic Scrolls
* 'ADVS': AdvSys
* 'EXEC': Native executable
[[This list of formats is taken from the Babel format agreement. See
<http://babel.ifarchive.org/> for more information. Most of these
development systems do not support Blorb at the present time; the list is
available for future use. Other executable formats may also be added in the
future. As a convention, the chunk types should be taken from the Babel
format name, converted to upper case and padded (if necessary) with
spaces.]]
[[The EXEC (native) chunk type is not likely to be useful, because it is
underspecified. Nothing (beyond the chunk data itself) indicates what CPU
or operating system the executable is intended for. Again, it is defined
here following the Babel format list.]]
A resource file which contains an executable chunk contains everything
needed to run the executable. An interpreter can begin interpreting when
handed such a resource file; it sees that there is an executable chunk,
loads it, and runs it.
A resource file which does not contain an executable chunk can only be used
in tandem with an executable file. The interpreter must be handed both the
resource file and the executable file in order to begin interpreting.
If an interpreter is handed inconsistent arguments -- that is, a resource
file with no executable chunk, or a resource file with an executable chunk
plus an executable file -- it should complain righteously to the user.
5.1: Multiple Executable Chunks
As of this spec, no IF system puts more than one 'Exec' chunk in a Blorb
file, or has any need to. However, this could change in the future.
One possible use (noted as a comment in earlier versions of this spec) is
to support several loadable libraries or game segments. In such a case,
chunk zero should contain the code to execute first, or at the top level.
Another possibility is to distribute several versions of a game in one
Blorb package. IF platforms are famed for the fragility of their save
files; a player who downloads an updated game file is likely to find that
it no longer loads her old saved games. This could be avoided if the
updated Blorb actually contained multiple game files, one per 'Exec' chunk.
Chunk zero would be the preferred (most recent) game version, but when
loading a save file, the interpreter would select whichever game version
was compatible with it.
6: The Game Identifier Chunk
This identifies which game the resources are associated with. The chunk
type is 'IFhd'.
This chunk is optional; at most one should appear. If it is present, and
the interpreter is given a game file along with a resource file, the
interpreter can check that the game matches the IFhd chunk. If they don't,
the interpreter should display an error. The interpreter may want to
provide a way for the user to ignore or skip this error (for example, if
the user is a game author testing changes to the game file.)
If the resource file contains an executable chunk, there is little reason
to have an IFhd chunk. It is legal, however, as long as the identifier
matches the executable.
For Z-code, the contents of the game identifier chunk are defined in the
common save file format specification, section 5. This spec can be found at
<http://ifarchive.org/if-archive/infocom/interpreters/specification/savefile
_14.txt>
The "Initial PC" field of the IFhd chunk (bytes 10 through 12) has no
meaning for resource files. It should be set to zero.
For Glulx, the contents of the game identifier chunk are defined in the
Glulx specification. This can be found at <http://eblong.com/zarf/glulx/>.
7: The Color Palette Chunk
This contains information about which colors are used by picture resources
in the file. The chunk type is 'Plte'. It is optional, and should not
appear if there are no 'Pict' resources in the file. At most one color
palette chunk should appear.
The format is:
4 bytes 'Plte' chunk ID
4 bytes n chunk length
n bytes ... color data
There are two possibilities for the color data format. The first is an
explicit list of colors. In this case, the data consists of 1 to 256 color
entries. Each entry is three bytes, of the form:
1 byte red value (0 = black, 255 = red)
1 byte green value (0 = black, 255 = green)
1 byte blue value (0 = black, 255 = blue)
The second case is a single byte, which may have either the value 16 or 32
(decimal). 16 indicates that the picture resources are best displayed on a
direct-color display which has 16 or more bits per pixel (5 or more bits
per color component.) 32 indicates that the resources are best displayed
with 32 or more bits per pixel (8 or more bits per color component.)
The two cases are differentiated by checking the chunk length (n). If n is
1, it's a direct color value; if it's a positive multiple of 3, it's a
color list, and the number of entries is the length divided by 3. Any other
length is illegal.
This chunk is only a hint; there is no guarantee about what the interpreter
will do with it. A color list will most likely be useful if the
interpreter's display can only display a limited number of colors (for
example, an 8-bit indexed color device). The interpreter may set the
display to the colors listed in the palette. Or it may set the display to
just some of the colors listed (for example, if it wishes to reserve some
colors for text display, or if it just doesn't have enough colors
available.) Or the interpreter may ignore the palette chunk, or do
something else.
Similarly, if the interpreter finds a "16" or "32" value, it may set the
display to the appropriate bit depth. Or it may set the display to an 8-bit
color cube, and dither the images for display. Or, again, it may ignore the
palette chunk entirely, or do something else.
It is not required that the palette chunk list every color used in the
'Pict' resources. It is not required that the colors in the palette all be
different, or that they all are actually used by 'Pict' resources. It is
not required that the palette have anything to do with the game art at all.
Of course, if you give the interpreter misleading hints, you deserve
whatever you get.
8: The Frontispiece Chunk
The Blorb format generally does not specify how images are loaded and
displayed; that is the province of the game file format. However, it may be
desirable to associate a single image with the game. The image would serve
as a frontispiece, or "cover art".
The exact use of a frontispiece image is left open to invention. An
interpreter may display it before starting a game. Or it might display
frontispieces while the player is *choosing* a game to play (as an aid to
locating a particular game). An index of games might extract the
frontispieces and use them as catalog illustrations.
If present, the frontispiece is simply an ordinary picture resource. It is
singled out as a frontispiece by a chunk with type 'Fspc'; this contains
its image resource number. There may not be more than one 'Fspc' chunk.
The frontispiece image may be of any legal Blorb type (except a placeholder
rectangle). The image may be of any size, but is preferred to be square or
approximately so. This allows interpreters to display frontispieces in a
systematic way, scaling them to fit a layout, without wasting screen space.
(Since the frontispiece image is not loaded by the game file, it may be
used even with game files that do not support graphics, such as the V5
Z-machine. In a graphics-capable game file, it is legal for the
frontispiece image to also be loaded by the game file in the usual way.)
4 bytes 'Fspc' chunk ID
4 bytes 4 chunk length
4 bytes number number of a Pict resource
9: The Resource Description Chunk
For a game to be fully accessible to visually impaired users, it should
provide textual descriptions to be displayed as alternatives to images.
Similarly, audio resources should have textual descriptions as alternatives
for hearing-impaired users.
The resource description chunk allows the Blorb file to offer this
information.
4 bytes 'RDes' chunk ID
4 bytes len chunk length
4 bytes num number of entries
... entries
The entries are variable-length, and look like:
4 bytes usage resource usage
4 bytes number number of resource
4 bytes length length of text (bytes)
length bytes text textual description (UTF-8,
not null-terminated)
There should be at most one entry for each resource -- that is, each
(usage, number) pair.
Resource descriptions are not required, but they are recommended for
significant sounds and images. (Images used for decoration, such as window
borders or text dividers, may not need textual descriptions.) Data and
executable chunks do not need descriptions; if they appear in this chunk,
the interpreter can ignore them.
[[An interpreter with a web interface would apply the textual description
of an image as an "alt" attribute on the <img> tag.]]
10: Metadata
Metadata is a contentious topic, with which the Blorb spec is not entirely
unentangled. (The game identifier and frontispiece chunks are answers to
small parts of the IF metadata problem.)
Rather than entangle ourselves further, we will merely say that metadata
will be stored as XML, in a chunk of type 'IFmd'. The XML structure is
documented in the Babel format agreement; see <http://babel.ifarchive.org/>.
4 bytes 'IFmd' chunk ID
4 bytes n chunk length
n bytes ... XML document (UTF-8 encoding)
The handling of metadata chunks will not be defined here. In particular,
the behavior of an interpreter which finds more than one metadata chunk is
undefined. It is likely to be a good idea to have at most one.
11: Chunks Specific to the Z-machine
The Z-machine's graphics and sound capabilities were added late in
Infocom's history, but early in the history of data format standardization.
As a result, the Z-machine's audio and image models are both too rigid and
too flexible to work well with modern file formats.
To compensate for this, we add additional information to the Blorb file.
Interpreters can use these hints to display the resource information
correctly.
Some of these hints are needed only to handle legacy Infocom games and
their resources. Others will be useful for the creation of new Z-code games.
Each of these chunks is optional; no more than one of each should appear.
11.1: The Release Number Chunk
This chunk is used to tell the interpreter the release number of the
resource file. It is meaningful only in Z-code resource files.
The interpreter passes this information to the game when the @picture_data
opcode is executed with an argument of 0. The release number is a 16-bit
value. The chunk format is:
4 bytes 'RelN' chunk ID
4 bytes 2 chunk length
2 bytes num release number
This chunk is optional. If it is not present, the interpreter should assume
a release number of 0.
11.2: The Resolution Chunk
This chunk contains information used to scale images. The chunk type is
'Reso'. It is optional. This chunk is meaningful only in Z-code resource
files.
A scalable image is one which the author says should be larger when more
space is available, and smaller when less space is available. (Note that
the Z-code game does *not* directly control the scaling of images. The
interpreter controls the scaling of images, in response to the information
in the resolution chunk. The interpreter then provides the scaled size in
response to @picture_data queries, and the game draws its display based on
those queries.)
It is also possible to create images that have a fixed scaling ratio; they
are always scaled up or down by a particular amount, regardless of window
size.
Not all images have to be scalable. Unless the resolution chunk gives
scaling data for an image, that image is assumed to be non-scalable.
Non-scalable images are always displayed at their actual size. (One image
pixel per screen pixel.)
This chunk is optional; if it is not present, then all of the images in
this file are non-scalable.
4 bytes 'Reso' chunk ID
4 bytes num*28+24 chunk length
4 bytes px standard window width
4 bytes py standard window height
4 bytes minx minimum window width
4 bytes miny minimum window height
4 bytes maxx maximum window width
4 bytes maxy maximum window height
num*28 bytes ... image resolution entries
The "standard window size" is the normal size, the author's original chosen
size, for the Z-machine window. It is not the only possible size; a good V6
game should be prepared for any window the interpreter chooses to create.
The idea is that when the Z-machine window is exactly the standard size,
scalable images are presented at their original size. When the Z-machine
window is larger than the standard size, scalable images are scaled up;
when it is smaller, scalable images are scaled down.
The minimum and maximum window sizes are provided as a hint to the
interpreter, when it is choosing a window size. It may also use the
standard window size as a hint for this purpose. (If the interpreter lacks
the ability to choose its own window size, of course, it will ignore these
hints.) The idea is that the minimum and maximum sizes define the range in
which the game can draw itself successfully.
Any or all of minx, miny, maxx, maxy can indicate "no limit in this
direction" by containing a value of zero. However, px and py must contain
non-zero values. Unless the min or max values are zero, it must be true
that minx <= px <= maxx, miny <= py <= maxy.
*Important* note: The standard, minimum, and maximum window size values are
measured in *screen pixels*. Furthermore, unscaled pictures should be drawn
in screen pixels -- one image pixel per screen pixel. (This may seem dumb
as rocks, and maybe it is, but my rationale is presented at the end of this
document.)
Also note that I have not mentioned Z-pixels. This standard does not
concern itself with Z-pixels.
On with the show.
The standard, minimum, and maximum window sizes are followed by a set of
image entries, one for each scalable image. (Non-scalable images do not
have an entry in this table; that's how they are declared to be
non-scalable.) Each image entry is 28 bytes, of the form:
4 bytes number image resource number
4 bytes ratnum numerator of standard ratio
4 bytes ratden denominator of standard ratio
4 bytes minnum numerator of minimum ratio
4 bytes minden denominator of minimum ratio
4 bytes maxnum numerator of maximum ratio
4 bytes maxden denominator of maximum ratio
The number is the picture number; in other words, this entry applies to the
resource whose usage is 'Pict' and whose number matches this value.
The entry then contains a standard, minimum, and maximum image scaling
ratio. Each ratio is a real number, represented by two integers:
* stdratio = ratnum / ratden
* minratio = minnum / minden,
* maxratio = maxnum / maxden.
Minratio can indicate zero ("no minimum limit") by having both minnum and
minden equal to zero. Similarly, maxratio can indicate infinity ("no
maximum limit") by having maxnum and maxden equal to zero. It is illegal to
have only half of a fraction be zero.
To compute the actual scaling ratio for this image, the interpreter must
first compute the overall game scaling ratio, or Elbow Room Factor (ERF).
If the actual game window size is (wx,wy), and the standard window size is
(px,py), then
* ERF = (wx/px) or (wy/py), whichever is smaller.
(Note that if the game's window is exactly its standard size, ERF = 1.0. If
the window is twice the standard size, ERF = 2.0. If the window is three
times the standard width and four times the standard height, then ERF =
3.0, because there's really only enough room for the game's standard layout
to be tripled before it overflows horizontally.)
The scaling ratio R for this image is then determined:
* If ERF*stdratio < minratio, then R = minratio.
* If ERF*sdtratio > maxratio, then R = maxratio.
* If minratio <= ERF*stdratio <= maxratio, then R = ERF*stdratio.
If minratio and maxratio are the same value, then R will always be this
value; ERF and stdratio are ignored in this case. (This indicates a
scalable image with a fixed scaling ratio.)
The interpreter then knows that this image should be drawn at a scale of R
screen pixels per image pixel, both vertically and horizontally. The
interpreter should report this scaled size to the game if queried with
@picture_data (as opposed to the original image size).
Yes, this is an ornate system. The author is free to ignore it by not
including a resolution chunk. If the author wants scaled images, or
variably-scalable images, this system should suffice.
Here are some examples. They're not necessarily examples of good art
design, but they do demonstrate how a given set of desires translate into
images and resolution values. All are for a game with a standard size of
(600,400).
The game wishes a title image that covers the entire window, and all the
resolution should be visible at the standard size. (So if the window is
twice the standard size, the image will be stretched and coarse-looking; if
the window is half the standard size, the image will be squashed and lose
detail.)
* Image size (600,400); stdratio 1.0; minratio zero; maxratio infinity.
The game has a background image of a cave, made from a scanned photograph.
At standard window size, this should cover the entire window, but not all
the detail needs to be visible. If the window is larger, the image should
still cover the entire window; more detail will be visible, up to twice the
standard size (at which point all the resolution should be visible.) If the
window is larger than twice the standard size, the image should not be
stretched farther; instead the game will center it and have blank space
around the edges.
* Image size (1200,800); stdratio 0.5; minratio zero; maxratio 1.0.
The game has small monochrome icons indicating different magical
perceptions, which it will draw interspersed with the text. The icons
should always be drawn at double size, two screen pixels per image pixel,
regardless of the window size.
* Image size (20,20); stdratio 1.0; minratio 2.0; maxratio 2.0. (In
this case, remember, the stdratio value is ignored.)
The game has a graphical compass rose which it will draw in the top left
corner. This should be 1/4 of the window size in the standard case, and
shrink proportionally if the window is smaller. However, if the window is
larger than standard, the rose should not grow; all the extra space can be
allotted for text. All detail (image pixels) should be visible in the
standard case.
* Image size (150,100); stdratio 1.0; minratio zero; maxratio 1.0.
The same compass rose, still to be 1/4 of the window size -- but this time
it is critical that all the image detail be visible when the window is as
small as half-standard (that is, when the rose is 75 by 50 pixels). At
standard scale (150 by 100), it will therefore appear stretched and coarse.
If the window is smaller than half the standard size, the rose should not
shrink beyond 75x50, so that pixels are never lost.
* Image size (75,50); stdratio 2.0; minratio 1.0; maxratio 2.0.
End of verbose examples.
11.3: The Adaptive Palette Chunk
This chunk contains a list of pictures that change their colors according
to the pictures plotted before. The chunk type is 'APal'. It is optional.
This chunk is meaningful only in Z-code resource files.
This format exists to describe the legacy behavior of some V6 Infocom games
(Zork Zero and Arthur). Its support in interpreters is optional, and its
use is strongly discouraged for any purpose other than conversions of
Infocom graphics.
4 bytes 'APal' chunk ID
4 bytes num*4 chunk length
num*4 bytes ... adaptive palette entries
Each entry is 4 bytes, of the form:
4 bytes number picture resource number
If this chunk is present:
* All pictures in the Blorb file will be PNGs or Rects.
* All PNGs will be indexed-color (color type 3).
* All PNGs will use only color indices 2 through 15.
* All PNGs will have no more than 16 entries in their PLTE chunk.
* PNGs may have a tRNS chunk marking color 0 only as fully transparent,
in which case color index 0 may also be used. No other forms of the tRNS
chunk are valid.
However, the following rules still apply from the PNG standard:
* Any bit depth of PNG is valid (1, 2, 4, or 8 bits per pixel).
* The PLTE chunk is required by the PNG standard, and it must have
sufficient entries to cover every color used in the PNG, even in
adaptive-palette pictures.
* The PLTE chunk may not have more entries than can be represented by
the PNG's bit depth.
* The PNGs may have gAMA, cHRM and sRGB or iCCP chunks describing the
color space. Interpreters should make every effort to support at least
gAMA. For the Infocom graphics at least, cHRM, sRGB and iCCP are probably
beyond the call of duty.
These restrictions, though intricate, serve to make the interpreter's life
easier at the expense of constraining the creator. The constraints are
natural given the form of the original Infocom graphics.
The interpreter should keep track of the "Current Palette". This will be a
14-entry table, covering color indices 2-16. For ease of implementation,
this will probably be a 16-entry table, whose first two entries are not
significant.
Whenever a picture *not* listed in the APal chunk is plotted, its palette
(as derived from its PLTE, gAMA, cHRM and sRGB/iCCP chunks) should be
copied into the Current Palette. If its palette has fewer than 16 entries,
then only those entries of the Current Palette are changed. (Possible
interpreter implementation: transform the PNG's PLTE chunk according to the
gAMA, cHRM, sRGB chunks, then copy it into your Current Palette which is
always in the screen color-space. With libpng, use png_get_PLTE, after
calling png_update_info).
Whenever a picture listed in the APal chunk is plotted, its palette should
be ignored, and it should be plotted with the Current Palette. (Possible
interpreter implementation: strip out the PLTE, gAMA, cHRM and sRGB/iCCP
chunks from the PNG, and insert the Current Palette as its PLTE. Or with
libpng, use png_set_PLTE before reading the data).
The behavior is undefined if any adaptive-palette pictures are plotted
before a non-adaptive picture has been plotted.
If picture caching (through @picture_data or otherwise) is implemented,
special attention may need to be paid to ensure that adaptive images that
are cached are still appropriate for the Current Palette when plotted. It
would appear that the Zork Zero does reset the cache after a palette
change, but this has not been exhaustively investigated.
Alternatively, for the full retro-gaming experience, the pictures can be
handled in the same way as the Amiga and IBM MCGA interpreters, as follows:
Use a 16-color screen mode. Copy non-adaptive pictures' palette (apart from
the first two entries) into the screen palette when plotted. Use color
indices 0 and 1 for the window background and text respectively. This
mimics the IBM MGA and Amiga display, where drawing a picture can change
the colors of graphics already on the screen, but it is not the preferred
rendering.
Shogun and Journey do not use any adaptive-palette images, but on some
platforms the effect of pictures already on the screen changing color is
visible. To give an interpreter the ability to do this if desired, and to
signal that optimizations may be possible because of the limited nature of
the graphics, the Blorb files for Shogun and Journey contain an empty APal
chunk.
[[Thanks to Kevin Bracey for this extension.]]
11.4: The Looping Chunk
This chunk contains information about which sounds are looped, in a V3
Z-machine game. The chunk type is 'Loop'. It is optional.
Note that in V5 and later, the @sound_effect opcode determines whether a
sound loops. The looping chunk is ignored. Therefore, this chunk should not
be used at all in Blorb files intended for games which are not V3 Z-machine
games.
The format is:
4 bytes 'Loop' chunk ID
4 bytes num*8 chunk length
num*8 bytes ... sound looping entries
Each entry is 8 bytes, of the form:
4 bytes number sound resource number
4 bytes value repeats
The repeats flag is one if the sound is to be played once; it is zero if
the sound is to repeat indefinitely (until it is stopped or another sound
started.) If there is no entry for a particular sound resource, or if the
looping chunk is absent, the V3 interpreter should assume the flag is one,
and play the sound exactly once.
12: Other Optional Chunks
A resource file can contain extra user-level information in 'AUTH', '(c) ',
and 'ANNO' chunks. These are all optional. An interpreter should not do
anything with these other than ignore them or (optionally) display them.
These chunks all contain simple ASCII text (all characters in the range
0x20 to 0x7E). The only indication of the length of this text is the chunk
length (there is no zero byte termination as in C, for example).
The 'AUTH' chunk, if present, contains the name of the author or creator of
the file. This could be a login name on multi-user systems, for example.
There should only be one such chunk per file.
The '(c) ' chunk contains the copyright message (date and holder, without
the actual copyright symbol). There should only be one such chunk per file.
The 'ANNO' chunk contains any textual annotation that the user or writing
program sees fit to include.
13: Deprecated Chunks
Some older Z-code Blorb files contain an 'SNam' (story name) chunk, which
contains the game's title. The format of this chunk is Unicode UTF-16, with
the 16-bit values stored big-endian. Modern Blorb files should not have an
'SNam' chunk; this information should be stored in the metadata chunk
instead.
14: Presentation and Compatibility
14.1: File Suffixes
Previous versions of the Blorb spec did not discuss file naming. However,
with the relapse of MacOS into filename suffix semantics, it is impossible
for us to pretend that the issue is an implementation detail.
It is always legal for a Blorb file to have a ".blorb" filename suffix.
However, interpreters have a natural interest in locating *their* sort of
Blorb files -- Z-code, Glulx, or so on -- and it is generally easier for
them to do this by filename suffix, rather than by opening each Blorb and
looking at its resource index. Therefore, ".zblorb" and ".gblorb" should be
used to designate Blorb files containing Z-code and Glulx games,
respectively.
On platforms which limit filename suffixes to three characters, the
suffixes ".blb", ".zlb", and ".glb" may be used instead. But this practice,
at least, I can deprecate without qualm. I hope.
14.2: MIME Types
Historically, Blorb files have been associated with the MIME type
application/x-blorb.
We can use the profile feature of MIME to differentiate the contents:
application/x-blorb;profile="zcode" and application/x-blorb;profile="glulx"
for the common virtual machines.
(Previous versions of this spec suggested application/x-blorb-zmachine and
application/x-blorb-glulx. These are now deprecated.)
14.3: Z-Machine Compatibility Issues
The image system presented in this document is fully backwards-compatible
with Infocom's interpreters. Infocom V6 games, such as Arthur, Journey, and
Zork Zero, contain only non-scalable image resources. The game files are
written to deal with both variations in window size and variations in image
size (since the interpreters for different platforms had different window
sizes and different art.) Therefore, if you construct a Blorb file
containing the images from a particular platform (say, the Mac) and give it
the suggested window size of the Infocom Mac interpreter, the game file
will deal with it correctly.
The image system is also sort of forwards-compatible, in the following
sense. If you take a Blorb file whose standard (intended) window size is
the same as the Infocom interpreter's, and break it out into Infocom image
files, the Infocom interpreter should display it correctly. The interpreter
will not scale images, but since the window size is equal to the standard
size, the Blorb rules require the images to be displayed unscaled anyway.
Also, of course, if you take a Blorb file which contains only non-scalable
images, an Infocom interpreter will act correctly, since it will not scale
the images regardless of the standard size.
The sound system is slightly more problematic. A game file can announce
that it uses sound, by setting a header bit; the interpreter can announce
that it does not support sound, by clearing that bit. But there is no way
to distinguish a game that uses sampled sound only, from one that uses
sampled sound and music. (And similarly for the interpreter's support of
samples versus music.) This may be addressed in a future revision of the
Z-machine. In the meantime, games should set that header bit if any kind of
sound is used (samples or music or both.) And interpreters should clear
that bit only if *no* sound support is available. If the interpreter
supports sampled sound but not music, it should leave the header bit set,
announcing that it does "support sound." It should then ignore any request
to play a music resource.
There is also the question of overlapping sounds. The Z-Spec (9.4.2) says
that starting a new sound effect automatically stops any current one. But
it is not desirable that a sound effect such as footsteps should interrupt
the playing of background music. Therefore, the interpreter should amend
this rule, and consider sampled sounds and music to be in seperate
"channels". Samples interrupt samples, and music interrupts music, but one
form of sound does not interrupt the other.
This is an actual variance in the behavior of the Z-machine, and worse, a
variance which depends on data format. (One sound will either stop another,
or not, depending on whether the sound is stored in AIFF (sampled) or
Ogg/MOD (music) format.) We apologize for the ugliness.
Again, future versions of the Z-machine may address this issue, and allow a
more general system where any sound can be overlaid on any other sound, or
interrupt it, as the game desires and regardless of storage format. (After
all, there can be background *sounds* as well as background *music*.) Such
a system would also allow the interpreter to announce its limitations and
capabilities -- whether it can play music, whether it can play two pieces
of music at once, how many sampled sounds it can play at once, etc.
A final, ah, note: The remark at the end of Z-Spec chapter 9, about
sequencing sound effects to simulate the slow Amiga version of "The Lurking
Horror", should not be applied to music sounds. New music should interrupt
old music immediately, regardless of whether keyboard input has occurred
since the old music started.
14.4: Glk Compatibility Issues
The Glk I/O library was designed with portable resources in mind, so there
should be no incompatibility.