//----------------------------------------------------------------------------- // 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; pt = 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; pgetMaterial(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 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; imMeshObjects[i].getMesh(od); MatrixF *mat = shapeinst->mMeshObjects[i].getTransform(); if(!mesh) continue; MatrixF m; if(mat) m = *mat; else m.identity(); ToolVector *vertsp; ToolVector *normsp; TSSkinMesh *smesh = dynamic_cast(mesh); if(smesh) { vertsp = &smesh->initialVerts; normsp = &smesh->initialNorms; } else { vertsp = &mesh->verts; normsp = &mesh->norms; } ToolVector &verts = *vertsp; ToolVector &norms = *normsp; for(U32 p=0; pprimitives.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 -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 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