V
eigentlich hätte ich gerne so etwas:
vector<Edge>::iterator remove_from = remove_if(ActiveEdgeTable.begin(),
ActiveEdgeTable.end(), mem_func<bool,Edge>(&Polygon::compareYmax));
hier der ganze code:
#ifndef Scanline_h
#define Scanline_h
#include <vector>
#include <algorithm>
#include <cassert>
#include <functional>
using namespace std;
namespace Vertexwahn
{
namespace Scanline
{
class Plane3D // Repräsentierte eine Ebene
{
public:
float A,B,C,D;
}; // class Plane
class Edge // Kante eines Polygons.
// Festlegung: Die Eckpunkte einer Kante sind immer ganzzahlig, liegen also genau auf einen Pixel
{
public:
Edge(int x1, int y1, int x2, int y2)
{
x_min = x1 > x2 ? x2 : x1;
y_min = y1 > y2 ? y2 : y1;
x = y1 > y2 ? x2 : x1;
if(y2 == y1) // bei vertikalen Kannten wird die Steigung auf 0 gesetzt
reciprocalSlope = 0;
else
reciprocalSlope = (x2-x1) / (y2-y1);
y_max = y1 > y2 ? y1 : y2;
color = 0xFFFF0000; // rot
}
void print()
{
cout<<"========================================"<<endl;
cout<<"y_min : "<<y_min<<endl;
cout<<"x : "<<x<<endl;
cout<<"reciprocalSlope: "<<reciprocalSlope<<endl;
cout<<"y_max : "<<y_max<<endl;
}
// zum Sortieren der Kanten nach dem kleinsten y-Wert - das "kleinste" Element ist ganz hinten
// im Array zu finden
bool operator<(const Edge &rhs)
{
/* // alter Code: hier war das kleinste Elment ganz vorn im Array zu finden
// wurde aber umgedreht, weil dadurch der Code in der draw Methode einfacher wird
if(y_min == rhs.y_min) // haben zwei Kanten den gleichen minimalen y-Wert, so werden sie nach
{
// aufsteigendem x-Wert sortiert
return x_min < rhs.x_min;
}
else
return y_min < rhs.y_min;
*/
if(y_min == rhs.y_min) // haben zwei Kanten den gleichen minimalen y-Wert, so werden sie nach
{
// aufsteigendem x-Wert sortiert
return x_min > rhs.x_min;
}
else
return y_min > rhs.y_min;
}
Edge(const Edge &edge)
{
x_min = edge.x_min;
y_min = edge.y_min;
x = edge.x;
reciprocalSlope = edge.reciprocalSlope;
y_max = edge.y_max;
color = edge.color;
}
Edge& operator=(const Edge &edge)
{
x_min = edge.x_min;
y_min = edge.y_min;
x = edge.x;
reciprocalSlope = edge.reciprocalSlope;
y_max = edge.y_max;
color = edge.color;
return *this;
}
int getYMax()
{
return y_max;
}
private:
int x_min; // kleinster x-Wert der Kante, wird zum Soriteren der GlobalEdgeTable benötigt
int y_min; // kleinster y-Wert der Kante - damit man bestimmen kann wann eine Kante in die
// Active Edge List aufgenommen werden soll
float x; // Die x-Koordinate des Kantenpunkts mit der kleineren y-Koordinate
float reciprocalSlope; // Kehrwert der Steigung (1/slope) zur Berechnung von Schittpunkten mit der Scanline
// Für vertikale Kanten wird der Wert 0 angenommen.
int y_max; // größter y-Wert der Kante - damit man bestimmen kann wan die Kante aus der Global bzw. Active
// Edge Table gelöscht werden kann
int color; // Farbe des Polygons
//Plane3D planeequation; // Ebenengleichung zur Bestimmung der Tiefe (für den Z-Buffer)
friend class Polygon; // die Klasse Polygon soll auf private Datenelmente der Kanten zugreifen dürfen
}; // class Edge
// Verwendetes Koordinatensystem
// y+
// |
// |
// | ======== Scanline wird von unten nach oben über das Polygon geschoben
// |
// 0-------x+
class Polygon
{
public:
void setPixelColor(int x, int y, int color)
{
}
bool compareYmax(Edge edge)
{
return scanline == edge.y_max;
}
// Methode sollte erste Aufgerufen werden, wenn die GlobalEdgeTable Kanten eines gülitgen Polygons
// enthält
void draw()
{
// Polygon soll von unten nach oben gerendert werden - also vom minimalen y-Wert bis maximalen y-Wert
// ist die GlobalEdgeTable nach y_min sortiert so muss man nur den minimalen y-Wert der ersten Kante
// ermitteln und erhält so den minimalen y-Wert der Kante. Der Algorithmus wird abgebrochen, wenn
// die GlobalEdgeTable und die ActiveEdgeTable leer ist. Damit wird der maximale y-Wert des Polygons
// nicht benötigt.
// GlobalEdgeTabel sortieren
sort(GlobalEdgeTable.begin(), GlobalEdgeTable.end());
// Startwert für die Scanline ist die minimale y-Koordinate des Polygons
scanline = GlobalEdgeTable.back().y_min;
// AET cleanen ;)
ActiveEdgeTable.clear();
// Solange die ActiveEdgeTable und die GlobalEdgeTable nicht leer sind
while(!(GlobalEdgeTable.empty() && ActiveEdgeTable.empty()))
{
// Alle Kanten werden zur ActiveEdgeTable hinzugefügt und aus der
// Global Edgetable entfernt deren minimaler y-Wert mit der Scanline übereinstimmt
while(!GlobalEdgeTable.empty() && (GlobalEdgeTable.back().y_min == scanline))
{
ActiveEdgeTable.push_back(GlobalEdgeTable.back());
GlobalEdgeTable.pop_back();
}
// Pixel zwischen jeweils zwei Schnittpunkten der AET malen
Fill();
// Alle Kanten in der Active Edge Table für die gilt y (scanline) == ymax werden entfernt
vector<Edge>::iterator remove_from = remove_if(ActiveEdgeTable.begin(),
ActiveEdgeTable.end(),
mem_func<bool,Edge>(&Polygon::compareYmax));
ActiveEdgeTable.erase(remove_from,ActiveEdgeTable.end());
// continue...
print();
int a;
a++;
}
// für die Scanline machen nur ganzzahlige werte sinn... ??? wenn start_y z.B. 2.9 ist wo mit scanline beginnen?
//
}
// Erwartet das die ActiveEdgeTable sortiert ist nach dem x-Wert und dieser zugleich
// den Schnittpunkt mit Scanline darstellt
void Fill()
{
// in der Active EdgeTable befindet sich immer eine gerade Anzahl von
// Kanten
assert(ActiveEdgeTable.size() % 2 == 0);
for(int i = 0; i < ActiveEdgeTable.size()-1; i++)
{
assert(ActiveEdgeTable[i].x < ActiveEdgeTable[i+1].x);
}
// Fill Conventions:
// siehe "Problem beim Füllen von Pixel zwischen zwei Schnittpunkten"
// an diese Fill Conentions halte ich mich noch nicht - diese Methode sollte jedoch halbwegs zufrieden
// stellende Ergebnisse liefern - für die Zukunft: Nur linke und untere Ränder zeichnen
// obere und rechte Ränder werden nicht gezeichnet
for(int i = 0; i < ActiveEdgeTable.size() / 2; i++)
{
DrawHorizontalLine(ActiveEdgeTable[i*2].x,ActiveEdgeTable[i*2+1].x);
}
}
void DrawHorizontalLine(int a, int b)
{
assert(a > 0);
assert(b > 0);
assert(a < 400);
assert(b < 400);
}
void print()
{
sort(GlobalEdgeTable.begin(), GlobalEdgeTable.end());
// GlobalEdgeTable
cout<<"GlobalEdgeTable"<<endl;
for(int i = 0; i < GlobalEdgeTable.size(); i++)
GlobalEdgeTable[i].print();
cout<<"ActiveEdgeTable"<<endl;
for(int i = 0; i < ActiveEdgeTable.size(); i++)
ActiveEdgeTable[i].print();
}
void add(int x1, int y1, int x2, int y2)
{
// Horizontale Kanten ignorieren
if(y1==y2)
return;
GlobalEdgeTable.push_back(Edge(x1,y1,x2,y2));
}
private:
vector<Edge> GlobalEdgeTable; // Kantenliste soritiert nach minimalen y-Wert enthalt nur Kanten, die
// nicht horizontal sind - Kanten werden entfernt, wenn sie in die Active
// Edge List übernommen werden
vector<Edge> ActiveEdgeTable; // Alle Kanten, die die Scanline aktuell schneiden tut ;)
float scanline; // y-Koordinaten der Scanline
}; // class Polygon
} // namespace Scanline
} // namespace Vertexwahn
#endif