Zunächst müssen die in einer Grafikdatei gespeicherten Daten ausgelesen werden, wobei auf das verwendete Grafikformat zu achten ist. Im zweiten Schritt müssen diese Daten mehr oder weniger aufwändig bearbeitet werden (definieren der transparenten Bereiche mithilfe eines Color Keys, berechnen einer Normal Map aus einer Height Map, usw.). Im letzten Schritt werden die Texturdaten in den Speicher der Grafikkarte kopiert, wo sie uns dann als „Textur“ zur Verfügung stehen.
Zum gegenwärtigen Zeitpunkt werden in unseren Programmbeispielen zwei Grafikformate unterstützt – das PNG-Format (Portable Network Graphics) und das BMP-Format (Bitmaps), beide mit jeweils 24-Bit-Farbtiefe (True Color, etwa 16,78 Millionen Farben).
Die Farben werden bei beiden Formaten im sogenannten RGB-Farbraum gespeichert. Hierbei stehen für jeden Farbkanal (Rot, Grün, Blau) jeweils 8 Bit zur Verfügung (256 Farbabstufungen).
Über das Format müssen wir uns beim Laden einer Grafikdatei zunächst keine Gedanken machen. Die SDL-Image-Funktion IMG_Load() benötigt lediglich den Speicherpfad einer existierenden Grafikdatei. Als Rückgabewert erhalten wir dann einen Zeiger auf einen SDL_Surface-Datentyp, in dem alle eingelesenen Informationen gespeichert sind. Werden diese Daten zu einem späteren Zeitpunkt nicht mehr benötigt, kann der belegte Speicherbereich mithilfe der Funktion SDL_FreeSurface() wieder freigegeben werden.
Um die eingelesenen Grafikdaten korrekt weiterverarbeiten zu können, benötigen wir die Zusatzinformation, ob nun eine BMP- oder eine PNG-Grafik eingelesen wurde. Beim Einlesen einer BMP-Datei werden die Farbkanäle in der SDL_Surface in der Reihenfolge Rot-Grün-Blau (RGB) gespeichert, beim Einlesen einer PNG-Datei in der Reihenfolge Blau-Grün-Rot (BGR).
Die Information über das verwendete Grafikformat kann anhand der Dateiendung ermittelt werden:
bool isPNG = false;
long len = strlen(FileName);
long i;
for(i = 0; i < len; i++)
{
if(FileName[i] == '.')
{
if(FileName[i+1] == 'p' || FileName[i+1] == 'P')
{
isPNG = true;
break;
}
}
}
long len = strlen(FileName);
long i;
for(i = 0; i < len; i++)
{
if(FileName[i] == '.')
{
if(FileName[i+1] == 'p' || FileName[i+1] == 'P')
{
isPNG = true;
break;
}
}
}
SDL_Surface *image = IMG_Load(FileName);
if(!image)
{
Add_To_Log(FileName,"IMG_Load() failed");
}
// Höhe, Breite, Farbtiefe (BytesPerPixel) und
// Anzahl der Farbpixel ermitteln:
Width = image->w;
Height = image->h;
long BytesPerPixel = image->format->BytesPerPixel;
long NumPixel = Width * Height;
if(!image)
{
Add_To_Log(FileName,"IMG_Load() failed");
}
// Höhe, Breite, Farbtiefe (BytesPerPixel) und
// Anzahl der Farbpixel ermitteln:
Width = image->w;
Height = image->h;
long BytesPerPixel = image->format->BytesPerPixel;
long NumPixel = Width * Height;
GLuint* data;
data = new GLuint[NumPixel];
ZeroMemory(data, NumPixel*sizeof(GLuint));
data = new GLuint[NumPixel];
ZeroMemory(data, NumPixel*sizeof(GLuint));
unsigned char* pColor = (unsigned char*)image->pixels;
Beispiel 1:
// Color Key:
TransparentColorBorderBlue = 10;
TransparentColorBorderRed = 10;
TransparentColorBorderGreen = 10;
TransparentColorBorderBlue = 10;
TransparentColorBorderRed = 10;
TransparentColorBorderGreen = 10;
// Farbwerte:
colorBlue = 5;
colorRed = 5;
colorGreen = 5;
colorBlue = 5;
colorRed = 5;
colorGreen = 5;
Beispiel 2:
// Color Key:
TransparentColorBorderBlue = 10;
TransparentColorBorderRed = 10;
TransparentColorBorderGreen = 10;
TransparentColorBorderBlue = 10;
TransparentColorBorderRed = 10;
TransparentColorBorderGreen = 10;
// Farbwerte:
colorBlue = 200;
colorRed = 5;
colorGreen = 5;
colorBlue = 200;
colorRed = 5;
colorGreen = 5;
Im letzten Schritt müssen wir die einzelnen Farbkanäle miteinander kombinieren und in einem unbenutzten GLuint-Datenarray-Element speichern.
Nachdem alle Farbwerte Pixel für Pixel in das GLuint-Array übertragen worden sind, können die Daten in den Speicher der Grafikkarte kopiert werden (Textur- und Sampler-Objekte werden im nächsten Artikel ausführlich behandelt). Da nun weder die SDL_Surface noch das GLuint-Array weiter benötigt werden, kann der von ihnen belegte Speicherplatz wieder freigegeben werden.
long Index, j, k;
// Farbkanäle:
unsigned char colorRed;
unsigned char colorGreen;
unsigned char colorBlue;
unsigned char colorAlpha;
k = 0;
for(i = 0; i < Height; i++)
{
for(j = 0; j < Width; j++)
{
Index = BytesPerPixel*j + i*Width*BytesPerPixel;
// Farbwerte der einzelnen Farbkanäle auslesen:
if(isPNG == false)
{
colorBlue = pColor[Index];
colorGreen = pColor[Index+1];
colorRed = pColor[Index+2];
}
else
{
colorBlue = pColor[Index+2];
colorGreen = pColor[Index+1];
colorRed = pColor[Index];
}
// transparente Bereiche der Textur bestimmen
// (Color Keying):
if(colorBlue > TransparentColorBorderBlue ||
colorGreen > TransparentColorBorderGreen ||
colorRed > TransparentColorBorderRed)
colorAlpha = 255;
else
// Pixel ist vollständig transparent:
colorAlpha = 0;
// Farbkanäle miteinander kombinieren und in einem
// unbenutzten GLuint-Array-Element speichern:
*(data+k) = (colorAlpha << 24) +
(colorRed << 16) +
(colorGreen << 8) +
colorBlue;
k++;
}
}
// an dieser Stelle wird die eigentliche Textur erzeugt:
. . .
// Speicherbereich der SDL_Surface wieder freigeben:
SDL_FreeSurface(image);
SAFE_DELETE_ARRAY(data)
// Farbkanäle:
unsigned char colorRed;
unsigned char colorGreen;
unsigned char colorBlue;
unsigned char colorAlpha;
k = 0;
for(i = 0; i < Height; i++)
{
for(j = 0; j < Width; j++)
{
Index = BytesPerPixel*j + i*Width*BytesPerPixel;
// Farbwerte der einzelnen Farbkanäle auslesen:
if(isPNG == false)
{
colorBlue = pColor[Index];
colorGreen = pColor[Index+1];
colorRed = pColor[Index+2];
}
else
{
colorBlue = pColor[Index+2];
colorGreen = pColor[Index+1];
colorRed = pColor[Index];
}
// transparente Bereiche der Textur bestimmen
// (Color Keying):
if(colorBlue > TransparentColorBorderBlue ||
colorGreen > TransparentColorBorderGreen ||
colorRed > TransparentColorBorderRed)
colorAlpha = 255;
else
// Pixel ist vollständig transparent:
colorAlpha = 0;
// Farbkanäle miteinander kombinieren und in einem
// unbenutzten GLuint-Array-Element speichern:
*(data+k) = (colorAlpha << 24) +
(colorRed << 16) +
(colorGreen << 8) +
colorBlue;
k++;
}
}
// an dieser Stelle wird die eigentliche Textur erzeugt:
. . .
// Speicherbereich der SDL_Surface wieder freigeben:
SDL_FreeSurface(image);
SAFE_DELETE_ARRAY(data)