aboutsummaryrefslogtreecommitdiff
path: root/mayaPlug/shaveBrushManip.cpp
diff options
context:
space:
mode:
authorBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
committerBen Marsh <[email protected]>2019-10-22 09:07:59 -0400
commitbd0027e737c6512397f841c22786274ed74b927f (patch)
treef7ffbdb8f3741bb7f24635616cc189cba5cb865c /mayaPlug/shaveBrushManip.cpp
downloadshave-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.cpp1069
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()
+{
+
+}