Internes DDS-Block Swapping [Repacking?]
-
Hier fing das Problem an, ich habe jetzt tatsächlich genug Informationen eingeholt um DDS Dateien zu Row-swappen.
DXT1 ist abgehandelt, geht verhältnismäßig einfach. DXT2/DXT3 sind quasi bitkompatibel, geht auch recht flux.
DXT4/DXT5 ist vom Color-Anteil harmlos, da selber Algo wie DXT1 - nur kommt dazu noch der Alpha-Anteil und da hackt es ordentlich.
Ich erkläre erstmal. Wenn DDS Dateien komprimiertes Pixelmaterial enthalten, so ist dieses blockkodiert. Blöcke sind 4x4 Texel groß, bei DXT4/DXT5 sind es 128bit (also 16 Bytes) pro Block.
Ein Block besteht bei DXT4/DXT5 aus zwei Teilen. Erster Teil (64bit) Alpha-Sektion. Zweiter Teil (64bit) Color-Sektion.
Die Color-Sektion ist uninteressant, da schon vollständig "reversed" (*g* - das MSDN Material ist dennoch Mist).
Die Alpha-Sektion ist interessant, da dort folgendes gelagert wird (nacheinander):
Zwei 8Bit Alpha-Werte (also insgesamt 16bit)
Danach 4x4 3Bit Alpha-Indices (nochmal 48bit)Ziel ist es jetzt diese 4x4 Indices umzugruppieren, also oben und unten zu tauschen. Da diese natürlich "highly packed" sind, wird das ganze zum Problem.
Ich habe jetzt folgendes gemacht und zwar erstmal einmal die Daten "unpacked" und in ein 4x4 byte-Array geschrieben. Dort das ganze umsortiert (geht ja jetzt recht einfach).
Dann habe ich die 48Bit wo die Daten vorher standen gecleared (std::memset) und diese wieder reingeschrieben.
Hier erstmal der Code:
// process first 64bit section (alpha-data) { o3byte input[4 * 4]; o3byte output[4 * 4]; // skip the two 8bit alpha-values blkPointer += 2; // unpack indices { o3uint16* alpha = NULL; alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x00); input[0x00] = (alpha[0] & 0x0007) >> 0; input[0x01] = (alpha[0] & 0x0038) >> 3; input[0x02] = (alpha[0] & 0x01c0) >> 6; alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x01); input[0x03] = (alpha[0] & 0x000e) >> 1; input[0x04] = (alpha[0] & 0x0070) >> 4; input[0x05] = (alpha[0] & 0x0380) >> 7; input[0x06] = (alpha[0] & 0x1c00) >> 10; input[0x07] = (alpha[0] & 0xe000) >> 13; alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x03); input[0x08] = (alpha[0] & 0x0007) >> 0; input[0x09] = (alpha[0] & 0x0038) >> 3; input[0x0a] = (alpha[0] & 0x01c0) >> 6; alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x04); input[0x0b] = (alpha[0] & 0x000e) >> 1; input[0x0c] = (alpha[0] & 0x0070) >> 4; input[0x0d] = (alpha[0] & 0x0380) >> 7; input[0x0e] = (alpha[0] & 0x1c00) >> 10; input[0x0f] = (alpha[0] & 0xe000) >> 13; } // swap indices output[0x00]=input[0x0c];output[0x01]=input[0x0d];output[0x02]=input[0x0e];output[0x03]=input[0x0e]; output[0x04]=input[0x08];output[0x05]=input[0x09];output[0x06]=input[0x0a];output[0x07]=input[0x0b]; output[0x08]=input[0x04];output[0x09]=input[0x05];output[0x0a]=input[0x06];output[0x0b]=input[0x07]; output[0x0c]=input[0x00];output[0x0d]=input[0x01];output[0x0e]=input[0x02];output[0x0f]=input[0x03]; // write back indices { o3Common::zeroMem(blkPointer, sizeof(o3byte) * 6); o3uint16* alpha = NULL; o3uint32 tmp; alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x00); alpha[0] |= (output[0x00] >> 0); alpha[0] |= (output[0x01] >> 3); alpha[0] |= (output[0x02] >> 6); alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x01); alpha[0] |= (output[0x03] >> 1); alpha[0] |= (output[0x04] >> 4); alpha[0] |= (output[0x05] >> 7); alpha[0] |= (output[0x06] >> 10); alpha[0] |= (output[0x07] >> 13); alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x03); alpha[0] |= (output[0x08] >> 0); alpha[0] |= (output[0x09] >> 3); alpha[0] |= (output[0x0a] >> 6); alpha = reinterpret_cast<o3uint16*>(blkPointer + 0x04); alpha[0] |= (output[0x0b] >> 1); alpha[0] |= (output[0x0c] >> 4); alpha[0] |= (output[0x0d] >> 7); alpha[0] |= (output[0x0e] >> 10); alpha[0] |= (output[0x0f] >> 13); } }Ich glaube das Unpacking dürfte so funktionieren, das Swapping ist denke ich trivial - nur das Repacking, da habe ich gewisse Bedenken.
Ich habe schon lange nichts mehr mit Bit Twiddling gemacht und würde gerne wissen ob der Einsatz des bitweisen OR-Operators hier wirklich den gewünschen Erfolg bringt, oder nicht?
Also die Bitboys sich das bitte mal angucken, ok?

cya
liquidPS: Das Posting steht schon auf ZFX im Board, aber ich denke mal, dass ich dort keine Antwort bekomme. Deswegen versuche ich es mal hier.
Und ich hoffe man kann das Problem unter Grafikprogrammierung einordnen, ansonsten bitte verschieben.
-
Sieht doch ziemlich korrekt aus. Aber ich finde das ziemlichen Blödsinn, denn eigentlich ist das dds Format gerade dazu gedacht, das die Informtionen genau so gespeichert werden, wie auf der Grafikkarte. Wenn du da was umdrehen musst beim Laden, dann liegt der Fehler IMHO woanders.
Bye, TGGC
-
Das Problem liegt an den Unterschieden zwischen D3D und OGL. Während OGL lower-left ist, ist D3D upper-left. Dementsprechend stehen dann die Texturen auf dem Kopf, wenn ich sie regulär lade und uploade.
Eine Alternative wäre die Manipulation von Texturkoordinaten, aber das ist in meinen Augen die schlechtere Möglichkeit. So kann ich die herkömmlichen Texturkoordinaten verwenden und muß nur einmal das Artwork konvertieren.cya
liquid