tge/engine/constructor/constructorSimpleMesh.cc
2017-04-17 06:17:10 -06:00

743 lines
20 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "constructor/constructorSimpleMesh.h"
#ifdef IS_CONSTRUCTOR
#include "constructor/lightingSystem/lightingSystem.h"
#else
#include "interior/interiorLMManager.h"
#endif
#include "console/console.h"
#include "sim/sceneObject.h"
#include "util/triRayCheck.h"
#include "math/mathIO.h"
#ifdef IS_CONSTRUCTOR
ConstructorSimpleMesh *ConstructorSimpleMeshLoader::currentMesh = NULL;
#endif
// *** DAW: Checks for polygon level collision with given planes
U32 _whichSide(PlaneF pln, Point3F* verts)
{
Point3F currv, nextv;
S32 csd, nsd;
// Find out which side the first vert is on
U32 side = PlaneF::On;
currv = verts[0];
csd = pln.whichSide(currv);
if(csd != PlaneF::On)
side = csd;
for(U32 k = 1; k < 3; k++)
{
nextv = verts[k];
nsd = pln.whichSide(nextv);
if((csd == PlaneF::Back && nsd == PlaneF::Front) ||
(csd == PlaneF::Front && nsd == PlaneF::Back))
return 2;
else if (nsd != PlaneF::On)
side = nsd;
currv = nextv;
csd = nsd;
}
// Loop back to the first vert
nextv = verts[0];
nsd = pln.whichSide(nextv);
if((csd == PlaneF::Back && nsd == PlaneF::Front) ||
(csd == PlaneF::Front && nsd == PlaneF::Back))
return 2;
else if(nsd != PlaneF::On)
side = nsd;
return side;
}
bool ConstructorSimpleMesh::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
{
bool found = false;
F32 best_t = F32_MAX;
Point3F best_normal = Point3F(0, 0, 1);
Point3F dir = end - start;
for(U32 p=0; p<primitives.size(); p++)
{
primitive &prim = primitives[p];
for(U32 t=2; t<prim.count; t++)
{
Point3F &v1 = verts[prim.start+t-2];
Point3F &v2 = verts[prim.start+t-1];
Point3F &v3 = verts[prim.start+t];
F32 cur_t = 0;
Point2F b;
if(castRayTriangle(start, dir, v1, v2, v3, cur_t, b))
{
if(cur_t < best_t)
{
best_t = cur_t;
best_normal = norms[prim.start+t];
found = true;
}
}
}
}
if(found && info)
{
info->t = best_t;
info->normal = best_normal;
info->material = 0;
}
return found;
}
bool ConstructorSimpleMesh::castPlanes(PlaneF left, PlaneF right, PlaneF top, PlaneF bottom)
{
for(U32 p=0; p<primitives.size(); p++)
{
primitive &prim = primitives[p];
for(U32 t=2; t<prim.count; t++)
{
Point3F v[3];
v[0] = verts[prim.start+t-2];
v[1] = verts[prim.start+t-1];
v[2] = verts[prim.start+t];
if(_whichSide(left, v) == PlaneF::Front)
continue;
if(_whichSide(right, v) == PlaneF::Front)
continue;
if(_whichSide(top, v) == PlaneF::Front)
continue;
if(_whichSide(bottom, v) == PlaneF::Front)
continue;
return true;
}
}
return false;
}
#ifdef IS_CONSTRUCTOR
void ConstructorSimpleMesh::render(bool transparent, bool texture, bool lightmap)
{
#else
void ConstructorSimpleMesh::render(bool transparent, bool texture, bool lightmap,
U32 interiorlmhandle, U32 instancelmhandle)
{
if(!materialList)
return;
#endif
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, verts.address());
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, 0, norms.address());
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, diffuseUVs.address());
//if (lightmap)
//{
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, lightmapUVs.address());
glClientActiveTextureARB(GL_TEXTURE0_ARB);
//}
for(S32 i=0; i<primitives.size(); i++)
{
primitive &draw = primitives[i];
if(draw.alpha != transparent)
continue;
if(texture)
{
#ifdef IS_CONSTRUCTOR
glBindTexture(GL_TEXTURE_2D, draw.diffuseId);
#else
glBindTexture(GL_TEXTURE_2D, materialList->getMaterial(draw.diffuseIndex).getGLName());
#endif
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, draw.texS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, draw.texT);
}
if(lightmap)
{
glActiveTextureARB(GL_TEXTURE1_ARB);
#ifdef IS_CONSTRUCTOR
glBindTexture(GL_TEXTURE_2D, draw.lightMapId);
#else
glBindTexture(GL_TEXTURE_2D, gInteriorLMManager.getHandle(interiorlmhandle, instancelmhandle, draw.lightMapIndex)->getGLName());
#endif
glActiveTextureARB(GL_TEXTURE0_ARB);
}
glDrawElements(GL_TRIANGLE_STRIP, draw.count, GL_UNSIGNED_SHORT,
&indices[draw.start]);
}
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
bool ConstructorSimpleMesh::read(Stream& stream)
{
// Simple serialization
S32 vectorSize = 0;
// Primitives
stream.read(&vectorSize);
primitives.setSize(vectorSize);
for (U32 i = 0; i < primitives.size(); i++)
{
stream.read(&primitives[i].alpha);
stream.read(&primitives[i].texS);
stream.read(&primitives[i].texT);
stream.read(&primitives[i].diffuseIndex);
stream.read(&primitives[i].lightMapIndex);
stream.read(&primitives[i].start);
stream.read(&primitives[i].count);
mathRead(stream, &primitives[i].lightMapEquationX);
mathRead(stream, &primitives[i].lightMapEquationY);
mathRead(stream, &primitives[i].lightMapOffset);
mathRead(stream, &primitives[i].lightMapSize);
}
// Indices
stream.read(&vectorSize);
indices.setSize(vectorSize);
for (U32 i = 0; i < indices.size(); i++)
stream.read(&indices[i]);
// Vertices
stream.read(&vectorSize);
verts.setSize(vectorSize);
for (U32 i = 0; i < verts.size(); i++)
mathRead(stream, &verts[i]);
// Normals
stream.read(&vectorSize);
norms.setSize(vectorSize);
for (U32 i = 0; i < norms.size(); i++)
mathRead(stream, &norms[i]);
// Diffuse UVs
stream.read(&vectorSize);
diffuseUVs.setSize(vectorSize);
for (U32 i = 0; i < diffuseUVs.size(); i++)
mathRead(stream, &diffuseUVs[i]);
// Lightmap UVs
stream.read(&vectorSize);
lightmapUVs.setSize(vectorSize);
for (U32 i = 0; i < lightmapUVs.size(); i++)
mathRead(stream, &lightmapUVs[i]);
// Material list
bool hasMaterialList = false;
stream.read(&hasMaterialList);
if (hasMaterialList)
{
// Since we are doing this externally to a TSShape read we need to
// make sure that our read version is the same as our write version.
// It is possible that it was changed along the way by a loaded TSShape.
TSShape::smReadVersion = TSShape::smVersion;
if (materialList)
delete materialList;
materialList = new TSMaterialList;
materialList->read(stream);
}
else
materialList = NULL;
// Diffuse bitmaps
stream.read(&vectorSize);
for (U32 i = 0; i < vectorSize; i++)
{
TextureHandle& handle = materialList->getMaterial(i);
bool hasBitmap = false;
stream.read(&hasBitmap);
if (hasBitmap)
{
GBitmap* bitMap = new GBitmap;
bitMap->readPNG(stream);
handle.set(materialList->getMaterialName(i), bitMap, BitmapKeepTexture);
}
}
// Misc data
stream.read(&hasSolid);
stream.read(&hasTranslucency);
mathRead(stream, &bounds);
mathRead(stream, &transform);
mathRead(stream, &scale);
calculateBounds();
return true;
}
bool ConstructorSimpleMesh::write(Stream& stream) const
{
// Simple serialization
// Primitives
stream.write(primitives.size());
for (U32 i = 0; i < primitives.size(); i++)
{
stream.write(primitives[i].alpha);
stream.write(primitives[i].texS);
stream.write(primitives[i].texT);
stream.write(primitives[i].diffuseIndex);
stream.write(primitives[i].lightMapIndex);
stream.write(primitives[i].start);
stream.write(primitives[i].count);
mathWrite(stream, primitives[i].lightMapEquationX);
mathWrite(stream, primitives[i].lightMapEquationY);
mathWrite(stream, primitives[i].lightMapOffset);
mathWrite(stream, primitives[i].lightMapSize);
}
// Indices
stream.write(indices.size());
for (U32 i = 0; i < indices.size(); i++)
stream.write(indices[i]);
// Vertices
stream.write(verts.size());
for (U32 i = 0; i < verts.size(); i++)
mathWrite(stream, verts[i]);
// Normals
stream.write(norms.size());
for (U32 i = 0; i < norms.size(); i++)
mathWrite(stream, norms[i]);
// Diffuse UVs
stream.write(diffuseUVs.size());
for (U32 i = 0; i < diffuseUVs.size(); i++)
mathWrite(stream, diffuseUVs[i]);
// Lightmap UVs
stream.write(lightmapUVs.size());
for (U32 i = 0; i < lightmapUVs.size(); i++)
mathWrite(stream, lightmapUVs[i]);
// Material list
if (materialList)
{
stream.write(true);
materialList->write(stream);
}
else
stream.write(false);
// Diffuse bitmaps
if (!materialList)
stream.write(0);
else
{
stream.write(materialList->getMaterialCount());
for (U32 i = 0; i < materialList->getMaterialCount(); i++)
{
TextureHandle& handle = materialList->getMaterial(i);
if (handle.isValid())
{
GBitmap* bitMap = handle.getBitmap();
if (bitMap)
{
stream.write(true);
bitMap->writePNG(stream);
}
else
stream.write(false);
}
else
stream.write(false);
}
}
// Misc data
stream.write(hasSolid);
stream.write(hasTranslucency);
mathWrite(stream, bounds);
mathWrite(stream, transform);
mathWrite(stream, scale);
return true;
}
//-----------------------------------------------------------------------------
#ifdef IS_CONSTRUCTOR
bool ConstructorSimpleMeshLoader::loadSimpleMesh(const char *filename, ConstructorSimpleMesh &mesh)
{
if(!filename)
return false;
const char *ext = dStrrchr(filename, '.');
if(!ext || (ext[0] == 0))
return false;
FileStream file;
if(!file.open(filename, FileStream::Read))
{
Con::errorf("Unable to open file '%s'.", filename);
return false;
}
currentMesh = &mesh;
currentMesh->clear();
bool res = false;
if(dStricmp(ext, ".dts") == 0)
res = loadDTSFile(filename);
//else if(dStricmp(ext, ".x") == 0)
// res = loadDirectXFile(&file);
else
{
ext = &ext[1];
if(ext[0] != 0)
{
char func[256];
func[0] = 0;
dStrcat(func, "SimpleMeshLoader_load");
dStrcat(func, ext);
dStrcat(func, "File");
const char *ret = Con::executef(1, func);
if(!ret || (dStricmp(ret, "1") != 0))
res = false;
else
res = true;
}
}
currentMesh->calculateBounds();
currentMesh = NULL;
return res;
}
bool ConstructorSimpleMeshLoader::loadDTSFile(const char *filename)
{
Resource<TSShape> shape;
shape = ResourceManager->load(filename);
if(shape.isNull())
return false;
TSShapeInstance *shapeinst = new TSShapeInstance(shape, true);
if(!shapeinst)
return false;
// load up...
currentMesh->materialList = new TSMaterialList(shapeinst->getMaterialList());
// only interested in the top detail...
const TSDetail *detail = &shapeinst->getShape()->details[0];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
S32 start = shapeinst->getShape()->subShapeFirstObject[ss];
S32 end = start + shapeinst->getShape()->subShapeNumObjects[ss];
shapeinst->animate(0);
shapeinst->setCurrentDetail(0);
shapeinst->setStatics(0);
currentMesh->hasSolid = true;
for(U32 i=start; i<end; i++)
{
TSMesh *mesh = shapeinst->mMeshObjects[i].getMesh(od);
MatrixF *mat = shapeinst->mMeshObjects[i].getTransform();
if(!mesh)
continue;
MatrixF m;
if(mat)
m = *mat;
else
m.identity();
ToolVector<Point3F> *vertsp;
ToolVector<Point3F> *normsp;
TSSkinMesh *smesh = dynamic_cast<TSSkinMesh *>(mesh);
if(smesh)
{
vertsp = &smesh->initialVerts;
normsp = &smesh->initialNorms;
}
else
{
vertsp = &mesh->verts;
normsp = &mesh->norms;
}
ToolVector<Point3F> &verts = *vertsp;
ToolVector<Point3F> &norms = *normsp;
for(U32 p=0; p<mesh->primitives.size(); p++)
{
TSDrawPrimitive &oldprim = mesh->primitives[p];
currentMesh->primitives.increment();
ConstructorSimpleMesh::primitive &newprim = currentMesh->primitives.last();
U32 flags = currentMesh->materialList->getFlags(oldprim.matIndex & TSDrawPrimitive::MaterialMask);
newprim.alpha = (flags & TSMaterialList::Translucent);
newprim.texS = (flags & TSMaterialList::S_Wrap) ? GL_REPEAT : GL_CLAMP;
newprim.texT = (flags & TSMaterialList::T_Wrap) ? GL_REPEAT : GL_CLAMP;
newprim.start = currentMesh->indices.size();
newprim.count = 0;
newprim.lightMapId = 0;
newprim.lightMapIndex = 0;
if(newprim.alpha)
currentMesh->hasTranslucency = true;
newprim.diffuseIndex = oldprim.matIndex & TSDrawPrimitive::MaterialMask;
TextureHandle &tex = currentMesh->materialList->getMaterial(newprim.diffuseIndex);
newprim.diffuseId = tex.getGLName();
for(U32 v=0; v<oldprim.numElements; v++)
{
AssertFatal(((S32(oldprim.start + v) > -1) &&
(S32(oldprim.start + v) < mesh->indices.size())), "!");
S32 srcindex = mesh->indices[oldprim.start + v];
S32 dstindex = currentMesh->verts.size();
currentMesh->indices.increment();
currentMesh->norms.increment();
currentMesh->verts.increment();
currentMesh->diffuseUVs.increment();
currentMesh->lightmapUVs.increment();
currentMesh->indices.last() = dstindex;
currentMesh->verts[dstindex] = verts[srcindex];
currentMesh->norms[dstindex] = norms[srcindex];
m.mulP(currentMesh->verts[dstindex]);
m.mulV(currentMesh->norms[dstindex]);
ToolVector<Point2F> uvs;
mesh->getUVs(TSMesh::tDiffuse, uvs);
if(uvs.size() > 0)
currentMesh->diffuseUVs[dstindex] = uvs[srcindex];
newprim.count++;
}
}
}
// Now grab the collision meshes and shove them into ConvexBrushes
for (U32 i = 0; i < shapeinst->getShape()->details.size(); i++)
{
const TSDetail * detail = &shapeinst->getShape()->details[i];
char* name = (char*)shapeinst->getShape()->names[detail->nameIndex];
if (dStrstr(dStrlwr(name), "collision-"))
{
shapeinst->animate(i);
shapeinst->setCurrentDetail(i);
shapeinst->setStatics(i);
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
S32 start = shapeinst->getShape()->subShapeFirstObject[ss];
S32 end = shapeinst->getShape()->subShapeNumObjects[ss] + start;
if (start < end)
{
// Run through objects and collide
for (S32 j = start; j < end; j++)
{
TSShapeInstance::MeshObjectInstance * mesh = &shapeinst->mMeshObjects[j];
if (od >= mesh->object->numMeshes)
continue;
ConcretePolyList polys;
// Get a valid transform for the polylist
MatrixF* mat = mesh->getTransform();
MatrixF m;
if(mat)
m = *mat;
else
m.identity();
polys.setTransform(&m, Point3F(1.0f, 1.0f, 1.0f));
// collide...
U32 surfaceKey = 0;
mesh->buildPolyList(od, &polys, surfaceKey);
if (polys.mPolyList.size() == 0)
continue;
// Now build our actual ConvexBrush
ConvexBrush* hull = new ConvexBrush;
for (U32 k = 0; k < polys.mPolyList.size(); k++)
{
ConcretePolyList::Poly& srcPoly = polys.mPolyList[k];
OptimizedPolyList::Poly dstPoly;
dstPoly.plane = hull->mFaces.addPlane(srcPoly.plane);
dstPoly.vertexStart = hull->mFaces.mIndexList.size();
dstPoly.vertexCount = srcPoly.vertexCount;
for (U32 m = 0; m < srcPoly.vertexCount; m++)
{
U32 srcIndex = polys.mIndexList[srcPoly.vertexStart + m];
Point3F& pt = polys.mVertexList[srcIndex];
U32 dstIndex = hull->mFaces.addPoint(pt);
hull->mFaces.mIndexList.push_back(dstIndex);
}
dstPoly.textureData.texture = StringTable->insert("null");
dstPoly.isNull = true;
hull->mFaces.setUpTextureMatrix(dstPoly);
hull->mFaces.mPolyList.push_back(dstPoly);
}
// We need to do a merging pass on the polylist since TSMesh's
// buildPolyList returns a list of individual triangles
// Setup the surface id's
for (U32 k = 0; k < hull->mFaces.mPlaneList.size(); k++)
{
for (U32 m = 0; m < hull->mFaces.size(); m++)
{
OptimizedPolyList::Poly& poly = hull->mFaces[m];
if (poly.plane == k)
poly.surfaceID = k;
}
}
// And do the actual merge
hull->mFaces.mergeSurfaces();
// Need to do a couple operations on our ConvexBrush
hull->mFaces.generateEdgelist();
hull->calcBounds();
hull->calcCentroid();
hull->mStatus = ConvexBrush::Good;
hull->mType = InteriorMapResource::Detail;
hull->mBrushScale = 32.0f;
// And now push it back into our collisionHulls list
currentMesh->collisionHulls.push_back(hull);
}
}
}
}
shapeinst->clearStatics();
delete shapeinst;
return true;
}
/*bool ConstructorSimpleMeshLoader::loadDirectXFile(Stream *stream)
{
return false;
}*/
ConsoleFunction(SimpleMeshLoader_createTriStrip, bool, 3, 3, "bool SimpleMeshLoader_createTriStrip(textureFileName, transparent)")
{
ConstructorSimpleMesh *mesh = ConstructorSimpleMeshLoader::currentMesh;
if(!mesh)
return false;
if(!mesh->materialList)
mesh->materialList = new TSMaterialList();
mesh->materialList->push_back(argv[2], 0);
mesh->primitives.increment();
ConstructorSimpleMesh::primitive &prim = mesh->primitives.last();
prim.start = mesh->indices.size();
prim.count = 0;
prim.diffuseIndex = mesh->materialList->size() - 1;
TextureHandle &tex = mesh->materialList->getMaterial(prim.diffuseIndex);
prim.diffuseId = tex.getGLName();
prim.lightMapId = 0;
prim.lightMapIndex = 0;
prim.alpha = ((dAtoi(argv[2]) == 1) || (dStrcmp(argv[2], "true") == 0));
prim.texS = GL_REPEAT;
prim.texT = GL_REPEAT;
return true;
}
ConsoleFunction(SimpleMeshLoader_createVert, bool, 4, 4, "bool SimpleMeshLoader_createVert(pos, norm, uv)")
{
ConstructorSimpleMesh *mesh = ConstructorSimpleMeshLoader::currentMesh;
if(!mesh || (mesh->primitives.size() < 1))
return false;
Point3F pos, norm;
Point2F uv;
dSscanf(argv[1], "%f %f %f", &pos.x, &pos.y, &pos.z);
dSscanf(argv[2], "%f %f %f", &norm.x, &norm.y, &norm.z);
dSscanf(argv[3], "%f %f", &uv.x, &uv.y);
ConstructorSimpleMesh::primitive &prim = mesh->primitives.last();
prim.count++;
mesh->indices.increment();
mesh->indices.last() = mesh->verts.size();
mesh->verts.increment();
mesh->verts.last() = pos;
mesh->norms.increment();
mesh->norms.last() = norm;
mesh->diffuseUVs.increment();
mesh->diffuseUVs.last() = uv;
mesh->lightmapUVs.increment();
return true;
}
#endif