mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-03-22 15:05:03 +01:00
2078 lines
75 KiB
C++
2078 lines
75 KiB
C++
//---------------------------------------------------------------------------
|
|
/*
|
|
MaSzyna EU07 locomotive simulator
|
|
Copyright (C) 2001-2004 Marcin Wozniak, Maciej Czapkiewicz and others
|
|
|
|
*/
|
|
|
|
#include "system.hpp"
|
|
#include "classes.hpp"
|
|
#pragma hdrstop
|
|
|
|
#include "Model3d.h"
|
|
#include "Usefull.h"
|
|
#include "Texture.h"
|
|
#include "logs.h"
|
|
#include "Globals.h"
|
|
#include "Timer.h"
|
|
#include "mtable.hpp"
|
|
//---------------------------------------------------------------------------
|
|
#pragma package(smart_init)
|
|
|
|
double TSubModel::fSquareDist=0;
|
|
int TSubModel::iInstance; //numer renderowanego egzemplarza obiektu
|
|
GLuint *TSubModel::ReplacableSkinId=NULL;
|
|
int TSubModel::iAlpha=0x30300030; //maska do testowania flag tekstur wymiennych
|
|
TModel3d* TSubModel::pRoot; //Ra: tymczasowo wskaŸnik na model widoczny z submodelu
|
|
AnsiString* TSubModel::pasText;
|
|
//przyk³ady dla TSubModel::iAlpha:
|
|
// 0x30300030 - wszystkie bez kana³u alfa
|
|
// 0x31310031 - tekstura -1 u¿ywana w danym cyklu, pozosta³e nie
|
|
// 0x32320032 - tekstura -2 u¿ywana w danym cyklu, pozosta³e nie
|
|
// 0x34340034 - tekstura -3 u¿ywana w danym cyklu, pozosta³e nie
|
|
// 0x38380038 - tekstura -4 u¿ywana w danym cyklu, pozosta³e nie
|
|
// 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
|
|
|
|
|
|
char* TStringPack::String(int n)
|
|
{//zwraca wskaŸnik do ³añcucha o podanym numerze
|
|
if (index?n<(index[1]>>2)-2:false)
|
|
return data+8+index[n+2]; //indeks upraszcza kwestiê wyszukiwania
|
|
//jak nie ma indeksu, to trzeba szukaæ
|
|
int max=*((int*)(data+4)); //d³ugoœæ obszaru ³añcuchów
|
|
char* ptr=data+8; //pocz¹ek obszaru ³añcuchów
|
|
for (int i=0;i<n;++i)
|
|
{//wyszukiwanie ³añcuchów nie jest zbyt optymalne, ale nie musi byæ
|
|
while (*ptr) ++ptr; //wyszukiwanie zera
|
|
++ptr; //pominiêcie zera
|
|
if (ptr>data+max) return NULL; //zbyt wysoki numer
|
|
}
|
|
return ptr;
|
|
};
|
|
|
|
__fastcall TSubModel::TSubModel()
|
|
{
|
|
ZeroMemory(this,sizeof(TSubModel)); //istotne przy zapisywaniu wersji binarnej
|
|
FirstInit();
|
|
};
|
|
|
|
void __fastcall TSubModel::FirstInit()
|
|
{
|
|
eType=TP_ROTATOR;
|
|
Vertices=NULL;
|
|
uiDisplayList=0;
|
|
iNumVerts=-1; //do sprawdzenia
|
|
iVboPtr=-1;
|
|
fLight=-1.0; //œwietcenie wy³¹czone
|
|
v_RotateAxis=float3(0,0,0);
|
|
v_TransVector=float3(0,0,0);
|
|
f_Angle=0;
|
|
b_Anim=at_None;
|
|
b_aAnim=at_None;
|
|
fVisible=0.0; //zawsze widoczne
|
|
iVisible=1;
|
|
fMatrix=NULL; //to samo co iMatrix=0;
|
|
Next=NULL;
|
|
Child=NULL;
|
|
TextureID=0;
|
|
//TexAlpha=false;
|
|
iFlags=0x0200; //bit 9=1: submodel zosta³ utworzony a nie ustawiony na wczytany plik
|
|
//TexHash=false;
|
|
//Hits=NULL;
|
|
//CollisionPts=NULL;
|
|
//CollisionPtsCount=0;
|
|
Opacity=1.0; //przy wczytywaniu modeli by³o dzielone przez 100...
|
|
bWire=false;
|
|
fWireSize=0;
|
|
fNearAttenStart=40;
|
|
fNearAttenEnd=80;
|
|
bUseNearAtten=false;
|
|
iFarAttenDecay=0;
|
|
fFarDecayRadius=100;
|
|
fCosFalloffAngle=0.5; //120°?
|
|
fCosHotspotAngle=0.3; //145°?
|
|
fCosViewAngle=0;
|
|
fSquareMaxDist=10000*10000; //10km
|
|
fSquareMinDist=0;
|
|
iName=-1; //brak nazwy
|
|
iTexture=0; //brak tekstury
|
|
//asName="";
|
|
//asTexture="";
|
|
pName=pTexture=NULL;
|
|
f4Ambient[0]=f4Ambient[1]=f4Ambient[2]=f4Ambient[3]=1.0; //{1,1,1,1};
|
|
f4Diffuse[0]=f4Diffuse[1]=f4Diffuse[2]=f4Diffuse[3]=1.0; //{1,1,1,1};
|
|
f4Specular[0]=f4Specular[1]=f4Specular[2]=0.0; f4Specular[3]=1.0; //{0,0,0,1};
|
|
f4Emision[0]=f4Emision[1]=f4Emision[2]=f4Emision[3]=1.0;
|
|
smLetter=NULL; //u¿ywany tylko roboczo dla TP_TEXT, do przyspieszenia wyœwietlania
|
|
};
|
|
|
|
__fastcall TSubModel::~TSubModel()
|
|
{
|
|
if (uiDisplayList) glDeleteLists(uiDisplayList,1);
|
|
if (iFlags&0x0200)
|
|
{//wczytany z pliku tekstowego musi sam posprz¹taæ
|
|
//SafeDeleteArray(Indices);
|
|
SafeDelete(Next);
|
|
SafeDelete(Child);
|
|
delete fMatrix; //w³asny transform trzeba usun¹æ (zawsze jeden)
|
|
delete[] Vertices;
|
|
delete[] pTexture;
|
|
delete[] pName;
|
|
}
|
|
/*
|
|
else
|
|
{//wczytano z pliku binarnego (nie jest w³aœcicielem tablic)
|
|
}
|
|
*/
|
|
delete[] smLetter; //u¿ywany tylko roboczo dla TP_TEXT, do przyspieszenia wyœwietlania
|
|
};
|
|
|
|
void __fastcall TSubModel::TextureNameSet(const char *n)
|
|
{//ustawienie nazwy submodelu, o ile nie jest wczytany z E3D
|
|
if (iFlags&0x0200)
|
|
{//tylko je¿eli submodel zosta utworzony przez new
|
|
delete[] pTexture; //usuniêcie poprzedniej
|
|
int i=strlen(n);
|
|
if (i)
|
|
{//utworzenie nowej
|
|
pTexture=new char[i+1];
|
|
strcpy(pTexture,n);
|
|
}
|
|
else
|
|
pTexture=NULL;
|
|
}
|
|
};
|
|
|
|
void __fastcall TSubModel::NameSet(const char *n)
|
|
{//ustawienie nazwy submodelu, o ile nie jest wczytany z E3D
|
|
if (iFlags&0x0200)
|
|
{//tylko je¿eli submodel zosta utworzony przez new
|
|
delete[] pName; //usuniêcie poprzedniej
|
|
int i=strlen(n);
|
|
if (i)
|
|
{//utworzenie nowej
|
|
pName=new char[i+1];
|
|
strcpy(pName,n);
|
|
}
|
|
else
|
|
pName=NULL;
|
|
}
|
|
};
|
|
|
|
//int __fastcall TSubModel::SeekFaceNormal(DWORD *Masks, int f,DWORD dwMask,vector3 *pt,GLVERTEX *Vertices)
|
|
int __fastcall TSubModel::SeekFaceNormal(DWORD *Masks,int f,DWORD dwMask,float3 *pt,float8 *Vertices)
|
|
{//szukanie punktu stycznego do (pt), zwraca numer wierzcho³ka, a nie trójk¹ta
|
|
int iNumFaces=iNumVerts/3; //bo maska powierzchni jest jedna na trójk¹t
|
|
//GLVERTEX *p; //roboczy wskaŸnik
|
|
float8 *p; //roboczy wskaŸnik
|
|
for (int i=f;i<iNumFaces;++i) //pêtla po trójk¹tach, od trójk¹ta (f)
|
|
if (Masks[i]&dwMask) //jeœli wspólna maska powierzchni
|
|
{p=Vertices+3*i;
|
|
if (p->Point==*pt) return 3*i;
|
|
if ((++p)->Point==*pt) return 3*i+1;
|
|
if ((++p)->Point==*pt) return 3*i+2;
|
|
}
|
|
return -1; //nie znaleziono stycznego wierzcho³ka
|
|
}
|
|
|
|
float emm1[]={1,1,1,0};
|
|
float emm2[]={0,0,0,1};
|
|
|
|
inline double readIntAsDouble(cParser& parser,int base=255)
|
|
{
|
|
int value;
|
|
parser.getToken(value);
|
|
return double(value)/base;
|
|
};
|
|
|
|
template <typename ColorT>
|
|
inline void readColor(cParser& parser,ColorT* color)
|
|
{
|
|
parser.ignoreToken();
|
|
color[0]=readIntAsDouble(parser);
|
|
color[1]=readIntAsDouble(parser);
|
|
color[2]=readIntAsDouble(parser);
|
|
};
|
|
|
|
inline void readColor(cParser& parser,int &color)
|
|
{
|
|
int r,g,b;
|
|
parser.ignoreToken();
|
|
parser.getToken(r);
|
|
parser.getToken(g);
|
|
parser.getToken(b);
|
|
color=r+(g<<8)+(b<<16);
|
|
};
|
|
/*
|
|
inline void readMatrix(cParser& parser,matrix4x4& matrix)
|
|
{//Ra: wczytanie transforma
|
|
for (int x=0;x<=3;x++) //wiersze
|
|
for (int y=0;y<=3;y++) //kolumny
|
|
parser.getToken(matrix(x)[y]);
|
|
};
|
|
*/
|
|
inline void readMatrix(cParser& parser,float4x4& matrix)
|
|
{//Ra: wczytanie transforma
|
|
for (int x=0;x<=3;x++) //wiersze
|
|
for (int y=0;y<=3;y++) //kolumny
|
|
parser.getToken(matrix(x)[y]);
|
|
};
|
|
|
|
int __fastcall TSubModel::Load(cParser& parser,TModel3d *Model,int Pos,bool dynamic)
|
|
{//Ra: VBO tworzone na poziomie modelu, a nie submodeli
|
|
iNumVerts=0;
|
|
iVboPtr=Pos; //pozycja w VBO
|
|
//TMaterialColorf Ambient,Diffuse,Specular;
|
|
//GLuint TextureID;
|
|
//char *extName;
|
|
if (!parser.expectToken("type:"))
|
|
Error("Model type parse failure!");
|
|
{
|
|
std::string type;
|
|
parser.getToken(type);
|
|
if (type=="mesh")
|
|
eType=GL_TRIANGLES; //submodel - trójkaty
|
|
else if (type=="point")
|
|
eType=GL_POINTS; //co to niby jest?
|
|
else if (type=="freespotlight")
|
|
eType=TP_FREESPOTLIGHT; //œwiate³ko
|
|
else if (type=="text")
|
|
eType=TP_TEXT; //wyœwietlacz tekstowy (generator napisów)
|
|
else if (type=="stars")
|
|
eType=TP_STARS; //wiele punktów œwietlnych
|
|
};
|
|
parser.ignoreToken();
|
|
std::string token;
|
|
//parser.getToken(token1); //ze zmian¹ na ma³e!
|
|
parser.getTokens(1,false); //nazwa submodelu bez zmieny na ma³e
|
|
parser >> token;
|
|
NameSet(token.c_str());
|
|
if (dynamic)
|
|
{//dla pojazdu, blokujemy za³¹czone submodele, które mog¹ byæ nieobs³ugiwane
|
|
if (token.find("_on")+3==token.length()) //jeœli nazwa koñczy siê na "_on"
|
|
iVisible=0; //to domyœlnie wy³¹czyæ, ¿eby siê nie nak³ada³o z obiektem "_off"
|
|
}
|
|
else //dla pozosta³ych modeli blokujemy zapalone œwiat³a, które mog¹ byæ nieobs³ugiwane
|
|
if (token.find("Light_On")==0) //jeœli nazwa zaczyna siê od "Light_On"
|
|
iVisible=0; //to domyœlnie wy³¹czyæ, ¿eby siê nie nak³ada³o z obiektem "Light_Off"
|
|
|
|
if (parser.expectToken("anim:")) //Ra: ta informacja by siê przyda³a!
|
|
{//rodzaj animacji
|
|
std::string type;
|
|
parser.getToken(type);
|
|
if (type!="false")
|
|
{iFlags|=0x4000; //jak animacja, to trzeba przechowywaæ macierz zawsze
|
|
if (type=="seconds_jump") b_Anim=b_aAnim=at_SecondsJump; //sekundy z przeskokiem
|
|
else if (type=="minutes_jump") b_Anim=b_aAnim=at_MinutesJump; //minuty z przeskokiem
|
|
else if (type=="hours_jump") b_Anim=b_aAnim=at_HoursJump; //godziny z przeskokiem
|
|
else if (type=="hours24_jump") b_Anim=b_aAnim=at_Hours24Jump; //godziny z przeskokiem
|
|
else if (type=="seconds") b_Anim=b_aAnim=at_Seconds; //minuty p³ynnie
|
|
else if (type=="minutes") b_Anim=b_aAnim=at_Minutes; //minuty p³ynnie
|
|
else if (type=="hours") b_Anim=b_aAnim=at_Hours; //godziny p³ynnie
|
|
else if (type=="hours24") b_Anim=b_aAnim=at_Hours24; //godziny p³ynnie
|
|
else if (type=="billboard") b_Anim=b_aAnim=at_Billboard; //obrót w pionie do kamery
|
|
else if (type=="wind") b_Anim=b_aAnim=at_Wind; //ruch pod wp³ywem wiatru
|
|
else if (type=="sky") b_Anim=b_aAnim=at_Sky; //aniamacja nieba
|
|
else if (type=="ik") b_Anim=b_aAnim=at_IK; //IK: zadaj¹cy
|
|
else if (type=="ik11") b_Anim=b_aAnim=at_IK11; //IK: kierunkowany
|
|
else if (type=="ik21") b_Anim=b_aAnim=at_IK21; //IK: kierunkowany
|
|
else if (type=="ik22") b_Anim=b_aAnim=at_IK22; //IK: kierunkowany
|
|
else if (type=="digital") b_Anim=b_aAnim=at_Digital; //licznik mechaniczny
|
|
else if (type=="digiclk") b_Anim=b_aAnim=at_DigiClk; //zegar cyfrowy
|
|
else b_Anim=b_aAnim=at_Undefined; //nieznana forma animacji
|
|
}
|
|
}
|
|
if (eType<TP_ROTATOR) readColor(parser,f4Ambient); //ignoruje token przed
|
|
readColor(parser,f4Diffuse);
|
|
if (eType<TP_ROTATOR) readColor(parser,f4Specular);
|
|
parser.ignoreTokens(1); //zignorowanie nazwy "SelfIllum:"
|
|
{
|
|
std::string light;
|
|
parser.getToken(light);
|
|
if (light=="true")
|
|
fLight=2.0; //zawsze œwieci
|
|
else if (light=="false")
|
|
fLight=-1.0; //zawsze ciemy
|
|
else
|
|
fLight=atof(light.c_str());
|
|
};
|
|
if (eType==TP_FREESPOTLIGHT)
|
|
{
|
|
if (!parser.expectToken("nearattenstart:"))
|
|
Error("Model light parse failure!");
|
|
parser.getToken(fNearAttenStart);
|
|
parser.ignoreToken();
|
|
parser.getToken(fNearAttenEnd);
|
|
parser.ignoreToken();
|
|
bUseNearAtten=parser.expectToken("true");
|
|
parser.ignoreToken();
|
|
parser.getToken(iFarAttenDecay);
|
|
parser.ignoreToken();
|
|
parser.getToken(fFarDecayRadius);
|
|
parser.ignoreToken();
|
|
parser.getToken(fCosFalloffAngle); //k¹t liczony dla œrednicy, a nie promienia
|
|
fCosFalloffAngle=cos(DegToRad(0.5*fCosFalloffAngle));
|
|
parser.ignoreToken();
|
|
parser.getToken(fCosHotspotAngle); //k¹t liczony dla œrednicy, a nie promienia
|
|
fCosHotspotAngle=cos(DegToRad(0.5*fCosHotspotAngle));
|
|
iNumVerts=1;
|
|
iFlags|=0x4010; //rysowane w cyklu nieprzezroczystych, macierz musi zostaæ bez zmiany
|
|
}
|
|
else if (eType<TP_ROTATOR)
|
|
{
|
|
parser.ignoreToken();
|
|
bWire=parser.expectToken("true");
|
|
parser.ignoreToken();
|
|
parser.getToken(fWireSize);
|
|
parser.ignoreToken();
|
|
Opacity=readIntAsDouble(parser,100.0f); //wymagane jest 0 dla szyb, 100 idzie w nieprzezroczyste
|
|
if (Opacity>1.0) Opacity*=0.01; //w 2013 by³ b³¹d i aby go obejœæ, trzeba by³o wpisaæ 10000.0
|
|
if ((Global::iConvertModels&1)==0) //dla zgodnoœci wstecz
|
|
Opacity=0.0; //wszystko idzie w przezroczyste albo zale¿nie od tekstury
|
|
if (!parser.expectToken("map:"))
|
|
Error("Model map parse failure!");
|
|
std::string texture;
|
|
parser.getToken(texture);
|
|
if (texture=="none")
|
|
{//rysowanie podanym kolorem
|
|
TextureID=0;
|
|
iFlags|=0x10; //rysowane w cyklu nieprzezroczystych
|
|
}
|
|
else if (texture.find("replacableskin")!=texture.npos)
|
|
{// McZapkie-060702: zmienialne skory modelu
|
|
TextureID=-1;
|
|
iFlags|=(Opacity<1.0)?1:0x10; //zmienna tekstura 1
|
|
}
|
|
else if (texture=="-1")
|
|
{
|
|
TextureID=-1;
|
|
iFlags|=(Opacity<1.0)?1:0x10; //zmienna tekstura 1
|
|
}
|
|
else if (texture=="-2")
|
|
{
|
|
TextureID=-2;
|
|
iFlags|=(Opacity<1.0)?2:0x10; //zmienna tekstura 2
|
|
}
|
|
else if (texture=="-3")
|
|
{
|
|
TextureID=-3;
|
|
iFlags|=(Opacity<1.0)?4:0x10; //zmienna tekstura 3
|
|
}
|
|
else if (texture=="-4")
|
|
{
|
|
TextureID=-4;
|
|
iFlags|=(Opacity<1.0)?8:0x10; //zmienna tekstura 4
|
|
}
|
|
else
|
|
{//jeœli tylko nazwa pliku, to dawaæ bie¿¹c¹ œcie¿kê do tekstur
|
|
//asTexture=AnsiString(texture.c_str()); //zapamiêtanie nazwy tekstury
|
|
TextureNameSet(texture.c_str());
|
|
if (texture.find_first_of("/\\")==texture.npos)
|
|
texture.insert(0,Global::asCurrentTexturePath.c_str());
|
|
TextureID=TTexturesManager::GetTextureID(szTexturePath,Global::asCurrentTexturePath.c_str(),texture);
|
|
//TexAlpha=TTexturesManager::GetAlpha(TextureID);
|
|
//iFlags|=TexAlpha?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta
|
|
if (Opacity<1.0) //przezroczystoϾ z tekstury brana tylko dla Opacity 0!
|
|
iFlags|=TTexturesManager::GetAlpha(TextureID)?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta
|
|
else
|
|
iFlags|=0x10; //normalnie nieprzezroczyste
|
|
//renderowanie w cyklu przezroczystych tylko jeœli:
|
|
//1. Opacity=0 (przejœciowo <1, czy tam <100) oraz
|
|
//2. tekstura ma przezroczystoϾ
|
|
};
|
|
}
|
|
else iFlags|=0x10;
|
|
parser.ignoreToken();
|
|
parser.getToken(fSquareMaxDist);
|
|
if (fSquareMaxDist>=0.0)
|
|
fSquareMaxDist*=fSquareMaxDist;
|
|
else
|
|
fSquareMaxDist=15000*15000; //15km to wiêcej, ni¿ siê obecnie wyœwietla
|
|
parser.ignoreToken();
|
|
parser.getToken(fSquareMinDist);
|
|
fSquareMinDist*=fSquareMinDist;
|
|
parser.ignoreToken();
|
|
fMatrix=new float4x4();
|
|
readMatrix(parser,*fMatrix); //wczytanie transform
|
|
if (!fMatrix->IdentityIs())
|
|
iFlags|=0x8000; //transform niejedynkowy - trzeba go przechowaæ
|
|
int iNumFaces; //iloœæ trójk¹tów
|
|
DWORD *sg; //maski przynale¿noœci trójk¹tów do powierzchni
|
|
if (eType<TP_ROTATOR)
|
|
{//wczytywanie wierzcho³ków
|
|
parser.ignoreToken();
|
|
//Ra 15-01: to wczytaæ jako tekst - jeœli pierwszy znak zawiera "*", to dalej bêdzie nazwa wczeœniejszego submodelu, z którego nale¿y wzi¹æ wierzcho³ki
|
|
//zapewni to jak¹œ zgodnoœæ wstecz, bo zamiast liczby bêdzie ci¹g, którego wartoœæ powinna byæ uznana jako zerowa
|
|
//parser.getToken(iNumVerts);
|
|
parser.getToken(token);
|
|
if (token[0]=='*')
|
|
{//jeœli pierwszy znak jest gwiazdk¹, poszukaæ submodelu o nazwie bez tej gwiazdki i wzi¹æ z niego wierzcho³ki
|
|
Error("Verticles reference not yet supported!");
|
|
}
|
|
else
|
|
{//normalna lista wierzcho³ków
|
|
iNumVerts=atoi(token.c_str());
|
|
if (iNumVerts%3)
|
|
{
|
|
iNumVerts=0;
|
|
Error("Mesh error, (iNumVertices="+AnsiString(iNumVerts)+")%3<>0");
|
|
return 0;
|
|
}
|
|
//Vertices=new GLVERTEX[iNumVerts];
|
|
if (iNumVerts)
|
|
{Vertices=new float8[iNumVerts];
|
|
iNumFaces=iNumVerts/3;
|
|
sg=new DWORD[iNumFaces]; //maski powierzchni: 0 oznacza brak u¿redniania wektorów normalnych
|
|
int *wsp=new int[iNumVerts]; //z którego wierzcho³ka kopiowaæ wektor normalny
|
|
int maska=0;
|
|
for (int i=0;i<iNumVerts;i++)
|
|
{//Ra: z konwersj¹ na uk³ad scenerii - bêdzie wydajniejsze wyœwietlanie
|
|
wsp[i]=-1; //wektory normalne nie s¹ policzone dla tego wierzcho³ka
|
|
if ((i%3)==0)
|
|
{//jeœli bêdzie maska -1, to dalej bêd¹ wierzcho³ki z wektorami normalnymi, podanymi jawnie
|
|
parser.getToken(maska); //maska powierzchni trójk¹ta
|
|
sg[i/3]=(maska==-1)?0:maska; //dla maski -1 bêdzie 0, czyli nie ma wspólnych wektorów normalnych
|
|
}
|
|
parser.getToken(Vertices[i].Point.x);
|
|
parser.getToken(Vertices[i].Point.y);
|
|
parser.getToken(Vertices[i].Point.z);
|
|
if (maska==-1)
|
|
{//jeœli wektory normalne podane jawnie
|
|
parser.getToken(Vertices[i].Normal.x);
|
|
parser.getToken(Vertices[i].Normal.y);
|
|
parser.getToken(Vertices[i].Normal.z);
|
|
wsp[i]=i; //wektory normalne "s¹ ju¿ policzone"
|
|
}
|
|
parser.getToken(Vertices[i].tu);
|
|
parser.getToken(Vertices[i].tv);
|
|
if (i%3==2) //je¿eli wczytano 3 punkty
|
|
{if (Vertices[i ].Point==Vertices[i-1].Point ||
|
|
Vertices[i-1].Point==Vertices[i-2].Point ||
|
|
Vertices[i-2].Point==Vertices[i ].Point)
|
|
{//je¿eli punkty siê nak³adaj¹ na siebie
|
|
--iNumFaces; //o jeden trójk¹t mniej
|
|
iNumVerts-=3; //czyli o 3 wierzcho³ki
|
|
i-=3; //wczytanie kolejnego w to miejsce
|
|
WriteLog(AnsiString("Degenerated triangle ignored in: \"")+AnsiString(pName)+"\", verticle "+AnsiString(i));
|
|
}
|
|
if (i>0) //jeœli pierwszy trójk¹t bêdzie zdegenerowany, to zostanie usuniêty i nie ma co sprawdzaæ
|
|
if (((Vertices[i ].Point-Vertices[i-1].Point).Length()>1000.0) ||
|
|
((Vertices[i-1].Point-Vertices[i-2].Point).Length()>1000.0) ||
|
|
((Vertices[i-2].Point-Vertices[i ].Point).Length()>1000.0))
|
|
{//je¿eli s¹ dalej ni¿ 2km od siebie //Ra 15-01: obiekt wstawiany nie powinien byæ wiêkszy ni¿ 300m (trójk¹ty terenu w E3D mog¹ mieæ 1.5km)
|
|
--iNumFaces; //o jeden trójk¹t mniej
|
|
iNumVerts-=3; //czyli o 3 wierzcho³ki
|
|
i-=3; //wczytanie kolejnego w to miejsce
|
|
WriteLog(AnsiString("Too large triangle ignored in: \"")+AnsiString(pName)+"\"");
|
|
}
|
|
}
|
|
}
|
|
int i; //indeks dla trójk¹tów
|
|
float3 *n=new float3[iNumFaces]; //tablica wektorów normalnych dla trójk¹tów
|
|
for (i=0;i<iNumFaces;i++) //pêtla po trójk¹tach - bêdzie szybciej, jak wstêpnie przeliczymy normalne trójk¹tów
|
|
n[i]=SafeNormalize(CrossProduct(Vertices[i*3].Point-Vertices[i*3+1].Point,Vertices[i*3].Point-Vertices[i*3+2].Point));
|
|
int v; //indeks dla wierzcho³ków
|
|
int f; //numer trójk¹ta stycznego
|
|
float3 norm; //roboczy wektor normalny
|
|
for (v=0;v<iNumVerts;v++)
|
|
{//pêtla po wierzcho³kach trójk¹tów
|
|
if (wsp[v]>=0) //jeœli ju¿ by³ liczony wektor normalny z u¿yciem tego wierzcho³ka
|
|
Vertices[v].Normal=Vertices[wsp[v]].Normal; //to wystarczy skopiowaæ policzony wczeœniej
|
|
else
|
|
{//inaczej musimy dopiero policzyæ
|
|
i=v/3; //numer trójk¹ta
|
|
norm=float3(0,0,0); //liczenie zaczynamy od zera
|
|
f=v; //zaczynamy dodawanie wektorów normalnych od w³asnego
|
|
while (f>=0)
|
|
{//sumowanie z wektorem normalnym s¹siada (w³¹cznie ze sob¹)
|
|
wsp[f]=v; //informacja, ¿e w tym wierzcho³ku jest ju¿ policzony wektor normalny
|
|
norm+=n[f/3];
|
|
f=SeekFaceNormal(sg,f/3+1,sg[i],&Vertices[v].Point,Vertices); //i szukanie od kolejnego trójk¹ta
|
|
}
|
|
//Ra 15-01: nale¿a³o by jeszcze uwzglêdniæ skalowanie wprowadzane przez transformy, aby normalne po przeskalowaniu by³y jednostkowe
|
|
Vertices[v].Normal=SafeNormalize(norm); //przepisanie do wierzcho³ka trójk¹ta
|
|
}
|
|
}
|
|
delete[] wsp;
|
|
delete[] n;
|
|
delete[] sg;
|
|
}
|
|
else //gdy brak wierzcho³ków
|
|
{eType=TP_ROTATOR; //submodel pomocniczy, ma tylko macierz przekszta³cenia
|
|
iVboPtr=iNumVerts=0; //dla formalnoœci
|
|
}
|
|
} //obs³uga submodelu z w³asn¹ list¹ wierzcho³ków
|
|
}
|
|
else if (eType==TP_STARS)
|
|
{//punkty œwiec¹ce dookólnie - sk³adnia jak dla smt_Mesh
|
|
parser.ignoreToken();
|
|
parser.getToken(iNumVerts);
|
|
//Vertices=new GLVERTEX[iNumVerts];
|
|
Vertices=new float8[iNumVerts];
|
|
int i,j;
|
|
for (i=0;i<iNumVerts;i++)
|
|
{
|
|
if (i%3==0)
|
|
parser.ignoreToken(); //maska powierzchni trójk¹ta
|
|
parser.getToken(Vertices[i].Point.x);
|
|
parser.getToken(Vertices[i].Point.y);
|
|
parser.getToken(Vertices[i].Point.z);
|
|
parser.getToken(j); //zakodowany kolor
|
|
parser.ignoreToken();
|
|
Vertices[i].Normal.x=((j )&0xFF)/255.0; //R
|
|
Vertices[i].Normal.y=((j>> 8)&0xFF)/255.0; //G
|
|
Vertices[i].Normal.z=((j>>16)&0xFF)/255.0; //B
|
|
}
|
|
}
|
|
//Visible=true; //siê potem wy³¹czy w razie potrzeby
|
|
//iFlags|=0x0200; //wczytano z pliku tekstowego (jest w³aœcicielem tablic)
|
|
if (iNumVerts<1) iFlags&=~0x3F; //cykl renderowania uzale¿niony od potomnych
|
|
return iNumVerts; //do okreœlenia wielkoœci VBO
|
|
};
|
|
|
|
int __fastcall TSubModel::TriangleAdd(TModel3d *m,int tex,int tri)
|
|
{//dodanie trójk¹tów do submodelu, u¿ywane przy tworzeniu E3D terenu
|
|
TSubModel *s=this;
|
|
while (s?(s->TextureID!=tex):false)
|
|
{//szukanie submodelu o danej teksturze
|
|
if (s==this)
|
|
s=Child;
|
|
else
|
|
s=s->Next;
|
|
}
|
|
if (!s)
|
|
{if (TextureID<=0)
|
|
s=this; //u¿ycie g³ównego
|
|
else
|
|
{//dodanie nowego submodelu do listy potomnych
|
|
s=new TSubModel();
|
|
m->AddTo(this,s);
|
|
}
|
|
//s->asTexture=AnsiString(TTexturesManager::GetName(tex).c_str());
|
|
s->TextureNameSet(TTexturesManager::GetName(tex).c_str());
|
|
s->TextureID=tex;
|
|
s->eType=GL_TRIANGLES;
|
|
//iAnimOwner=0; //roboczy wskaŸnik na wierzcho³ek
|
|
}
|
|
if (s->iNumVerts<0)
|
|
s->iNumVerts=tri; //bo na pocz¹tku jest -1, czyli ¿e nie wiadomo
|
|
else
|
|
s->iNumVerts+=tri; //aktualizacja iloœci wierzcho³ków
|
|
return s->iNumVerts-tri; //zwraca pozycjê tych trójk¹tów w submodelu
|
|
};
|
|
|
|
float8* __fastcall TSubModel::TrianglePtr(int tex,int pos,int *la,int *ld,int*ls)
|
|
{//zwraca wskaŸnik do wype³nienia tabeli wierzcho³ków, u¿ywane przy tworzeniu E3D terenu
|
|
TSubModel *s=this;
|
|
while (s?s->TextureID!=tex:false)
|
|
{//szukanie submodelu o danej teksturze
|
|
if (s==this)
|
|
s=Child;
|
|
else
|
|
s=s->Next;
|
|
}
|
|
if (!s)
|
|
return NULL; //coœ nie tak posz³o
|
|
if (!s->Vertices)
|
|
{//utworznie tabeli trójk¹tów
|
|
s->Vertices=new float8[s->iNumVerts];
|
|
//iVboPtr=pos; //pozycja submodelu w tabeli wierzcho³ków
|
|
//pos+=iNumVerts; //rezerwacja miejsca w tabeli
|
|
s->iVboPtr=iInstance; //pozycja submodelu w tabeli wierzcho³ków
|
|
iInstance+=s->iNumVerts; //pozycja dla nastêpnego
|
|
}
|
|
s->ColorsSet(la,ld,ls); //ustawienie kolorów œwiate³
|
|
return s->Vertices+pos; //wskaŸnik na wolne miejsce w tabeli wierzcho³ków
|
|
};
|
|
|
|
void __fastcall TSubModel::DisplayLists()
|
|
{//utworznie po jednej skompilowanej liœcie dla ka¿dego submodelu
|
|
if (Global::bUseVBO) return; //Ra: przy VBO to siê nie przyda
|
|
//iFlags|=0x4000; //wy³¹czenie przeliczania wierzcho³ków, bo nie s¹ zachowane
|
|
if (eType<TP_ROTATOR)
|
|
{
|
|
if (iNumVerts>0)
|
|
{
|
|
uiDisplayList=glGenLists(1);
|
|
glNewList(uiDisplayList,GL_COMPILE);
|
|
glColor3fv(f4Diffuse); //McZapkie-240702: zamiast ub
|
|
#ifdef USE_VERTEX_ARRAYS
|
|
// ShaXbee-121209: przekazywanie wierzcholkow hurtem
|
|
glVertexPointer(3,GL_DOUBLE,sizeof(GLVERTEX),&Vertices[0].Point.x);
|
|
glNormalPointer(GL_DOUBLE,sizeof(GLVERTEX),&Vertices[0].Normal.x);
|
|
glTexCoordPointer(2,GL_FLOAT,sizeof(GLVERTEX),&Vertices[0].tu);
|
|
glDrawArrays(eType,0,iNumVerts);
|
|
#else
|
|
glBegin(eType);
|
|
for (int i=0;i<iNumVerts;i++)
|
|
{
|
|
/*
|
|
glNormal3dv(&Vertices[i].Normal.x);
|
|
glTexCoord2f(Vertices[i].tu,Vertices[i].tv);
|
|
glVertex3dv(&Vertices[i].Point.x);
|
|
*/
|
|
glNormal3fv(&Vertices[i].Normal.x);
|
|
glTexCoord2f(Vertices[i].tu,Vertices[i].tv);
|
|
glVertex3fv(&Vertices[i].Point.x);
|
|
};
|
|
glEnd();
|
|
#endif
|
|
glEndList();
|
|
}
|
|
}
|
|
else if (eType==TP_FREESPOTLIGHT)
|
|
{
|
|
uiDisplayList=glGenLists(1);
|
|
glNewList(uiDisplayList,GL_COMPILE);
|
|
glBindTexture(GL_TEXTURE_2D,0);
|
|
// if (eType==smt_FreeSpotLight)
|
|
// {
|
|
// if (iFarAttenDecay==0)
|
|
// glColor3f(Diffuse[0],Diffuse[1],Diffuse[2]);
|
|
// }
|
|
// else
|
|
//TODO: poprawic zeby dzialalo
|
|
//glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]);
|
|
glColorMaterial(GL_FRONT,GL_EMISSION);
|
|
glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly
|
|
glBegin(GL_POINTS);
|
|
glVertex3f(0,0,0);
|
|
glEnd();
|
|
glEnable(GL_LIGHTING);
|
|
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
glEndList();
|
|
}
|
|
else if (eType==TP_STARS)
|
|
{//punkty œwiec¹ce dookólnie
|
|
uiDisplayList=glGenLists(1);
|
|
glNewList(uiDisplayList,GL_COMPILE);
|
|
glBindTexture(GL_TEXTURE_2D,0); //tekstury nie ma
|
|
glColorMaterial(GL_FRONT,GL_EMISSION);
|
|
glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly
|
|
glBegin(GL_POINTS);
|
|
for (int i=0;i<iNumVerts;i++)
|
|
{
|
|
glColor3f(Vertices[i].Normal.x,Vertices[i].Normal.y,Vertices[i].Normal.z);
|
|
//glVertex3dv(&Vertices[i].Point.x);
|
|
glVertex3fv(&Vertices[i].Point.x);
|
|
};
|
|
glEnd();
|
|
glEnable(GL_LIGHTING);
|
|
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
glEndList();
|
|
}
|
|
//SafeDeleteArray(Vertices); //przy VBO musz¹ zostaæ do za³adowania ca³ego modelu
|
|
if (Child) Child->DisplayLists();
|
|
if (Next) Next->DisplayLists();
|
|
};
|
|
|
|
void __fastcall TSubModel::InitialRotate(bool doit)
|
|
{//konwersja uk³adu wspó³rzêdnych na zgodny ze sceneri¹
|
|
if (iFlags&0xC000) //jeœli jest animacja albo niejednostkowy transform
|
|
{//niejednostkowy transform jest mno¿ony i wystarczy zabawy
|
|
if (doit)
|
|
{//obrót lewostronny
|
|
if (!fMatrix) //macierzy mo¿e nie byæ w dodanym "bananie"
|
|
{fMatrix=new float4x4(); //tworzy macierz o przypadkowej zawartoœci
|
|
fMatrix->Identity(); //a zaczynamy obracanie od jednostkowej
|
|
}
|
|
iFlags|=0x8000; //po obróceniu bêdzie raczej niejedynkowy matrix
|
|
fMatrix->InitialRotate(); //zmiana znaku X oraz zamiana Y i Z
|
|
if (fMatrix->IdentityIs()) iFlags&=~0x8000; //jednak jednostkowa po obróceniu
|
|
}
|
|
if (Child)
|
|
Child->InitialRotate(false); //potomnych nie obracamy ju¿, tylko ewentualnie optymalizujemy
|
|
else
|
|
if (Global::iConvertModels&2) //optymalizacja jest opcjonalna
|
|
if ((iFlags&0xC000)==0x8000) //o ile nie ma animacji
|
|
{//jak nie ma potomnych, mo¿na wymno¿yæ przez transform i wyjedynkowaæ go
|
|
float4x4 *mat=GetMatrix(); //transform submodelu
|
|
if (Vertices)
|
|
{for (int i=0;i<iNumVerts;++i)
|
|
Vertices[i].Point=(*mat)*Vertices[i].Point;
|
|
(*mat)(3)[0]=(*mat)(3)[1]=(*mat)(3)[2]=0.0; //zerujemy przesuniêcie przed obracaniem normalnych
|
|
if (eType!=TP_STARS) //gwiazdki maj¹ kolory zamiast normalnych, to ich wtedy nie ruszamy
|
|
for (int i=0;i<iNumVerts;++i)
|
|
Vertices[i].Normal=SafeNormalize((*mat)*Vertices[i].Normal);
|
|
}
|
|
mat->Identity(); //jedynkowanie transformu po przeliczeniu wierzcho³ków
|
|
iFlags&=~0x8000; //transform jedynkowy
|
|
}
|
|
}
|
|
else //jak jest jednostkowy i nie ma animacji
|
|
if (doit)
|
|
{//jeœli jest jednostkowy transform, to przeliczamy wierzcho³ki, a mno¿enie podajemy dalej
|
|
double t;
|
|
if (Vertices)
|
|
for (int i=0;i<iNumVerts;++i)
|
|
{
|
|
Vertices[i].Point.x=-Vertices[i].Point.x; //zmiana znaku X
|
|
t=Vertices[i].Point.y; //zamiana Y i Z
|
|
Vertices[i].Point.y=Vertices[i].Point.z;
|
|
Vertices[i].Point.z=t;
|
|
//wektory normalne równie¿ trzeba przekszta³ciæ, bo siê Ÿle oœwietlaj¹
|
|
Vertices[i].Normal.x=-Vertices[i].Normal.x; //zmiana znaku X
|
|
t=Vertices[i].Normal.y; //zamiana Y i Z
|
|
Vertices[i].Normal.y=Vertices[i].Normal.z;
|
|
Vertices[i].Normal.z=t;
|
|
}
|
|
if (Child) Child->InitialRotate(doit); //potomne ewentualnie obrócimy
|
|
}
|
|
if (Next) Next->InitialRotate(doit);
|
|
};
|
|
|
|
void __fastcall TSubModel::ChildAdd(TSubModel *SubModel)
|
|
{//dodanie submodelu potemnego (uzale¿nionego)
|
|
//Ra: zmiana kolejnoœci, ¿eby kolejne móc renderowaæ po aktualnym (by³o przed)
|
|
if (SubModel) SubModel->NextAdd(Child); //Ra: zmiana kolejnoœci renderowania
|
|
Child=SubModel;
|
|
};
|
|
|
|
void __fastcall TSubModel::NextAdd(TSubModel *SubModel)
|
|
{//dodanie submodelu kolejnego (wspólny przodek)
|
|
if (Next)
|
|
Next->NextAdd(SubModel);
|
|
else
|
|
Next=SubModel;
|
|
};
|
|
|
|
int __fastcall TSubModel::FlagsCheck()
|
|
{//analiza koniecznych zmian pomiêdzy submodelami
|
|
//samo pomijanie glBindTexture() nie poprawi wydajnoœci
|
|
//ale mo¿na sprawdziæ, czy mo¿na w ogóle pomin¹æ kod do tekstur (sprawdzanie replaceskin)
|
|
int i;
|
|
if (Child)
|
|
{//Child jest renderowany po danym submodelu
|
|
if (Child->TextureID) //o ile ma teksturê
|
|
if (Child->TextureID!=TextureID) //i jest ona inna ni¿ rodzica
|
|
Child->iFlags|=0x80; //to trzeba sprawdzaæ, jak z teksturami jest
|
|
i=Child->FlagsCheck();
|
|
iFlags|=0x00FF0000&((i<<16)|(i)|(i>>8)); //potomny, rodzeñstwo i dzieci
|
|
if (eType==TP_TEXT)
|
|
{//wy³¹czenie renderowania Next dla znaków wyœwietlacza tekstowego
|
|
TSubModel *p=Child;
|
|
while (p)
|
|
{p->iFlags&=0xC0FFFFFF;
|
|
p=p->Next;
|
|
}
|
|
}
|
|
}
|
|
if (Next)
|
|
{//Next jest renderowany po danym submodelu (kolejnoœæ odwrócona po wczytaniu T3D)
|
|
if (TextureID) //o ile dany ma teksturê
|
|
if ((TextureID!=Next->TextureID)||(i&0x00800000)) //a ma inn¹ albo dzieci zmieniaj¹
|
|
iFlags|=0x80; //to dany submodel musi sobie j¹ ustawiaæ
|
|
i=Next->FlagsCheck();
|
|
iFlags|=0xFF000000&((i<<24)|(i<<8)|(i)); //nastêpny, kolejne i ich dzieci
|
|
//tekstury nie ustawiamy tylko wtedy, gdy jest taka sama jak Next i jego dzieci nie zmieniaj¹
|
|
}
|
|
return iFlags;
|
|
};
|
|
|
|
void __fastcall TSubModel::SetRotate(float3 vNewRotateAxis,float fNewAngle)
|
|
{//obrócenie submodelu wg podanej osi (np. wskazówki w kabinie)
|
|
v_RotateAxis=vNewRotateAxis;
|
|
f_Angle=fNewAngle;
|
|
if (fNewAngle!=0.0)
|
|
{b_Anim=at_Rotate;
|
|
b_aAnim=at_Rotate;
|
|
}
|
|
iAnimOwner=iInstance; //zapamiêtanie czyja jest animacja
|
|
}
|
|
|
|
void __fastcall TSubModel::SetRotateXYZ(float3 vNewAngles)
|
|
{//obrócenie submodelu o podane k¹ty wokó³ osi lokalnego uk³adu
|
|
v_Angles=vNewAngles;
|
|
b_Anim=at_RotateXYZ;
|
|
b_aAnim=at_RotateXYZ;
|
|
iAnimOwner=iInstance; //zapamiêtanie czyja jest animacja
|
|
}
|
|
|
|
void __fastcall TSubModel::SetRotateXYZ(vector3 vNewAngles)
|
|
{//obrócenie submodelu o podane k¹ty wokó³ osi lokalnego uk³adu
|
|
v_Angles.x=vNewAngles.x;
|
|
v_Angles.y=vNewAngles.y;
|
|
v_Angles.z=vNewAngles.z;
|
|
b_Anim=at_RotateXYZ;
|
|
b_aAnim=at_RotateXYZ;
|
|
iAnimOwner=iInstance; //zapamiêtanie czyja jest animacja
|
|
}
|
|
|
|
void __fastcall TSubModel::SetTranslate(float3 vNewTransVector)
|
|
{//przesuniêcie submodelu (np. w kabinie)
|
|
v_TransVector=vNewTransVector;
|
|
b_Anim=at_Translate;
|
|
b_aAnim=at_Translate;
|
|
iAnimOwner=iInstance; //zapamiêtanie czyja jest animacja
|
|
}
|
|
|
|
void __fastcall TSubModel::SetTranslate(vector3 vNewTransVector)
|
|
{//przesuniêcie submodelu (np. w kabinie)
|
|
v_TransVector.x=vNewTransVector.x;
|
|
v_TransVector.y=vNewTransVector.y;
|
|
v_TransVector.z=vNewTransVector.z;
|
|
b_Anim=at_Translate;
|
|
b_aAnim=at_Translate;
|
|
iAnimOwner=iInstance; //zapamiêtanie czyja jest animacja
|
|
}
|
|
|
|
void __fastcall TSubModel::SetRotateIK1(float3 vNewAngles)
|
|
{//obrócenie submodelu o podane k¹ty wokó³ osi lokalnego uk³adu
|
|
v_Angles=vNewAngles;
|
|
iAnimOwner=iInstance; //zapamiêtanie czyja jest animacja
|
|
}
|
|
|
|
struct ToLower
|
|
{
|
|
char operator()(char input) { return tolower(input); }
|
|
};
|
|
|
|
TSubModel* __fastcall TSubModel::GetFromName(AnsiString search,bool i)
|
|
{
|
|
return GetFromName(search.c_str(),i);
|
|
};
|
|
|
|
TSubModel* __fastcall TSubModel::GetFromName(char *search,bool i)
|
|
{
|
|
TSubModel* result;
|
|
//std::transform(search.begin(),search.end(),search.begin(),ToLower());
|
|
//search=search.LowerCase();
|
|
//AnsiString name=AnsiString();
|
|
if (pName&&search)
|
|
if ((i?stricmp(pName,search):strcmp(pName,search))==0)
|
|
return this;
|
|
else
|
|
if (pName==search)
|
|
return this; //oba NULL
|
|
if (Next)
|
|
{
|
|
result=Next->GetFromName(search);
|
|
if (result) return result;
|
|
}
|
|
if (Child)
|
|
{
|
|
result=Child->GetFromName(search);
|
|
if (result) return result;
|
|
}
|
|
return NULL;
|
|
};
|
|
|
|
//WORD hbIndices[18]={3,0,1,5,4,2,1,0,4,1,5,3,2,3,5,2,4,0};
|
|
|
|
void __fastcall TSubModel::RaAnimation(TAnimType a)
|
|
{//wykonanie animacji niezale¿nie od renderowania
|
|
switch (a)
|
|
{//korekcja po³o¿enia, jeœli submodel jest animowany
|
|
case at_Translate: //Ra: by³o "true"
|
|
if (iAnimOwner!=iInstance) break; //cudza animacja
|
|
glTranslatef(v_TransVector.x,v_TransVector.y,v_TransVector.z);
|
|
break;
|
|
case at_Rotate: //Ra: by³o "true"
|
|
if (iAnimOwner!=iInstance) break; //cudza animacja
|
|
glRotatef(f_Angle,v_RotateAxis.x,v_RotateAxis.y,v_RotateAxis.z);
|
|
break;
|
|
case at_RotateXYZ:
|
|
if (iAnimOwner!=iInstance) break; //cudza animacja
|
|
glTranslatef(v_TransVector.x,v_TransVector.y,v_TransVector.z);
|
|
glRotatef(v_Angles.x,1.0,0.0,0.0);
|
|
glRotatef(v_Angles.y,0.0,1.0,0.0);
|
|
glRotatef(v_Angles.z,0.0,0.0,1.0);
|
|
break;
|
|
case at_SecondsJump: //sekundy z przeskokiem
|
|
glRotatef(floor(GlobalTime->mr)*6.0,0.0,1.0,0.0);
|
|
break;
|
|
case at_MinutesJump: //minuty z przeskokiem
|
|
glRotatef(GlobalTime->mm*6.0,0.0,1.0,0.0);
|
|
break;
|
|
case at_HoursJump: //godziny skokowo 12h/360°
|
|
glRotatef(GlobalTime->hh*30.0*0.5,0.0,1.0,0.0);
|
|
break;
|
|
case at_Hours24Jump: //godziny skokowo 24h/360°
|
|
glRotatef(GlobalTime->hh*15.0*0.25,0.0,1.0,0.0);
|
|
break;
|
|
case at_Seconds: //sekundy p³ynnie
|
|
glRotatef(GlobalTime->mr*6.0,0.0,1.0,0.0);
|
|
break;
|
|
case at_Minutes: //minuty p³ynnie
|
|
glRotatef(GlobalTime->mm*6.0+GlobalTime->mr*0.1,0.0,1.0,0.0);
|
|
break;
|
|
case at_Hours: //godziny p³ynnie 12h/360°
|
|
//glRotatef(GlobalTime->hh*30.0+GlobalTime->mm*0.5+GlobalTime->mr/120.0,0.0,1.0,0.0);
|
|
glRotatef(2.0*Global::fTimeAngleDeg,0.0,1.0,0.0);
|
|
break;
|
|
case at_Hours24: //godziny p³ynnie 24h/360°
|
|
//glRotatef(GlobalTime->hh*15.0+GlobalTime->mm*0.25+GlobalTime->mr/240.0,0.0,1.0,0.0);
|
|
glRotatef(Global::fTimeAngleDeg,0.0,1.0,0.0);
|
|
break;
|
|
case at_Billboard: //obrót w pionie do kamery
|
|
{matrix4x4 mat; //potrzebujemy wspó³rzêdne przesuniêcia œrodka uk³adu wspó³rzêdnych submodelu
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,mat.getArray()); //pobranie aktualnej matrycy
|
|
float3 gdzie=float3(mat[3][0],mat[3][1],mat[3][2]); //pocz¹tek uk³adu wspó³rzêdnych submodelu wzglêdem kamery
|
|
glLoadIdentity(); //macierz jedynkowa
|
|
glTranslatef(gdzie.x,gdzie.y,gdzie.z); //pocz¹tek uk³adu zostaje bez zmian
|
|
glRotated(atan2(gdzie.x,gdzie.z)*180.0/M_PI,0.0,1.0,0.0); //jedynie obracamy w pionie o k¹t
|
|
}
|
|
break;
|
|
case at_Wind: //ruch pod wp³ywem wiatru (wiatr bêdziemy liczyæ potem...)
|
|
glRotated(1.5*sin(M_PI*GlobalTime->mr/6.0),0.0,1.0,0.0);
|
|
break;
|
|
case at_Sky: //animacja nieba
|
|
glRotated(Global::fLatitudeDeg,1.0,0.0,0.0); //ustawienie osi OY na pó³noc
|
|
//glRotatef(Global::fTimeAngleDeg,0.0,1.0,0.0); //obrót dobowy osi OX
|
|
glRotated(-fmod(Global::fTimeAngleDeg,360.0),0.0,1.0,0.0); //obrót dobowy osi OX
|
|
break;
|
|
case at_IK11: //ostatni element animacji szkieletowej (podudzie, stopa)
|
|
glRotatef(v_Angles.z,0.0,1.0,0.0); //obrót wzglêdem osi pionowej (azymut)
|
|
glRotatef(v_Angles.x,1.0,0.0,0.0); //obrót wzglêdem poziomu (deklinacja)
|
|
break;
|
|
case at_DigiClk: //animacja zegara cyfrowego
|
|
{//ustawienie animacji w submodelach potomnych
|
|
TSubModel *sm=ChildGet();
|
|
do
|
|
{//pêtla po submodelach potomnych i obracanie ich o k¹t zale¿y od czasu
|
|
if (sm->pName)
|
|
{//musi mieæ niepust¹ nazwê
|
|
if ((*sm->pName)>='0')
|
|
if ((*sm->pName)<='5') //zegarek ma 6 cyfr maksymalnie
|
|
sm->SetRotate(float3(0,1,0),-Global::fClockAngleDeg[(*sm->pName)-'0']);
|
|
}
|
|
sm=sm->NextGet();
|
|
} while (sm);
|
|
}
|
|
break;
|
|
}
|
|
if (mAnimMatrix) //mo¿na by to daæ np. do at_Translate
|
|
{glMultMatrixf(mAnimMatrix->readArray());
|
|
mAnimMatrix=NULL; //jak animator bêdzie potrzebowa³, to ustawi ponownie
|
|
}
|
|
};
|
|
|
|
void __fastcall TSubModel::RenderDL()
|
|
{//g³ówna procedura renderowania przez DL
|
|
if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDist<fSquareMaxDist))
|
|
{
|
|
if (iFlags&0xC000)
|
|
{glPushMatrix();
|
|
if (fMatrix)
|
|
glMultMatrixf(fMatrix->readArray());
|
|
if (b_Anim) RaAnimation(b_Anim);
|
|
}
|
|
if (eType<TP_ROTATOR)
|
|
{//renderowanie obiektów OpenGL
|
|
if (iAlpha&iFlags&0x1F) //rysuj gdy element nieprzezroczysty
|
|
{if (TextureID<0) // && (ReplacableSkinId!=0))
|
|
{//zmienialne skóry
|
|
glBindTexture(GL_TEXTURE_2D,ReplacableSkinId[-TextureID]);
|
|
//TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury
|
|
}
|
|
else
|
|
glBindTexture(GL_TEXTURE_2D,TextureID); //równie¿ 0
|
|
if (Global::fLuminance<fLight)
|
|
{glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo
|
|
glCallList(uiDisplayList); //tylko dla siatki
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
}
|
|
else
|
|
glCallList(uiDisplayList); //tylko dla siatki
|
|
}
|
|
}
|
|
else if (eType==TP_FREESPOTLIGHT)
|
|
{//wersja DL
|
|
matrix4x4 mat; //macierz opisuje uk³ad renderowania wzglêdem kamery
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,mat.getArray());
|
|
//k¹t miêdzy kierunkiem œwiat³a a wspó³rzêdnymi kamery
|
|
vector3 gdzie=mat*vector3(0,0,0); //pozycja punktu œwiec¹cego wzglêdem kamery
|
|
fCosViewAngle=DotProduct(Normalize(mat*vector3(0,0,1)-gdzie),Normalize(gdzie));
|
|
if (fCosViewAngle>fCosFalloffAngle) //k¹t wiêkszy ni¿ maksymalny sto¿ek swiat³a
|
|
{
|
|
double Distdimm=1.0;
|
|
if (fCosViewAngle<fCosHotspotAngle) //zmniejszona jasnoœæ miêdzy Hotspot a Falloff
|
|
if (fCosFalloffAngle<fCosHotspotAngle)
|
|
Distdimm=1.0-(fCosHotspotAngle-fCosViewAngle)/(fCosHotspotAngle-fCosFalloffAngle);
|
|
glColor3f(f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm);
|
|
/* TODO: poprawic to zeby dzialalo
|
|
if (iFarAttenDecay>0)
|
|
switch (iFarAttenDecay)
|
|
{
|
|
case 1:
|
|
Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); //dorobic od kata
|
|
break;
|
|
case 2:
|
|
Distdimm=fFarDecayRadius/(1+fSquareDist); //dorobic od kata
|
|
break;
|
|
}
|
|
if (Distdimm>1)
|
|
Distdimm=1;
|
|
glColor3f(Diffuse[0]*Distdimm,Diffuse[1]*Distdimm,Diffuse[2]*Distdimm);
|
|
*/
|
|
// glPopMatrix();
|
|
// return;
|
|
glCallList(uiDisplayList); //wyœwietlenie warunkowe
|
|
}
|
|
}
|
|
else if (eType==TP_STARS)
|
|
{
|
|
//glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly
|
|
if (Global::fLuminance<fLight)
|
|
{glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo
|
|
glCallList(uiDisplayList); //narysuj naraz wszystkie punkty z DL
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
}
|
|
}
|
|
if (Child!=NULL)
|
|
if (iAlpha&iFlags&0x001F0000)
|
|
Child->RenderDL();
|
|
if (iFlags&0xC000)
|
|
glPopMatrix();
|
|
}
|
|
if (b_Anim<at_SecondsJump)
|
|
b_Anim=at_None; //wy³¹czenie animacji dla kolejnego u¿ycia subm
|
|
if (Next)
|
|
if (iAlpha&iFlags&0x1F000000)
|
|
Next->RenderDL(); //dalsze rekurencyjnie
|
|
}; //Render
|
|
|
|
void __fastcall TSubModel::RenderAlphaDL()
|
|
{//renderowanie przezroczystych przez DL
|
|
if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDist<fSquareMaxDist))
|
|
{
|
|
if (iFlags&0xC000)
|
|
{glPushMatrix();
|
|
if (fMatrix)
|
|
glMultMatrixf(fMatrix->readArray());
|
|
if (b_aAnim) RaAnimation(b_aAnim);
|
|
}
|
|
if (eType<TP_ROTATOR)
|
|
{//renderowanie obiektów OpenGL
|
|
if (iAlpha&iFlags&0x2F) //rysuj gdy element przezroczysty
|
|
{if (TextureID<0) // && (ReplacableSkinId!=0))
|
|
{//zmienialne skóry
|
|
glBindTexture(GL_TEXTURE_2D,ReplacableSkinId[-TextureID]);
|
|
//TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury
|
|
}
|
|
else
|
|
glBindTexture(GL_TEXTURE_2D,TextureID); //równie¿ 0
|
|
if (Global::fLuminance<fLight)
|
|
{glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo
|
|
glCallList(uiDisplayList); //tylko dla siatki
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
}
|
|
else
|
|
glCallList(uiDisplayList); //tylko dla siatki
|
|
}
|
|
}
|
|
else if (eType==TP_FREESPOTLIGHT)
|
|
{
|
|
// dorobiæ aureolê!
|
|
}
|
|
if (Child!=NULL)
|
|
if (eType==TP_TEXT)
|
|
{//tekst renderujemy w specjalny sposób, zamiast submodeli z ³añcucha Child
|
|
int i,j=pasText->Length();
|
|
TSubModel *p;
|
|
char c;
|
|
if (!smLetter)
|
|
{//jeœli nie ma tablicy, to j¹ stworzyæ; miejsce nieodpowiednie, ale tymczasowo mo¿e byæ
|
|
smLetter=new TSubModel*[256]; //tablica wskaŸników submodeli dla wyœwietlania tekstu
|
|
ZeroMemory(smLetter,256*sizeof(TSubModel*)); //wype³nianie zerami
|
|
p=Child;
|
|
while (p)
|
|
{
|
|
smLetter[*p->pName]=p;
|
|
p=p->Next; //kolejny znak
|
|
}
|
|
}
|
|
for (i=1;i<=j;++i)
|
|
{
|
|
p=smLetter[(*pasText)[i]]; //znak do wyœwietlenia
|
|
if (p)
|
|
{//na razie tylko jako przezroczyste
|
|
p->RenderAlphaDL();
|
|
if (p->fMatrix) glMultMatrixf(p->fMatrix->readArray()); //przesuwanie widoku
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (iAlpha&iFlags&0x002F0000)
|
|
Child->RenderAlphaDL();
|
|
if (iFlags&0xC000)
|
|
glPopMatrix();
|
|
}
|
|
if (b_aAnim<at_SecondsJump)
|
|
b_aAnim=at_None; //wy³¹czenie animacji dla kolejnego u¿ycia submodelu
|
|
if (Next!=NULL)
|
|
if (iAlpha&iFlags&0x2F000000)
|
|
Next->RenderAlphaDL();
|
|
}; //RenderAlpha
|
|
|
|
void __fastcall TSubModel::RenderVBO()
|
|
{//g³ówna procedura renderowania przez VBO
|
|
if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDist<fSquareMaxDist))
|
|
{
|
|
if (iFlags&0xC000)
|
|
{glPushMatrix();
|
|
if (fMatrix)
|
|
glMultMatrixf(fMatrix->readArray());
|
|
if (b_Anim) RaAnimation(b_Anim);
|
|
}
|
|
if (eType<TP_ROTATOR)
|
|
{//renderowanie obiektów OpenGL
|
|
if (iAlpha&iFlags&0x1F) //rysuj gdy element nieprzezroczysty
|
|
{if (TextureID<0) // && (ReplacableSkinId!=0))
|
|
{//zmienialne skóry
|
|
glBindTexture(GL_TEXTURE_2D,ReplacableSkinId[-TextureID]);
|
|
//TexAlpha=!(iAlpha&1); //zmiana tylko w przypadku wymienej tekstury
|
|
}
|
|
else
|
|
glBindTexture(GL_TEXTURE_2D,TextureID); //równie¿ 0
|
|
glColor3fv(f4Diffuse); //McZapkie-240702: zamiast ub
|
|
//glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,f4Diffuse); //to samo, co glColor
|
|
if (Global::fLuminance<fLight)
|
|
{glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo
|
|
glDrawArrays(eType,iVboPtr,iNumVerts); //narysuj naraz wszystkie trójk¹ty z VBO
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
}
|
|
else
|
|
glDrawArrays(eType,iVboPtr,iNumVerts); //narysuj naraz wszystkie trójk¹ty z VBO
|
|
}
|
|
}
|
|
else if (eType==TP_FREESPOTLIGHT)
|
|
{//wersja VBO
|
|
matrix4x4 mat; //macierz opisuje uk³ad renderowania wzglêdem kamery
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,mat.getArray());
|
|
//k¹t miêdzy kierunkiem œwiat³a a wspó³rzêdnymi kamery
|
|
vector3 gdzie=mat*vector3(0,0,0); //pozycja punktu œwiec¹cego wzglêdem kamery
|
|
fCosViewAngle=DotProduct(Normalize(mat*vector3(0,0,1)-gdzie),Normalize(gdzie));
|
|
if (fCosViewAngle>fCosFalloffAngle) //k¹t wiêkszy ni¿ maksymalny sto¿ek swiat³a
|
|
{
|
|
double Distdimm=1.0;
|
|
if (fCosViewAngle<fCosHotspotAngle) //zmniejszona jasnoœæ miêdzy Hotspot a Falloff
|
|
if (fCosFalloffAngle<fCosHotspotAngle)
|
|
Distdimm=1.0-(fCosHotspotAngle-fCosViewAngle)/(fCosHotspotAngle-fCosFalloffAngle);
|
|
|
|
/* TODO: poprawic to zeby dzialalo
|
|
|
|
2- Inverse (Applies inverse decay. The formula is luminance=R0/R, where R0 is
|
|
the radial source of the light if no attenuation is used, or the Near End
|
|
value of the light if Attenuation is used. R is the radial distance of the
|
|
illuminated surface from R0.)
|
|
|
|
3- Inverse Square (Applies inverse-square decay. The formula for this is (R0/R)^2.
|
|
This is actually the "real-world" decay of light, but you might find it too dim
|
|
in the world of computer graphics.)
|
|
|
|
<light>.DecayRadius -- The distance over which the decay occurs.
|
|
|
|
if (iFarAttenDecay>0)
|
|
switch (iFarAttenDecay)
|
|
{
|
|
case 1:
|
|
Distdimm=fFarDecayRadius/(1+sqrt(fSquareDist)); //dorobic od kata
|
|
break;
|
|
case 2:
|
|
Distdimm=fFarDecayRadius/(1+fSquareDist); //dorobic od kata
|
|
break;
|
|
}
|
|
if (Distdimm>1)
|
|
Distdimm=1;
|
|
|
|
*/
|
|
glBindTexture(GL_TEXTURE_2D,0); //nie teksturowaæ
|
|
//glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]);
|
|
//glColorMaterial(GL_FRONT,GL_EMISSION);
|
|
float color[4]={f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm,0};
|
|
//glColor3f(f4Diffuse[0]*Distdimm,f4Diffuse[1]*Distdimm,f4Diffuse[2]*Distdimm);
|
|
glColorMaterial(GL_FRONT,GL_EMISSION);
|
|
glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly
|
|
glColor3fv(color); //inaczej s¹ bia³e
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,color);
|
|
glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj wierzcho³ek z VBO
|
|
glEnable(GL_LIGHTING);
|
|
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE); //co ma ustawiaæ glColor
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2); //bez tego s³upy siê œwiec¹
|
|
}
|
|
}
|
|
else if (eType==TP_STARS)
|
|
{
|
|
//glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly
|
|
if (Global::fLuminance<fLight)
|
|
{//Ra: pewnie mo¿na by to zrobiæ lepiej, bez powtarzania StartVBO()
|
|
pRoot->EndVBO(); //Ra: to te¿ nie jest zbyt ³adne
|
|
if (pRoot->StartColorVBO())
|
|
{//wyœwietlanie kolorowych punktów zamiast trójk¹tów
|
|
glBindTexture(GL_TEXTURE_2D,0); //tekstury nie ma
|
|
glColorMaterial(GL_FRONT,GL_EMISSION);
|
|
glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly
|
|
//glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo
|
|
glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj naraz wszystkie punkty z VBO
|
|
glEnable(GL_LIGHTING);
|
|
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
|
|
//glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
pRoot->EndVBO();
|
|
pRoot->StartVBO();
|
|
}
|
|
}
|
|
}
|
|
/*Ra: tu coœ jest bez sensu...
|
|
else
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
// if (eType==smt_FreeSpotLight)
|
|
// {
|
|
// if (iFarAttenDecay==0)
|
|
// glColor3f(Diffuse[0],Diffuse[1],Diffuse[2]);
|
|
// }
|
|
// else
|
|
//TODO: poprawic zeby dzialalo
|
|
glColor3f(f4Diffuse[0],f4Diffuse[1],f4Diffuse[2]);
|
|
glColorMaterial(GL_FRONT,GL_EMISSION);
|
|
glDisable(GL_LIGHTING); //Tolaris-030603: bo mu punkty swiecace sie blendowaly
|
|
//glBegin(GL_POINTS);
|
|
glDrawArrays(GL_POINTS,iVboPtr,iNumVerts); //narysuj wierzcho³ek z VBO
|
|
// glVertex3f(0,0,0);
|
|
//glEnd();
|
|
glEnable(GL_LIGHTING);
|
|
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
//glEndList();
|
|
}
|
|
*/
|
|
if (Child!=NULL)
|
|
if (iAlpha&iFlags&0x001F0000)
|
|
Child->RenderVBO();
|
|
if (iFlags&0xC000)
|
|
glPopMatrix();
|
|
}
|
|
if (b_Anim<at_SecondsJump)
|
|
b_Anim=at_None; //wy³¹czenie animacji dla kolejnego u¿ycia submodelu
|
|
if (Next)
|
|
if (iAlpha&iFlags&0x1F000000)
|
|
Next->RenderVBO(); //dalsze rekurencyjnie
|
|
}; //RaRender
|
|
|
|
void __fastcall TSubModel::RenderAlphaVBO()
|
|
{//renderowanie przezroczystych przez VBO
|
|
if (iVisible && (fSquareDist>=fSquareMinDist) && (fSquareDist<fSquareMaxDist))
|
|
{
|
|
if (iFlags&0xC000)
|
|
{glPushMatrix(); //zapamiêtanie matrycy
|
|
if (fMatrix)
|
|
glMultMatrixf(fMatrix->readArray());
|
|
if (b_aAnim) RaAnimation(b_aAnim);
|
|
}
|
|
glColor3fv(f4Diffuse);
|
|
if (eType<TP_ROTATOR)
|
|
{//renderowanie obiektów OpenGL
|
|
if (iAlpha&iFlags&0x2F) //rysuj gdy element przezroczysty
|
|
{
|
|
if (TextureID<0) // && (ReplacableSkinId!=0))
|
|
{//zmienialne skory
|
|
glBindTexture(GL_TEXTURE_2D,ReplacableSkinId[-TextureID]);
|
|
//TexAlpha=iAlpha&1; //zmiana tylko w przypadku wymienej tekstury
|
|
}
|
|
else
|
|
glBindTexture(GL_TEXTURE_2D,TextureID); //równie¿ 0
|
|
if (Global::fLuminance<fLight)
|
|
{glMaterialfv(GL_FRONT,GL_EMISSION,f4Diffuse); //zeby swiecilo na kolorowo
|
|
glDrawArrays(eType,iVboPtr,iNumVerts); //narysuj naraz wszystkie trójk¹ty z VBO
|
|
glMaterialfv(GL_FRONT,GL_EMISSION,emm2);
|
|
}
|
|
else
|
|
glDrawArrays(eType,iVboPtr,iNumVerts); //narysuj naraz wszystkie trójk¹ty z VBO
|
|
}
|
|
}
|
|
else if (eType==TP_FREESPOTLIGHT)
|
|
{
|
|
// dorobiæ aureolê!
|
|
}
|
|
if (Child)
|
|
if (iAlpha&iFlags&0x002F0000)
|
|
Child->RenderAlphaVBO();
|
|
if (iFlags&0xC000)
|
|
glPopMatrix();
|
|
}
|
|
if (b_aAnim<at_SecondsJump)
|
|
b_aAnim=at_None; //wy³¹czenie animacji dla kolejnego u¿ycia submodelu
|
|
if (Next)
|
|
if (iAlpha&iFlags&0x2F000000)
|
|
Next->RenderAlphaVBO();
|
|
}; //RaRenderAlpha
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
void __fastcall TSubModel::RaArrayFill(CVertNormTex *Vert)
|
|
{//wype³nianie tablic VBO
|
|
if (Child) Child->RaArrayFill(Vert);
|
|
if ((eType<TP_ROTATOR)||(eType==TP_STARS))
|
|
for (int i=0;i<iNumVerts;++i)
|
|
{Vert[iVboPtr+i].x =Vertices[i].Point.x;
|
|
Vert[iVboPtr+i].y =Vertices[i].Point.y;
|
|
Vert[iVboPtr+i].z =Vertices[i].Point.z;
|
|
Vert[iVboPtr+i].nx=Vertices[i].Normal.x;
|
|
Vert[iVboPtr+i].ny=Vertices[i].Normal.y;
|
|
Vert[iVboPtr+i].nz=Vertices[i].Normal.z;
|
|
Vert[iVboPtr+i].u =Vertices[i].tu;
|
|
Vert[iVboPtr+i].v =Vertices[i].tv;
|
|
}
|
|
else if (eType==TP_FREESPOTLIGHT)
|
|
Vert[iVboPtr].x=Vert[iVboPtr].y=Vert[iVboPtr].z=0.0;
|
|
if (Next) Next->RaArrayFill(Vert);
|
|
};
|
|
|
|
void __fastcall 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)
|
|
AnsiString t=AnsiString(pTexture);
|
|
if (t.SubString(t.Length()-3,4)==".tga")
|
|
t.Delete(t.Length()-3,4);
|
|
else if (t.SubString(t.Length()-3,4)==".dds")
|
|
t.Delete(t.Length()-3,4);
|
|
if (t!=AnsiString(pTexture))
|
|
{//jeœli siê zmieni³o
|
|
//pName=new char[token.length()+1]; //nie ma sensu skracaæ tabeli
|
|
strcpy(pTexture,t.c_str());
|
|
}
|
|
info->iTextureLen=t.Length()+1; //przygotowanie do zapisania, z zerem na koñcu
|
|
}
|
|
}
|
|
else info->iTexture=TextureID; //nie ma albo wymienna
|
|
//if (asName.Length())
|
|
if (pName)
|
|
{info->iName=info->iTotalNames++; //przydzielenie numeru nazwy w pliku (od 0)
|
|
info->iNameLen=strlen(pName)+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 __fastcall 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
|
|
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
|
|
Next=(TSubModel*)info->iNext; //numer nastêpnego
|
|
Child=(TSubModel*)info->iChild; //numer potomnego
|
|
iFlags&=~0x200; //nie jest wczytany z tekstowego
|
|
//asTexture=asName="";
|
|
pTexture=pName=NULL;
|
|
};
|
|
|
|
void __fastcall TSubModel::BinInit(TSubModel *s,float4x4 *m,float8 *v,TStringPack *t,TStringPack *n,bool dynamic)
|
|
{//ustawienie wskaŸników w submodelu
|
|
iVisible=1; //tymczasowo u¿ywane
|
|
Child=((int)Child>0)?s+(int)Child:NULL; //zerowy nie mo¿e byæ potomnym
|
|
Next=((int)Next>0)?s+(int)Next:NULL; //zerowy nie mo¿e byæ nastêpnym
|
|
fMatrix=((iMatrix>=0)&&m)?m+iMatrix:NULL;
|
|
//if (n&&(iName>=0)) asName=AnsiString(n->String(iName)); else asName="";
|
|
if (n&&(iName>=0))
|
|
{pName=n->String(iName);
|
|
AnsiString s=AnsiString(pName);
|
|
if (!s.IsEmpty())
|
|
{//jeœli dany submodel jest zgaszonym œwiat³em, to domyœlnie go ukrywamy
|
|
if (s.SubString(1,8)=="Light_On") //jeœli jest œwiat³em numerowanym
|
|
iVisible=0; //to domyœlnie wy³¹czyæ, ¿eby siê nie nak³ada³o z obiektem "Light_Off"
|
|
else if (dynamic) //inaczej wy³¹cza³o smugê w latarniach
|
|
if (s.SubString(s.Length()-2,3)=="_on") //jeœli jest kontrolk¹ w stanie zapalonym
|
|
iVisible=0; //to domyœlnie wy³¹czyæ, ¿eby siê nie nak³ada³o z obiektem "_off"
|
|
}
|
|
}
|
|
else
|
|
pName=NULL;
|
|
if (iTexture>0)
|
|
{//obs³uga sta³ej tekstury
|
|
//TextureID=TTexturesManager::GetTextureID(t->String(TextureID));
|
|
//asTexture=AnsiString(t->String(iTexture));
|
|
pTexture=t->String(iTexture);
|
|
AnsiString t=AnsiString(pTexture);
|
|
if (t.LastDelimiter("/\\")==0)
|
|
t.Insert(Global::asCurrentTexturePath,1);
|
|
TextureID=TTexturesManager::GetTextureID(szTexturePath,Global::asCurrentTexturePath.c_str(),t.c_str());
|
|
//TexAlpha=TTexturesManager::GetAlpha(TextureID); //zmienna robocza
|
|
//ustawienie cyklu przezroczyste/nieprzezroczyste zale¿nie od w³asnoœci sta³ej tekstury
|
|
//iFlags=(iFlags&~0x30)|(TTexturesManager::GetAlpha(TextureID)?0x20:0x10); //0x10-nieprzezroczysta, 0x20-przezroczysta
|
|
if (Opacity<1.0) //przezroczystoϾ z tekstury brana tylko dla Opacity 0!
|
|
iFlags|=TTexturesManager::GetAlpha(TextureID)?0x20:0x10; //0x10-nieprzezroczysta, 0x20-przezroczysta
|
|
else
|
|
iFlags|=0x10; //normalnie nieprzezroczyste
|
|
}
|
|
b_aAnim=b_Anim; //skopiowanie animacji do drugiego cyklu
|
|
iFlags&=~0x0200; //wczytano z pliku binarnego (nie jest w³aœcicielem tablic)
|
|
Vertices=v+iVboPtr;
|
|
//if (!iNumVerts) eType=-1; //tymczasowo zmiana typu, ¿eby siê nie renderowa³o na si³ê
|
|
};
|
|
void __fastcall TSubModel::AdjustDist()
|
|
{//aktualizacja odleg³oœci faz LoD, zale¿na od rozdzielczoœci pionowej oraz multisamplingu
|
|
if (fSquareMaxDist>0.0) fSquareMaxDist*=Global::fDistanceFactor;
|
|
if (fSquareMinDist>0.0) fSquareMinDist*=Global::fDistanceFactor;
|
|
//if (fNearAttenStart>0.0) fNearAttenStart*=Global::fDistanceFactor;
|
|
//if (fNearAttenEnd>0.0) fNearAttenEnd*=Global::fDistanceFactor;
|
|
if (Child) Child->AdjustDist();
|
|
if (Next) Next->AdjustDist();
|
|
};
|
|
|
|
void __fastcall TSubModel::ColorsSet(int *a,int *d,int*s)
|
|
{//ustawienie kolorów dla modelu terenu
|
|
int i;
|
|
if (a) for (i=0;i<4;++i) f4Ambient[i]=a[i]/255.0;
|
|
if (d) for (i=0;i<4;++i) f4Diffuse[i]=d[i]/255.0;
|
|
if (s) for (i=0;i<4;++i) f4Specular[i]=s[i]/255.0;
|
|
};
|
|
void __fastcall TSubModel::ParentMatrix(float4x4 *m)
|
|
{//pobranie transformacji wzglêdem wstawienia modelu
|
|
//jeœli nie zosta³o wykonane Init() (tzn. zaraz po wczytaniu T3D), to dodatkowy obrót
|
|
//obrót T3D jest wymagany np. do policzenia wysokoœci pantografów
|
|
*m=float4x4(*fMatrix); //skopiowanie, bo bêdziemy mno¿yæ
|
|
//m(3)[1]=m[3][1]+0.054; //w górê o wysokoœæ œlizgu (na razie tak)
|
|
TSubModel *sm=this;
|
|
while (sm->Parent)
|
|
{//przenieœæ tê funkcjê do modelu
|
|
if (sm->Parent->GetMatrix())
|
|
*m=*sm->Parent->GetMatrix()**m;
|
|
sm=sm->Parent;
|
|
}
|
|
//dla ostatniego mo¿e byæ potrzebny dodatkowy obrót, jeœli wczytano z T3D, a nie obrócono jeszcze
|
|
};
|
|
float __fastcall TSubModel::MaxY(const float4x4 &m)
|
|
{//obliczenie maksymalnej wysokoœci, na pocz¹tek œlizgu w pantografie
|
|
if (eType!=4) return 0; //tylko dla trójk¹tów liczymy
|
|
if (iNumVerts<1) return 0;
|
|
if (!Vertices) return 0;
|
|
float y,my=m[0][1]*Vertices[0].Point.x+m[1][1]*Vertices[0].Point.y+m[2][1]*Vertices[0].Point.z+m[3][1];
|
|
for (int i=1;i<iNumVerts;++i)
|
|
{
|
|
y=m[0][1]*Vertices[i].Point.x+m[1][1]*Vertices[i].Point.y+m[2][1]*Vertices[i].Point.z+m[3][1];
|
|
if (my<y) my=y;
|
|
}
|
|
return my;
|
|
};
|
|
//---------------------------------------------------------------------------
|
|
|
|
__fastcall TModel3d::TModel3d()
|
|
{
|
|
//Materials=NULL;
|
|
//MaterialsCount=0;
|
|
Root=NULL;
|
|
iFlags=0;
|
|
iSubModelsCount=0;
|
|
iModel=NULL; //tylko jak wczytany model binarny
|
|
iNumVerts=0; //nie ma jeszcze wierzcho³ków
|
|
};
|
|
/*
|
|
__fastcall TModel3d::TModel3d(char *FileName)
|
|
{
|
|
// Root=NULL;
|
|
// Materials=NULL;
|
|
// MaterialsCount=0;
|
|
Root=NULL;
|
|
SubModelsCount=0;
|
|
iFlags=0;
|
|
LoadFromFile(FileName);
|
|
};
|
|
*/
|
|
__fastcall TModel3d::~TModel3d()
|
|
{
|
|
//SafeDeleteArray(Materials);
|
|
if (iFlags&0x0200)
|
|
{//wczytany z pliku tekstowego, submodele sprz¹taj¹ same
|
|
SafeDelete(Root); //submodele siê usun¹ rekurencyjnie
|
|
}
|
|
else
|
|
{//wczytano z pliku binarnego (jest w³aœcicielem tablic)
|
|
m_pVNT=NULL; //nie usuwaæ tego, bo wskazuje na iModel
|
|
Root=NULL;
|
|
delete[] iModel; //usuwamy ca³y wczytany plik i to wystarczy
|
|
}
|
|
//póŸniej siê jeszcze usuwa obiekt z którego dziedziczymy tabelê VBO
|
|
};
|
|
|
|
TSubModel* __fastcall TModel3d::AddToNamed(const char *Name,TSubModel *SubModel)
|
|
{
|
|
TSubModel *sm=Name?GetFromName(Name):NULL;
|
|
AddTo(sm,SubModel); //szukanie nadrzêdnego
|
|
return sm; //zwracamy wskaŸnik do nadrzêdnego submodelu
|
|
};
|
|
|
|
void __fastcall TModel3d::AddTo(TSubModel *tmp,TSubModel *SubModel)
|
|
{//jedyny poprawny sposób dodawania submodeli, inaczej mog¹ zgin¹æ przy zapisie E3D
|
|
if (tmp)
|
|
{//jeœli znaleziony, pod³¹czamy mu jako potomny
|
|
tmp->ChildAdd(SubModel);
|
|
}
|
|
else
|
|
{//jeœli nie znaleziony, podczepiamy do ³añcucha g³ównego
|
|
SubModel->NextAdd(Root); //Ra: zmiana kolejnoœci renderowania wymusza zmianê tu
|
|
Root=SubModel;
|
|
}
|
|
++iSubModelsCount; //teraz jest o 1 submodel wiêcej
|
|
iFlags|=0x0200; //submodele s¹ oddzielne
|
|
};
|
|
|
|
TSubModel* __fastcall TModel3d::GetFromName(const char *sName)
|
|
{//wyszukanie submodelu po nazwie
|
|
if (!sName) return Root; //potrzebne do terenu z E3D
|
|
if (iFlags&0x0200) //wczytany z pliku tekstowego, wyszukiwanie rekurencyjne
|
|
return Root?Root->GetFromName(sName):NULL;
|
|
else //wczytano z pliku binarnego, mo¿na wyszukaæ iteracyjnie
|
|
{
|
|
//for (int i=0;i<iSubModelsCount;++i)
|
|
return Root?Root->GetFromName(sName):NULL;
|
|
}
|
|
};
|
|
|
|
/*
|
|
TMaterial* __fastcall TModel3d::GetMaterialFromName(char *sName)
|
|
{
|
|
AnsiString tmp=AnsiString(sName).Trim();
|
|
for (int i=0; i<MaterialsCount; i++)
|
|
if (strcmp(sName,Materials[i].Name.c_str())==0)
|
|
// if (Trim()==Materials[i].Name.tmp)
|
|
return Materials+i;
|
|
return Materials;
|
|
}
|
|
*/
|
|
|
|
bool __fastcall TModel3d::LoadFromFile(char *FileName,bool dynamic)
|
|
{//wczytanie modelu z pliku
|
|
AnsiString name=AnsiString(FileName).LowerCase();
|
|
int i=name.LastDelimiter(".");
|
|
if (i)
|
|
if (name.SubString(i,name.Length()-i+1)==".t3d")
|
|
name.Delete(i,4);
|
|
asBinary=name+".e3d";
|
|
if (FileExists(asBinary))
|
|
{LoadFromBinFile(asBinary.c_str(),dynamic);
|
|
asBinary=""; //wy³¹czenie zapisu
|
|
Init();
|
|
}
|
|
else
|
|
{if (FileExists(name+".t3d"))
|
|
{LoadFromTextFile(FileName,dynamic); //wczytanie tekstowego
|
|
if (!dynamic) //pojazdy dopiero po ustawieniu animacji
|
|
Init(); //generowanie siatek i zapis E3D
|
|
}
|
|
}
|
|
return Root?(iSubModelsCount>0):false; //brak pliku albo problem z wczytaniem
|
|
};
|
|
|
|
void __fastcall TModel3d::LoadFromBinFile(char *FileName,bool dynamic)
|
|
{//wczytanie modelu z pliku binarnego
|
|
WriteLog("Loading - binary model: "+AnsiString(FileName));
|
|
int i=0,j,k,ch,size;
|
|
TFileStream *fs=new TFileStream(AnsiString(FileName),fmOpenRead);
|
|
size=fs->Size>>2;
|
|
iModel=new int[size]; //ten wskaŸnik musi byæ w modelu, aby zwolniæ pamiêæ
|
|
fs->Read(iModel,fs->Size); //wczytanie pliku
|
|
delete fs;
|
|
float4x4 *m=NULL; //transformy
|
|
//zestaw kromek:
|
|
while ((i<<2)<size) //w pliku mo¿e byæ kilka modeli
|
|
{ch=iModel[i]; //nazwa kromki
|
|
j=i+(iModel[i+1]>>2); //pocz¹tek nastêpnej kromki
|
|
if (ch=='E3D0') //g³ówna: 'E3D0',len,pod-kromki
|
|
{//tylko tê kromkê znamy, mo¿e kiedyœ jeszcze DOF siê zrobi
|
|
i+=2;
|
|
while (i<j)
|
|
{//przetwarzanie kromek wewnêtrznych
|
|
ch=iModel[i]; //nazwa kromki
|
|
k=(iModel[i+1]>>2); //d³ugoœæ aktualnej kromki
|
|
switch (ch)
|
|
{case 'MDL0': //zmienne modelu: 'E3D0',len,(informacje o modelu)
|
|
break;
|
|
case 'VNT0': //wierzcho³ki: 'VNT0',len,(32 bajty na wierzcho³ek)
|
|
iNumVerts=(k-2)>>3;
|
|
m_nVertexCount=iNumVerts;
|
|
m_pVNT=(CVertNormTex*)(iModel+i+2);
|
|
break;
|
|
case 'SUB0': //submodele: 'SUB0',len,(256 bajtów na submodel)
|
|
iSubModelsCount=(k-2)/64;
|
|
Root=(TSubModel*)(iModel+i+2); //numery na wskaŸniki przetworzymy póŸniej
|
|
break;
|
|
case 'SUB1': //submodele: 'SUB1',len,(320 bajtów na submodel)
|
|
iSubModelsCount=(k-2)/80;
|
|
Root=(TSubModel*)(iModel+i+2); //numery na wskaŸniki przetworzymy póŸniej
|
|
for (ch=1;ch<iSubModelsCount;++ch) //trzeba przesun¹æ bli¿ej, bo 256 wystarczy
|
|
MoveMemory(((char*)Root)+256*ch,((char*)Root)+320*ch,256);
|
|
break;
|
|
case 'TRA0': //transformy: 'TRA0',len,(64 bajty na transform)
|
|
m=(float4x4*)(iModel+i+2); //tabela transformów
|
|
break;
|
|
case 'TRA1': //transformy: 'TRA1',len,(128 bajtów na transform)
|
|
m=(float4x4*)(iModel+i+2); //tabela transformów
|
|
for (ch=0;ch<((k-2)>>1);++ch)
|
|
*(((float*)m)+ch)=*(((double*)m)+ch); //przepisanie double do float
|
|
break;
|
|
case 'IDX1': //indeksy 1B: 'IDX2',len,(po bajcie na numer wierzcho³ka)
|
|
break;
|
|
case 'IDX2': //indeksy 2B: 'IDX2',len,(po 2 bajty na numer wierzcho³ka)
|
|
break;
|
|
case 'IDX4': //indeksy 4B: 'IDX4',len,(po 4 bajty na numer wierzcho³ka)
|
|
break;
|
|
case 'TEX0': //tekstury: 'TEX0',len,(³añcuchy zakoñczone zerem - pliki tekstur)
|
|
Textures.Init((char*)(iModel+i)); //³¹cznie z nag³ówkiem
|
|
break;
|
|
case 'TIX0': //indeks nazw tekstur
|
|
Textures.InitIndex((int*)(iModel+i)); //³¹cznie z nag³ówkiem
|
|
break;
|
|
case 'NAM0': //nazwy: 'NAM0',len,(³añcuchy zakoñczone zerem - nazwy submodeli)
|
|
Names.Init((char*)(iModel+i)); //³¹cznie z nag³ówkiem
|
|
break;
|
|
case 'NIX0': //indeks nazw submodeli
|
|
Names.InitIndex((int*)(iModel+i)); //³¹cznie z nag³ówkiem
|
|
break;
|
|
}
|
|
i+=k; //przejœcie do kolejnej kromki
|
|
}
|
|
}
|
|
i=j;
|
|
}
|
|
for (i=0;i<iSubModelsCount;++i)
|
|
{//aktualizacja wskaŸników w submodelach
|
|
Root[i].BinInit(Root,m,(float8*)m_pVNT,&Textures,&Names,dynamic);
|
|
if (Root[i].ChildGet())
|
|
Root[i].ChildGet()->Parent=Root+i; //wpisanie wskaŸnika nadrzêdnego do potmnego
|
|
if (Root[i].NextGet())
|
|
Root[i].NextGet()->Parent=Root[i].Parent; //skopiowanie wskaŸnika nadrzêdnego do kolejnego
|
|
}
|
|
iFlags&=~0x0200;
|
|
return;
|
|
};
|
|
|
|
void __fastcall TModel3d::LoadFromTextFile(char *FileName,bool dynamic)
|
|
{//wczytanie submodelu z pliku tekstowego
|
|
WriteLog("Loading - text model: "+AnsiString(FileName));
|
|
iFlags|=0x0200; //wczytano z pliku tekstowego (w³aœcicielami tablic s¹ submodle)
|
|
cParser parser(FileName,cParser::buffer_FILE); //Ra: tu powinno byæ "models\\"...
|
|
TSubModel *SubModel;
|
|
std::string token;
|
|
parser.getToken(token);
|
|
iNumVerts=0; //w konstruktorze to jest
|
|
while (token!="" || parser.eof())
|
|
{
|
|
std::string parent;
|
|
//parser.getToken(parent);
|
|
parser.getTokens(1,false); //nazwa submodelu nadrzêdnego bez zmieny na ma³e
|
|
parser >> parent;
|
|
if (parent=="") break;
|
|
SubModel=new TSubModel();
|
|
iNumVerts+=SubModel->Load(parser,this,iNumVerts,dynamic);
|
|
SubModel->Parent=AddToNamed(parent.c_str(),SubModel); //bêdzie potrzebne do wyliczenia pozycji, np. pantografu
|
|
//iSubModelsCount++;
|
|
parser.getToken(token);
|
|
}
|
|
//Ra: od wersji 334 przechylany jest ca³y model, a nie tylko pierwszy submodel
|
|
//ale bujanie kabiny nadal u¿ywa bananów :( od 393 przywrócone, ale z dodatkowym warunkiem
|
|
if (Global::iConvertModels&4)
|
|
{//automatyczne banany czasem psu³y przechylanie kabin...
|
|
if (dynamic&&Root)
|
|
{if (Root->NextGet()) //jeœli ma jakiekolwiek kolejne
|
|
{//dynamic musi mieæ "banana", bo tylko pierwszy obiekt jest animowany, a nastêpne nie
|
|
SubModel=new TSubModel(); //utworzenie pustego
|
|
SubModel->ChildAdd(Root);
|
|
Root=SubModel;
|
|
++iSubModelsCount;
|
|
}
|
|
Root->WillBeAnimated(); //bo z tym jest du¿o problemów
|
|
}
|
|
}
|
|
}
|
|
|
|
void __fastcall TModel3d::Init()
|
|
{//obrócenie pocz¹tkowe uk³adu wspó³rzêdnych, dla pojazdów wykonywane po analizie animacji
|
|
if (iFlags&0x8000) return; //operacje zosta³y ju¿ wykonane
|
|
if (Root)
|
|
{if (iFlags&0x0200) //jeœli wczytano z pliku tekstowego
|
|
{//jest jakiœ dziwny b³¹d, ¿e obkrêcany ma byæ tylko ostatni submodel g³ównego ³añcucha
|
|
//TSubModel *p=Root;
|
|
//do
|
|
//{p->InitialRotate(true); //ostatniemu nale¿y siê konwersja uk³adu wspó³rzêdnych
|
|
// p=p->NextGet();
|
|
//}
|
|
//while (p->NextGet())
|
|
//Root->InitialRotate(false); //a poprzednim tylko optymalizacja
|
|
Root->InitialRotate(true); //argumet okreœla, czy wykonaæ pierwotny obrót
|
|
}
|
|
iFlags|=Root->FlagsCheck()|0x8000; //flagi ca³ego modelu
|
|
if (!asBinary.IsEmpty()) //jeœli jest podana nazwa
|
|
{if (Global::iConvertModels) //i w³¹czony zapis
|
|
SaveToBinFile(asBinary.c_str()); //utworzy tablicê (m_pVNT)
|
|
asBinary=""; //zablokowanie powtórnego zapisu
|
|
}
|
|
if (iNumVerts)
|
|
{
|
|
if (Global::fDistanceFactor!=1.0) //trochê zaoszczêdzi czasu na modelach z wieloma submocelami
|
|
Root->AdjustDist(); //aktualizacja odleg³oœci faz LoD, zale¿nie od rozdzielczoœci pionowej oraz multisamplingu
|
|
if (Global::bUseVBO)
|
|
{if (!m_pVNT) //jeœli nie ma jeszcze tablicy (wczytano z pliku tekstowego)
|
|
{//tworzenie tymczasowej tablicy z wierzcho³kami ca³ego modelu
|
|
MakeArray(iNumVerts); //tworzenie tablic dla VBO
|
|
Root->RaArrayFill(m_pVNT); //wype³nianie tablicy
|
|
BuildVBOs(); //tworzenie VBO i usuwanie tablicy z pamiêci
|
|
}
|
|
else
|
|
BuildVBOs(false); //tworzenie VBO bez usuwania tablicy z pamiêci
|
|
}
|
|
else
|
|
{//przygotowanie skompilowanych siatek dla DisplayLists
|
|
Root->DisplayLists(); //tworzenie skompilowanej listy dla submodelu
|
|
}
|
|
//if (Root->TextureID) //o ile ma teksturê
|
|
// Root->iFlags|=0x80; //koniecznoϾ ustawienia tekstury
|
|
}
|
|
}
|
|
};
|
|
|
|
void __fastcall TModel3d::SaveToBinFile(char *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);
|
|
fs->Write("E3D0",4); //kromka g³ówna
|
|
fs->Write(&len,4);
|
|
{fs->Write("SUB0",4); //dane submodeli
|
|
fs->Write(&sub,4);
|
|
for (i=0;i<iSubModelsCount;++i)
|
|
{roboczy->InfoSet(info+i);
|
|
fs->Write(roboczy,sizeof(TSubModel)); //zapis jednego submodelu
|
|
}
|
|
}
|
|
if (tra)
|
|
{//zapis transformów
|
|
fs->Write("TRA0",4); //transformy
|
|
fs->Write(&tra,4);
|
|
for (i=0;i<iSubModelsCount;++i)
|
|
if (info[i].iTransform>=0)
|
|
fs->Write(info[i].pSubModel->GetMatrix(),16*4);
|
|
}
|
|
{//zapis wierzcho³ków
|
|
MakeArray(iNumVerts); //tworzenie tablic dla VBO
|
|
Root->RaArrayFill(m_pVNT); //wype³nianie tablicy
|
|
fs->Write("VNT0",4); //wierzcho³ki
|
|
fs->Write(&vnt,4);
|
|
fs->Write(m_pVNT,32*iNumVerts);
|
|
}
|
|
if (tex) //mo¿e byæ jeden submodel ze zmienn¹ tekstur¹ i nazwy nie bêdzie
|
|
{//zapis nazw tekstur
|
|
fs->Write("TEX0",4); //nazwy tekstur
|
|
i=(tex+3)&~3; //zaokr¹glenie w górê
|
|
fs->Write(&i,4);
|
|
fs->Write(&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)
|
|
fs->Write(info[i].pSubModel->pTexture,info[i].iTextureLen);
|
|
if ((-tex)&3) fs->Write(&zero,((-tex)&3)); //wyrównanie do wielokrotnoœci 4 bajtów
|
|
}
|
|
if (nam) //mo¿e byæ jeden anonimowy submodel w modelu
|
|
{//zapis nazw submodeli
|
|
fs->Write("NAM0",4); //nazwy submodeli
|
|
i=(nam+3)&~3; //zaokr¹glenie w górê
|
|
fs->Write(&i,4);
|
|
for (i=0;i<iSubModelsCount;++i)
|
|
if (info[i].iNameLen)
|
|
fs->Write(info[i].pSubModel->pName,info[i].iNameLen);
|
|
if ((-nam)&3) fs->Write(&zero,((-nam)&3)); //wyrównanie do wielokrotnoœci 4 bajtów
|
|
}
|
|
delete fs;
|
|
//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 __fastcall TModel3d::BreakHierarhy()
|
|
{
|
|
Error("Not implemented yet :(");
|
|
};
|
|
|
|
/*
|
|
void __fastcall TModel3d::Render(vector3 pPosition,double fAngle,GLuint ReplacableSkinId,int iAlpha)
|
|
{
|
|
// glColor3f(1.0f,1.0f,1.0f);
|
|
// glColor3f(0.0f,0.0f,0.0f);
|
|
glPushMatrix();
|
|
|
|
glTranslated(pPosition.x,pPosition.y,pPosition.z);
|
|
if (fAngle!=0)
|
|
glRotatef(fAngle,0,1,0);
|
|
/*
|
|
matrix4x4 Identity;
|
|
Identity.Identity();
|
|
|
|
matrix4x4 CurrentMatrix;
|
|
glGetdoublev(GL_MODELVIEW_MATRIX,CurrentMatrix.getArray());
|
|
vector3 pos=vector3(0,0,0);
|
|
pos=CurrentMatrix*pos;
|
|
fSquareDist=SquareMagnitude(pos);
|
|
* /
|
|
fSquareDist=SquareMagnitude(pPosition-Global::GetCameraPosition());
|
|
|
|
#ifdef _DEBUG
|
|
if (Root)
|
|
Root->Render(ReplacableSkinId,iAlpha);
|
|
#else
|
|
Root->Render(ReplacableSkinId,iAlpha);
|
|
#endif
|
|
glPopMatrix();
|
|
};
|
|
*/
|
|
|
|
void __fastcall TModel3d::Render(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha)
|
|
{
|
|
iAlpha^=0x0F0F000F; //odwrócenie flag tekstur, aby wy³apaæ nieprzezroczyste
|
|
if (iAlpha&iFlags&0x1F1F001F) //czy w ogóle jest co robiæ w tym cyklu?
|
|
{TSubModel::fSquareDist=fSquareDistance; //zmienna globalna!
|
|
Root->ReplacableSet(ReplacableSkinId,iAlpha);
|
|
Root->RenderDL();
|
|
}
|
|
};
|
|
|
|
void __fastcall TModel3d::RenderAlpha(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha)
|
|
{
|
|
if (iAlpha&iFlags&0x2F2F002F)
|
|
{
|
|
TSubModel::fSquareDist=fSquareDistance; //zmienna globalna!
|
|
Root->ReplacableSet(ReplacableSkinId,iAlpha);
|
|
Root->RenderAlphaDL();
|
|
}
|
|
};
|
|
|
|
/*
|
|
void __fastcall TModel3d::RaRender(vector3 pPosition,double fAngle,GLuint *ReplacableSkinId,int iAlpha)
|
|
{
|
|
// glColor3f(1.0f,1.0f,1.0f);
|
|
// glColor3f(0.0f,0.0f,0.0f);
|
|
glPushMatrix(); //zapamiêtanie matrycy przekszta³cenia
|
|
glTranslated(pPosition.x,pPosition.y,pPosition.z);
|
|
if (fAngle!=0)
|
|
glRotatef(fAngle,0,1,0);
|
|
/*
|
|
matrix4x4 Identity;
|
|
Identity.Identity();
|
|
|
|
matrix4x4 CurrentMatrix;
|
|
glGetdoublev(GL_MODELVIEW_MATRIX,CurrentMatrix.getArray());
|
|
vector3 pos=vector3(0,0,0);
|
|
pos=CurrentMatrix*pos;
|
|
fSquareDist=SquareMagnitude(pos);
|
|
*/
|
|
/*
|
|
fSquareDist=SquareMagnitude(pPosition-Global::GetCameraPosition()); //zmienna globalna!
|
|
if (StartVBO())
|
|
{//odwrócenie flag, aby wy³apaæ nieprzezroczyste
|
|
Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F);
|
|
Root->RaRender();
|
|
EndVBO();
|
|
}
|
|
glPopMatrix(); //przywrócenie ustawieñ przekszta³cenia
|
|
};
|
|
*/
|
|
|
|
void __fastcall TModel3d::RaRender(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha)
|
|
{//renderowanie specjalne, np. kabiny
|
|
iAlpha^=0x0F0F000F; //odwrócenie flag tekstur, aby wy³apaæ nieprzezroczyste
|
|
if (iAlpha&iFlags&0x1F1F001F) //czy w ogóle jest co robiæ w tym cyklu?
|
|
{TSubModel::fSquareDist=fSquareDistance; //zmienna globalna!
|
|
if (StartVBO())
|
|
{//odwrócenie flag, aby wy³apaæ nieprzezroczyste
|
|
Root->ReplacableSet(ReplacableSkinId,iAlpha);
|
|
Root->pRoot=this;
|
|
Root->RenderVBO();
|
|
EndVBO();
|
|
}
|
|
}
|
|
};
|
|
|
|
void __fastcall TModel3d::RaRenderAlpha(double fSquareDistance,GLuint *ReplacableSkinId,int iAlpha)
|
|
{//renderowanie specjalne, np. kabiny
|
|
if (iAlpha&iFlags&0x2F2F002F) //czy w ogóle jest co robiæ w tym cyklu?
|
|
{TSubModel::fSquareDist=fSquareDistance; //zmienna globalna!
|
|
if (StartVBO())
|
|
{Root->ReplacableSet(ReplacableSkinId,iAlpha);
|
|
Root->RenderAlphaVBO();
|
|
EndVBO();
|
|
}
|
|
}
|
|
};
|
|
|
|
/*
|
|
void __fastcall TModel3d::RaRenderAlpha(vector3 pPosition,double fAngle,GLuint *ReplacableSkinId,int iAlpha)
|
|
{
|
|
glPushMatrix();
|
|
glTranslatef(pPosition.x,pPosition.y,pPosition.z);
|
|
if (fAngle!=0)
|
|
glRotatef(fAngle,0,1,0);
|
|
fSquareDist=SquareMagnitude(pPosition-Global::GetCameraPosition()); //zmienna globalna!
|
|
if (StartVBO())
|
|
{Root->ReplacableSet(ReplacableSkinId,iAlpha);
|
|
Root->RaRenderAlpha();
|
|
EndVBO();
|
|
}
|
|
glPopMatrix();
|
|
};
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//2011-03-16 cztery nowe funkcje renderowania z mo¿liwoœci¹ pochylania obiektów
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void __fastcall TModel3d::Render(vector3 *vPosition,vector3 *vAngle,GLuint *ReplacableSkinId,int iAlpha)
|
|
{//nieprzezroczyste, Display List
|
|
glPushMatrix();
|
|
glTranslated(vPosition->x,vPosition->y,vPosition->z);
|
|
if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0);
|
|
if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0);
|
|
if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0);
|
|
TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna!
|
|
//odwrócenie flag, aby wy³apaæ nieprzezroczyste
|
|
Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F);
|
|
Root->RenderDL();
|
|
glPopMatrix();
|
|
};
|
|
void __fastcall TModel3d::RenderAlpha(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId,int iAlpha)
|
|
{//przezroczyste, Display List
|
|
glPushMatrix();
|
|
glTranslated(vPosition->x,vPosition->y,vPosition->z);
|
|
if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0);
|
|
if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0);
|
|
if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0);
|
|
TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna!
|
|
Root->ReplacableSet(ReplacableSkinId,iAlpha);
|
|
Root->RenderAlphaDL();
|
|
glPopMatrix();
|
|
};
|
|
void __fastcall TModel3d::RaRender(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId,int iAlpha)
|
|
{//nieprzezroczyste, VBO
|
|
glPushMatrix();
|
|
glTranslated(vPosition->x,vPosition->y,vPosition->z);
|
|
if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0);
|
|
if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0);
|
|
if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0);
|
|
TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna!
|
|
if (StartVBO())
|
|
{//odwrócenie flag, aby wy³apaæ nieprzezroczyste
|
|
Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F);
|
|
Root->RenderVBO();
|
|
EndVBO();
|
|
}
|
|
glPopMatrix();
|
|
};
|
|
void __fastcall TModel3d::RaRenderAlpha(vector3* vPosition,vector3* vAngle,GLuint *ReplacableSkinId,int iAlpha)
|
|
{//przezroczyste, VBO
|
|
glPushMatrix();
|
|
glTranslated(vPosition->x,vPosition->y,vPosition->z);
|
|
if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0);
|
|
if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0);
|
|
if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0);
|
|
TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna!
|
|
if (StartVBO())
|
|
{Root->ReplacableSet(ReplacableSkinId,iAlpha);
|
|
Root->RenderAlphaVBO();
|
|
EndVBO();
|
|
}
|
|
glPopMatrix();
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//2012-02 funkcje do tworzenia terenu z E3D
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int __fastcall TModel3d::TerrainCount()
|
|
{//zliczanie kwadratów kilometrowych (g³ówna linia po Next) do tworznia tablicy
|
|
int i=0;
|
|
TSubModel *r=Root;
|
|
while (r)
|
|
{r=r->NextGet();
|
|
++i;
|
|
}
|
|
return i;
|
|
};
|
|
TSubModel* __fastcall TModel3d::TerrainSquare(int n)
|
|
{//pobieranie wskaŸnika do submodelu (n)
|
|
int i=0;
|
|
TSubModel *r=Root;
|
|
while (i<n)
|
|
{r=r->NextGet();
|
|
++i;
|
|
}
|
|
r->UnFlagNext(); //blokowanie wyœwietlania po Next g³ównej listy
|
|
return r;
|
|
};
|
|
void __fastcall TModel3d::TerrainRenderVBO(int n)
|
|
{//renderowanie terenu z VBO
|
|
glPushMatrix();
|
|
//glTranslated(vPosition->x,vPosition->y,vPosition->z);
|
|
//if (vAngle->y!=0.0) glRotated(vAngle->y,0.0,1.0,0.0);
|
|
//if (vAngle->x!=0.0) glRotated(vAngle->x,1.0,0.0,0.0);
|
|
//if (vAngle->z!=0.0) glRotated(vAngle->z,0.0,0.0,1.0);
|
|
//TSubModel::fSquareDist=SquareMagnitude(*vPosition-Global::GetCameraPosition()); //zmienna globalna!
|
|
if (StartVBO())
|
|
{//odwrócenie flag, aby wy³apaæ nieprzezroczyste
|
|
//Root->ReplacableSet(ReplacableSkinId,iAlpha^0x0F0F000F);
|
|
TSubModel *r=Root;
|
|
while (r)
|
|
{
|
|
if (r->iVisible==n) //tylko jeœli ma byæ widoczny w danej ramce (problem dla 0==false)
|
|
r->RenderVBO(); //sub kolejne (Next) siê nie wyrenderuj¹
|
|
r=r->NextGet();
|
|
}
|
|
EndVBO();
|
|
}
|
|
glPopMatrix();
|
|
};
|
|
|