Welcome to the new Friends-of-FPC!

Here you can find all kinds of information about the FreePascal Compiler. We have many tutorials and howtos as well as a selection of tools to help you with your programming. We also have some example codes for you. And if you want to contribute some information/ sources/ tools yourself you can do so.
Also we have finally relaunched the FoFPC forum. It's your chance for some Q&A about everything FreePascal.

Friends-of-FPC

Tutorials: Learn how to code with FreePascal.

Source Codes: A collection of examples, miscellaneous source codes and open source stuff.

Tools and Help Files: Intro- duction of some tools that might help you with FPC.

Community

Forum: Ask or answer questions about the FreePascal Compiler, programming or just babble about coding.

Contribute! Contribute your own Tutorial, Source Codes or Tools and send them to us!

Website

About: Information about Friends-of-FPC.org.

Grundlagen der Grafikprogrammierung - Teil 10 - by Delax

Tach!

Dieses Mal machen wir einen lockeren Teil und binden einfach nur unsere bisherigen Prozeduren in eine eigene Unit. Wieso das? Hauptsächlich der Übersicht wegen. Also auf!

Was ist eine Unit überhaupt? Eine Unit ist eine Art "Prozeduren-Sammlung". Einige Units kennt ihr schon: Windows z.B. - das sind nämlich genau jene, die ihr im Programmkopf einbindet. Sie enthalten lauter kleine Funktionen und Prozeduren, die wir dann von unserem Programm aus nutzen können.

Dennoch können wir nicht einfach "Unit" über unsere Prozeduren schreiben und gut ist. Eine Unit hat einen etwas anderen Aufbau als ein normales Pascal Programm. Eine leere Unit sieht so aus:

UNIT		NAME;

INTERFACE

USES		DATEINAME;

VAR		VARIABLEN;

CONST		KONSTANTEN;

IMPLEMENTATION

END.

Also als erstes wird der Name der Unit angegeben. Dieser muß identisch mit dem Dateinamen der abgespeicherten Unit sein. Wir nennen unsere mal "Toolbox". Dann im INTERFACE stehen alle öffentlich zugänglichen Daten. Jede Variable und Konstante, die hier angegeben wird ist automatisch global, d.h. alle Programme, die die Unit einbinden können sie nutzen. Umgekehrt ist es aber nicht so einfach möglich das eine Unit eine Variable eures Hauptprogrammes nutzt.

Im IMPLEMENTATION Teil steht all das, was intern in der Unit passiert - also auch die eigentlichen Prozeduren und Funktionen. Ohne große Vorrede nun hier unsere Unit "Toolbox":

UNIT		toolbox;

INTERFACE

USES		Windows, Sysutils;

VAR		MaxX, MaxY	: LongInt;

PROCEDURE PutPixel(destiny : pointer; x,y : longint; color1, color2 : byte);
PROCEDURE Line(destiny : pointer; x1,y1,x2,y2 : longint; color1, color2 : byte);
PROCEDURE Circle(destiny : pointer; x0,y0,radius : longint; color1, color2 : byte);

IMPLEMENTATION

PROCEDURE PutPixel(destiny : pointer; x,y : longint; color1, color2 : byte);
  BEGIN
   if (x<0) or (x>MaxX) or (y<0) or (y>MaxY) then exit;

   ASM
     mov edi,destiny

     mov eax,x
     mov ebx,2
     imul ebx
     add edi,eax

     mov eax,MaxX
     imul ebx
     imul y
     add edi,eax

     mov al,color1
     mov [edi],al

     add edi,1
     mov al,color2
     mov [edi],al

   END;
  END;

PROCEDURE Line(destiny : pointer; x1,y1,x2,y2 : longint; color1, color2 : byte);
   Var dx,dy,sx,sy,k : longint;
  BEGIN

   sx:=1;
   sy:=1;
   dx:=x2-x1;
   if dx<0 then begin
    dx:=-dx;
    sx:=-1;
   end;
   dy:=y2-y1;
   if dy<0 then begin
    dy:=-dy;
    sy:=-1;
   end;
   k:=-(dx shr 1);
   PutPixel(destiny,x1,y1,color1, color2);

   while (x1<>x2) or (y1<>y2) do
    if (k>=0) and (y1<>y2) then begin
     inc(y1,sy);
     dec(k,dx);
     PutPixel(destiny,x1,y1,color1, color2);
    end
    else begin
     inc(x1,sx);
     inc(k,dy);
     PutPixel(destiny,x1,y1,color1, color2);
    end;

  END;

PROCEDURE Circle(destiny : pointer; x0,y0,radius : longint; color1, color2 : byte);
Var x,y,p : longint;
  BEGIN

   x:=0;
   y:=-radius;
   p:=y shl 1+3;
   while x<=-y do begin
    PutPixel(destiny,x0+x,y0+y,color1, color2);
    PutPixel(destiny,x0-x,y0+y,color1, color2);
    PutPixel(destiny,x0+x,y0-y,color1, color2);
    PutPixel(destiny,x0-x,y0-y,color1, color2);
    PutPixel(destiny,x0+y,y0+x,color1, color2);
    PutPixel(destiny,x0-y,y0+x,color1, color2);
    PutPixel(destiny,x0+y,y0-x,color1, color2);
    PutPixel(destiny,x0-y,y0-x,color1, color2);
    if p>=0 then begin
     inc(y);
     inc(p,(x+y)shl 2+6);
    end else inc(p,x shl 2+6);
    inc(x);
   end;

  END;

  end.

Hier als Datei zum download

Hand hoch Leute, wem fällt etwas auf? Da oben stehen 2 Variablen namens MaxX und MaxY. Diese brauchen wir ja für unsere PutPixel Routine zum multiplizieren. Allerdings brauchen wir sie auch im Hauptprogramm, um die fenstergröße zu definieren. Da man aber Variablen vom Hauptprogramm schlecht in Units verwenden kann, deklarieren wir sie in der Unit und unser Programm kann sie auch nutzen - wir dürfen nur nicht vergessen sie am Anfang mit Werten zu versorgen!

Die Frage kommt da zwangsläufig auf: wieso sparen wir uns nicht die Angabe der Auflösung und nageln sie auf 640x480 fest? Vorteil: wir könnten uns das deklarieren sparen und außerdem: wenn wir genau den Multiplikator in der PutPixel Prozedur kennen würden könnten wir Binary Shifting nutzen, was sehr viel schneller wäre. Die Antwort lautet: es IST eine Überlegung wert, aber die einstellbare Auflösung hat auch Vorteile: man kann den User entscheiden lassen, welche er gerne hätte - einfach nur ein Auswahlmenu davor basteln.

Im Endeffekt ist das eine Zielfrage: Was will man machen? Genügen einem die 640x460 und will man den Geschwindigkeitsvorteil, dann sollte man die Auflösung fixieren, ansonsten sollte man sie lieber variabel halten.

Das nächste Mal wird etwas bewegt ;)

Delax/ Sundancer Inc.
[delax@sundancerinc.de]

Back to previous page

Useful Links









Link to us