mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 07:59:34 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			359 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			359 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    $Id$
 | 
						|
    This file is part of the Free Pascal run time library.
 | 
						|
    Copyright (c) 1999-2000 by Florian Klaempfl
 | 
						|
    member of the Free Pascal development team
 | 
						|
 | 
						|
    Video unit for Win32
 | 
						|
 | 
						|
    See the file COPYING.FPC, included in this distribution,
 | 
						|
    for details about the copyright.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
						|
 | 
						|
 **********************************************************************}
 | 
						|
unit Video;
 | 
						|
interface
 | 
						|
 | 
						|
{$i videoh.inc}
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
uses
 | 
						|
  windows,dos;
 | 
						|
 | 
						|
{$i video.inc}
 | 
						|
 | 
						|
var
 | 
						|
  OldVideoBuf : PVideoBuf;
 | 
						|
  ConsoleInfo : TConsoleScreenBufferInfo;
 | 
						|
  ConsoleCursorInfo : TConsoleCursorInfo;
 | 
						|
  MaxVideoBufSize : DWord;
 | 
						|
 | 
						|
procedure InitVideo;
 | 
						|
begin
 | 
						|
  ScreenColor:=true;
 | 
						|
  GetConsoleScreenBufferInfo(TextRec(Output).Handle, ConsoleInfo);
 | 
						|
  GetConsoleCursorInfo(TextRec(Output).Handle, ConsoleCursorInfo);
 | 
						|
 | 
						|
  with ConsoleInfo.srWindow do
 | 
						|
    begin
 | 
						|
       ScreenWidth:=right-left+1;
 | 
						|
       ScreenHeight:=bottom-top+1;
 | 
						|
    end;
 | 
						|
 | 
						|
  { srWindow is sometimes bigger then dwMaximumWindowSize
 | 
						|
    this led to wrong ScreenWidth and ScreenHeight values PM }
 | 
						|
  { damned: its also sometimes less !! PM }
 | 
						|
  with ConsoleInfo.dwMaximumWindowSize do
 | 
						|
    begin
 | 
						|
       {if ScreenWidth>X then}
 | 
						|
         ScreenWidth:=X;
 | 
						|
       {if ScreenHeight>Y then}
 | 
						|
         ScreenHeight:=Y;
 | 
						|
    end;
 | 
						|
 | 
						|
  { TDrawBuffer only has FVMaxWidth elements
 | 
						|
    larger values lead to crashes }
 | 
						|
  if ScreenWidth> FVMaxWidth then
 | 
						|
    ScreenWidth:=FVMaxWidth;
 | 
						|
 | 
						|
  CursorX:=ConsoleInfo.dwCursorPosition.x;
 | 
						|
  CursorY:=ConsoleInfo.dwCursorPosition.y;
 | 
						|
  if not ConsoleCursorInfo.bvisible then
 | 
						|
    CursorLines:=0
 | 
						|
  else
 | 
						|
    CursorLines:=ConsoleCursorInfo.dwSize;
 | 
						|
 | 
						|
  { allocate back buffer }
 | 
						|
  MaxVideoBufSize:= ScreenWidth * ScreenHeight * 2;
 | 
						|
  VideoBufSize:=ScreenWidth*ScreenHeight*2;
 | 
						|
 | 
						|
  GetMem(VideoBuf,MaxVideoBufSize);
 | 
						|
  GetMem(OldVideoBuf,MaxVideoBufSize);
 | 
						|
 | 
						|
  {ClearScreen; not needed PM }
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure DoneVideo;
 | 
						|
begin
 | 
						|
  { ClearScreen; also not needed PM }
 | 
						|
  SetCursorType(crUnderLine);
 | 
						|
  { SetCursorPos(0,0); also not needed PM }
 | 
						|
  FreeMem(VideoBuf,MaxVideoBufSize);
 | 
						|
  FreeMem(OldVideoBuf,MaxVideoBufSize);
 | 
						|
  VideoBufSize:=0;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function GetCapabilities: Word;
 | 
						|
begin
 | 
						|
  GetCapabilities:=cpColor or cpChangeCursor;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure SetCursorPos(NewCursorX, NewCursorY: Word);
 | 
						|
var
 | 
						|
  pos : COORD;
 | 
						|
begin
 | 
						|
   pos.x:=NewCursorX;
 | 
						|
   pos.y:=NewCursorY;
 | 
						|
   SetConsoleCursorPosition(TextRec(Output).Handle,pos);
 | 
						|
   CursorX:=pos.x;
 | 
						|
   CursorY:=pos.y;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function GetCursorType: Word;
 | 
						|
begin
 | 
						|
   GetConsoleCursorInfo(TextRec(Output).Handle,ConsoleCursorInfo);
 | 
						|
   if not ConsoleCursorInfo.bvisible then
 | 
						|
     GetCursorType:=crHidden
 | 
						|
   else
 | 
						|
     case ConsoleCursorInfo.dwSize of
 | 
						|
        1..30:
 | 
						|
          GetCursorType:=crUnderline;
 | 
						|
        31..70:
 | 
						|
          GetCursorType:=crHalfBlock;
 | 
						|
        71..100:
 | 
						|
          GetCursorType:=crBlock;
 | 
						|
     end;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure SetCursorType(NewType: Word);
 | 
						|
begin
 | 
						|
   GetConsoleCursorInfo(TextRec(Output).Handle,ConsoleCursorInfo);
 | 
						|
   if newType=crHidden then
 | 
						|
     ConsoleCursorInfo.bvisible:=false
 | 
						|
   else
 | 
						|
     begin
 | 
						|
        ConsoleCursorInfo.bvisible:=true;
 | 
						|
        case NewType of
 | 
						|
           crUnderline:
 | 
						|
             ConsoleCursorInfo.dwSize:=10;
 | 
						|
 | 
						|
           crHalfBlock:
 | 
						|
             ConsoleCursorInfo.dwSize:=50;
 | 
						|
 | 
						|
           crBlock:
 | 
						|
             ConsoleCursorInfo.dwSize:=99;
 | 
						|
        end
 | 
						|
     end;
 | 
						|
   SetConsoleCursorInfo(TextRec(Output).Handle,ConsoleCursorInfo);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
function DefaultVideoModeSelector(const VideoMode: TVideoMode; Params: Longint): Boolean;
 | 
						|
begin
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure ClearScreen;
 | 
						|
begin
 | 
						|
  FillWord(VideoBuf^,VideoBufSize div 2,$0720);
 | 
						|
  UpdateScreen(true);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
{$IFDEF FPC}
 | 
						|
function WriteConsoleOutput(hConsoleOutput:HANDLE; lpBuffer:pointer; dwBufferSize:COORD; dwBufferCoord:COORD;
 | 
						|
   var lpWriteRegion:SMALL_RECT):WINBOOL; external 'kernel32' name 'WriteConsoleOutputA';
 | 
						|
{$ENDIF}
 | 
						|
 | 
						|
procedure UpdateScreen(Force: Boolean);
 | 
						|
type TmpRec = Array[0..(1024*32) - 1] of TCharInfo;
 | 
						|
 | 
						|
type WordRec = record
 | 
						|
                  One, Two: Byte;
 | 
						|
               end; { wordrec }
 | 
						|
 | 
						|
var
 | 
						|
   BufSize,
 | 
						|
   BufCoord    : COORD;
 | 
						|
   WriteRegion : SMALL_RECT;
 | 
						|
   LineBuf     : ^TmpRec;
 | 
						|
   BufCounter  : Longint;
 | 
						|
   LineCounter,
 | 
						|
   ColCounter  : Longint;
 | 
						|
   smallforce  : boolean;
 | 
						|
{
 | 
						|
begin
 | 
						|
  if LockUpdateScreen<>0 then
 | 
						|
   exit;
 | 
						|
  if not force then
 | 
						|
   begin
 | 
						|
     asm
 | 
						|
        movl    VideoBuf,%esi
 | 
						|
        movl    OldVideoBuf,%edi
 | 
						|
        movl    VideoBufSize,%ecx
 | 
						|
        shrl    $2,%ecx
 | 
						|
        repe
 | 
						|
        cmpsl
 | 
						|
        setne   force
 | 
						|
     end;
 | 
						|
   end;
 | 
						|
  if Force then
 | 
						|
   begin
 | 
						|
      BufSize.X := ScreenWidth;
 | 
						|
      BufSize.Y := ScreenHeight;
 | 
						|
 | 
						|
      BufCoord.X := 0;
 | 
						|
      BufCoord.Y := 0;
 | 
						|
      with WriteRegion do
 | 
						|
        begin
 | 
						|
           Top :=0;
 | 
						|
           Left :=0;
 | 
						|
           Bottom := ScreenHeight-1;
 | 
						|
           Right := ScreenWidth-1;
 | 
						|
        end;
 | 
						|
      New(LineBuf);
 | 
						|
      BufCounter := 0;
 | 
						|
 | 
						|
      for LineCounter := 1 to ScreenHeight do
 | 
						|
        begin
 | 
						|
           for ColCounter := 1 to ScreenWidth do
 | 
						|
             begin
 | 
						|
               LineBuf^[BufCounter].UniCodeChar := WordRec(VideoBuf^[BufCounter]).One;
 | 
						|
               LineBuf^[BufCounter].Attributes := WordRec(VideoBuf^[BufCounter]).Two;
 | 
						|
 | 
						|
               Inc(BufCounter);
 | 
						|
             end; { for }
 | 
						|
        end; { for }
 | 
						|
 | 
						|
      WriteConsoleOutput(TextRec(Output).Handle, LineBuf, BufSize, BufCoord, WriteRegion);
 | 
						|
      Dispose(LineBuf);
 | 
						|
 | 
						|
      move(VideoBuf^,OldVideoBuf^,VideoBufSize);
 | 
						|
   end;
 | 
						|
end;
 | 
						|
}
 | 
						|
var
 | 
						|
   x1,y1,x2,y2 : longint;
 | 
						|
 | 
						|
begin
 | 
						|
  if LockUpdateScreen<>0 then
 | 
						|
   exit;
 | 
						|
  if force then
 | 
						|
   smallforce:=true
 | 
						|
  else
 | 
						|
   begin
 | 
						|
     asm
 | 
						|
        movl    VideoBuf,%esi
 | 
						|
        movl    OldVideoBuf,%edi
 | 
						|
        movl    VideoBufSize,%ecx
 | 
						|
        shrl    $2,%ecx
 | 
						|
        repe
 | 
						|
        cmpsl
 | 
						|
        orl     %ecx,%ecx
 | 
						|
        jz      .Lno_update
 | 
						|
        movb    $1,smallforce
 | 
						|
.Lno_update:
 | 
						|
     end;
 | 
						|
   end;
 | 
						|
  if SmallForce then
 | 
						|
   begin
 | 
						|
      BufSize.X := ScreenWidth;
 | 
						|
      BufSize.Y := ScreenHeight;
 | 
						|
 | 
						|
      BufCoord.X := 0;
 | 
						|
      BufCoord.Y := 0;
 | 
						|
      with WriteRegion do
 | 
						|
        begin
 | 
						|
           Top :=0;
 | 
						|
           Left :=0;
 | 
						|
           Bottom := ScreenHeight-1;
 | 
						|
           Right := ScreenWidth-1;
 | 
						|
        end;
 | 
						|
      New(LineBuf);
 | 
						|
      BufCounter := 0;
 | 
						|
      x1:=ScreenWidth+1;
 | 
						|
      x2:=-1;
 | 
						|
      y1:=ScreenHeight+1;
 | 
						|
      y2:=-1;
 | 
						|
      for LineCounter := 1 to ScreenHeight do
 | 
						|
        begin
 | 
						|
           for ColCounter := 1 to ScreenWidth do
 | 
						|
             begin
 | 
						|
               if (WordRec(VideoBuf^[BufCounter]).One<>WordRec(OldVideoBuf^[BufCounter]).One) or
 | 
						|
                 (WordRec(VideoBuf^[BufCounter]).Two<>WordRec(OldVideoBuf^[BufCounter]).Two) then
 | 
						|
                 begin
 | 
						|
                    if ColCounter<x1 then
 | 
						|
                      x1:=ColCounter;
 | 
						|
                    if ColCounter>x2 then
 | 
						|
                      x2:=ColCounter;
 | 
						|
                    if LineCounter<y1 then
 | 
						|
                      y1:=LineCounter;
 | 
						|
                    if LineCounter>y2 then
 | 
						|
                      y2:=LineCounter;
 | 
						|
                 end;
 | 
						|
               LineBuf^[BufCounter].UniCodeChar := WordRec(VideoBuf^[BufCounter]).One;
 | 
						|
               { If (WordRec(VideoBuf^[BufCounter]).Two and $80)<>0 then
 | 
						|
                 LineBuf^[BufCounter].Attributes := $100+WordRec(VideoBuf^[BufCounter]).Two
 | 
						|
               else }
 | 
						|
                 LineBuf^[BufCounter].Attributes := WordRec(VideoBuf^[BufCounter]).Two;
 | 
						|
 | 
						|
               Inc(BufCounter);
 | 
						|
             end; { for }
 | 
						|
        end; { for }
 | 
						|
      BufSize.X := ScreenWidth;
 | 
						|
      BufSize.Y := ScreenHeight;
 | 
						|
 | 
						|
      with WriteRegion do
 | 
						|
        begin
 | 
						|
           if force then
 | 
						|
             begin
 | 
						|
               Top := 0;
 | 
						|
               Left :=0;
 | 
						|
               Bottom := ScreenHeight-1;
 | 
						|
               Right := ScreenWidth-1;
 | 
						|
               BufCoord.X := 0;
 | 
						|
               BufCoord.Y := 0;
 | 
						|
             end
 | 
						|
           else
 | 
						|
             begin
 | 
						|
               Top := y1-1;
 | 
						|
               Left :=x1-1;
 | 
						|
               Bottom := y2-1;
 | 
						|
               Right := x2-1;
 | 
						|
               BufCoord.X := x1-1;
 | 
						|
               BufCoord.Y := y1-1;
 | 
						|
             end;
 | 
						|
        end;
 | 
						|
      {
 | 
						|
      writeln('X1: ',x1);
 | 
						|
      writeln('Y1: ',y1);
 | 
						|
      writeln('X2: ',x2);
 | 
						|
      writeln('Y2: ',y2);
 | 
						|
      }
 | 
						|
      WriteConsoleOutput(TextRec(Output).Handle, LineBuf, BufSize, BufCoord, WriteRegion);
 | 
						|
      Dispose(LineBuf);
 | 
						|
 | 
						|
      move(VideoBuf^,OldVideoBuf^,VideoBufSize);
 | 
						|
   end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure RegisterVideoModes;
 | 
						|
begin
 | 
						|
  { don't know what to do for win32 (FK) }
 | 
						|
  RegisterVideoMode(80, 25, True, @DefaultVideoModeSelector, $00000003);
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
initialization
 | 
						|
  RegisterVideoModes;
 | 
						|
 | 
						|
finalization
 | 
						|
  UnRegisterVideoModes;
 | 
						|
end.
 | 
						|
{
 | 
						|
  $Log$
 | 
						|
  Revision 1.1  2001-01-13 11:03:59  peter
 | 
						|
    * API 2 RTL commit
 | 
						|
 | 
						|
}
 | 
						|
 |