Files
Tools_CPP/lib/object3d.cpp
2024-11-01 12:23:13 +05:00

580 lines
20 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//#pragma hdrstop
#include <GL/glew.h> //Должен стоять до "wx/gl...h"
#include <GL/glu.h>
#include <wx/glcanvas.h>
#include <wx/string.h>
#include "object3d.h"
#include "texture.h"
#include "mathTools.h"
//#include "tools/debug.h"
//---------------------------------------------------------------------------
TTriMat::TTriMat()
{
textureid=0;
ColorAmbientRGB.r=0.2f; // 0.2 по умолчанию в OpenGL
ColorAmbientRGB.g=0.2f;
ColorAmbientRGB.b=0.2f;
ColorAmbientRGB.a=1.0f;
ColorDiffuseRGB.r=0.8f; // 0.8 по умолчанию в OpenGL
ColorDiffuseRGB.g=0.8f;
ColorDiffuseRGB.b=0.8f;
ColorDiffuseRGB.a=1.0f;
ColorSpecularRGB.r=0.0f; // 0.0 по умолчанию в OpenGL
ColorSpecularRGB.g=0.0f;
ColorSpecularRGB.b=0.0f;
ColorSpecularRGB.a=1.0f;
USCALE=1.0f;
VSCALE=1.0f;
}
//---------------------------------------------------------------------------
void TTriMat::Release()
{
//прозрачность
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (float*)&ColorAmbientRGB);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (float*)&ColorDiffuseRGB);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (float*)&ColorSpecularRGB);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 100.0f); //яркость источника цвета от 0 до 128
//если текстурированна
if(textureid!=0)
{
glBindTexture(GL_TEXTURE_2D, textureid);
glEnable(GL_TEXTURE_2D);
//чтобы цвет не воздействовал на текстуру если она есть
glEnable(GL_COLOR_MATERIAL);
glColor4f(1,1,1,ColorDiffuseRGB.a);
glDisable(GL_COLOR_MATERIAL);
} else glDisable(GL_TEXTURE_2D);
}
//---------------------------------------------------------------------------
TTriangles::TTriangles()
{
del=false;
bSmooth=false;
CountVertex=0;
CountFaces=0;
//countMapPoint=0;
Vertices=NULL;
SmoothNormals=NULL;
faces=NULL;
TexVertices=NULL;
SmoothG=NULL;
bInit=false;
//разбивка по материалам
countMF=0;
MatFaces=NULL;
//материал (после разбивки)
TriMat=NULL;
}
//------------------------------------------------------------------------------
TTriangles::~TTriangles()
{
if (Vertices!=NULL) delete[] Vertices;
Vertices=NULL;
if (SmoothNormals!=NULL) delete[] SmoothNormals;
SmoothNormals=NULL;
if (faces!=NULL) delete[] faces;
faces=NULL;
if (TexVertices!=NULL) delete[] TexVertices;
TexVertices=NULL;
if (SmoothG!=NULL) delete[] SmoothG;
SmoothG=NULL;
if (bInit)
{
glDeleteBuffersARB(1,&vbov);
glDeleteBuffersARB(1,&vbot);
glDeleteBuffersARB(1,&vbon);
glDeleteBuffersARB(1,&vbof);
}
for(unsigned int i=0;i<countMF;i++)
{
delete[] MatFaces[i].name;
delete[] MatFaces[i].faces;
}
if(MatFaces!=NULL) delete[] MatFaces;
MatFaces=NULL;
}
//------------------------------------------------------------------------------
//TODO предусмотреть загрузку в видео память как 1го объекта так и группы (если группой то здесь сохраняется указатель и смещение к нужному объекту)
void TTriangles::render()
{
if(TexVertices==NULL) TexVertices = new RfPointXY[CountVertex];
//if(Material!=NULL) Material.Release();
if(!bSmooth) glShadeModel(GL_FLAT); else glShadeModel(GL_SMOOTH);
//передаём указатели на массивы и рендерим
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
/*RdPointXYZ *d=new RdPointXYZ[CountVertex];
for(unsigned int i=0;i<CountVertex;i++)
{
d[i].x=Vertices[i].x;
d[i].y=Vertices[i].y;
d[i].z=Vertices[i].z;
}
glVertexPointer(3,GL_DOUBLE,0,&d[0]);*/
glVertexPointer(3,GL_FLOAT,0,&Vertices[0]);
glNormalPointer(GL_FLOAT, 0, &SmoothNormals[0]);
glTexCoordPointer(2,GL_FLOAT, 0, &TexVertices[0]);
glDrawElements(GL_TRIANGLES, CountFaces*3, GL_UNSIGNED_SHORT, &faces[0]);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//delete[] d;
/**/
/*if (!bInit)
{
//огромные переделки:
//однотипные обьекты должны храниться в одном vbov значит рендеринг должен быть преобразован в другой вид а именно
//с начала идет цикл по всем созданным VBO он биндиться потом цикл по моделям(смещениям) в этом VBO здесь применяеться механизм отсечения потом
//потом применяеться подходящяя текстура потом собственно glDrawElements
glGenBuffersARB(1,&vbov);
glBindBufferARB( GL_ARRAY_BUFFER_ARB, vbov );
glBufferDataARB( GL_ARRAY_BUFFER_ARB, VertexCount*sizeof(RfPointXYZ), &fPointXYZ[0], GL_STATIC_DRAW_ARB);
glGenBuffersARB(1,&vbot);
glBindBufferARB( GL_ARRAY_BUFFER_ARB, vbot );
glBufferDataARB( GL_ARRAY_BUFFER_ARB, VertexCount*sizeof(RfPointXY), &fMapPointXY[0], GL_STATIC_DRAW_ARB );
glGenBuffersARB(1,&vbon);
glBindBufferARB( GL_ARRAY_BUFFER_ARB, vbon );
glBufferDataARB( GL_ARRAY_BUFFER_ARB, VertexCount*sizeof(RfPointXYZ), &fNormalXYZ[0], GL_STATIC_DRAW_ARB );
glGenBuffersARB(1,&vbof);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vbof);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, p_object->faces*sizeof(RsFacesABC), &face[0], GL_STATIC_DRAW_ARB);
bInit=true;
}
// vbov,vbon,vbot,vbof :TGLuint; //вершины,нормали,текстура,рёбра
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbov);
glVertexPointer( 3, GL_FLOAT, 0, (char *) NULL );
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbot);
glTexCoordPointer( 2, GL_FLOAT, 0, (char *) NULL );
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbon);
glNormalPointer( GL_FLOAT, 0, (char *) NULL );
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, vbof);
glDrawElements(GL_TRIANGLES, p_object->faces*3 ,GL_UNSIGNED_SHORT, NULL);
//биндим нулевой буфер
glBindBufferARB(GL_ARRAY_BUFFER_ARB,0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB,0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
/**/
}
//------------------------------------------------------------------------------
void TTriangles::CalcMinMaxPoint()
{
if(CountVertex>0)
{
MaxPointXYZ.x=Vertices[0].x;
MaxPointXYZ.y=Vertices[0].y;
MaxPointXYZ.z=Vertices[0].z;
MinPointXYZ.x=Vertices[0].x;
MinPointXYZ.y=Vertices[0].y;
MinPointXYZ.z=Vertices[0].z;
}
for(unsigned int i=1;i<CountVertex;i++)
{
if(MaxPointXYZ.x<Vertices[i].x) MaxPointXYZ.x=Vertices[i].x;
if(MaxPointXYZ.y<Vertices[i].y) MaxPointXYZ.y=Vertices[i].y;
if(MaxPointXYZ.z<Vertices[i].z) MaxPointXYZ.z=Vertices[i].z;
if(MinPointXYZ.x>Vertices[i].x) MinPointXYZ.x=Vertices[i].x;
if(MinPointXYZ.y>Vertices[i].y) MinPointXYZ.y=Vertices[i].y;
if(MinPointXYZ.z>Vertices[i].z) MinPointXYZ.z=Vertices[i].z;
}
PointXYZCenter.x=(MinPointXYZ.x+MaxPointXYZ.x)/2.0f;
PointXYZCenter.y=(MinPointXYZ.y+MaxPointXYZ.y)/2.0f;
PointXYZCenter.z=(MinPointXYZ.z+MaxPointXYZ.z)/2.0f;
/* //DOTO есть такие параметры как сдвиг вращения масштаб я здесь учитываю только масштаб и сдвиг
MaxPointXYZ.x=(MaxPointXYZ.x*ScaleXYZ.x)+ShiftXYZ.x;
MaxPointXYZ.y=(MaxPointXYZ.y*ScaleXYZ.y)+ShiftXYZ.y;
MaxPointXYZ.z=(MaxPointXYZ.z*ScaleXYZ.z)+ShiftXYZ.z;
MinPointXYZ.x=(MinPointXYZ.x*ScaleXYZ.x)+ShiftXYZ.x;
MinPointXYZ.y=(MinPointXYZ.y*ScaleXYZ.y)+ShiftXYZ.y;
MinPointXYZ.z=(MinPointXYZ.z*ScaleXYZ.z)+ShiftXYZ.z;
//так как выделяем обьект по попаданию точки в нутырь куба для плоских обьектов немного расширем пространиство
MaxPointXYZ.x=MaxPointXYZ.x+0.001;
MaxPointXYZ.y=MaxPointXYZ.y+0.001;
MaxPointXYZ.z=MaxPointXYZ.z+0.001;
MinPointXYZ.x=MinPointXYZ.x-0.001;
MinPointXYZ.y=MinPointXYZ.y-0.001;
MinPointXYZ.z=MinPointXYZ.z-0.001;*/
}
//------------------------------------------------------------------------------
//просчитать сглаживающие нормали к поверхности
void TTriangles::CalcSmoothNormals()
{
unsigned int j;
if(SmoothNormals==NULL) SmoothNormals=new RfPointXYZ[CountVertex]; //память под нормали к точке
//если отключенно сглаживание то учитываеться только последний вектор к грани
if(!bSmooth)
{
for(j=0;j<CountVertex;j++)
{
SmoothNormals[j].x=0;
SmoothNormals[j].y=0;
SmoothNormals[j].z=0;
}
for(j=0;j<CountFaces;j++)
{
CalcNormals(Vertices[faces[j].a].x,Vertices[faces[j].a].y,Vertices[faces[j].a].z,Vertices[faces[j].b].x,Vertices[faces[j].b].y,Vertices[faces[j].b].z,Vertices[faces[j].c].x,Vertices[faces[j].c].y,Vertices[faces[j].c].z,SmoothNormals[faces[j].c].x,SmoothNormals[faces[j].c].y,SmoothNormals[faces[j].c].z);
}
}else
{
for(j=0;j<CountVertex;j++)
{
SmoothNormals[j].x=0;
SmoothNormals[j].y=0;
SmoothNormals[j].z=0;
}
unsigned int *mas=new unsigned int[CountVertex];
for(j=0;j<CountVertex;j++) mas[j]=0; //для усреднения
//подсчитываем нормали для каждой точки
RfPointXYZ point;
for(j=0;j<CountFaces;j++)
{
CalcNormals(Vertices[faces[j].a].x,Vertices[faces[j].a].y,Vertices[faces[j].a].z,Vertices[faces[j].b].x,Vertices[faces[j].b].y,Vertices[faces[j].b].z,Vertices[faces[j].c].x,Vertices[faces[j].c].y,Vertices[faces[j].c].z,point.x,point.y,point.z);
SmoothNormals[faces[j].a].x=SmoothNormals[faces[j].a].x+point.x;
SmoothNormals[faces[j].a].y=SmoothNormals[faces[j].a].y+point.y;
SmoothNormals[faces[j].a].z=SmoothNormals[faces[j].a].z+point.z;
mas[faces[j].a]++;
SmoothNormals[faces[j].b].x=SmoothNormals[faces[j].b].x+point.x;
SmoothNormals[faces[j].b].y=SmoothNormals[faces[j].b].y+point.y;
SmoothNormals[faces[j].b].z=SmoothNormals[faces[j].b].z+point.z;
mas[faces[j].b]++;
SmoothNormals[faces[j].c].x=SmoothNormals[faces[j].c].x+point.x;
SmoothNormals[faces[j].c].y=SmoothNormals[faces[j].c].y+point.y;
SmoothNormals[faces[j].c].z=SmoothNormals[faces[j].c].z+point.z;
mas[faces[j].c]++;
}
//нормализуем нормали
for(j=0;j<CountVertex;j++)
{
SmoothNormals[j].x=SmoothNormals[j].x/mas[j];
SmoothNormals[j].y=SmoothNormals[j].y/mas[j];
SmoothNormals[j].z=SmoothNormals[j].z/mas[j];
normalized(SmoothNormals[j]); //приведу к еденичной длине
}
delete[] mas;
}
}
//------------------------------------------------------------------------------
void TTriangles::cutOnSmoothGroup()
{
/*if(SmoothG==NULL)
{*/
//груп сглаживания нет то каждая грань имеет единоличные точки
RfPointXYZ *vbuf=new RfPointXYZ[CountFaces*3];
RfPointXY *tbuf=new RfPointXY[CountFaces*3];
unsigned short count=0;
for(unsigned int i=0;i<CountFaces;i++)
{
vbuf[count]=Vertices[faces[i].a];
if(TexVertices!=NULL) tbuf[count]=TexVertices[faces[i].a];
faces[i].a=count; //сохраняем новый номер точки
count++;
vbuf[count]=Vertices[faces[i].b];
if(TexVertices!=NULL) tbuf[count]=TexVertices[faces[i].b];
faces[i].b=count; //сохраняем новый номер точки
count++;
vbuf[count]=Vertices[faces[i].c];
if(TexVertices!=NULL) tbuf[count]=TexVertices[faces[i].c];
faces[i].c=count; //сохраняем новый номер точки
count++;
}
delete[] Vertices;
Vertices=vbuf;
CountVertex=CountFaces*3;
if(TexVertices!=NULL) delete[] TexVertices;
TexVertices=tbuf;
/*}else
{
}*/
CalcSmoothNormals(); //просчитываем сглаживающие нормали к точкам
delete[] SmoothG;
SmoothG=NULL;
}
//------------------------------------------------------------------------------
//добавить материал
//название материала,колво элементов, список фейсов с этим материалом
void TTriangles::AddMaterial(char *name,unsigned short count,unsigned short *faces)
{
RMatFaces *buf=new RMatFaces[countMF+1];
for(unsigned int i=0;i<countMF;i++) buf[i]=MatFaces[i];
buf[countMF].name=name;
buf[countMF].count=count;
buf[countMF].faces=faces;
if(MatFaces!=NULL) delete[] MatFaces;
MatFaces=buf;
countMF++;
}
//******************************************************************************
TTrianglesList::TTrianglesList()
{
count=0;
List=NULL;
countMat=0; //количество материалов
ListMat=NULL; //массив материалов
}
//------------------------------------------------------------------------------
TTrianglesList::~TTrianglesList()
{
for(unsigned int i=0;i<count;i++) delete List[i];
if(List!=NULL) delete[] List;
count=4294967295; //на всяк.
for(unsigned int i=0;i<countMat;i++) delete ListMat[i];
if(ListMat!=NULL) delete[] ListMat;
countMat=4294967295; //на всяк.
}
//------------------------------------------------------------------------------
TTriangles* TTrianglesList::Add()
{
TTriangles **buf = new TTriangles*[count+1];
for(unsigned int i=0;i<count;i++) buf[i]=List[i];
buf[count]=new TTriangles();
if(List!=NULL) delete[] List;
List=buf;
return List[count++];
}
//------------------------------------------------------------------------------
//удалить обьект из массива
void TTrianglesList::DelTri(TTriangles* tri)
{
for(unsigned int i=0;i<count;i++)
{
if(List[i]==tri)
{
TTriangles **buf = new TTriangles*[count-1];
unsigned int pos=0;
for(unsigned int j=0;j<count;j++)
{
if(i!=j){buf[pos]=List[j]; pos++;}
}
delete[] List;
delete tri;
List=buf;
count--;
break;
}
}
}
//------------------------------------------------------------------------------
//добавить новый метериал
TTriMat* TTrianglesList::AddMat()
{
TTriMat **buf = new TTriMat*[countMat+1];
for(unsigned int i=0;i<countMat;i++) buf[i]=ListMat[i];
buf[countMat]=new TTriMat();
if(ListMat!=NULL) delete[] ListMat;
ListMat=buf;
return ListMat[countMat++];
}
//------------------------------------------------------------------------------
void TTrianglesList::render()
{
for(unsigned int i=0;i<count;i++)
{
TTriangles *tri=List[i];
if(tri->TriMat!=NULL) tri->TriMat->Release();
tri->render();
}
}
//------------------------------------------------------------------------------
void TTrianglesList::CalcMinMaxPoint()
{
for(unsigned int i=0;i<count;i++)
{
TTriangles *tri=List[i];
tri->CalcMinMaxPoint();
if(i==0) MinPointXYZ=tri->MinPointXYZ; else
{
if(MinPointXYZ.x>tri->MinPointXYZ.x) MinPointXYZ.x=tri->MinPointXYZ.x;
if(MinPointXYZ.y>tri->MinPointXYZ.y) MinPointXYZ.y=tri->MinPointXYZ.y;
if(MinPointXYZ.z>tri->MinPointXYZ.z) MinPointXYZ.z=tri->MinPointXYZ.z;
}
if(i==0) MaxPointXYZ=tri->MaxPointXYZ; else
{
if(MaxPointXYZ.x<tri->MaxPointXYZ.x) MaxPointXYZ.x=tri->MaxPointXYZ.x;
if(MaxPointXYZ.y<tri->MaxPointXYZ.y) MaxPointXYZ.y=tri->MaxPointXYZ.y;
if(MaxPointXYZ.z<tri->MaxPointXYZ.z) MaxPointXYZ.z=tri->MaxPointXYZ.z;
}
}
CenterPointXYZ.x=(MaxPointXYZ.x+MinPointXYZ.x)/2.0f;
CenterPointXYZ.y=(MaxPointXYZ.y+MinPointXYZ.y)/2.0f;
CenterPointXYZ.z=(MaxPointXYZ.z+MinPointXYZ.z)/2.0f;
}
//------------------------------------------------------------------------------
void TTrianglesList::CalcSmoothNormals()
{
for(unsigned int i=0;i<count;i++)
{
TTriangles *tri=List[i];
tri->CalcSmoothNormals();
}
}
//------------------------------------------------------------------------------
void TTrianglesList::cutOnSmoothGroup()
{
for(unsigned int i=0;i<count;i++)
{
TTriangles *tri=List[i];
tri->cutOnSmoothGroup();
}
}
//------------------------------------------------------------------------------
TTriMat *TTrianglesList::FindMatOnName(char *name)
{
for(unsigned int i=0;i<countMat;i++)
{
if(wxString::FromAscii(ListMat[i]->name).Lower()==wxString::FromAscii(name).Lower()) return ListMat[i];
}
return NULL;
}
//------------------------------------------------------------------------------
//разбить обьект по списку материалов (сколько материалов столшько и объектов будет)
//применять после разбения по группам сглаживания и просчёта нормалей а то на границе между разными материалами не будет сглаживания
void TTrianglesList::cutOnMaterials()
{
for(unsigned int i=0;i<count;i++)
{
TTriangles *tri=List[i];
if(tri->countMF==1)
{
tri->TriMat=FindMatOnName(tri->MatFaces[0].name);
}else
if(tri->countMF>1) //если несколько материалов то размножаем объекты
{
//в списке фейсов для этого материала раздные точки
//составляем список уникальных точек затем копируем их
//память выделяем под самый плохой вариант
unsigned short *buf=new unsigned short[tri->CountVertex*2]; //уникальные номера точек
for(unsigned int j=0;j<tri->countMF;j++)
{
//создаём новый объект и копируем туда точки в соответствии с материалом
unsigned int cnt=0;
for(unsigned int k=0;k<tri->MatFaces[j].count;k++)
{
if(tri->MatFaces[j].faces[k]>=tri->CountFaces)
return;
bool b=false;
for(unsigned int q=0;q<cnt;q++)
if(buf[q]==tri->faces[tri->MatFaces[j].faces[k]].a)
{
b=true;
break;
}
if(!b){buf[cnt]=tri->faces[tri->MatFaces[j].faces[k]].a; cnt++;}
b=false;
for(unsigned int q=0;q<cnt;q++)
if(buf[q]==tri->faces[tri->MatFaces[j].faces[k]].b)
{
b=true;
break;
}
if(!b){buf[cnt]=tri->faces[tri->MatFaces[j].faces[k]].b; cnt++;}
b=false;
for(unsigned int q=0;q<cnt;q++)
if(buf[q]==tri->faces[tri->MatFaces[j].faces[k]].c)
{
b=true;
break;
}
if(!b){buf[cnt]=tri->faces[tri->MatFaces[j].faces[k]].c; cnt++;}
}
//выбрали список точек нужных для нового обьекта теперь копируем
TTriangles* newTri=Add();
newTri->TriMat=FindMatOnName(tri->MatFaces[j].name);
newTri->CountVertex=cnt;
newTri->Vertices=new RfPointXYZ[newTri->CountVertex];
newTri->TexVertices=new RfPointXY[newTri->CountVertex];
newTri->SmoothNormals=new RfPointXYZ[newTri->CountVertex];
newTri->CountFaces=tri->MatFaces[j].count;
newTri->faces=new RsFacesABC[newTri->CountFaces];
for(unsigned int k=0;k<cnt;k++) //копируем точки
{
newTri->Vertices[k]=tri->Vertices[buf[k]];
newTri->TexVertices[k]=tri->TexVertices[buf[k]];
newTri->SmoothNormals[k]=tri->SmoothNormals[buf[k]];
}
for(unsigned int k=0;k<tri->MatFaces[j].count;k++)
{
newTri->faces[k]=tri->faces[tri->MatFaces[j].faces[k]];
//ищем номер точки
bool b=true;
for(unsigned int q=0;q<cnt;q++){ if(newTri->faces[k].a==buf[q]) {newTri->faces[k].a=q; b=false; break;} }
if(b||newTri->faces[k].a>=cnt)
return;
b=true;
for(unsigned int q=0;q<cnt;q++){ if(newTri->faces[k].b==buf[q]) {newTri->faces[k].b=q; b=false; break;} }
if(b||newTri->faces[k].b>=cnt)
return;
b=true;
for(unsigned int q=0;q<cnt;q++){ if(newTri->faces[k].c==buf[q]) {newTri->faces[k].c=q; b=false; break;} }
if(b||newTri->faces[k].c>=cnt)
return;
}
}
tri->del=true;
delete[] buf;
}
}
unsigned int i=0;
while(i<count)
{
TTriangles *tri=List[i];
//tri->CountVertex;
if(tri->del)
DelTri(tri);
else i++;
}
//домножаем текущие координаты материала на USCALE и VSCALE текущего материала
for(unsigned int i=0;i<count;i++)
{
TTriangles *tri=List[i];
if(tri->TriMat!=NULL)
for(unsigned int j=0;j<tri->CountVertex;j++)
{
tri->TexVertices[j].x*=tri->TriMat->USCALE;
tri->TexVertices[j].y*=tri->TriMat->VSCALE;
}
}
}
//------------------------------------------------------------------------------