//- // ========================================================================== // Copyright (C) 1995 - 2005 Alias Systems Corp. and/or its licensors. All // rights reserved. // // The coded instructions, statements, computer programs, and/or related // material (collectively the "Data") in these files are provided by Alias // Systems Corp. ("Alias") and/or its licensors for the exclusive use of the // Customer (as defined in the Alias Software License Agreement that // accompanies this Alias software). Such Customer has the right to use, // modify, and incorporate the Data into other products and to distribute such // products for use by end-users. // // THE DATA IS PROVIDED "AS IS". ALIAS HEREBY DISCLAIMS ALL WARRANTIES // RELATING TO THE DATA, INCLUDING, WITHOUT LIMITATION, ANY AND ALL EXPRESS OR // IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. IN NO EVENT SHALL ALIAS BE LIABLE FOR ANY DAMAGES // WHATSOEVER, WHETHER DIRECT, INDIRECT, SPECIAL, OR PUNITIVE, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, OR IN EQUITY, // ARISING OUT OF ACCESS TO, USE OF, OR RELIANCE UPON THE DATA. // ========================================================================== //+ #ifdef WIN32 #pragma warning( disable : 4786 ) #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(OSMac_MachO_) #include #include #else #include #include #endif #include "blindDataShader.h" void mergeSort( int startIndex, int sortingOffset, MIntArray& sortingArray, int* tempSortingArray, MDoubleArray& otherArray, double* tempOtherArray) // // Description: // This is a very dirty recursive implementation of the merge sort // that is very application-specific // { if (sortingOffset == 2) { if (sortingArray[startIndex] > sortingArray[startIndex+1]) { int temp = sortingArray[startIndex+1]; sortingArray[startIndex+1] = sortingArray[startIndex]; sortingArray[startIndex] = temp; double ftemp = otherArray[startIndex+1]; otherArray[startIndex+1] = otherArray[startIndex]; otherArray[startIndex] = ftemp; } } else if (sortingOffset > 2) { // First, sort each half // int leftCount = sortingOffset / 2; int rightCount = sortingOffset - leftCount; int leftIndex = startIndex; int rightIndex = startIndex + leftCount; mergeSort(leftIndex, leftCount, sortingArray, tempSortingArray, otherArray, tempOtherArray); mergeSort(rightIndex, rightCount, sortingArray, tempSortingArray, otherArray, tempOtherArray); // Second, merge the halves into the temporary arrays // int index = startIndex; while (leftIndex < (startIndex + leftCount) && rightIndex < (startIndex + sortingOffset) ) { if (sortingArray[leftIndex] < sortingArray[rightIndex]) { tempSortingArray[index] = sortingArray[leftIndex]; tempOtherArray[index++] = otherArray[leftIndex++]; } else { tempSortingArray[index] = sortingArray[rightIndex]; tempOtherArray[index++] = otherArray[rightIndex++]; } } // One of the sides is done, so add the other side // while (leftIndex < (startIndex + leftCount) ) { tempSortingArray[index] = sortingArray[leftIndex]; tempOtherArray[index++] = otherArray[leftIndex++]; } while (rightIndex < (startIndex + sortingOffset) ) { tempSortingArray[index] = sortingArray[rightIndex]; tempOtherArray[index++] = otherArray[rightIndex++]; } // Finally, copy the temporary sorting array over to the other side // for (index = startIndex; index < (startIndex + sortingOffset); ++index) { sortingArray[index] = tempSortingArray[index]; otherArray[index] = tempOtherArray[index]; } } } int binarySearch(int searchValue, MIntArray& searchArray) // // Description: // Application-specific implementation of the binary search algorithm. // It returns the index in the "searchArray" where the "searchValue" // is found or -1 if it is not found. // { int max = searchArray.length(); int min = 0; while (max - min > 1) { int currentIndex = ((max - min) / 2) + min; int currentValue = searchArray[currentIndex]; if (currentValue == searchValue) return currentIndex; else if (currentValue < searchValue) min = currentIndex; else max = currentIndex; } if (searchArray[min] == searchValue) return min; else return -1; } /**************************************************************************** * Blind Data Shader class ***************************************************************************/ // Static class member variables // // Unique Node TypeId MTypeId blindDataShader::id( 0x00086000 ); void* blindDataShader::creator() // // Description: Static member function that returns a new // dynamically-allocated instance of the class. // { return new blindDataShader(); } MStatus blindDataShader::initialize() // // Description: Static member function that initializes the static // member variables of the class. In this case, it does nothing, since // "id" is already set to the default value. // { return MS::kSuccess; } MStatus blindDataShader::compute( const MPlug& plug, MDataBlock& block ) { bool k = false; k |= (plug==outColor); k |= (plug==outColorR); k |= (plug==outColorG); k |= (plug==outColorB); if( !k ) return MS::kUnknownParameter; // Always return black for now. MFloatVector resultColor(0.0,0.0,0.0); // set ouput color attribute MDataHandle outColorHandle = block.outputValue( outColor ); MFloatVector& outColor = outColorHandle.asFloatVector(); outColor = resultColor; outColorHandle.setClean(); return MS::kSuccess; } MStatus blindDataShader::bind(const MDrawRequest& request, M3dView& view) { view.beginGL(); glPushAttrib( GL_ALL_ATTRIB_BITS ); glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); view.endGL(); return MS::kSuccess; } MStatus blindDataShader::unbind(const MDrawRequest& request, M3dView& view) { view.beginGL(); glPopClientAttrib(); glPopAttrib(); view.endGL(); return MS::kSuccess; } MStatus blindDataShader::geometry( const MDrawRequest& request, M3dView& view, int prim, unsigned int writable, int indexCount, const unsigned int * indexArray, int vertexCount, const int * vertexIDs, const float * vertexArray, int normalCount, const float ** normalArrays, int colorCount, const float ** colorArrays, int texCoordCount, const float ** texCoordArrays) // // Description: // Once everything is plugged, this function is called by the Maya rendering // engine to render the given objects. It will be called for each frame, so // the efficiency of this algorithm is important. // { const int blindDataUniqueID = 60; MStatus stat; int i; // Create our own empty colour array and // populate it with the default colour value for the attribute. // double* colours = new double[vertexCount * 3]; float defaultColour[3] = { 0.0f, 0.0f, 0.0f }; MPlug plug( thisMObject(), outColor ); MObject colorObject; plug.getValue(colorObject); MFnNumericData data(colorObject); data.getData(defaultColour[0], defaultColour[1], defaultColour[2]); // Use the blind data to set independant colour values // MFnMesh mesh(request.multiPath().node(), &stat); if (stat && mesh.hasBlindData(MFn::kMeshVertComponent, &stat) && mesh.hasBlindData(vertexIDs[0], MFn::kMeshVertComponent, blindDataUniqueID, &stat)) { MIntArray redComponentIDs, greenComponentIDs, blueComponentIDs; MDoubleArray redColour, greenColour, blueColour; stat = mesh.getDoubleBlindData( MFn::kMeshVertComponent, blindDataUniqueID, "red", redComponentIDs, redColour); if (stat) stat = mesh.getDoubleBlindData( MFn::kMeshVertComponent, blindDataUniqueID, "green", greenComponentIDs, greenColour); if (stat) stat = mesh.getDoubleBlindData( MFn::kMeshVertComponent, blindDataUniqueID, "blue", blueComponentIDs, blueColour); if (stat && redComponentIDs.length() == redColour.length() && greenComponentIDs.length() == greenColour.length() && blueComponentIDs.length() == blueColour.length()) { // Now that I have all the blind data, // use the vertex IDs and the component IDs arrays // to map the blind data values inside the colour array. // // Sort the components IDs and the colour values in increasing // order to speed up the association // int maxArrayLength = (redComponentIDs.length() > greenComponentIDs.length()) ? ((redComponentIDs.length() > blueComponentIDs.length()) ? redComponentIDs.length() : blueComponentIDs.length()) : ((greenComponentIDs.length() > blueComponentIDs.length()) ? greenComponentIDs.length() : blueComponentIDs.length()); int* tempIntArray = new int[maxArrayLength]; double* tempFloatArray = new double[maxArrayLength]; mergeSort(0, redComponentIDs.length(), redComponentIDs, tempIntArray, redColour, tempFloatArray); mergeSort(0, greenComponentIDs.length(), greenComponentIDs, tempIntArray, greenColour, tempFloatArray); mergeSort(0, blueComponentIDs.length(), blueComponentIDs, tempIntArray, blueColour, tempFloatArray); // Associate the vertex IDs with the colour values // for (i = 0; i < vertexCount; ++i) { int index = binarySearch(vertexIDs[i], redComponentIDs); if (index != -1) colours[3*i] = redColour[index]; else colours[3*i] = defaultColour[0]; index = binarySearch(vertexIDs[i], greenComponentIDs); if (index != -1) colours[3*i+1] = greenColour[index]; else colours[3*i+1] = defaultColour[1]; index = binarySearch(vertexIDs[i], blueComponentIDs); if (index != -1) colours[3*i+2] = blueColour[index]; else colours[3*i+2] = defaultColour[2]; } } } // Render the triangles using the new vertex colour information // taken from the blind data values of the mesh // view.beginGL(); glPushAttrib( GL_ALL_ATTRIB_BITS ); glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glDisable(GL_LIGHTING); glVertexPointer(3, GL_FLOAT, 0, vertexArray); glEnableClientState(GL_VERTEX_ARRAY); // Is the next line necessary? glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); glColorPointer(3, GL_DOUBLE, 0, colours); glEnableClientState(GL_COLOR_ARRAY); glDrawElements(prim, indexCount, GL_UNSIGNED_INT, indexArray); glDisable(GL_COLOR_MATERIAL); glPopClientAttrib(); glPopAttrib(); view.endGL(); return MS::kSuccess; }