http://sulfurzona.ru/
News
Service
Magazine
Software (Battle City Game, Wallpaper manager, Superpad, VG-NOW, Puzzle Game, Netler Internet Browser, ..)
Wing-Thunder Game (fly simulator)
Dune Game (Dune III, Dune IV, Cheats, Forum, ..)
Games free
Turbo Pascal (Assembler, Docs, Sources, Debbugers, ..)
Books (Docs for developers)
Guest book
Компьютерная диагностика двигателя автомобиля (адаптер К-линии)Компьютерная диагностика двигателя автомобиля (адаптер К-линии)
 
 
Скачать игру Крыло-Гром (Wing-Thunder) бесплатно
 
 
 

Паскаль для новичков (часть 40)

 
Спрашивали? Отвечаю…
 

Работаем с графическим режимом 3 (продолжение)

 
Автор: Владислав Демьянишин
 
Паскаль для новичковНас на некоторое время прервали, но я продолжу ;0)
А вот и краткий код подпрограмм PutPixel24BitsVesa, GetPixel24BitsVesa:
 
procedure PutPixel24BitsVesa( X, Y : word; Color : TColor ); assembler;
asm
 mov si,X; shl si,2 {24 bits/color}; mov bx,Y
 …
 int 10h
@a: mov ax,word ptr Color; mov es:[di],ax
 add di,2; mov ax,word ptr Color+2; mov es:[di],ax
end;
 
function GetPixel24BitsVesa( X, Y : word ): TColor; assembler;
asm
 mov si,X; shl si,2; mov bx,Y
 …
 int 10h
@a: mov ax,es:[di]; add di,2; mov dx,es:[di]
end;
 
Так как все дальние подпрограммы уже описаны, то можно закрыть блок директивой {$F-}. Теперь можно перейти к универсальным подпрограммам PutPixel и GetPixel. Они обеспечивают не только вывод и чтение точки, но и проверку выхода ее координат за пределы текущего ограничивающего окна, что позволит избежать вычисления некорректного адреса точки и обращения по нему, стало быть, и аварии.
 
procedure PutPixel( X, Y : integer; Color : TColor );
begin
if (X<0) or (X>=WinRect.Width) then exit;
if (Y<0) or (Y>=WinRect.Height) then exit;
X := X + WinRect.Left;
Y := Y + WinRect.Top;
PutPixelProc(X,Y,Color);
end;
 
function GetPixel( X, Y : integer ): TColor;
begin
GetPixel := 0;
if (X<0) or (X>=WinRect.Width) then exit;
if (Y<0) or (Y>=WinRect.Height) then exit;
X := X + WinRect.Left;
Y := Y + WinRect.Top;
GetPixel := GetPixelProc(X,Y);
end;
 
А вот и те две пресловутые функции, позволяющие получить информацию о видеоадаптере и параметрах поддерживаемых видеорежимов в глобальные переменные VESAInfo и ModeInfo.
 
function GetVESAInfo: boolean; assembler;
asm
 mov ax,4f00h; lea di,VESAInfo; int 10h
 shr ax,8; sub ax,1
end;
 
Данный код вызывает функцию 4f00h видео BIOS’а, которая возвращает информацию об адаптере в переменную типа TVESAInfo, адрес которой должен быть в регистровой паре ES:DI. В регистр AH при успехе возвращает нуль, иначе единицу. Поэтому это значение приходится командами shr ax,8; sub ax,1 преобразовать в тип boolean, где значение true будет означать успех. Интерфейс вызова следующей функции BIOS’а аналогичен, но она в переменную типа TVESAModeInfo возвращает информацию о видеорежиме с номером Mode.
 
function GetVESAModeInfo( Mode : word ): boolean; assembler;
asm
 mov ax,4f01h; mov cx,mode; lea di,ModeInfo
 int 10h; shr ax,8; sub ax,1
end;
 
Процедура инициализации констант базовых цветов:
 
procedure PrepareColors;
begin
clBlack := RGBToColor(0,0,0);
clBlue := RGBToColor(0,0,255);
clGreen := RGBToColor(0,128,0);
clRed := RGBToColor(255,0,0);
clYellow := RGBToColor(255,255,0);
clWhite := RGBToColor(255,255,255);
end;
 
А вот и функция для определения значения параметра GranulShift, то есть длины битового сдвига, соответствующего гранулярности текущего видеорежима:
 
function GetGranulShift( WinGranul : word ): word;
var Count : word;
begin
Count := 0;
while WinGranul <> 64 do begin
          WinGranul := WinGranul shl 1;
          inc( Count );
          end;
GetGranulShift := Count;
end;
 
Тут все просто, и сводится к подсчету количества бит, на которое следует сдвинуть количество 64Кб-ых страниц, чтобы получить количество реальных страниц для текущего адаптера.
  
Очередная функция выполняет подготовку к установке затребованного видеорежима VESA по индексу массива режимов. Для этого вызывается функция GetVESAModeInfo для получения информации о режиме. Если информация получена, то режим поддерживается. Тогда инициализируется параметр GranulShift, затем выполняется установка видеорежима при помощи ассемблерной вставки с вызовом функции $4F02 BIOS’а, а в переменную Res возвращается значение типа boolean, где true – это успех. Завершает функцию код инициализации структур Screen и WinRect. Функция возвращает true в случае успеха.
 
function PrepareVesaMode( Index : word ): boolean;
var Res : boolean;
begin
PrepareVesaMode := false;
if not GetVESAModeInfo(Metrics[Index].mode) then exit;
GranulShift:=GetGranulShift(ModeInfo.WinGranul);
asm
 mov LastPage,$FFFF; mov bx,Screen.Mode
 mov ax,4F02h; int 10h; shr ax,8; sub ax,1
 mov Res,al
end;
PrepareVesaMode := Res;
if Res then begin
   with Screen do begin
     Width := Metrics[Index].Width;
     Height := Metrics[Index].Height;
     BytesPerScanline:=ModeInfo.BytesPerScanline;
     BitsPerPixel := ModeInfo.BitsPerPixel;
     end;
   DefaultWindow;
   end;
end;
 
Функция SetMode обеспечивает установку текстового режима и графических режимов VGA, VESA. При этом, в ней выполняется инициализация процедурных переменных PutPixelProc, GetPixelProc, RGBToColor, а также константы базовых цветов. Функция возвращает true в случае успеха.
 
function SetMode( Index : word ): boolean;
begin
SetMode := false;
Move( Metrics[Index], Screen,
            Sizeof( TVESAGraphMode ) );
case Index of
 0: begin
     asm
      mov ax,Screen.Mode; int 10h
     end;
    PutPixelProc := NilProc;
    GetPixelProc := NilFunc;
    end;
 1: begin
     asm
      mov ax,Screen.Mode; int 10h
     end;
    PutPixelProc := PutPixel8BitsVga;
    GetPixelProc := GetPixel8BitsVga;
    with Screen do begin
            Width := Metrics[Index].Width;
            Height := Metrics[Index].Height;
            BytesPerScanline := Width;
            BitsPerPixel := 8;
            end;
    clGray := 15;
    DefaultWindow;
    end;
2..6: if PrepareVesaMode( Index ) then begin
         PutPixelProc := PutPixel8BitsVesa;
         GetPixelProc := GetPixel8BitsVesa;
         end
         else exit;
7..11: if PrepareVesaMode( Index ) then begin
          PutPixelProc := PutPixel16BitsVesa;
          GetPixelProc := GetPixel16BitsVesa;
          RGBToColor := RGBTo16Bits;
          PrepareColors;
          end
          else exit;
 else if PrepareVesaMode( Index ) then begin
         PutPixelProc := PutPixel24BitsVesa;
         GetPixelProc := GetPixel24BitsVesa;
         RGBToColor := RGBTo24Bits;
         PrepareColors;
         end
         else exit;
end; {case}
SetMode := true;
end;
 
Следующие две подпрограммы реализуют привычный интерфейс включения/выключения видеорежима.
 
function InitGraph( ModeIndex : word ): boolean;
begin
InitGraph := SetMode( ModeIndex );
end;
 
procedure ExitGraph;
begin
if SetMode( VESAText ) then;
end;
 
При установке видеорежима позиция и границы текущего окна совпадают с границами экрана дисплея. Для задания новых параметров окна достаточно создать следующую процедуру:
 
procedure SetWindow( MinX, MinY, MaxX, MaxY : word );
begin
with WinRect do begin
 if MinX>Screen.Width-1 then MinX:=Screen.Width-1;
 Left:=MinX;
 if MinY>Screen.Height-1 then MinY:=Screen.Height-1;
 Top:=MinY;
 if MaxX>Screen.Width-1 then MaxX:=Screen.Width-1;
 Right:=MaxX;
 if MaxY>Screen.Height-1 then MaxY:=Screen.Height-1;
 Bottom := MaxY;
 Width := (Right-Left)+1;
 Height := (Bottom-Top)+1;
 end;
end;
 
При вызове данной процедуры параметры текущего окна задаются в глобальных координатах всего экрана (в пикселях), после чего вывод графики в окне производится в локальных координатах относительно верхнего левого угла окна (0,0). Если возникнет необходимость вернуться к исходному окну, то это легко осуществить с помощью следующей процедуры:
 
procedure DefaultWindow;
begin
with WinRect do begin
         Left := 0;
         Top := 0;
         Right := Screen.Width-1;
         Bottom := Screen.Height-1;
         Width := Screen.Width;
         Height := Screen.Height;
         end;
end;
 
Следующие две процедуры предназначены для чтения/установки текущей палитры для 256-цветных режимов отображения. Для этого используются функции $1017 и $1012 BIOS’а соответственно.
 
procedure GetPalette( var Palette ); assembler;
asm
 mov ax,1017h; mov bx,0; mov cx,256
 les dx,Palette; int 10h
end;
 
procedure SetPalette( var Palette ); assembler;
asm
 mov ax,1012h; mov bx,0; mov cx,256
 les dx,Palette; int 10h
end;
 
На всякий случай оформим процедуру установки текущей страницы видеопамяти для отображения в видеобуфере.
 
procedure SetPage( Index : word ); assembler;
asm
 mov dx,Index; mov LastPage,dx; mov ax,4f05h
 xor bx,bx; int 10h
end;
 
Следующая функция позволяет определить, является ли видеоадаптер VGA-совместимым. Для этого вызывается подфункция 0 функции $1A BIOS’а для получения кода сочетания дисплея. Если функция возвращает значение $1A в регистре AL, то эта функция поддерживается, и тогда можно по значению в регистре BL определить тип дисплея: $00 – нет дисплея; $07 – монохромный VGA; $08 – цветной VGA; $FF – неизвестный тип дисплея. При успехе функция возвращает true.
 
function IsVGA : boolean; assembler;
asm
 mov ah,1ah; mov al,00h; int 10h; cmp al,1ah
 jne @NoVGA
 cmp bl,07h; je @VgaPresent
 cmp bl,08h; je @VgaPresent
@NoVGA: xor ax,ax; jmp @end
@VgaPresent: mov al,1
@end:
end;
 
Еще одна процедура, о которой уже слагают легенды ;0) позволяет дождаться момента, когда луч ЭЛТ-монитора начнет свой обратный ход из нижней строки в верхнюю. Обычно в момент обратного хода луча экран выключен и бит 3 (считать от нуля) регистра состояния дисплея, который доступен для чтения через порт $3DA, установлен в единицу. При этом, если в этот момент рисовать точки на экране, то это позволит избежать побочного эффекта "хлопьев" или мерцания изображения.
 
procedure WaitRetrace; assembler;
asm
 mov dx, 3DAh
@L1: in al,dx; and al,08h; jnz @L1
@L2: in al,dx; and al,08h; jz @L2
end;
 
Наконец, модуль можно завершить блоком инициализации.
 
begin
PutPixelProc := NilProc;
GetPixelProc := NilFunc;
RGBToColor := NilRGBFunc;
end.
 
Подпрограммы данного модуля обеспечивают лишь самые примитивные манипуляции с графикой. Чтобы иметь возможность рисовать на экране линии, окружности, эллипсы, прямоугольники, закрашивать сложные фигуры, рисовать текст и выводить и масштабировать изображения в формате BMP могут пригодиться модули SBRUSH.PAS, FONTS.PAS и BITMAPS.PAS вашего покорного слуги. ;O)
  
Эти модули базируются на возможностях модуля, описанного в данной статье. Освещение этих модулей могло бы занять еще много страниц МК, поэтому я не стану испытывать терпение редакции, и не буду ущемлять других авторов, отбирая у них свободные страницы МК, чем обрекаю себя на голодную смерть ;о) , а просто предложу вам самим скачать с выше указанного сайта все эти модули вместе с примерами и самостоятельно разобраться в них.
 
Данный титанический труд вынудил меня составить материал объемом, равным трем статьям. Спасибо вам за терпение, с которым вы смогли прочесть данный толмут. ;0)
 
Продолжение следует…
 
© Владислав Демьянишин
 

Литература

1. Диалоговая справочная система Norton Guide.
2. VESA BIOS EXTENSION (VBE) Core Functions Version: 2.0
3. Interrupt list by Ralf Brawn v.3.3.
 
На нашем сайте можно не только бесплатно скачать игры, но и документацию и книги по программированию на MIDLetPascal, Turbo Pascal 6, Turbo Pascal 7, Borland Pascal, по программированию устройств Sound Blaster, Adlib, VESA BIOS, справочник Norton Guide и много другой полезной информации для программистов, включая примеры решения реальных задач по созданию резидентных программ.
 

Журнал > Программирование > Паскаль для новичков (Turbo Pascal, Assembler) > Паскаль для новичков (часть 40): Работаем с графическим режимом 3 (продолжение)
 
 
 
 
 
 
На главную страницу На предыдущую страницу На начало страницы