diff --git a/Engine/source/T3D/convexShape.cpp b/Engine/source/T3D/convexShape.cpp index f179ad25a1..5dccc0a35d 100644 --- a/Engine/source/T3D/convexShape.cpp +++ b/Engine/source/T3D/convexShape.cpp @@ -42,6 +42,7 @@ #include "T3D/physics/physicsBody.h" #include "T3D/physics/physicsCollision.h" #include "console/engineAPI.h" +#include "core/strings/stringUnit.h" IMPLEMENT_CO_NETOBJECT_V1( ConvexShape ); @@ -206,6 +207,12 @@ bool ConvexShape::protectedSetSurface( void *object, const char *index, const ch Point3F pos; //MatrixF mat; + U32 matID; + Point2F offset; + Point2F scale; + F32 rot = 0; + bool horz = true, vert = true; + /* dSscanf( data, "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %g", &mat[0], &mat[1], &mat[2], &mat[3], @@ -214,23 +221,59 @@ bool ConvexShape::protectedSetSurface( void *object, const char *index, const ch &mat[12], &mat[13], &mat[14], &mat[15] ); */ - dSscanf( data, "%g %g %g %g %g %g %g", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z ); + String t = data; + S32 len = t.length(); + + dSscanf( data, "%g %g %g %g %g %g %g %i %g %g %g %g %f", &quat.x, &quat.y, &quat.z, &quat.w, &pos.x, &pos.y, &pos.z, + &matID, &offset.x, &offset.y, &scale.x, &scale.y, &rot); MatrixF surface; quat.setMatrix( &surface ); surface.setPosition( pos ); - shape->mSurfaces.push_back( surface ); + shape->mSurfaces.push_back( surface ); + + surfaceUV surfUV; + if (StringUnit::getUnitCount(data, " ") > 7) + { + surfUV.matID = matID; + surfUV.offset = offset; + surfUV.scale = scale; + surfUV.zRot = rot; + surfUV.horzFlip = horz; + surfUV.vertFlip = vert; + } + else + { + surfUV.matID = 0; + surfUV.offset = Point2F(0,0); + surfUV.scale = Point2F(1, 1); + surfUV.zRot = 0; + surfUV.horzFlip = false; + surfUV.vertFlip = false; + } + + shape->mSurfaceUVs.push_back(surfUV); return false; } +bool ConvexShape::protectedSetSurfaceTexture(void *object, const char *index, const char *data) +{ + ConvexShape *shape = static_cast< ConvexShape* >(object); + + surfaceMaterial surface; + + surface.materialName = data; + + shape->mSurfaceTextures.push_back(surface); + + return false; +} ConvexShape::ConvexShape() : mMaterialName( "Grid512_OrangeLines_Mat" ), mMaterialInst( NULL ), - mVertCount( 0 ), - mPrimCount( 0 ), mPhysicsRep( NULL ), mNormalLength( 0.3f ) { @@ -240,6 +283,10 @@ ConvexShape::ConvexShape() StaticShapeObjectType; mConvexList = new Convex; + + mSurfaceBuffers.clear(); + mSurfaceUVs.clear(); + mSurfaceTextures.clear(); } ConvexShape::~ConvexShape() @@ -247,6 +294,12 @@ ConvexShape::~ConvexShape() if ( mMaterialInst ) SAFE_DELETE( mMaterialInst ); + for(U32 i=0; i points; + points.push_back(a); + points.push_back(b); + points.push_back(c); + + Point3F vertices[64]; + p.clipPolygon(points.address(), points.size(), vertices); + return true; } @@ -374,6 +452,20 @@ void ConvexShape::writeFields( Stream &stream, U32 tabStop ) count = smMaxSurfaces; } + for (U32 i = 0; i < mSurfaceTextures.size(); i++) + { + stream.writeTabs(tabStop); + + char buffer[1024]; + dMemset(buffer, 0, 1024); + + const char* tex = mSurfaceTextures[i].materialName.c_str(); + + dSprintf(buffer, 1024, "surfaceTexture = \"%s\";", mSurfaceTextures[i].materialName.c_str()); + + stream.writeLine((const U8*)buffer); + } + for ( U32 i = 0; i < count; i++ ) { const MatrixF &mat = mSurfaces[i]; @@ -386,8 +478,10 @@ void ConvexShape::writeFields( Stream &stream, U32 tabStop ) char buffer[1024]; dMemset( buffer, 0, 1024 ); - dSprintf( buffer, 1024, "surface = \"%g %g %g %g %g %g %g\";", - quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z ); + dSprintf( buffer, 1024, "surface = \"%g %g %g %g %g %g %g %i %g %g %g %g %g %i %i\";", + quat.x, quat.y, quat.z, quat.w, pos.x, pos.y, pos.z, mSurfaceUVs[i].matID, + mSurfaceUVs[i].offset.x, mSurfaceUVs[i].offset.y, mSurfaceUVs[i].scale.x, + mSurfaceUVs[i].scale.y, mSurfaceUVs[i].zRot, mSurfaceUVs[i].horzFlip, mSurfaceUVs[i].vertFlip); stream.writeLine( (const U8*)buffer ); } @@ -398,6 +492,9 @@ bool ConvexShape::writeField( StringTableEntry fieldname, const char *value ) if ( fieldname == StringTable->insert("surface") ) return false; + if ( fieldname == StringTable->insert("surfaceTexture") ) + return false; + return Parent::writeField( fieldname, value ); } @@ -440,8 +537,26 @@ U32 ConvexShape::packUpdate( NetConnection *conn, U32 mask, BitStream *stream ) Point3F pos( mSurfaces[i].getPosition() ); mathWrite( *stream, quat ); - mathWrite( *stream, pos ); + mathWrite( *stream, pos ); + + mathWrite(*stream, mSurfaceUVs[i].offset); + mathWrite(*stream, mSurfaceUVs[i].scale); + + stream->writeFlag(mSurfaceUVs[i].horzFlip); + stream->writeFlag(mSurfaceUVs[i].vertFlip); + + stream->writeInt(mSurfaceUVs[i].matID, 16); } + + const U32 surfaceTex = mSurfaceTextures.size(); + + stream->writeInt( surfaceTex, 32 ); + //next check for any texture coord or scale mods + for(U32 i=0; i < surfaceTex; i++) + { + String a = mSurfaceTextures[i].materialName; + stream->write( mSurfaceTextures[i].materialName ); + } } return retMask; @@ -464,10 +579,8 @@ void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream ) { stream->read( &mMaterialName ); - if ( isProperlyAdded() ) - _updateMaterial(); - mSurfaces.clear(); + mSurfaceUVs.clear(); const U32 surfCount = stream->readInt( 32 ); for ( S32 i = 0; i < surfCount; i++ ) @@ -483,8 +596,33 @@ void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream ) quat.setMatrix( &mat ); mat.setPosition( pos ); + + mSurfaceUVs.increment(); + + mathRead(*stream, &mSurfaceUVs[i].offset); + mathRead(*stream, &mSurfaceUVs[i].scale); + + mSurfaceUVs[i].horzFlip = stream->readFlag(); + mSurfaceUVs[i].vertFlip = stream->readFlag(); + + mSurfaceUVs[i].matID = stream->readInt(16); } + //now fetch our text coord mods to store into the geometry data + mSurfaceTextures.clear(); + const U32 surfaceTex = stream->readInt( 32 ); + + //next check for any texture coord or scale mods + for(U32 i=0; i < surfaceTex; i++) + { + mSurfaceTextures.increment(); + + stream->read( &mSurfaceTextures[i].materialName ); + } + + if (isProperlyAdded()) + _updateMaterial(); + if ( isProperlyAdded() ) _updateGeometry( true ); } @@ -492,86 +630,89 @@ void ConvexShape::unpackUpdate( NetConnection *conn, BitStream *stream ) void ConvexShape::prepRenderImage( SceneRenderState *state ) { - if ( state->isDiffusePass() ) + for (U32 i = 0; i < mSurfaceBuffers.size(); i++) { - ObjectRenderInst *ri2 = state->getRenderPass()->allocInst(); - ri2->renderDelegate.bind( this, &ConvexShape::_renderDebug ); - ri2->type = RenderPassManager::RIT_Editor; - state->getRenderPass()->addInst( ri2 ); - } - - if ( mVertexBuffer.isNull() || !state) - return; + if (mSurfaceBuffers[i].mPrimitiveBuffer.isNull()) + continue; - // If we don't have a material instance after the override then - // we can skip rendering all together. - BaseMatInstance *matInst = state->getOverrideMaterial( mMaterialInst ? mMaterialInst : MATMGR->getWarningMatInstance() ); - if ( !matInst ) - return; + // If we don't have a material instance after the override then + // we can skip rendering all together. + BaseMatInstance *matInst; + if (i == 0) + { + matInst = state->getOverrideMaterial(mMaterialInst ? mMaterialInst : MATMGR->getWarningMatInstance()); + } + else + { + matInst = state->getOverrideMaterial(mSurfaceTextures[i - 1].materialInst ? mSurfaceTextures[i - 1].materialInst : MATMGR->getWarningMatInstance()); + } - // Get a handy pointer to our RenderPassmanager - RenderPassManager *renderPass = state->getRenderPass(); + if (!matInst) + continue; - // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager - MeshRenderInst *ri = renderPass->allocInst(); + // Get a handy pointer to our RenderPassmanager + RenderPassManager *renderPass = state->getRenderPass(); - // Set our RenderInst as a standard mesh render - ri->type = RenderPassManager::RIT_Mesh; + // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager + MeshRenderInst *ri = renderPass->allocInst(); - // Calculate our sorting point - if ( state ) - { - // Calculate our sort point manually. - const Box3F& rBox = getRenderWorldBox(); - ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() ); - } - else - ri->sortDistSq = 0.0f; - - // Set up our transforms - MatrixF objectToWorld = getRenderTransform(); - objectToWorld.scale( getScale() ); - - ri->objectToWorld = renderPass->allocUniqueXform( objectToWorld ); - ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); - ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection); - - // If we need lights then set them up. - if ( matInst->isForwardLit() ) - { - LightQuery query; - query.init( getWorldSphere() ); - query.getLights( ri->lights, 8 ); - } + // Set our RenderInst as a standard mesh render + ri->type = RenderPassManager::RIT_Mesh; + + // Calculate our sorting point + if (state) + { + // Calculate our sort point manually. + const Box3F& rBox = getRenderWorldBox(); + ri->sortDistSq = rBox.getSqDistanceToPoint(state->getCameraPosition()); + } + else + ri->sortDistSq = 0.0f; - // Make sure we have an up-to-date backbuffer in case - // our Material would like to make use of it - // NOTICE: SFXBB is removed and refraction is disabled! - //ri->backBuffTex = GFX->getSfxBackBuffer(); + // Set up our transforms + MatrixF objectToWorld = getRenderTransform(); + objectToWorld.scale(getScale()); - // Set our Material - ri->matInst = matInst; - if ( matInst->getMaterial()->isTranslucent() ) - { - ri->translucentSort = true; - ri->type = RenderPassManager::RIT_Translucent; - } + ri->objectToWorld = renderPass->allocUniqueXform(objectToWorld); + ri->worldToCamera = renderPass->allocSharedXform(RenderPassManager::View); + ri->projection = renderPass->allocSharedXform(RenderPassManager::Projection); - // Set up our vertex buffer and primitive buffer - ri->vertBuff = &mVertexBuffer; - ri->primBuff = &mPrimitiveBuffer; + // If we need lights then set them up. + if (matInst->isForwardLit()) + { + LightQuery query; + query.init(getWorldSphere()); + query.getLights(ri->lights, 8); + } + + // Make sure we have an up-to-date backbuffer in case + // our Material would like to make use of it + // NOTICE: SFXBB is removed and refraction is disabled! + //ri->backBuffTex = GFX->getSfxBackBuffer(); - ri->prim = renderPass->allocPrim(); - ri->prim->type = GFXTriangleList; - ri->prim->minIndex = 0; - ri->prim->startIndex = 0; - ri->prim->numPrimitives = mPrimCount; - ri->prim->startVertex = 0; - ri->prim->numVertices = mVertCount; + // Set our Material + ri->matInst = matInst; + if (matInst->getMaterial()->isTranslucent()) + { + ri->translucentSort = true; + ri->type = RenderPassManager::RIT_Translucent; + } - // We sort by the material then vertex buffer. - ri->defaultKey = matInst->getStateHint(); - ri->defaultKey2 = (uintptr_t)ri->vertBuff; // Not 64bit safe! + // Set up our vertex buffer and primitive buffer + ri->vertBuff = &mSurfaceBuffers[i].mVertexBuffer; + ri->primBuff = &mSurfaceBuffers[i].mPrimitiveBuffer; + + ri->prim = renderPass->allocPrim(); + ri->prim->type = GFXTriangleList; + ri->prim->minIndex = 0; + ri->prim->startIndex = 0; + ri->prim->numPrimitives = mSurfaceBuffers[i].mPrimCount; + ri->prim->startVertex = 0; + ri->prim->numVertices = mSurfaceBuffers[i].mVertCount; + + // We sort by the material then vertex buffer. + ri->defaultKey = matInst->getStateHint(); + ri->defaultKey2 = (U32)ri->vertBuff; // Not 64bit safe! // Submit our RenderInst to the RenderPassManager state->getRenderPass()->addInst( ri ); @@ -791,10 +932,21 @@ bool ConvexShape::castRay( const Point3F &start, const Point3F &end, RayInfo *in F32 t; F32 tmin = F32_MAX; S32 hitFace = -1; - Point3F pnt; + Point3F hitPnt, pnt; VectorF rayDir( end - start ); rayDir.normalizeSafe(); - + + if ( false ) + { + PlaneF plane( Point3F(0,0,0), Point3F(0,0,1) ); + Point3F sp( 0,0,-1 ); + Point3F ep( 0,0,1 ); + + F32 t = plane.intersect( sp, ep ); + Point3F hitPnt; + hitPnt.interpolate( sp, ep, t ); + } + for ( S32 i = 0; i < planeCount; i++ ) { // Don't hit the back-side of planes. @@ -1037,8 +1189,33 @@ void ConvexShape::getSurfaceLineList( S32 surfId, Vector< Point3F > &lineList ) void ConvexShape::_updateMaterial() { + //update our custom surface materials + for (U32 i = 0; igetMaterial()->getName(), String::NoCase)) + continue; + + Material *material; + + if (!Sim::findObject(mSurfaceTextures[i].materialName, material)) + //bail + continue; + + mSurfaceTextures[i].materialInst = material->createMatInstance(); + + FeatureSet features = MATMGR->getDefaultFeatures(); + + mSurfaceTextures[i].materialInst->init(features, getGFXVertexFormat()); + + if (!mSurfaceTextures[i].materialInst->isValid()) + { + SAFE_DELETE(mSurfaceTextures[i].materialInst); + } + } + // If the material name matches then don't bother updating it. - if ( mMaterialInst && mMaterialName.equal( mMaterialInst->getMaterial()->getName(), String::NoCase ) ) + if (mMaterialInst && mMaterialName.equal(mMaterialInst->getMaterial()->getName(), String::NoCase)) return; SAFE_DELETE( mMaterialInst ); @@ -1074,11 +1251,46 @@ void ConvexShape::_updateGeometry( bool updateCollision ) for ( S32 i = 0; i < mSurfaces.size(); i++ ) mPlanes.push_back( PlaneF( mSurfaces[i].getPosition(), mSurfaces[i].getUpVector() ) ); - Vector< Point3F > tangents; - for ( S32 i = 0; i < mSurfaces.size(); i++ ) - tangents.push_back( mSurfaces[i].getRightVector() ); - - mGeometry.generate( mPlanes, tangents ); + Vector< Point3F > tangents; + for (S32 i = 0; i < mSurfaces.size(); i++) + tangents.push_back(mSurfaces[i].getRightVector()); + + //prepping the texture info + Vector texOffset; + Vector texScale; + Vector horzFlip; + Vector vertFlip; + //step in here, and add new surfaceTextures if we don't match the count of surfaces, we use + //msurfaces as the counter, because we need to match it. + if (mSurfaceUVs.size() > mSurfaces.size()) + { + for (U32 x = mSurfaceUVs.size(); x > mSurfaces.size(); x--) + mSurfaceUVs.pop_front(); + } + else if (mSurfaceUVs.size() < mSurfaces.size()) + { + for (U32 x = mSurfaceUVs.size(); x <= mSurfaces.size(); x++) + { + mSurfaceUVs.increment(); + mSurfaceUVs[x].offset = Point2F(0, 0); + mSurfaceUVs[x].scale = Point2F(1, 1); + mSurfaceUVs[x].zRot = 0; + mSurfaceUVs[x].horzFlip = false; + mSurfaceUVs[x].vertFlip = false; + mSurfaceUVs[x].matID = 0; + } + } + + for (S32 i = 0; i < mSurfaceUVs.size(); i++) + { + //add our offsets/scales for passing to the geometry now + texOffset.push_back(mSurfaceUVs[i].offset); + texScale.push_back(mSurfaceUVs[i].scale); + horzFlip.push_back(mSurfaceUVs[i].horzFlip); + vertFlip.push_back(mSurfaceUVs[i].vertFlip); + } + + mGeometry.generate(mPlanes, tangents, mSurfaceTextures, texOffset, texScale, horzFlip, vertFlip); AssertFatal( mGeometry.faces.size() <= mSurfaces.size(), "Got more faces than planes?" ); @@ -1098,10 +1310,21 @@ void ConvexShape::_updateGeometry( bool updateCollision ) // Update bounding box. updateBounds( false ); - mVertexBuffer = NULL; - mPrimitiveBuffer = NULL; - mVertCount = 0; - mPrimCount = 0; + mSurfaceBuffers.clear(); + + //set up buffers based on how many materials we have, but we always have at least one for our default mat + mSurfaceBuffers.increment(); + mSurfaceBuffers[0].mVertexBuffer = NULL; + mSurfaceBuffers[0].mVertCount = 0; + mSurfaceBuffers[0].mPrimCount = 0; + + for (U32 i = 0; i < mSurfaceTextures.size(); i++) + { + mSurfaceBuffers.increment(); + mSurfaceBuffers[i+1].mVertexBuffer = NULL; + mSurfaceBuffers[i + 1].mVertCount = 0; + mSurfaceBuffers[i + 1].mPrimCount = 0; + } if ( updateCollision ) _updateCollision(); @@ -1113,59 +1336,81 @@ void ConvexShape::_updateGeometry( bool updateCollision ) if ( faceList.empty() ) return; + //We do this in 2 parts. First, going through and building the buffers for all faces with the default material(matID -1) + //After that, we then through and build buffers for all faces sharing materials. This means we can have a single buffer, + //or one for each face of the brush, depending on how it's textured // Get total vert and prim count. for ( S32 i = 0; i < faceList.size(); i++ ) { - U32 count = faceList[i].triangles.size(); - mPrimCount += count; - mVertCount += count * 3; + U32 count = faceList[i].triangles.size(); + + S32 matID = mSurfaceUVs[i].matID; + + mSurfaceBuffers[mSurfaceUVs[i].matID].mPrimCount += count; + mSurfaceBuffers[mSurfaceUVs[i].matID].mVertCount += count * 3; } - // Allocate VB and copy in data. + // + for (U32 i = 0; i < mSurfaceBuffers.size(); i++) + { + if (mSurfaceBuffers[i].mVertCount > 0) + { + U32 primCount = mSurfaceBuffers[i].mPrimCount; + U32 vertCount = mSurfaceBuffers[i].mVertCount; - mVertexBuffer.set( GFX, mVertCount, GFXBufferTypeStatic ); - VertexType *pVert = mVertexBuffer.lock(); + mSurfaceBuffers[i].mVertexBuffer.set(GFX, mSurfaceBuffers[i].mVertCount, GFXBufferTypeStatic); + VertexType *pVert = mSurfaceBuffers[i].mVertexBuffer.lock(); - for ( S32 i = 0; i < faceList.size(); i++ ) - { - const ConvexShape::Face &face = faceList[i]; - const Vector< U32 > &facePntMap = face.points; - const Vector< ConvexShape::Triangle > &triangles = face.triangles; - const ColorI &faceColor = sgConvexFaceColors[ i % sgConvexFaceColorCount ]; + U32 vc = 0; - for ( S32 j = 0; j < triangles.size(); j++ ) - { - for ( S32 k = 0; k < 3; k++ ) - { - pVert->normal = face.normal; - pVert->tangent = face.tangent; - pVert->color = faceColor; - pVert->point = pointList[ facePntMap[ triangles[j][k] ] ]; - pVert->texCoord = face.texcoords[ triangles[j][k] ]; + for (S32 f = 0; f < faceList.size(); f++) + { + if (mSurfaceUVs[f].matID == i) + { + const ConvexShape::Face &face = faceList[f]; + const Vector< U32 > &facePntMap = face.points; + const Vector< ConvexShape::Triangle > &triangles = face.triangles; + const ColorI &faceColor = sgConvexFaceColors[f % sgConvexFaceColorCount]; - pVert++; - } - } - } + const Point3F binormal = mCross(face.normal, face.tangent); - mVertexBuffer.unlock(); + for (S32 j = 0; j < triangles.size(); j++) + { + for (S32 k = 0; k < 3; k++) + { + pVert->normal = face.normal; + pVert->tangent = face.tangent; + pVert->color = faceColor; + pVert->point = pointList[facePntMap[triangles[j][k]]]; + pVert->texCoord = face.texcoords[triangles[j][k]]; + + pVert++; + vc++; + } + } + } + } - // Allocate PB + mSurfaceBuffers[i].mVertexBuffer.unlock(); - mPrimitiveBuffer.set( GFX, mPrimCount * 3, mPrimCount, GFXBufferTypeStatic ); + // Allocate PB - U16 *pIndex; - mPrimitiveBuffer.lock( &pIndex ); + mSurfaceBuffers[i].mPrimitiveBuffer.set(GFX, mSurfaceBuffers[i].mPrimCount * 3, mSurfaceBuffers[i].mPrimCount, GFXBufferTypeStatic); - for ( U16 i = 0; i < mPrimCount * 3; i++ ) - { - *pIndex = i; - pIndex++; - } + U16 *pIndex; + mSurfaceBuffers[i].mPrimitiveBuffer.lock(&pIndex); - mPrimitiveBuffer.unlock(); + for (U16 p = 0; p < mSurfaceBuffers[i].mPrimCount * 3; p++) + { + *pIndex = p; + pIndex++; + } + + mSurfaceBuffers[i].mPrimitiveBuffer.unlock(); + } + } } void ConvexShape::_updateCollision() @@ -1488,7 +1733,7 @@ void ConvexShape::getSurfaceTriangles( S32 surfId, Vector< Point3F > *outPoints, objToWorld.mulP( (*outPoints)[i] ); } } -void ConvexShape::Geometry::generate( const Vector< PlaneF > &planes, const Vector< Point3F > &tangents ) +void ConvexShape::Geometry::generate(const Vector< PlaneF > &planes, const Vector< Point3F > &tangents, const Vector< surfaceMaterial > surfaceTextures, const Vector< Point2F > texOffset, const Vector< Point2F > texScale, const Vector< bool > horzFlip, const Vector< bool > vertFlip) { PROFILE_SCOPE( Geometry_generate ); @@ -1759,7 +2004,26 @@ void ConvexShape::Geometry::generate( const Vector< PlaneF > &planes, const Vect F32 x = planex.distToPlane( points[ newFace.points[ j ] ] ); F32 y = planey.distToPlane( points[ newFace.points[ j ] ] ); - newFace.texcoords[j].set( -x, -y ); + if (!texOffset.empty()) + { + x += texOffset[i].x; + y += texOffset[i].y; + } + + //now scale + if (!texScale.empty() && !texScale[i].isZero()) + { + x *= (texScale[i].x); + y *= (texScale[i].y); + } + + if (horzFlip.size() > 0 && horzFlip[i]) + x *= -1; + + if (vertFlip.size() > 0 && vertFlip[i]) + y *= -1; + + newFace.texcoords[j].set(-x, -y); } // Data verification tests. diff --git a/Engine/source/T3D/convexShape.h b/Engine/source/T3D/convexShape.h index 62b38f3548..b61bce3164 100644 --- a/Engine/source/T3D/convexShape.h +++ b/Engine/source/T3D/convexShape.h @@ -131,9 +131,46 @@ class ConvexShape : public SceneObject S32 id; }; + struct surfaceMaterial + { + // The name of the Material we will use for rendering + String materialName; + + // The actual Material instance + BaseMatInstance* materialInst; + + surfaceMaterial() + { + materialName = ""; + materialInst = NULL; + } + }; + + struct surfaceUV + { + S32 matID; + Point2F offset; + Point2F scale; + float zRot; + bool horzFlip; + bool vertFlip; + + surfaceUV() : matID(0), offset(Point2F(0.0f, 0.0f)), scale(Point2F(1.0f, 1.0f)), zRot(0.0f), horzFlip(false), vertFlip(false) {} + }; + + struct surfaceBuffers + { + // The GFX vertex and primitive buffers + GFXVertexBufferHandle< VertexType > mVertexBuffer; + GFXPrimitiveBufferHandle mPrimitiveBuffer; + + U32 mVertCount; + U32 mPrimCount; + }; + struct Geometry { - void generate( const Vector< PlaneF > &planes, const Vector< Point3F > &tangents ); + void generate(const Vector< PlaneF > &planes, const Vector< Point3F > &tangents, const Vector< surfaceMaterial > surfaceTextures, const Vector< Point2F > texOffset, const Vector< Point2F > texScale, const Vector< bool > horzFlip, const Vector< bool > vertFlip); Vector< Point3F > points; Vector< Face > faces; @@ -215,6 +252,9 @@ class ConvexShape : public SceneObject static S32 QSORT_CALLBACK _comparePlaneDist( const void *a, const void *b ); static bool protectedSetSurface( void *object, const char *index, const char *data ); + + static bool protectedSetSurfaceTexture( void *object, const char *index, const char *data ); + static bool protectedSetSurfaceUV(void *object, const char *index, const char *data); protected: @@ -224,13 +264,6 @@ class ConvexShape : public SceneObject // The actual Material instance BaseMatInstance* mMaterialInst; - // The GFX vertex and primitive buffers - GFXVertexBufferHandle< VertexType > mVertexBuffer; - GFXPrimitiveBufferHandle mPrimitiveBuffer; - - U32 mVertCount; - U32 mPrimCount; - Geometry mGeometry; Vector< PlaneF > mPlanes; @@ -239,6 +272,11 @@ class ConvexShape : public SceneObject Vector< Point3F > mFaceCenters; + //this is mostly for storage purposes, so we can save the texture mods + Vector< surfaceMaterial > mSurfaceTextures; + Vector< surfaceUV > mSurfaceUVs; + Vector< surfaceBuffers > mSurfaceBuffers; + Convex *mConvexList; PhysicsBody *mPhysicsRep; diff --git a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp index bcb53df80f..61d828836b 100644 --- a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp +++ b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.cpp @@ -80,7 +80,8 @@ GuiConvexEditorCtrl::GuiConvexEditorCtrl() mHasCopied( false ), mLastUndo( NULL ), mUndoManager( NULL ), - mCtrlDown( false ) + mCtrlDown( false ), + mGridSnap(false) { mMaterialName = StringTable->insert("Grid512_OrangeLines_Mat"); } @@ -630,10 +631,44 @@ void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event) submitUndo( ModifyShape, mConvexSEL ); } - if ( mGizmo->getMode() == ScaleMode ) + if ( mGizmo->getMode() == ScaleMode && !(event.modifier & SI_CTRL)) { scaleFace( mConvexSEL, mFaceSEL, mGizmo->getScale() ); } + + else if ( mGizmo->getMode() == ScaleMode && (event.modifier & SI_CTRL) ) + { + Point3F scale = mGizmo->getDeltaScale(); + + F32 scalar = 1; + mConvexSEL->mSurfaceUVs[mFaceSEL].scale += (Point2F(scale.x, scale.y) * scalar); + + if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x < 0.01) + mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x = 0.01; + + if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y < 0.01) + mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y = 0.01; + + if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x > 100) + mConvexSEL->mSurfaceUVs[mFaceSEL].scale.x = 100; + + if (mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y > 100) + mConvexSEL->mSurfaceUVs[mFaceSEL].scale.y = 100; + + Point2F test = mConvexSEL->mSurfaceUVs[mFaceSEL].scale; + mConvexSEL->setMaskBits( ConvexShape::UpdateMask ); + + updateShape( mConvexSEL, mFaceSEL ); + } + /*else if ( mGizmo->getMode() == MoveMode && event.modifier & SI_CTRL ) { + Point3F scale = mGizmo->getOffset(); + + F32 scalar = 0.8; + mConvexSEL->mSurfaceTextures[mFaceSEL].offset += (Point2F(-scale.x, scale.z) * scalar); + mConvexSEL->setMaskBits( ConvexShape::UpdateMask ); + + updateShape( mConvexSEL, mFaceSEL ); + }*/ else { // Why does this have to be so ugly. @@ -662,6 +697,20 @@ void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event) // Clear out floating point errors. cleanMatrix( surfMat ); + if (mGizmo->getSelection() == Gizmo::Axis_Z) + { + MatrixF curSurfMat = mConvexSEL->mSurfaces[mFaceSEL]; + EulerF curSufRot = curSurfMat.toEuler(); + + EulerF newSufRot = surfMat.toEuler(); + + float zRot = mRadToDeg(newSufRot.z - curSufRot.z); + + float curZRot = mConvexSEL->mSurfaceUVs[mFaceSEL].zRot; + + mConvexSEL->mSurfaceUVs[mFaceSEL].zRot += zRot; + } + mConvexSEL->mSurfaces[mFaceSEL] = surfMat; updateShape( mConvexSEL, mFaceSEL ); @@ -699,7 +748,28 @@ void GuiConvexEditorCtrl::on3DMouseDragged(const Gui3DMouseEvent & event) if ( mGizmo->getMode() == MoveMode ) { - mConvexSEL->setPosition( mGizmo->getPosition() ); + //mConvexSEL->setPosition( mGizmo->getPosition() ); + + //MatrixF mat = mGizmo->getTransform(); + Point3F wPos = mGizmo->getPosition(); + //mat.getColumn(3, &wPos); + + // adjust + //wPos += offset; + + if (mGridSnap && mGridPlaneSize != 0.f) + { + if (mGizmo->getSelection() == Gizmo::Selection::Axis_X || mGizmo->getSelection() == Gizmo::Selection::Plane_XY || mGizmo->getSelection() == Gizmo::Selection::Plane_XZ) + wPos.x -= mFmod(wPos.x, mGridPlaneSize); + + if (mGizmo->getSelection() == Gizmo::Selection::Axis_Y || mGizmo->getSelection() == Gizmo::Selection::Plane_XY || mGizmo->getSelection() == Gizmo::Selection::Plane_YZ) + wPos.y -= mFmod(wPos.y, mGridPlaneSize); + + if (mGizmo->getSelection() == Gizmo::Selection::Axis_Z || mGizmo->getSelection() == Gizmo::Selection::Plane_XZ || mGizmo->getSelection() == Gizmo::Selection::Plane_YZ) + wPos.z -= mFmod(wPos.z, mGridPlaneSize); + } + + mConvexSEL->setPosition(wPos); } else if ( mGizmo->getMode() == RotateMode ) { @@ -845,8 +915,9 @@ void GuiConvexEditorCtrl::updateGizmo() if ( mFaceSEL != -1 && mode == MoveMode ) { - if ( mCtrlDown ) - flags &= ~( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn ); + if ( mCtrlDown ) + //hijacking the CTRL modifier for texture offsetting control + flags &= ~GizmoProfile::CanScaleZ; else flags |= ( GizmoProfile::CanTranslateX | GizmoProfile::CanTranslateY | GizmoProfile::PlanarHandlesOn ); } @@ -1201,13 +1272,51 @@ void GuiConvexEditorCtrl::translateFace( ConvexShape *shape, S32 faceId, const P AssertFatal( shape->mSurfaces[ face.id ].isAffine(), "ConvexShapeEditor - surface not affine." ); + Point3F modDisplace = Point3F(displace.x, displace.y, displace.z); + + //snapping + if (mGridSnap && mGridPlaneSize != 0) + { + Point3F faceCenter = Point3F::Zero; + + for (S32 i = 0; i < face.points.size(); i++) + { + Point3F &pnt = pointList[face.points[i]]; + faceCenter += pnt; + } + + faceCenter /= face.points.size(); + + // Transform displacement into object space. + MatrixF objToWorld(shape->getWorldTransform()); + objToWorld.scale(shape->getScale()); + objToWorld.inverse(); + + objToWorld.mulP(faceCenter); + + modDisplace = faceCenter + displace; + Point3F fMod = Point3F::Zero; + + if (!mIsZero(displace.x)) + fMod.x = mFmod(modDisplace.x - (displace.x > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize); + + if (!mIsZero(displace.y)) + fMod.y = mFmod(modDisplace.y - (displace.y > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize); + + if (!mIsZero(displace.z)) + fMod.z = mFmod(modDisplace.z - (displace.z > 0 ? mGridPlaneSize : -mGridPlaneSize), mGridPlaneSize); + + modDisplace -= fMod; + modDisplace -= faceCenter; + } + // Transform displacement into object space. MatrixF worldToObj( shape->getTransform() ); worldToObj.scale( shape->getScale() ); worldToObj.inverse(); Point3F displaceOS; - worldToObj.mulV( displace, &displaceOS ); + worldToObj.mulV(modDisplace, &displaceOS); for ( S32 i = 0; i < face.points.size(); i++ ) { @@ -1776,6 +1885,281 @@ bool GuiConvexEditorCtrl::getEdgesTouchingPoint( ConvexShape *shape, S32 faceId, return !edgeIdxList.empty(); } +Point2F GuiConvexEditorCtrl::getSelectedFaceUVOffset() +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return Point2F(0, 0); + + return mConvexSEL->mSurfaceUVs[mFaceSEL].offset; +} + +Point2F GuiConvexEditorCtrl::getSelectedFaceUVScale() +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return Point2F(0, 0); + + return mConvexSEL->mSurfaceUVs[mFaceSEL].scale; +} + +const char* GuiConvexEditorCtrl::getSelectedFaceMaterial() +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return ""; + + if (mConvexSEL->mSurfaceUVs[mFaceSEL].matID == 0) + { + return mConvexSEL->mMaterialName; + } + else + { + return mConvexSEL->mSurfaceTextures[mConvexSEL->mSurfaceUVs[mFaceSEL].matID - 1].materialName; + } +} + +bool GuiConvexEditorCtrl::getSelectedFaceHorzFlip() +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return false; + + return mConvexSEL->mSurfaceUVs[mFaceSEL].horzFlip; +} + +bool GuiConvexEditorCtrl::getSelectedFaceVertFlip() +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return false; + + return mConvexSEL->mSurfaceUVs[mFaceSEL].vertFlip; +} + +float GuiConvexEditorCtrl::getSelectedFaceZRot() +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return false; + + return mConvexSEL->mSurfaceUVs[mFaceSEL].zRot; +} + +void GuiConvexEditorCtrl::setSelectedFaceUVOffset(Point2F offset) +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return; + + mConvexSEL->mSurfaceUVs[mFaceSEL].offset = offset; + + mConvexSEL->setMaskBits(ConvexShape::UpdateMask); +} + +void GuiConvexEditorCtrl::setSelectedFaceUVScale(Point2F scale) +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return; + + mConvexSEL->mSurfaceUVs[mFaceSEL].scale = scale; + + mConvexSEL->setMaskBits(ConvexShape::UpdateMask); +} + +void GuiConvexEditorCtrl::setSelectedFaceMaterial(const char* materialName) +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return; + + if (mConvexSEL->mSurfaceUVs.size() < mFaceSEL) + return; + + //first, see if the mat already exists in our list + bool found = false; + U32 oldmatID = mConvexSEL->mSurfaceUVs[mFaceSEL].matID; + + if (dStrcmp(materialName, mConvexSEL->getMaterialName().c_str())) + { + for (U32 i = 0; i < mConvexSEL->mSurfaceTextures.size(); i++) + { + if (!dStrcmp(mConvexSEL->mSurfaceTextures[i].materialName, materialName)) + { + //found a match + mConvexSEL->mSurfaceUVs[mFaceSEL].matID = i + 1; + found = true; + } + } + + if (!found) + { + //add a new one + ConvexShape::surfaceMaterial newMat; + newMat.materialName = materialName; + + mConvexSEL->mSurfaceTextures.push_back(newMat); + + mConvexSEL->mSurfaceUVs[mFaceSEL].matID = mConvexSEL->mSurfaceTextures.size(); + } + } + else + { + mConvexSEL->mSurfaceUVs[mFaceSEL].matID = 0; + } + + //run through and find out if there are any other faces still using the old mat texture + if (oldmatID != 0) + { + S32 curMatCount = mConvexSEL->mSurfaceTextures.size(); + + bool used = false; + for (U32 i = 0; i < mConvexSEL->mSurfaceUVs.size(); i++) + { + if (mConvexSEL->mSurfaceUVs[i].matID == oldmatID) + { + used = true; + break; + } + } + + if (!used) + { + //that was the last reference, so let's update the listings on the shape + if (mConvexSEL->mSurfaceTextures[oldmatID - 1].materialInst) + SAFE_DELETE(mConvexSEL->mSurfaceTextures[oldmatID - 1].materialInst); + + mConvexSEL->mSurfaceTextures.erase(oldmatID-1); + + for (U32 i = 0; i < mConvexSEL->mSurfaceUVs.size(); i++) + { + if (mConvexSEL->mSurfaceUVs[i].matID > oldmatID) + mConvexSEL->mSurfaceUVs[i].matID--; + } + } + } + + //mConvexSEL->mSurfaceUVs[mFaceSEL].materialName = materialName; + + mConvexSEL->setMaskBits(ConvexShape::UpdateMask); +} + +void GuiConvexEditorCtrl::setSelectedFaceHorzFlip(bool flipped) +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return; + + mConvexSEL->mSurfaceUVs[mFaceSEL].horzFlip = flipped; + + mConvexSEL->setMaskBits(ConvexShape::UpdateMask); +} + +void GuiConvexEditorCtrl::setSelectedFaceVertFlip(bool flipped) +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return; + + mConvexSEL->mSurfaceUVs[mFaceSEL].vertFlip = flipped; + + mConvexSEL->setMaskBits(ConvexShape::UpdateMask); +} + +void GuiConvexEditorCtrl::setSelectedFaceZRot(float degrees) +{ + if (mFaceSEL == -1 || mConvexSEL == NULL) + return; + + F32 oldRot = mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot); + mConvexSEL->mSurfaceUVs[mFaceSEL].zRot = degrees; + + EulerF curEul = mConvexSEL->mSurfaces[mFaceSEL].toEuler(); + + MatrixF oldRotMat = MatrixF(EulerF(0, 0, -oldRot)); + + mConvexSEL->mSurfaces[mFaceSEL].mul(oldRotMat); + + MatrixF newRotMat = MatrixF(EulerF(0, 0, mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot))); + + mConvexSEL->mSurfaces[mFaceSEL].mul(newRotMat); + + //Point3F curPos = mConvexSEL->mSurfaces[mFaceSEL].getPosition(); + + //we roll back our existing modified rotation before setting the new one, just to keep it consistent + //const MatrixF &gMat = MatrixF(EulerF(curEul.x, curEul.y, curEul.z - oldRot + mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)), curPos); + + //mConvexSEL->mSurfaces[mFaceSEL] = MatrixF(EulerF(curEul.x, curEul.y, mDegToRad(mConvexSEL->mSurfaceUVs[mFaceSEL].zRot)), curPos); + + /*MatrixF surfMat; + surfMat.mul(mConvexSEL->mWorldToObj, gMat); + + MatrixF worldToObj(mConvexSEL->getTransform()); + worldToObj.scale(mConvexSEL->getScale()); + worldToObj.inverse(); + + Point3F newPos; + newPos = gMat.getPosition(); + + worldToObj.mulP(newPos); + surfMat.setPosition(newPos); + + // Clear out floating point errors. + cleanMatrix(surfMat); + + mConvexSEL->mSurfaces[mFaceSEL] = surfMat;*/ + + updateShape(mConvexSEL, mFaceSEL); + + mConvexSEL->setMaskBits(ConvexShape::UpdateMask); + + /* + const MatrixF &gMat = mGizmo->getTransform(); + MatrixF surfMat; + surfMat.mul( mConvexSEL->mWorldToObj, gMat ); + + MatrixF worldToObj ( mConvexSEL->getTransform() ); + worldToObj.scale( mConvexSEL->getScale() ); + worldToObj.inverse(); + + Point3F newPos; + newPos = gMat.getPosition(); + + worldToObj.mulP( newPos ); + surfMat.setPosition( newPos ); + + // Clear out floating point errors. + cleanMatrix( surfMat ); + + if (mGizmo->getSelection() == Gizmo::Axis_Z) + { + MatrixF curSurfMat = mConvexSEL->mSurfaces[mFaceSEL]; + EulerF curSufRot = curSurfMat.toEuler(); + + EulerF newSufRot = surfMat.toEuler(); + + float zRot = mRadToDeg(newSufRot.z - curSufRot.z); + + float curZRot = mConvexSEL->mSurfaceTextures[mFaceSEL].zRot; + + mConvexSEL->mSurfaceTextures[mFaceSEL].zRot += zRot; + } + + mConvexSEL->mSurfaces[mFaceSEL] = surfMat; + + updateShape( mConvexSEL, mFaceSEL ); + */ +} + +void GuiConvexEditorCtrl::toggleGridSnapping() +{ + if (mGridSnap) + mGridSnap = false; + else + mGridSnap = true; +} + +void GuiConvexEditorCtrl::updateShape() +{ + if (mConvexSEL) + mConvexSEL->inspectPostApply(); +} + +void GuiConvexEditorCtrl::setGridSnapSize(float gridSize) +{ + mGridPlaneSize = gridSize; +} + void GuiConvexEditorUndoAction::undo() { ConvexShape *object = NULL; @@ -2514,3 +2898,188 @@ DefineEngineMethod( GuiConvexEditorCtrl, splitSelectedFace, void, (), , "" ) { object->splitSelectedFace(); } + +DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceUVOffset, Point2F, (), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + //return Point2F(0, 0); + return object->getSelectedFaceUVOffset(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceUVScale, Point2F, (), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + //return Point2F(0, 0); + return object->getSelectedFaceUVScale(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceUVOffset, void, ( Point2F offset ), ( Point2F(0,0) ), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + //return Point2F(0, 0); + return object->setSelectedFaceUVOffset(offset); +} + +DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceUVScale, void, (Point2F scale), (Point2F(0, 0)), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + //return Point2F(0, 0); + return object->setSelectedFaceUVScale(scale); +} + +DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceMaterial, void, (const char* materialName), (""), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + //return Point2F(0, 0); + if (!dStrcmp(materialName, "")) + return; + + object->setSelectedFaceMaterial(materialName); +} + +DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceMaterial, const char*, (), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + return object->getSelectedFaceMaterial(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceHorzFlip, void, (bool flipped), (false), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->setSelectedFaceHorzFlip(flipped); +} + +DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceVertFlip, void, (bool flipped), (false), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->setSelectedFaceVertFlip(flipped); +} + +DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceHorzFlip, bool, (), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + return object->getSelectedFaceHorzFlip(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceVertFlip, bool, (), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + return object->getSelectedFaceVertFlip(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, setSelectedFaceZRot, void, (float degrees), (0.0), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->setSelectedFaceZRot(degrees); +} + +DefineEngineMethod(GuiConvexEditorCtrl, getSelectedFaceZRot, float, (), , + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + return object->getSelectedFaceZRot(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, toggleGridSnapping, void, (),, + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->toggleGridSnapping(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, setGridSnapSize, void, (float gridSize), (1.0), + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + object->setGridSnapSize(gridSize); +} + +DefineEngineMethod(GuiConvexEditorCtrl, getGridSnapSize, float, (),, + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + return object->getGridSnapSize(); +} + +DefineEngineMethod(GuiConvexEditorCtrl, updateShape, void, (),, + "@brief Mount objB to this object at the desired slot with optional transform.\n\n" + + "@param objB Object to mount onto us\n" + "@param slot Mount slot ID\n" + "@param txfm (optional) mount offset transform\n" + "@return true if successful, false if failed (objB is not valid)") +{ + //return Point2F(0, 0); + return object->updateShape(); +} diff --git a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.h b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.h index dbf8f267f4..3f4b91606a 100644 --- a/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.h +++ b/Engine/source/gui/worldEditor/guiConvexShapeEditorCtrl.h @@ -116,6 +116,25 @@ class GuiConvexEditorCtrl : public EditTSCtrl SceneObject* createPolyhedralObject(const char* className, SceneObject* geometryProvider); ConvexShape* createConvexShapeFrom(SceneObject* polyObject); + Point2F getSelectedFaceUVOffset(); + Point2F getSelectedFaceUVScale(); + const char* getSelectedFaceMaterial(); + bool getSelectedFaceHorzFlip(); + bool getSelectedFaceVertFlip(); + float getSelectedFaceZRot(); + + void setSelectedFaceUVOffset(Point2F offset); + void setSelectedFaceUVScale(Point2F offset); + void setSelectedFaceMaterial(const char* materialName); + void setSelectedFaceHorzFlip(bool flipped); + void setSelectedFaceVertFlip(bool flipped); + void setSelectedFaceZRot(float degrees); + void toggleGridSnapping(); + void setGridSnapSize(float gridSize); + + void updateShape(); + + float getGridSnapSize() { return mGridPlaneSize; } /// Interface with Tools. /// @{ @@ -158,6 +177,20 @@ class GuiConvexEditorCtrl : public EditTSCtrl U32 mSavedGizmoFlags; + Vector> mSelectedBrushes; + struct selectedFace + { + SimObjectPtr mOwnerBrush; + U32 faceId; + }; + Vector mSelectedFaces; + + struct selectedVert + { + SimObjectPtr mOwnerBrush; + U32 vertId; + }; + Vector mSelectedVerts; /// The selected ConvexShape. SimObjectPtr mConvexSEL; @@ -183,6 +216,8 @@ class GuiConvexEditorCtrl : public EditTSCtrl bool mHasCopied; RayInfo mLastRayInfo; + bool mGridSnap; + Gui3DMouseEvent mMouseDownEvent; Point3F mGizmoMatOffset; diff --git a/Templates/BaseGame/game/tools/convexEditor/convexEditorGui.cs b/Templates/BaseGame/game/tools/convexEditor/convexEditorGui.cs index 1cda5416cb..7f6ea15886 100644 --- a/Templates/BaseGame/game/tools/convexEditor/convexEditorGui.cs +++ b/Templates/BaseGame/game/tools/convexEditor/convexEditorGui.cs @@ -22,6 +22,19 @@ function ConvexEditorGui::onWake( %this ) { + convexEditorToolbar-->gridSnapSizeEdit.setText(%this.getGridSnapSize()); + + if(ConvexEditorOptionssWindow-->matPreviewBtn.bitmap $= "") + { + //no active material, so set one + ConvexEditorOptionssWindow-->matPreviewBtn.setText(""); + + %mat = EditorSettings.Value("ConvexEditor/MaterialName"); + + ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%mat.diffuseMap[0]); + + ConvexEditorOptionssWindow.activeMaterial = %mat; + } } function ConvexEditorGui::onSleep( %this ) @@ -45,18 +58,159 @@ ConvexEditorDeleteFaceBtn.setActive( false ); ConvexEditorDeleteFaceBtn.ToolTip = "Delete selection [Disabled] (Delete)"; - if ( !isObject( %shape ) ) + if ( !isObject( %shape ) ) + { + ConvexEditorOptionssWindow-->defMatPreviewBtn.setText("No Brush Selected"); + ConvexEditorOptionssWindow.activeShape = ""; return; + } ConvexEditorDeleteFaceBtn.setActive( true ); + + ConvexEditorOptionssWindow-->defMatPreviewBtn.setText(""); + ConvexEditorOptionssWindow-->defMatPreviewBtn.setBitmap(%shape.material.diffuseMap[0]); + + ConvexEditorOptionssWindow.activeShape = %shape; if ( %face == -1 ) + { ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected ConvexShape (Delete)"; + + ConvexEditorOptionssWindow-->UOffset.setText(""); + ConvexEditorOptionssWindow-->VOffset.setText(""); + + ConvexEditorOptionssWindow-->UScale.setText(""); + ConvexEditorOptionssWindow-->VScale.setText(""); + + ConvexEditorOptionssWindow-->ZRotation.setText(""); + } else { ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected Face (Delete)"; ConvexEditorSplitFaceBtn.ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control"; ConvexEditorSplitFaceBtn.setActive( true ); + + %UVOffset = %this.getSelectedFaceUVOffset(); + + ConvexEditorOptionssWindow-->UOffset.setText(%UVOffset.x); + ConvexEditorOptionssWindow-->VOffset.setText(%UVOffset.y); + + %UVScale = %this.getSelectedFaceUVScale(); + + ConvexEditorOptionssWindow-->UScale.setText(%UVScale.x); + ConvexEditorOptionssWindow-->VScale.setText(%UVScale.y); + + ConvexEditorOptionssWindow-->ZRotation.setText(ConvexEditorGui.getSelectedFaceZRot()); } +} + +function ConvexEditorUVFld::onReturn(%this) +{ + EWorldEditor.isDirty = true; + + %offset = "0 0"; + %offset.x = ConvexEditorOptionssWindow-->UOffset.getText(); + %offset.y = ConvexEditorOptionssWindow-->VOffset.getText(); + + %scale = "0 0"; + %scale.x = ConvexEditorOptionssWindow-->UScale.getText(); + %scale.y = ConvexEditorOptionssWindow-->VScale.getText(); + + %rot = ConvexEditorOptionssWindow-->ZRotation.getText(); + + ConvexEditorGui.setSelectedFaceUVOffset(%offset); + ConvexEditorGui.setSelectedFaceUVScale(%scale); + ConvexEditorGui.setSelectedFaceZRot(%rot); +} + +function ConvexEditorUVHorzFlipBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + %current = ConvexEditorGui.getSelectedFaceHorzFlip(); + ConvexEditorGui.setSelectedFaceHorzFlip(!%current); +} + +function ConvexEditorUVVertFlipBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + %current = ConvexEditorGui.getSelectedFaceVertFlip(); + ConvexEditorGui.setSelectedFaceVertFlip(!%current); +} + +function ConvexEditorMaterialBtn::onClick(%this) +{ + %this.getMaterialName(); +} + +function ConvexEditorMaterialBtn::getMaterialName(%this) +{ + materialSelector.showDialog(%this @ ".gotMaterialName", "name"); +} + +function ConvexEditorMaterialBtn::gotMaterialName(%this, %name) +{ + //eval(%this.object @ "." @ %this.targetField @ " = " @ %name @ ";"); + //%this.object.changeMaterial(getTrailingNumber(%this.targetField), %name); + //%this.object.inspectorApply(); + %diffusemap = %name.diffuseMap[0]; + + ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%diffusemap); + + ConvexEditorOptionssWindow.activeMaterial = %name; +} + +function ConvexEditorMaterialApplyBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + ConvexEditorGui.setSelectedFaceMaterial(ConvexEditorOptionssWindow.activeMaterial); + ConvexEditorGui.updateShape(); +} + +function ConvexEditorMaterialLiftBtn::onClick(%this) +{ + %mat = ConvexEditorGui.getSelectedFaceMaterial(); + ConvexEditorOptionssWindow.activeMaterial = %mat; + ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%mat.diffuseMap[0]); +} + +function ConvexEditorMaterialResetBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + ConvexEditorGui.setSelectedFaceMaterial(ConvexEditorOptionssWindow.activeShape.material); + ConvexEditorGui.updateShape(); +} + +function ConvexEditorGui::toggleGridSnap(%this) +{ + %this.toggleGridSnapping(); +} + +function ConvexEditorGridSnapSizeFld::onReturn(%this) +{ + ConvexEditorGui.setGridSnapSize(%this.getText()); +} + +function ConvexEditorDefaultMaterialBtn::onClick(%this) +{ + %this.getMaterialName(); +} + +function ConvexEditorDefaultMaterialBtn::getMaterialName(%this) +{ + materialSelector.showDialog(%this @ ".gotMaterialName", "name"); +} + +function ConvexEditorDefaultMaterialBtn::gotMaterialName(%this, %name) +{ + //eval(%this.object @ "." @ %this.targetField @ " = " @ %name @ ";"); + //%this.object.changeMaterial(getTrailingNumber(%this.targetField), %name); + //%this.object.inspectorApply(); + %diffusemap = %name.diffuseMap[0]; + + ConvexEditorOptionssWindow-->defMatPreviewBtn.setBitmap(%diffusemap); + + ConvexEditorOptionssWindow.activeShape.material = %name; + + ConvexEditorGui.updateShape(); } \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/convexEditor/convexEditorToolbar.ed.gui b/Templates/BaseGame/game/tools/convexEditor/convexEditorToolbar.ed.gui index 575907d81b..bd76a265eb 100644 --- a/Templates/BaseGame/game/tools/convexEditor/convexEditorToolbar.ed.gui +++ b/Templates/BaseGame/game/tools/convexEditor/convexEditorToolbar.ed.gui @@ -21,6 +21,95 @@ EdgeSnap = "0"; text =""; + new GuiTextCtrl() { + profile = "ToolsGuiTextProfile"; + horizSizing = "right"; + vertSizing = "bottom"; + position = "15 7"; + extent = "86 16"; + minExtent = "8 8"; + visible = "1"; + text = "Sketch Tool"; + maxLength = "255"; + helpTag = "0"; + }; + new GuiBitmapCtrl() { + Profile = "ToolsGuiDefaultProfile"; + position = "94 3"; + Extent = "2 26"; + MinExtent = "1 1"; + bitmap = "tools/gui/images/separator-h.png"; + }; + new GuiBitmapButtonCtrl(ConvexEditorCreateBoxBtn) { + canSaveDynamicFields = "0"; + isContainer = "0"; + Profile = "ToolsGuiButtonProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + Position = "100 3"; + Extent = "29 27"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + Command = "ConvexEditorGui.createConvexBox();"; + tooltipprofile = "ToolsGuiToolTipProfile"; + ToolTip = "Create ConvexShape Box" NL "Use Alt + Click-Drag instead of this for more control of starting placement."; + hovertime = "1000"; + bitmap = "tools/convexEditor/images/convex-editor-btn"; + text = ""; + groupNum = "-1"; + buttonType = "pushButton"; + useMouseEvents = "0"; + }; + new GuiBitmapButtonCtrl(ConvexEditorSplitFaceBtn) { + canSaveDynamicFields = "0"; + isContainer = "0"; + Profile = "ToolsGuiButtonProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + Position = "134 3"; + Extent = "29 27"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + Command = "ConvexEditorGui.splitSelectedFace();"; + tooltipprofile = "ToolsGuiToolTipProfile"; + ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control."; + hovertime = "1000"; + bitmap = "tools/convexEditor/images/split-face-btn"; + text = ""; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + }; + new GuiBitmapButtonCtrl(ConvexEditorDeleteFaceBtn) { + canSaveDynamicFields = "0"; + isContainer = "0"; + Profile = "ToolsGuiButtonProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + Position = "166 3"; + Extent = "29 27"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + Command = "ConvexEditorGui.handleDelete();"; + tooltipprofile = "ToolsGuiToolTipProfile"; + ToolTip = "Delete selected face" NL "(Delete)"; + hovertime = "1000"; + bitmap = "tools/gui/images/menubar/delete-btn"; + text = ""; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + }; + new GuiBitmapCtrl() { + Profile = "ToolsGuiDefaultProfile"; + position = "190 3"; + Extent = "2 26"; + MinExtent = "1 1"; + bitmap = "tools/gui/images/separator-h.png"; + }; new GuiContainer() { canSaveDynamicFields = "0"; Enabled = "1"; @@ -28,94 +117,87 @@ Profile = "menubarProfile"; HorizSizing = "width"; VertSizing = "bottom"; - Position = "0 0"; - Extent = "800 32"; + Position = "195 0"; + Extent = "190 32"; MinExtent = "8 8"; canSave = "1"; Visible = "1"; hovertime = "1000"; - - new GuiTextCtrl() { - profile = "ToolsGuiTextProfile"; - horizSizing = "right"; - vertSizing = "bottom"; - position = "15 7"; - extent = "86 16"; - minExtent = "8 8"; - visible = "1"; - text = "Sketch Tool"; - maxLength = "255"; - helpTag = "0"; - }; - new GuiBitmapCtrl() { - Profile = "ToolsGuiDefaultProfile"; - position = "94 3"; - Extent = "2 26"; - MinExtent = "1 1"; - bitmap = "tools/gui/images/separator-h.png"; - }; - new GuiBitmapButtonCtrl(ConvexEditorCreateBoxBtn) { + + new GuiBitmapButtonCtrl() { canSaveDynamicFields = "0"; + internalName = "objectGridSnapBtn"; + Enabled = "1"; isContainer = "0"; Profile = "ToolsGuiButtonProfile"; HorizSizing = "right"; VertSizing = "bottom"; - Position = "100 3"; + Position = "5 3"; Extent = "29 27"; MinExtent = "8 8"; canSave = "1"; Visible = "1"; - Command = "ConvexEditorGui.createConvexBox();"; + Command = "ConvexEditorGui.toggleGridSnap();"; tooltipprofile = "ToolsGuiToolTipProfile"; - ToolTip = "Create ConvexShape Box" NL "Use Alt + Click-Drag instead of this for more control of starting placement."; + ToolTip = "Toggles grid snapping (G)"; hovertime = "1000"; - bitmap = "tools/convexEditor/images/convex-editor-btn"; - text = ""; groupNum = "-1"; - buttonType = "pushButton"; + buttonType = "toggleButton"; useMouseEvents = "0"; - }; - new GuiBitmapButtonCtrl(ConvexEditorSplitFaceBtn) { + groupNum = "-1"; + bitmap = "tools/gui/images/menubar/snap-grid"; + textMargin = "4"; + }; + new GuiTextCtrl() { canSaveDynamicFields = "0"; + Enabled = "1"; isContainer = "0"; - Profile = "ToolsGuiButtonProfile"; + Profile = "ToolsGuiTextProfile"; HorizSizing = "right"; VertSizing = "bottom"; - Position = "134 3"; - Extent = "29 27"; - MinExtent = "8 8"; + position = "39 10"; + Extent = "108 10"; + MinExtent = "8 2"; canSave = "1"; Visible = "1"; - Command = "ConvexEditorGui.splitSelectedFace();"; - tooltipprofile = "ToolsGuiToolTipProfile"; - ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control."; hovertime = "1000"; - bitmap = "tools/convexEditor/images/split-face-btn"; - text = ""; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - }; - new GuiBitmapButtonCtrl(ConvexEditorDeleteFaceBtn) { + Margin = "0 0 0 0"; + Padding = "0 0 0 0"; + AnchorTop = "1"; + AnchorBottom = "0"; + AnchorLeft = "1"; + AnchorRight = "0"; + text = "Grid snap size(m)"; + maxLength = "1024"; + }; + new GuiTextEditCtrl() { canSaveDynamicFields = "0"; + internalName = "gridSnapSizeEdit"; isContainer = "0"; - Profile = "ToolsGuiButtonProfile"; + profile="ToolsGuiNumericDropSliderTextProfile"; HorizSizing = "right"; VertSizing = "bottom"; - Position = "166 3"; - Extent = "29 27"; - MinExtent = "8 8"; + position = "130 6"; + Extent = "42 16"; + MinExtent = "8 16"; canSave = "1"; Visible = "1"; - Command = "ConvexEditorGui.handleDelete();"; - tooltipprofile = "ToolsGuiToolTipProfile"; - ToolTip = "Delete selected face" NL "(Delete)"; + class = "ConvexEditorGridSnapSizeFld"; hovertime = "1000"; - bitmap = "tools/gui/images/menubar/delete-btn"; - text = ""; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - }; + text = "1"; + maxLength = "4"; + historySize = "0"; + password = "0"; + tabComplete = "0"; + sinkAllKeyEvents = "0"; + }; }; + new GuiBitmapCtrl() { + Profile = "ToolsGuiDefaultProfile"; + position = "380 3"; + Extent = "2 26"; + MinExtent = "1 1"; + bitmap = "tools/gui/images/separator-h.png"; + }; }; +//--- OBJECT WRITE END --- \ No newline at end of file diff --git a/Templates/BaseGame/game/tools/convexEditor/images/occluderProxyImage.png b/Templates/BaseGame/game/tools/convexEditor/images/occluderProxyImage.png new file mode 100644 index 0000000000..51fe109f4d Binary files /dev/null and b/Templates/BaseGame/game/tools/convexEditor/images/occluderProxyImage.png differ diff --git a/Templates/BaseGame/game/tools/convexEditor/images/portalProxyImage.png b/Templates/BaseGame/game/tools/convexEditor/images/portalProxyImage.png new file mode 100644 index 0000000000..3828f437c7 Binary files /dev/null and b/Templates/BaseGame/game/tools/convexEditor/images/portalProxyImage.png differ diff --git a/Templates/BaseGame/game/tools/convexEditor/images/triggerProxyImage.png b/Templates/BaseGame/game/tools/convexEditor/images/triggerProxyImage.png new file mode 100644 index 0000000000..f21c4c9ad9 Binary files /dev/null and b/Templates/BaseGame/game/tools/convexEditor/images/triggerProxyImage.png differ diff --git a/Templates/BaseGame/game/tools/convexEditor/images/zoneProxyImage.png b/Templates/BaseGame/game/tools/convexEditor/images/zoneProxyImage.png new file mode 100644 index 0000000000..323e174984 Binary files /dev/null and b/Templates/BaseGame/game/tools/convexEditor/images/zoneProxyImage.png differ diff --git a/Templates/BaseGame/game/tools/convexEditor/main.cs b/Templates/BaseGame/game/tools/convexEditor/main.cs index 4577f20e26..c5a3208988 100644 --- a/Templates/BaseGame/game/tools/convexEditor/main.cs +++ b/Templates/BaseGame/game/tools/convexEditor/main.cs @@ -28,16 +28,20 @@ function initializeConvexEditor() exec( "./convexEditorGui.gui" ); exec( "./convexEditorToolbar.ed.gui" ); exec( "./convexEditorGui.cs" ); - + exec( "./convexEditorSidebarGui.gui" ); + exec( "./materials.cs" ); + ConvexEditorGui.setVisible( false ); ConvexEditorOptionsWindow.setVisible( false ); ConvexEditorTreeWindow.setVisible( false ); ConvexEditorToolbar.setVisible( false ); + ConvexEditorOptionssWindow.setVisible( false ); EditorGui.add( ConvexEditorGui ); EditorGui.add( ConvexEditorOptionsWindow ); EditorGui.add( ConvexEditorTreeWindow ); EditorGui.add( ConvexEditorToolbar ); + EditorGui.add( ConvexEditorOptionssWindow ); new ScriptObject( ConvexEditorPlugin ) { @@ -98,6 +102,7 @@ singleton PopupMenu( ConvexActionsMenu ) EditorGui.bringToFront( ConvexEditorGui ); ConvexEditorGui.setVisible( true ); ConvexEditorToolbar.setVisible( true ); + ConvexEditorOptionssWindow.setVisible( true ); ConvexEditorGui.makeFirstResponder( true ); %this.map.push(); @@ -132,6 +137,7 @@ singleton PopupMenu( ConvexActionsMenu ) ConvexEditorGui.setVisible( false ); ConvexEditorOptionsWindow.setVisible( false ); ConvexEditorTreeWindow.setVisible( false ); + ConvexEditorOptionssWindow.setVisible( false ); ConvexEditorToolbar.setVisible( false ); %this.map.pop(); diff --git a/Templates/Full/game/tools/convexEditor/convexEditorGui.cs b/Templates/Full/game/tools/convexEditor/convexEditorGui.cs index 1cda5416cb..e2351dde52 100644 --- a/Templates/Full/game/tools/convexEditor/convexEditorGui.cs +++ b/Templates/Full/game/tools/convexEditor/convexEditorGui.cs @@ -22,6 +22,19 @@ function ConvexEditorGui::onWake( %this ) { + convexEditorToolbar-->gridSnapSizeEdit.setText(%this.getGridSnapSize()); + + if(ConvexEditorOptionssWindow-->matPreviewBtn.bitmap $= "") + { + //no active material, so set one + ConvexEditorOptionssWindow-->matPreviewBtn.setText(""); + + %mat = EditorSettings.Value("ConvexEditor/MaterialName"); + + ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%mat.diffuseMap[0]); + + ConvexEditorOptionssWindow.activeMaterial = %mat; + } } function ConvexEditorGui::onSleep( %this ) @@ -45,18 +58,159 @@ ConvexEditorDeleteFaceBtn.setActive( false ); ConvexEditorDeleteFaceBtn.ToolTip = "Delete selection [Disabled] (Delete)"; - if ( !isObject( %shape ) ) + if ( !isObject( %shape ) ) + { + ConvexEditorOptionssWindow-->defMatPreviewBtn.setText("No Brush Selected"); + ConvexEditorOptionssWindow.activeShape = ""; return; + } ConvexEditorDeleteFaceBtn.setActive( true ); + + ConvexEditorOptionssWindow-->defMatPreviewBtn.setText(""); + ConvexEditorOptionssWindow-->defMatPreviewBtn.setBitmap(%shape.material.diffuseMap[0]); + + ConvexEditorOptionssWindow.activeShape = %shape; if ( %face == -1 ) + { ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected ConvexShape (Delete)"; + + ConvexEditorOptionssWindow-->UOffset.setText(""); + ConvexEditorOptionssWindow-->VOffset.setText(""); + + ConvexEditorOptionssWindow-->UScale.setText(""); + ConvexEditorOptionssWindow-->VScale.setText(""); + + ConvexEditorOptionssWindow-->ZRotation.setText(""); + } else { ConvexEditorDeleteFaceBtn.ToolTip = "Delete selected Face (Delete)"; ConvexEditorSplitFaceBtn.ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control"; ConvexEditorSplitFaceBtn.setActive( true ); + + %UVOffset = %this.getSelectedFaceUVOffset(); + + ConvexEditorOptionssWindow-->UOffset.setText(%UVOffset.x); + ConvexEditorOptionssWindow-->VOffset.setText(%UVOffset.y); + + %UVScale = %this.getSelectedFaceUVScale(); + + ConvexEditorOptionssWindow-->UScale.setText(%UVScale.x); + ConvexEditorOptionssWindow-->VScale.setText(%UVScale.y); + + ConvexEditorOptionssWindow-->ZRotation.setText(ConvexEditorGui.getSelectedFaceZRot()); } +} + +function ConvexEditorUVFld::onReturn(%this) +{ + EWorldEditor.isDirty = true; + + %offset = "0 0"; + %offset.x = ConvexEditorOptionssWindow-->UOffset.getText(); + %offset.y = ConvexEditorOptionssWindow-->VOffset.getText(); + + %scale = "0 0"; + %scale.x = ConvexEditorOptionssWindow-->UScale.getText(); + %scale.y = ConvexEditorOptionssWindow-->VScale.getText(); + + %rot = ConvexEditorOptionssWindow-->ZRotation.getText(); + + ConvexEditorGui.setSelectedFaceUVOffset(%offset); + ConvexEditorGui.setSelectedFaceUVScale(%scale); + ConvexEditorGui.setSelectedFaceZRot(%rot); +} + +function ConvexEditorUVHorzFlipBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + %current = ConvexEditorGui.getSelectedFaceHorzFlip(); + ConvexEditorGui.setSelectedFaceHorzFlip(!%current); +} + +function ConvexEditorUVVertFlipBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + %current = ConvexEditorGui.getSelectedFaceVertFlip(); + ConvexEditorGui.setSelectedFaceVertFlip(!%current); +} + +function ConvexEditorMaterialBtn::onClick(%this) +{ + %this.getMaterialName(); +} + +function ConvexEditorMaterialBtn::getMaterialName(%this) +{ + materialSelector.showDialog(%this @ ".gotMaterialName", "name"); +} + +function ConvexEditorMaterialBtn::gotMaterialName(%this, %name) +{ + //eval(%this.object @ "." @ %this.targetField @ " = " @ %name @ ";"); + //%this.object.changeMaterial(getTrailingNumber(%this.targetField), %name); + //%this.object.inspectorApply(); + %diffusemap = %name.diffuseMap[0]; + + ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%diffusemap); + + ConvexEditorOptionssWindow.activeMaterial = %name; +} + +function ConvexEditorMaterialApplyBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + ConvexEditorGui.setSelectedFaceMaterial(ConvexEditorOptionssWindow.activeMaterial); + ConvexEditorGui.updateShape(); +} + +function ConvexEditorMaterialLiftBtn::onClick(%this) +{ + %mat = ConvexEditorGui.getSelectedFaceMaterial(); + ConvexEditorOptionssWindow.activeMaterial = %mat; + ConvexEditorOptionssWindow-->matPreviewBtn.setBitmap(%mat.diffuseMap[0]); +} + +function ConvexEditorMaterialResetBtn::onClick(%this) +{ + EWorldEditor.isDirty = true; + ConvexEditorGui.setSelectedFaceMaterial(ConvexEditorOptionssWindow.activeShape.material); + ConvexEditorGui.updateShape(); +} + +function ConvexEditorGui::toggleGridSnap(%this) +{ + %this.toggleGridSnapping(); +} + +function ConvexEditorGridSnapSizeFld::onReturn(%this) +{ + ConvexEditorGui.setGridSnapSize(%this.getText()); +} + +function ConvexEditorDefaultMaterialBtn::onClick(%this) +{ + %this.getMaterialName(); +} + +function ConvexEditorDefaultMaterialBtn::getMaterialName(%this) +{ + materialSelector.showDialog(%this @ ".gotMaterialName", "name"); +} + +function ConvexEditorDefaultMaterialBtn::gotMaterialName(%this, %name) +{ + //eval(%this.object @ "." @ %this.targetField @ " = " @ %name @ ";"); + //%this.object.changeMaterial(getTrailingNumber(%this.targetField), %name); + //%this.object.inspectorApply(); + %diffusemap = %name.diffuseMap[0]; + + ConvexEditorOptionssWindow-->defMatPreviewBtn.setBitmap(%diffusemap); + + ConvexEditorOptionssWindow.activeShape.material = %name; + + ConvexEditorGui.updateShape(); } \ No newline at end of file diff --git a/Templates/Full/game/tools/convexEditor/convexEditorToolbar.ed.gui b/Templates/Full/game/tools/convexEditor/convexEditorToolbar.ed.gui index 575907d81b..bd76a265eb 100644 --- a/Templates/Full/game/tools/convexEditor/convexEditorToolbar.ed.gui +++ b/Templates/Full/game/tools/convexEditor/convexEditorToolbar.ed.gui @@ -21,6 +21,95 @@ EdgeSnap = "0"; text =""; + new GuiTextCtrl() { + profile = "ToolsGuiTextProfile"; + horizSizing = "right"; + vertSizing = "bottom"; + position = "15 7"; + extent = "86 16"; + minExtent = "8 8"; + visible = "1"; + text = "Sketch Tool"; + maxLength = "255"; + helpTag = "0"; + }; + new GuiBitmapCtrl() { + Profile = "ToolsGuiDefaultProfile"; + position = "94 3"; + Extent = "2 26"; + MinExtent = "1 1"; + bitmap = "tools/gui/images/separator-h.png"; + }; + new GuiBitmapButtonCtrl(ConvexEditorCreateBoxBtn) { + canSaveDynamicFields = "0"; + isContainer = "0"; + Profile = "ToolsGuiButtonProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + Position = "100 3"; + Extent = "29 27"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + Command = "ConvexEditorGui.createConvexBox();"; + tooltipprofile = "ToolsGuiToolTipProfile"; + ToolTip = "Create ConvexShape Box" NL "Use Alt + Click-Drag instead of this for more control of starting placement."; + hovertime = "1000"; + bitmap = "tools/convexEditor/images/convex-editor-btn"; + text = ""; + groupNum = "-1"; + buttonType = "pushButton"; + useMouseEvents = "0"; + }; + new GuiBitmapButtonCtrl(ConvexEditorSplitFaceBtn) { + canSaveDynamicFields = "0"; + isContainer = "0"; + Profile = "ToolsGuiButtonProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + Position = "134 3"; + Extent = "29 27"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + Command = "ConvexEditorGui.splitSelectedFace();"; + tooltipprofile = "ToolsGuiToolTipProfile"; + ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control."; + hovertime = "1000"; + bitmap = "tools/convexEditor/images/split-face-btn"; + text = ""; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + }; + new GuiBitmapButtonCtrl(ConvexEditorDeleteFaceBtn) { + canSaveDynamicFields = "0"; + isContainer = "0"; + Profile = "ToolsGuiButtonProfile"; + HorizSizing = "right"; + VertSizing = "bottom"; + Position = "166 3"; + Extent = "29 27"; + MinExtent = "8 8"; + canSave = "1"; + Visible = "1"; + Command = "ConvexEditorGui.handleDelete();"; + tooltipprofile = "ToolsGuiToolTipProfile"; + ToolTip = "Delete selected face" NL "(Delete)"; + hovertime = "1000"; + bitmap = "tools/gui/images/menubar/delete-btn"; + text = ""; + groupNum = "-1"; + buttonType = "PushButton"; + useMouseEvents = "0"; + }; + new GuiBitmapCtrl() { + Profile = "ToolsGuiDefaultProfile"; + position = "190 3"; + Extent = "2 26"; + MinExtent = "1 1"; + bitmap = "tools/gui/images/separator-h.png"; + }; new GuiContainer() { canSaveDynamicFields = "0"; Enabled = "1"; @@ -28,94 +117,87 @@ Profile = "menubarProfile"; HorizSizing = "width"; VertSizing = "bottom"; - Position = "0 0"; - Extent = "800 32"; + Position = "195 0"; + Extent = "190 32"; MinExtent = "8 8"; canSave = "1"; Visible = "1"; hovertime = "1000"; - - new GuiTextCtrl() { - profile = "ToolsGuiTextProfile"; - horizSizing = "right"; - vertSizing = "bottom"; - position = "15 7"; - extent = "86 16"; - minExtent = "8 8"; - visible = "1"; - text = "Sketch Tool"; - maxLength = "255"; - helpTag = "0"; - }; - new GuiBitmapCtrl() { - Profile = "ToolsGuiDefaultProfile"; - position = "94 3"; - Extent = "2 26"; - MinExtent = "1 1"; - bitmap = "tools/gui/images/separator-h.png"; - }; - new GuiBitmapButtonCtrl(ConvexEditorCreateBoxBtn) { + + new GuiBitmapButtonCtrl() { canSaveDynamicFields = "0"; + internalName = "objectGridSnapBtn"; + Enabled = "1"; isContainer = "0"; Profile = "ToolsGuiButtonProfile"; HorizSizing = "right"; VertSizing = "bottom"; - Position = "100 3"; + Position = "5 3"; Extent = "29 27"; MinExtent = "8 8"; canSave = "1"; Visible = "1"; - Command = "ConvexEditorGui.createConvexBox();"; + Command = "ConvexEditorGui.toggleGridSnap();"; tooltipprofile = "ToolsGuiToolTipProfile"; - ToolTip = "Create ConvexShape Box" NL "Use Alt + Click-Drag instead of this for more control of starting placement."; + ToolTip = "Toggles grid snapping (G)"; hovertime = "1000"; - bitmap = "tools/convexEditor/images/convex-editor-btn"; - text = ""; groupNum = "-1"; - buttonType = "pushButton"; + buttonType = "toggleButton"; useMouseEvents = "0"; - }; - new GuiBitmapButtonCtrl(ConvexEditorSplitFaceBtn) { + groupNum = "-1"; + bitmap = "tools/gui/images/menubar/snap-grid"; + textMargin = "4"; + }; + new GuiTextCtrl() { canSaveDynamicFields = "0"; + Enabled = "1"; isContainer = "0"; - Profile = "ToolsGuiButtonProfile"; + Profile = "ToolsGuiTextProfile"; HorizSizing = "right"; VertSizing = "bottom"; - Position = "134 3"; - Extent = "29 27"; - MinExtent = "8 8"; + position = "39 10"; + Extent = "108 10"; + MinExtent = "8 2"; canSave = "1"; Visible = "1"; - Command = "ConvexEditorGui.splitSelectedFace();"; - tooltipprofile = "ToolsGuiToolTipProfile"; - ToolTip = "Split selected face" NL "Use Ctrl + Rotate instead for more control."; hovertime = "1000"; - bitmap = "tools/convexEditor/images/split-face-btn"; - text = ""; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - }; - new GuiBitmapButtonCtrl(ConvexEditorDeleteFaceBtn) { + Margin = "0 0 0 0"; + Padding = "0 0 0 0"; + AnchorTop = "1"; + AnchorBottom = "0"; + AnchorLeft = "1"; + AnchorRight = "0"; + text = "Grid snap size(m)"; + maxLength = "1024"; + }; + new GuiTextEditCtrl() { canSaveDynamicFields = "0"; + internalName = "gridSnapSizeEdit"; isContainer = "0"; - Profile = "ToolsGuiButtonProfile"; + profile="ToolsGuiNumericDropSliderTextProfile"; HorizSizing = "right"; VertSizing = "bottom"; - Position = "166 3"; - Extent = "29 27"; - MinExtent = "8 8"; + position = "130 6"; + Extent = "42 16"; + MinExtent = "8 16"; canSave = "1"; Visible = "1"; - Command = "ConvexEditorGui.handleDelete();"; - tooltipprofile = "ToolsGuiToolTipProfile"; - ToolTip = "Delete selected face" NL "(Delete)"; + class = "ConvexEditorGridSnapSizeFld"; hovertime = "1000"; - bitmap = "tools/gui/images/menubar/delete-btn"; - text = ""; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - }; + text = "1"; + maxLength = "4"; + historySize = "0"; + password = "0"; + tabComplete = "0"; + sinkAllKeyEvents = "0"; + }; }; + new GuiBitmapCtrl() { + Profile = "ToolsGuiDefaultProfile"; + position = "380 3"; + Extent = "2 26"; + MinExtent = "1 1"; + bitmap = "tools/gui/images/separator-h.png"; + }; }; +//--- OBJECT WRITE END --- \ No newline at end of file diff --git a/Templates/Full/game/tools/convexEditor/main.cs b/Templates/Full/game/tools/convexEditor/main.cs index 54de25d029..c5a3208988 100644 --- a/Templates/Full/game/tools/convexEditor/main.cs +++ b/Templates/Full/game/tools/convexEditor/main.cs @@ -28,16 +28,20 @@ function initializeConvexEditor() exec( "./convexEditorGui.gui" ); exec( "./convexEditorToolbar.ed.gui" ); exec( "./convexEditorGui.cs" ); - + exec( "./convexEditorSidebarGui.gui" ); + exec( "./materials.cs" ); + ConvexEditorGui.setVisible( false ); ConvexEditorOptionsWindow.setVisible( false ); ConvexEditorTreeWindow.setVisible( false ); ConvexEditorToolbar.setVisible( false ); + ConvexEditorOptionssWindow.setVisible( false ); EditorGui.add( ConvexEditorGui ); EditorGui.add( ConvexEditorOptionsWindow ); EditorGui.add( ConvexEditorTreeWindow ); EditorGui.add( ConvexEditorToolbar ); + EditorGui.add( ConvexEditorOptionssWindow ); new ScriptObject( ConvexEditorPlugin ) { @@ -98,6 +102,7 @@ singleton PopupMenu( ConvexActionsMenu ) EditorGui.bringToFront( ConvexEditorGui ); ConvexEditorGui.setVisible( true ); ConvexEditorToolbar.setVisible( true ); + ConvexEditorOptionssWindow.setVisible( true ); ConvexEditorGui.makeFirstResponder( true ); %this.map.push(); @@ -132,6 +137,7 @@ singleton PopupMenu( ConvexActionsMenu ) ConvexEditorGui.setVisible( false ); ConvexEditorOptionsWindow.setVisible( false ); ConvexEditorTreeWindow.setVisible( false ); + ConvexEditorOptionssWindow.setVisible( false ); ConvexEditorToolbar.setVisible( false ); %this.map.pop(); @@ -189,7 +195,7 @@ singleton PopupMenu( ConvexActionsMenu ) { if( ConvexEditorGui.isDirty ) { - getRootScene().save( %missionFile ); + getScene(0).save( %missionFile ); ConvexEditorGui.isDirty = false; } } @@ -201,7 +207,7 @@ singleton PopupMenu( ConvexActionsMenu ) function ConvexEditorPlugin::initSettings( %this ) { EditorSettings.beginGroup( "ConvexEditor", true ); - EditorSettings.setDefaultValue( "MaterialName", "Grid512_OrangeLines_Mat" ); + EditorSettings.setDefaultValue( "MaterialName", "Grid_512_Orange" ); EditorSettings.endGroup(); }