diff --git a/Client/App/App.vcproj b/Client/App/App.vcproj index d37b5c48..9130c10e 100644 --- a/Client/App/App.vcproj +++ b/Client/App/App.vcproj @@ -797,6 +797,10 @@ RelativePath=".\include\v8datamodel\Camera.h" > + + @@ -1302,6 +1306,10 @@ RelativePath=".\v8datamodel\Camera.cpp" > + + @@ -1388,7 +1396,6 @@ diff --git a/Client/App/include/v8datamodel/CustomMesh.h b/Client/App/include/v8datamodel/CustomMesh.h new file mode 100644 index 00000000..b5be1147 --- /dev/null +++ b/Client/App/include/v8datamodel/CustomMesh.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include "reflection/reflection.h" +#include "util/MeshId.h" +#include "util/TextureId.h" +#include "v8tree/Instance.h" + +namespace RBX { + extern const char* sSpecialMesh; + + class SpecialShape : public RBX::DescribedCreatable + { + public: + enum MeshType + { + HEAD_MESH, + TORSO_MESH, + WEDGE_MESH, + SPHERE_MESH, + CYLINDER_MESH, + FILE_MESH, + BRICK_MESH + }; + + private: + MeshType meshType; + G3D::Vector3 scale; + TextureId textureId; + MeshId meshId; + G3D::Vector3 vertColor; + public: + SpecialShape(); + const MeshType getMeshType() const + { + return meshType; + } + void setMeshType(MeshType value); + const G3D::Vector3& getScale() const + { + return scale; + } + void setScale(const G3D::Vector3& value); + const G3D::Vector3& getVertColor() const + { + return vertColor; + } + void setVertColor(const G3D::Vector3& value); + const float getAlpha() const; + + const MeshId getMeshId() const + { + return meshId; + } + + void setMeshId(const MeshId& value); + const TextureId getTextureId() const + { + return textureId; + } + void setTextureId(const TextureId& value); + protected: + virtual bool askSetParent(const Instance*) const; + }; + +}; \ No newline at end of file diff --git a/Client/App/include/v8datamodel/Decal.h b/Client/App/include/v8datamodel/Decal.h index b3c7a80a..d23010ff 100644 --- a/Client/App/include/v8datamodel/Decal.h +++ b/Client/App/include/v8datamodel/Decal.h @@ -3,10 +3,12 @@ #include "reflection/reflection.h" #include "v8datamodel/FaceInstance.h" #include "util/TextureId.h" +#include namespace RBX { extern const char* sDecal; + extern const char* sTexture; class Decal : public DescribedCreatable { @@ -20,11 +22,50 @@ namespace RBX static const Reflection::PropDescriptor prop_Shiny; Decal(); - TextureId getTexture() const; + TextureId getTexture() const + { + return texture; + } + void setTexture(TextureId); - float getSpecular() const; + + float getSpecular() const + { + return specular; + } + void setSpecular(float); - float getShiny() const; + + float getShiny() const + { + return shiny; + } void setShiny(float); }; + + class Texture : public DescribedCreatable + { + private: + G3D::Vector2 studsPerTile; + public: + static const Reflection::PropDescriptor prop_StudsPerTileU; + static const Reflection::PropDescriptor prop_StudsPerTileV; + + Texture(); + const G3D::Vector2& getStudsPerTile() + { + return studsPerTile; + } + + float getStudsPerTileU() const + { + return studsPerTile.x; + } + void setStudsPerTileU(float value); + float getStudsPerTileV() const + { + return studsPerTile.y; + } + void setStudsPerTileV(float value); + }; }; \ No newline at end of file diff --git a/Client/App/include/v8datamodel/FaceInstance.h b/Client/App/include/v8datamodel/FaceInstance.h index 79161332..09f82ff3 100644 --- a/Client/App/include/v8datamodel/FaceInstance.h +++ b/Client/App/include/v8datamodel/FaceInstance.h @@ -15,7 +15,10 @@ namespace RBX public: static const Reflection::EnumPropDescriptor prop_Face; FaceInstance(); - NormalId getFace() const; + NormalId getFace() const + { + return face; + } void setFace(NormalId); protected: virtual bool askSetParent(const Instance*) const; diff --git a/Client/App/v8datamodel/CustomMesh.cpp b/Client/App/v8datamodel/CustomMesh.cpp new file mode 100644 index 00000000..4eadce7d --- /dev/null +++ b/Client/App/v8datamodel/CustomMesh.cpp @@ -0,0 +1,95 @@ +#include "v8datamodel/CustomMesh.h" +#include "v8datamodel/PartInstance.h" +namespace RBX +{ + const char* sSpecialMesh = "SpecialMesh"; + static const Reflection::EnumPropDescriptor desc_meshType("MeshType", "Data", &SpecialShape::getMeshType, &SpecialShape::setMeshType, Reflection::EnumPropertyDescriptor::STANDARD); + static const Reflection::PropDescriptor desc_scale("Scale", "Data", &SpecialShape::getScale, &SpecialShape::setScale, Reflection::PropertyDescriptor::STANDARD); + static const Reflection::PropDescriptor desc_meshId("MeshId", "Data", &SpecialShape::getMeshId, &SpecialShape::setMeshId, Reflection::PropertyDescriptor::STANDARD); + static const Reflection::PropDescriptor desc_textureId("TextureId", "Data", &SpecialShape::getTextureId, &SpecialShape::setTextureId, Reflection::PropertyDescriptor::STANDARD); + static const Reflection::PropDescriptor desc_vertColor("VertexColor", "Data", &SpecialShape::getVertColor, &SpecialShape::setVertColor, Reflection::PropertyDescriptor::STANDARD); + + const float SpecialShape::getAlpha() const + { + if (getParent()) + { + PartInstance* part = fastDynamicCast(getParent()); + + if (part) + { + return part->getTransparencyUi(); + } + } + return 0.0f; + } + + SpecialShape::SpecialShape() + : meshType(HEAD_MESH), + scale(1.0f, 1.0f, 1.0f), + textureId(), + meshId(), + vertColor(1.0f, 1.0f, 1.0f) + { + setName("Mesh"); + } + + void SpecialShape::setMeshType(MeshType value) + { + if (meshType != value) + { + meshType = value; + raisePropertyChanged(desc_meshType); + } + } + + void SpecialShape::setScale(const G3D::Vector3& value) + { + if (scale != value) + { + scale = value; + raisePropertyChanged(desc_scale); + } + } + + void SpecialShape::setVertColor(const G3D::Vector3& value) + { + if (vertColor != value) + { + vertColor = value; + raisePropertyChanged(desc_vertColor); + } + } + + void SpecialShape::setMeshId(const MeshId& value) + { + if (meshId != value) + { + meshId = value; + raisePropertyChanged(desc_meshId); + if (meshType != FILE_MESH) + { + meshType = FILE_MESH; + raisePropertyChanged(desc_meshType); + } + } + } + + void SpecialShape::setTextureId(const TextureId& value) + { + if (textureId != value) + { + textureId = value; + raisePropertyChanged(desc_textureId); + if (meshType != FILE_MESH) + { + meshType = FILE_MESH; + raisePropertyChanged(desc_meshType); + } + } + } + + bool SpecialShape::askSetParent(const Instance* instance) const + { + return fastDynamicCast(instance) != NULL; + } +}; \ No newline at end of file diff --git a/Client/App/v8datamodel/Decal.cpp b/Client/App/v8datamodel/Decal.cpp index 3cf561b8..158628d0 100644 --- a/Client/App/v8datamodel/Decal.cpp +++ b/Client/App/v8datamodel/Decal.cpp @@ -6,9 +6,12 @@ namespace RBX { const char* sDecal = "Decal"; + const char* sTexture = "Texture"; const Reflection::PropDescriptor Decal::prop_Texture("Texture", "Appearance", &Decal::getTexture, &Decal::setTexture, Reflection::PropertyDescriptor::STANDARD); const Reflection::PropDescriptor Decal::prop_Specular("Specular", "Appearance", &Decal::getSpecular, &Decal::setSpecular, Reflection::PropertyDescriptor::STANDARD); const Reflection::PropDescriptor Decal::prop_Shiny("Shiny", "Appearance", &Decal::getShiny, &Decal::setShiny, Reflection::PropertyDescriptor::STANDARD); + const Reflection::PropDescriptor Texture::prop_StudsPerTileU("StudsPerTileU", "Appearance", &Texture::getStudsPerTileU, &Texture::setStudsPerTileU, Reflection::PropertyDescriptor::STANDARD); + const Reflection::PropDescriptor Texture::prop_StudsPerTileV("StudsPerTileV", "Appearance", &Texture::getStudsPerTileV, &Texture::setStudsPerTileV, Reflection::PropertyDescriptor::STANDARD); Decal::Decal() :texture(), @@ -17,21 +20,6 @@ namespace RBX { setName("Decal"); } - - float Decal::getShiny() const - { - return shiny; - } - - float Decal::getSpecular() const - { - return specular; - }; - - TextureId Decal::getTexture() const - { - return texture; - } void Decal::setTexture(TextureId value) { @@ -59,4 +47,28 @@ namespace RBX raisePropertyChanged(prop_Shiny); } } + + void Texture::setStudsPerTileU(float value) + { + if (studsPerTile.x != value && value > 0.0f) + { + studsPerTile.x = value; + raisePropertyChanged(prop_StudsPerTileU); + } + } + + void Texture::setStudsPerTileV(float value) + { + if (studsPerTile.y != value && value > 0.0f) + { + studsPerTile.y = value; + raisePropertyChanged(prop_StudsPerTileV); + } + } + + Texture::Texture() + : studsPerTile(2.0f, 2.0f) + { + setName("Texture"); + } }; \ No newline at end of file diff --git a/Client/App/v8datamodel/FaceInstance.cpp b/Client/App/v8datamodel/FaceInstance.cpp index 225c61cb..14f7a8b3 100644 --- a/Client/App/v8datamodel/FaceInstance.cpp +++ b/Client/App/v8datamodel/FaceInstance.cpp @@ -22,12 +22,6 @@ namespace RBX } } - - NormalId FaceInstance::getFace() const - { - return face; - } - bool FaceInstance::askSetParent(const Instance* instance) const { return fastDynamicCast(instance) != NULL; diff --git a/Client/RbxView/FileMesh.cpp b/Client/RbxView/FileMesh.cpp index 1c1324ea..db8a3694 100644 --- a/Client/RbxView/FileMesh.cpp +++ b/Client/RbxView/FileMesh.cpp @@ -1,10 +1,61 @@ #include "FileMesh.h" #include +#include "util/ContentProvider.h" +#include namespace RBX { namespace View { + //44.36% matching + //a *start* + bool FileMesh::loadFromMeshFile(const G3D::Vector3 &scale, const RBX::MeshId meshFile) + { + std::string fileName; + int num_faces; + if (!RBX::ContentProvider::singleton().requestContentFile(meshFile, fileName)) + { + return false; + } + Render::Mesh::Level* level = new Render::Mesh::Level(G3D::RenderDevice::TRIANGLES); + levels.append(level); + + FILE* fp = fopen(fileName.c_str(), "r"); + fscanf(fp, "version 1.00\n"); + fscanf(fp, "%d\n", num_faces); + + std::vector verts; + for (int i = 0; i < num_faces; i++) + { + for (int j = 0; j < 3; j++) + { + float vtxX, vtxY, vtxZ, normX, normY, normZ, texU, texV, texW; + fscanf(fp, "[%f,%f,%f][%f,%f,%f][%f,%f,%f]", &vtxX, &vtxY, &vtxZ, &normX, &normY, &normZ, &texU, &texV, &texW); + G3D::Vector3 vert(vtxX * 0.5f, vtxY * 0.5f, vtxY * 0.5f); + G3D::Vector2 tex(texU, 1.0f - texV); + G3D::Vector3 norm(normX, normY, normZ); + vert *= scale; + unsigned int vtx1 = allocVertex(vert, norm, tex, true); + verts.push_back(vtx1); + unsigned int vtx2 = allocVertex(i, 1); + verts.push_back(vtx2); + unsigned int vtx3 = allocVertex(i, 1); + verts.push_back(vtx3); + unsigned int vtx4 = allocVertex(i, 1); + verts.push_back(vtx4); + level->indexArray.append(vtx1, vtx2, vtx3, vtx4); + + for (int k = 0; k < 3; k++) + { + freeVertex(verts[k]); + } + + verts.clear(); + } + } + return true; + } + G3D::ReferenceCountedPointer FileMesh::create(const G3D::Vector3& scale, const MeshId meshFile) { FileMesh* newMesh = new FileMesh; diff --git a/Client/RbxView/HeadMesh.cpp b/Client/RbxView/HeadMesh.cpp index be956568..5dd2c929 100644 --- a/Client/RbxView/HeadMesh.cpp +++ b/Client/RbxView/HeadMesh.cpp @@ -5,7 +5,11 @@ class CylinderTransform const float bevel; const int halfVertexCount; public: - CylinderTransform(float, int); + CylinderTransform(float bevel, int halfVertexCount) + : bevel(bevel), + halfVertexCount(halfVertexCount) + { + } void operator()(G3D::Vector3&, G3D::Vector3&, G3D::Vector2&, const G3D::Vector3&, const G3D::Vector2int16&); }; @@ -19,3 +23,98 @@ class EndcapTransform } void operator()(G3D::Vector3&, G3D::Vector3&, G3D::Vector2&, const G3D::Vector3&, const G3D::Vector2int16&); }; + +//72.86% matching +//Weird stuff with the size setting +inline G3D::Vector3 getSizeMax(const G3D::Vector3& v) { + float maxSizeX = G3D::min(v.x, v.z); + float maxSizeZ = G3D::min(v.x, v.z); + + G3D::Vector3 newVec; + newVec.x = maxSizeX; + newVec.y = v.y; + newVec.z = maxSizeZ; + + return newVec; +} + +HeadBuilder::HeadBuilder(G3D::ReferenceCountedPointer level, G3D::Vector3 size, RBX::View::RenderSurfaceTypes surfaceTypes, size_t elements, float bevel) +: LevelBuilder(level, getSizeMax(size), surfaceTypes), + elements(elements), + bevel(bevel) +{ +} + +void HeadBuilder::buildTop(RBX::View::LevelBuilder::Purpose purpose) { + int e = elements; + buildFace(EndcapTransform(bevel), G3D::Vector2int16(e, e), purpose); +} + +void HeadBuilder::buildBottom(RBX::View::LevelBuilder::Purpose purpose) { + int e = elements; + buildFace(EndcapTransform(bevel), G3D::Vector2int16(e, e), purpose); +} + +//77.81% matching +void HeadBuilder::buildLeft(RBX::View::LevelBuilder::Purpose purpose) { + int e = elements; + buildFace(CylinderTransform(bevel, e / 2), G3D::Vector2int16(e, e), purpose); +} + +//77.81% matching +void HeadBuilder::buildRight(RBX::View::LevelBuilder::Purpose purpose) { + int e = elements; + buildFace(CylinderTransform(bevel, e / 2), G3D::Vector2int16(e, e), purpose); +} + +//77.81% matching +void HeadBuilder::buildFront(RBX::View::LevelBuilder::Purpose purpose) { + int e = elements; + buildFace(CylinderTransform(bevel, e / 2), G3D::Vector2int16(e, e), purpose); +}; + +//77.81% matching +void HeadBuilder::buildBack(RBX::View::LevelBuilder::Purpose purpose) { + int e = elements; + buildFace(CylinderTransform(bevel, e / 2), G3D::Vector2int16(e, e), purpose); +} + +namespace RBX { + namespace View { + + HeadMesh::HeadMesh(const G3D::Vector3& size, NormalId decalFace) + { + float bevel = G3D::min(size.x, size.z); + bevel *= 0.25f; + Render::Mesh::Level* level = new Render::Mesh::Level(G3D::RenderDevice::QUADS); + levels.push_back(level); + + HeadBuilder builder(level, size, RenderSurfaceTypes(), 9, bevel); + builder.buildFace(decalFace, LevelBuilder::Decal); + } + + HeadMesh::HeadMesh(const G3D::Vector3& size, NormalId textureFace, const G3D::Vector2& studsPerTile) + { + float bevel = G3D::min(size.x, size.z); + bevel *= 0.25f; + Render::Mesh::Level* level = new Render::Mesh::Level(G3D::RenderDevice::QUADS); + levels.push_back(level); + + HeadBuilder builder(level, size, RenderSurfaceTypes(), 9, bevel); + builder.textureScale = mapToUvw_Legacy(size, textureFace).xy() * 2.0f / studsPerTile; + + builder.buildFace(textureFace, LevelBuilder::Decal); + } + + HeadMesh::HeadMesh(const G3D::Vector3& partSize, RenderSurfaceTypes surfaceTypes) + { + float bevel = G3D::min(partSize.x, partSize.z); + bevel *= 0.25f; + levels.push_back(new Render::Mesh::Level(G3D::RenderDevice::QUADS)); + + G3D::ReferenceCountedPointer level = levels.last(); + HeadBuilder builder(level, partSize, surfaceTypes, 9, bevel); + builder.build(LevelBuilder::Surface); + } + }; +}; \ No newline at end of file diff --git a/Client/RbxView/MaterialFactory.h b/Client/RbxView/MaterialFactory.h index 0149eaea..f78ed5c4 100644 --- a/Client/RbxView/MaterialFactory.h +++ b/Client/RbxView/MaterialFactory.h @@ -9,6 +9,7 @@ namespace RBX { class MaterialFactory { + public: struct Attributes { const BrickColor color; diff --git a/Client/RbxView/Part.cpp b/Client/RbxView/Part.cpp index fd4f341c..d8ae825e 100644 --- a/Client/RbxView/Part.cpp +++ b/Client/RbxView/Part.cpp @@ -1 +1,652 @@ -#include "stdafx.h" +#include "Part.h" +#include "v8tree/Instance.h" +#include "reflection/property.h" +#include "v8datamodel/Surfaces.h" +#include "v8datamodel/CustomMesh.h" +#include "v8datamodel/Workspace.h" +#include "v8datamodel/FaceInstance.h" +#include "v8datamodel/Decal.h" +#include +#include +#include +#include "RbxView/View.h" +#include "RenderLib/RenderScene.h" +#include "QuadVolume.h" +#include "BrickMesh.h" +#include "HeadMesh.h" +#include "CylinderMesh.h" +#include "FileMesh.h" +#include "SphereMesh.h" +#include "PBBMesh.h" +#include "WedgeMesh.h" +#include "TorsoMesh.h" +#include "MeshFactory.h" +#include "MaterialFactory.h" + +namespace RBX { + namespace View { + const G3D::CoordinateFrame& PartChunk::cframe() + { + coordinateFrame = partInstance->getCoordinateFrame(); + return coordinateFrame; + } + + void PartChunk::onSpecialShapeChanged() + { + invalidateMesh(); + invalidateMaterial(); + } + + G3D::ReferenceCountedPointer PartChunk::getMesh() + { + if (mesh.isNull()) + updateMesh(); + + return mesh; + } + + void PartChunk::onChildRemoved(boost::shared_ptr child) + { + if (child.px == (Instance*)specialShape) + { + shapePropertyChangedConnection.disconnect(); + specialShape = NULL; + invalidateMesh(); + } + } + + void PartChunk::onPropertyChanged(const RBX::Reflection::PropertyDescriptor* descriptor) + { + if (descriptor == &RBX::PartInstance::prop_Size) + { + invalidateMesh(); + invalidateMaterial(); + return; + } + + //this could be an inline + if (descriptor == &RBX::PartInstance::prop_shapeXml) { + invalidateMesh(); + return; + } else if (RBX::Surfaces::isSurfaceDescriptor(*descriptor)) { + invalidateMesh(); + } + } + + //97.33% matching + void PartChunk::onChildAdded(boost::shared_ptr child) + { + RBX::SpecialShape* shape = RBX::Instance::fastDynamicCast(child.get()); + if (shape) { + specialShape = shape; + //This line is the cause + //If I move the boost::slot, that causes even more mismatches + shapePropertyChangedConnection = RBX::Instance::event_propertyChanged.connect(specialShape, boost::slot>(boost::bind(&PartChunk::onSpecialShapeChanged, this))); + invalidateMesh(); + } + } + + //99.81% matching + void PartChunk::onAncestorChanged(boost::shared_ptr ancestor) + { + RBX::Workspace* workspace = RBX::Workspace::findWorkspace(partInstance.px); + RBX::Instance* parent; + + //the issue seems to be lie with the parent = partInstance.get()->getParent(), however the parent check needs to be after the workspace check + if (!workspace || (parent = partInstance.get()->getParent(), workspace == parent) || !parent || !parent->isDescendentOf(workspace)) + { + view->sceneManager->removeModel(this); + } + } + + PartChunk::~PartChunk() {} + + void PartChunk::invalidateMesh() + { + mesh = NULL; + view->sceneManager->invalidateModel(this, partInstance.get()->getCanAggregate()); + } + + void PartChunk::invalidateMaterial() + { + material = NULL; + materialInvalid = true; + view->sceneManager->invalidateModel(this, partInstance.get()->getCanAggregate()); + } + + PartChunk::PartChunk(float polygonOffset, const boost::shared_ptr &partInstance, RBX::View::View *view) + : Chunk(polygonOffset), + coordinateFrame(), + childAddedConnection(), + childRemovedConnection(), + ancestorChangedConnection(), + propertyChangedConnection(), + shapePropertyChangedConnection(), + partInstance(partInstance), + material(), + materialInvalid(true), + mesh(), + view(view), + specialShape() + { + view->sceneManager->addModel(this); + childAddedConnection = RBX::Instance::event_childAdded.connect(specialShape, boost::slot)>>(boost::bind(&PartChunk::onChildAdded, this, _1))); + childRemovedConnection = RBX::Instance::event_childRemoved.connect(specialShape, boost::slot)>>(boost::bind(&PartChunk::onChildRemoved, this, _1))); + ancestorChangedConnection = RBX::Instance::event_ancestryChanged.connect(specialShape, boost::slot)>>(boost::bind(&PartChunk::onAncestorChanged, this, _1))); + propertyChangedConnection = RBX::Instance::event_propertyChanged.connect(specialShape, boost::slot>(boost::bind(&PartChunk::onPropertyChanged, this, _1))); + //RBX::Instance::visitChildren call + } + + bool Part::usesMegaTexture() const + { + if (!specialShape) + { + RBX::PartInstance* px = partInstance.get(); + + if (px->getPartType() != RBX::Part::BLOCK_PART) + return false; + + G3D::Vector3 size = px->getPartSizeXml(); + return primaryComponent(size) < 30.0f; + } + + return false; + } + + void Part::onPropertyChanged(const RBX::Reflection::PropertyDescriptor *descriptor) + { + if (descriptor == &RBX::PartInstance::prop_Size) + { + invalidateMesh(); + invalidateMaterial(); + } else if (descriptor == &RBX::PartInstance::prop_shapeXml) + { + invalidateMesh(); + } else if (RBX::Surfaces::isSurfaceDescriptor(*descriptor)) + { + invalidateMesh(); + } + + if (descriptor == &RBX::PartInstance::prop_Color) + { + if (usesMegaTexture()) + { + invalidateMesh(); + invalidateMaterial(); + return; + } + } else if (descriptor != &RBX::PartInstance::prop_Transparency && descriptor != &RBX::PartInstance::prop_Reflectance) + return; + + invalidateMaterial(); + } + + void Part::onEvent(const RBX::PartInstance *source, RBX::CanAggregateChanged event) + { + //having to do with RBX::Notifier in specialShape + } + + //73.90% matching + //pretty messy + //setSurfaceType for RenderSurfaceTypes will need to be defined for 100% + //also the switch case could be apart of an inline? not too sure + void Part::updateMesh() + { + RenderSurfaceType curSurface; + + RenderSurfaceTypes surfaceTypes; + + switch(partInstance.get()->getSurfaces()[NORM_X].getSurfaceType()) + { + case STUDS: + curSurface = STUDS; + break; + case INLET: + curSurface = INLET; + break; + case WELD: + curSurface = WELD; + break; + case GLUE: + curSurface = GLUE; + break; + default: + curSurface = FLAT; + break; + } + surfaceTypes.setSurfaceType(NORM_X, curSurface); + switch(partInstance.get()->getSurfaces()[NORM_Y].getSurfaceType()) + { + case STUDS: + curSurface = STUDS; + break; + case INLET: + curSurface = INLET; + break; + case WELD: + curSurface = WELD; + break; + case GLUE: + curSurface = GLUE; + break; + default: + curSurface = FLAT; + break; + } + surfaceTypes.setSurfaceType(NORM_Y, curSurface); + switch(partInstance.get()->getSurfaces()[NORM_Z].getSurfaceType()) + { + case STUDS: + curSurface = STUDS; + break; + case INLET: + curSurface = INLET; + break; + case WELD: + curSurface = WELD; + break; + case GLUE: + curSurface = GLUE; + break; + default: + curSurface = FLAT; + break; + } + surfaceTypes.setSurfaceType(NORM_Z, curSurface); + switch(partInstance.get()->getSurfaces()[NORM_X_NEG].getSurfaceType()) + { + case STUDS: + curSurface = STUDS; + break; + case INLET: + curSurface = INLET; + break; + case WELD: + curSurface = WELD; + break; + case GLUE: + curSurface = GLUE; + break; + default: + curSurface = FLAT; + break; + } + surfaceTypes.setSurfaceType(NORM_X_NEG, curSurface); + switch(partInstance.get()->getSurfaces()[NORM_Y_NEG].getSurfaceType()) + { + case STUDS: + curSurface = STUDS; + break; + case INLET: + curSurface = INLET; + break; + case WELD: + curSurface = WELD; + break; + case GLUE: + curSurface = GLUE; + break; + default: + curSurface = FLAT; + break; + } + surfaceTypes.setSurfaceType(NORM_Y_NEG, curSurface); + switch(partInstance.get()->getSurfaces()[NORM_Z_NEG].getSurfaceType()) + { + case STUDS: + curSurface = STUDS; + break; + case INLET: + curSurface = INLET; + break; + case WELD: + curSurface = WELD; + break; + case GLUE: + curSurface = GLUE; + break; + default: + curSurface = FLAT; + break; + } + surfaceTypes.setSurfaceType(NORM_Z_NEG, curSurface); + + G3D::Vector3 size = partInstance.get()->getPartSizeXml(); + + if (usesMegaTexture()) + { + mesh = RBX::View::BrickMesh::create(size, surfaceTypes, partInstance.get()->getColor()); + } else if (partInstance.get()->getPartType()) + { + switch (partInstance.get()->getPartType()) + { + case RBX::Part::CYLINDER_PART: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case RBX::Part::BLOCK_PART: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case RBX::Part::BALL_PART: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + } + } + + if (specialShape) + { + size *= specialShape->getScale(); + switch(specialShape->getMeshType()) + { + case SpecialShape::WEDGE_MESH: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case SpecialShape::HEAD_MESH: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case SpecialShape::TORSO_MESH: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case SpecialShape::SPHERE_MESH: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case SpecialShape::CYLINDER_MESH: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case SpecialShape::BRICK_MESH: + mesh = RBX::View::MeshFactory::create(size, surfaceTypes); + break; + case SpecialShape::FILE_MESH: + mesh = RBX::View::FileMesh::create(size, specialShape->getMeshId()); + break; + } + } + + radius = sqrt(2.0f) * 0.5 * primaryComponent(size); + } + + //34.14% matching + //also messy + G3D::ReferenceCountedPointer Part::getMaterial() + { + if (materialInvalid) + { + RBX::PartInstance* partInstancePX = partInstance.get(); + RBX::View::MaterialFactory::Attributes attributes = {partInstancePX->getColor(), partInstancePX->getTransparencyUi(), partInstancePX->getReflectance()}; + if (usesMegaTexture()) + { + material = view->materialFactory->getMegaMaterial(attributes); + } else if (!specialShape || specialShape->getMeshType() != SpecialShape::FILE_MESH) + { + material = view->materialFactory->getMaterial(attributes); + return material; + } + + std::string texFile; + if (RBX::ContentProvider::singleton().requestContentFile(specialShape->getTextureId(), texFile)) + { + G3D::Color3 vertColor = specialShape->getVertColor(); + float alpha = specialShape->getAlpha(); + + material = new RBX::Render::Material(); + RBX::Render::TextureProxy* texProxy = new RBX::Render::TextureProxy(*view->textureManager.get(), texFile, false); + material.getPointer()->appendLevel(texProxy, vertColor, 0.0f, 0.1f, 0.0f, partInstance.get()->getTransparencyUi()); + } else + { + material = view->materialFactory->getMaterial(attributes); + } + materialInvalid = false; + return material; + } + return material; + } + + //78.70% matching + Part::~Part() { + //has Notifier remove listener + } + + void Decal::onDecalPropertyChanged(const RBX::Reflection::PropertyDescriptor* descriptor) + { + if (descriptor == &FaceInstance::prop_Face) + { + invalidateMesh(); + } else if (descriptor == &RBX::Decal::prop_Texture || descriptor == &RBX::Decal::prop_Specular || descriptor == &RBX::Decal::prop_Shiny) + { + invalidateMaterial(); + } + } + + + //99.88% matching + void Decal::onDecalAncestorChanged(boost::shared_ptr ancestor) + { + RBX::Workspace* workspace = RBX::Workspace::findWorkspace(decal.get()); + RBX::Instance* parent; + + //same error as the PartChunk variant + if (!workspace || (parent = decal.get()->getParent(), workspace == parent) || !parent || !parent->isDescendentOf(workspace)) + { + view->sceneManager->removeModel(this); + } + } + + //38.85% matching + //would probably be way higher if it weren't for the fact that the part type switch case is above where it should be + //i legit don't know why it isn't in its proper position + void Decal::updateMesh() + { + if (partInstance.get()) + { + G3D::Vector3 size = partInstance->getPartSizeXml(); + if (specialShape) + { + size *= specialShape->getScale(); + } + + if (partInstance->getPartType()) + { + switch (partInstance->getPartType()) + { + case RBX::Part::CYLINDER_PART: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + case RBX::Part::BLOCK_PART: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + case RBX::Part::BALL_PART: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + } + } + + if (specialShape) + { + switch(specialShape->getMeshType()) + { + case SpecialShape::WEDGE_MESH: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + case SpecialShape::HEAD_MESH: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + case SpecialShape::TORSO_MESH: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + case SpecialShape::SPHERE_MESH: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + case SpecialShape::CYLINDER_MESH: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + case SpecialShape::BRICK_MESH: + mesh = RBX::View::MeshFactory::createDecal(size, decal->getFace()); + break; + default: + break; + } + } + radius = sqrt(2.0f) * 0.5 * primaryComponent(size); + } + } + + //75.61% matching + G3D::ReferenceCountedPointer Decal::getMaterial() + { + if (materialInvalid) + { + std::string textureFile; + if (RBX::ContentProvider::singleton().requestContentFile(decal->getTexture(), textureFile)) + { + RBX::Render::Material* newMat = new RBX::Render::Material(); + material = newMat; + RBX::Render::TextureProxy* texProxy = new RBX::Render::TextureProxy(*view->textureManager.get(), textureFile, false); + material->appendLevel(texProxy, G3D::Color3::WHITE, decal->getSpecular(), decal->getShiny(), 0.0f, 0.0f); + materialInvalid = false; + } + } + + return material; + } + + Decal::~Decal() {} + + //75.92% matching + //more boost connection problems + Decal::Decal(RBX::Decal &decal, RBX::PartInstance &partInstance, RBX::View::View *view) + : PartChunk(RBX::Render::Chunk::DECAL_OFFSET, RBX::shared_from(&partInstance), view), + decal(RBX::shared_from(&decal)), + decalAncestorChangedConnection(), + decalPropertyChangedConnection() + { + decalAncestorChangedConnection = RBX::Instance::event_ancestryChanged.connect(&decal, boost::slot)>>(boost::bind(&Decal::onDecalAncestorChanged, this, _1))); + decalPropertyChangedConnection = RBX::Instance::event_propertyChanged.connect(&decal, boost::slot>(boost::bind(&Decal::onDecalPropertyChanged, this, _1))); + } + + //99.88% matching + void Texture::onTextureAncestorChanged(boost::shared_ptr ancestor) + { + RBX::Workspace* workspace = RBX::Workspace::findWorkspace(texture.get()); + RBX::Instance* parent; + + //same error as the PartChunk variant + if (!workspace || (parent = texture.get()->getParent(), workspace == parent) || !parent || !parent->isDescendentOf(workspace)) + { + view->sceneManager->removeModel(this); + } + } + + //99.71% matching + //Branching :pray: + void Texture::onTexturePropertyChanged(const RBX::Reflection::PropertyDescriptor *descriptor) + { + if (descriptor != &FaceInstance::prop_Face) + { + if (descriptor == &RBX::Decal::prop_Texture || descriptor == &RBX::Decal::prop_Specular || descriptor == &RBX::Decal::prop_Shiny) + { + invalidateMaterial(); + return; + } + } + if (descriptor != &RBX::Texture::prop_StudsPerTileU && descriptor != &RBX::Texture::prop_StudsPerTileV) + { + return; + } + invalidateMesh(); + } + + //75.62% matching + G3D::ReferenceCountedPointer Texture::getMaterial() + { + if (materialInvalid) + { + std::string textureFile; + if (RBX::ContentProvider::singleton().requestContentFile(texture->getTexture(), textureFile)) + { + RBX::Render::Material* newMat = new RBX::Render::Material(); + material = newMat; + RBX::Render::TextureProxy* texProxy = new RBX::Render::TextureProxy(*view->textureManager.get(), textureFile, true); + material->appendLevel(texProxy, G3D::Color3::WHITE, texture->getSpecular(), texture->getShiny(), 0.0f, 0.0f); + materialInvalid = false; + } + } + + return material; + } + + Texture::~Texture() + { + } + + //38.85% matching + //just like decals + void Texture::updateMesh() + { + if (partInstance.get()) + { + G3D::Vector3 size = partInstance->getPartSizeXml(); + if (specialShape) + { + size *= specialShape->getScale(); + } + + if (partInstance->getPartType()) + { + switch (partInstance->getPartType()) + { + case RBX::Part::CYLINDER_PART: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + case RBX::Part::BLOCK_PART: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + case RBX::Part::BALL_PART: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + } + } + + if (specialShape) + { + switch(specialShape->getMeshType()) + { + case SpecialShape::WEDGE_MESH: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + case SpecialShape::HEAD_MESH: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + case SpecialShape::TORSO_MESH: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + case SpecialShape::SPHERE_MESH: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + case SpecialShape::CYLINDER_MESH: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + case SpecialShape::BRICK_MESH: + mesh = RBX::View::MeshFactory::createTexture(size, texture->getFace(), texture->getStudsPerTile()); + break; + default: + break; + } + } + radius = sqrt(2.0f) * 0.5 * primaryComponent(size); + } + } + + + //75.92% + //similar to decal's + Texture::Texture(RBX::Texture &texture, RBX::PartInstance &parentPart, RBX::View::View *view) + : PartChunk(RBX::Render::Chunk::TEXTURE_OFFSET, RBX::shared_from(&parentPart), view), + texture(RBX::shared_from(&texture)), + textureAncestorChangedConnection(), + texturePropertyChangedConnection() + { + textureAncestorChangedConnection = RBX::Instance::event_ancestryChanged.connect(&texture, boost::slot)>>(boost::bind(&Texture::onTextureAncestorChanged, this, _1))); + texturePropertyChangedConnection = RBX::Instance::event_propertyChanged.connect(&texture, boost::slot>(boost::bind(&Texture::onTexturePropertyChanged, this, _1))); + } + + }; +}; \ No newline at end of file diff --git a/Client/RbxView/Part.h b/Client/RbxView/Part.h index e69de29b..3198a182 100644 --- a/Client/RbxView/Part.h +++ b/Client/RbxView/Part.h @@ -0,0 +1,113 @@ +#pragma once + +#include "RenderLib/Chunk.h" +#include "v8datamodel/PartInstance.h" +#include "reflection/reflection.h" +#include +#include +#include + +namespace RBX +{ + class SpecialShape; + class Instance; + class Decal; + class Texture; + + namespace View + { + class View; + + class __declspec(novtable) PartChunk : public RBX::Render::Chunk + { + private: + G3D::CoordinateFrame coordinateFrame; + boost::signals::scoped_connection childAddedConnection; + boost::signals::scoped_connection childRemovedConnection; + boost::signals::scoped_connection ancestorChangedConnection; + boost::signals::scoped_connection propertyChangedConnection; + boost::signals::scoped_connection shapePropertyChangedConnection; + protected: + boost::shared_ptr partInstance; + G3D::ReferenceCountedPointer material; + bool materialInvalid; + G3D::ReferenceCountedPointer mesh; + View* view; + RBX::SpecialShape* specialShape; + private: + virtual void updateMesh() = 0; + public: + virtual ~PartChunk(); //May not actually exist + virtual bool castShadows() const + { + return true; + } + virtual bool cullable() const + { + return true; + } + protected: + PartChunk(float polygonOffset, const boost::shared_ptr& partInstance, View* view); + void invalidateMaterial(); + void invalidateMesh(); + virtual void onPropertyChanged(const RBX::Reflection::PropertyDescriptor* descriptor); + virtual G3D::ReferenceCountedPointer getMesh(); + virtual const G3D::CoordinateFrame& cframe(); + private: + void onAncestorChanged(boost::shared_ptr); + void onChildAdded(boost::shared_ptr); + void onChildRemoved(boost::shared_ptr); + void onSpecialShapeChanged(); + }; + + class Part : public PartChunk, public RBX::Listener + { + public: + Part(const boost::shared_ptr& partInstance, RBX::View::View* view); + virtual ~Part(); + virtual G3D::ReferenceCountedPointer getMaterial(); + protected: + virtual void onPropertyChanged(const RBX::Reflection::PropertyDescriptor* descriptor); + virtual void onEvent(const RBX::PartInstance* source, RBX::CanAggregateChanged event); + private: + bool usesMegaTexture() const; + virtual void updateMesh(); + }; + + class Decal : public PartChunk + { + private: + boost::shared_ptr decal; + boost::signals::scoped_connection decalAncestorChangedConnection; + boost::signals::scoped_connection decalPropertyChangedConnection; + public: + Decal(RBX::Decal& decal, RBX::PartInstance& partInstance, RBX::View::View* view); + virtual ~Decal(); + virtual G3D::ReferenceCountedPointer getMaterial(); + protected: + void onDecalPropertyChanged(const RBX::Reflection::PropertyDescriptor* descriptor); + void onDecalAncestorChanged(boost::shared_ptr ancestor); + private: + virtual void updateMesh(); + }; + + class Texture : public PartChunk + { + private: + boost::shared_ptr texture; + boost::signals::scoped_connection textureAncestorChangedConnection; + boost::signals::scoped_connection texturePropertyChangedConnection; + public: + Texture(RBX::Texture& decal, RBX::PartInstance& parentPart, RBX::View::View* view); + virtual ~Texture(); + virtual G3D::ReferenceCountedPointer getMaterial(); + protected: + void onTexturePropertyChanged(const RBX::Reflection::PropertyDescriptor* descriptor); + void onTextureAncestorChanged(boost::shared_ptr ancestor); + private: + virtual void updateMesh(); + }; + + float primaryComponent(const G3D::Vector3& v); + }; +}; \ No newline at end of file diff --git a/Client/RbxView/QuadVolume.h b/Client/RbxView/QuadVolume.h index eedeb3d2..c7f65337 100644 --- a/Client/RbxView/QuadVolume.h +++ b/Client/RbxView/QuadVolume.h @@ -24,7 +24,7 @@ namespace RBX : data(0) { } - void setSurfaceType(NormalId, RenderSurfaceType); + void setSurfaceType(NormalId normal, RenderSurfaceType type); RenderSurfaceType getSurfaceType(NormalId) const; unsigned int hashCode() const; diff --git a/Client/RbxView/RbxView.vcproj b/Client/RbxView/RbxView.vcproj index a44bfa6b..e17091f6 100644 --- a/Client/RbxView/RbxView.vcproj +++ b/Client/RbxView/RbxView.vcproj @@ -261,6 +261,10 @@ RelativePath=".\TorsoMesh.h" > + + diff --git a/Client/RbxView/include/RbxView/View.h b/Client/RbxView/include/RbxView/View.h new file mode 100644 index 00000000..05ecdb0e --- /dev/null +++ b/Client/RbxView/include/RbxView/View.h @@ -0,0 +1,63 @@ +#pragma once + +#include "ViewBase.h" +#include +#include +#include +#include +#include +#include + +class RenderStats; + +namespace RBX +{ + class DataModel; + + namespace Render { + //Really, Really, REALLY weird class (or struct? idk) + //There is like NO INFO about it except the std::map below + //No header, no pdb data, NOTHING + //Your only guess into how this classed worked is probably through the use of models + class Model; + + class SceneManager; + class RenderScene; + }; + + namespace View + { + class MaterialFactory; + + class View : public ViewBase + { + private: + G3D::ReferenceCountedPointer sky; + boost::shared_ptr dataModel; + std::map models; + boost::signals::scoped_connection lightingChangedConnection; + boost::signals::scoped_connection workspaceDescendentAddedConnection; + bool lightingValid; + public: + std::auto_ptr sceneManager; + std::auto_ptr renderScene; + std::auto_ptr textureManager; + std::auto_ptr materialFactory; + + View(boost::shared_ptr dataModel); + virtual ~View(); + virtual void render(void* rd); + G3D::ReferenceCountedPointer getMaterial(G3D::ReferenceCountedPointer); + virtual float getShadingQuality() const; + virtual float getMeshDetail() const; + virtual void updateSettings(float shadingQuality, float meshDetail, bool shadows, float cameraDistance); + virtual void suppressSkybox(); + virtual RBX::Instance* getWorkspace(); + virtual RenderStats& getRenderStats(); + private: + virtual void onWorkspaceDescendentAdded(boost::shared_ptr descendent); + virtual void updateLighting(); + virtual void invalidateLighting(bool updateSkybox); + }; + }; +}; \ No newline at end of file diff --git a/configure.py b/configure.py index fe8a4f32..d0b519d0 100644 --- a/configure.py +++ b/configure.py @@ -7,9 +7,14 @@ parser = argparse.ArgumentParser() parser.add_argument("targetPath", help="The directory to your target object files.") +basePaths = [ + root / "Client/App/obj/ReleaseAssert", + root / "Client/RBXView/obj/Release" +] + def configure(desiredTargetPath): targetPath = root / desiredTargetPath - basePath = root / "Client/App/obj/ReleaseAssert" +# basePath = root / "Client/App/obj/ReleaseAssert" if not targetPath.is_dir(): print("Specified target directory does not exist.") @@ -33,10 +38,13 @@ def configure(desiredTargetPath): "target_path": str(targetPath / objName) }) - if basePath.joinpath(objName).is_file(): - config["units"][i].update({ - "base_path": str(basePath / objName) - }) + for j in range(len(basePaths)): + basePath = basePaths[j] + + if basePath.joinpath(objName).is_file(): + config["units"][i].update({ + "base_path": str(basePath / objName) + }) json.dump(config, file, indent=4)