Получаваш три файла .s7m с 3D модели. Документация няма. Задачата е да разбереш как са устроени само от байтовете, да напишеш програма, която ги чете, и накрая да видиш моделите на екрана.
S_Well_01.s7m (31 KB), W_Windmill_01.s7m (196 KB), N_Tavern_01.s7m (533 KB).BinaryReader е чудесен избор).Инструменти, които ще ти трябват по пътя. Не казват нищо за формата, само как се четат различни видове данни с BinaryReader.
using System.Text;
static class Bin
{
// 16-битово реално число (half) → float, ръчно, с битови операции.
// Структура: 1 бит знак | 5 бита степен (изместване 15) | 10 бита мантиса
public static float HalfToFloat(ushort h)
{
int sign = (h >> 15) & 0x1;
int exponent = (h >> 10) & 0x1F;
int mantissa = h & 0x3FF;
int bits;
if (exponent == 0)
{
if (mantissa == 0)
bits = sign << 31; // ±0
else
{
// денормализирано число: изместваме, докато се появи скритата единица
exponent = 1;
while ((mantissa & 0x400) == 0) { mantissa <<= 1; exponent--; }
mantissa &= 0x3FF;
bits = (sign << 31) | ((exponent + 127 - 15) << 23) | (mantissa << 13);
}
}
else if (exponent == 31)
bits = (sign << 31) | 0x7F800000 | (mantissa << 13); // ±∞ или NaN
else
bits = (sign << 31) | ((exponent + 127 - 15) << 23) | (mantissa << 13);
return BitConverter.Int32BitsToSingle(bits);
}
public static float ReadHalf(BinaryReader r) => HalfToFloat(r.ReadUInt16());
// В .NET 5+ има и готово: (float)r.ReadHalf(). Сравни двата резултата!
// n байта като текст, напр. подпис от 4 знака
public static string ReadFixedString(BinaryReader r, int n)
=> Encoding.ASCII.GetString(r.ReadBytes(n));
// Текст, завършващ с нулев байт, на дадена позиция.
// След четенето позицията във файла се връща там, където е била.
public static string ReadCStringAt(BinaryReader r, long pos)
{
long back = r.BaseStream.Position;
r.BaseStream.Position = pos;
var bytes = new List<byte>();
byte b;
while ((b = r.ReadByte()) != 0) bytes.Add(b);
r.BaseStream.Position = back;
return Encoding.Latin1.GetString(bytes.ToArray());
}
// Прескача до следващия адрес, кратен на n (ако вече не е)
public static void Align(BinaryReader r, int n)
{
long p = r.BaseStream.Position;
r.BaseStream.Position = p + (n - p % n) % n;
}
}
// Използване:
// using var r = new BinaryReader(File.OpenRead("S_Well_01.s7m"));
// string podpis = Bin.ReadFixedString(r, 4);
// uint chislo = r.ReadUInt32(); // little-endian, както във файла
Упражнение: провери HalfToFloat за всички 65 536 възможни стойности срещу вградения (float)BitConverter.UInt16BitsToHalf(h). Колко от тях са NaN?
Отвори най-малкия файл. Не пиши код, само гледай.
Сложи трите файла един до друг. Сравнявай байтовете в началото: кои са еднакви (подпис, версия), кои са различни и растат заедно с размера на файла (брой елементи).
Първите десетки байтове описват целия файл. Разбери значението на колкото може повече полета.
Байтовете са little-endian: 79 03 00 00 е 0x379 = 889. Реалното число 1.0 като 4-байтов float е 00 00 80 3F, а отрицателните реални числа завършват на байт ≥ 80.
След заглавната част файлът е поредица от блокове, всеки със собствена малка заглавна част. Открий нейната структура.
Напиши програма, която обхожда файла и отпечатва списък на блоковете: отместване, тип, размер.
Готово, когато: за всеки от трите файла последният блок свършва точно в края на файла.
Текстовете от етап 1 също са блок. Потърси числото, равно на дължината на текстовата част, точно преди нея.
Един от блоковете съдържа данни за всеки връх. Колко байта е един връх? Какво има в тях?
FF?Готово, когато: минималните и максималните x, y, z на всички върхове съвпадат (приблизително) с шестте числа от етап 2, дължината на всяка нормала е ≈ 1, а UV координатите са предимно между 0 и 1.
В .NET има тип Half: BitConverter.ToHalf. Байтът 127 или 128 в опакована нормала означава приблизително 0.
Готово, когато: сборът на индексите по частите е равен на брояча от заглавната част, а нито един индекс не е ≥ броя на върховете.
Програмата отпечатва отчет в конзолата и записва модела във формат .obj:
Файл: S_Well_01.s7m Версия: ... Върхове: ... Триъгълници: ... Граници: (...) – (...) Блокове: ... Части: [0] ... индекси ...–... текстура ... ... Записан: S_Well_01.obj
Отвори .obj файла в Blender или в онлайн 3D преглед. Ако видиш кладенец, вятърна мелница и кръчма, формата е разшифрован.
Мелницата и кръчмата имат блокове, които кладенецът няма. Един от тях съдържа имена. Друг е масив с по 8 байта за всеки връх.
.obj само частта от мелницата, която би трябвало да се върти.Напиши документацията, която липсваше: таблица с всяко поле (отместване, размер, тип, значение) и отделно поле за това, което не си разбрала. Добрата спецификация признава какво остава неизвестно.