Введение
Язык программирования GRASS (GRAphics Symbiosis System) — это язык программирования, созданный для создания скриптов 2D векторной графической анимации. Синтаксис GRASS был схож с BASIC, но он включал множество инструкций для задания анимации 2D-объектов, в том числе масштабирование, перемещение и вращение во времени. Эти функции напрямую поддерживались графическим терминалом Vector General 3D, для которого и был разработан GRASS. Он быстро завоевал популярность в художественном сообществе, экспериментировавшем с новым средством компьютерной графики, и наиболее известен тем, что Ларри Куба использовал его для создания оригинальной анимации "атака на Звезду Смерти будет нелегкой" в фильме "Звёздные войны" (1977). В рамках последующего сотрудничества с Midway Games язык был портирован на Z Box от Midway, основанный на процессоре Z80. Эта машина использовала растровую графику и спрайты, что потребовало значительных изменений для поддержки, а также анимации изменения цвета. Эта версия получила название ZGRASS.
GRASS (GRAphics Symbiosis System) is a programming language created to script 2D vector graphics animations. GRASS was similar to BASIC in syntax, but added numerous instructions for specifying 2D object animation, including scaling, translation and rotation over time. These functions were directly supported by the Vector General 3D graphics terminal GRASS was written for. It quickly became a hit with the artistic community who were experimenting with the new medium of computer graphics, and is most famous for its use by Larry Cuba to create the original "attacking the Death Star will not be easy" animation in Star Wars (1977). As part of a later partnership with Midway Games, the language was ported to the Midway's Z80 based Z Box. This machine used raster graphics and a form of sprites, which required extensive changes to support, along with animating color changes. This version was known as ZGRASS.
ТРАС
Оригинальная версия GRASS была разработана Томом ДеФанти для его докторской диссертации в 1974 году в Университете штата Огайо. Она была разработана на PDP 11/45, управляющем дисплеем Vector General 3DR. Как следует из названия, это была чисто векторная графическая машина. GRASS включал в себя ряд команд векторного рисования и мог организовывать их коллекции в иерархию, применяя различные эффекты анимации к целым "деревьям" изображения сразу (хранящиеся в массивах). После окончания университета ДеФанти переехал в Университет Иллинойса в Чикаго. Там он присоединился к Дэну Сандину, и вместе они создали Circle Graphics Habitat (сегодня известную как Лаборатория электронной визуализации, или EVL). Сандин присоединился к университету в 1971 году и создал Sandin Image Processor, или IP. IP был аналоговым компьютером, который принимал два видеовхода, смешивал их, раскрашивал результаты и затем воссоздавал ТВ-выход. Он описал его как видеоверсию синтезатора Moog. ДеФанти подключил существующую систему GRASS в качестве входных данных для IP, создав GRASS/Image Processor, который использовался на протяжении середины 1970-х годов. Чтобы сделать систему более полезной, ДеФанти и Сандин добавили всевозможные "разовые" команды к существующей системе GRASS, но эти изменения также сделали язык значительно более своеобразным. В 1977 году другой член Habitat, Нола Донато, переработал многие контрольные структуры GRASS, приведя их к более общим формам, в результате чего появился значительно более чистый GRASS3. Работа Ларри Кубы над фильмом "Звездные войны" основана на полуавтоматизированной съемке системы GRASS, работающей на 3D-терминале Vector General. VG3D имел внутреннее аппаратное обеспечение, которое выполняло базовые преобразования – масштабирование, вращение и т.д. – в реальном времени, не взаимодействуя с компьютером. Только во время представления новых сцен происходит гораздо более медленная связь с языком GRASS. Это можно увидеть в последовательности: в начальных сценах фильма Звезда Смерти вращается и масштабируется очень быстро, в то время как в более поздних сценах, имитирующих полет вниз по траншее, требуется загружать новые сцены из "деревьев" GRASS. Их можно увидеть появляющимися группами.
ZGRASS и UV-1
В 1977 году ДеФанти познакомился с Джеффом Фредериксеном, разработчиком микросхем, работавшим в Dave Nutting Associates. Nutting получил контракт от Midway, игрового подразделения Bally, на создание стандартизированной микросхемы графического драйвера. Они планировали использовать её в большинстве своих будущих аркадных игр, а также в разрабатываемой ими видеоигровой консоли, которая впоследствии стала Astrocade. Midway проявляла большой интерес к запуску языка GRASS на своей системе и заключила с ДеФанти контракт на его портирование на эту платформу. Над проектом, который они называли Z Box, работали несколько сотрудников Habitat, а также специалисты из Nutting. GRASS3, работающий на Z Box, получил название ZGRASS. Z Box представлял собой растровую графическую машину, в отличие от оригинальных систем GRASS, поэтому, хотя в ZGRASS был сохранен основной стиль GRASS3, в него были добавлены команды, предназначенные для работы с растровыми изображениями. Среди них был обширный набор команд передачи блоками бит для имитации спрайтов, которых не было в аппаратной части. Midway так и не выпустила эту разработку, но Circle использовала её в качестве основы для создания машин Datamax UV 1.
ГРАСС RT/1
Последняя версия GRASS была RT/1 – это порт GRASS на другие платформы, который отделил язык программирования от модели отображения и обеспечил возможность переноса на другие платформы. Версии существовали для MS DOS, Microsoft Windows, платформы SGI с использованием OpenGL, HP UX, AIX, Macintosh и Amiga. Язык остался схожим с более ранними версиями, поэтому причина смены названия остаётся неясной.
Описание
Это описание основано на оригинальных руководствах Bally, а также на описании ACM. Zgrass был основан на стандартном наборе команд BASIC и использовал большую часть его синтаксиса. Отличием Zgrass от BASIC было то, что все команды фактически были функциями и возвращали значения, подобно языку программирования C. Если явного возвращаемого значения не было, ожидалось, что функция вернет 1 в случае успеха и 0 в случае неудачи. Например, команда PRINT PRINT 10 была бы недопустима в BASIC, но в Zgrass она вывела бы 10 1, где 1 – это значение, возвращенное второй командой PRINT, означающее "Я успешно вывела строку '10'". Программы в Zgrass назывались "макросами" и хранились в виде строк. Обе эти особенности были намеренными, поскольку Zgrass позволял любой строке стать программой. Например, MYBOX="BOX 0,0,100,100,2" определяет строку (не требуется символ $ у переменной, как в Microsoft BASIC), содержащую фрагмент кода Zgrass. Просто набрав ее, можно было запустить команды внутри. Эта функция может использоваться вместо более традиционной команды GOSUB из BASIC, но имеет дополнительное преимущество в виде четко определенного имени, в отличие от непрозрачного номера строки. Кроме того, команда остается в форме строки в памяти и может быть обработана во время выполнения стандартными строковыми операциями. Большинство интерпретаторов BASIC того времени преобразовывали входной текст в токенизированную версию, в которой каждая команда заменялась одним числом (обычно длиной в один байт). Это ускоряло выполнение программы, поскольку не требовалось постоянно декодировать команды из строк. Использование строковых макросов в Zgrass затрудняло это, поэтому токенизация не применялась. Вместо этого был включен компилятор, который можно было использовать для любого конкретного макроса, значительно ускоряя его выполнение. Программы часто состояли из смеси скомпилированных и нескомпилированных макросов. Номера строк в Zgrass были необязательными и обычно появлялись только на строках, являющихся целью команды GOTO. Большинство интерпретаторов BASIC требовали номера строк для каждой строки кода, что было связано с их использованием в "редакторе строк" – если нужно было отредактировать определенную строку, ссылаться на нее можно было только по номеру. Zgrass использовал более продвинутый полноэкранный редактор, устраняющий эту необходимость. Zgrass позволял любой строке выступать в качестве "номера строки", и оба варианта были допустимы. Zgrass также включал безымянные переходы, используя инструкцию, которая перемещала выполнение вперед или назад на заданное количество строк. Это важно в Zgrass, поскольку номера строк были необязательными, и разные макросы могли использовать одни и те же метки. Например, некоторые вариации, вероятно, будут найдены во многих фрагментах кода, что может привести к конфликту имен. Использование избежало этой возможности. В соответствии с первоначальным назначением как графического языка, Zgrass включал многочисленные команды для простого рисования. Система координат Zgrass имела одну точку для каждого пикселя в режиме высокого разрешения графического чипа Nutting, что давало сетку 320×202. Astrocade, по замыслу, мог использовать только режим низкого разрешения этого чипа, дисплей 160×101. Чтобы избежать потенциальных проблем с отображением, нулевая точка координатного пространства была помещена в центр экрана. −160 до 160 были допустимыми значениями X, а −101 до 101 – допустимыми значениями Y. Для использования на Astrocade использовались только положительные значения, в то время как на UV 1 было доступно все пространство. Zgrass добавил довольно полный набор функций для работы с массивами, поскольку массивы широко используются в графике. Это включало возможность "захвата" частей дисплея в массив в виде растрового изображения, с которым можно было манипулировать как с любым другим графическим элементом. Это позволило Zgrass включить в язык функциональность, подобную спрайтам, что аппаратное обеспечение Nutting не поддерживало напрямую. Еще одной особенностью, отсутствовавшей в Astrocade, была возможность обрабатывать массивы с разумной скоростью, поэтому UV 1 включал FPU, поставляемый Zilog, для повышения производительности. Zgrass включал три уровня приоритета (называемые "уровнями"), которые позволяли запускать макросы в обычном режиме или на уровнях "переднего плана" или "заднего плана". Это добавило простую форму многозадачности, которая была чрезвычайно полезна в языке, ориентированном на анимацию. Авторы игр могли помещать подпрограммы чтения джойстика в макрос, настроенный на выполнение на заднем плане, и тогда джойстик считывался бы автоматически после завершения текущего макроса рисования. Функции, помещенные на передний план, выполнялись раньше, и часто использовались для таймеров и других задач, требующих "низкой задержки". Zgrass включал функцию, которая вызывала макросы через заданные промежутки времени, что упрощало реализацию таймеров. Zgrass также включал серию команд, которые "перекрывали" CP/M, что позволяло получать доступ к диску без выхода в командную строку. Можно было легко сохранить макросы в именованные файлы и загрузить их тем же способом, что позволяло создавать программы путем загрузки различных макросов с диска в одну большую программу. Команды также автоматически создавали резервную копию каждого сохранения. Аналогичные функции поддерживались для хранения на компакт-кассете, но, странно, синтаксис не был параллельным: команды для диска начинались с D, например, , а команды для кассеты не начинались с T, например, , а скорее с TAPE, например, .
С программами, построенными из случайно выбранных модулей, Zgrass нуждался в лучшем контроле над своими переменными, чем BASIC. В BASIC все переменные "глобальные", поэтому, если два подпрограммы используют одну и ту же переменную, которая часто используется в качестве переменной-счетчика цикла, они могут изменять значения друг друга, что приводит к трудноустранимым проблемам. В Zgrass программист, загружающий два модуля, мог легко обнаружить, что оба используют в качестве счетчика цикла, что могло вызвать проблемы. Для решения этой проблемы Zgrass считал переменные, названные строчными буквами, локальными только для этого макроса, поэтому и были разными переменными, глобальной и локальной соответственно. Странно, но примеры, поставляемые с языком, не широко используют эту функцию, что может сбить с толку новых программистов, которые могут не знать о ее существовании.
With programs constructed from randomly selected modules, Zgrass needed to have better control over its variables than BASIC. In BASIC all variables are "global", so if two subroutines both use the variable , which is very commonly used as a loop index variable, then they could set each other's values which leads to hard to debug problems. Under Zgrass a programmer loading up two modules could easily find that both used as a loop counter, which could cause problems. To address this issue, Zgrass considered variables named with lowercase letters to be local only to that macro, so and were different variables, global and local respectively. Oddly, the examples provided with the language do not make widespread use of this feature, potentially confusing new programmers who might not be aware the feature exists.
Пример
Этот текст создает новый макрос под названием SINCURVE, который можно вызвать, просто введя SINCURVE в командную строку или из других макросов или программ. SINCURVE использует две локальные переменные, x и angle, а также глобальную переменную OFFSET. PROMPT/INPUT является модификацией оригинального BASIC INPUT, который не будет запрашивать ввод, если пользователь введет его в командную строку при вызове макроса. В этом случае ввод SINCURVE приведет к появлению запроса и ожиданию ввода, тогда как ввод SINCURVE 30 пропустит запрос, и OFFSET будет автоматически присвоено значение 30. Это позволяет использовать один и тот же макрос как интерактивно, так и внутри программы в качестве функции. POINT – пример одной из многих графических команд, включенных в язык Zgrass. POINT требует указания координат X и Y, а также цвета. В этом примере пользователь задает OFFSET, который смещает x-позицию кривой на экране, а Y-позиция вычисляется тригонометрической функцией, соответствующим образом увеличенной для отображения (в данном случае, в 80 раз). Цвет задается последним значением, и в этом случае это 3. UV 1 использовал цветовые регистры, поэтому 3 не определял конкретный цвет, а цвет, выбранный из текущей палитры. IF также заслуживает внимания. Он помещает инкремент (x=x+1) перед условием, что обычно недоступно в BASIC. В этом случае IF предписывает вызвать SKIP 2, если условие истинно, что переместит курсор назад на две строки и может быть использовано вместо GOTO, поскольку отсутствует целевой номер строки.