Hallo,
Ich bin für das Abgabegespräch nochmal den Code durchgegangen und habe einfach mal eine Zusammenfassung für das 4. Beispiel gemacht da hier in den Posts zu den Abgabegesprächen oft wiedersprüchliche Aussagen gemacht wurden. Ich kann natürlich für nichts garantieren 
Beispiel 4
BuildEdgeList() (FillScan)
Es werden die clipped Vertices durchiteriert (entgegen dem Uhrzeiger) und aus jeweils zwei Vertices eine Edge erstellt. Es müssen die clipped Vertices sein da sonst Kanten ausserhalb des Bildschirms existieren können. Die Kanten werden so erstellt, dass der Vertex mit dem niedrigeren y-Wert immer zuerst ist. Haben beide Vertices den gleichen y-Wert werden sie ignoriert (horizontale Linie). Wurde das Problem nach Hearn & Baker gelöst überprüft man mit dem yNext zusätzlich ob die nächste Kante steigt oder fällt ( < oder > ). In diesen Fällen muss yUpper -1 bei dem oberen Vertex verwendet werden (die Kante wird um 1 verkleinert. Das Verhindert, dass beim Scannen beide Kanten im Punkt yUpper gleichzeitig in der Activelist sind(konkret, der Endpunkt der einen Kante und der Anfangspunkt der anderen Kante). Bei Kanten die \/ oder /\ ausfallen ist das egal ( Hearn & Baker 3. Aufl p 197). Probleme treten daher auf, dass wir mit einer odd-even Rule füllen (ab erster Kante wird gefüllt bis zur nächsten Kante, dann von der 3. bis zur 4. usw). Man kann sich leicht davon überzeugen, dass die Problemfälle zu fehlerhaften Füllergebnissen führen.
Hat man eine Lösung ähnlich der Musterlösung werden einfach alle oberen Vertices mit yUpper-1 in die Edgelist aufgenommen. Das führt natürlich bei einer oberen Spitze /\ zu einem kleinen Fehler der aber durch etwas mehr Performance in Kauf genommen wird.
Es werden diese Kanten dann in die Edgelist eingefügt, und zwar an der die Position des niedrigeren y-Wertes der Kante, als edgelist[lower[Y]]. Zusätzlich muss man noch den xIntersect an dieser Stelle und den dxPerScan (also wie weit man x inkrementieren muss wenn man einen Schritt bei der y-Achse macht) angeben.
Die Edgelist hat die Höhe des Canvas (es geht theoretisch auch anders aber darauf will ich jetzt nicht eingehen) und muss mit leeren Edgelists für alle Felder des Arrays initalisiert werden.
Nach BuildEdgeList() sollte nun jede Kante in dem edgelist[] Array stehen und zwar genau an der Position wo der "tiefere" Vertex seine y-Koordinate hat. Werden mehrere Kanten an einer Stelle eingefügt so werden sie zusätzlich nach ihren x Koordinaten an jenem Vertex sortiert (alles zusammen ist ein Bucket Sort) .
DrawClipped() (FillScan)
Erst wird mit buildEdgeList() alle Kanten richtig in die Edgelist eingefügt. Dann wird über alle y Koordinaten (also von 0 bis canvas.Height) iteriert und dabei BuildActiveList(scan) und FillScan(scan,canvas)aufgerufen. Zusätzlich wird nach dem durchlaufen der Scanline activelist.update() und activelist.resort() aufgerufen. Durch update wird der xIntersect aller aktiven Kanten um dxPerIntersect erhöht (und später auch zIntersect und cIntersect) und zudem Kanten entfernt deren yUpper position erreicht wurde (fertig gezeichnet). Rresort sortiert die Kanten da beim Kreuzen zweier Kanten die Reihenfolge vertauscht wird.
BuildActiveList(scan) (FillScan)
Es werden nun alle y-Positionen des Canvas einzeln mit der Scanline durchlaufen. Wurde nichts in die edgelist[scan] eingefügt wird einfach in die nächste Zeile gesprungen. Existieren nun Edges in dieser Zeile werden sie in die Activelist eingefügt. (wieder in der richtigen Reihenfolge der x Koordinaten). Die ActiveList enthält somit alle Kanten die momentan gekreuzt werden.
FillScan(scan,canvas)
Es wird die erste Kante aus der ActiveList geholt und von ihrem xIntersect bis zum xIntersect der nächsten Kante mit der Farbe des Polygons gefüllt. Dann wird die übernächste Kante und ihr Nachfolger geladen und ebenso verfahren bis es keine Kanten mehr gibt.
Backface Culling:
Backface culling wird in CG1Object ausgeführt und zwar in der funktion draw(). Da die Objekte nur VertexNormals besitzen muss man ein FaceNormal durch berechnen zweier Kanten und dem Ermitteln des Kreuzprodukts erstellen. Generell würde man nun das Dot Product des View Vectors mit dem Normalvector nehmen und überprüfen ob der wert > 0 (bzw >=) 0 ist. Ist dies der fall zeigt die Normale und somit die Oberfläche von uns weg und muss nicht gezeichnet werden da man sie nicht sieht (es gibt hier ganz klar Probleme zum Beispiel bei "Löchern" in einem Objekt wo man die Hinterseite sehr wohl sieht oder bei 2D Objekten). In unserem Fall kann man aber auch einfach die z Komponente des Normalvektors analysieren da unser View vector fixiert ist und in die negative z richtung schaut. Zeigt der Normalvektor in die negative z Richtung oder auf 0 zeigt die Normale weg von uns oder ist im rechten Winkel und muss nicht gezeichnet werden.