-- Data structures TBCPV_UVimageOutputSize = #(256,512,1024) TBCPV_paddingSizeArray = #(16,10,4) -- Dump textures to here, this is for debug only TBCPV_outputTextureFolder = RsConfigGetWildWestDir() + "assets/texture_based_data/texture_based_CPV" -- Struct to hold vertex index, its colour, and its uv coords struct RsTa_cpvVertData ( vertMeshIndex = undefined, vertCPVColour = undefined, vertUVArray = #() ) -- Function that collects all the map/UV verts from the mesh verts -- Returns data as an array where each index corresponds to the mesh index -- Save the UV coordinate too fn RsTa_TBCPV_meshVertToUVVert meshobj UVChannel = ( -- Work on a mesh version of the geometry local tempMesh = snapshotasmesh meshobj local numMeshFaces = tempMesh.numFaces local UVMappingArray = #() -- Run through the mesh and collect the UV data for each face -- Each triangle will have 3 verts, so 3 values will be returned startTime = timeStamp() for faceIndex=1 to numMeshFaces do ( theMeshFace = getFace tempMesh faceIndex theTFace = getTVFace tempMesh faceIndex -- The Mesh face has 3 points, x, y, and z -- These correspond to the x, y and z of the tvert -- Store the mapping plus the U, V and W of the Tvert local VertMapping = #(theMeshFace.x as integer, theTFace.x as integer, (getTVert tempMesh theTFace.x)) append UVMappingArray VertMapping local VertMapping = #(theMeshFace.y as integer, theTFace.y as integer, (getTVert tempMesh theTFace.y)) append UVMappingArray VertMapping local VertMapping = #(theMeshFace.z as integer, theTFace.z as integer, (getTVert tempMesh theTFace.z)) append UVMappingArray VertMapping ) endTime = timeStamp() format "Collection mapping time :% seconds\n" ((endTime-startTime )/ 1000) -- The mapping array is very full, I need to make is as small as possible local parsedUVMappingArray = #(UVMappingArray[1]) local mappingcount = UVMappingArray.count startTime = timeStamp() -- Loop through the collected data, collecting any unique vert/texture vert mappings -- This can get slow with large data sets - ~10 seconds for 3000 verts for UVMappingArrayIndex = 2 to mappingcount do ( -- Grab the mapped entry local theMappingEntry = UVMappingArray[UVMappingArrayIndex] -- Set a found flag to be false matchfound = false -- Check each in sequence currentParsedCount = parsedUVMappingArray.count for checkIndex = 1 to currentParsedCount do ( local chkMappingEntry = parsedUVMappingArray[checkIndex] -- Have already stored that mesh vert? if theMappingEntry[1] == chkMappingEntry[1] then ( -- Have we go that Texture vert too? if theMappingEntry[2] == chkMappingEntry[2] then ( matchfound = true ) ) ) -- If no match is found then we want to save this data if matchfound == false then append parsedUVMappingArray theMappingEntry ) -- End parsing endTime = timeStamp() format "Search time :% seconds\n" ((endTime-startTime )/ 1000) -- Sort this parsed array to make things easier later qsort parsedUVMappingArray sortArraybySubIndex subIndex:1 parsedUVMappingArray -- return this mapping ) -- Collect the vert data -- Takes an object and returns a breakdown of the verts fn RsTa_TBCPV_CollectMeshData meshObject theObjectUVChannel = ( -- Switch to modify mode max modify mode local numObjectVerts = meshObject.numVerts -- Loop through all the verts in index order and for each vertex get its colour from channel 11 local cpvVertListData = #() for vertIndex = 1 to numObjectVerts do ( -- Create a struct to hold this data RsTa_cpvVertDataInstance = RsTa_cpvVertData vertMeshIndex:vertIndex if (classOf meshObject.baseObject == Editable_Poly) then ( polyop.setVertSelection meshObject vertIndex RsTa_cpvVertDataInstance.vertCPVColour = meshObject.GetVertexColor 11 ) else ( ) append cpvVertListData RsTa_cpvVertDataInstance ) -- End vertex loop -- Now we need to map this CPV data to the UV data -- This will be used so that for each mesh vert I know what UV vert to use local meshTextureVertMapping = RsTa_TBCPV_meshVertToUVVert meshObject theObjectUVChannel -- For each vert, find the corresponsing map vert and the UV coordinate local theCount = cpvVertListData.count for meshVertIndex = 1 to theCount do ( for textureVertIndex = 1 to meshTextureVertMapping.count do ( if meshTextureVertMapping[textureVertIndex][1] == meshVertIndex then ( append cpvVertListData[meshVertIndex].vertUVArray meshTextureVertMapping[textureVertIndex] ) ) ) -- end vertex loop cpvVertListData -- return the collected data ) -- Function that creates RGB texture from the CPV colour data fn RsTa_TBCPV_writeCPVToTexture meshObject collectedMeshData outputTextureFolder saveDataName outputTextureSize paddingSizeArray = ( -- Make sure the folder exists outputTextureFolder = outputTextureFolder + "/" makeDir outputTextureFolder all:true -- Create a texture of the specified size and fill it with black theTextureName = meshObject.name + ".tga" theCPVImage = bitmap outputTextureSize outputTextureSize color:black theCPVImage.filename = outputTextureFolder + theTextureName -- Now write the CPV colour into this texture -- So, loop through all the verts and see if they use this bone for theVertIndex = 1 to collectedMeshData.count do ( local theMeshVert = collectedMeshData[theVertIndex] -- The get the current vert's colour local cpvColour = theMeshVert.vertCPVColour -- Use a the padding array input parameter to add the fuzziness to the blocks -- Create this as a new bitmap, then paste it into the bigger image theCPVBlockRGB = bitmap paddingSizeArray[1] paddingSizeArray[1] color:cpvColour theCPVBlockG = bitmap paddingSizeArray[2] paddingSizeArray[2] color:cpvColour theCPVBlockB = bitmap paddingSizeArray[3] paddingSizeArray[3] color:cpvColour g_offset = (paddingSizeArray[1] - paddingSizeArray[2])/2 b_offset = g_offset + ((paddingSizeArray[2] - paddingSizeArray[3])/2) pasteBitmap theCPVBlockG theCPVBlockRGB (box2 0 0 paddingSizeArray[2] paddingSizeArray[2]) [g_offset, g_offset] pasteBitmap theCPVBlockB theCPVBlockRGB (box2 0 0 paddingSizeArray[3] paddingSizeArray[2]) [b_offset, b_offset] -- There might be multiple texture co-ordinates for the mesh vert for tvertIndex = 1 to theMeshVert.vertUVArray.count do ( local UVCoordinate = theMeshVert.vertUVArray[tvertIndex][3] local paddingOffset = (paddingSizeArray[1] - 1)/2 local bitmapUVCoordinate = [((UVCoordinate.x * outputTextureSize) - paddingOffset), ((outputTextureSize - (UVCoordinate.y * outputTextureSize)) - paddingOffset)] pasteBitmap theCPVBlockRGB theCPVImage (box2 0 0 paddingSizeArray[1] paddingSizeArray[1]) bitmapUVCoordinate ) -- end tvert loop ) -- end mesh vert loop -- debug: display the created image --display theCPVImage -- Save the texture save theCPVImage -- Let the user know that this has worked messagebox ("CPV texture data written to the folder " + outputTextureFolder) ) -- Function that loads CPV colours from an image onto a mesh fn RsTa_TBCPV_loadCPVFromTexture meshObject collectedMeshData texToLoad = ( if collectedMeshData == undefined then ( messagebox "There is no saved CPV data." title:"ERROR" return false ) pushPrompt "Loading CPV Colours..." -- open the image and get its size theimageFile = openBitmap texToLoad theImageSize = theimageFile.width local theCount = collectedMeshData.count allstartTime = timeStamp() for collectedVert = 1 to theCount do ( theUVpos = collectedMeshData[collectedVert].vertUVArray[1][3] -- Calculate the UV coordiante based on the image size -- Bitmaps are upside down, so invert the Y xyUV = [theUVpos.x * theImageSize, theImageSize - (theUVpos.y * theImageSize)] thePixelColour = getPixels theimageFile xyUV 1 if (classOf meshObject.baseObject == Editable_Poly) then ( polyOp.setVertColor meshObject 11 collectedVert thePixelColour[1] ) else if (classOf meshObject.baseObject == Editable_mesh) then ( meshOp.setVertColor meshObject 11 collectedVert thePixelColour[1] ) ) allendTime = timeStamp() format "Search time for all verts in all images was :% seconds\n" ((allendTime-allstartTime )/ 1000) -- close the image close theimageFile free theimageFile popPrompt() print "Finished Loading Skin Weights." messagebox "Finished Loading Skin Weights." ) -- turns on display of the wind channel vertex colours fn RsTa_TBCPV_setDisplayMode theObject= ( theObject.showVertexColors = true theObject.vertexColorsShaded = false theObject.vertexColorType = #Map_Channel theObject.vertexColorMapChannel = 11 )