//----------------------------------------------------------------------------- // Copyright (c) 2012 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "platform/platform.h" #include "interior/interiorSimpleMesh.h" #include "interior/interiorLMManager.h" #include "interior/interior.h" #include "console/console.h" #include "scene/sceneObject.h" #include "math/mathIO.h" #include "materials/matInstance.h" #include "materials/materialManager.h" #include "scene/sceneManager.h" #include "scene/sceneRenderState.h" #include "ts/tsShape.h" #include "gfx/bitmap/gBitmap.h" Vector *InteriorSimpleMesh::renderInstList = new Vector(); // 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 InteriorSimpleMesh::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 InteriorSimpleMesh::castPlanes(PlaneF left, PlaneF right, PlaneF top, PlaneF bottom) { for(U32 p=0; pmPrimitiveCount == packedPrimitives.size()), "Primitive mismatch"); renderInstList->clear(); for(S32 i=0; igetRenderPass()->allocInst(); *inst = copyinst; inst->matInst = materialList->getMaterialInst(draw.diffuseIndex); if(!inst->matInst) inst->matInst = MATMGR->getWarningMatInstance(); if(!inst->matInst) continue; inst->primBuffIndex = i; inst->primBuff = &primBuff; inst->vertBuff = &vertBuff; if(draw.alpha) { inst->translucentSort = true; inst->type = RenderPassManager::RIT_Translucent; } inst->lightmap = gInteriorLMManager.getHandle(interiorlmhandle, instancelmhandle, draw.lightMapIndex); state->getRenderPass()->addInst(inst); renderInstList->push_back(inst); } if(lightingplugin && renderInstList->size() > 0) { if(lightingplugin->interiorInstInit(intInst, this)) { if(lightingplugin->allZoneInit()) { Vector &list = *renderInstList; // clone the origial instances to avoid damaging the originals' data for(int i=0; isize(); i++) { MeshRenderInst *inst = state->getRenderPass()->allocInst(); const MeshRenderInst *oldinst = list[i]; *inst = *oldinst; list[i] = inst; } lightingplugin->processRI(state, list); } } } */ } bool InteriorSimpleMesh::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 = 25; 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++) { // need to read these bool hasBitmap = false; stream.read(&hasBitmap); if(hasBitmap) { GBitmap* bitMap = new GBitmap; bitMap->readBitmap("png",stream); delete bitMap; } } // Misc data stream.read(&hasSolid); stream.read(&hasTranslucency); mathRead(stream, &bounds); mathRead(stream, &transform); mathRead(stream, &scale); calculateBounds(); buildBuffers(); return true; } bool InteriorSimpleMesh::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->size()); for (U32 i = 0; i < materialList->size(); i++) { GFXTexHandle handle(materialList->getDiffuseTexture(i)); if (handle.isValid()) { GBitmap* bitMap = handle.getBitmap(); if (bitMap) { stream.write(true); bitMap->writeBitmap("png",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; } void InteriorSimpleMesh::buildBuffers() { bool flipped = false; MatrixF trans = transform; trans.scale(scale); Point3F r0, r1, r2; trans.getRow(0, &r0); trans.getRow(1, &r1); trans.getRow(2, &r2); F32 det = r0.x * (r1.y * r2.z - r1.z * r2.y) - r0.y * (r1.x * r2.z - r1.z * r2.x) + r0.z * (r1.x * r2.y - r1.y * r2.x); flipped = det < 0.0f; // setup the repack vectors packedIndices.clear(); packedPrimitives.clear(); packedIndices.reserve(indices.size() * 2); packedPrimitives.reserve(primitives.size()); Vector addedprim; addedprim.setSize(primitives.size()); dMemset(addedprim.address(), 0, (addedprim.size() * sizeof(bool))); Vector tang; Vector binorm; tang.setSize(verts.size()); binorm.setSize(verts.size()); dMemset(tang.address(), 0, (tang.size() * sizeof(Point3F))); dMemset(binorm.address(), 0, (binorm.size() * sizeof(Point3F))); // fill the repack vectors for(U32 p=0; p packedprims; packedprims.setSize(packedPrimitives.size()); for(U32 i=0; i packedIndices[prim.start + ii]) p.minIndex = packedIndices[prim.start + ii]; if(maxindex < packedIndices[prim.start + ii]) maxindex = packedIndices[prim.start + ii]; } // D3D voodoo - not the actual numverts, only the max span (maxindex - minindex) - this needs a better variable name... p.numVertices = (maxindex - p.minIndex) + 1; } // create vb style sysmem buffer Vector packedverts; packedverts.setSize(verts.size()); // fill it for(U32 i=0; i &tang, Vector &binorm) { const Point3F& va = verts[i0]; const Point3F& vb = verts[i1]; const Point3F& vc = verts[i2]; const Point2F& uva = diffuseUVs[i0]; const Point2F& uvb = diffuseUVs[i1]; const Point2F& uvc = diffuseUVs[i2]; float x1 = vb.x - va.x; float x2 = vc.x - va.x; float y1 = vb.y - va.y; float y2 = vc.y - va.y; float z1 = vb.z - va.z; float z2 = vc.z - va.z; float s1 = uvb.x - uva.x; float s2 = uvc.x - uva.x; float t1 = uvb.y - uva.y; float t2 = uvc.y - uva.y; F32 denom = (s1 * t2 - s2 * t1); if(fabs(denom) < 0.0001) return; float r = 1.0F / denom; Point3F s((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); Point3F t((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); tang[i0] += s; tang[i1] += s; tang[i2] += s; binorm[i0] += t; binorm[i1] += t; binorm[i2] += t; } void InteriorSimpleMesh::packPrimitive(primitive &primnew, const primitive &primold, Vector &indicesnew, bool flipped, Vector &tang, Vector &binorm) { // convert from strip to list and add to primnew for(U32 p=2; pload(InteriorTexture, path, false); materialList->mapMaterials(); // GFX2_RENDER_MERGE materialList->initMatInstances( MATMGR->getDefaultFeatures(), getGFXVertexFormat() ); return true; }