home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Misc / DEMOMANIAC100%.DMS / in.adf / DM_DOC&DOK.lha / VECTOR.DOK < prev   
Encoding:
Text File  |  1992-09-02  |  74.1 KB  |  2,002 lines

  1.  
  2.                          0. SOME WORDS IN ADVANCE
  3.  
  4.      This is V1.23 of the famous DemoManiac - Supplied by vADIUM/aVT!
  5.  
  6. This version is a bugfixed version of V1.21. We also added all examples
  7. and docs of V1.21 to release a full & complete version of this cool program.
  8.  
  9.                           This package includes:
  10.  
  11.                           - English & German Docs
  12.                           - Vector-Doc for DemoManiac
  13.                           - all Examples/Tutorials
  14.  
  15.                             ~~~ Vector 100%  ~~~
  16.  
  17.  
  18. Immer schneller,immer echter und immer complexer (yeah!). Das ist der trend bei
  19. Vectorgraphic. Hatte man vor ein paar Jahren (ja,ja damals) die Leute noch
  20. mit Linevector beeindrucken können so muß es heute Shading,Texturekarting,Shadows
  21. und son neumodischen Zeugs sein.
  22. Aber lassen wir den Einleitungs-quatsch! Mein Rechner traced gerade so vor sich 
  23. hin (ja,ja auch ich bin der Sucht verfallen) und ich kann nicht schlafen also
  24. schreib ich euch (ja euch alle da draußen mein ich ! ) mal wieder(?) nen 
  25. Wörkschop ! Diesmal möchte ich mein gesammeltes Wissen über RICHTIGEN VECTOR
  26. an den mann/den coder bringen (soviel isses zwar nich,aber immerhin).
  27. Also zunächst einmal : Umdenken! für Alle die noch immer den Blitter für Vector
  28. nutzen. Ja richtig ich will euch heute in den erlesenen (hüstel) Kreis der
  29. Processor-vector-könner erheben (sülz) damit wir von nun an gemeinsam auf
  30. die runterblicken können die noch keinen Durchblick haben ....
  31.  
  32. Die 1. DIMENSION
  33. ----------------
  34.  
  35. Ist Langweilig (geht ja gut los...) weil sie nur Punkte enthält und daher
  36. auch noch von (hoffentlich) jedem beherrscht wird ! Wer schreibt die schnellste
  37. Punkt-setz-routiene ??
  38.  
  39. Die 2. DIMENSION
  40. ----------------
  41.  
  42. Ist schon viel besser! da wir hier den ALLER,ALLER WICHTIGSTEN Baustein des
  43. Processorvectors finden : DIE LINIE (tatatataaa)
  44.  
  45. Damit können wir folgendes anstellen:
  46.         - sehr schneller inkonvexer (überscheidender) Vector
  47.         - pencil vector
  48.         - gouraud shading
  49.         - texturemapping
  50.         - wolfenstein
  51.         
  52.  
  53. Also einige nette Sachen ! Und das alles schneller als mit dem Blitter obwohl
  54. der im linienzeichnen (einfarbig,ohne unterbrechungen) 2mal schneller ist
  55. als die BESTE Processorroutiene auf einem 68020 mit 14mhz...
  56.  
  57.  
  58.  
  59. DIE LINIE
  60. ---------
  61.  
  62. Also, fangen wir bei 0 an : Wir wollen eine Linie zeichnen von X1/Y1 nach 
  63. X2/Y2 also nehmen wir die aus der guten(?) alten(!) Schule bekannte Formel:
  64.  
  65.     Y=m*x+b
  66.  
  67. Und merken das wir damit noch keine Linie hinkriegen! Also nehmen wir die
  68. schon viel weniger geliebte 'Zeipunkteform' und stellen diese um :
  69. (so hat meine ERSTE linienroutiene,in Basic, funktioniert)
  70.  
  71.    y-y1     x2-x1      
  72.   ------ = -------                  | *(x-x1)
  73.    x-x1     y2-y1
  74.  
  75.             x2-x1
  76.    y-y1  = ------- * (x-x1)         | +y1
  77.             y2-y1 
  78.  
  79.             x2-x1
  80.       y  = ------- * (x-x1) +y1       
  81.             y2-y1 
  82.  
  83. Und schon haben wir ne tolle Formel um ganz prima Linien zu zeichnen ! 
  84. Juhu! Aber leider ist sie nicht besonders schnell (fließkomma multiplikation
  85. bei jedem punkt ect...) und sie ist leider auch nicht besonders genau (weil
  86. fließkommazahlen beschränkt (je nach Sprache) ) so daß die Linien meistens
  87. am Ziel vorbeischießen oder 'zerreißen' und und und
  88. Also kurz und gut dieser Ansatz war völlige ZEITVERSCHWENDUNG !
  89.  
  90. Nun wir würden uns wohl noch alle in dieser Linien-Steinzeit befinden
  91. (selbst ich! obwohl ich noch andere tolle ideen hatte...wurzel ect...)
  92. wenn nicht... Ja wenn nicht der geniale Herr Bresenham gekommen wäre !
  93. (ober gekommen ist war zwar relativ egal hauptsache er hat nachgedacht)
  94.  
  95. BRESENHAM- dieses Zauberwort hat jeder(?) Coder schon mal gehört und weiß das
  96. ist irgentwas schnelles,geniales und kurzes was keiner versteht und jeder 
  97. benutzt....
  98. Doch was ist das eigentlich DER BRESENHAM-ALGORITHMUS ? und wie funktioniert
  99. er ? und wie kam der Typ auf son genialen Kram ? und was sollen diese blöden
  100. fragen ?
  101.  
  102. Nun ich will versuchen es dir,lieber Leser, (da du mich bis jetzt ertragen hast)
  103. zu erklären....
  104.  
  105.  
  106.  
  107. Nun, der gute Bresenham hat,scharfsinnig wie Mathematiker nunmal sind, 
  108. erkannt was bei den konventionellen Linien-algorithmen so viel Zeit kostet :
  109. Die komplette Nueberechnung der Koordinaten für jeden Punkt !
  110. und die anschließende Umrechnung der Fließkommakoordinaten in 'richtige' !
  111.  
  112. Was ? Das hättest du ihm auch sagen können ? Tja soweit ist alles noch ganz
  113. Banal (MERKE : WICHTIGE FRAGE - WAS BRAUCHT HIER SOVIEL ZEIT !) .
  114. Also phantasierte unser Bresie ... es wäre doch echt geil wenn man aus einer
  115. Bildschirmkoordinate gleich die nächste berechnen könnte.
  116. (MERKE: GEDANKEN FREIEN LAUF LASSEN UM ANDERE LÖSUNGSWEGE ZU FINDEN - VIELE
  117. SCHWACHSINNIGE ABER VIELLEICHT IST JA DER EINE GUTE DABEI..)
  118.  
  119. Aber auch der kluge Bresie kam mit klugen Gedanken nicht weiter! Also tat er
  120. das was man immer tun sollte wenn ein Problem zu groß ist/scheit : Er 
  121. zerteilte es in Teilprobleme und lößte erstmal eines davon !
  122.  
  123. Er sagte sich also : gesetzt den Fall (ja ja so denken Mathematiker...) die
  124. Linie die ich zeichnen soll liegt garantiert im ERSTEN OKTANTEN dann...
  125. HA!! erwischt ! Es weiß wieder keiner wo der 1.Oktant sein soll ! 
  126. Also noch mal für alle :
  127.                  \ 3|2 /
  128.                 4 \ | / 1     (beispiel : okt2 :  45°- 90°)
  129.                 ---------       (           okt5 : 180°-225°)
  130.                 5 / | \ 8
  131.                  / 6|7 \
  132.  
  133. Sagen wir also jemand zeichnet eine Linie im ersten Oktanten (keine ganz
  134. einfache also nicht genau 0° und nicht genau 45°) aber irgenteine nette
  135. Linie halt.
  136.  
  137.             _-¯    <-Das ist sie !
  138.  
  139. Dan wird er/sie/es wohl zunächst den Startpunkt setzen. Von da aus gibt es 
  140. nun 2 möglichkeiten wohin der nächste Punkt muß :
  141.  
  142.     1. Direkt rechts neben den 1.Punkt
  143.     2. Rechts und oberhalb des 1.Punktes 
  144.  
  145. Alles Andere geht im 1.Okt nicht ! - Bitte nachvollziehen !
  146. Hätte die Linie nun die Steigung 1 (45°) dann wäre es für jeden Punkt der
  147. Fall 2.
  148. Hätte sie die Steigung 0 (0°) dann wäre es immer fall 1 (waagerecht).
  149. Sonst wechseln sich die beiden fälle endsprechend der Steigung immer ab.
  150.  
  151. Aber wie trifft man nun die Entscheidung welche der beiden Möglichkeiten
  152. verwendet werden soll ? 
  153. Bresenham verwendet hier einen FehlerTerm ! Mit dem er entscheiden kann welcher
  154. der beiden Punkte denn nun näher an der 'echten' Linie liegt.
  155. Der fehlerterm ist also quasi der Abstand von der 'echten' zu 'bildschirm'-linie
  156. Mathematisch gesehen ist der Fehlerterm der Nachkommateil den man bei den
  157. 'alten'-Algorithmen von den Koordinaten abgetrennt hat um aus Fließkomma-
  158. koordinaten Bildschirm-koordinaten zu machen. (klar ?)
  159. Ein kleines Beispiel:
  160.    mit dem y=(x2-x1)/(y2-..... Algorithmus kam für Y z.B : 5.783 raus !
  161.    Also schnitten wir 0,783 ab und setzten den Punkt an Y=5.
  162.    Der Fehlerwert für diesen Fall wäre also 0,783 ! Der Punkt war 0,8 falsch!
  163.  
  164. Na ja..Bresenham berechnet diesen Nachkommateil also ,sogesehen, von den
  165. Koordinaten getrennt. Die genaue Fehlerterm-formel kenne ich auch nicht aber
  166. so tief müssen wir ja auch nicht einsteigen um es zu verstehen.
  167. Er geht nun immer einen Schritt nach rechts und zählt dabei mit wie falsch
  168. seine Linie wird. Bei Steigung 0 würde sie nie falsch werden aber bei jeder
  169. anderen Steigung würde die Linie mit jedem Punkt 'falscher' werden.
  170. Wenn sie nun 'zu falsch' ist mach er einfach noch einen Schritt nach oben
  171. und zieht wieder etwas vom fehler-counter ab,weil die Linie ja nun etwas
  172. richtiger geworden ist...
  173.  
  174. Bresenhams Prinzip in Kurzform:
  175.  
  176.     -Inialisieren eines Fehlerwertzählers
  177.     -Punkt setzten
  178.     -einen Wert auf den Fehlercounter addierten 
  179.     -Wenn Fehler nun zu groß geworden dann...
  180.            -schritt in die andere Richtung 
  181.            -und etwas vom Fehlerwert abziehen (linie wieder besser)
  182.         -Sonst wieder punkt setzten...
  183.  
  184.  
  185. Warum man den Fehlercounter mit M inialisieren muß und immer M addieren muß
  186. und warum der 'schwellwert' genau 0,5 ist das hängt damit zusammen wie
  187. der Fehlerterm eigentlich aussah (steigung...maximal 1.....) aber wie gesagt 
  188. so tief will/kann ich hier nicht einsteigen.
  189.  
  190. Also das alles in einem Listing:
  191.  
  192.     dx=x2-x1
  193.     dy=y2-y1
  194.     
  195.     m=dy/dx
  196.     fehler=m
  197.  
  198.     while    x1<x2
  199.       plot    x1,y2
  200.       if fehler>0,5 then
  201.          fehler=fehler-1                         
  202.          y1=y1+1            'wenn über schwellwert dann UPRIGHT
  203.       end if
  204.       fehler=fehler+m
  205.       x1=x1+1            'sonst nur RIGHT
  206.     wend
  207.  
  208. Das soll er also sein ? Der tolle Bresenham-algorithmus ? 
  209. Mit Fließkomma-addition und -division ? Na Toll ! Aber Bresenham hat an
  210. diesem Punkt nicht aufgegeben und resigniert ! sondern er hat das wofür wir
  211. (wir Coder) ihn Heute alle Bewundern (den Einfall hatte er bestimmt aufm Klo!)
  212. getan :
  213.  
  214. Er multiplizerte alle vorkommenden Terme mit 2*DX und zwar nicht aus Frust und
  215. um die Routiene noch langsamer zu machen ! Nein weil... aber sehen wir selbst
  216.  
  217.  
  218.                dy                    dy*2*dx
  219.     aus    M = ----    wird nun  ---------  und daraus  M = 2*DY 
  220.              dx               dx*1 
  221.  
  222.     -Zack- Keine Fließkommazahlen mehr ! Wenn das nicht genial war ? !
  223.  
  224. Aber er tat noch mehr : Den Startwert für den Fehlerterm änderte er von
  225.  
  226. f=m also f=2*dy in f=m-dx also
  227.  
  228. f=2*dy-dx     (er hat ihn also um DX verändert!)
  229.  
  230. Warum ? Nun weil dann der Schwellwert sich von 0,5 auf 0 !!! Ändert ! 
  231. Zwar muß nun auch nicht mehr 1 abgezogen werden wenn der Schwellwert 
  232. überschritten wurde (fehler=fehler-1) sondern nun muß 2*dx abgezogen werden !
  233. aber auch das ist logisch : vorher : -1     (0,5*2 = 1)
  234.                 nun    : -2*dx  (um dx verändert*2 = 2*dx)
  235.  
  236. Um etwas mehr Klarheit (ja noch mehr!) zu schaffen hier ein neues Listing :
  237.  
  238.     dx=x2-x1
  239.     dy=y2-y1
  240.     
  241.     ddx=dx*2
  242.     ddy=dy*2
  243.  
  244.     fehler=ddy-dx
  245.  
  246.     for I=0 to dx
  247.       plot x1,y1
  248.           if fehler>0 then
  249.              fehler=fehler-ddx
  250.              y1=y1+1
  251.           end
  252.           fehler=fehler+ddy
  253.           x1=x1+1
  254.         next i
  255.  
  256. Das sieht doch schon viel besser aus ! Wir benutzten nur noch INTEGER-werte
  257. und Verglichen mit 0 !
  258. Aber die Lösung ist noch immer für ein Mathematisches-koordinatenkreuz und auch
  259. hier nur für den 1. Oktanten !
  260. Wie die Sache für die Oktanten 1,4,5,8 aussieht kann man sich denken
  261. (Spiegelung and x und/oder y achse)
  262. Hier muß lediglich für y1=y1+1 <=> y1=y1-1 und/oder für x1=x1+1 <=> x1=x1-1
  263. eingesetzt werden.
  264. Für die Übrigen Oktanten 2,3,6,7 müssen dagegen lediglich X und Y vertauscht 
  265. werden. (sowie deren deltas ect.)
  266.  
  267. Hier nun ein 'fertiger' BRESENHAM-LINIEN-ALGORITHMUS für alle Oktanten und
  268. für das Computer-koordinaten-system:
  269.  
  270.  
  271.     px=1
  272.     py=1
  273.     dx=x2-x1
  274.     dy=y2-y1
  275.  
  276.     if dx<0 then dx=-dx:px=-1       'spiegelung an x
  277.     if dy<0 then dy=-dy:py=-1    'spiegelung an y
  278.     
  279.     ddx=dx*2
  280.     ddy=dy*2
  281.  
  282.     if dx>dy then            'oktant 1/4/5/8
  283.       fehler=ddy-dx
  284.           for i=0 to dx
  285.             plot x1,y1
  286.             if fehler>0 then
  287.                y1=y1+py
  288.                fehler=fehler-ddx
  289.             end
  290.             fehler=fehler+ddy
  291.             x1=x1+px
  292.           next i
  293.           exit
  294.      else                'oktant 2/3/6/7
  295.       fehler=ddx-dy
  296.       for i=0 to dy
  297.         plot x1,y1
  298.         if fehler>0 then
  299.            x1=x1+px
  300.            fehler=fehler-ddy
  301.             end
  302.             fehler=fehler+ddx
  303.             y1=y1+py
  304.           next i
  305.     end
  306.  
  307.  
  308. Diese Routiene kann man ja mal in Assembler umsetzten !
  309.  
  310. Wie du dann sicher bemerkst braucht der Kram jetzt schon ne ganze Menge 
  311. Register genaugenommen (bei meinem ersten try) alle ! und das ist SCHLECHT!
  312. Aber auch hiergegen ist ein Kraut gewachsen ! Und damit ich nicht warten
  313. muß bis du selber drauf kommst sag ich's lieber gleich :
  314.  
  315. Errinern wir uns nochmal welche 8 Möglichkeiten es für eine Linie gibt
  316. (oktanten) :
  317.                           3 2
  318.             4     1
  319.                 +
  320.             5     8
  321.               6 7
  322.  
  323.  
  324. Nun könnte man meinen das eine Linie die von + nach 3 geht (also im 3.okt
  325. liegt) doch genauso aussieht wie eine die von + nach 7 geht (also im 7.okt
  326. liegt) und das ist auch richtig denn um eine Linie vom 3. in den 7. oktanten
  327. zu bringen genügt es die Start und die End-koordinaten zu vertauschen.
  328. (dasselbe gilt für 4/8 5/1 ect...)
  329.  
  330. Man könnte sich also entweder die oktanten 5/6/7/8 oder die oktanten
  331. 3/4/5/6 sparen wenn man die Linie gegebenenfalls 'umdreht' und damit spart
  332. man entweder PY oder PX je nachdem in welchem Fall (X oder Y spiegelung)
  333. ein 'umdrehen' der Linie stattfinden soll.
  334. Um immer Linien in den Oktanten 2/1/8/7 (immer steigende x-koordinaten)
  335. zu erhalten müßte man also lediglich schreiben:
  336.  
  337.     cmp.w    d0,d2        ;x1 und x2 vergleichen
  338.     bge.s    .ok        ;x2 >= x1 ? ja dann
  339.     exg    d0,d2        ;x1 und x2 vertauschen
  340.     exg    d1,d3        ;y1 und y2 vertauschen
  341. .ok:
  342.  
  343. Warum gerade dieser Fall sehr nützlich sein kann erkläre ich dir später.
  344. Aber selber denken schadet ja nicht -also warum könnte es beim punktesetzten
  345. gut sein wenn man immer nur ein bit nach rechts gehen muß (und evl nach oben).
  346.  
  347. Nun aber erstmal zu einer anderen Optimierungsmöglichkeit (viele gibt es 
  348. nicht mehr): noch einmal eine kurze übersicht in Basic :
  349.     .
  350.     .
  351.     Plot...
  352.     If fehler=0 ....   -A
  353.       y+...
  354.           fehler-...
  355.         end...
  356.     fehler+....       -B
  357.     x+...
  358.     .
  359.     .
  360. Der Vergliche (A),in Assembler ein TST, kann entfallen wenn ... na kommste 
  361. drauf ?..... wenn man die Routiene so umstellt :
  362.  
  363.     Plot...
  364.     fehler+....       -B
  365.     if fehler=0 ....   -A
  366.       y+....
  367.       fehler-...
  368.     .
  369.     .
  370.     .
  371.  
  372. Richtig ! einfach die fehleraddition(B) schon etwas früher machen ! Das 
  373. schadet nicht da die Addition ja sowieso ausgefürt werden müßte....
  374. Denn nun steht in Assembler inetwa dies ....
  375.  
  376.     ADD.W    Dx,Dy
  377.     TST.W    Dy
  378.     BLE.s    .....    ;<=0 ?
  379.  
  380. Da aber : MERKEN : Nach einem Schreibzugriff auf ein Datenregister sind die
  381.            Flags so gesetzt als hätte man danach ein CMP.x #0,Dy
  382.            gemacht.!!
  383. Also ist das TST in diesem Fall überflüssig und es bleibt nur noch folgendes
  384. übrig :
  385.     ADD.W    Dx,Dy
  386.     BLE.s    ....    ;<=0 ?
  387.  
  388. Und schon haben wir einen Befehl gespart ! Was meinst du ? Nicht viel ?
  389. Einerseits hast du Recht ein TST braucht gerade soviel Zeit wie ein NOP,nämlich
  390. 4 Zyklen aber das sind bei einer Linie über einen Loresschirm :
  391. (eine rasterzeile hat 228 zyklen)
  392.  
  393.     (320*4)/228 = 5.6 RASTERZEILEN !!        
  394.  
  395. Also bringt uns dieses lächerliche TST schon bei 45 langen Linien EINE FRAME !!!!
  396. MERKE: DIE WICHTIGKEIT EINES BEFEHLS STEIGT LINEAR MIT ANZAHL DER DURCHLÄUFE
  397. Darum sind auch Plotroutienen die vorher noch alle Register retten beim
  398. Linienzeichnen ABSOLUT TÖTLICH !
  399.  
  400. Aber ich vermute das war euch auch schon klar...
  401.  
  402. Die BRESENHAM-ROUTIENE die uns jetzt zur Verfügung steht ist schon sehr gut
  403. und kann nur noch auf einen Spezialfall hin optimiert werden also gut 
  404. aufbewahren! denn anstelle von Punktesetzten werden noch viele andere nette
  405. Dinge treten.....
  406.  
  407. Trotzdem möchte ich hier noch einmal kurz zeigen wie man denn nun am SCHNELLSTEN
  408. einfache Processorlinien ziehen kann.
  409. Die 68000 user müssen hier wesentlich mehr arbeiten als die '68020 oder höher'-
  410. Coder.Es kann aber auch für solche (68020'er) interissant sein:
  411.  
  412. Also zunächst eine normale 68000 Punktsetzroutiene
  413.  
  414.                     ;d0/d1 - position
  415.                     ;A4    - mulutab
  416.                     ;A6    - screenpointer
  417.  
  418.     move.w    d0,d2            ;xpos retten
  419.     lsr.w    #3,d2            ;xhardpos (x/8)
  420.     add.w    d1,d1            ;für mulutab
  421.     add.w    (a4,d1.w),d2        ;(x/8)+(y*40)=offset
  422.     not.b    d0
  423.     bset    d0,(a6,d2.w)        ;set the dot !
  424.  
  425. Eine schnellere Möglichkeit einen beliebigen Punkt zu setzten gibt es auf einem
  426. A500 nicht ?! Mir ist jedenfalls keine bekannt ! Der Nachteil ist nur hier
  427. werden 3 Register verunstaltet und die wollen alle gerettet sein....
  428. Außerdem sind das noch viel zu viele Befehle die bei jedem Punkt ausgeführt
  429. werden müssen ! (siehe TST-rechnung)
  430.  
  431. Also wenn wir den weiter oben gezeigten Trick einsetzten um immer nur das
  432. bit rechts neben dem letzten setzten zu müssen (nur oktanten 2/1/8/7) also
  433. bei jedem punkt x+1 dann gibt das doch schon viele neue ideen ....
  434. Man könnte z.B eine Liste anlegen die alle bits enthält und bei jedem Punkt
  435. Das nächste Muster aus der Liste holen und es dann in die Plane odern :
  436. or.b (a0)+ oder sowas..
  437. Aber noch schneller und noch cleverer geht es mit dem folgenden Trick :
  438. (Der is übrigens nich von mir ! aber trotzdem prima!)
  439.  
  440. Nehmen wir an wir würden den Punkt wie folgt setzten können :
  441.  
  442.     BSET    d0,(a6)
  443.  
  444. Und d0 würde auf 7 stehen also im aktuellen byte ganz links (8tes bit) dann
  445. bräuchten wir jetzt nur ein
  446.  
  447.     SUBQ    #1,d0
  448.  
  449. Um einen Pixel nach rechts zu kommen (7tes bit) ! Prima ! Aber leider klappt 
  450. das nur bis D0 auf 0 steht (1tes bit) danach käme D0=-1 und das wäre MIST ! 
  451. Aber in diesem Fall müsste man nur D0 wieder auf 7 setzten und ein byte nach 
  452. rechts gehen, was mit einem :
  453.  
  454.     MOVEQ    #7,d0
  455.     ADDQ.L    #1,a6
  456.  
  457. In kürzester Zeit getan wäre ! Und ob D0 negativ geworden ist läßt sich ja auch
  458. ganz einfach feststellen (BMI.s x) also eigentlich müsste das doch möglich
  459. sein ....
  460.  
  461. Also machen wir eine erste skizze in Assembler ! Sagen wir wir haben das
  462. startbit ermittelt und in D4 abgelegt sowie das startbyte in A0
  463. Außerdem haben wir :      ¯¯                     ¯¯
  464.             
  465. Fehler    -D0
  466. ddx    -D1
  467. ddy    -D2
  468. i    -D5 (counter für länge der linie)
  469.  
  470.  
  471. Dann könnten wir (für den ersten oktanten) schreiben :
  472.  
  473.     bra.s    .loop
  474. .loop1:                    ;Schleife mit sprung ins nächste byte
  475.     moveq    #7,d4            
  476.     addq.l    #1,a0
  477. .loop:                    ;Normale schleife
  478.     bset    d4,(a0)            ;punkt setzen
  479.     add.w    d1,d0            ;fehler=fehler+ddx
  480.     ble.s    .NoUP            ;fehler<=0 ? ja dann
  481.     sub.w    d2,d0            ;fehler=fehler-ddy
  482.     lea    -40(a0),a0        ;eine Zeile rauf
  483. .NoUP:
  484.     subq.w    #1,d4            ;ein bit nach rechts
  485.     
  486. So erstmal bis hier denn nun folgt ein auf den ersten Blick nur schwer zu
  487. schluckender Schritt ! Aber ich zeig ihn euch erstmal .. bitte nicht sofort
  488. verzweifeln....
  489.  
  490.     dbmi    d5,.loop        ;normal
  491.     dbpl    d5,.loop1        ;wenn negative-flag gesetzt
  492.     rts
  493.     
  494. Ja ja,da staunt der jenige der von DBcc bisher nur Dbra kannte ! aber was
  495. tut diese wahnwitzige Befehlskombination ? 
  496.  
  497. Nun der DBMI befehl testet 2 Sachen gleichzeitig : ob ein überlauf ins 
  498. nächste Byte stattgefunden hat (d4 negativ) und ob die linie schon zuende
  499. ist (d5=$ffff) !
  500. Falls also der [subq.w #1,d4] das N-bit gesetzt hat (negative) wird der
  501. DBMI befehl übergangen ! Aber es wird auch nicht eins von D5 abgezogen wie
  502. es normalerweise beim DBcc durchlauf geschieht.
  503. Darum hätten wir ein Problem wenn gleichzeitig ein Überlauf und das Linien-ende
  504. eintreten würden.
  505. Aber verfolgen wir den oben angesprochenen Fall weiter :
  506.  
  507. Das N-bit ist also gesetzt und D5 ist noch nicht 0
  508. Der DBMI-befehl wird also übersprungen ! das DBPL jedoch würde nur übersprungen
  509. wenn das N-bit nicht gesetzt ist - es wird also ausgeführt ! 
  510. und prüft daraufhin ob D5 schon 0 ist ! ist es nicht wird es um 1 decremiert
  511. und es wird nach loop1 gesprungen , wo das nächste byte angesteuert wird und
  512. dann geht es (ohen sprung!) in die normale Loop über.
  513.  
  514. Alle anderen fälle kannste dir selber erklären ! (solltest du auch!) Aber
  515. es funktioniert immer !
  516. Genial was ? Schneller kann man wirklich keine Linien auf einem 68000 ziehen!
  517. Oder doch ? Wer weiß vielleicht kommt ja ein neuer Bresenham und zeigt uns
  518. wie blöd wir doch alle waren.....
  519.  
  520.  
  521.  
  522.  
  523.  
  524. Hallo der Nächste schöne Tag ist vorbei und ich dachte mir, da ich zum coden
  525. schon zu Müde bin schreib ich meinen WerkSchop weiter also denn....
  526. (1:06 Uhr - hab gerade Al.Mundy auf VOX gesehen )
  527.  
  528.  
  529.  
  530.  
  531. Also gut jetzt nocheinmal in den Bresenham endspurt ! Ich werde dir jetzt eine
  532. mit allen mir bekannten Tricks Optimierte Bresenham-routiene vorstellen.
  533. Diesmal sogar in Assembler, so richtig zu ausschneiden und freuen.
  534. Aber vorher will ich dir noch einen Letzten Trick offenbaren :
  535.  
  536. Mit Hilfe einer weiteren kleinen Umstellung der Terme (hab kein Bock die 
  537. jetzt auch noch bis ins letzte zu erklären) kann man sich noch ein paar
  538. Befehle sparen.
  539. Also hier zum Verstehen nocheinmal in Basic für den ersten Oktanten :
  540.  
  541.     dx=x2-x1
  542.     dy=y2-y1
  543.     
  544.     e=-dx/2
  545.     for i=0 to dx
  546.       plot x1,y1
  547.       e=e+dy
  548.       if e>0 then
  549.            e=e-dx
  550.         y=y+1
  551.       end
  552.       x=x+1
  553.     next
  554.  
  555. Wie das Kennerauge sofor sieht müssen die Deltas (dx & dy) nun nicht mehr
  556. mit zwei multipliziert werden ! Dafür ist die Berechnung von e nun etwas
  557. anders aber wen störts....
  558. Aber nu in assembler :
  559.  
  560.     
  561. ***************************************************************************
  562. LINE:                    ;bresenhamgrundstock d0/d1-d2/d3
  563.     
  564.     cmp.w    d1,d3            ;y1<y2 ?
  565.     bge.s    .ok
  566.     exg    d0,d2            ;immer y1<y2 ! nicht ideal zum punkte
  567.     exg    d1,d3            ;setzten aber für andere dinge....
  568. .ok:
  569.     
  570.     ;a0 hier aus d1 berechnen     ;je nach anwendung verschieden.....
  571.  
  572.     moveq    #1,d7            ;px (richtung für x)
  573.  
  574.     sub.w    d1,d3            ;dy=y2-y1       [d3=dy]
  575.     sub.w    d0,d2            ;dx=x2-x1       [d2=dx]
  576.     bpl.s    .ok2            ;dx positiv ?
  577.     neg.w    d2            ;|dx|
  578.     moveq    #-1,d7            ;px (richtung für x)
  579. .ok2:
  580.     move.w    d2,d4
  581.     lsr.w    #1,d4            ;e=dx/2
  582.     neg.w    d4            ;e=-dx/2    [d4=e]
  583.  
  584.     cmp.w    d2,d3            ;dx>dy ?
  585.     bgt.s    .okt2
  586.     move.w    d2,d1            ;i=dx        [d1=i]
  587.  
  588. .loop1:
  589.     ;Do something; xpos=d0 ypos=a0    ;plot or calc or ......
  590.     
  591.     add.w    d3,d4            ;e=e+dy
  592.     ble.s    .2
  593.     addq.l    #....,a0        ;y=y+1
  594.     sub.w    d2,d4            ;e=e-dx
  595. .2:    add.w    d7,d0            ;x=x+1 oder x=x-1 je nach d7
  596.     dbra    d1,.loop1
  597.     rts
  598. .okt2:
  599.     move.w    d3,d1            ;i=dy        [d1=i]
  600. .loop2:
  601.     ;Do something; xpos=d0 ypos=a0    ;plot or calc or ......
  602.  
  603.     addq.l    #....,a0        ;y=y+1
  604.     add.w    d2,d4            ;e=e+dx
  605.     ble.s    .3
  606.     sub.w    d3,d4            ;e=e-dy
  607.     add.w    d7,d0            ;x=x+1 oder x=x-1 je nach d7
  608. .3:    dbra    d1,.loop2
  609.     rts
  610. **************************************************************************
  611.  
  612.  
  613. So da hast du eine nach bestem Wissen optimierte Bresenham-linien-berechnungs-
  614. routiene ! Auf ihr werde ich im ganzen weitern Verlauf aufbauen ! Also 
  615. versteh sie oder lass es bleiben ich hab jedenfalls mein Bestes gegeben 
  616. (das war nich viel,ich weiß) dir die Entstehung und die vielen(?) kleinen
  617. Tricks beim Bresenham näher zu bringen.
  618.  
  619.  
  620.  
  621. Die 3. DIMENSION
  622. ----------------
  623.  
  624.  
  625. Ja jetzt wirds spannend (knister) ein klein weing hast du ja schon erfahren
  626. über 'die Welt des richtigen Vectors' aber jetzt gehts richtig ab !
  627. Es gibt so viel zu sagen über -3D- das ich,damit dieser Workshop nicht (noch)
  628. endlos(er) wird,einiges vorraussetzten bzw. anderen Workshops überlassen
  629. muß :
  630.     - DU bekommst keinen Haarausfall vor Schreck wenn du das Wort
  631.       Vector hörts !
  632.     - DU kannst 3punkte in weniger als 3frames um alle 3achsen rotieren
  633.       (wie matrix-rotation funktionert siehe HowToCode7.0)
  634.     - DU köntest dir eventuell vorstellen das es möglich wäre anstelle
  635.       von wilden blitt-orgien auch mal den Processor zu bemühen.
  636.       (Blitter   : dumm & schnell)
  637.       (Processor : clever & nur schnell mit dem richtigen Prinzip)
  638.  
  639. Alles in Butter ? (HA ! Das bringt mich auf eine Idee - Alles in Vector ? 
  640. wäre doch 'n prima Wahlspruch für uns Vectorfans?????)
  641.  
  642.                 
  643.                 PENCIL-VECTOR
  644.                 ---------------------
  645.  
  646. Nun ..... höre gut zu mein Sohn ...... der Hohepriester wird dich nun .....
  647. in die Geheimnisse des .... (gong,lichtblitz) PENCIL's (rauch) einweihen....
  648. Nun (warum fange ich eigentlich immer mit 'nun' an ? das ist doch kein Stil
  649. also nochmal) :
  650. Also Pencil hat zwei große Vorteile : Er ist Aufwendig und Langsam .
  651. Ha alle gelacht ? Na,ja dann eben nicht ! Jetzt aber im Ärnst :
  652.  
  653. Pencil ist relativ einfach zu Coden und sieht ganz nett aus. Außerdem ist er
  654. noch nicht so 'abgedroschen' wie der gute alte blaue BlitterCube .
  655. Aber wie funktioniert Pencil eigentlich ?
  656.  
  657. Pencil beruht auf dem folgendem Prinzip : 
  658.  
  659.     -Man baut jede Fläche für sich zeilenweise auf .
  660.     -Jede Zeile wird dabei mit einem Frabverlauf von hell nach dunkel
  661.      (oder andersrum) gefüllt abhänig von ihrer länge.
  662.  
  663. Dadurch ergibt sich das in der ganzen Fläche später ein Verlauf zu sehen ist.
  664. Da sich die Zeilenlängen andauernd ändern ergibt sich ein schönes Muster :
  665. -pencil vector,eben- ,das einen sogar an eine Beistiftzeichnung errinern
  666. kann (na ja! sagt da der Kust-LK-schüler).
  667.  
  668. Nun zur Umsetztung : Also die Farbverläufe werden natürlich abgelegt ! Für
  669. jede mögliche Breite einen (0-319) das geht in einenm kleinen IFF-picture 
  670. von 320x320 pixel größe.
  671. Diese müssen dann nur an die richtige Position geblittet werden und schwubs
  672. steht da ein wunderprächtiger Pencilvector...
  673.  
  674. Dabei stoßen wir auf ein sehr bewegendes Problem : Wir müssen für jede Zeile
  675. einer Fläche ihre Breite und die X-position des ersten pixels kennen um
  676. den entsprechenden Verlauf an die richtige Stelle blitten zu können !
  677.  
  678. Oder nochmal anders gesagt:
  679. Für jede Zeile einer Fläche werden eine X-start und eine X-end koordinate
  680. benötigt.
  681.  
  682. Dies ist das erste Problem des Processor-Vectors ! Wenn es dir gelingen sollte
  683. es zu lösen dann hast du den Rest schon in der Tasche !
  684. Also viel glück ich hau mir/mich jetzt ne runde aufs Ohr. (1:54 uhr)
  685.  
  686.  
  687.  
  688. ............................ DENK PAUSE ...................................
  689.  
  690.  
  691.  
  692.  
  693. Hallo und weiter gehts (9:11:93 23:59) mit dem ULTIMATIVEN WORKSHOP !
  694. Meine 100 Bilder Animation ist inzwischen übrigens fertig...
  695. RAYTRACING RULES!
  696.  
  697. Ich hoffe du hast dir mittlerweile Gedanken gemacht über das erste und 
  698. vielleicht wichtigste Problem bei Processorvector!
  699. Aber ich will trotzdem versuchen alles zu erklären..
  700. Also zunächst betrachten wir nur 1ne fläche und der Einfachheit halber
  701. ein Dreieck (MERKE:PROBLEM VEREINFACHEN/TEILEN) wir benötigen nun für jede
  702. Zeile der Fläche 2 Informationen (Xstart und Xstop).
  703.  
  704. Damit wir diese Verwalten können benötigen wir zunächst einen Speicherblock
  705. der für jede Zeile 2 words parat hält(also 256*4 bytes).
  706. Der Grundgedanke ist nun ganz einfach : Um an die Xstart/stop Werte zu 
  707. kommen benutzen wir einen einfachen Linien-algorithmus,nur anstelle von 
  708. Punktsetzten speichern wir für jede Zeile den aktuellen X-wert.
  709. Bei nur einer Linie von 0/0 nach 6/6 würde dann dies in unserem Buffer
  710. stehen (wenn wir immer als XStart speichern).
  711.  
  712. BUFFER:    0,0        ;Zeile 1     *
  713.     1,0        ;Zeile 2      *
  714.     2,0        ;Zeile 3           * 
  715.     3,0        ;Zeile 4            *    <-Die Linie !
  716.     4,0        ;Zeile 5             *
  717.     5,0        ;Zeile 6              *
  718.     6,0        ;zeile 7               *
  719.  
  720. In jeder Zeile hatte sich die Xposition also um eins erhöht.
  721. Soweit ist das alles kein Prob. aber die Schwierigkeit liegt nun darin
  722. festzustellen ob es sich bei den Xkoordinaten um Xstart oder Xstop-werte
  723. handelt! 
  724. Eine Möglichkeit diese Entscheidung zu Treffe ist nun z.b diese :
  725. Wenn der Xstart-wert einer Zeile schon beschrieben wurde dann ist ein
  726. weiterer Wert in dieser Zeile als Xstop zu werten,da nur 2 punkte in einer 
  727. Zeile pro Fläche möglich sind (dreieck/viereck und regelm. vieleck).
  728.  
  729. Dieses Verfahren setzt aber vorraus,daß die Tabelle inialisiert wurde
  730. z.B mit -1 und das bei jedem Punkt eine Überprüfung durchgeführt werden
  731. kann. Dies ist zwar Technisch kein Problem aber RasterZeit.....
  732. Trotzdem basierten meine ersten Pencilroutienen auf diesem Prinzip.
  733.  
  734. Eine andere Möglichkeit die entscheidung Xstart/Xstop zu Treffen ist diese
  735. [die ich von Arne B. habe (echt genial!) ] : 
  736. Er hat festgestellt,daß immer eine ganze Linie entweder nur Xstart oder
  737. nur Xstop-werte liefert und so der Vergleich bei jedem Punkt entfallen kann.
  738. Aber was noch viel genialer ist : Er fand heraus,daß wenn man die Linien
  739. in zwei Gruppen einteilt,nämlich in (A) von unten nach oben verlaufende und
  740. (B) von oben nach unten verlaufende man bei einem Wechsel von A nach B (oder
  741. B nach A) einfach auch zwischen Xstart und Xstop wechseln muß.
  742. Also nochmal langsam :
  743.     -Die erste Linie ist immer Xstart 
  744.      Ihr 'Typ' (A oder B) wird gerettet und die Spalte (Xstart/Xstop)
  745.        in der sie vermerkt wurde (hier immer Xstart) ebenfalls.
  746.  
  747.     -Ist die nächste Linie vom selben Typ so wird sie in der selben
  748.      spalte (Xstart/Xstop) vermerkt.
  749.  
  750.     -Ist sie jedoch vom jeweils anderen Typ so wird auch die jeweils
  751.      andere Spalte benutzt.
  752.  
  753. Mit Hilfe dieses Prinzips erhält man eine komplette Liste von Xstart/Xstop-
  754. werten für beliebige convexe (2punkte pro Zeile) Flächen.
  755. Man muß nun lediglich noch daran denken die Minimale und Maximale Y-position
  756. der Fläche mitzuspeichern um später nicht den ganzen Buffer abarbeiten zu
  757. müssen.
  758. Bedenkt man dies so braucht man den Buffer auch nicht wieder zu Clearen ect.
  759.  
  760.  
  761. So das solle erstmal reichen für Heute ich bin nu echt zu müde...0:34
  762.  
  763.  
  764. Ha ! viele Wochen sind vergangen und ich binn wieder ausgeschlafen.
  765. Da Du jetzt das Prinzip des Pencilvectors kennst (Buffer,Xstart,Xstop...)
  766. kennst können wir langsam weitermachen...
  767.  
  768.             
  769.                     PROCESSOR VECTOR
  770.             -----------------------
  771.  
  772. Processor Vector unterscheidet sich von 'veraltetem' Blittervector nur dadurch,
  773. daß die Flächen mit dem ... ja mit dem Processor gezeichnet werden.
  774. Aber warum mit dem processor ? wo der Blitter doch so geniale Funktionen für
  775. Vector bereitstellt ? 
  776. Tja auf einem A500 mit 68000 (für den der Blitter ja eigentlich entwickelt
  777. wurde) ist Blittervector auch noch immer das Beste und schnellste (der beste
  778. Blittervector-Coder ist unbestritten TaiPan/Complex).
  779. Aber wenn man Inconvexe (überschneidene Flächen) Objekte macht , und das 
  780. sollte man immer da sie wesentlich schöner sind, wird der Blitter auf
  781. einmal entsätzlich langsam (in buffer zeichnen , diesen kopieren und löschen...).
  782. Wenn man nun noch einen schnellen 32bit Processor (ab 68020) besitzt, was
  783. in allen noch verkaufen Amigas der fall ist, und wolmöglich noch echten
  784. 32bit FAST-ram dann ist der Processor um einen Faktor schneller als der gute
  785. alte Blitter.
  786.  
  787. Beim Blitter-vector hatte man immer zunächst die Umrandungs-Linien gezeichnet
  788. un diese dann gefüllt. Dies funktioniert natürlich auch mit dem Processor
  789. ist aber ENTSÄTZLICH langsam.
  790. Aber wenn man weiß wie Pencil funktioniert kann man schnell daruf kommen wie
  791. man Flächen auch Zeichnen kann (ohne punkte und füllen).
  792.  
  793. Man berechnet zuerst wieder eine Tabelle mit Xstart und Xstop werten für
  794. jede Zeile der Fläche und anstelle diese Linien dann untereinander zu
  795. blitten (wie beim Pencil) MOVEt man sie mit dem Processor in den Speicher.
  796. Dies hat den gewaltigen Vorteil das man keinen Buffer benötigt, weil ja
  797. die darunter Liegenden Flächen automatisch überschrieben werden außerdem
  798. wird nun jeder Punkt einer Fläche nun nur EINMAL gezeichnet - mit dem 
  799. Blitter wurden die Randpunkte ZWEIMAL gezeichnet (einmal beim Linienziehen
  800. und einmal beim Füllen).
  801.  
  802.  
  803. Die wichtigste Routiene beim Processorvector ist also die die eine Zeile
  804. von Xstart bis Xstop mit einer Farbe ausfüllt.
  805. Hier macht es sich wieder schmerzlich bemerkbar das der Amiga noch keinen
  806. ChunkyPixel-mode hat (1byte=1pixel) weil in unserem Planarem-System (1bit=
  807. 1pixel) mit den normalen Assembler befehlen das Arbeiten enorm verlangsamt
  808. wird.(wir müssen für 256farben 8mal auf den Speicher zugreifen - die
  809. Chunky Leute nur 1mal !!!)
  810.  
  811.  
  812. Obwohl sich Processorvector eigentlich nicht so richtig auf einem 68000
  813. lohnt überlegen wir uns doch zunächst einmal wie die FillLine routiene 
  814. hier aussehen müsste.
  815.  
  816. Die Aufgabenstellung ist klar : Eine waagerechte Linie (----) Zeichnen
  817.                                 von Pixel A bis Pixel B
  818.  
  819. Man könnte hierzu natürlich eine Schleife durchlaufen, die alle einzelnen
  820. Punkte plottet. Aber wenn man bedenkt das die FillLine routiene schon bei 
  821. einem einfachen Würfen bis zu 600 mal durchlaufen wird sollte man doch
  822. nach einer etwas schnelleren Lösung suchen...
  823.  
  824. such...such...such...
  825.  
  826. Also wenn die Linie immer an durch 16 teilbaren Positionen beginnen würde
  827. und immer eine durch 16 teilbare Länge hätte so könne man sie mit
  828.  
  829.  move.w   #-1,(a0)+
  830.  
  831. in den Speicher kopieren. Um etwas konkreter werden zu können gehen wir
  832. zunächst von einem Beispiel aus : von pixel 0 an eine 64 Pixel lange linie.
  833.  
  834.  move.w   #-1,(a0)+
  835.  move.w   #-1,(a0)+
  836.  move.w   #-1,(a0)+
  837.  move.w   #-1,(a0)+
  838.  
  839. Und nun etwas schwerer : von 0 eine 73 Pixel lange Linie (73=64+9).
  840.  
  841.  move.w   #-1,(a0)+
  842.  move.w   #-1,(a0)+
  843.  move.w   #-1,(a0)+
  844.  move.w   #-1,(a0)+
  845.  or.w      #%1111111110000000,(a0)+
  846.  
  847. Was haben wir gemacht ? Nun ganz einfach die 64 pixel ließen sich blitz 
  848. schnell zeichnen un die überschüssigen 9 Pixel wurden einfach noch hinten
  849. drangehängt.
  850. Dies mußte mit OR geschehen da ein Move die letzten 7 bit hinter der Zeile
  851. gelöscht hätte (7 nullbits am ende) was aber nicht erwünscht war.
  852.  
  853. Und nun richtig kompliziert : von 12 eine 73 pixel lange Linie.
  854.  
  855.  or.w    #%00000000000011111,(a0)+
  856.  move.w    #-1,(a0)+
  857.  move.w    #-1,(a0)+
  858.  move.w    #-1,(a0)+
  859.  move.w    #-1,(a0)+
  860.  or.w    #%11110000000000000,(a0)+
  861.  
  862. Das Kennerauge hat natürlich sofort erkannt das wir nun auch am Anfang 
  863. einige Bits 'von hand' gesetzt haben um auf von 12 auf die nächste durch
  864. 16 teilbare Position zu kommen.
  865. Die nächste durch 16 teilbare Position nach 12 ist ---- ja bravo ! 16 !.
  866. also müssen die ersten 4 bits (von 12 bis 16) mittels or gesetzt werden.
  867. Danach können wir aber wieder mit Mega-speed (16pixel pro befehl) weiter-
  868. machen. Bis wir 69 Pixel haben (5+4*16) weil nun ein weiteres Word schon 
  869. zuviel des guten wäre (wir wollen ja nur 73pix) also setzten wir den
  870. Rest (73-69=4) wieder 'von Hand'.
  871.  
  872. Aus diesen Beispielen hast du (hoffentlich) folgendes Prinizip erkannt :
  873. Für Linien die länger als 16 pixel sind ....
  874.  
  875. Zuerst setzt man die Bits die notwendig sind um auf eine durch 16 teilbare
  876. Position zu kommen (ein OR.W) dann schreibt man munter 16ner Blöcke (Move.w)
  877. bis (länge-anfangspixel)/16 Pixel gesetzt wurden und schließlich klebt
  878. man hinten noch einige bits (wenn jetzt noch welche fehlen) dran (ein OR.w).
  879. Die beiden OR-schritte können hierbei natürlich manchmal wegfallen - dann
  880. nämlich wenn die Linie schon auf einer 16ner Position liegt oder sowieso
  881. eine durch 16 teilbare Länge hat.
  882.  
  883. Mit diesem Prinzip hat man eine 16bit-LineFill Routiene. 16bit deshalb weil
  884. man in jedem Fall ein Word schreibt (das schnellste auf einem 68000).
  885. Würde man die oben beschriebene Methode des Plots-in-der-schleife benutzen
  886. hätte man eine 1bit-Linefill routien (klingt doch schon viel langsamer !?).
  887.  
  888. Auf einem 68020 wird man eine 32bit Routiene benutzen (es ist ja nicht umsonst 
  889. ein 32bit Processor) also eine die nur mit Longwords arbeitet aber dies auf
  890. einem 68000 zu versuchen ist zwecklos,da ein Longword hier genau doppelt
  891. so langsam in den Speicher geschrieben wird wie zwei words - das ganze bringt
  892. also (aufm 68000) keinen Vorteil.
  893.  
  894. Doch bevor es an die Praxis geht müssen wir noch etwas weiter denken denn
  895. unser Prinzip hat bis jetzt noch eine Einschränkung : Es können nur Linien
  896. die länger als 16pixel sind verarbeitet werden.
  897.  
  898. Um auch kleinere Linien zuzulassen gibt es nun prinizipell zwei möglichkeiten :
  899.  
  900. 1. Man schreibt eine Extra routiene die auf kleine Linien spezialisiert ist.
  901.    In diesem Fall muß man aber bei jeder Linie überprüfen ob sie klein oder
  902.    groß (<16 ? >16 ?) ist.
  903.  
  904. 2. Man verändert den Algorithmus etwas (Ich zeig dir gleich wie) um auch
  905.    kleiner Linien bis hin zu einzelnen Punkten zuzulassen.
  906.    In diesem Fall wird aber bei kleinen Linien etwas zuviel gearbeitet.
  907.  
  908. Die 2te Möglichkeit besteht darin, daß man immer einen 16ner Block mehr moved
  909. als eigentlich nötig (easy, da DBRA sowieso immer einen durchlauf zuviel
  910. macht) und dann die Zuviel gezeichneten Pixel mittels AND wieder löscht.
  911. Um also zwei Pixel an Position 7 zu Zeichen :
  912.  
  913.  or.w    #%0000001111111111,(a0)+    ;nächste 16ner position
  914.                     ;keine 16ner blöcke (negative anzahl)
  915.  and.w  #%0000001100000000,-2(a0)    ;end korrektur.
  916.  
  917. Diese Methode benötigt aber eine Kompliziertere Berechnung und außerdem müßte
  918. man nachdem man gelöscht hat den alten inhalt wieder einkopieren...
  919. Das Ganze ist zwar verbreitet aber es ist Langsamer und Komplizierter als
  920. wenn man eine eigene Rotiene für mini Linien (<16) schreibt.
  921.  
  922. Also zur ersten Möglichkeit zurück ...
  923. Eine Routiene für maximal 16 pixel lange Linien könnte so aussehen :
  924.  
  925.  d0 - first pix
  926.  d1 - length
  927.  
  928. ShortLine:
  929.     moveq    #-1,d2        ;Alle bits setzen
  930.     lsr.l    d1,d2        ;'length' bits löschen (ganz links werden nullbits eingeschoben)
  931.     not.l    d2        ;nur noch 'length' bits gesetzt
  932.     move.w    d0,d1        ;retten
  933.     and.w    #$f,d0        
  934.     lsr.l    d0,d2        ;an richtige Position shiften.
  935.  
  936.     lsr.w    #4,d1        ;Ziel offset berechnen
  937.     add.w    d1,d1    
  938.  
  939.     or.l    d2,(a6,d1.w)    ;Linie zeichnen
  940.     rts
  941.  
  942. Diese Routiene berechnet das benötigte Bitmuster am Anfang indem sie zuerst
  943. alle bits setzt (moveq    #-1)
  944.  
  945.  %1111111111111111 1111111111111111
  946.  
  947. Dann das ganze um 'länge' nach rechts verschiebt (z.B um 6) :
  948.  
  949.  %0000001111111111 1111111111111111
  950.  
  951. Dadurch entstehen 'länge'-nullbits,welche nun durch ein not.l invertiert
  952. werden:
  953.  
  954.  %1111110000000000 0000000000000000
  955.  
  956. Schwubs schon haben wir ein Longword in dem 'länge'-bits am anfang gesetzt
  957. sind. Dieses wird nun nur noch für die richtige Position zurechgeshiftet
  958. (z.b für pos 13):
  959.  
  960.  %0000000000000111 1110000000000000
  961.  
  962. Und das sich ergebene Muster kann nun prima ge OR't werden...
  963.  
  964. Diese Lösung ist vielleicht nicht die schnelste aber sie ist schneller als
  965. eine Routiene bei der Alle Breiten an Allen Positionen (1KB an precalc-daten)
  966. bereits vorberechnet sind und nur noch ausgelesen werden müssen!
  967. Warum ? Nun weil zu mauslesen komplizierte 'speicher-befehle' benötigt werden
  968. z.B : move.w (a0,d1.w),(a1,d2.w) und ähnliches...
  969. Außerdem müssen Offsets berechnet werden oder aus Tabellen gelesen werden,so
  970. daß das Ganze in einer wilden Moverei ausartet.
  971. Während unsere Lösung nur mit 'kleinen' Befehlen arbeitet sie ist sozusagen
  972. leicher zu verdauen,flinker,optimierter,kürzer und schwerer zu schreiben...
  973. Aber genau dieser Stil, nämlich der mit vielen kleinen ADD's,NOT's,LSx's
  974. die alle nur mit Datenregistern operieren ist der Stil der Zukunft !
  975.  
  976. Eine damit programmierte Routiene wird auf einem 68020 4mal schneller als
  977. auf einem 68000,währen eine tabellen-Move-orgie nur 1.8mal schneller wird.
  978. (Alle angaben sind wie immer ohne Gegenwehr.)
  979. Und für die Träumer die sich schon an RISC's coden sehen ist der Vorteil
  980. noch gewaltiger denn dort gibt es bekanntlich keinen Move mehr...
  981. (Um einen wert von a nach b im Speicher zu kopieren werden min 2befehle
  982. benötigt und bei move.w (a0)+,4(a1,d3.w*4) sind es 9 Befehle!!!)
  983.  
  984.  
  985. Um dir noch einmal das nötige Rüstzeug für den richtigen Weg zu geben - 
  986. hier einige kurze Tips zu Bitfriemel-befehlen :
  987.  
  988.  OR    - gleich schnell wie Add. Verändert nur in Quelle gesetzte bits.
  989.      Alles was in quelle gesetzt ist nachher auch im Ziel gesetzt.
  990.  
  991.  AND   - Läßt nur die Bits im Ziel stehen für die in der Quelle 1 steht.
  992.      Ein and.w #15,dx bewirkt das dx immer zwischen 0 und 15 liegt.
  993.      es ermöglicht ein wundervolles clipping!! (-2 => 13) MERKEN !!!
  994.      (dieser Trick geht nur mit 1,3,7,15,31,63,127,255....)
  995.  
  996.  EOR   - invertiert die Bits die in der Quelle gesetzt sind.
  997.          ein Eor.w #15,dx wirkt wie ein x=15-x ! MERKEN !!!
  998.  
  999.  NOT   - invertiert alle bits im Ziel! Nicht verwechseln mit NEG !!!!!
  1000.  
  1001.  NEG   - wirkt wie 1-(x+1) - Negiert also das ziel ! Verändert NICHT nur
  1002.          das höchste bit,obwohl nur das als Sign-bit gilt!
  1003.  
  1004.  LSx   - Kennt wohl jeder. schiebt IMMER nullbits nach.
  1005.      Das Bit was zuletzt links oder rechts rausgeschoben wurde landet
  1006.      im X-Flag.
  1007.  
  1008.  ASx   - Schiebt bei Negativen Zahlen unter umständen auch 1bits nach
  1009.      Vorzeichenrichtig shiften. (langsamer als die LSx befehle)
  1010.      Auch ASx läd rausgeschobene Bits ins X-Flag.
  1011.  
  1012.  ADD   - Keine Angst ich halte dich nicht für so bescheuert das du ADD
  1013.      nicht kapiert hast aber ich wolte doch noch kurz erwähnt haben
  1014.      das bei einem Überlauf ($ffffffff+$1=0) das X-Flag gesetzt wird!!
  1015.  
  1016.  ADDX  - Führt eine ganz normale Addition aus UND addiert danach noch
  1017.       1 wenn das X-flag gesetzt war (dies wird dabei gelöscht).
  1018.  
  1019.  EXT.L - Erweitert ein Register auf Longword. Wenn das untere word positiv
  1020.       ist wird das obere word gelöscht! ist es dagegen negativ so wird
  1021.      das obere word mit $ffff gefüllt. Manchmal kann man diesen Befehl
  1022.      trickreich einsetzten um das obere Word zu löschen ohen zu Swappen.
  1023.  
  1024.  EXT.w - Wie Ext.l nur das alles ne Nummer kleiner abläuft :
  1025.      Ist das untere Byte positiv wird das obere byte gelöscht und sonst
  1026.      mit $ff gefüllt. Das Hiword wird bei diesem Befehl nicht beachtet.
  1027.      Um also ein Byte auf Longword zu Extenden ist folgendes notwendig:
  1028.         ext.w    d0
  1029.         ext.l    d0
  1030.      Auf dem >=68020 Processoren gibt es für diese Kombination den befehl
  1031.         extb.l  d0
  1032.  
  1033.  
  1034. Wenn man nur Datenregister benutzt ist jeder diese Befehle gleich schnell.
  1035. Und benötigt genau 1word im Speicher.
  1036. Wenn möglich sollten also immer zwei davon hintereinander stehen bevor der
  1037. nächste 'komplexe' Befehl kommt,damit dieser an einer Longword-addresse
  1038. steht (nur bei 680x0 x>1).
  1039.  
  1040.  
  1041. Noch ein kleiner Trick am Rande : Will man den Rest einer ganzzahldivision
  1042. durch eine zweierpotenz X erhalten so kann man schreiben :
  1043.     DIVU    #x,d0
  1044.     CLR.W    d0
  1045.     SWAP    d0
  1046. Es geht aber viel schneller mit :
  1047.     AND.W    #x-1,d0
  1048.  
  1049. Im Moment denkst du vielleicht noch wan baruch ich so'n sch... aber ich
  1050. hab nur die befehle und Tricks erklärt die ich später noch dringent brauche...
  1051.  
  1052. Also gut ! Bevor wir das Kapitel PROCESSOR-VECTOR abschließen werden wir
  1053. uns noch eine Richtige 16bitFillLine Routiene basteln,die nach strich und
  1054. faden für 68000 optimiert ist (die 68020 version sollst du selbst machen!!!).
  1055.  
  1056.  
  1057.  
  1058. OPTIMIEREN DURCH LONGWORD GRENZEN,CACHING und SCHLEIFEN 
  1059. -------------------------------------------------------
  1060.  
  1061.  
  1062. Um eine Optimierte Routiene zu schreiben hier etwas darüber wie bestimmte
  1063. Processoren ihren Code am liebsten haben...
  1064.  
  1065. 68000:    Möglichst viel Vorberechnen (solange der Bitfriemelweg nicht schneller
  1066.     ist). Pipelineing der Copros benutzen (blitter,proc,blitter,proc...).
  1067.     Möglichst wenig und kurz springen! Keine Dbra-schleifen bei Zeitkritischen
  1068.     routienen - lieber den Code x-mal hintereinander Kopieren...
  1069.     Für viele Einzellfälle eigene Routienen von Programm aus erzeugen 
  1070.     oder Modifizieren (selbstmodifikation)...
  1071.     Aber das alles ist schnee von gestern,kalter kaffee,kalter schnee,
  1072.         kaffe von gestern ...
  1073.         
  1074.  
  1075. 68010:  Einzige verbesserung : 3word-schleifen wie z.B :
  1076.     .loop:    move.w    (a0)+,(a1)+
  1077.         dbra    d0,.loop
  1078.     Werden erkannt und stark beschleunigt ! Sonst ist alles beim alten
  1079.     geblieben. (abgesehen von MMU-unterstützung des 010)...
  1080.     Wer sich freiwillig einen 68010 einbauen läßt gehört bestraft !
  1081.  
  1082.  
  1083. 68020:  Geniale neuerungen ! Echte 32 Bit !!! Das heißt Longwords werden nicht
  1084.     langsamer behandelt als words! Sehr nützliche Befehle um mit Tabellen
  1085.     zu arbeiten (a0,d0.w*2) kostet KEINE Zeit mehr als (a0,d0.w)!
  1086.     Neue Befehle um mit Bits zu friemeln (BitFields).
  1087.     Verbesserte Architektur (ist bei gleicher Taktfrequenz schneller).
  1088.     WaitState-handling : Wenn vor einem Schreibzugriff auf das Chip-Mem
  1089.     wartezyklen eingelegt werden müssen so wird hier schon der nächste
  1090.     Befehl abgearbeitet sofern er nich auf das ergebnis des letzten
  1091.     angewiesen ist.
  1092.     Befehle die an LongwordAddressen (durch 4 teilbar) liegen werden
  1093.     DOPPELT(!) so schnell ausgeführt.
  1094.     Instruction-Cache (reicht um auch kompliziertere Schleifen stark zu
  1095.     beschleunigen)
  1096.     FPU-unterstützung. eine FPU kann direkt angesprochen werden (auf einem
  1097.     68000 war eine emulation zwischengeschaltet).
  1098.  
  1099.     Auf diesem Processor sollten Dbraschleifen verwendet werden.
  1100.     Auf den Blitter größtenteils verzichtet werden.
  1101.     Auf cache-optimierung geachtet werden. 
  1102.     Das Fastmem kan bedenkenlos benutzt werden,wohingegen das Chipmem
  1103.     nur mit der Kneifzange angefasst werden sollte.
  1104.     Füll den 256er Chache ! (Ist ja nicht besonders schwer..)
  1105.  
  1106.     
  1107.  
  1108. 68030:    Nur hardware optimierungen. Jetzt auch Daten-Cache ! sowie größerer
  1109.     Instruction-Cache.
  1110.     Eigentlich eine 'schönere' (schnellere) Version des 68020.
  1111.     Ein 50mhz 68030 mit 50mhz 68882 ist auf dem Amiga immernoch das
  1112.     schnellste was es gibt. (wenn das Gerücht um 80mhz 68040 nicht
  1113.     stimmt)
  1114.  
  1115.     Das Fastmem ist hier manchmal langsamer,was aber durch den Daten
  1116.     Cache aufgefangen werden sollte ?!
  1117.     Viele 'kleine' Befehle bei wenigen Speicherzugriffen lautet hier
  1118.     das Motto
  1119.  
  1120.  
  1121. 68040:    Hammerharte Architektur! Das Caching-system wurde stark erweitert
  1122.     und verbessert(?) aber es setzt eine genaue Kentniss der vielen
  1123.     Cache-Modi vorraus wenn man hier erfolgreich Coden will...
  1124.     Es wurde direkt eine FPU integriert, die noch schneller ist als
  1125.     die 68882. 
  1126.     Der 68040 is genial für Raytracing! benötigt aber ein sehr genaues
  1127.     studium der Processor-Architektur und eine gute Kenntnins der
  1128.     Speicherbausteile (Burst?,WaitStates?,Zugriffszeit?...).
  1129.  
  1130.     Der 68040 ist beim ansprechen des CHIPrams nur geringfügig schneller
  1131.     als ich beim eintippen der Zahl in einen Taschenrechner...
  1132.     Da auch das Fastmem meist nicht als 72ns RAM ausgeliefert wird
  1133.     kann man hier nur sagen : Finger weg vom RAM und nutzt den Cache !
  1134.  
  1135.  
  1136. PS:    NO RISC NO FUN !
  1137.  
  1138.  
  1139. Du mußt dich also entscheiden für welchen Processor du Programmierst...
  1140. Obwohl die eigentliche Entscheidung nur zwichen
  1141. 68000,68010  und  68020,68030,68030  fällt.
  1142. Wir wollen hier aber nochmal den guten(?) alten(!) 68000 bedienen .....
  1143.  
  1144.  
  1145. ALSO LOS :
  1146.  
  1147. Die Routiene soll eine horizontale Linie zeichnen von PixelA nach PixelB.
  1148. Also kriegen wir zwei X-Positionen Übergeben sowie ein Register das uns
  1149. auf den Anfang der richtigen Zeile Zeigt...
  1150.  
  1151. Fillline:                ;d0-pos1   d1-pos2
  1152.                     ;a6-linestart (ypos)
  1153.     cmp.w    d0,d1
  1154.     bge.s    .ok
  1155.     exg    d0,d1
  1156. .ok:    sub.w    d0,d1            ;d0-start d1-length
  1157.  
  1158. Das war noch ganz easy, aus den Koordinaten erstmal Start und Länge machen.
  1159.  
  1160.     cmp.w    #16,d1
  1161.     ble    ShortLine
  1162.  
  1163. Hier springen wir gleich raus wenns sich um eine 'kleine' Linie handelt.
  1164. Jetzt müssen wir das word ermittlen in dem unsere Linie anfängt ..
  1165.  
  1166.     move.w    d0,d2            ;save start
  1167.     lsr.w    #4,d0            ;start/16 (welches word)
  1168.     add.w    d0,d0            ;start*2  (wieder in bytes umrechnen)
  1169.     lea    (a6,d0.w),a0        ;START ADR
  1170.  
  1171. Die nächste Frage die uns Quält ist : bei welchen Pixel innerhalb dieses 
  1172. Words fängt unsere Linie denn nun genau an ? also ...
  1173.  
  1174.     and.w    #$f,d2            ;rest von Start/16
  1175.     
  1176. Wenn nun das ergebnis beispielsweise 6 wäre so wüßten wir das wir ,um bis
  1177. zur nächsten Wordgrenze zu füllen, %000000111111111 odern müßten.
  1178. (NACHVOLLZIEHEN !)
  1179. Wäre das Ergebnis 15 so käme %0000000000000001 ins aktuelle word und bei
  1180. 0 wäre es dann gleich %1111111111111111..
  1181. Werte unter 0 und über 15 sind nach dem AND #$F natürlich nicht mehr möglich.
  1182. eine Möglichkeit das Muster zu erzeugen wäre :
  1183.     moveq    #-1,dx
  1184.     lsr.w    d2,dx        
  1185. eine Andere Möglichkeit wäre das Auslesen aus einer Tabelle :
  1186.     add.w    d2,d2
  1187.     move.w    .bits(pc,d2.w),d0    ;Die Tabelle darf nicht weit weg
  1188.                      liegen (in code integrieren)!
  1189. Die Tabelle würde in diesem Fall so aussehen :
  1190. .Bits:    dc.w    %1111111111111111      
  1191.     dc.w    %0111111111111111  
  1192.     dc.w    %0011111111111111  
  1193.     dc.w    %0001111111111111  
  1194.     dc.w    %0000111111111111  
  1195.     dc.w    %0000011111111111
  1196.     dc.w    %0000001111111111
  1197.     dc.w    %0000000111111111
  1198.     dc.w    %0000000011111111
  1199.     dc.w    %0000000001111111
  1200.     dc.w    %0000000000111111
  1201.     dc.w    %0000000000011111
  1202.     dc.w    %0000000000001111
  1203.     dc.w    %0000000000000111
  1204.     dc.w    %0000000000000011
  1205.     dc.w    %0000000000000001
  1206. Fast jeder arbeitet mit einer solchen SHIFT-TABELLE aber ich weiß nicht ob
  1207. die BIT-Friemel-lösung nicht schneller ist ?! Da dies aber ein 68000 ist
  1208. ist die Vorberechnung vermutlich schneller.
  1209.  
  1210. Wir haben also den Richtigen Pattern um auf die nächste Word-Position zu
  1211. kommen in D0 !    Also worauf warten wir noch ? rein damit ...
  1212.  
  1213.     or.w    d0,(a0)+        ;Write Begin bytes
  1214.  
  1215. Jetzt ist aber die Frage : Wieviele Bits habe ich denn damit schon gesetzt?
  1216. denn dieser Wert muß nun ja von der Länge abgezogen werden !
  1217. Nun die Formel für dies wäre ja ganz einfach : 16 - PosInWord = PixDone !
  1218. Aber wie kriegen wird das raus....
  1219.  
  1220. ..Ja richtig wir wenden einen Trick der Bit-Friemler an : EOR.W #$f,D2
  1221. (wenn du das nicht verstehst dann hast du etwas weiter oben nicht richtig
  1222. aufgepasst!) Probiers im Notfall auf einem Zettel aus : Wenn du bei einer
  1223. Zahl zwischen 0 und 15 die unteren 4 Bit ($f=%1111) invertierst so erhälst
  1224. du y=15-x... toll was ...
  1225.  
  1226. Die Sache hat nur einen Haken : (ich gehe davon aus das wir den weg mit Tabelle
  1227. benutzen) wir haben PosInWord vorhin mit 2multipliziert um den Offset auf die
  1228. Tabelle zu erhalten. Noch ein Grund auf die Tabelle zu verzichten ?? aber
  1229. für Optimierungen bis du zuständig...
  1230. Also da ein Retten des Registers vorher und zurückholen nachher 2 Befehle
  1231. benötigt ist wohl das wieder durch zwei teilen am schnellsten...
  1232.  
  1233.     lsr.w    #1,d2
  1234.     eor.w    #$f,d2            ;how many bits done ?
  1235.  
  1236. Diese Zahl ziehen wir jetzt von der Länge ab...
  1237.  
  1238.     sub.w    d2,d1
  1239.     beq    .done
  1240.  
  1241. und verschwinden gleich wenn das schon alles war (länge=0). Wenn nicht so
  1242. müssen wir nun berechnen wie viele Words wir füllen können bevor das ende
  1243. der Linie erreicht ist (restlänge/16).
  1244.  
  1245.     move.w    d1,d2            ;copy length
  1246.     lsr.w    #4,d2            ;how many words can we fill ?
  1247.     beq    .rest
  1248.     moveq    #-1,d3            ;fill pattern
  1249.  
  1250. Wenn schon ein ganzes word zuviel ist (restlänge/16=0) dann springen wir
  1251. gleich in den Teil der die letzten bits 'von Hand' dranklebt.
  1252. Wenn nicht kommt nun der TURBO-FILL Teil der Routiene ! Das beschreiben des
  1253. Musters könnte übrigens auch außerhalb der Routiene geschehen um noch einige
  1254. Cyclen zu spaaren...
  1255. Doch bevor es weitergeht kommt noch ein Trick :
  1256.  
  1257. Normalerweise würde nun eine DBRA-Schleife folgen die die Words in den 
  1258. Speicher presst. Das bedeutet aber das nach jedem Move einmal der Dbra-
  1259. Befehl ausgeführt werden muß ! Auf einem 68020 ist dies nicht weiter 
  1260. Tragisch da schon beim zweiten Durchlauf Move&Dbra im Cahce stehen und
  1261. auch ein 68010 könnte (bei 1er plane) die Schleife erkennen aber ein
  1262. 68000 wird einfach nur langsamer ...
  1263.  
  1264. Deshalb greifen wir hier zu einem besonderem Trick :
  1265. (gefunden in Trexx-Warrior) 
  1266. Wir überlegen uns das die Schleife maximal 20 mal durchlaufen werden kann
  1267. (320/16=20) und legen demendsprechend folgenden Code ab :
  1268.     
  1269. .fill:    move.w    d3,(a0)+        ;20ig mal...
  1270.     move.w    d3,(a0)+
  1271.     move.w    d3,(a0)+
  1272.     move.w    d3,(a0)+
  1273.     move.w    d3,(a0)+
  1274.     .
  1275.     .
  1276.     .
  1277. Und wenn wir nun 20ig moves benötigen springen wir einfach zu .fill !
  1278. Wenn wir aber nur 19 moves benötigen springen wir nach .fill+2 !
  1279. bei 18 moves nach .fill+4 uns so weiter....  
  1280. Soweit so gut, um den Offset zu berechnen wäre aber nun ein y=20-x fällig
  1281. und das geht NICHT mit eor.w #20,dx ! (20 ist keine 2erpotenz-1)
  1282. Man könnte einfach 31 Moves anlegen und dann den Offset über EOR.W #31,dx 
  1283. berechnen ! aber platzsparender ist es das den Karren vor den Ochsen zu
  1284. spannen oder das Pferd von hinten aufzuzäumen ...
  1285. Was ich sagen will ist das Label '.fill:' Einfach hinter das letzte Move
  1286. zu setzten weill dann : bei 0 moves zu .fill gejumpt werden kann.
  1287.             bei 1 move zu .fill-2
  1288.             bei 15 moves zu .fill-(15*2)...
  1289. Der Offset Läßt sich also einfach durch y=-x*2 berechnen...
  1290.  
  1291.     add.w    d2,d2
  1292.     neg.w    d2
  1293.     jmp    .fill(pc,d2.w)        ;instead of dbra !
  1294.  
  1295. 3 Befehle Am Anfang anstelle von einem Dbra nach jedem Move ...
  1296. Diese Technik kann auch einem 68020 unter Umständen zu noch mehr Speed
  1297. verhelfen da 20 Moves noch locker in den Cache passen ! Aber bei 8Planes
  1298. wäre ein Dbra dann auf jeden Fall schneller...
  1299.  
  1300. Mit diesem Turbo-Fill (Bei JEDEM Befehl 16pixel !!!) haben wir die SCHNELLSTE
  1301. MÖGLICHE 16BitFill-loop die es gibt ! da wirklich bei jedem befehl 16bit
  1302. gefüllt werden...
  1303. Nach dieser Turbo-schleife kommt nun noch etwas berechnung um die rest-bits
  1304. zu setzten :
  1305.  
  1306. .rest:
  1307.     and.w    #$f,d1            ;rest bits...
  1308.     beq.s    .done
  1309.  
  1310. Aus der Länge berechnen wir nun den Teil der nicht mehr ganz in ein word
  1311. passte und falls es einen solchen nicht gibt (länge/16 teilbar) gehts
  1312. gleich raus..
  1313. Um die rest-bits zu setzten verwenden wir nun wieder eine Tabelle..
  1314.  
  1315.     add.w    d1,d1
  1316.     move.w    bits2(pc,d1.w),d0
  1317.     or.w    d0,(a0)
  1318. .done:
  1319.     rts
  1320.  
  1321. Nicht besonders kompliziert ,was ? Die Tabelle muß hier allerding genau
  1322. invertiert sein im vergleich zu ersten Shift-Tabelle :
  1323.  
  1324. Bits2:    dc.w    %0000000000000000
  1325.     dc.w    %1000000000000000
  1326.     dc.w    %1100000000000000
  1327.     dc.w    %1110000000000000
  1328.     dc.w    %1111000000000000
  1329.     dc.w    %1111100000000000
  1330.     dc.w    %1111110000000000
  1331.     dc.w    %1111111000000000
  1332.     dc.w    %1111111100000000
  1333.     dc.w    %1111111110000000
  1334.     dc.w    %1111111111000000
  1335.     dc.w    %1111111111100000
  1336.     dc.w    %1111111111110000
  1337.     dc.w    %1111111111111000
  1338.     dc.w    %1111111111111100
  1339.     dc.w    %1111111111111110
  1340.  
  1341. Vergiß bitte nicht (zur 68020 beschleunigung) nach jeder Tabelle ein 
  1342.     CNOP  0,4
  1343. zu setzten damit der danachfolgende Code wieder an einer durch 4 Teilbaren
  1344. Addresse liegt ! Die Tabellen müssen mitten im Code stehen weil sie nicht
  1345. weiter als 256 vom (pc,xx) entfernd stehen dürfen ! Und über PC müssen
  1346. sie angesprochen werden weil wir sonst nicht genügend Addressregister
  1347. frei haben um den Turbofill auch mit 3/4/5 Bitplanes durchzuziehen !
  1348.  
  1349. Aber es fehlt noch ein Teil ! Der ShortLine-Algorithmus ! Ich habe zwar
  1350. weiter oben schon einen Vorgestellt aber hier kommt ein besserer und zu
  1351. dieser (getesteten) Routiene passender :
  1352.  
  1353. ShortLine:                ;do-firstpix d1-length
  1354.     moveq    #1,d2
  1355.     ror.l    d2,d2
  1356.     asr.l    d1,d2
  1357.  
  1358. Na ? Hast du verstanden wie hier das BitMuster erstellt wurde ?? Das Ziel
  1359. war kalr : Es sollten D1 bits am oberen rand des Highword von d2 gesetzt
  1360. werden.
  1361.     moveq    #1,d2        ->   d2=%0000000000000000 0000000000000001
  1362.     ror.l    d2,d2        ->   d2=%1000000000000000 0000000000000000
  1363.                     Diese zahl ist NEGATIV ! weil bit 31
  1364.     {=ror.l #1,d2}            gesetzt ! (erinner dich : Sign-bit ist immer das höchste...)
  1365.  
  1366.     asr.l    d1,d2        
  1367.  
  1368. Schiebt nun links 1bits nach weil die Zahl ja negativ ist ! Ob dieses Prinzip
  1369. schneller ist als das weiter oben vorgestellte weiß ich nicht, ich wollte
  1370. nur deine Bit-Friemel Kentnisse noch einmal erproben.
  1371. Also weiter im Text...
  1372.  
  1373.     move.w    d0,d1        ;xpos retten
  1374.     and.w    #$f,d0        ;pos im word
  1375.     lsr.l    d0,d2        ;bitmuster auf diese Pos shiften
  1376.  
  1377.     lsr.w    #4,d1        ;word offset berechnen
  1378.     add.w    d1,d1
  1379.     
  1380.     or.l    d2,(a6,d1.w)    ;Muster schreiben
  1381.     rts
  1382.  
  1383. Tja das wars auch schon um alles vom Punkt zur 15pix langen Linie an jeder
  1384. Xposition zu zeichnen. Und zusammen mit der Turbo-Fill routiene kann jede
  1385. waagerechte Linie von 1-320 pixel länge an jeder Xposition mit high-speed 
  1386. gefüllt werden.
  1387. Um dies auch in vielen bunten Farben zu ermöglichen sollte man einfach
  1388. neben A0 auch noch A1/A2/A3/A4... als Plane pointer verwenden und dann
  1389. FÜR JEDE FARBE EINE ROUTIENE ! schreiben. Nur so kann die hohe Geschwindigkeit
  1390. auch bei 16Farben beibehalten werden...
  1391.  
  1392. 68020 User haben es etwas einfacher beim ShortLine :
  1393. (Und das sogar bei 32bitFillLine)
  1394.  
  1395. Shortline:
  1396.     bfset    (a6){d0:d1}
  1397.     rts
  1398.  
  1399. Also geh und hol dir einen ordentlichen processor....
  1400.  
  1401.  
  1402. So - damit wär das Kapitel ProcessorVector fast durch ! Und dein Stil und
  1403. dein Wissen hat sich hoffentlich schon etwas verbessert/erweitert..
  1404. Sprachlich jedenfalls können wir schon ziemlich auftrumpfen :
  1405.  
  1406.     Damals : Ich mach BlitterLines und Füll die dann...
  1407.     Heute  : Wir verwenden einen Integer-Bresenham und eine 16bit
  1408.          Turbo-Fill routiene um Polygone zu zeichnen.
  1409.  
  1410.     Damals : Das geht ziemlich schnell..
  1411.     Heute  : Wir erreichen eine maximale Effizienz von 4pixel pro 
  1412.          Taktzyklus (ohne Cache...)
  1413.  
  1414.     Damals : Ich Bearbeite immer ein Rechteck um die Fläche und das
  1415.          bei 16farben inconvex 12 mal...
  1416.     Heute  : kein Punkt außerhalb der Fläche wird angesprochen und
  1417.          jeder Punkt innerhalb wird auch bei inconvexen Flächen
  1418.          nur 1mal pro Fläche bearbeitet.
  1419.  
  1420. Also Du hast jetzt das KNOW HOW und das KNOW WHY ! Einige dich jetzt noch
  1421. mit dir selbst über das KNOW WHEN und ab gehts...
  1422.  
  1423.  
  1424.  
  1425. SHADING
  1426. ----------
  1427.  
  1428. Ja langsam haben wir genug Rüstzeug zusammen um tiefer einzusteigen ...
  1429. Es gibt viele Arten von Shading mit tollen Namen wie :
  1430. PHONG-SHADE,GOURAUD-SHADE,FLAT-SHADE,METAL-SHADE,ENVIRONMENT-SHADE...
  1431. All diese Namen stehen für Beleuchtungmodelle. Jedes davon stellt einen
  1432. anderen Kompromiß zwischen Geschwindigkeit,Realismus und Aufwand dar.
  1433. Ihnen allen liegt ein Algorithmus zugrunde der für einen Punkt im Raum
  1434. (x,y,z) dessen Helligkeit berechnet wenn sich an einer anderen Stelle des
  1435. Raumes eine Lichtquelle (lx,ly,lz) befindet.
  1436. Diesen Grundalgorithmus kann man auf mehrere Lichtquellen ausdehnen (helligkeit
  1437. durch L1 PLUS helligkeit von L2 ... =gesamt helligkeit des Punktes) und
  1438. man kann auch Farbige Lichtquellen unterstützen wenn man anstelle von einer
  1439. mit drei Helligkeiten (rot,grün,blau) arbeitet (dies macht nur bei mehreren
  1440. Lichquellen sinn).
  1441.  
  1442. Dieser Algorithmus ist eigentlich der Winkel des Lichtstrahls zur Fläche.
  1443. Um diesen jedoch zu berechnen benötigen wir zunächst einen Vector der
  1444. die Lage der Fläche im Raum beschreibt ! Dafür werden wir einen Normal-
  1445. Vector (Steht senkrecht auf der fläche) verwenden der beim rotieren der
  1446. Fläche entsprechend mitrotiert wird.
  1447.  
  1448. Zur erstellung des Normalvectors :
  1449.  
  1450.  xa=px2-px1   (differenzvector zwischen Punkt1 und 2 der Fläche)
  1451.  ya=py2-py1
  1452.  za=pz2-pz1
  1453.  
  1454.  xb=px3-px1   (differenzvector zwischen Punkt1 und 3 der Fläche)
  1455.  yb=py3-py1
  1456.  zb=pz3-pz1
  1457.  
  1458.  xn=ya*zb-za*yb
  1459.  yn=za*xb-xa*zb
  1460.  zn=xa*yb-ya*xb
  1461.  
  1462. Die Bildung der Differenz-vectoren dürfte dir von der Hidden-Line-Berechnung
  1463. her bekannt sein und die eigentliche Normalvector berechnung ist auch keine
  1464. große Hürde,da sie ja nur einmal am Anfang gemacht wird und dann immer
  1465. mitrotiert wird...
  1466.  
  1467. Dann wird der Winkel noch durch das Skalarprodukt ermittelt :
  1468.  
  1469.     S=| xn*lx+yn*ly+zn*lz |
  1470.  
  1471. Aber Du merkst sicher schon langsam das dieser Weg nicht der schnellste ist
  1472. vorallem benötigt man noch eine Wurzel um die Länge des Vectors zu ermitteln
  1473. weil man das SkalarProdukt nämlich durch diese Teilen muß um einen Wert
  1474. zwischen 0-1 zu erhalten egal wie groß die Fläche ist...
  1475.  
  1476. Also kommen wir zu vereinfachungen die das ganze auch für nicht FPU-besitzer
  1477. erreichbar machen ...
  1478.  
  1479. Die verbreitste und vermutlich auch beste faked-lightsource berechnung ist
  1480. die die einfach den Durchschnitt aller Z-Koordinaten einer Fläche durch
  1481. einen Wert Teilt und diesen dann als Helligkeit interpretiert...
  1482. Das Problem hierbei ist das der Wert durch den Dividiert wird so gewählt
  1483. werden muß das auch ganz nahe und ganz weit entfernte Flächen noch richtig
  1484. behandelt werden.
  1485. Aber das ist uns egal ! Z-koords=Lightsource ! solche Formeln lieben Coder...
  1486. (Bei der Verwendung von Zkoords liegt die Lichtquelle übrigens immer auf
  1487. der Nase des Betrachters...)
  1488.  
  1489. Ok du kannst nun die Helligkeit eines Punktes ermitteln also weiter mit den
  1490. Shading-prinzipien...
  1491.  
  1492. FLAT-SHADING
  1493. ------------
  1494. Ist lediglich ein cooler Name für das was der Volksmund Light-Sourcing
  1495. nennt und bezeichnet das Verfahren bei dem eine gesamte Fläche mit ihrer
  1496. Durchschnittlichen helligkeit gefüllt wird...
  1497.  
  1498. GOURAUD-SHADING
  1499. ---------------
  1500. Ist die schnellste Shading Variante ! Hier wird für jeden Eckpunkt einer
  1501. Fläche die helligkeit ermittelt und alle dazischen liegenden Punkte werden
  1502. endsprechend Interpoliert.
  1503. Wie dieses Verfahren zu realisieren ist wird später noch genauer besprochen...
  1504.  
  1505. METAL-SHADING
  1506. -------------
  1507. Ist ein erweitertes Gouraud-shading das auch einen Glanzpunkt auf der Fläche
  1508. ermöglicht. Es wird berechnet ob der Lichtstrahl die Fläche schneidet (steil
  1509. darauftrift) und wenn ja wird dieser Schnittpunkt berechnet.
  1510. Daraufhin wird die Fläche zerlegt x-----x       x-x---x
  1511.                   |     |  __\  | |   |
  1512.                   | ·   |    /  x-X---x
  1513.                   |     |       | |   |
  1514.                   x-----x       x-x---x
  1515.                                    
  1516.                                  x=Eckpunkte ·=Lichtstrahlzentrum 
  1517. Die sich ergebenen 4 Flächen werden nun Gouraud-geshadet. Wobei der neu
  1518. eingefügte Eckpunkt (X) eine extrem helle Farbe hat die die normale Fläche
  1519. sonst nicht erreichen kann. (z.B: Lichpunkt=weiß  Fläche max=hell blau)
  1520. Dieses Shading sieht schon sehr echt aus und kann auf den ersten Blick wie
  1521. Raytracing wirken.
  1522. Ist aber auch ziemlich langsam weil bei mehreren Lichtquellen die Fläche
  1523. rekrusiv mehrmals zerteilt werden muß.
  1524.  
  1525. PHONG-SHADING
  1526. -------------
  1527. Ist vermutlich von jemandem entwickelt worden,der sich um die Zeit keine 
  1528. Gedanken zu machen brauchte. Denn hier wird wirklich für jeden Punkt der
  1529. Fläche die helligkeit einzeln berechnet.
  1530. Ein aufwendiges Verfahren das allerdings auch Rauhe Oberflächen und
  1531. Bump-Mapping ermöglicht obwohl es immernoch schneller ist als eine ScanLine-
  1532. Berechnung.
  1533.  
  1534. ENVIRONMENT-SHADING
  1535. -------------------
  1536. Wurde bisher nur in CALIGARI verwendet und bezeichnet ein Verfahren um aus
  1537. Phong-shading fast echtes Raytracing zu machen indem auch Spiegelungen
  1538. ermöglicht werden. Hierzu wird, wenn die Spiegelung eines Schachfeldes in
  1539. einem Würfel erzeugt werden soll, zunächst das Schachfeld 'aus sicht der
  1540. spiegelnden Fläche' gezeichnet und dieses Bild wird dann als TextureMap
  1541. auf die Spiegelnde Fläche gelegt...
  1542. Interissanter aber bei vielen Spiegelungen sehr komplizierter und rekrusiver
  1543. Algorithmus. Das verfahren ist fast immer wesentlich schneller als wirkliches
  1544. Ray-tracing aber fast nie schneller als Scan-Line-berechnung.
  1545.  
  1546.  
  1547.  
  1548. WIR SHADEN SELBST...
  1549. ---------------------
  1550. Es hat einige Zeit gedauert bis ich mir klar war darüber wie Gouraud-shading
  1551. zu Programmieren ist aber denk erst mal selbst nach...
  1552.  
  1553. Aufgabe:  Man hat ein Viereck (z.B Saloförmig) und man hat die Helligkeit
  1554.       jedes Eckpunktes (die sind alle verschieden weil das viereck
  1555.       völlig quer im Raum liegt) und nun soll daraus eine Fläche werden
  1556.       deren Helligkeit für jeden Punkt genau so festgelegt wird das ein
  1557.       sauberer Übergang zwischen den 4 festen Werten entsteht.
  1558.  
  1559.  
  1560.                      { NA KANNST DU's OHNE TIP ?? }
  1561.    
  1562.  
  1563.  
  1564. Tips:      Man kann die Fläche trotzdem aus waagerechten Linien aufbauen.
  1565.       Was barucht man nun außer den xstart und xstop werten ?
  1566.       Wie kann man das bekommen ?
  1567.  
  1568.  
  1569. Lösung:
  1570.  
  1571. Während wir das 'Outline'-der Fläche berechnen (xstart&xstop für jede zeile)
  1572. speichern wir auch die Helligkeit am anfang und ende der Zeile mit.
  1573. (Oder besser gesagt speichern wir die Z-Koordinate mit weil die genauer ist
  1574. als die Helligkeit.)
  1575. Diese können wir leicht berechnen weil wir die Helligkeit am anfang und
  1576. am ende einer Flächen-Kante kennen.
  1577. Also wenn wir die Linie von Punkt1 nach Punkt2 berechnen legen wir nicht
  1578. nur für jede Zeile die X-Koordinate dieser Linie ab sondern auch die 
  1579. Z-Koordinate. Beide Werte kommen je nachdem ob es sich bei der Linie um
  1580. Xstart oder Xstop linie handelt in eine andere Spalte in unserem Buffer.
  1581.  
  1582. Wir brauchen also 4 einträge pro Zeile :
  1583.  
  1584.    Xstart | Zstart | Xstop | Zstop
  1585.  
  1586. Wenn wir diese Daten für jede Zeile der Fläche haben können wir mit einer
  1587. leicht veränderten FillLine routiene blitzartig eine Gouraud geshadete Fläche
  1588. zeichnen.
  1589.  
  1590. Um nun neben den X-koordinaten auch noch für jeden Punkt der Linie eine
  1591. Z-koordinate zu erhalten gibt es wieder zwei Möglichkeiten :
  1592.  
  1593.     1)  Wir schreiben einen 3D-bresenham 
  1594.     2)  Wir erzeugen die Z-koordinate durch Festkomma-addition
  1595.  
  1596. Ich hab mich schon an Möglichkeit 1 versucht - bin aber gescheitert und so
  1597. wie es aussah wäre diese Lösung nicht einmal besonders schnell geworden...
  1598. Also bleibt uns nur weg nummer 2:
  1599.  
  1600. Wir kennen die Z-Koordinate am Anfang - Wir kennen die z-Koordinate am Ende
  1601. und wir wissen wieviele Punkte unsere Linie lang sein wird...
  1602. Falls das nicht ganz klar sein sollte :
  1603. Die Länge einer Linie definiert sich in den Augen eines Mathematikers
  1604. (spätestens seit Pythagoras) so :
  1605.  
  1606.     l=sqr((x2-x1)²+(y2-y1)²)
  1607.  
  1608. dank Wurzel keine besonders anziehende Formel... aber sie kann auch für
  1609. Computersysteme nicht gelten sagt uns unsere Logik (ja tut sie das??)..
  1610. Denn So würde für eine Linie von 0/0 nach 2/2 eine länge von 2.8284271...
  1611. rauskommen - das kann auf dem Papier auch stimmen aber in Pixeln ist es
  1612. völlig unmöglich einen nicht Ganzzahligen Wert als Länge zu erhalten denn
  1613. schließlich kann die Linie keine halben oder 0.82tel Pixel benutzen...
  1614. In der Praxis zeigt sich jedenfalls das eine Linie immer soviele Pixel hat
  1615. wie das größere Delta der Linie (+/- eins).
  1616. Also für Coder gilt die Formel :
  1617.  
  1618.     l=gd
  1619.  
  1620. Toll wie wir das gekürzt haben... Also sosehr ich auch Pixeltreppen verab-
  1621. scheue sie haben auch ihre Vorteile !
  1622.  
  1623. Also wir kennen den Start Z-Wert und wir wissen das wir bei jedem Punkt
  1624.  (zend-zstart)/länge
  1625. addieren müssen um die nächste Z-koordinate zu erhalten.
  1626. Das führt uns zu einem weiteren Randproblem : den Fließkomma-zahlen
  1627.  
  1628.  
  1629. DIE WELT HINTER DEM KOMMA...
  1630. ------------------------------
  1631.  
  1632. Zahlen mit Nachkommastellen ohne FPU zu verwalten und mit ihnen zu rechnen
  1633. ist nicht ganz einfach - genaugenommen sogar Unmöglich.
  1634. An diesem Punkt könnten wir nun sagen : Schade,dann geb' ich eben auf....
  1635.  
  1636. Aber, ja richtig das tun wir nicht weil wir ja alle wissen das es sowas wie
  1637. Fließkommazahlen gibt. Will man 124.78 in einer Computerverständlichen
  1638. Form speichern so wird beim Fließkommaverfahren 12478*10^-2 abgelegt
  1639. (Genauer es werden 12478 und -2 abgelegt).
  1640. Die Zahl wird also so umgerechnet das alle Nachkommastellen wegfallen,
  1641. die zahl aber Mathematisch noch die Selbe ist.
  1642. Dieses Prinzip (WERT&EXPONENT) ist zwar sehr Flexibel und sehr genau aber
  1643. es ist auch sehr Langsam (!) und damit für uns uninterissant...
  1644.  
  1645. Viel besser ist für uns das Festkomma-system :
  1646. Auf dieses System wird auch jeder Coder früher oder später selber kommen.
  1647. Was würdest du tun um aus 124.78 eine Zahl ohne Komma zu machen ??
  1648. Richtig du würdest sie mit 100 Multiplizieren. Das hätte nur den Nachteil
  1649. das eben nur Zahlen mit maximal 2 Nachkommastellen ohne Verlust in ganzzahlen 
  1650. umgewandelt werden könnten.
  1651. Aber das Prinzip ist klar :
  1652. Um eine Zahl zur Ganzzahl zu machen wird sie mit einem Faktor F multipliziert
  1653.  
  1654.   integer=real*f
  1655.  
  1656. Soweit Kinderleicht.. Um nun zwei Kommazahlen zu addieren könnte man so
  1657. vorgehen :
  1658.  
  1659.    1.34 + 3.66 = 5
  1660.  
  1661.    f = 100
  1662.    1.34*f = 134
  1663.    3.66*f = 366
  1664.  
  1665.    134+366 = 500
  1666.  
  1667.    500/f = 5
  1668.  
  1669. Also addition (und auch subtraktionen) sind auch mit den Selbstgemachten
  1670. Ganzzahlen ohne Probleme möglich. Um später wieder den Vorkommateil des
  1671. Ergebinsses zu erhalten genügt eine Division durch F.
  1672.  
  1673. Doch ein Fakor von 100 oder 1000 wie wir Menschen ihn lieben ist für Computer
  1674. geradezu Abscheulich ! Prbieren wir es deshalb mit einem Computer mäßigen
  1675. Faktor von f=256.
  1676.  
  1677.    1.34*f = 343 (gerundet)
  1678.    3.66*f = 937 (gerundet)
  1679.  
  1680.    343+937 = 1280
  1681.  
  1682.    1280/f = 5
  1683.  
  1684. Es Funktioniert also mit jedem beliebigen F - obwohl wir schon hier sehen :
  1685. Um so kleiner der Faktor umso Ungenauer das Ergebnis (weniger Nachkomma-
  1686. stellen). Bei einem Faktor von 256 hätten wir 8bit für die Nachkommastellen
  1687. reserviert. Wenn man nur Zahlen zwischen 0..1 darstellen will könnte man
  1688. sogar 15bit für die Nachkommastellen benutzen (f=32768) ohne der Word-
  1689. bereich verlassen zu müssen.
  1690.  
  1691. Doch nun zum ersten Haken :
  1692.  
  1693.   1.34*3.66 = 4.9044
  1694.  
  1695.   f=100
  1696.  
  1697.   134*366 = 49044
  1698.  
  1699.   49044/f = 490.44 ! (nicht = 4.9044)
  1700.  
  1701. Überascht ? Nein ! Das konnte natürlich nicht klappen ! Wir sehen also :
  1702. Bei einer Multiplikation im FestKomma-system darf entweder nur eine der
  1703. beiden (zu multiplizierenden) Zahlen mit F erweitert sein ODER es muß
  1704. danach durch F dividiert werden um nicht doppelt mit F erweitert zu haben.
  1705. Ein Beispiel :
  1706.  
  1707.   1.34*3.66 = 4.9044
  1708.  
  1709. f=1024
  1710.  
  1711.   1.34*f = 1372
  1712.   3.66*f = 3748
  1713.  
  1714.  1372*3748/f = 5021
  1715.  
  1716.   5021/f = 5 (gerundet)
  1717.  
  1718. Es Funktioniert also ! Aber schon hier macht sich die Ungenauigkeit bemerkbar
  1719. denn selbst mit F=1024 (10bit) kommt nur 4.91... anstelle von 5 raus !
  1720. In der Praxis wird sich aber selten ein Problem stellen, daß es verlangt
  1721. zwei Zahlen mit Nachkommastellen zu Multiplizieren. Meist hat nur eine
  1722. von beiden Stellen hinter dem Komma und in diesem fall genügt folgender 
  1723. Weg :
  1724.  
  1725.      a=1.23   b=7
  1726.  
  1727.      y=a*b
  1728.  
  1729.      y*f=(a*f)*b
  1730.  
  1731. Ok, ich glaube die Multiplikation hat auch jeder geschnallt - also weiter...
  1732. Bei der Division verhält es sich ähnlich :
  1733.  
  1734.     y=a/b
  1735.  
  1736.     y*f=(a*f)/b
  1737.  
  1738. Also auch hier : NUR eine der Zahlen mit F erweitern - haben beide 
  1739. Nachkommastellen so muß eine doppelt erweitert werden y*f=(a*f*f)/(b*f)
  1740.  
  1741. Ok, das rechnen in der Welt der Festkommazahlen ist also geklärt - auf zur
  1742. Praxis...
  1743.  
  1744. Sagen wir wir haben zwei INTEGER-Werte (a und b) die Dividiert werden sollen.
  1745. Das Ergebnis soll aber MIT Nachkommastellen gerettet werden. Also :
  1746.  
  1747.     a=a*f  (eine mit f erweitern)
  1748.     c=a/b  (c ist nun Festkommazahl mit dem Ergebnis von a/b)
  1749.  
  1750. Wenn dieses Ergebnis nun auf eine Andere Zahl addiert werden soll so muß dies
  1751. auch eine Festkomma-Zahl sein, sie muß also auch mit F erweitert sein.
  1752.  
  1753. Kommen wir nun zum interissanten Teil, nämlich der Implementation in 
  1754. Assembler. Wir wollen eine möglichst hohe Genauigkeit also verwenden wir
  1755. 16bit für den Nachkommateil und 16bit für den Vorkommateil - genau ein
  1756. Longword (so ein Zufall)...
  1757. ACHTUNG : Dies geht nur auf >=68020 Processoren !!! Wegen DIVU.L !!!!
  1758.  
  1759.  
  1760. Um eine 'normale' Zahl in eine 'erweiterte' Zahl umzuwandeln genügt nun
  1761. ein :
  1762.  
  1763.     SWAP    Dx   (*65536)
  1764.     CLR.w    Dx   (Nachkommateil (lowword) löschen)
  1765.  
  1766. Sofern das Highword der 'normalen' Zahl garantiert 0 war kann das CLR auch
  1767. entfallen. Aus einer 'erweiterten' Zahl wird auch blitzartig wieder eine
  1768. 'normale' :
  1769.  
  1770.     SWAP    Dx   (/65536)
  1771.     EXT.l    Dx    
  1772.  
  1773. Auch hier kann das EXT entfallen wen einem das High-word egal ist oder wenn
  1774. man die zahl später wieder zurückwandeln will - die Nachkommastellen so zu 
  1775. sagen im Highword zwischenspeichert und später wieder (durch ein SWAP)
  1776. die alte Festkomma-zahl herzustellen.
  1777. Wenn man sich also mühe gibt so muß man immer nur SWAPpen um vom einen in
  1778. den Anderen Zustand zu wechseln ! Man sollte aber höllisch aufpassen wann
  1779. wo was im High- und was im Low- word steht ! Durch das viele Swappen kann
  1780. man leicht die Übersicht verlieren.
  1781.  
  1782. Ein Beispiel :
  1783.  
  1784.  (4/18)*16+0.5 = 4
  1785.  
  1786. V=vorkomma N=nachkomma
  1787.  
  1788.     moveq    #4,d0        ;a=4    (high=$0000 Low=$0004)  0/V
  1789.     moveq    #18,d1        ;b=18   (high=$0000 Low=$0012)  0/V
  1790.     
  1791.     swap    d0        ;a=4*f  (high=$0004 Low=$0000)  V/N 
  1792.  
  1793.     divs.l    d1,d0        ;a=a/b  (high=$0000 Low=$38e3)  V/N 
  1794.             
  1795.     lsl.l    #4,d0        ;a=a*16 (high=$0003 Low=$8e30)  V/N
  1796.                 ;    \-nur eine der zahlen war erweitert (a)
  1797.  
  1798.     moveq    #1,d1        ;b=1    (high=$0000 Low=$0001)  0/V
  1799.     swap    d1        ;b=b*f  (high=$0001 Low=$0000)  V/N
  1800.     lsr.l    #1,d1        ;b=b/2  (high=$0000 Low=$8000)  V/N
  1801.  
  1802.     add.l    d1,d0        ;a=a+b  (high=$0004 Low=$0e30)  V/N
  1803.     swap    d0        ;a=a/f  (high=$0e30 Low=$0004)  N/V
  1804.     
  1805.     add.w    d0,d7        ;das Ergebnis auf andere Integer Zahl addieren
  1806.                 ;d7+int(a)
  1807.  
  1808.     swap    d0        ;a=a*f  (high=$0004 Low=$0e30)  V/N
  1809.     
  1810.     ;Weiterrechnen......
  1811.  
  1812.     swap    d0        ;a=a/f  N/V
  1813.     ext.l    d0        ;       0/V
  1814.  
  1815. Alles Klaro ? Na Prima ! Ich erkläre dir das alles so genau weil ich später
  1816. vorraussetzen werde das du ohne Probleme überall mit Integer und Real-zahlen
  1817. jonglieren kannst ohne dabei über ein SWAP zu stolpern...
  1818.  
  1819. Aber es kommt noch besser - denn bisher benötigte man 2 SWAP Befehle wenn
  1820. man (wie es später oft vorkommen wird) nur mal kurz den Vorkommateil als
  1821. Offset benötigt so zum Beispliel :
  1822.  
  1823.     d0 - ist erweiterter Zähler
  1824.     d1 - ist erweiterte Zahl
  1825.  
  1826. Loop:
  1827.     add.l    d1,d0        ;raufzählen
  1828.     swap    d0        ;integer machen
  1829.     move.w    (a0,d0.w),d7    ;als offset benutzen (nur unteres word!!!)
  1830.     swap    d0        ;wieder die alte Real-zahl...
  1831.  
  1832.  
  1833. Diese Art des Speicher-addressierens mit Real-Zahlen werden wir bei allen
  1834. Möglichen Gelegenheiten wiederfinden ! Darum gleich hier eine weitere
  1835. Optimierung, die allerdings noch mehr Gehirn-verknotung erfordert :
  1836.  
  1837. Zunächst die Idee : 
  1838. Es wäre viel nützlicher wenn anstelle der alten aufteilung :HIGHword=Vork.
  1839. und LOWword=Nachk. man es schaffen könnte die Zahlen so im speicher zu
  1840. halten : HIGHword=nachk. LOWword=Vork. ! (genau umgedreht also).
  1841. Warum dies von Vorteil ist liegt nach dem obigen Beispiel auf der Hand :
  1842. durch ein '(a0,d0.w)' kann direkt der Vorkommateil angesprochen werden 
  1843. ohne erst swappen zu müssen.
  1844.  
  1845. Doch diese Art von Zahlen läßt sich nicht so einfach Addieren, weil bei
  1846. einem 'überlauf' des Nachkommateils (highwords) nicht automatisch der
  1847. Vorkommateil (lowword) um 1ns erhöht wird,wie dies bei der alten Aufteilung
  1848. der Fall war.
  1849. Aber hier hilft ein Trick :
  1850.  
  1851.     moveq    #0,d7        ;dummy register das auf Null gesetzt werden
  1852.                 ;muß !
  1853.  
  1854.     in d0 steht ein Counter im neuen system (N/V)
  1855.     in d1 steht eine Zahl im neuen system (N/V)
  1856.  
  1857.     add.l    d1,d0        ;Addition mit Festkommazahlen im N/V-system.
  1858.     addx.w    d7,d0        
  1859.  
  1860. Tja, das sieht cool aus nicht ? Ich war ziemlich stolz damals auf diesen
  1861. Einfall - bis ich bemerkte das den schon viele vor mir hatten - aber egal.
  1862. Also wir führen eine Normale Addition aus und wenn das Highword einen
  1863. Überlauf hatte (nachkommateil) dann wird von ADD automatisch das X-FLAG
  1864. gesetzt ! (siehe Bit-friemel Tricks).
  1865. Der Nächste Befehl (ADDX.w) addiert nun D7 auf D0 - was ziemlich wirkungslos
  1866. ist weil D7 immer auf 0 steht; sinnlos also ? Nein,denn AddX prüft außerdem
  1867. das X-Flag und addiert wenn es gesetzt ist noch 1 zusätzlich auf D0 !
  1868. Damit wird, wenn der Nachkommateil überläuft (0.9999+0.1), automatisch der
  1869. Vorkommateil (im LowWord) um eins erhöht.
  1870. Nach dem ADDX ist das X-flag wieder gelöscht und es kann von neuem die
  1871. Schleife durchlaufen werden....
  1872.  
  1873. Wir haben also mit nur zwei befehlen zwei Festkommazahlen mit Vorkommateil
  1874. im LOWword addiert. Effektiv bedeutet das einen Befehl gespaart im vergleich
  1875. zur swap/add/swap methode - nicht viel ? kann sein aber das ist der Stoff 
  1876. aus dem Rekorde sind !
  1877.  
  1878. Eine Subtraktion funktioniert endsprechend :
  1879.  
  1880.     sub.l    d1,d0
  1881.     subx.w    d7,d0
  1882.  
  1883. Nur Multiplikationen und Divisionen sind NICHT in diesem System möglich !!
  1884. Hierzu muß mittels eines SWAP wieder in das 'alte' V/N-system umgeschaltet
  1885. werden. Nach der Rechenoperation gehts dann mittels SWAP wieder im N/V-
  1886. system weiter...
  1887.  
  1888.     Um d1 zu addieren und dann durch d2 zu teilen in einer schleife :
  1889.  
  1890.     add.l    d1,d0        ;N/V-addition
  1891.     addx.w    d7,d0
  1892.     swap    d0        ;make V/N
  1893.     divu.l    d2,d0        ;V/N-division
  1894.     swap    d0        ;make N/V
  1895.     .
  1896.     .
  1897.  
  1898. Ich glaube du ahnst schon langsam wie einen swap verwirren kann...
  1899.  
  1900. Noch etwas wirrer wird es wenn man in dem N/V-system multiplikationen durch
  1901. Shiften durchführen will - dies ist möglich wenn man anstelle von
  1902.  
  1903.     lsl.w    #4,d0        ;normales *16
  1904.  
  1905. den
  1906.     
  1907.     rol.l    #4,d0        ;n/v *16
  1908.  
  1909. Befehl verwendet. Dies ist notwendig damit die bits aus dem Nachkommateil
  1910. richtig in den Vorkommateil übertragen werden. ACHTUNG : Bei zu großen
  1911. Werten findet ein Überlauf im Low-word statt und aus ganz großen Werten
  1912. werden ganz kleine... (dieser Fehler tritt aber auch bei INTEGER-werten
  1913. auf).
  1914. Eine Division ist auch mit shiften möglich - ist aber schneller wenn man
  1915. mit zwei kurzen Swap's auf V/N umschaltet. Im N/V-modus wäre nämlich noch
  1916. ein AND nötig um vom HIGH ins LOW-word geschobene Bits wieder zu eliminieren.
  1917.  
  1918.     ror.l    #x,d0                ;n/v teilen
  1919.     and.l    #$ffff0000+($ffff>>x),d0    ;korrigieren
  1920.  
  1921. Und da ist ein normales ...
  1922.  
  1923.     swap    d0
  1924.     lsr.l    #x,d0
  1925.     swap    d0
  1926.  
  1927. ... doch viel angenehmer und auch schneller !
  1928.  
  1929. SO ! Damit genug für Heute - Genug gelernt und genug gelabert ....
  1930. Morgen ist auch noch ein Tag (hoffe ich?!) und dann gehts weiter in meinem
  1931. ARTIGEN und EINZIGEN - WORKSHOP ... [03:27:07]
  1932. Ich hoffe du Träumst nicht von Bits....
  1933.  
  1934.         { Träum , schnarch , grins ....}
  1935.  
  1936.     
  1937.  
  1938.  
  1939.  
  1940.  
  1941.  
  1942. SCIENTS FICTION
  1943. ---------------
  1944.  
  1945. Wo geht die Entwicklung hin ? Ich glaube das bald ein Computer wie folgt
  1946. aufgebaut sein wird...
  1947. CONSUMER VERSION
  1948.  
  1949.     2-4 RISC cpu's mit 100mhz die alle einen parallelen FPU-teil
  1950.     besitzen und auch untereinander daten austauschen können ohne
  1951.     dazu den Umweg über den Speicher machen zu müssen...
  1952.     Jede der CPU's hat einen 8mb großen onchip-cache der das gesamte
  1953.     momentan laufende Programm aufnimmt und mit einer Pipeline an den
  1954.     Speicher angeschlossen ist.
  1955.  
  1956.     Multitasking währe also 1)Programm in cache 2)nächstes Programm in
  1957.     Pipeline 3)während P1 abgearbeitet wird 4)Taskswitch(pipeline->cache)
  1958.     5)nachstes Programm in, Pipeline.....
  1959.     und das auf 2-4 Processoren gleichzeitig !!
  1960.  
  1961.     Der Hauptspeicher dürfte so um die 128 MB liegen und wie auch die
  1962.     CPU's mit einer bandbreite von 64bit Arbeiten.
  1963.     Alle CPU's können gleichzeitig die selbe Addresse lesen ! nur wenn
  1964.     ein schreibzugriff auf eine Addresse erfolgt wird diese für kurze
  1965.     Zeit gelockt. 
  1966.  
  1967.     Ein VideoChip könnte das bild aus einem 32bit-Chunky Mode generieren
  1968.     (Ein Longword pro pixel). Wobei die unteren 24-bit als Farbdaten
  1969.     und die oberen 8-bit als Alpha-Channel benutz werden.
  1970.     Der Video-Chip kann auflösungen bis 2048x2048 generieren ohne unter
  1971.     70hz Frequenz zu sinken.
  1972.     Der VideoChip ist natürlich in der Lage direkt den Systemspeicher
  1973.     zu addressieren - man braucht also keinen BUS wie auf PC-Systemen.
  1974.     
  1975.     Für die Sound-ausgabe würden wohl 12 Stimmen mit 16bit qualität
  1976.     ausreichen, wobei natürlich auf einen Asynchronen Sound-chip
  1977.     (wie auch im Amiga) wert gelegt werden wird um nicht selbst die
  1978.     Samples durch die Gegend schaufeln zu müssen.
  1979.  
  1980.     Sehr sinnvoll wäre ein 64bit breiter Parallel-anschluß um die 
  1981.     Datenmengen zu bewältigen die bei Datenhandschuhen/Videokameras
  1982.     anfallen. Dieser müßte über einen kleinen Puffer von 1MB an
  1983.     den Hauptspeicher angeschlossen sein.
  1984.     
  1985.     Als Medium wären eigentlich nur wiederbeschreibbare CD's oder
  1986.     ähnliches denkbar...
  1987.     Auch DAT-Rekorder (einige Giga-Byte pro Band) könnten erschwinglich
  1988.     werden...
  1989.  
  1990.         
  1991. Aber ausreichen wird weder die Rechenleistung noch die Geschwindigkeit 
  1992. niemals... Mit den 4RISC-CPU/FPU's wäre bei 100mhz zwar ca 50hz Realtime-
  1993. Raytracing (bei 50.000 polygonen) in den 24bit Chunky möglich - aber 50hz
  1994. ist dann eben schon nicht mehr 1frame...
  1995. Und auch sonst das Coden wird auch hier nicht zum Kinderspiel denn 2048x2048
  1996. Longwords wollen erstmal berechnet sein (1342200000000 bits im vergleich zu
  1997. den 655360 bits die wir heute beackern..) also : Hardcore-Coder werden immer
  1998. benötigt werden und Spiele in Basic werden NIE zum Renner werden....
  1999. Auch wenn hier in Basic 1frame (70hz) Texturemapping Städte erkundet werden
  2000. können - wer will das schon wenn er in Assembler durch Scanline Städte mit
  2001. Schatten,Nebel,Reflexionen ect fliegen kann ...
  2002.