diff options
| author | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
|---|---|---|
| committer | Ben Marsh <[email protected]> | 2019-10-22 09:07:59 -0400 |
| commit | bd0027e737c6512397f841c22786274ed74b927f (patch) | |
| tree | f7ffbdb8f3741bb7f24635616cc189cba5cb865c /mayaPlug/shaveBrushManip.cpp | |
| download | shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.tar.xz shave-and-a-haircut-bd0027e737c6512397f841c22786274ed74b927f.zip | |
Adding Shave-and-a-Haircut 9.6
Diffstat (limited to 'mayaPlug/shaveBrushManip.cpp')
| -rw-r--r-- | mayaPlug/shaveBrushManip.cpp | 1069 |
1 files changed, 1069 insertions, 0 deletions
diff --git a/mayaPlug/shaveBrushManip.cpp b/mayaPlug/shaveBrushManip.cpp new file mode 100644 index 0000000..bc0079b --- /dev/null +++ b/mayaPlug/shaveBrushManip.cpp @@ -0,0 +1,1069 @@ +// Shave and a Haircut +// (c) 2019 Epic Games +// US Patent 6720962 + +//Qt headers must be included before any others !!! +#if (defined LINUX) || (defined OSMac_) +#include <QtOpenGL/QGLContext> +#include <QtOpenGL/QGLWidget> + +#if QT_VERSION < 0x050000 +# include <QtGui/QWidget> +#else +# include <QtWidgets/QWidget> +#endif +#endif + +#include <maya/M3dView.h> +#include <maya/MDagPath.h> +#include <maya/MFnDependencyNode.h> +#include <maya/MFnNumericAttribute.h> +#include <maya/MFnTransform.h> +#include <maya/MHWGeometry.h> +#include <maya/MGlobal.h> +#include <maya/MPoint.h> +#include <maya/MShaderManager.h> +#include <maya/MString.h> +#include <maya/MVector.h> + +#if defined(_WIN32) && (MAYA_API_VERSION >= 201600) +#include <Windows.h> +#endif + +#ifdef OSMac_MachO_ +# include <OpenGL/gl.h> +# include <OpenGL/glu.h> +//# include <AppKit/NSOpenGL.h> +#else +//#define GL_GLEXT_PROTOTYPES +# include <GL/gl.h> +# include <GL/glu.h> +#endif + +#include "shaveBrushManip.h" + +MTypeId shaveBrushManip::id(0x001029B8); +MString shaveBrushManip::nodeTypeName = "shaveBrushManip"; + + +// The 'fast brush' does an XOR draw on top of the view, meaning that it +// can be drawn and erased without having Maya redraw the entire view. +// +// The standard brush is drawn normally during a refresh, which is +// triggered either by moving a proxy transform within the scene to match +// the mouse movement, or by forcing a refresh. +// +// The fast brush is enabled by default in shaveGlobals, but on some +// graphics cards it can cause visual anomalies, in which case the user +// can switch to the standard brush. + +shaveBrushManip::shaveBrushManip() +: mBrushSize(0.0f) +, mClearOld(false) +, mCX(-1) +, mCY(-1) +, mFastBrush(true) +, mIsActive(false) +, mViewHeight(0) +, mViewWidth(0) +, mWindow(0) +{ + aWidget = NULL; +} + + +shaveBrushManip::~shaveBrushManip() +{ + mProxy = MObject::kNullObj; +} + + +MStatus shaveBrushManip::connectToDependNode(const MObject& node) +{ + //thisObj = thisMObject(); + + finishAddingManips(); + MPxManipContainer::connectToDependNode(node); + + if (!mFastBrush) + { + MFnDependencyNode nodeFn(node); + mProxy = node; + } + + return MS::kSuccess; +} + + +MStatus shaveBrushManip::createChildren() +{ + // + // We don't want any manips because their handles, even though not + // drawn, can still capture mouse clicks. + // + return MS::kSuccess; +} + + +void shaveBrushManip::draw( + M3dView& view, + const MDagPath& path, + M3dView::DisplayStyle dStyle, + M3dView::DisplayStatus dStatus +) +{ + if (mFastBrush) + { + // + // If Maya is asking us to redraw in the same view where we last did a + // draw, then it must have already cleared the old image, so we should + // not try to clear it ourselves. + // + if (mClearOld && isSameView(view)) mClearOld = false; + } + else + { + M3dView activeView = M3dView::active3dView(); + + if ((view.window() == activeView.window()) + && (mCX >= 0) && (mCY >= 0) + && (mCX < view.portWidth()) && (mCY < view.portHeight())) + { + prepareView(activeView); + drawBrush(); + restoreView(activeView); + } + } +} + + +void shaveBrushManip::getBrushRadii(int& rx, int& ry) const +{ + rx = mRX; + ry = mRY; +} + + +void shaveBrushManip::leaveView() +{ + //MGlobal::displayInfo("leaveView"); + + /////////////////////////// + //return; + /////////////////////////// + + if (mIsActive) + { + M3dView activeView = M3dView::active3dView(); + + if (mFastBrush) + eraseBrush(activeView); + else + { + if(mCX != -1 || mCY != -1) //to avoid exra redraws + { + // This will let us know not to draw the brush. + mCX = mCY = -1; + + // Force Maya to redraw the view so that the brush will be + // erased. + activeView.refresh(false, true); + } + } + } +} + + +void shaveBrushManip::setActive(bool active) +{ + /////////////////////////// + //return; + /////////////////////////// + + if (mIsActive != active) + { + // + // If we're being made active then clear out the old view + // information. + // + // If we're being made inactive then erase the current brush image. + // + if (active) + { + mWindow = 0; + mViewHeight = 0; + mViewWidth = 0; + } + else + { + M3dView activeView = M3dView::active3dView(); + eraseBrush(activeView, false); + } + + mIsActive = active; + } +} + + +void shaveBrushManip::setBrushPos( + int cx, int cy, bool forceRedraw, bool isMayaDraw +) +{ + /////////////////////////// + //return; + /////////////////////////// + + //printf("set pos %i %i\n",cx,cx);fflush(stdout); + + M3dView activeView = M3dView::active3dView(); + bool isNewView = !isSameView(activeView); + + // If someone is giving us brush positions, then we must be active. + setActive(true); + + if (mFastBrush) + { + // If we were previously inactive or the view has changed, then we + // will need to redraw the brush even if its position is unchanged. + if (isNewView || !mIsActive) + forceRedraw = true; + + // If the brush has moved, or this is a forced redraw, then do the + // draw. + if (forceRedraw || (mCX != cx) || (mCY != cy)) + { + bool activeViewPrepared = eraseBrush(activeView, true); + + if (!activeViewPrepared) prepareView(activeView); + + // If we've changed views, or the view has changed size, then + // we need to recalculate the radii. + if (isNewView) + { + saveView(activeView); + calculateRadii(); + } + + mCX = cx; + mCY = cy; + + if ((mCX >= 0) && (mCY >= 0)) + { + drawBrush(); + mClearOld = true; + } + + if (!isMayaDraw) + swapGLBuffers(activeView); + + restoreView(activeView); + } + } + else + { + // If the brush has moved, move the proxy transform + // correspondingly. + if ((mCX != cx) || (mCY != cy)) + { + // If we've changed views, or the view has changed size, then + // we need to recalculate the radii. + if (isNewView) + { + saveView(activeView); + calculateRadii(); + } + + MPoint nearPlane; + MPoint farPlane; + activeView.viewToWorld(cx, cy, nearPlane, farPlane); + + MVector translation( + (nearPlane.x + farPlane.x) / 2.0, + (nearPlane.y + farPlane.y) / 2.0, + (nearPlane.z + farPlane.z) / 2.0 + ); + MFnTransform transformFn(mProxy); + transformFn.setTranslation(translation, MSpace::kObject); + + mCX = cx; + mCY = cy; + } + } + + MHWRender::MRenderer::setGeometryDrawDirty(thisObj); +} + + +void shaveBrushManip::setBrushSize(float brushSize) +{ + /////////////////////////// + //return; + /////////////////////////// + + if (brushSize != mBrushSize) + { + M3dView view; + bool viewPrepared = false; + bool foundView = findOldView(view); + + if (foundView) + viewPrepared = eraseBrush(view, true); + + mBrushSize = brushSize; + + if (foundView) + { + calculateRadii(); + + if (!viewPrepared) + prepareView(view); + + if ((mCX >= 0) && (mCY >= 0)) + { + drawBrush(); + mClearOld = true; + } + + swapGLBuffers(view); + restoreView(view); + } + } +} + + +//---------------------------------------------------------------------- +// +// Internal Methods +// +//---------------------------------------------------------------------- + +void shaveBrushManip::calculateRadii() +{ + unsigned radius; + + if (mViewHeight < mViewWidth) + radius = (unsigned)((float)mViewHeight * mBrushSize / 2.0f + 0.5); + else + radius = (unsigned)((float)mViewWidth * mBrushSize / 2.0f + 0.5); + + if (radius < 4) radius = 4; + + // + // %%% We eventually need to compensate for non-square pixels by + // assigning X and Y different radii. + // + mRX = radius; + mRY = radius; +} + + +void shaveBrushManip::drawBrush() const +{ + //printf("draw pos %i %i\n",mCX,mCY);fflush(stdout); + // + // Draw the outer circle. We use an ellipse drawing method because + // eventually we want to support displays with non-square pixels, which + // will require different X and Y radii. + // + drawEllipse(mCX, mCY, mRX, mRY); + +#if 0 + // + // Draw a small crosshair in the center. + // + glBegin(GL_LINES); + glVertex2i(mCX-4, mCY); + glVertex2i(mCX+4, mCY); + + glVertex2i(mCX, mCY-4); + glVertex2i(mCX, mCY+4); + glEnd(); +#endif +} + + +// +// This method uses a DDA to draw an ellipse with the given radii into the +// bitmap. +// +// The algorithm is taken almost verbatim from Tim Kientzle's 'Algorithm +// Alley' column in the July, 1994 issue of Dr. Dobb's Journal. +// +void shaveBrushManip::drawEllipse(int cx, int cy, unsigned rx, unsigned ry) +{ + const unsigned rxSquared = rx * rx; + const unsigned rySquared = ry * ry; + const unsigned twoRXSquared = 2 * rxSquared; + const unsigned twoRYSquared = 2 * rySquared; + + glBegin(GL_POINTS); + + // + // Plot the octant from the top of the ellipse to the top-right + // and reflect it in the other four quadrants. + // + int x = 0; + int y = ry; + + int twoXTimesRYSquared = 0; + int twoYTimesRXSquared = (int)(y * twoRXSquared); + int error = -(int)(y * rxSquared); + + while (twoXTimesRYSquared <= twoYTimesRXSquared) + { + drawMirroredVert(cx, cy, x, y); + + x += 1; + twoXTimesRYSquared += (int)twoRYSquared; + error += twoXTimesRYSquared - (int)rySquared; + + if (error >= 0) + { + y -= 1; + twoYTimesRXSquared -= (int)twoRXSquared; + error -= twoYTimesRXSquared; + } + } + + // + // Plot the octant from the right of the ellipse to the top-right + // and reflect it in the other four quadrants. + // + x = rx; + y = 0; + twoXTimesRYSquared = (int)(x * twoRYSquared); + twoYTimesRXSquared = 0; + error = -(int)(x * rySquared); + + while (twoXTimesRYSquared > twoYTimesRXSquared) + { + drawMirroredVert(cx, cy, x, y); + + y += 1; + twoYTimesRXSquared += (int)twoRXSquared; + error += twoYTimesRXSquared - (int)rxSquared; + + if (error >= 0) + { + x -= 1; + twoXTimesRYSquared -= (int)twoRYSquared; + error -= twoXTimesRYSquared; + } + } + + glEnd(); +} + + +void shaveBrushManip::drawMirroredVert(int cx, int cy, int x, int y) +{ + // + // Mirror the vert in the four quadrants around the center point. + // + // Because we are drawing in XOR mode, we don't want to plot the same + // point an even number of times as that will be as if we hadn't + // plotted it at all. So we have special cases for x==0 and y==0 to + // prevent that. + // + if (x == 0) + { + glVertex2i(cx, cy + y); + glVertex2i(cx, cy - y); + } + else if (y == 0) + { + glVertex2i(cx + x, cy); + glVertex2i(cx - x, cy); + } + else + { + glVertex2i(cx + x, cy + y); + glVertex2i(cx + x, cy - y); + glVertex2i(cx - x, cy + y); + glVertex2i(cx - x, cy - y); + } +} + + +bool shaveBrushManip::eraseBrush( + M3dView& currentView, bool dontRestoreCurrentView +) +{ + bool currentViewIsPrepared = false; + + + if (mFastBrush && mClearOld) + { + // + // If the previous brush image was drawn in a different view from + // the one passed to us by the caller, then we must find that view. + // + if (!isSameView(currentView)) + { + M3dView oldView; + + if (findOldView(oldView)) + { + prepareView(oldView); + drawBrush(); + swapGLBuffers(oldView); + restoreView(oldView); + } + } + else + { + prepareView(currentView); + drawBrush(); + + if (dontRestoreCurrentView) + currentViewIsPrepared = true; + else + { + swapGLBuffers(currentView); + restoreView(currentView); + } + } + + mClearOld = false; + } + + return currentViewIsPrepared; +} + + +bool shaveBrushManip::findOldView(M3dView& view) const +{ + if (mIsActive) + { + unsigned numViews = M3dView::numberOf3dViews(); + unsigned i; + + for (i = 0; i < numViews; i++) + { + M3dView::get3dView(i, view); + + if (isSameView(view)) return true; + } + } + + return false; +} + + +bool shaveBrushManip::isSameView(M3dView& view) const +{ + if ((view.window() != mWindow) + || (view.portHeight() != mViewHeight) + || (view.portWidth() != mViewWidth)) + { + return false; + + } + + +#if OSMac_ + QWidget* wgt = view.widget(); + return (wgt == aWidget); +#endif + + return true; +} + +void shaveBrushManip::prepareView(M3dView& view) +{ + view.beginGL(); + + glPushAttrib(GL_TRANSFORM_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D( + 0.0, (GLdouble)view.portWidth(), + 0.0, (GLdouble)view.portHeight() + ); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + // This bit of magic is from marqueeTool.cpp in the devkit. + glTranslatef(0.375, 0.375, 0.0); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + if (mFastBrush) + { + glEnable(GL_COLOR_LOGIC_OP); + glLogicOp(GL_XOR); + + // Because we're doing XOR, if we set the draw color to 12 (red) + // it won't appear red when over the default grey background of + // Maya's views. By choosing light green XOR will give us + // reddish-orange against a grey background, which is at least + // close to red. + view.setDrawColor(18, M3dView::kActiveColors); + } + else + view.setDrawColor(12, M3dView::kActiveColors); // red +} + + +void shaveBrushManip::restoreView(M3dView& view) +{ + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glPopAttrib(); + + view.endGL(); +} + + +void shaveBrushManip::saveView(M3dView& view) +{ + mWindow = view.window(); + mViewHeight = view.portHeight(); + mViewWidth = view.portWidth(); + +#ifdef OSMac_ + // + // On OSX the views do not have their own windows but are merely + // regions within the main window. So to know if we have the correct + // view we must compare not just the window but the position of the + // region. + // + aWidget = view.widget(); +#endif +} + + +void shaveBrushManip::swapGLBuffers(M3dView& view) +{ +#if defined(LINUX) + glXSwapBuffers(view.display(), view.window()); +#elif defined(OSMac_) + //there is no good way to swap buffers now + //so we grey out 'fast brush' checkbox for 2011 + + //const QGLContext* qgl = QGLContext::currentContext(); + //if(qgl) + // qgl->swapBuffers(); + //else + // MGlobal::displayInfo("null QGLContext"); + + //NSOpenGLContext* nsgl = view.display(); + //[nsgl flushBuffer]; //cocoa + //nsgl->flushBuffer(); + //CGLContextObj* cgl = nsgl->CGLContextObj(); +#elif defined(_WIN32) + SwapBuffers(view.deviceContext()); +#else + #error Unsupported OS type. +#endif +} + +MString shaveBrushManip::drawDbClassification("drawdb/geometry/shaveBrushManip"); +MString shaveBrushManip::drawRegistrantId("shave_and_haircut_brush"); + +MObject shaveBrushManip::trigger; + +MStatus shaveBrushManip::initialize() +{ + MStatus stat; + MFnNumericAttribute na; + + trigger = na.create("atrigger", "tr", MFnNumericData::kInt,0,&stat); + if(stat != MStatus::kSuccess) + { + MGlobal::displayError("shaveBrushManip: can't create attribute"); + } + na.setStorable(false); + na.setHidden(true); + + stat = addAttribute(trigger); + if(stat != MStatus::kSuccess) + { + MGlobal::displayError("shaveBrushManip: can't add attribute"); + } + + return MStatus::kSuccess; + //return MPxManipContainer::initialize(); +} + + +// pre-draw callback +static void shaveBrushPreDrawCallback( + MHWRender::MDrawContext& context, + const MHWRender::MRenderItemList& renderItemList, + MHWRender::MShaderInstance *shaderInstance + ) +{ + //printf("Pre-draw callback triggered for render item with name '%s'\n", renderItem->name().asChar()); +} +// post-draw callback +static void shaveBrushPostDrawCallback( + MHWRender::MDrawContext& context, + const MHWRender::MRenderItemList& renderItemList, + MHWRender::MShaderInstance *shaderInstance + ) +{ + //printf("Post-draw callback triggered for render item with name '%s'\n", renderItem->name().asChar()); +} + +shaveBrushOverride::shaveBrushOverride(const MObject& obj) +: MPxGeometryOverride(obj) +, brush(NULL) +{ + MStatus status; + MFnDependencyNode node(obj, &status); + if (status) + { + brush = dynamic_cast<shaveBrushManip*>(node.userNode()); + } +} + +shaveBrushOverride::~shaveBrushOverride() +{ +} + +MHWRender::DrawAPI shaveBrushOverride::supportedDrawAPIs() const +{ + //return MHWRender::kAllDevices; + return MHWRender::kOpenGL; +} + +void shaveBrushOverride::updateDG() +{ + if (brush) + { + //nothing to do at the moment + } +} + +//#define BRUSH_BY_SHADER //geom shaders are + +static const bool debugShader = false;//true; + +void shaveBrushOverride::updateRenderItems(const MDagPath& path, + MHWRender::MRenderItemList& list) +{ + MHWRender::MRenderer* renderer = MHWRender::MRenderer::theRenderer(); + if (!renderer) return; + + const MHWRender::MShaderManager* shaderMgr = renderer->getShaderManager(); + if (!shaderMgr) return; + + + MHWRender::MRenderItem* item = NULL; + int index = list.indexOf( + "shaveBrush", +//#ifdef BRUSH_BY_SHADER +// MHWRender::MGeometry::kPoints, +//#else + MHWRender::MGeometry::kLines, +//#endif + MHWRender::MGeometry::kAll); + + if (index < 0) + { + item = MHWRender::MRenderItem::Create + ( "shaveBrush", +//#ifdef BRUSH_BY_SHADER +// MHWRender::MGeometry::kPoints, +//#else + MHWRender::MGeometry::kLines, +//#endif + MHWRender::MGeometry::kAll, + false); + list.append(item); + + //MHWRender::MShaderInstance* shader = shaderMgr->getStockShader( + // MHWRender::MShaderManager::k3dSolidShader, + // debugShader ? shaveBrushPreDrawCallback : NULL, + // debugShader ? shaveBrushPostDrawCallback : NULL); + MHWRender::MShaderInstance* shader = shaderMgr->getEffectsFileShader("shaveHair.cgfx","Brush"); + if (shader) + { + //static const float theColor[] = {0.0f, 0.01f, 0.27f, 1.0f}; + //shader->setParameter("solidColor", theColor); + + // assign shader + item->setShader(shader); + + // sample debug code + if (debugShader) + { + MStringArray params; + shader->parameterList(params); + unsigned int numParams = params.length(); + printf("DEBUGGING SHADER, BEGIN PARAM LIST OF LENGTH %d\n", numParams); + for (unsigned int i=0; i<numParams; i++) + { + printf("ParamName='%s', ParamType=", params[i].asChar()); + switch (shader->parameterType(params[i])) + { + case MHWRender::MShaderInstance::kInvalid: + printf("'Invalid', "); + break; + case MHWRender::MShaderInstance::kBoolean: + printf("'Boolean', "); + break; + case MHWRender::MShaderInstance::kInteger: + printf("'Integer', "); + break; + case MHWRender::MShaderInstance::kFloat: + printf("'Float', "); + break; + case MHWRender::MShaderInstance::kFloat2: + printf("'Float2', "); + break; + case MHWRender::MShaderInstance::kFloat3: + printf("'Float3', "); + break; + case MHWRender::MShaderInstance::kFloat4: + printf("'Float4', "); + break; + case MHWRender::MShaderInstance::kFloat4x4Row: + printf("'Float4x4Row', "); + break; + case MHWRender::MShaderInstance::kFloat4x4Col: + printf("'Float4x4Col', "); + break; + case MHWRender::MShaderInstance::kTexture1: + printf("'1D Texture', "); + break; + case MHWRender::MShaderInstance::kTexture2: + printf("'2D Texture', "); + break; + case MHWRender::MShaderInstance::kTexture3: + printf("'3D Texture', "); + break; + case MHWRender::MShaderInstance::kTextureCube: + printf("'Cube Texture', "); + break; + case MHWRender::MShaderInstance::kSampler: + printf("'Sampler', "); + break; + default: + printf("'Unknown', "); + break; + } + printf("IsArrayParameter='%s'\n", shader->isArrayParameter(params[i]) ? "YES" : "NO"); + } + printf("END PARAM LIST\n"); + fflush(stdout); + } + } + } +} + + + +void shaveBrushOverride::populateGeometry( + const MHWRender::MGeometryRequirements& requirements, + const MHWRender::MRenderItemList& itemList, + MHWRender::MGeometry& data + ) +{ + MHWRender::MVertexBuffer* positionBuffer = NULL; + float* positions = NULL; + + const MHWRender::MVertexBufferDescriptorList& descList = requirements.vertexRequirements(); + int numVertexReqs = descList.length(); + MHWRender::MVertexBufferDescriptor desc; + +#ifndef BRUSH_BY_SHADER + int nsegs = 24; + int nverts = nsegs*2; +#endif + + for (int reqNum=0; reqNum<numVertexReqs; reqNum++) + { + if (!descList.getDescriptor(reqNum, desc)) + { + continue; + } + + switch (desc.semantic()) + { + case MHWRender::MGeometry::kPosition: + { + positionBuffer = data.createVertexBuffer(desc); + if (positionBuffer) +#ifdef BRUSH_BY_SHADER + positions = (float*)positionBuffer->acquire(2); +#else + positions = (float*)positionBuffer->acquire(nverts); +#endif + } + break; + + case MHWRender::MGeometry::kColor: + case MHWRender::MGeometry::kTexture: + case MHWRender::MGeometry::kNormal: + case MHWRender::MGeometry::kTangent: + case MHWRender::MGeometry::kBitangent: + default: + break; + } + } + + + if (positions) + { +#ifdef BRUSH_BY_SHADER + + M3dView activeView = M3dView::active3dView(); + float H = (float)activeView.portHeight(); + float W = (float)activeView.portWidth(); + + float x = (brush->mCX - 0.5f*W)/(0.5f*W); + float y = (brush->mCY - 0.5f*H)/(0.5f*H); + + //MVector C(0.0f, 0.0f, 0.0f); + MVector C(x, y, 0.0f); + //MVector C(brush->mCX, brush->mCY, 0.0f); + + positions[0] = C.x; + positions[1] = C.y; + positions[2] = 0.0f; + + + float w = brush->mRX/(0.5f*W); + float h = brush->mRY/(0.5f*H); + + MVector P(w, h, 0.0f); + //MVector P(brush->mRX, brush->mRY, 0.0f); + + positions[3] = P.x; + positions[4] = P.y; + positions[5] = 0.0f; +#else + float R = 0.3f; + + M3dView activeView = M3dView::active3dView(); + float H = (float)activeView.portHeight(); + float W = (float)activeView.portWidth(); + + float x = (brush->mCX - 0.5f*W)/(0.5f*W); + float y = (brush->mCY - 0.5f*H)/(0.5f*H); + MVector C(x, y, 0.0f); + + float _w = brush->mRX/(0.5f*W); + float _h = brush->mRY/(0.5f*H); + MVector P(_w, _h, 0.0f); + + const float pi = 3.14159f; + float dstep = 360.0f/nsegs; + float rstep = dstep*pi/(180.0f); + int pid = 0; + for (int h = 0; h < nsegs; h++) + { + int hh = (h+1)%nsegs; + float a1 = rstep*(float)h; + float a2 = rstep*(float)hh; + + //float x1 = C.x + R*sin(a1); + //float y1 = C.y + R*cos(a1); + + //float x2 = C.x + R*sin(a2); + //float y2 = C.y + R*cos(a2); + + float x1 = (float)(C.x + P.x*sin(a1)); + float y1 = (float)(C.y + P.y*cos(a1)); + + float x2 = (float)(C.x + P.x*sin(a2)); + float y2 = (float)(C.y + P.y*cos(a2)); + + positions[pid++] = x1; + positions[pid++] = y1; + positions[pid++] = 0.0f; + + positions[pid++] = x2; + positions[pid++] = y2; + positions[pid++] = 0.0f; + } +#endif + positionBuffer->commit(positions); + } + + // index data + MHWRender::MIndexBuffer* indexBuffer = NULL; + int numItems = itemList.length(); + for (int i=0; i<numItems; i++) + { + const MHWRender::MRenderItem* item = itemList.itemAt(i); + if (!item) continue; + + // Enable to debug vertex buffers that are associated with each render item. + // Can also use to generate indexing better, but we don't need that here. + // Also debugs custom data on the render item. + static const bool debugStuff = false; + if (debugShader) + { + const MHWRender::MVertexBufferDescriptorList& itemBuffers =item->requiredVertexBuffers(); + int numBufs = itemBuffers.length(); + MHWRender::MVertexBufferDescriptor desc; + for (int bufNum=0; bufNum<numBufs; bufNum++) + { + if (itemBuffers.getDescriptor(bufNum, desc)) + { + printf("Buffer Required for Item #%d ('%s'):\n", i, item->name().asChar()); + printf("\tBufferName: %s\n", desc.name().asChar()); + printf("\tDataType: %s (dimension %d)\n", MHWRender::MGeometry::dataTypeString(desc.dataType()).asChar(), desc.dimension()); + printf("\tSemantic: %s\n", MHWRender::MGeometry::semanticString(desc.semantic()).asChar()); + printf("\n"); + } + } + fflush(stdout); + } + + //same indexing for all + if (item->name() == "shaveBrush") + { + if (!indexBuffer) + { + indexBuffer = data.createIndexBuffer(MHWRender::MGeometry::kUnsignedInt32); + if (indexBuffer) + { +#ifdef BRUSH_BY_SHADER + unsigned int* buffer = (unsigned int*)indexBuffer->acquire(2); + if (buffer) + { + buffer[0] = 0; + buffer[1] = 1; + indexBuffer->commit(buffer); + } +#else + unsigned int* buffer = (unsigned int*)indexBuffer->acquire(nsegs*2); + if (buffer) + { + int idx = 0; + for (int h = 0; h < nsegs; h++) + { + buffer[idx] = idx; + buffer[idx+1] = idx+1; + idx += 2; + } + indexBuffer->commit(buffer); + } +#endif + } + } + + // Associate same index buffer with either render item + if (indexBuffer) + { + item->associateWithIndexBuffer(indexBuffer); + + } + } + } + +} + +void shaveBrushOverride::cleanUp() +{ + +} |