serializacja e3d

This commit is contained in:
VB
2017-02-26 18:40:00 +01:00
parent 62e9766962
commit fcf74abfa2
8 changed files with 284 additions and 225 deletions

View File

@@ -25,6 +25,12 @@ void float4x4::deserialize_float64(std::istream &s)
e[i] = (float)sn_utils::ld_float64(s);
}
void float4x4::serialize_float32(std::ostream &s)
{
for (size_t i = 0; i < 16; i++)
sn_utils::ls_float32(s, e[i]);
}
void float4x4::Quaternion(float4 *q)
{ // konwersja kwaternionu obrotu na macierz obrotu
float xx = q->x * q->x, yy = q->y * q->y, zz = q->z * q->z;

View File

@@ -184,11 +184,12 @@ struct float8
class float4x4
{ // macierz transformacji pojedynczej precyzji
public:
float e[16];
public:
void deserialize_float32(std::istream &s);
void deserialize_float64(std::istream &s);
void deserialize_float32(std::istream&);
void deserialize_float64(std::istream&);
void serialize_float32(std::ostream&);
float4x4(void){};
float4x4(float f[16])
{
@@ -282,6 +283,16 @@ inline float4x4 &float4x4::Rotation(double angle, float3 axis)
return *this;
};
inline bool operator==(const float4x4& v1, const float4x4& v2)
{
for (size_t i = 0; i < 16; i++)
{
if (v1.e[i] != v2.e[i])
return false;
}
return true;
}
inline float4x4 operator*(const float4x4 &m1, const float4x4 &m2)
{ // iloczyn macierzy
float4x4 retVal;

View File

@@ -42,12 +42,6 @@ std::string *TSubModel::pasText;
// 0x3F3F003F - wszystkie wymienne tekstury używane w danym cyklu
// Ale w TModel3d okerśla przezroczystość tekstur wymiennych!
int TSubModelInfo::iTotalTransforms = 0; // ilość transformów
int TSubModelInfo::iTotalNames = 0; // długość obszaru nazw
int TSubModelInfo::iTotalTextures = 0; // długość obszaru tekstur
int TSubModelInfo::iCurrent = 0; // aktualny obiekt
TSubModelInfo *TSubModelInfo::pTable = NULL; // tabele obiektów pomocniczych
TSubModel::TSubModel()
{
ZeroMemory(this, sizeof(TSubModel)); // istotne przy zapisywaniu wersji binarnej
@@ -1477,82 +1471,6 @@ void TSubModel::RaArrayFill(CVertNormTex *Vert)
Next->RaArrayFill(Vert);
};
void TSubModel::Info()
{ // zapisanie informacji o submodelu do obiektu
// pomocniczego
TSubModelInfo *info = TSubModelInfo::pTable + TSubModelInfo::iCurrent;
info->pSubModel = this;
if (fMatrix && (iFlags & 0x8000)) // ma matrycę i jest ona niejednostkowa
info->iTransform = info->iTotalTransforms++;
if (TextureID > 0)
{ // jeśli ma teksturę niewymienną
for (int i = 0; i < info->iCurrent; ++i)
if (TextureID == info->pTable[i].pSubModel->TextureID) // porównanie z wcześniejszym
{
info->iTexture = info->pTable[i].iTexture; // taki jaki już był
break; // koniec sprawdzania
}
if (info->iTexture < 0) // jeśli nie znaleziono we wcześniejszych
{
info->iTexture = ++info->iTotalTextures; // przydzielenie numeru tekstury
// w pliku (od 1)
std::string t(pTexture);
// trim extension
size_t kropka = t.rfind('.');
if (kropka != std::string::npos &&
(t.substr(kropka) == ".tga" || t.substr(kropka) == ".dds"))
{
t.erase(t.rfind('.'));
}
if (t != std::string(pTexture))
{ // jeśli się zmieniło
// pName=new char[token.length()+1]; //nie ma sensu skracać tabeli
pTexture = t;
}
info->iTextureLen = (int)t.size() + 1; // przygotowanie do zapisania, z zerem na końcu
}
}
else
info->iTexture = TextureID; // nie ma albo wymienna
// if (asName.Length())
if (pName.size())
{
info->iName = info->iTotalNames++; // przydzielenie numeru nazwy w pliku (od 0)
info->iNameLen = (int)pName.size() + 1; // z zerem na końcu
}
++info->iCurrent; // przejście do kolejnego obiektu pomocniczego
if (Child)
{
info->iChild = info->iCurrent;
Child->Info();
}
if (Next)
{
info->iNext = info->iCurrent;
Next->Info();
}
};
void TSubModel::InfoSet(TSubModelInfo *info)
{ // ustawienie danych wg obiektu
// pomocniczego do zapisania w
// pliku
int ile = (char *)&uiDisplayList - (char *)&eType; // ilość bajtów pomiędzy tymi zmiennymi
ZeroMemory(this, sizeof(TSubModel)); // zerowaie całości
CopyMemory(this, info->pSubModel, ile); // skopiowanie pamięci 1:1
tVboPtr = (int)info->pSubModel->iVboPtr;
iTexture = info->iTexture; // numer nazwy tekstury, a nie numer w OpenGL
TextureID = info->iTexture; // numer tekstury w OpenGL
iName = info->iName; // numer nazwy w obszarze nazw
iMatrix = info->iTransform; // numer macierzy
iNext = info->iNext; // numer następnego
iChild = info->iChild; // numer potomnego
iFlags &= ~0x200; // nie jest wczytany z tekstowego
// asTexture=asName="";
pTexture = "";
pName = "";
};
void TSubModel::AdjustDist()
{ // aktualizacja odległości faz LoD, zależna od
// rozdzielczości pionowej oraz multisamplingu
@@ -1744,9 +1662,173 @@ bool TModel3d::LoadFromFile(std::string const &FileName, bool dynamic)
return result;
};
// E3D deserialization
// E3D serialization
// http://rainsted.com/pl/Format_binarny_modeli_-_E3D
//m7todo: wymyślić lepszą nazwę
template <typename L, typename T>
size_t get_container_pos(L &list, T o)
{
auto i = std::find(list.begin(), list.end(), o);
if (i == list.end())
{
list.push_back(o);
return list.size() - 1;
}
else
{
return std::distance(list.begin(), i);
}
}
//m7todo: za dużo argumentów, może przenieść do osobnej
//klasy serializera mającej własny stan, albo zrobić
//strukturę TModel3d::SerializerContext?
void TSubModel::serialize(std::ostream &s,
std::vector<TSubModel*> &models,
std::vector<std::string> &names,
std::vector<std::string> &textures,
std::vector<float4x4> &transforms)
{
size_t end = (size_t)s.tellp() + 256;
if (!Next)
sn_utils::ls_int32(s, -1);
else
sn_utils::ls_int32(s, (int32_t)get_container_pos(models, Next));
if (!Child)
sn_utils::ls_int32(s, -1);
else
sn_utils::ls_int32(s, (int32_t)get_container_pos(models, Child));
sn_utils::ls_int32(s, eType);
if (pName.size() == 0)
sn_utils::ls_int32(s, -1);
else
sn_utils::ls_int32(s, (int32_t)get_container_pos(names, pName));
sn_utils::ls_int32(s, (int)b_Anim);
sn_utils::ls_int32(s, iFlags);
sn_utils::ls_int32(s, (int32_t)get_container_pos(transforms, *fMatrix));
sn_utils::ls_int32(s, iNumVerts);
sn_utils::ls_int32(s, (int)iVboPtr);
if (TextureID <= 0)
sn_utils::ls_int32(s, TextureID);
else
sn_utils::ls_int32(s, (int32_t)get_container_pos(textures, pTexture));
sn_utils::ls_float32(s, fVisible);
sn_utils::ls_float32(s, fLight);
for (size_t i = 0; i < 4; i++)
sn_utils::ls_float32(s, f4Ambient[i]);
for (size_t i = 0; i < 4; i++)
sn_utils::ls_float32(s, f4Diffuse[i]);
for (size_t i = 0; i < 4; i++)
sn_utils::ls_float32(s, f4Specular[i]);
for (size_t i = 0; i < 4; i++)
sn_utils::ls_float32(s, f4Emision[i]);
sn_utils::ls_float32(s, fWireSize);
sn_utils::ls_float32(s, fSquareMaxDist);
sn_utils::ls_float32(s, fSquareMinDist);
sn_utils::ls_float32(s, fNearAttenStart);
sn_utils::ls_float32(s, fNearAttenEnd);
sn_utils::ls_uint32(s, bUseNearAtten ? 1 : 0);
sn_utils::ls_int32(s, iFarAttenDecay);
sn_utils::ls_float32(s, fFarDecayRadius);
sn_utils::ls_float32(s, fCosFalloffAngle);
sn_utils::ls_float32(s, fCosHotspotAngle);
sn_utils::ls_float32(s, fCosViewAngle);
size_t fill = end - s.tellp();
for (size_t i = 0; i < fill; i++)
s.put(0);
}
void TModel3d::SaveToBinFile(char const *FileName)
{
WriteLog("saving e3d model..");
//m7todo: można by zoptymalizować robiąc unordered_map
//na wyszukiwanie numerów już dodanych stringów i osobno
//vector na wskaźniki do stringów w kolejności numeracji
//tylko czy potrzeba?
std::vector<TSubModel*> models;
models.push_back(Root);
std::vector<std::string> names;
std::vector<std::string> textures;
textures.push_back("");
std::vector<float4x4> transforms;
std::ofstream s(FileName, std::ios::binary);
sn_utils::ls_uint32(s, MAKE_ID4('E', '3', 'D', '0'));
size_t e3d_spos = s.tellp();
sn_utils::ls_uint32(s, 0);
{
sn_utils::ls_uint32(s, MAKE_ID4('S', 'U', 'B', '0'));
size_t sub_spos = s.tellp();
sn_utils::ls_uint32(s, 0);
for (size_t i = 0; i < models.size(); i++)
models[i]->serialize(s, models, names, textures, transforms);
size_t pos = s.tellp();
s.seekp(sub_spos);
sn_utils::ls_uint32(s, (uint32_t)(4 + pos - sub_spos));
s.seekp(pos);
}
sn_utils::ls_uint32(s, MAKE_ID4('T', 'R', 'A', '0'));
sn_utils::ls_uint32(s, 8 + (uint32_t)transforms.size() * 64);
for (size_t i = 0; i < transforms.size(); i++)
transforms[i].serialize_float32(s);
MakeArray(iNumVerts);
Root->RaArrayFill(m_pVNT);
sn_utils::ls_uint32(s, MAKE_ID4('V', 'N', 'T', '0'));
sn_utils::ls_uint32(s, 8 + iNumVerts * 32);
for (size_t i = 0; i < iNumVerts; i++)
m_pVNT[i].serialize(s);
if (textures.size())
{
sn_utils::ls_uint32(s, MAKE_ID4('T', 'E', 'X', '0'));
size_t tex_spos = s.tellp();
sn_utils::ls_uint32(s, 0);
for (size_t i = 0; i < textures.size(); i++)
sn_utils::s_str(s, textures[i]);
size_t pos = s.tellp();
s.seekp(tex_spos);
sn_utils::ls_uint32(s, (uint32_t)(4 + pos - tex_spos));
s.seekp(pos);
}
if (names.size())
{
sn_utils::ls_uint32(s, MAKE_ID4('N', 'A', 'M', '0'));
size_t nam_spos = s.tellp();
sn_utils::ls_uint32(s, 0);
for (size_t i = 0; i < names.size(); i++)
sn_utils::s_str(s, names[i]);
size_t pos = s.tellp();
s.seekp(nam_spos);
sn_utils::ls_uint32(s, (uint32_t)(4 + pos - nam_spos));
s.seekp(pos);
}
size_t end = s.tellp();
s.seekp(e3d_spos);
sn_utils::ls_uint32(s, (uint32_t)(4 + end - e3d_spos));
s.close();
WriteLog("..done.");
}
void TSubModel::deserialize(std::istream &s)
{
iNext = sn_utils::ld_int32(s);
@@ -1769,13 +1851,10 @@ void TSubModel::deserialize(std::istream &s)
for (size_t i = 0; i < 4; i++)
f4Ambient[i] = sn_utils::ld_float32(s);
for (size_t i = 0; i < 4; i++)
f4Diffuse[i] = sn_utils::ld_float32(s);
for (size_t i = 0; i < 4; i++)
f4Specular[i] = sn_utils::ld_float32(s);
for (size_t i = 0; i < 4; i++)
f4Emision[i] = sn_utils::ld_float32(s);
@@ -1893,6 +1972,7 @@ void TModel3d::deserialize(std::istream &s, size_t size, bool dynamic)
void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v,
std::vector<std::string> *t, std::vector<std::string> *n, bool dynamic)
{ // ustawienie wskaźników w submodelu
//m7todo: brzydko
iVisible = 1; // tymczasowo używane
Child = (iChild > 0) ? s + iChild : nullptr; // zerowy nie może być potomnym
Next = (iNext > 0) ? s + iNext : nullptr; // zerowy nie może być następnym
@@ -1953,7 +2033,7 @@ void TSubModel::BinInit(TSubModel *s, float4x4 *m, float8 *v,
void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic)
{ // wczytanie modelu z pliku binarnego
WriteLog("Loading - binary model: " + FileName);
WriteLog("loading e3d model " + FileName + " ..");
std::ifstream file(FileName, std::ios::binary);
@@ -1965,6 +2045,8 @@ void TModel3d::LoadFromBinFile(std::string const &FileName, bool dynamic)
deserialize(file, size, dynamic);
file.close();
WriteLog("..done.");
};
void TModel3d::LoadFromTextFile(std::string const &FileName, bool dynamic)
@@ -2067,100 +2149,6 @@ void TModel3d::Init()
}
};
void TModel3d::SaveToBinFile(char const *FileName)
{ // zapis modelu binarnego
WriteLog("Saving E3D binary model.");
int i, zero = 0;
TSubModelInfo *info = new TSubModelInfo[iSubModelsCount];
info->Reset();
Root->Info(); // zebranie informacji o submodelach
int len; //łączna długość pliku
int sub; // ilość submodeli (w bajtach)
int tra; // wielkość obszaru transformów
int vnt; // wielkość obszaru wierzchołków
int tex = 0; // wielkość obszaru nazw tekstur
int nam = 0; // wielkość obszaru nazw submodeli
sub = 8 + sizeof(TSubModel) * iSubModelsCount;
tra = info->iTotalTransforms ? 8 + 64 * info->iTotalTransforms : 0;
vnt = 8 + 32 * iNumVerts;
for (i = 0; i < iSubModelsCount; ++i)
{
tex += info[i].iTextureLen;
nam += info[i].iNameLen;
}
if (tex)
tex += 9; // 8 na nagłówek i jeden ciąg pusty (tylko znacznik końca)
if (nam)
nam += 8;
len = 8 + sub + tra + vnt + tex + ((-tex) & 3) + nam + ((-nam) & 3);
TSubModel *roboczy = new TSubModel(); // bufor używany do zapisywania
// AnsiString *asN=&roboczy->asName,*asT=&roboczy->asTexture;
// roboczy->FirstInit(); //żeby delete nie usuwało czego nie powinno
/* TFileStream *fs = new TFileStream(AnsiString(FileName), fmCreate);
*/ {
std::ofstream file(FileName, std::ios::binary);
file.unsetf(std::ios::skipws);
file.write("E3D0", 4); // kromka główna
file.write(reinterpret_cast<char *>(&len), 4);
file.write("SUB0", 4); // dane submodeli
file.write(reinterpret_cast<char *>(&sub), 4);
for (i = 0; i < iSubModelsCount; ++i)
{
roboczy->InfoSet(info + i);
file.write(reinterpret_cast<char *>(roboczy),
256); // zapis jednego submodelu
}
if (tra)
{ // zapis transformów
file.write("TRA0", 4); // transformy
file.write(reinterpret_cast<char *>(&tra), 4);
for (i = 0; i < iSubModelsCount; ++i)
if (info[i].iTransform >= 0)
file.write(reinterpret_cast<char *>(info[i].pSubModel->GetMatrix()), 16 * 4);
}
{ // zapis wierzchołków
MakeArray(iNumVerts); // tworzenie tablic dla VBO
Root->RaArrayFill(m_pVNT); // wypełnianie tablicy
file.write("VNT0", 4); // wierzchołki
file.write(reinterpret_cast<char *>(&vnt), 4);
file.write(reinterpret_cast<char *>(m_pVNT), 32 * iNumVerts);
}
if (tex) // może być jeden submodel ze zmienną teksturą i nazwy nie będzie
{ // zapis nazw tekstur
file.write("TEX0", 4); // nazwy tekstur
i = (tex + 3) & ~3; // zaokrąglenie w górę
file.write(reinterpret_cast<char *>(&i), 4);
file.write(reinterpret_cast<char *>(&zero),
1); // ciąg o numerze zero nie jest używany, ma tylko znacznik końca
for (i = 0; i < iSubModelsCount; ++i)
if (info[i].iTextureLen)
file.write(info[i].pSubModel->pTexture.c_str(), info[i].iTextureLen);
if ((-tex) & 3)
file.write(reinterpret_cast<char *>(&zero),
((-tex) & 3)); // wyrównanie do wielokrotności 4 bajtów
}
if (nam) // może być jeden anonimowy submodel w modelu
{ // zapis nazw submodeli
file.write("NAM0", 4); // nazwy submodeli
i = (nam + 3) & ~3; // zaokrąglenie w górę
file.write(reinterpret_cast<char *>(&i), 4);
for (i = 0; i < iSubModelsCount; ++i)
if (info[i].iNameLen)
file.write(info[i].pSubModel->pName.c_str(), info[i].iNameLen);
if ((-nam) & 3)
file.write(reinterpret_cast<char *>(&zero),
((-nam) & 3)); // wyrównanie do wielokrotności 4 bajtów
}
} // file autocloses on getting out of scope
// roboczy->FirstInit(); //żeby delete nie usuwało czego nie powinno
// roboczy->iFlags=0; //żeby delete nie usuwało czego nie powinno
// roboczy->asName)=asN;
//&roboczy->asTexture=asT;
delete roboczy;
delete[] info;
};
void TModel3d::BreakHierarhy()
{
Error("Not implemented yet :(");

View File

@@ -128,7 +128,6 @@ enum TAnimType // rodzaj animacji
};
class TModel3d;
class TSubModelInfo;
class TSubModel
{ // klasa submodelu - pojedyncza siatka, punkt świetlny albo grupa punktów
@@ -206,7 +205,6 @@ public: // chwilowo
TAnimType b_aAnim; // kody animacji oddzielnie, bo zerowane
public:
float4x4 *mAnimMatrix; // macierz do animacji kwaternionowych (należy do AnimContainer)
char space[8]; // wolne miejsce na przyszłe zmienne (zmniejszyć w miarę potrzeby)
public:
TSubModel **
smLetter; // wskaźnik na tablicę submdeli do generoania tekstu (docelowo zapisać do E3D)
@@ -279,8 +277,6 @@ public:
};
void InitialRotate(bool doit);
void DisplayLists();
void Info();
void InfoSet(TSubModelInfo *info);
void BinInit(TSubModel *s, float4x4 *m, float8 *v,
std::vector<std::string> *t, std::vector<std::string> *n, bool dynamic);
void ReplacableSet(texture_manager::size_type *r, int a)
@@ -316,36 +312,12 @@ public:
float MaxY(const float4x4 &m);
void AdjustDist();
void deserialize(std::istream &s);
};
class TSubModelInfo
{ // klasa z informacjami o submodelach, do tworzenia pliku binarnego
public:
TSubModel *pSubModel; // wskaźnik na submodel
int iTransform; // numer transformu (-1 gdy brak)
int iName; // numer nazwy
int iTexture; // numer tekstury
int iNameLen; // długość nazwy
int iTextureLen; // długość tekstury
int iNext, iChild; // numer następnego i potomnego
static int iTotalTransforms; // ilość transformów
static int iTotalNames; // ilość nazw
static int iTotalTextures; // ilość tekstur
static int iCurrent; // aktualny obiekt
static TSubModelInfo *pTable; // tabele obiektów pomocniczych
TSubModelInfo()
{
pSubModel = NULL;
iTransform = iName = iTexture = iNext = iChild = -1; // nie ma
iNameLen = iTextureLen = 0;
}
void Reset()
{
pTable = this; // ustawienie wskaźnika tabeli obiektów
iTotalTransforms = iTotalNames = iTotalTextures = iCurrent = 0; // zerowanie liczników
}
~TSubModelInfo() {};
void deserialize(std::istream&);
void TSubModel::serialize(std::ostream&,
std::vector<TSubModel*>&,
std::vector<std::string>&,
std::vector<std::string>&,
std::vector<float4x4>&);
};
class TModel3d : public CMesh

14
VBO.cpp
View File

@@ -28,6 +28,20 @@ void CVertNormTex::deserialize(std::istream &s)
v = sn_utils::ld_float32(s);
}
void CVertNormTex::serialize(std::ostream &s)
{
sn_utils::ls_float32(s, x);
sn_utils::ls_float32(s, y);
sn_utils::ls_float32(s, z);
sn_utils::ls_float32(s, nx);
sn_utils::ls_float32(s, ny);
sn_utils::ls_float32(s, nz);
sn_utils::ls_float32(s, u);
sn_utils::ls_float32(s, v);
}
CMesh::CMesh()
{ // utworzenie pustego obiektu
m_pVNT = nullptr;

3
VBO.h
View File

@@ -22,7 +22,8 @@ class CVertNormTex
float u = 0.0; // U mapowania
float v = 0.0; // V mapowania
void deserialize(std::istream &s);
void deserialize(std::istream&);
void serialize(std::ostream&);
};
class CMesh

View File

@@ -69,4 +69,64 @@ std::string sn_utils::d_str(std::istream &s)
r.push_back(buf[0]);
}
return r;
}
void sn_utils::ls_uint16(std::ostream &s, uint16_t v)
{
uint8_t buf[2];
buf[0] = v;
buf[1] = v >> 8;
s.write((char*)buf, 2);
}
void sn_utils::ls_uint32(std::ostream &s, uint32_t v)
{
uint8_t buf[4];
buf[0] = v;
buf[1] = v >> 8;
buf[2] = v >> 16;
buf[3] = v >> 24;
s.write((char*)buf, 4);
}
void sn_utils::ls_int32(std::ostream &s, int32_t v)
{
uint8_t buf[4];
buf[0] = v;
buf[1] = v >> 8;
buf[2] = v >> 16;
buf[3] = v >> 24;
s.write((char*)buf, 4);
}
void sn_utils::ls_float32(std::ostream &s, float t)
{
uint32_t v = reinterpret_cast<uint32_t&>(t);
uint8_t buf[4];
buf[0] = v;
buf[1] = v >> 8;
buf[2] = v >> 16;
buf[3] = v >> 24;
s.write((char*)buf, 4);
}
void sn_utils::ls_float64(std::ostream &s, double t)
{
uint64_t v = reinterpret_cast<uint64_t&>(t);
uint8_t buf[8];
buf[0] = v;
buf[1] = v >> 8;
buf[2] = v >> 16;
buf[3] = v >> 24;
buf[4] = v >> 32;
buf[5] = v >> 40;
buf[6] = v >> 48;
buf[7] = v >> 56;
s.write((char*)buf, 8);
}
void sn_utils::s_str(std::ostream &s, std::string v)
{
const char* buf = v.c_str();
s.write(buf, v.size() + 1);
}

View File

@@ -3,10 +3,17 @@
class sn_utils
{
public:
static uint16_t ld_uint16(std::istream &s);
static uint32_t ld_uint32(std::istream &s);
static int32_t ld_int32(std::istream &s);
static float ld_float32(std::istream &s);
static double ld_float64(std::istream &s);
static std::string d_str(std::istream &s);
static uint16_t ld_uint16(std::istream&);
static uint32_t ld_uint32(std::istream&);
static int32_t ld_int32(std::istream&);
static float ld_float32(std::istream&);
static double ld_float64(std::istream&);
static std::string d_str(std::istream&);
static void ls_uint16(std::ostream&, uint16_t);
static void ls_uint32(std::ostream&, uint32_t);
static void ls_int32(std::ostream&, int32_t);
static void ls_float32(std::ostream&, float);
static void ls_float64(std::ostream&, double);
static void s_str(std::ostream&, std::string);
};