diff --git a/assets/turntable/README.md b/assets/turntable/README.md new file mode 100644 index 0000000..23e8d03 --- /dev/null +++ b/assets/turntable/README.md @@ -0,0 +1,85 @@ +#### USD Turntable Presets And You + +--- +#### Turning tables + +`usd-qtpy` supports the rendering of assets with a turntable preset. +This turntable preset is a USD file, that gets referenced along with a temporary +export of the scene itself. + +By using a hierarchical structure that conforms to the standard, you too +can make a preset that turns your tables the exact way you wish your tables +to be turned. + +#### Getting started + +The turntable preset system requires the hierarchy to be laid out like so: + +``` +/ +│ +└─ turntable (Xform, default prim) + │ + ├─ scene (Xform) + │ │ + | ├─ lights (Xform) (Optional) + │ │ └─ [all lights in scene] + │ │ + │ ├─ camera (Camera pointing at your target) + │ │ + │ └─ [some scene geometry] (Optional) + │ + ├─ parent (Xform, usually holds rotation animation) + │ + └─ bounds (Xform) (Optional) + │ + └─ [some invisible geometry that fits the bounds of your camera] + +``` + +You can look at an example of a complete compliant hierarchy, +in `turntable_preset.usda`. +It isn't required to have a usda file, usd and usdc are supported as well. + +##### Things that matter: +- `turntable` needs to be the default primitive +- Some Usd Camera needs to be present in the hierarchy +- `parent` must exist +- At least 1 `camera` exists somewhere (the first found camera will be used) + +##### Things that don't matter: +- `bounds` doesn't have to exist +- `scene/lights` doesn't have to exist +- `camera` can be named anything and can exist everywhere in the hierarchy. + +#### Functionality in the turntable system: +##### Bounds: +There are times where you are unsure whether assets will fit in the camera view. +This worry can be entirely mitigated by including the bounds Xform, with some +geometry in it that fills the camera view. + +If `bounds` is present, the turntable will automagically fit the geometry +uniformly so that it fits the bounds of the geometry contained in this Xform. + +##### Scene lights: +Scene lights can be included with any name in any order. These will be turned +off for GL renders, because GL renders are lit by default. The introduction +of lights would make the renders overexposed. + +Should you still want to have lights regardless of the renderer being used, +just include them them in `scene`. + +##### Parent: +This is where the subject of the turntable will end up, +and it's usually an Xform that holds rotation frames. + +The subject is placed at the centroid and lower bound in the middle of the scene +automatically, meaning that you can place `parent` pretty much wherever you want +in the scene, the subject will inherit its transforms. + +##### Limits (for now): +- USD attributes `endTimeCode` and `startTimeCode` are not able to be read, +I might attempt to parse the actual description of the USD scene in the future, +but for now, manual entry of start and end timecodes is needed. + +##### Happy turntabling! \ No newline at end of file diff --git a/assets/turntable/turntable_preset.usda b/assets/turntable/turntable_preset.usda new file mode 100644 index 0000000..ac3fe2e --- /dev/null +++ b/assets/turntable/turntable_preset.usda @@ -0,0 +1,1369 @@ +#usda 1.0 +( + defaultPrim = "turntable" + endTimeCode = 200 + framesPerSecond = 24 + metersPerUnit = 1 + startTimeCode = 0 + timeCodesPerSecond = 24 + upAxis = "Y" +) + +def Xform "turntable" ( + kind = "group" +) +{ + matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + + def Xform "scene" ( + kind = "group" + ) + { + matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + + def Xform "table" ( + kind = "component" + ) + { + matrix4d xformOp:transform:xform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform:xform"] + + def Mesh "mesh_0" + { + float3[] extent = [(-6.5, -0.29999995, -7), (6.5, 3.7, 4.994965)] + int[] faceVertexCounts = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [0, 2, 1, 0, 3, 2, 0, 4, 3, 0, 5, 4, 0, 6, 5, 0, 7, 6, 0, 8, 7, 0, 9, 8, 0, 10, 9, 0, 11, 10, 0, 12, 11, 0, 13, 12, 0, 14, 13, 0, 15, 14, 0, 16, 15, 0, 17, 16, 0, 18, 17, 0, 19, 18, 0, 20, 19, 0, 21, 20, 0, 22, 21, 0, 23, 22, 0, 24, 23, 0, 25, 24, 0, 26, 25, 0, 27, 26, 0, 28, 27, 0, 29, 28, 0, 30, 29, 0, 31, 30, 0, 32, 31, 0, 33, 32, 0, 34, 33, 0, 35, 34, 0, 36, 35, 0, 37, 36, 0, 38, 37, 0, 39, 38, 0, 40, 39, 0, 41, 40, 0, 42, 41, 0, 43, 42, 0, 44, 43, 0, 45, 44, 0, 46, 45, 0, 47, 46, 0, 48, 47, 0, 49, 48, 0, 50, 49, 0, 51, 50, 0, 52, 51, 0, 53, 52, 0, 54, 53, 0, 55, 54, 0, 56, 55, 0, 57, 56, 0, 58, 57, 0, 59, 58, 0, 60, 59, 0, 61, 60, 0, 62, 61, 0, 63, 62, 0, 64, 63, 0, 65, 64, 0, 66, 65, 0, 67, 66, 0, 68, 67, 0, 69, 68, 0, 70, 69, 0, 1, 70, 1, 2, 72, 71, 2, 3, 73, 72, 3, 4, 74, 73, 4, 5, 75, 74, 5, 6, 76, 75, 6, 7, 77, 76, 7, 8, 78, 77, 8, 9, 79, 78, 9, 10, 80, 79, 10, 11, 81, 80, 11, 12, 82, 81, 12, 13, 83, 82, 13, 14, 84, 83, 14, 15, 85, 84, 15, 16, 86, 85, 16, 17, 87, 86, 17, 18, 88, 87, 18, 19, 89, 88, 19, 20, 90, 89, 20, 21, 91, 90, 21, 22, 92, 91, 22, 23, 93, 92, 23, 24, 94, 93, 24, 25, 95, 94, 25, 26, 96, 95, 26, 27, 97, 96, 27, 28, 98, 97, 28, 29, 99, 98, 29, 30, 100, 99, 30, 31, 101, 100, 31, 32, 102, 101, 32, 33, 103, 102, 33, 34, 104, 103, 34, 35, 105, 104, 35, 36, 106, 105, 36, 37, 107, 106, 37, 38, 108, 107, 38, 39, 109, 108, 39, 40, 110, 109, 40, 41, 111, 110, 41, 42, 112, 111, 42, 43, 113, 112, 43, 44, 114, 113, 44, 45, 115, 114, 45, 46, 116, 115, 46, 47, 117, 116, 47, 48, 118, 117, 48, 49, 119, 118, 49, 50, 120, 119, 50, 51, 121, 120, 51, 52, 122, 121, 52, 53, 123, 122, 53, 54, 124, 123, 54, 55, 125, 124, 55, 56, 126, 125, 56, 57, 127, 126, 57, 58, 128, 127, 58, 59, 129, 128, 59, 60, 130, 129, 60, 61, 131, 130, 61, 62, 132, 131, 62, 63, 133, 132, 63, 64, 134, 133, 64, 65, 135, 134, 65, 66, 136, 135, 66, 67, 137, 136, 67, 68, 138, 137, 68, 69, 139, 138, 69, 70, 140, 139, 70, 1, 71, 140, 71, 72, 142, 141, 72, 73, 143, 142, 73, 74, 144, 143, 74, 75, 145, 144, 75, 76, 146, 145, 76, 77, 147, 146, 77, 78, 148, 147, 78, 79, 149, 148, 79, 80, 150, 149, 80, 81, 151, 150, 81, 82, 152, 151, 82, 83, 153, 152, 83, 84, 154, 153, 84, 85, 155, 154, 85, 86, 156, 155, 86, 87, 157, 156, 87, 88, 158, 157, 88, 89, 159, 158, 89, 90, 160, 159, 90, 91, 161, 160, 91, 92, 162, 161, 92, 93, 163, 162, 93, 94, 164, 163, 94, 95, 165, 164, 95, 96, 166, 165, 96, 97, 167, 166, 97, 98, 168, 167, 98, 99, 169, 168, 99, 100, 170, 169, 100, 101, 171, 170, 101, 102, 172, 171, 102, 103, 173, 172, 103, 104, 174, 173, 104, 105, 175, 174, 105, 106, 176, 175, 106, 107, 177, 176, 107, 108, 178, 177, 108, 109, 179, 178, 109, 110, 180, 179, 110, 111, 181, 180, 111, 112, 182, 181, 112, 113, 183, 182, 113, 114, 184, 183, 114, 115, 185, 184, 115, 116, 186, 185, 116, 117, 187, 186, 117, 118, 188, 187, 118, 119, 189, 188, 119, 120, 190, 189, 120, 121, 191, 190, 121, 122, 192, 191, 122, 123, 193, 192, 123, 124, 194, 193, 124, 125, 195, 194, 125, 126, 196, 195, 126, 127, 197, 196, 127, 128, 198, 197, 128, 129, 199, 198, 129, 130, 200, 199, 130, 131, 201, 200, 131, 132, 202, 201, 132, 133, 203, 202, 133, 134, 204, 203, 134, 135, 205, 204, 135, 136, 206, 205, 136, 137, 207, 206, 137, 138, 208, 207, 138, 139, 209, 208, 139, 140, 210, 209, 140, 71, 141, 210, 141, 142, 212, 211, 142, 143, 213, 212, 143, 144, 214, 213, 144, 145, 215, 214, 145, 146, 216, 215, 146, 147, 217, 216, 147, 148, 218, 217, 148, 149, 219, 218, 149, 150, 220, 219, 150, 151, 221, 220, 151, 152, 222, 221, 152, 153, 223, 222, 153, 154, 224, 223, 154, 155, 225, 224, 155, 156, 226, 225, 156, 157, 227, 226, 157, 158, 228, 227, 158, 159, 229, 228, 159, 160, 230, 229, 160, 161, 231, 230, 161, 162, 232, 231, 162, 163, 233, 232, 163, 164, 234, 233, 164, 165, 235, 234, 165, 166, 236, 235, 166, 167, 237, 236, 167, 168, 238, 237, 168, 169, 239, 238, 169, 170, 240, 239, 170, 171, 241, 240, 171, 172, 242, 241, 172, 173, 243, 242, 173, 174, 244, 243, 174, 175, 245, 244, 175, 176, 246, 245, 176, 177, 247, 246, 177, 178, 248, 247, 178, 179, 249, 248, 179, 180, 250, 249, 180, 181, 251, 250, 181, 182, 252, 251, 182, 183, 253, 252, 183, 184, 254, 253, 184, 185, 255, 254, 185, 186, 256, 255, 186, 187, 257, 256, 187, 188, 258, 257, 188, 189, 259, 258, 189, 190, 260, 259, 190, 191, 261, 260, 191, 192, 262, 261, 192, 193, 263, 262, 193, 194, 264, 263, 194, 195, 265, 264, 195, 196, 266, 265, 196, 197, 267, 266, 197, 198, 268, 267, 198, 199, 269, 268, 199, 200, 270, 269, 200, 201, 271, 270, 201, 202, 272, 271, 202, 203, 273, 272, 203, 204, 274, 273, 204, 205, 275, 274, 205, 206, 276, 275, 206, 207, 277, 276, 207, 208, 278, 277, 208, 209, 279, 278, 209, 210, 280, 279, 210, 141, 211, 280, 211, 212, 282, 281, 212, 213, 283, 282, 213, 214, 284, 283, 214, 215, 285, 284, 215, 216, 286, 285, 216, 217, 287, 286, 217, 218, 288, 287, 218, 219, 289, 288, 219, 220, 290, 289, 220, 221, 291, 290, 221, 222, 292, 291, 222, 223, 293, 292, 223, 224, 294, 293, 224, 225, 295, 294, 225, 226, 296, 295, 226, 227, 297, 296, 227, 228, 298, 297, 228, 229, 299, 298, 229, 230, 300, 299, 230, 231, 301, 300, 231, 232, 302, 301, 232, 233, 303, 302, 233, 234, 304, 303, 234, 235, 305, 304, 235, 236, 306, 305, 236, 237, 307, 306, 237, 238, 308, 307, 238, 239, 309, 308, 239, 240, 310, 309, 240, 241, 311, 310, 241, 242, 312, 311, 242, 243, 313, 312, 243, 244, 314, 313, 244, 245, 315, 314, 245, 246, 316, 315, 246, 247, 317, 316, 247, 248, 318, 317, 248, 249, 319, 318, 249, 250, 320, 319, 250, 251, 321, 320, 251, 252, 322, 321, 252, 253, 323, 322, 253, 254, 324, 323, 254, 255, 325, 324, 255, 256, 326, 325, 256, 257, 327, 326, 257, 258, 328, 327, 258, 259, 329, 328, 259, 260, 330, 329, 260, 261, 331, 330, 261, 262, 332, 331, 262, 263, 333, 332, 263, 264, 334, 333, 264, 265, 335, 334, 265, 266, 336, 335, 266, 267, 337, 336, 267, 268, 338, 337, 268, 269, 339, 338, 269, 270, 340, 339, 270, 271, 341, 340, 271, 272, 342, 341, 272, 273, 343, 342, 273, 274, 344, 343, 274, 275, 345, 344, 275, 276, 346, 345, 276, 277, 347, 346, 277, 278, 348, 347, 278, 279, 349, 348, 279, 280, 350, 349, 280, 211, 281, 350, 281, 282, 352, 351, 282, 283, 353, 352, 283, 284, 354, 353, 284, 285, 355, 354, 285, 286, 356, 355, 286, 287, 357, 356, 287, 288, 358, 357, 288, 289, 359, 358, 289, 290, 360, 359, 290, 291, 361, 360, 291, 292, 362, 361, 292, 293, 363, 362, 293, 294, 364, 363, 294, 295, 365, 364, 295, 296, 366, 365, 296, 297, 367, 366, 297, 298, 368, 367, 298, 299, 369, 368, 299, 300, 370, 369, 300, 301, 371, 370, 301, 302, 372, 371, 302, 303, 373, 372, 303, 304, 374, 373, 304, 305, 375, 374, 305, 306, 376, 375, 306, 307, 377, 376, 307, 308, 378, 377, 308, 309, 379, 378, 309, 310, 380, 379, 310, 311, 381, 380, 311, 312, 382, 381, 312, 313, 383, 382, 313, 314, 384, 383, 314, 315, 385, 384, 315, 316, 386, 385, 316, 317, 387, 386, 317, 318, 388, 387, 318, 319, 389, 388, 319, 320, 390, 389, 320, 321, 391, 390, 321, 322, 392, 391, 322, 323, 393, 392, 323, 324, 394, 393, 324, 325, 395, 394, 325, 326, 396, 395, 326, 327, 397, 396, 327, 328, 398, 397, 328, 329, 399, 398, 329, 330, 400, 399, 330, 331, 401, 400, 331, 332, 402, 401, 332, 333, 403, 402, 333, 334, 404, 403, 334, 335, 405, 404, 335, 336, 406, 405, 336, 337, 407, 406, 337, 338, 408, 407, 338, 339, 409, 408, 339, 340, 410, 409, 340, 341, 411, 410, 341, 342, 412, 411, 342, 343, 413, 412, 343, 344, 414, 413, 344, 345, 415, 414, 345, 346, 416, 415, 346, 347, 417, 416, 347, 348, 418, 417, 348, 349, 419, 418, 349, 350, 420, 419, 350, 281, 351, 420, 351, 352, 422, 421, 352, 353, 423, 422, 353, 354, 424, 423, 354, 355, 425, 424, 355, 356, 426, 425, 356, 357, 427, 426, 357, 358, 428, 427, 358, 359, 429, 428, 359, 360, 430, 429, 360, 361, 431, 430, 361, 362, 432, 431, 362, 363, 433, 432, 363, 364, 434, 433, 364, 365, 435, 434, 365, 366, 436, 435, 366, 367, 437, 436, 367, 368, 438, 437, 368, 369, 439, 438, 369, 370, 440, 439, 370, 371, 441, 440, 371, 372, 442, 441, 372, 373, 443, 442, 373, 374, 444, 443, 374, 375, 445, 444, 375, 376, 446, 445, 376, 377, 447, 446, 377, 378, 448, 447, 378, 379, 449, 448, 379, 380, 450, 449, 380, 381, 451, 450, 381, 382, 452, 451, 382, 383, 453, 452, 383, 384, 454, 453, 384, 385, 455, 454, 385, 386, 456, 455, 386, 387, 457, 456, 387, 388, 458, 457, 388, 389, 459, 458, 389, 390, 460, 459, 390, 391, 461, 460, 391, 392, 462, 461, 392, 393, 463, 462, 393, 394, 464, 463, 394, 395, 465, 464, 395, 396, 466, 465, 396, 397, 467, 466, 397, 398, 468, 467, 398, 399, 469, 468, 399, 400, 470, 469, 400, 401, 471, 470, 401, 402, 472, 471, 402, 403, 473, 472, 403, 404, 474, 473, 404, 405, 475, 474, 405, 406, 476, 475, 406, 407, 477, 476, 407, 408, 478, 477, 408, 409, 479, 478, 409, 410, 480, 479, 410, 411, 481, 480, 411, 412, 482, 481, 412, 413, 483, 482, 413, 414, 484, 483, 414, 415, 485, 484, 415, 416, 486, 485, 416, 417, 487, 486, 417, 418, 488, 487, 418, 419, 489, 488, 419, 420, 490, 489, 420, 351, 421, 490, 421, 422, 492, 491, 422, 423, 493, 492, 423, 424, 494, 493, 424, 425, 495, 494, 425, 426, 496, 495, 426, 427, 497, 496, 427, 428, 498, 497, 428, 429, 499, 498, 429, 430, 500, 499, 430, 431, 501, 500, 431, 432, 502, 501, 432, 433, 503, 502, 433, 434, 504, 503, 434, 435, 505, 504, 435, 436, 506, 505, 436, 437, 507, 506, 437, 438, 508, 507, 438, 439, 509, 508, 439, 440, 510, 509, 440, 441, 511, 510, 441, 442, 512, 511, 442, 443, 513, 512, 443, 444, 514, 513, 444, 445, 515, 514, 445, 446, 516, 515, 446, 447, 517, 516, 447, 448, 518, 517, 448, 449, 519, 518, 449, 450, 520, 519, 450, 451, 521, 520, 451, 452, 522, 521, 452, 453, 523, 522, 453, 454, 524, 523, 454, 455, 525, 524, 455, 456, 526, 525, 456, 457, 527, 526, 457, 458, 528, 527, 458, 459, 529, 528, 459, 460, 530, 529, 460, 461, 531, 530, 461, 462, 532, 531, 462, 463, 533, 532, 463, 464, 534, 533, 464, 465, 535, 534, 465, 466, 536, 535, 466, 467, 537, 536, 467, 468, 538, 537, 468, 469, 539, 538, 469, 470, 540, 539, 470, 471, 541, 540, 471, 472, 542, 541, 472, 473, 543, 542, 473, 474, 544, 543, 474, 475, 545, 544, 475, 476, 546, 545, 476, 477, 547, 546, 477, 478, 548, 547, 478, 479, 549, 548, 479, 480, 550, 549, 480, 481, 551, 550, 481, 482, 552, 551, 482, 483, 553, 552, 483, 484, 554, 553, 484, 485, 555, 554, 485, 486, 556, 555, 486, 487, 557, 556, 487, 488, 558, 557, 488, 489, 559, 558, 489, 490, 560, 559, 490, 421, 491, 560, 561, 562, 572, 571, 562, 563, 573, 572, 563, 564, 574, 573, 564, 565, 575, 574, 565, 566, 576, 575, 566, 567, 577, 576, 567, 568, 578, 577, 568, 569, 579, 578, 569, 570, 580, 579, 571, 572, 582, 581, 572, 573, 583, 582, 573, 574, 584, 583, 574, 575, 585, 584, 575, 576, 586, 585, 576, 577, 587, 586, 577, 578, 588, 587, 578, 579, 589, 588, 579, 580, 590, 589, 581, 582, 592, 591, 582, 583, 593, 592, 583, 584, 594, 593, 584, 585, 595, 594, 585, 586, 596, 595, 586, 587, 597, 596, 587, 588, 598, 597, 588, 589, 599, 598, 589, 590, 600, 599, 591, 592, 602, 601, 592, 593, 603, 602, 593, 594, 604, 603, 594, 595, 605, 604, 595, 596, 606, 605, 596, 597, 607, 606, 597, 598, 608, 607, 598, 599, 609, 608, 599, 600, 610, 609, 601, 602, 612, 611, 602, 603, 613, 612, 603, 604, 614, 613, 604, 605, 615, 614, 605, 606, 616, 615, 606, 607, 617, 616, 607, 608, 618, 617, 608, 609, 619, 618, 609, 610, 620, 619, 611, 612, 622, 621, 612, 613, 623, 622, 613, 614, 624, 623, 614, 615, 625, 624, 615, 616, 626, 625, 616, 617, 627, 626, 617, 618, 628, 627, 618, 619, 629, 628, 619, 620, 630, 629, 621, 622, 632, 631, 622, 623, 633, 632, 623, 624, 634, 633, 624, 625, 635, 634, 625, 626, 636, 635, 626, 627, 637, 636, 627, 628, 638, 637, 628, 629, 639, 638, 629, 630, 640, 639, 631, 632, 642, 641, 632, 633, 643, 642, 633, 634, 644, 643, 634, 635, 645, 644, 635, 636, 646, 645, 636, 637, 647, 646, 637, 638, 648, 647, 638, 639, 649, 648, 639, 640, 650, 649, 641, 642, 652, 651, 642, 643, 653, 652, 643, 644, 654, 653, 644, 645, 655, 654, 645, 646, 656, 655, 646, 647, 657, 656, 647, 648, 658, 657, 648, 649, 659, 658, 649, 650, 660, 659] + uniform token orientation = "leftHanded" + point3f[] points = [(0, 0, 0), (0.625, 0, -5.4639237e-8), (0.62248397, 0, -0.056024566), (0.61495596, 0, -0.11159806), (0.6024768, 0, -0.16627303), (0.5851468, 0, -0.21960928), (0.5631055, 0, -0.27117735), (0.5365305, 0, -0.32056206), (0.5056356, 0, -0.36736578), (0.4706697, 0, -0.4112117), (0.43191418, 0, -0.45174676), (0.38968113, 0, -0.4886447), (0.34431064, 0, -0.5216083), (0.29616794, 0, -0.5503722), (0.24564065, 0, -0.5747049), (0.1931356, 0, -0.59441036), (0.1390756, 0, -0.60932994), (0.0838958, 0, -0.6193436), (0.028040502, 0, -0.62437063), (-0.028040484, 0, -0.6243707), (-0.08389578, 0, -0.6193436), (-0.13907559, 0, -0.60932994), (-0.19313559, 0, -0.59441036), (-0.24564064, 0, -0.5747049), (-0.29616785, 0, -0.55037224), (-0.34431058, 0, -0.5216083), (-0.38968113, 0, -0.4886447), (-0.43191415, 0, -0.45174682), (-0.4706697, 0, -0.4112117), (-0.5056357, 0, -0.36736575), (-0.5365305, 0, -0.32056212), (-0.5631055, 0, -0.27117738), (-0.5851468, 0, -0.21960929), (-0.6024768, 0, -0.16627304), (-0.61495596, 0, -0.111598045), (-0.62248397, 0, -0.056024536), (-0.625, 0, 5.4639237e-8), (-0.62248397, 0, 0.056024496), (-0.61495596, 0, 0.11159801), (-0.6024768, 0, 0.166273), (-0.5851468, 0, 0.21960926), (-0.5631055, 0, 0.27117735), (-0.5365305, 0, 0.3205621), (-0.5056357, 0, 0.36736572), (-0.47066972, 0, 0.41121167), (-0.43191418, 0, 0.45174676), (-0.38968128, 0, 0.48864457), (-0.34431073, 0, 0.52160823), (-0.296168, 0, 0.5503721), (-0.24564072, 0, 0.5747048), (-0.19313568, 0, 0.5944103), (-0.13907564, 0, 0.60932994), (-0.08389582, 0, 0.6193436), (-0.028040523, 0, 0.62437063), (0.028040538, 0, 0.62437063), (0.08389583, 0, 0.6193436), (0.13907565, 0, 0.60932994), (0.19313571, 0, 0.5944103), (0.24564074, 0, 0.5747048), (0.29616776, 0, 0.5503723), (0.34431046, 0, 0.52160835), (0.38968104, 0, 0.48864478), (0.43191406, 0, 0.45174685), (0.4706696, 0, 0.4112118), (0.5056356, 0, 0.3673658), (0.5365305, 0, 0.3205621), (0.5631055, 0, 0.27117735), (0.5851468, 0, 0.21960926), (0.6024768, 0, 0.16627298), (0.614956, 0, 0.111598), (0.62248397, 0, 0.056024484), (1.25, 0, -1.09278474e-7), (1.2449679, 0, -0.11204913), (1.2299119, 0, -0.22319612), (1.2049536, 0, -0.33254606), (1.1702936, 0, -0.43921855), (1.126211, 0, -0.5423547), (1.073061, 0, -0.6411241), (1.0112712, 0, -0.73473155), (0.9413394, 0, -0.8224234), (0.86382836, 0, -0.9034935), (0.77936226, 0, -0.9772894), (0.6886213, 0, -1.0432166), (0.5923359, 0, -1.1007444), (0.4912813, 0, -1.1494098), (0.3862712, 0, -1.1888207), (0.2781512, 0, -1.2186599), (0.1677916, 0, -1.2386872), (0.056081004, 0, -1.2487413), (-0.056080967, 0, -1.2487414), (-0.16779156, 0, -1.2386872), (-0.27815118, 0, -1.2186599), (-0.38627118, 0, -1.1888207), (-0.49128127, 0, -1.1494098), (-0.5923357, 0, -1.1007445), (-0.68862116, 0, -1.0432166), (-0.77936226, 0, -0.9772894), (-0.8638283, 0, -0.90349364), (-0.9413394, 0, -0.8224234), (-1.0112714, 0, -0.7347315), (-1.073061, 0, -0.64112425), (-1.126211, 0, -0.54235476), (-1.1702936, 0, -0.43921858), (-1.2049536, 0, -0.3325461), (-1.2299119, 0, -0.22319609), (-1.2449679, 0, -0.11204907), (-1.25, 0, 1.09278474e-7), (-1.2449679, 0, 0.11204899), (-1.2299119, 0, 0.22319601), (-1.2049536, 0, 0.332546), (-1.1702936, 0, 0.43921852), (-1.126211, 0, 0.5423547), (-1.073061, 0, 0.6411242), (-1.0112714, 0, 0.73473144), (-0.94133943, 0, 0.82242334), (-0.86382836, 0, 0.9034935), (-0.77936256, 0, 0.97728914), (-0.68862146, 0, 1.0432165), (-0.592336, 0, 1.1007442), (-0.49128145, 0, 1.1494097), (-0.38627136, 0, 1.1888206), (-0.27815127, 0, 1.2186599), (-0.16779163, 0, 1.2386872), (-0.056081045, 0, 1.2487413), (0.056081075, 0, 1.2487413), (0.16779166, 0, 1.2386872), (0.2781513, 0, 1.2186599), (0.38627142, 0, 1.1888206), (0.49128148, 0, 1.1494097), (0.5923355, 0, 1.1007446), (0.6886209, 0, 1.0432167), (0.7793621, 0, 0.97728956), (0.8638281, 0, 0.9034937), (0.9413392, 0, 0.8224236), (1.0112712, 0, 0.7347316), (1.073061, 0, 0.6411242), (1.126211, 0, 0.5423547), (1.1702936, 0, 0.43921852), (1.2049536, 0, 0.33254597), (1.229912, 0, 0.223196), (1.2449679, 0, 0.11204897), (1.875, 0, -1.639177e-7), (1.8674518, 0, -0.1680737), (1.844868, 0, -0.33479416), (1.8074304, 0, -0.49881908), (1.7554405, 0, -0.65882784), (1.6893166, 0, -0.81353205), (1.6095915, 0, -0.96168613), (1.5169069, 0, -1.1020973), (1.412009, 0, -1.2336351), (1.2957425, 0, -1.3552403), (1.1690434, 0, -1.465934), (1.0329319, 0, -1.5648248), (0.8885038, 0, -1.6511166), (0.73692197, 0, -1.7241145), (0.5794068, 0, -1.783231), (0.41722682, 0, -1.8279898), (0.2516874, 0, -1.8580308), (0.08412151, 0, -1.873112), (-0.08412145, 0, -1.8731121), (-0.25168735, 0, -1.8580308), (-0.4172268, 0, -1.8279898), (-0.57940674, 0, -1.783231), (-0.7369219, 0, -1.7241145), (-0.88850355, 0, -1.6511167), (-1.0329318, 0, -1.5648248), (-1.1690434, 0, -1.465934), (-1.2957424, 0, -1.3552405), (-1.412009, 0, -1.2336351), (-1.516907, 0, -1.1020973), (-1.6095914, 0, -0.9616864), (-1.6893166, 0, -0.8135322), (-1.7554404, 0, -0.6588279), (-1.8074304, 0, -0.4988191), (-1.844868, 0, -0.33479413), (-1.8674518, 0, -0.16807361), (-1.875, 0, 1.639177e-7), (-1.8674518, 0, 0.16807349), (-1.844868, 0, 0.334794), (-1.8074304, 0, 0.49881902), (-1.7554405, 0, 0.6588278), (-1.6893166, 0, 0.81353205), (-1.6095914, 0, 0.96168625), (-1.516907, 0, 1.1020972), (-1.4120091, 0, 1.233635), (-1.2957425, 0, 1.3552403), (-1.1690438, 0, 1.4659337), (-1.0329322, 0, 1.5648247), (-0.888504, 0, 1.6511165), (-0.73692214, 0, 1.7241144), (-0.57940704, 0, 1.7832309), (-0.41722688, 0, 1.8279898), (-0.25168747, 0, 1.8580308), (-0.08412157, 0, 1.873112), (0.084121615, 0, 1.873112), (0.2516875, 0, 1.8580308), (0.41722694, 0, 1.8279898), (0.5794071, 0, 1.7832309), (0.7369222, 0, 1.7241144), (0.8885033, 0, 1.6511168), (1.0329314, 0, 1.564825), (1.1690432, 0, 1.4659343), (1.2957422, 0, 1.3552406), (1.4120088, 0, 1.2336353), (1.5169067, 0, 1.1020974), (1.6095914, 0, 0.96168625), (1.6893166, 0, 0.81353205), (1.7554405, 0, 0.6588278), (1.8074304, 0, 0.49881896), (1.8448681, 0, 0.33479398), (1.8674518, 0, 0.16807345), (2.5, 0, -2.1855695e-7), (2.4899359, 0, -0.22409827), (2.4598238, 0, -0.44639224), (2.409907, 0, -0.6650921), (2.3405871, 0, -0.8784371), (2.252422, 0, -1.0847094), (2.146122, 0, -1.2822483), (2.0225425, 0, -1.4694631), (1.8826787, 0, -1.6448468), (1.7276567, 0, -1.806987), (1.5587245, 0, -1.9545788), (1.3772426, 0, -2.0864332), (1.1846718, 0, -2.2014887), (0.9825626, 0, -2.2988195), (0.7725424, 0, -2.3776414), (0.5563024, 0, -2.4373198), (0.3355832, 0, -2.4773743), (0.11216201, 0, -2.4974825), (-0.112161934, 0, -2.4974828), (-0.33558312, 0, -2.4773743), (-0.55630237, 0, -2.4373198), (-0.77254236, 0, -2.3776414), (-0.98256254, 0, -2.2988195), (-1.1846714, 0, -2.201489), (-1.3772423, 0, -2.0864332), (-1.5587245, 0, -1.9545788), (-1.7276566, 0, -1.8069873), (-1.8826787, 0, -1.6448468), (-2.0225427, 0, -1.469463), (-2.146122, 0, -1.2822485), (-2.252422, 0, -1.0847095), (-2.3405871, 0, -0.87843716), (-2.409907, 0, -0.6650922), (-2.4598238, 0, -0.44639218), (-2.4899359, 0, -0.22409815), (-2.5, 0, 2.1855695e-7), (-2.4899359, 0, 0.22409798), (-2.4598238, 0, 0.44639203), (-2.409907, 0, 0.665092), (-2.3405871, 0, 0.87843704), (-2.252422, 0, 1.0847094), (-2.146122, 0, 1.2822484), (-2.0225427, 0, 1.4694629), (-1.8826789, 0, 1.6448467), (-1.7276567, 0, 1.806987), (-1.5587251, 0, 1.9545783), (-1.3772429, 0, 2.086433), (-1.184672, 0, 2.2014885), (-0.9825629, 0, 2.2988193), (-0.7725427, 0, 2.3776412), (-0.55630255, 0, 2.4373198), (-0.33558327, 0, 2.4773743), (-0.11216209, 0, 2.4974825), (0.11216215, 0, 2.4974825), (0.33558333, 0, 2.4773743), (0.5563026, 0, 2.4373198), (0.77254283, 0, 2.3776412), (0.98256296, 0, 2.2988193), (1.184671, 0, 2.2014892), (1.3772418, 0, 2.0864334), (1.5587242, 0, 1.9545791), (1.7276562, 0, 1.8069874), (1.8826784, 0, 1.6448472), (2.0225425, 0, 1.4694632), (2.146122, 0, 1.2822484), (2.252422, 0, 1.0847094), (2.3405871, 0, 0.87843704), (2.409907, 0, 0.66509193), (2.459824, 0, 0.446392), (2.4899359, 0, 0.22409794), (3.125, 0, -2.7319618e-7), (3.1124196, 0, -0.28012282), (3.07478, 0, -0.55799025), (3.012384, 0, -0.8313651), (2.925734, 0, -1.0980463), (2.8155277, 0, -1.3558867), (2.6826525, 0, -1.6028103), (2.5281782, 0, -1.836829), (2.3533485, 0, -2.0560584), (2.159571, 0, -2.2587337), (1.9484056, 0, -2.4432235), (1.7215531, 0, -2.6080415), (1.4808397, 0, -2.7518609), (1.2282033, 0, -2.8735242), (0.96567804, 0, -2.9720516), (0.69537807, 0, -3.0466497), (0.419479, 0, -3.096718), (0.1402025, 0, -3.1218534), (-0.14020242, 0, -3.1218534), (-0.41947892, 0, -3.096718), (-0.69537795, 0, -3.0466497), (-0.965678, 0, -2.9720516), (-1.2282032, 0, -2.8735242), (-1.4808393, 0, -2.751861), (-1.721553, 0, -2.6080415), (-1.9484056, 0, -2.4432235), (-2.1595707, 0, -2.258734), (-2.3533485, 0, -2.0560584), (-2.5281782, 0, -1.8368287), (-2.6826522, 0, -1.6028106), (-2.8155277, 0, -1.3558869), (-2.9257338, 0, -1.0980464), (-3.012384, 0, -0.8313652), (-3.07478, 0, -0.55799025), (-3.1124196, 0, -0.2801227), (-3.125, 0, 2.7319618e-7), (-3.1124196, 0, 0.2801225), (-3.07478, 0, 0.5579901), (-3.012384, 0, 0.83136505), (-2.925734, 0, 1.0980463), (-2.8155277, 0, 1.3558867), (-2.6826522, 0, 1.6028104), (-2.5281782, 0, 1.8368285), (-2.3533485, 0, 2.0560584), (-2.159571, 0, 2.2587337), (-1.9484063, 0, 2.443223), (-1.7215537, 0, 2.608041), (-1.4808401, 0, 2.7518609), (-1.2282037, 0, 2.8735242), (-0.9656784, 0, 2.9720516), (-0.6953781, 0, 3.0466497), (-0.4194791, 0, 3.096718), (-0.14020261, 0, 3.1218534), (0.14020269, 0, 3.1218534), (0.41947913, 0, 3.096718), (0.69537824, 0, 3.0466497), (0.9656785, 0, 2.9720516), (1.2282038, 0, 2.8735242), (1.4808389, 0, 2.7518616), (1.7215524, 0, 2.6080418), (1.9484053, 0, 2.4432237), (2.1595705, 0, 2.2587342), (2.353348, 0, 2.056059), (2.528178, 0, 1.8368291), (2.6826522, 0, 1.6028104), (2.8155277, 0, 1.3558867), (2.925734, 0, 1.0980463), (3.012384, 0, 0.8313649), (3.07478, 0, 0.55799), (3.1124196, 0, 0.2801224), (3.75, 0, -3.278354e-7), (3.7349036, 0, -0.3361474), (3.689736, 0, -0.6695883), (3.6148608, 0, -0.99763817), (3.510881, 0, -1.3176557), (3.3786333, 0, -1.6270641), (3.219183, 0, -1.9233723), (3.0338137, 0, -2.2041945), (2.824018, 0, -2.4672701), (2.591485, 0, -2.7104807), (2.3380868, 0, -2.931868), (2.0658638, 0, -3.1296496), (1.7770076, 0, -3.3022332), (1.4738439, 0, -3.448229), (1.1588136, 0, -3.566462), (0.83445364, 0, -3.6559796), (0.5033748, 0, -3.7160616), (0.16824302, 0, -3.746224), (-0.1682429, 0, -3.7462242), (-0.5033747, 0, -3.7160616), (-0.8344536, 0, -3.6559796), (-1.1588135, 0, -3.566462), (-1.4738438, 0, -3.448229), (-1.7770071, 0, -3.3022335), (-2.0658636, 0, -3.1296496), (-2.3380868, 0, -2.931868), (-2.5914848, 0, -2.710481), (-2.824018, 0, -2.4672701), (-3.033814, 0, -2.2041945), (-3.2191827, 0, -1.9233727), (-3.3786333, 0, -1.6270643), (-3.5108807, 0, -1.3176558), (-3.6148608, 0, -0.9976382), (-3.689736, 0, -0.66958827), (-3.7349036, 0, -0.33614722), (-3.75, 0, 3.278354e-7), (-3.7349036, 0, 0.33614698), (-3.689736, 0, 0.669588), (-3.6148608, 0, 0.99763805), (-3.510881, 0, 1.3176556), (-3.3786333, 0, 1.6270641), (-3.2191827, 0, 1.9233725), (-3.033814, 0, 2.2041943), (-2.8240182, 0, 2.46727), (-2.591485, 0, 2.7104807), (-2.3380876, 0, 2.9318674), (-2.0658643, 0, 3.1296494), (-1.777008, 0, 3.302233), (-1.4738443, 0, 3.4482288), (-1.1588141, 0, 3.5664618), (-0.83445376, 0, 3.6559796), (-0.50337493, 0, 3.7160616), (-0.16824314, 0, 3.746224), (0.16824323, 0, 3.746224), (0.503375, 0, 3.7160616), (0.8344539, 0, 3.6559796), (1.1588142, 0, 3.5664618), (1.4738444, 0, 3.4482288), (1.7770066, 0, 3.3022337), (2.065863, 0, 3.12965), (2.3380864, 0, 2.9318686), (2.5914843, 0, 2.7104812), (2.8240175, 0, 2.4672706), (3.0338135, 0, 2.2041948), (3.2191827, 0, 1.9233725), (3.3786333, 0, 1.6270641), (3.510881, 0, 1.3176556), (3.6148608, 0, 0.9976379), (3.6897361, 0, 0.66958797), (3.7349036, 0, 0.3361469), (4.375, 0, -3.8247464e-7), (4.3573875, 0, -0.39217198), (4.304692, 0, -0.7811864), (4.2173376, 0, -1.1639112), (4.096028, 0, -1.537265), (3.9417386, 0, -1.8982414), (3.7557135, 0, -2.2439344), (3.5394495, 0, -2.5715604), (3.2946877, 0, -2.8784819), (3.0233994, 0, -3.1622274), (2.727768, 0, -3.420513), (2.4101744, 0, -3.651258), (2.0731757, 0, -3.8526053), (1.7194846, 0, -4.022934), (1.3519492, 0, -4.1608725), (0.9735293, 0, -4.2653093), (0.5872706, 0, -4.3354053), (0.19628352, 0, -4.3705945), (-0.19628339, 0, -4.370595), (-0.5872705, 0, -4.3354053), (-0.97352916, 0, -4.2653093), (-1.3519491, 0, -4.1608725), (-1.7194844, 0, -4.022934), (-2.073175, 0, -3.8526056), (-2.4101741, 0, -3.651258), (-2.727768, 0, -3.420513), (-3.023399, 0, -3.1622276), (-3.2946877, 0, -2.8784819), (-3.5394497, 0, -2.5715601), (-3.7557132, 0, -2.2439349), (-3.9417386, 0, -1.8982416), (-4.0960274, 0, -1.5372651), (-4.2173376, 0, -1.1639113), (-4.304692, 0, -0.78118634), (-4.3573875, 0, -0.39217177), (-4.375, 0, 3.8247464e-7), (-4.3573875, 0, 0.39217147), (-4.304692, 0, 0.78118604), (-4.2173376, 0, 1.163911), (-4.096028, 0, 1.5372648), (-3.9417386, 0, 1.8982414), (-3.7557132, 0, 2.2439346), (-3.5394497, 0, 2.57156), (-3.294688, 0, 2.8784816), (-3.0233994, 0, 3.1622274), (-2.727769, 0, 3.420512), (-2.410175, 0, 3.6512575), (-2.0731761, 0, 3.852605), (-1.719485, 0, 4.022934), (-1.3519498, 0, 4.160872), (-0.9735294, 0, 4.2653093), (-0.58727074, 0, 4.3354053), (-0.19628367, 0, 4.3705945), (0.19628376, 0, 4.3705945), (0.5872708, 0, 4.3354053), (0.9735295, 0, 4.2653093), (1.3519499, 0, 4.160872), (1.7194852, 0, 4.022934), (2.0731745, 0, 3.852606), (2.4101734, 0, 3.6512585), (2.7277672, 0, 3.4205134), (3.0233984, 0, 3.1622279), (3.2946873, 0, 2.8784823), (3.5394492, 0, 2.5715606), (3.7557132, 0, 2.2439346), (3.9417386, 0, 1.8982414), (4.096028, 0, 1.5372648), (4.2173376, 0, 1.1639109), (4.3046923, 0, 0.781186), (4.3573875, 0, 0.39217138), (5, 0, -4.371139e-7), (4.9798717, 0, -0.44819653), (4.9196477, 0, -0.8927845), (4.819814, 0, -1.3301842), (4.6811743, 0, -1.7568742), (4.504844, 0, -2.1694188), (4.292244, 0, -2.5644965), (4.045085, 0, -2.9389262), (3.7653575, 0, -3.2896936), (3.4553134, 0, -3.613974), (3.117449, 0, -3.9091575), (2.7544851, 0, -4.1728663), (2.3693435, 0, -4.4029775), (1.9651252, 0, -4.597639), (1.5450848, 0, -4.755283), (1.1126049, 0, -4.8746395), (0.6711664, 0, -4.9547486), (0.22432402, 0, -4.994965), (-0.22432387, 0, -4.9949656), (-0.67116624, 0, -4.9547486), (-1.1126047, 0, -4.8746395), (-1.5450847, 0, -4.755283), (-1.9651251, 0, -4.597639), (-2.3693428, 0, -4.402978), (-2.7544847, 0, -4.1728663), (-3.117449, 0, -3.9091575), (-3.4553132, 0, -3.6139746), (-3.7653575, 0, -3.2896936), (-4.0450854, 0, -2.938926), (-4.292244, 0, -2.564497), (-4.504844, 0, -2.169419), (-4.6811743, 0, -1.7568743), (-4.819814, 0, -1.3301843), (-4.9196477, 0, -0.89278436), (-4.9798717, 0, -0.4481963), (-5, 0, 4.371139e-7), (-4.9798717, 0, 0.44819596), (-4.9196477, 0, 0.89278406), (-4.819814, 0, 1.330184), (-4.6811743, 0, 1.7568741), (-4.504844, 0, 2.1694188), (-4.292244, 0, 2.5644968), (-4.0450854, 0, 2.9389257), (-3.7653577, 0, 3.2896934), (-3.4553134, 0, 3.613974), (-3.1174502, 0, 3.9091566), (-2.7544858, 0, 4.172866), (-2.369344, 0, 4.402977), (-1.9651258, 0, 4.5976386), (-1.5450854, 0, 4.7552824), (-1.1126051, 0, 4.8746395), (-0.67116654, 0, 4.9547486), (-0.22432418, 0, 4.994965), (0.2243243, 0, 4.994965), (0.67116666, 0, 4.9547486), (1.1126052, 0, 4.8746395), (1.5450857, 0, 4.7552824), (1.9651259, 0, 4.5976386), (2.369342, 0, 4.4029784), (2.7544837, 0, 4.172867), (3.1174483, 0, 3.9091582), (3.4553125, 0, 3.6139748), (3.7653568, 0, 3.2896943), (4.045085, 0, 2.9389265), (4.292244, 0, 2.5644968), (4.504844, 0, 2.1694188), (4.6811743, 0, 1.7568741), (4.819814, 0, 1.3301839), (4.919648, 0, 0.892784), (4.9798717, 0, 0.44819587), (-6.5, 3.7, -7), (-5.0555553, 3.7, -7), (-3.611111, 3.7, -7), (-2.1666663, 3.7, -7), (-0.7222219, 3.7, -7), (0.72222257, 3.7, -7), (2.166667, 3.7, -7), (3.6111114, 3.7, -7), (5.055556, 3.7, -7), (6.5, 3.7, -7), (-6.5, 3.2555556, -7), (-5.0555553, 3.2555556, -7), (-3.611111, 3.2555556, -7), (-2.1666663, 3.2555556, -7), (-0.7222219, 3.2555556, -7), (0.72222257, 3.2555556, -7), (2.166667, 3.2555556, -7), (3.6111114, 3.2555556, -7), (5.055556, 3.2555556, -7), (6.5, 3.2555556, -7), (-6.5, 2.811111, -7), (-5.0555553, 2.811111, -7), (-3.611111, 2.811111, -7), (-2.1666663, 2.811111, -7), (-0.7222219, 2.811111, -7), (0.72222257, 2.811111, -7), (2.166667, 2.811111, -7), (3.6111114, 2.811111, -7), (5.055556, 2.811111, -7), (6.5, 2.811111, -7), (-6.5, 2.3666668, -7), (-5.0555553, 2.3666668, -7), (-3.611111, 2.3666668, -7), (-2.1666663, 2.3666668, -7), (-0.7222219, 2.3666668, -7), (0.72222257, 2.3666668, -7), (2.166667, 2.3666668, -7), (3.6111114, 2.3666668, -7), (5.055556, 2.3666668, -7), (6.5, 2.3666668, -7), (-6.5, 1.9222221, -7), (-5.0555553, 1.9222221, -7), (-3.611111, 1.9222221, -7), (-2.1666663, 1.9222221, -7), (-0.7222219, 1.9222221, -7), (0.72222257, 1.9222221, -7), (2.166667, 1.9222221, -7), (3.6111114, 1.9222221, -7), (5.055556, 1.9222221, -7), (6.5, 1.9222221, -7), (-6.5, 1.4777777, -7), (-5.0555553, 1.4777777, -7), (-3.611111, 1.4777777, -7), (-2.1666663, 1.4777777, -7), (-0.7222219, 1.4777777, -7), (0.72222257, 1.4777777, -7), (2.166667, 1.4777777, -7), (3.6111114, 1.4777777, -7), (5.055556, 1.4777777, -7), (6.5, 1.4777777, -7), (-6.5, 1.0333333, -7), (-5.0555553, 1.0333333, -7), (-3.611111, 1.0333333, -7), (-2.1666663, 1.0333333, -7), (-0.7222219, 1.0333333, -7), (0.72222257, 1.0333333, -7), (2.166667, 1.0333333, -7), (3.6111114, 1.0333333, -7), (5.055556, 1.0333333, -7), (6.5, 1.0333333, -7), (-6.5, 0.58888876, -7), (-5.0555553, 0.58888876, -7), (-3.611111, 0.58888876, -7), (-2.1666663, 0.58888876, -7), (-0.7222219, 0.58888876, -7), (0.72222257, 0.58888876, -7), (2.166667, 0.58888876, -7), (3.6111114, 0.58888876, -7), (5.055556, 0.58888876, -7), (6.5, 0.58888876, -7), (-6.5, 0.14444435, -7), (-5.0555553, 0.14444435, -7), (-3.611111, 0.14444435, -7), (-2.1666663, 0.14444435, -7), (-0.7222219, 0.14444435, -7), (0.72222257, 0.14444435, -7), (2.166667, 0.14444435, -7), (3.6111114, 0.14444435, -7), (5.055556, 0.14444435, -7), (6.5, 0.14444435, -7), (-6.5, -0.29999995, -7), (-5.0555553, -0.29999995, -7), (-3.611111, -0.29999995, -7), (-2.1666663, -0.29999995, -7), (-0.7222219, -0.29999995, -7), (0.72222257, -0.29999995, -7), (2.166667, -0.29999995, -7), (3.6111114, -0.29999995, -7), (5.055556, -0.29999995, -7), (6.5, -0.29999995, -7)] ( + interpolation = "vertex" + ) + float[] primvars:curveu = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.6, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9] ( + interpolation = "vertex" + ) + int[] primvars:curveu:indices = None + color3f[] primvars:displayColor = [(0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (0.189, 0.189, 0.189), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (1, 1, 1), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.9970244, 0.9970244, 0.9970244), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.8541976, 0.8541976, 0.8541976), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.7113709, 0.7113709, 0.7113709), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.5685441, 0.5685441, 0.5685441), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.42571726, 0.42571726, 0.42571726), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.28289053, 0.28289053, 0.28289053), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0.14006372, 0.14006372, 0.14006372), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)] ( + interpolation = "vertex" + ) + int[] primvars:displayColor:indices = None + uniform token subdivisionScheme = "none" + } + } + + def Camera "camera" + { + float2 clippingRange = (1, 1000000) + float focalLength.timeSamples = { + 1: 0.32, + 2: 0.32, + 3: 0.32, + 4: 0.32, + 5: 0.32, + 6: 0.32, + 7: 0.32, + 8: 0.32, + 9: 0.32, + 10: 0.32, + 11: 0.32, + 12: 0.32, + 13: 0.32, + 14: 0.32, + 15: 0.32, + 16: 0.32, + 17: 0.32, + 18: 0.32, + 19: 0.32, + 20: 0.32, + 21: 0.32, + 22: 0.32, + 23: 0.32, + 24: 0.32, + 25: 0.32, + 26: 0.32, + 27: 0.32, + 28: 0.32, + 29: 0.32, + 30: 0.32, + 31: 0.32, + 32: 0.32, + 33: 0.32, + 34: 0.32, + 35: 0.32, + 36: 0.32, + 37: 0.32, + 38: 0.32, + 39: 0.32, + 40: 0.32, + 41: 0.32, + 42: 0.32, + 43: 0.32, + 44: 0.32, + 45: 0.32, + 46: 0.32, + 47: 0.32, + 48: 0.32, + 49: 0.32, + 50: 0.32, + 51: 0.32, + 52: 0.32, + 53: 0.32, + 54: 0.32, + 55: 0.32, + 56: 0.32, + 57: 0.32, + 58: 0.32, + 59: 0.32, + 60: 0.32, + 61: 0.32, + 62: 0.32, + 63: 0.32, + 64: 0.32, + 65: 0.32, + 66: 0.32, + 67: 0.32, + 68: 0.32, + 69: 0.32, + 70: 0.32, + 71: 0.32, + 72: 0.32, + 73: 0.32, + 74: 0.32, + 75: 0.32, + 76: 0.32, + 77: 0.32, + 78: 0.32, + 79: 0.32, + 80: 0.32, + 81: 0.32, + 82: 0.32, + 83: 0.32, + 84: 0.32, + 85: 0.32, + 86: 0.32, + 87: 0.32, + 88: 0.32, + 89: 0.32, + 90: 0.32, + 91: 0.32, + 92: 0.32, + 93: 0.32, + 94: 0.32, + 95: 0.32, + 96: 0.32, + 97: 0.32, + 98: 0.32, + 99: 0.32, + 100: 0.32, + } + float focusDistance = 4 + float fStop = 0 + float horizontalAperture.timeSamples = { + 1: 0.20955, + 2: 0.20955, + 3: 0.20955, + 4: 0.20955, + 5: 0.20955, + 6: 0.20955, + 7: 0.20955, + 8: 0.20955, + 9: 0.20955, + 10: 0.20955, + 11: 0.20955, + 12: 0.20955, + 13: 0.20955, + 14: 0.20955, + 15: 0.20955, + 16: 0.20955, + 17: 0.20955, + 18: 0.20955, + 19: 0.20955, + 20: 0.20955, + 21: 0.20955, + 22: 0.20955, + 23: 0.20955, + 24: 0.20955, + 25: 0.20955, + 26: 0.20955, + 27: 0.20955, + 28: 0.20955, + 29: 0.20955, + 30: 0.20955, + 31: 0.20955, + 32: 0.20955, + 33: 0.20955, + 34: 0.20955, + 35: 0.20955, + 36: 0.20955, + 37: 0.20955, + 38: 0.20955, + 39: 0.20955, + 40: 0.20955, + 41: 0.20955, + 42: 0.20955, + 43: 0.20955, + 44: 0.20955, + 45: 0.20955, + 46: 0.20955, + 47: 0.20955, + 48: 0.20955, + 49: 0.20955, + 50: 0.20955, + 51: 0.20955, + 52: 0.20955, + 53: 0.20955, + 54: 0.20955, + 55: 0.20955, + 56: 0.20955, + 57: 0.20955, + 58: 0.20955, + 59: 0.20955, + 60: 0.20955, + 61: 0.20955, + 62: 0.20955, + 63: 0.20955, + 64: 0.20955, + 65: 0.20955, + 66: 0.20955, + 67: 0.20955, + 68: 0.20955, + 69: 0.20955, + 70: 0.20955, + 71: 0.20955, + 72: 0.20955, + 73: 0.20955, + 74: 0.20955, + 75: 0.20955, + 76: 0.20955, + 77: 0.20955, + 78: 0.20955, + 79: 0.20955, + 80: 0.20955, + 81: 0.20955, + 82: 0.20955, + 83: 0.20955, + 84: 0.20955, + 85: 0.20955, + 86: 0.20955, + 87: 0.20955, + 88: 0.20955, + 89: 0.20955, + 90: 0.20955, + 91: 0.20955, + 92: 0.20955, + 93: 0.20955, + 94: 0.20955, + 95: 0.20955, + 96: 0.20955, + 97: 0.20955, + 98: 0.20955, + 99: 0.20955, + 100: 0.20955, + } + float horizontalApertureOffset.timeSamples = { + 1: 0, + 2: 0, + 3: 0, + 4: 0, + 5: 0, + 6: 0, + 7: 0, + 8: 0, + 9: 0, + 10: 0, + 11: 0, + 12: 0, + 13: 0, + 14: 0, + 15: 0, + 16: 0, + 17: 0, + 18: 0, + 19: 0, + 20: 0, + 21: 0, + 22: 0, + 23: 0, + 24: 0, + 25: 0, + 26: 0, + 27: 0, + 28: 0, + 29: 0, + 30: 0, + 31: 0, + 32: 0, + 33: 0, + 34: 0, + 35: 0, + 36: 0, + 37: 0, + 38: 0, + 39: 0, + 40: 0, + 41: 0, + 42: 0, + 43: 0, + 44: 0, + 45: 0, + 46: 0, + 47: 0, + 48: 0, + 49: 0, + 50: 0, + 51: 0, + 52: 0, + 53: 0, + 54: 0, + 55: 0, + 56: 0, + 57: 0, + 58: 0, + 59: 0, + 60: 0, + 61: 0, + 62: 0, + 63: 0, + 64: 0, + 65: 0, + 66: 0, + 67: 0, + 68: 0, + 69: 0, + 70: 0, + 71: 0, + 72: 0, + 73: 0, + 74: 0, + 75: 0, + 76: 0, + 77: 0, + 78: 0, + 79: 0, + 80: 0, + 81: 0, + 82: 0, + 83: 0, + 84: 0, + 85: 0, + 86: 0, + 87: 0, + 88: 0, + 89: 0, + 90: 0, + 91: 0, + 92: 0, + 93: 0, + 94: 0, + 95: 0, + 96: 0, + 97: 0, + 98: 0, + 99: 0, + 100: 0, + } + custom float houdini:guidescale + float houdini:guidescale.timeSamples = { + 1: 1, + 2: 1, + 3: 1, + 4: 1, + 5: 1, + 6: 1, + 7: 1, + 8: 1, + 9: 1, + 10: 1, + 11: 1, + 12: 1, + 13: 1, + 14: 1, + 15: 1, + 16: 1, + 17: 1, + 18: 1, + 19: 1, + 20: 1, + 21: 1, + 22: 1, + 23: 1, + 24: 1, + 25: 1, + 26: 1, + 27: 1, + 28: 1, + 29: 1, + 30: 1, + 31: 1, + 32: 1, + 33: 1, + 34: 1, + 35: 1, + 36: 1, + 37: 1, + 38: 1, + 39: 1, + 40: 1, + 41: 1, + 42: 1, + 43: 1, + 44: 1, + 45: 1, + 46: 1, + 47: 1, + 48: 1, + 49: 1, + 50: 1, + 51: 1, + 52: 1, + 53: 1, + 54: 1, + 55: 1, + 56: 1, + 57: 1, + 58: 1, + 59: 1, + 60: 1, + 61: 1, + 62: 1, + 63: 1, + 64: 1, + 65: 1, + 66: 1, + 67: 1, + 68: 1, + 69: 1, + 70: 1, + 71: 1, + 72: 1, + 73: 1, + 74: 1, + 75: 1, + 76: 1, + 77: 1, + 78: 1, + 79: 1, + 80: 1, + 81: 1, + 82: 1, + 83: 1, + 84: 1, + 85: 1, + 86: 1, + 87: 1, + 88: 1, + 89: 1, + 90: 1, + 91: 1, + 92: 1, + 93: 1, + 94: 1, + 95: 1, + 96: 1, + 97: 1, + 98: 1, + 99: 1, + 100: 1, + } + custom bool houdini:inviewermenu = 1 + token projection = "perspective" + double shutter:close = 0 + double shutter:open = 0 + float verticalAperture.timeSamples = { + 1: 0.11787187, + 2: 0.11787187, + 3: 0.11787187, + 4: 0.11787187, + 5: 0.11787187, + 6: 0.11787187, + 7: 0.11787187, + 8: 0.11787187, + 9: 0.11787187, + 10: 0.11787187, + 11: 0.11787187, + 12: 0.11787187, + 13: 0.11787187, + 14: 0.11787187, + 15: 0.11787187, + 16: 0.11787187, + 17: 0.11787187, + 18: 0.11787187, + 19: 0.11787187, + 20: 0.11787187, + 21: 0.11787187, + 22: 0.11787187, + 23: 0.11787187, + 24: 0.11787187, + 25: 0.11787187, + 26: 0.11787187, + 27: 0.11787187, + 28: 0.11787187, + 29: 0.11787187, + 30: 0.11787187, + 31: 0.11787187, + 32: 0.11787187, + 33: 0.11787187, + 34: 0.11787187, + 35: 0.11787187, + 36: 0.11787187, + 37: 0.11787187, + 38: 0.11787187, + 39: 0.11787187, + 40: 0.11787187, + 41: 0.11787187, + 42: 0.11787187, + 43: 0.11787187, + 44: 0.11787187, + 45: 0.11787187, + 46: 0.11787187, + 47: 0.11787187, + 48: 0.11787187, + 49: 0.11787187, + 50: 0.11787187, + 51: 0.11787187, + 52: 0.11787187, + 53: 0.11787187, + 54: 0.11787187, + 55: 0.11787187, + 56: 0.11787187, + 57: 0.11787187, + 58: 0.11787187, + 59: 0.11787187, + 60: 0.11787187, + 61: 0.11787187, + 62: 0.11787187, + 63: 0.11787187, + 64: 0.11787187, + 65: 0.11787187, + 66: 0.11787187, + 67: 0.11787187, + 68: 0.11787187, + 69: 0.11787187, + 70: 0.11787187, + 71: 0.11787187, + 72: 0.11787187, + 73: 0.11787187, + 74: 0.11787187, + 75: 0.11787187, + 76: 0.11787187, + 77: 0.11787187, + 78: 0.11787187, + 79: 0.11787187, + 80: 0.11787187, + 81: 0.11787187, + 82: 0.11787187, + 83: 0.11787187, + 84: 0.11787187, + 85: 0.11787187, + 86: 0.11787187, + 87: 0.11787187, + 88: 0.11787187, + 89: 0.11787187, + 90: 0.11787187, + 91: 0.11787187, + 92: 0.11787187, + 93: 0.11787187, + 94: 0.11787187, + 95: 0.11787187, + 96: 0.11787187, + 97: 0.11787187, + 98: 0.11787187, + 99: 0.11787187, + 100: 0.11787187, + } + float verticalApertureOffset.timeSamples = { + 1: 0, + 2: 0, + 3: 0, + 4: 0, + 5: 0, + 6: 0, + 7: 0, + 8: 0, + 9: 0, + 10: 0, + 11: 0, + 12: 0, + 13: 0, + 14: 0, + 15: 0, + 16: 0, + 17: 0, + 18: 0, + 19: 0, + 20: 0, + 21: 0, + 22: 0, + 23: 0, + 24: 0, + 25: 0, + 26: 0, + 27: 0, + 28: 0, + 29: 0, + 30: 0, + 31: 0, + 32: 0, + 33: 0, + 34: 0, + 35: 0, + 36: 0, + 37: 0, + 38: 0, + 39: 0, + 40: 0, + 41: 0, + 42: 0, + 43: 0, + 44: 0, + 45: 0, + 46: 0, + 47: 0, + 48: 0, + 49: 0, + 50: 0, + 51: 0, + 52: 0, + 53: 0, + 54: 0, + 55: 0, + 56: 0, + 57: 0, + 58: 0, + 59: 0, + 60: 0, + 61: 0, + 62: 0, + 63: 0, + 64: 0, + 65: 0, + 66: 0, + 67: 0, + 68: 0, + 69: 0, + 70: 0, + 71: 0, + 72: 0, + 73: 0, + 74: 0, + 75: 0, + 76: 0, + 77: 0, + 78: 0, + 79: 0, + 80: 0, + 81: 0, + 82: 0, + 83: 0, + 84: 0, + 85: 0, + 86: 0, + 87: 0, + 88: 0, + 89: 0, + 90: 0, + 91: 0, + 92: 0, + 93: 0, + 94: 0, + 95: 0, + 96: 0, + 97: 0, + 98: 0, + 99: 0, + 100: 0, + } + matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0.8, 6, 1) ) + matrix4d xformOp:transform:graftbranches1 = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform:graftbranches1", "xformOp:transform"] + } + + def Xform "lights" + { + def DomeLight "domelight_white" ( + prepend apiSchemas = ["HoudiniViewportGuideAPI"] + ) + { + custom rel filters = None + float houdini:guidescale.timeSamples = { + 0: 1, + 1: 1, + 2: 1, + 3: 1, + 4: 1, + 5: 1, + 6: 1, + 7: 1, + 8: 1, + 9: 1, + 10: 1, + 11: 1, + 12: 1, + 13: 1, + 14: 1, + 15: 1, + 16: 1, + 17: 1, + 18: 1, + 19: 1, + 20: 1, + 21: 1, + 22: 1, + 23: 1, + 24: 1, + 25: 1, + 26: 1, + 27: 1, + 28: 1, + 29: 1, + 30: 1, + 31: 1, + 32: 1, + 33: 1, + 34: 1, + 35: 1, + 36: 1, + 37: 1, + 38: 1, + 39: 1, + 40: 1, + 41: 1, + 42: 1, + 43: 1, + 44: 1, + 45: 1, + 46: 1, + 47: 1, + 48: 1, + 49: 1, + 50: 1, + 51: 1, + 52: 1, + 53: 1, + 54: 1, + 55: 1, + 56: 1, + 57: 1, + 58: 1, + 59: 1, + 60: 1, + 61: 1, + 62: 1, + 63: 1, + 64: 1, + 65: 1, + 66: 1, + 67: 1, + 68: 1, + 69: 1, + 70: 1, + 71: 1, + 72: 1, + 73: 1, + 74: 1, + 75: 1, + 76: 1, + 77: 1, + 78: 1, + 79: 1, + 80: 1, + 81: 1, + 82: 1, + 83: 1, + 84: 1, + 85: 1, + 86: 1, + 87: 1, + 88: 1, + 89: 1, + 90: 1, + 91: 1, + 92: 1, + 93: 1, + 94: 1, + 95: 1, + 96: 1, + 97: 1, + 98: 1, + 99: 1, + 100: 1, + 101: 1, + 102: 1, + 103: 1, + 104: 1, + 105: 1, + 106: 1, + 107: 1, + 108: 1, + 109: 1, + 110: 1, + 111: 1, + 112: 1, + 113: 1, + 114: 1, + 115: 1, + 116: 1, + 117: 1, + 118: 1, + 119: 1, + 120: 1, + 121: 1, + 122: 1, + 123: 1, + 124: 1, + 125: 1, + 126: 1, + 127: 1, + 128: 1, + 129: 1, + 130: 1, + 131: 1, + 132: 1, + 133: 1, + 134: 1, + 135: 1, + 136: 1, + 137: 1, + 138: 1, + 139: 1, + 140: 1, + 141: 1, + 142: 1, + 143: 1, + 144: 1, + 145: 1, + 146: 1, + 147: 1, + 148: 1, + 149: 1, + 150: 1, + 151: 1, + 152: 1, + 153: 1, + 154: 1, + 155: 1, + 156: 1, + 157: 1, + 158: 1, + 159: 1, + 160: 1, + 161: 1, + 162: 1, + 163: 1, + 164: 1, + 165: 1, + 166: 1, + 167: 1, + 168: 1, + 169: 1, + 170: 1, + 171: 1, + 172: 1, + 173: 1, + 174: 1, + 175: 1, + 176: 1, + 177: 1, + 178: 1, + 179: 1, + 180: 1, + 181: 1, + 182: 1, + 183: 1, + 184: 1, + 185: 1, + 186: 1, + 187: 1, + 188: 1, + 189: 1, + 190: 1, + 191: 1, + 192: 1, + 193: 1, + 194: 1, + 195: 1, + 196: 1, + 197: 1, + 198: 1, + 199: 1, + 200: 1, + } + bool houdini:inviewermenu = 0 + color3f inputs:color = (1, 1, 1) + float inputs:diffuse = 1 + bool inputs:enableColorTemperature = 0 + float inputs:exposure = 2.25 + float inputs:intensity = 1 + bool inputs:normalize = 0 + float inputs:specular = 1 + asset inputs:texture:file = @@ + token inputs:texture:format = "automatic" + rel light:filters = None + rel portals = None + matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + } + + def SphereLight "topleftlight" ( + prepend apiSchemas = ["HoudiniViewportGuideAPI", "HoudiniViewportLightAPI"] + ) + { + float2 houdini:clippingRange = (0.001, 10000) + float houdini:guidescale.timeSamples = { + 0: 1, + 1: 1, + 2: 1, + 3: 1, + 4: 1, + 5: 1, + 6: 1, + 7: 1, + 8: 1, + 9: 1, + 10: 1, + 11: 1, + 12: 1, + 13: 1, + 14: 1, + 15: 1, + 16: 1, + 17: 1, + 18: 1, + 19: 1, + 20: 1, + 21: 1, + 22: 1, + 23: 1, + 24: 1, + 25: 1, + 26: 1, + 27: 1, + 28: 1, + 29: 1, + 30: 1, + 31: 1, + 32: 1, + 33: 1, + 34: 1, + 35: 1, + 36: 1, + 37: 1, + 38: 1, + 39: 1, + 40: 1, + 41: 1, + 42: 1, + 43: 1, + 44: 1, + 45: 1, + 46: 1, + 47: 1, + 48: 1, + 49: 1, + 50: 1, + 51: 1, + 52: 1, + 53: 1, + 54: 1, + 55: 1, + 56: 1, + 57: 1, + 58: 1, + 59: 1, + 60: 1, + 61: 1, + 62: 1, + 63: 1, + 64: 1, + 65: 1, + 66: 1, + 67: 1, + 68: 1, + 69: 1, + 70: 1, + 71: 1, + 72: 1, + 73: 1, + 74: 1, + 75: 1, + 76: 1, + 77: 1, + 78: 1, + 79: 1, + 80: 1, + 81: 1, + 82: 1, + 83: 1, + 84: 1, + 85: 1, + 86: 1, + 87: 1, + 88: 1, + 89: 1, + 90: 1, + 91: 1, + 92: 1, + 93: 1, + 94: 1, + 95: 1, + 96: 1, + 97: 1, + 98: 1, + 99: 1, + 100: 1, + 101: 1, + 102: 1, + 103: 1, + 104: 1, + 105: 1, + 106: 1, + 107: 1, + 108: 1, + 109: 1, + 110: 1, + 111: 1, + 112: 1, + 113: 1, + 114: 1, + 115: 1, + 116: 1, + 117: 1, + 118: 1, + 119: 1, + 120: 1, + 121: 1, + 122: 1, + 123: 1, + 124: 1, + 125: 1, + 126: 1, + 127: 1, + 128: 1, + 129: 1, + 130: 1, + 131: 1, + 132: 1, + 133: 1, + 134: 1, + 135: 1, + 136: 1, + 137: 1, + 138: 1, + 139: 1, + 140: 1, + 141: 1, + 142: 1, + 143: 1, + 144: 1, + 145: 1, + 146: 1, + 147: 1, + 148: 1, + 149: 1, + 150: 1, + 151: 1, + 152: 1, + 153: 1, + 154: 1, + 155: 1, + 156: 1, + 157: 1, + 158: 1, + 159: 1, + 160: 1, + 161: 1, + 162: 1, + 163: 1, + 164: 1, + 165: 1, + 166: 1, + 167: 1, + 168: 1, + 169: 1, + 170: 1, + 171: 1, + 172: 1, + 173: 1, + 174: 1, + 175: 1, + 176: 1, + 177: 1, + 178: 1, + 179: 1, + 180: 1, + 181: 1, + 182: 1, + 183: 1, + 184: 1, + 185: 1, + 186: 1, + 187: 1, + 188: 1, + 189: 1, + 190: 1, + 191: 1, + 192: 1, + 193: 1, + 194: 1, + 195: 1, + 196: 1, + 197: 1, + 198: 1, + 199: 1, + 200: 1, + } + bool houdini:inviewermenu = 1 + color3f inputs:color = (1, 1, 1) + float inputs:diffuse = 1 + bool inputs:enableColorTemperature = 0 + float inputs:exposure = 5.35 + float inputs:intensity = 1 + bool inputs:normalize = 0 + float inputs:specular = 1 + rel light:filters = None + bool treatAsPoint = 1 + matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (1.1628675758838654, 2.7278940104183045, 2.755570574390484, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + } + } + } + + def Xform "bounds" ( + kind = "component" + ) + { + token visibility = "invisible" + matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ) + matrix4d xformOp:transform:xform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform", "xformOp:transform:xform"] + + def Cube "bound_box" + { + float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)] + double size = 1 + matrix4d xformOp:transform = ( (3.3, 0, 0, 0), (0, 1.55, 0, 0), (0, 0, 1.8, 0), (0, 0.835, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + } + + def Mesh "mesh_0" + { + float3[] extent = [(-1.65, 0, -0.9), (1.65, 1.65, 0.9)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [0, 1, 3, 2, 4, 5, 7, 6, 6, 7, 2, 3, 5, 4, 1, 0, 5, 0, 2, 7, 1, 4, 6, 3] + uniform token orientation = "leftHanded" + point3f[] points = [(1.65, 0, 0.9), (-1.65, 0, 0.9), (1.65, 1.65, 0.9), (-1.65, 1.65, 0.9), (-1.65, 0, -0.9), (1.65, 0, -0.9), (-1.65, 1.65, -0.9), (1.65, 1.65, -0.9)] ( + interpolation = "vertex" + ) + uniform token subdivisionScheme = "none" + } + } + + def Xform "parent" + { + matrix4d xformOp:transform.timeSamples = { + 0: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 1: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 2: ( (0.9980267284282716, 0, -0.06279051952931336, 0), (0, 1, 0, 0), (0.06279051952931336, 0, 0.9980267284282716, 0), (0, 0, 0, 1) ), + 3: ( (0.9921147013144779, 0, -0.1253332335643042, 0), (0, 1, 0, 0), (0.1253332335643042, 0, 0.9921147013144779, 0), (0, 0, 0, 1) ), + 4: ( (0.9822872507286887, 0, -0.1873813145857246, 0), (0, 1, 0, 0), (0.1873813145857246, 0, 0.9822872507286887, 0), (0, 0, 0, 1) ), + 5: ( (0.9685831611286312, 0, -0.24868988716485463, 0), (0, 1, 0, 0), (0.24868988716485463, 0, 0.9685831611286312, 0), (0, 0, 0, 1) ), + 6: ( (0.9510565162951536, 0, -0.30901699437494723, 0), (0, 1, 0, 0), (0.30901699437494723, 0, 0.9510565162951536, 0), (0, 0, 0, 1) ), + 7: ( (0.9297764858882516, 0, -0.36812455268467764, 0), (0, 1, 0, 0), (0.36812455268467764, 0, 0.9297764858882516, 0), (0, 0, 0, 1) ), + 8: ( (0.9048270524660197, 0, -0.4257792915650723, 0), (0, 1, 0, 0), (0.4257792915650723, 0, 0.9048270524660197, 0), (0, 0, 0, 1) ), + 9: ( (0.8763066800438638, 0, -0.4817536741017148, 0), (0, 1, 0, 0), (0.4817536741017148, 0, 0.8763066800438638, 0), (0, 0, 0, 1) ), + 10: ( (0.8443279255020155, 0, -0.535826794978996, 0), (0, 1, 0, 0), (0.535826794978996, 0, 0.8443279255020155, 0), (0, 0, 0, 1) ), + 11: ( (0.8090169943749479, 0, -0.5877852522924725, 0), (0, 1, 0, 0), (0.5877852522924725, 0, 0.8090169943749479, 0), (0, 0, 0, 1) ), + 12: ( (0.7705132427757898, 0, -0.637423989748689, 0), (0, 1, 0, 0), (0.637423989748689, 0, 0.7705132427757898, 0), (0, 0, 0, 1) ), + 13: ( (0.7289686274214123, 0, -0.6845471059286878, 0), (0, 1, 0, 0), (0.6845471059286878, 0, 0.7289686274214123, 0), (0, 0, 0, 1) ), + 14: ( (0.6845471059286896, 0, -0.7289686274214106, 0), (0, 1, 0, 0), (0.7289686274214106, 0, 0.6845471059286896, 0), (0, 0, 0, 1) ), + 15: ( (0.637423989748691, 0, -0.7705132427757883, 0), (0, 1, 0, 0), (0.7705132427757883, 0, 0.637423989748691, 0), (0, 0, 0, 1) ), + 16: ( (0.5877852522924748, 0, -0.8090169943749462, 0), (0, 1, 0, 0), (0.8090169943749462, 0, 0.5877852522924748, 0), (0, 0, 0, 1) ), + 17: ( (0.5358267949789984, 0, -0.8443279255020139, 0), (0, 1, 0, 0), (0.8443279255020139, 0, 0.5358267949789984, 0), (0, 0, 0, 1) ), + 18: ( (0.48175367410171727, 0, -0.8763066800438625, 0), (0, 1, 0, 0), (0.8763066800438625, 0, 0.48175367410171727, 0), (0, 0, 0, 1) ), + 19: ( (0.42577929156507527, 0, -0.9048270524660184, 0), (0, 1, 0, 0), (0.9048270524660184, 0, 0.42577929156507527, 0), (0, 0, 0, 1) ), + 20: ( (0.3681245526846806, 0, -0.9297764858882503, 0), (0, 1, 0, 0), (0.9297764858882503, 0, 0.3681245526846806, 0), (0, 0, 0, 1) ), + 21: ( (0.3090169943749502, 0, -0.9510565162951526, 0), (0, 1, 0, 0), (0.9510565162951526, 0, 0.3090169943749502, 0), (0, 0, 0, 1) ), + 22: ( (0.248689887164858, 0, -0.9685831611286303, 0), (0, 1, 0, 0), (0.9685831611286303, 0, 0.248689887164858, 0), (0, 0, 0, 1) ), + 23: ( (0.18738131458572843, 0, -0.9822872507286879, 0), (0, 1, 0, 0), (0.9822872507286879, 0, 0.18738131458572843, 0), (0, 0, 0, 1) ), + 24: ( (0.125333233564308, 0, -0.9921147013144773, 0), (0, 1, 0, 0), (0.9921147013144773, 0, 0.125333233564308, 0), (0, 0, 0, 1) ), + 25: ( (0.06279051952931751, 0, -0.9980267284282713, 0), (0, 1, 0, 0), (0.9980267284282713, 0, 0.06279051952931751, 0), (0, 0, 0, 1) ), + 26: ( (4.502124438457994e-15, 0, -1, 0), (0, 1, 0, 0), (1, 0, 4.502124438457994e-15, 0), (0, 0, 0, 1) ), + 27: ( (-0.06279051952930853, 0, -0.9980267284282719, 0), (0, 1, -0, 0), (0.9980267284282719, 0, -0.06279051952930853, 0), (0, 0, -0, 1) ), + 28: ( (-0.12533323356429907, 0, -0.9921147013144784, 0), (0, 1, -0, 0), (0.9921147013144784, 0, -0.12533323356429907, 0), (0, 0, -0, 1) ), + 29: ( (-0.18738131458571958, 0, -0.9822872507286896, 0), (0, 1, -0, 0), (0.9822872507286896, 0, -0.18738131458571958, 0), (0, 0, -0, 1) ), + 30: ( (-0.2486898871648486, 0, -0.9685831611286327, 0), (0, 1, -0, 0), (0.9685831611286327, 0, -0.2486898871648486, 0), (0, 0, -0, 1) ), + 31: ( (-0.30901699437494123, 0, -0.9510565162951556, 0), (0, 1, -0, 0), (0.9510565162951556, 0, -0.30901699437494123, 0), (0, 0, -0, 1) ), + 32: ( (-0.36812455268467237, 0, -0.9297764858882536, 0), (0, 1, -0, 0), (0.9297764858882536, 0, -0.36812455268467237, 0), (0, 0, -0, 1) ), + 33: ( (-0.42577929156506633, 0, -0.9048270524660225, 0), (0, 1, -0, 0), (0.9048270524660225, 0, -0.42577929156506633, 0), (0, 0, -0, 1) ), + 34: ( (-0.48175367410170883, 0, -0.8763066800438671, 0), (0, 1, -0, 0), (0.8763066800438671, 0, -0.48175367410170883, 0), (0, 0, -0, 1) ), + 35: ( (-0.5358267949789904, 0, -0.844327925502019, 0), (0, 1, -0, 0), (0.844327925502019, 0, -0.5358267949789904, 0), (0, 0, -0, 1) ), + 36: ( (-0.5877852522924666, 0, -0.8090169943749521, 0), (0, 1, -0, 0), (0.8090169943749521, 0, -0.5877852522924666, 0), (0, 0, -0, 1) ), + 37: ( (-0.6374239897486832, 0, -0.7705132427757946, 0), (0, 1, -0, 0), (0.7705132427757946, 0, -0.6374239897486832, 0), (0, 0, -0, 1) ), + 38: ( (-0.6845471059286823, 0, -0.7289686274214175, 0), (0, 1, -0, 0), (0.7289686274214175, 0, -0.6845471059286823, 0), (0, 0, -0, 1) ), + 39: ( (-0.7289686274214056, 0, -0.684547105928695, 0), (0, 1, -0, 0), (0.684547105928695, 0, -0.7289686274214056, 0), (0, 0, -0, 1) ), + 40: ( (-0.7705132427757835, 0, -0.6374239897486967, 0), (0, 1, -0, 0), (0.6374239897486967, 0, -0.7705132427757835, 0), (0, 0, -0, 1) ), + 41: ( (-0.8090169943749417, 0, -0.5877852522924811, 0), (0, 1, -0, 0), (0.5877852522924811, 0, -0.8090169943749417, 0), (0, 0, -0, 1) ), + 42: ( (-0.8443279255020099, 0, -0.5358267949790049, 0), (0, 1, -0, 0), (0.5358267949790049, 0, -0.8443279255020099, 0), (0, 0, -0, 1) ), + 43: ( (-0.8763066800438587, 0, -0.48175367410172415, 0), (0, 1, -0, 0), (0.48175367410172415, 0, -0.8763066800438587, 0), (0, 0, -0, 1) ), + 44: ( (-0.9048270524660152, 0, -0.42577929156508176, 0), (0, 1, -0, 0), (0.42577929156508176, 0, -0.9048270524660152, 0), (0, 0, -0, 1) ), + 45: ( (-0.9297764858882476, 0, -0.36812455268468763, 0), (0, 1, -0, 0), (0.36812455268468763, 0, -0.9297764858882476, 0), (0, 0, -0, 1) ), + 46: ( (-0.9510565162951502, 0, -0.30901699437495767, 0), (0, 1, -0, 0), (0.30901699437495767, 0, -0.9510565162951502, 0), (0, 0, -0, 1) ), + 47: ( (-0.9685831611286283, 0, -0.24868988716486556, 0), (0, 1, -0, 0), (0.24868988716486556, 0, -0.9685831611286283, 0), (0, 0, -0, 1) ), + 48: ( (-0.9822872507286866, 0, -0.18738131458573548, 0), (0, 1, -0, 0), (0.18738131458573548, 0, -0.9822872507286866, 0), (0, 0, -0, 1) ), + 49: ( (-0.9921147013144763, 0, -0.125333233564316, 0), (0, 1, -0, 0), (0.125333233564316, 0, -0.9921147013144763, 0), (0, 0, -0, 1) ), + 50: ( (-0.9980267284282708, 0, -0.06279051952932511, 0), (0, 1, -0, 0), (0.06279051952932511, 0, -0.9980267284282708, 0), (0, 0, -0, 1) ), + 51: ( (-1, 0, -1.2112873345866426e-14, 0), (0, 1, -0, 0), (1.2112873345866426e-14, 0, -1, 0), (0, 0, -0, 1) ), + 52: ( (-0.9980267284282723, 0, 0.06279051952930093, 0), (-0, 1, 0, 0), (-0.06279051952930093, 0, -0.9980267284282723, 0), (-0, 0, 0, 1) ), + 53: ( (-0.9921147013144795, 0, 0.12533323356429107, 0), (-0, 1, 0, 0), (-0.12533323356429107, 0, -0.9921147013144795, 0), (-0, 0, 0, 1) ), + 54: ( (-0.982287250728691, 0, 0.1873813145857121, 0), (-0, 1, 0, 0), (-0.1873813145857121, 0, -0.982287250728691, 0), (-0, 0, 0, 1) ), + 55: ( (-0.9685831611286345, 0, 0.24868988716484167, 0), (-0, 1, 0, 0), (-0.24868988716484167, 0, -0.9685831611286345, 0), (-0, 0, 0, 1) ), + 56: ( (-0.9510565162951576, 0, 0.3090169943749351, 0), (-0, 1, 0, 0), (-0.3090169943749351, 0, -0.9510565162951576, 0), (-0, 0, 0, 1) ), + 57: ( (-0.929776485888256, 0, 0.3681245526846664, 0), (-0, 1, 0, 0), (-0.3681245526846664, 0, -0.929776485888256, 0), (-0, 0, 0, 1) ), + 58: ( (-0.9048270524660253, 0, 0.4257792915650602, 0), (-0, 1, 0, 0), (-0.4257792915650602, 0, -0.9048270524660253, 0), (-0, 0, 0, 1) ), + 59: ( (-0.8763066800438701, 0, 0.48175367410170333, 0), (-0, 1, 0, 0), (-0.48175367410170333, 0, -0.8763066800438701, 0), (-0, 0, 0, 1) ), + 60: ( (-0.8443279255020226, 0, 0.5358267949789848, 0), (-0, 1, 0, 0), (-0.5358267949789848, 0, -0.8443279255020226, 0), (-0, 0, 0, 1) ), + 61: ( (-0.8090169943749556, 0, 0.5877852522924618, 0), (-0, 1, 0, 0), (-0.5877852522924618, 0, -0.8090169943749556, 0), (-0, 0, 0, 1) ), + 62: ( (-0.7705132427757986, 0, 0.6374239897486784, 0), (-0, 1, 0, 0), (-0.6374239897486784, 0, -0.7705132427757986, 0), (-0, 0, 0, 1) ), + 63: ( (-0.728968627421421, 0, 0.6845471059286786, 0), (-0, 1, 0, 0), (-0.6845471059286786, 0, -0.728968627421421, 0), (-0, 0, 0, 1) ), + 64: ( (-0.6845471059286986, 0, 0.7289686274214022, 0), (-0, 1, 0, 0), (-0.7289686274214022, 0, -0.6845471059286986, 0), (-0, 0, 0, 1) ), + 65: ( (-0.6374239897487012, 0, 0.7705132427757797, 0), (-0, 1, 0, 0), (-0.7705132427757797, 0, -0.6374239897487012, 0), (-0, 0, 0, 1) ), + 66: ( (-0.5877852522924848, 0, 0.809016994374939, 0), (-0, 1, 0, 0), (-0.809016994374939, 0, -0.5877852522924848, 0), (-0, 0, 0, 1) ), + 67: ( (-0.5358267949790083, 0, 0.8443279255020076, 0), (-0, 1, 0, 0), (-0.8443279255020076, 0, -0.5358267949790083, 0), (-0, 0, 0, 1) ), + 68: ( (-0.4817536741017277, 0, 0.8763066800438567, 0), (-0, 1, 0, 0), (-0.8763066800438567, 0, -0.4817536741017277, 0), (-0, 0, 0, 1) ), + 69: ( (-0.42577929156508504, 0, 0.9048270524660137, 0), (-0, 1, 0, 0), (-0.9048270524660137, 0, -0.42577929156508504, 0), (-0, 0, 0, 1) ), + 70: ( (-0.368124552684691, 0, 0.9297764858882462, 0), (-0, 1, 0, 0), (-0.9297764858882462, 0, -0.368124552684691, 0), (-0, 0, 0, 1) ), + 71: ( (-0.3090169943749611, 0, 0.9510565162951491, 0), (-0, 1, 0, 0), (-0.9510565162951491, 0, -0.3090169943749611, 0), (-0, 0, 0, 1) ), + 72: ( (-0.24868988716486734, 0, 0.9685831611286279, 0), (-0, 1, 0, 0), (-0.9685831611286279, 0, -0.24868988716486734, 0), (-0, 0, 0, 1) ), + 73: ( (-0.18738131458573773, 0, 0.9822872507286862, 0), (-0, 1, 0, 0), (-0.9822872507286862, 0, -0.18738131458573773, 0), (-0, 0, 0, 1) ), + 74: ( (-0.1253332335643178, 0, 0.9921147013144761, 0), (-0, 1, 0, 0), (-0.9921147013144761, 0, -0.1253332335643178, 0), (-0, 0, 0, 1) ), + 75: ( (-0.0627905195293265, 0, 0.9980267284282708, 0), (-0, 1, 0, 0), (-0.9980267284282708, 0, -0.0627905195293265, 0), (-0, 0, 0, 1) ), + 76: ( (-1.2618194895673856e-14, 0, 1, 0), (-0, 1, 0, 0), (-1, 0, -1.2618194895673856e-14, 0), (-0, 0, 0, 1) ), + 77: ( (0.06279051952930043, 0, 0.9980267284282723, 0), (0, 1, 0, 0), (-0.9980267284282723, 0, 0.06279051952930043, 0), (0, 0, 0, 1) ), + 78: ( (0.1253332335642919, 0, 0.9921147013144794, 0), (0, 1, 0, 0), (-0.9921147013144794, 0, 0.1253332335642919, 0), (0, 0, 0, 1) ), + 79: ( (0.18738131458571292, 0, 0.9822872507286909, 0), (0, 1, 0, 0), (-0.9822872507286909, 0, 0.18738131458571292, 0), (0, 0, 0, 1) ), + 80: ( (0.24868988716484375, 0, 0.968583161128634, 0), (0, 1, 0, 0), (-0.968583161128634, 0, 0.24868988716484375, 0), (0, 0, 0, 1) ), + 81: ( (0.30901699437493624, 0, 0.9510565162951572, 0), (0, 1, 0, 0), (-0.9510565162951572, 0, 0.30901699437493624, 0), (0, 0, 0, 1) ), + 82: ( (0.36812455268466754, 0, 0.9297764858882556, 0), (0, 1, 0, 0), (-0.9297764858882556, 0, 0.36812455268466754, 0), (0, 0, 0, 1) ), + 83: ( (0.42577929156506217, 0, 0.9048270524660245, 0), (0, 1, 0, 0), (-0.9048270524660245, 0, 0.42577929156506217, 0), (0, 0, 0, 1) ), + 84: ( (0.4817536741017056, 0, 0.8763066800438689, 0), (0, 1, 0, 0), (-0.8763066800438689, 0, 0.4817536741017056, 0), (0, 0, 0, 1) ), + 85: ( (0.5358267949789878, 0, 0.8443279255020207, 0), (0, 1, 0, 0), (-0.8443279255020207, 0, 0.5358267949789878, 0), (0, 0, 0, 1) ), + 86: ( (0.5877852522924658, 0, 0.8090169943749528, 0), (0, 1, 0, 0), (-0.8090169943749528, 0, 0.5877852522924658, 0), (0, 0, 0, 1) ), + 87: ( (0.6374239897486831, 0, 0.7705132427757947, 0), (0, 1, 0, 0), (-0.7705132427757947, 0, 0.6374239897486831, 0), (0, 0, 0, 1) ), + 88: ( (0.6845471059286835, 0, 0.7289686274214164, 0), (0, 1, 0, 0), (-0.7289686274214164, 0, 0.6845471059286835, 0), (0, 0, 0, 1) ), + 89: ( (0.7289686274214063, 0, 0.6845471059286942, 0), (0, 1, 0, 0), (-0.6845471059286942, 0, 0.7289686274214063, 0), (0, 0, 0, 1) ), + 90: ( (0.7705132427757859, 0, 0.6374239897486937, 0), (0, 1, 0, 0), (-0.6374239897486937, 0, 0.7705132427757859, 0), (0, 0, 0, 1) ), + 91: ( (0.8090169943749437, 0, 0.5877852522924784, 0), (0, 1, 0, 0), (-0.5877852522924784, 0, 0.8090169943749437, 0), (0, 0, 0, 1) ), + 92: ( (0.8443279255020124, 0, 0.5358267949790009, 0), (0, 1, 0, 0), (-0.5358267949790009, 0, 0.8443279255020124, 0), (0, 0, 0, 1) ), + 93: ( (0.8763066800438614, 0, 0.4817536741017192, 0), (0, 1, 0, 0), (-0.4817536741017192, 0, 0.8763066800438614, 0), (0, 0, 0, 1) ), + 94: ( (0.9048270524660175, 0, 0.42577929156507704, 0), (0, 1, 0, 0), (-0.42577929156507704, 0, 0.9048270524660175, 0), (0, 0, 0, 1) ), + 95: ( (0.9297764858882505, 0, 0.3681245526846803, 0), (0, 1, 0, 0), (-0.3681245526846803, 0, 0.9297764858882505, 0), (0, 0, 0, 1) ), + 96: ( (0.951056516295153, 0, 0.30901699437494934, 0), (0, 1, 0, 0), (-0.30901699437494934, 0, 0.951056516295153, 0), (0, 0, 0, 1) ), + 97: ( (0.9685831611286307, 0, 0.2486898871648562, 0), (0, 1, 0, 0), (-0.2486898871648562, 0, 0.9685831611286307, 0), (0, 0, 0, 1) ), + 98: ( (0.9822872507286887, 0, 0.18738131458572468, 0), (0, 1, 0, 0), (-0.18738131458572468, 0, 0.9822872507286887, 0), (0, 0, 0, 1) ), + 99: ( (0.9921147013144781, 0, 0.125333233564302, 0), (0, 1, 0, 0), (-0.125333233564302, 0, 0.9921147013144781, 0), (0, 0, 0, 1) ), + 100: ( (0.9980267284282716, 0, 0.06279051952931326, 0), (0, 1, 0, 0), (-0.06279051952931326, 0, 0.9980267284282716, 0), (0, 0, 0, 1) ), + 101: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 102: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 103: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 104: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 105: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 106: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 107: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 108: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 109: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 110: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 111: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 112: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 113: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 114: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 115: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 116: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 117: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 118: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 119: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 120: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 121: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 122: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 123: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 124: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 125: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 126: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 127: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 128: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 129: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 130: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 131: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 132: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 133: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 134: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 135: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 136: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 137: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 138: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 139: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 140: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 141: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 142: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 143: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 144: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 145: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 146: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 147: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 148: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 149: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 150: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 151: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 152: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 153: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 154: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 155: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 156: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 157: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 158: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 159: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 160: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 161: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 162: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 163: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 164: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 165: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 166: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 167: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 168: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 169: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 170: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 171: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 172: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 173: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 174: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 175: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 176: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 177: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 178: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 179: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 180: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 181: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 182: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 183: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 184: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 185: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 186: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 187: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 188: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 189: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 190: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 191: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 192: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 193: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 194: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 195: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 196: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 197: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 198: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 199: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + 200: ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) ), + } + uniform token[] xformOpOrder = ["xformOp:transform"] + } +} + diff --git a/pyproject.toml b/pyproject.toml index 304dd4a..9ee9977 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ name = "usd-qtpy" authors = [ {name = "BigRoy"}, {name = "Hannes"}, + {name = "Sasbom"}, ] description = "Python Qt components for building custom USD tools." readme = "README.md" diff --git a/usd_qtpy/editor.py b/usd_qtpy/editor.py index d7891ae..cc6825a 100644 --- a/usd_qtpy/editor.py +++ b/usd_qtpy/editor.py @@ -1,11 +1,13 @@ import logging +from functools import partial from qtpy import QtWidgets, QtCore from . import ( prim_hierarchy, layer_editor, - prim_spec_editor + prim_spec_editor, + render_util ) @@ -29,6 +31,8 @@ def __init__(self, stage, parent=None): title = f"{title}: {name}" self.setWindowTitle(title) + self._stage = stage + self.setWindowFlags( self.windowFlags() | QtCore.Qt.Dialog @@ -49,8 +53,10 @@ def __init__(self, stage, parent=None): splitter.addWidget(hierarchy_widget) viewer_widget = None + self._stageview = None if HAS_VIEWER: viewer_widget = viewer.Widget(stage=stage) + self._stageview = viewer_widget.view splitter.addWidget(viewer_widget) prim_spec_editor_widget = prim_spec_editor.SpecEditorWindow(stage=stage) @@ -75,6 +81,8 @@ def build_menubar(self): menubar = QtWidgets.QMenuBar() + # Panels menu + panels_menu = menubar.addMenu("Panels") for label, widget in self._panels.items(): action = panels_menu.addAction(label) @@ -94,5 +102,45 @@ def update_panel_checkstate(): panels_menu.aboutToShow.connect(update_panel_checkstate) + # Render menu + render_menu = menubar.addMenu("Render") + render_labels = ( + "Snapshot View", "Snapshot Framing Camera", + "Playblast Stage", "Turntable Stage" + ) + render_actions = {label: render_menu.addAction(label) for label in render_labels} + + # brings up dialog to snap the current camera view. + render_snap = partial(render_util.dialog._savepicture_dialog, self._stage, self._stageview) + + def snap_framingcam(stage): + """Render still frame from a 'framed camera'""" + filepath = render_util.prompt_output_path("Save frame with framing camera") + if not filepath: + return + camera = render_util.create_framing_camera_in_stage(stage, fit=1.1) + render_util.render_playblast(stage, + filepath, + "1", + 1920, + renderer="GL", + camera=camera) + stage.RemovePrim(camera.GetPath()) + + render_snap_with_framingcam = partial(snap_framingcam, self._stage) + + def show_dialog(parent, stage, stageview): + dialog = render_util.PlayblastDialog(parent, stage, stageview) + dialog.show() + + def show_ttable_dialog(parent, stage, stageview): + dialog = render_util.TurntableDialog(parent, stage, stageview) + dialog.show() + + render_actions["Snapshot View"].triggered.connect(render_snap) + render_actions["Snapshot Framing Camera"].triggered.connect(render_snap_with_framingcam) + render_actions["Playblast Stage"].triggered.connect(partial(show_dialog, self, self._stage, self._stageview)) + render_actions["Turntable Stage"].triggered.connect(partial(show_ttable_dialog, self, self._stage, self._stageview)) + layout = self.layout() layout.setMenuBar(menubar) diff --git a/usd_qtpy/lib/qt.py b/usd_qtpy/lib/qt.py index f91da8b..9ec0842 100644 --- a/usd_qtpy/lib/qt.py +++ b/usd_qtpy/lib/qt.py @@ -1,6 +1,7 @@ import re import sys import logging +from functools import wraps from qtpy import QtCore, QtGui, QtWidgets @@ -55,6 +56,7 @@ def report_error(fn): `Tf.Notice` registry because those do not output the errors that occur. """ + @wraps(fn) # keep signature and docstring of decorated function intact. def wrap(*args, **kwargs): try: return fn(*args, **kwargs) diff --git a/usd_qtpy/lib/usd.py b/usd_qtpy/lib/usd.py index 7dfbb21..32dda74 100644 --- a/usd_qtpy/lib/usd.py +++ b/usd_qtpy/lib/usd.py @@ -1,4 +1,5 @@ from collections import defaultdict +from typing import Union from pxr import Usd, Plug, Tf, Sdf import logging @@ -319,4 +320,4 @@ def remove_spec(spec): spec.owner.RemoveVariant(spec) else: - raise TypeError(f"Unsupported spec type: {spec}") + raise TypeError(f"Unsupported spec type: {spec}") \ No newline at end of file diff --git a/usd_qtpy/render_util/__init__.py b/usd_qtpy/render_util/__init__.py new file mode 100644 index 0000000..718a09f --- /dev/null +++ b/usd_qtpy/render_util/__init__.py @@ -0,0 +1,46 @@ +# module named render_util to not collide in names with houdini's render.py +from .playblast import * +from .framing_camera import * +from .turntable import * +from .dialog import * +from .base import * + + +from_base = (RenderReportable, + using_tempfolder, + TempStageOpen + ) + +from_dialog = (prompt_input_path, + prompt_output_path, + PlayblastDialog, + TurntableDialog + ) + +from_turntable = (create_turntable_xform, + create_turntable_camera, + get_turntable_frames_string, + turntable_from_file, + get_file_timerange_as_string, + file_is_zup + ) + +from_playblast = (camera_from_stageview, + iter_stage_cameras, + get_file_cameras, + get_frames_string, + tuples_to_frames_string, + render_playblast + ) + +from_framing_camera = (get_stage_up, + create_framing_camera_in_stage, + camera_conform_sensor_to_aspect, + ) + +# Unroll into __all__ and expose +__all__ = [*from_base, + *from_dialog, + *from_turntable, + *from_playblast, + *from_framing_camera] \ No newline at end of file diff --git a/usd_qtpy/render_util/base.py b/usd_qtpy/render_util/base.py new file mode 100644 index 0000000..a8a688b --- /dev/null +++ b/usd_qtpy/render_util/base.py @@ -0,0 +1,86 @@ +# Provides mixins and classes to be inherited from, as well as decorators +import os +from contextlib import contextmanager +from functools import wraps +from typing import Callable, Union + +from qtpy import QtCore +from pxr import Usd, Sdf + +TEMPFOLDER = "./temp" + + +def get_tempfolder() -> str: + """ + Utility function to get temporary folder adress from module + """ + return TEMPFOLDER + + +def using_tempfolder(func: Callable): + """ + Decorator to indicate use of temporary folder, + so that it may be cleaned up after. + """ + + tempfolder: str = TEMPFOLDER + + @wraps(func) + def wrapper(*args,**kwargs): + # make temp folder + if not os.path.isdir(tempfolder): + os.mkdir(tempfolder) + + # execute function + result = func(*args,**kwargs) + # remove temp folder + + os.rmdir(tempfolder) + + return result + + return wrapper + + +@contextmanager +def defer_file_deletion(path: str): + try: + yield None + finally: + os.remove(path) + + +@contextmanager +def defer_primpath_deletion(stage: Usd.Stage, path: Union[str, Sdf.Path]): + if isinstance(path, str): + path = Sdf.Path(path) + try: + yield None + finally: + stage.RemovePrim(path) + + +class TempStageOpen: + """ + Context manager for Usd.Stage that needs to temporarily be open. + """ + def __init__(self, path: str, remove_file: bool = False): + self._stage = Usd.Stage.Open(path) + self._remove_file = remove_file + self._path = path + + def __enter__(self) -> Usd.Stage: + return self._stage + + def __exit__(self, type, value, traceback): + del self._stage + if self._remove_file: + os.remove(self._path) + + +class RenderReportable: + """ + Mixin class to set up signals for everything needing slots. + """ + render_progress: QtCore.Signal = QtCore.Signal(int) + total_frames: QtCore.Signal = QtCore.Signal(int) \ No newline at end of file diff --git a/usd_qtpy/render_util/dialog.py b/usd_qtpy/render_util/dialog.py new file mode 100644 index 0000000..61f24e8 --- /dev/null +++ b/usd_qtpy/render_util/dialog.py @@ -0,0 +1,951 @@ +# Dialog functions and wrappers to do with the rendering API. + +import os +import re +from functools import partial +from contextlib import ExitStack + +from qtpy import QtWidgets, QtCore +from pxr import Usd, UsdGeom, Sdf +from pxr.Usdviewq.stageView import StageView + +from . import playblast, framing_camera, turntable +from .base import (RenderReportable, + TempStageOpen, + get_tempfolder, + using_tempfolder, + defer_primpath_deletion, + defer_file_deletion) +from ..resources import get_icon + + +REGEX_HASH = re.compile(r"(#{2,})") +REGEX_FRAMENUM = re.compile(r"(\d+)") + + +def _rectify_path_framenumberspec(path: str, padding: int = 4): + """Ensure a placeholder for framenumbers exists in the path. + + >>> _rectify_path_framenumberspec("filename##.png") + "filename####.png" + >>> _rectify_path_framenumberspec("filename###.png") + "filename####.png" + + Returns: + str: The path with an ensured frame number hash. + + """ + base, file = os.path.split(path) + file, extension = os.path.splitext(file) + # if too little hashes were present, remove them. + file = file.replace("#", "") + file += "#" * padding + + return os.path.join(base, file + extension) + + +def _path_sequence_to_framenumberspec(path: str): + """ get the last found element of a filename that is a sequence of numbers, + and modify them to hashes (#) """ + + framenum_match = list(REGEX_FRAMENUM.finditer(path)) + + if framenum_match: + last_match = framenum_match[-1] + start, end = last_match.span() + hash_padding = len(last_match.group(0)) + path = f"{path[:start]}{hash_padding * '#'}{path[end:]}" + + return path + + +def prompt_input_path(caption: str="Load item", folder: str = None) -> str: + + filename, _ = QtWidgets.QFileDialog.getOpenFileName( + caption=caption, + filter="USD (*.usd *.usda *.usdc)", + directory=folder + ) + return filename + + +def prompt_output_path(caption="Save frame", folder: str = None): + """Prompt for render filename, ensure frame hashes are present in path""" + filename, _ = QtWidgets.QFileDialog.getSaveFileName( + caption=caption, + filter="PNG (*.png);;JPEG (*.jpg, *.jpeg)", + directory=folder + ) + + # Attempt to replace last occurring sequence of numbers + # in filename with hashes + filename = _path_sequence_to_framenumberspec(filename) + + # ensure there's at least two or more hashes, if not, put in 4. + hash_match = REGEX_HASH.search(filename) + if not hash_match: + filename = _rectify_path_framenumberspec(filename) + + return filename + + +def _savepicture_dialog(stage: Usd.Stage, + stageview: StageView, + width: int = 16, + height: int = 9): + """ + Save a simple snap of the scene to a given folder. + """ + + filename = prompt_output_path() + + camera = playblast.camera_from_stageview(stage, stageview, "viewerCamera") + + # ensure camera aspect ratio + # Aperture size (24) is based on the size of a full frame SLR camera sensor + # https://en.wikipedia.org/wiki/Image_sensor_format#Common_image_sensor_formats + aspect_ratio: float = width / float(height) + camera.CreateHorizontalApertureAttr(24 * aspect_ratio) + camera.CreateHorizontalApertureOffsetAttr(0) + camera.CreateVerticalApertureAttr(24) + camera.CreateVerticalApertureOffsetAttr(0) + + frame_timecode: Usd.TimeCode = stageview._dataModel.currentFrame + + # cannot be earliest timecode when passing as argument. + if frame_timecode == Usd.TimeCode.EarliestTime(): + frame_timecode = None + + frame = 0 if frame_timecode is None else frame_timecode.GetValue() + + playblast.render_playblast(stage, + filename, + frames=f"{frame}", + width=1920, + camera=camera) + + stage.RemovePrim(camera.GetPath()) + + +class PlayblastDialog(QtWidgets.QDialog, RenderReportable): + def __init__(self, parent: QtCore.QObject, stage: Usd.Stage, stageview: StageView = None): + super(PlayblastDialog,self).__init__(parent=parent) + self.setWindowTitle("USD Playblast") + + + self.setStyleSheet("QToolButton::menu-indicator { " + " width: 0px;" + "} ") + self._parent = parent + self._stage = stage + self._stageview = stageview + self._has_viewer = "Scene Viewer" in parent._panels + + self.total_frames.connect(self._set_total_frames) + self.render_progress.connect(self._set_render_progress) + + width, height, margin = 600, 900, 15 + geometry = QtCore.QRect(margin, margin, + width - margin * 2, height - margin * 2) + + size = QtCore.QSize(width,height) + self.resize(size) + self.setFixedSize(size) + + self._container = QtWidgets.QGroupBox(self) + self._container.setTitle("Playblast settings...") + self._container.setGeometry(geometry) + + self.vlayout = QtWidgets.QVBoxLayout() + self.vlayout.addSpacing(30) # add some spacing from the top + self._container.setLayout(self.vlayout) + + self.formlayout = QtWidgets.QFormLayout() + self.formlayout.setHorizontalSpacing(50) + + # UI pre hook + self.ui_pre_hook(self.vlayout) + + # File name browser + lbl_filedest = QtWidgets.QLabel(self) + lbl_filedest.setText("Path to save render to...") + lbl_filedest.setFixedHeight(30) + self.vlayout.addWidget(lbl_filedest) + + self.txt_filename = QtWidgets.QLineEdit() + self.txt_filename.setPlaceholderText("Path to render...") + self.btn_browse = QtWidgets.QPushButton(icon=get_icon("folder")) + self.btn_browse.setFixedSize(QtCore.QSize(30, 30)) + + self.btn_browse.clicked.connect(self._prompt_renderoutput) + + filename_hlayout = QtWidgets.QHBoxLayout() + filename_hlayout.addWidget(self.txt_filename) + filename_hlayout.addWidget(self.btn_browse) + self.vlayout.addLayout(filename_hlayout) + + self.vlayout.addSpacing(15) + + # Frame range + self.frame_range_callback(self.formlayout) + + separator_1 = QtWidgets.QFrame() + separator_1.setFrameShape(QtWidgets.QFrame.HLine) + self.formlayout.addWidget(separator_1) + + # Resolution + self.spinbox_horresolution = QtWidgets.QSpinBox() + self.spinbox_verresolution = QtWidgets.QSpinBox() + self.spinbox_horresolution.setMaximum(4096) + self.spinbox_horresolution.setMinimum(1) + self.spinbox_verresolution.setMaximum(4096) + self.spinbox_verresolution.setMinimum(1) + self.spinbox_horresolution.setValue(1920) + self.spinbox_verresolution.setValue(1080) + + self.btn_resolution = QtWidgets.QToolButton(icon=get_icon("chevron-down")) + self.btn_resolution.clicked.connect(self.btn_resolution.showMenu) + self.btn_resolution.setFixedSize(QtCore.QSize(30, 30)) + + self.btn_resolution_menu = QtWidgets.QMenu(self) + resolution_presets = {"SD 480p" : (640, 480), + "HD 720p" : (1280, 720), + "HD 1080p" : (1920, 1080), + "UHD 4K" : (3840, 2160), + "1k Square" : (1024, 1024), + "2k Square" : (2048, 2048), + "4k Square" : (4096, 4096) + } + + for label, res_tuple in resolution_presets.items(): + action = self.btn_resolution_menu.addAction(label) + action.triggered.connect(partial(self._update_resolution, res_tuple)) + action.setData(res_tuple) + + self.btn_resolution.setMenu(self.btn_resolution_menu) + + resolution_hlayout = QtWidgets.QHBoxLayout() + resolution_hlayout.addWidget(self.spinbox_horresolution) + resolution_hlayout.addWidget(self.spinbox_verresolution) + resolution_hlayout.addWidget(self.btn_resolution) + self.formlayout.addRow("Resolution", resolution_hlayout) + + # Camera selection + self.cbox_camera = QtWidgets.QComboBox() + self.populate_camera_combobox(self.cbox_camera) + + self.cbox_camera.setCurrentIndex(0) + self.formlayout.addRow("Camera",self.cbox_camera) + + self.spinbox_fit = QtWidgets.QDoubleSpinBox() + self.spinbox_fit.setMinimum(0.01) + self.spinbox_fit.setMaximum(10) + self.spinbox_fit.setValue(1.2) + self.cbox_camera.currentIndexChanged.connect(self._update_fit) + self.lbl_fit = QtWidgets.QLabel() + self.lbl_fit.setText("Fit stage:") + + self.formlayout.addRow(self.lbl_fit,self.spinbox_fit) + + separator_2 = QtWidgets.QFrame() + separator_2.setFrameShape(QtWidgets.QFrame.HLine) + self.formlayout.addWidget(separator_2) + + # Purposes + self.chk_purpose_default = QtWidgets.QCheckBox() + self.chk_purpose_render = QtWidgets.QCheckBox() + self.chk_purpose_proxy = QtWidgets.QCheckBox() + self.chk_purpose_guide = QtWidgets.QCheckBox() + + self.chk_purpose_default.setText("Default") + self.chk_purpose_render.setText("Render") + self.chk_purpose_proxy.setText("Proxy") + self.chk_purpose_guide.setText("Guide") + + self.chk_purpose_default.setChecked(True) + self.chk_purpose_render.setChecked(True) + self.chk_purpose_proxy.setChecked(True) + self.chk_purpose_guide.setChecked(False) + + purpose_vlayout = QtWidgets.QVBoxLayout() + purpose_vlayout.addWidget(self.chk_purpose_default) + purpose_vlayout.addWidget(self.chk_purpose_render) + purpose_vlayout.addWidget(self.chk_purpose_proxy) + purpose_vlayout.addWidget(self.chk_purpose_guide) + + self.formlayout.addRow("Included purposes:",purpose_vlayout) + + # Complexity combobox + self.cbox_complexity = QtWidgets.QComboBox() + self.cbox_complexity.addItems(playblast.get_complexity_levels()) + self.cbox_complexity.setCurrentIndex(2) + self.formlayout.addRow("Complexity / Quality",self.cbox_complexity) + + # Renderer Combobox + self.cbox_renderer = QtWidgets.QComboBox() + self.cbox_renderer.addItems(playblast.iter_renderplugin_names()) + self.cbox_renderer.setCurrentIndex(0) + self.formlayout.addRow("Renderer",self.cbox_renderer) + + self.vlayout.addLayout(self.formlayout) + + # Ui post hook + self.ui_post_hook(self.vlayout) + + self.vlayout.addStretch() + + # Playblast button + + self.btn_playblast = QtWidgets.QPushButton() + self.btn_playblast.setText("Playblast!") + self.vlayout.addWidget(self.btn_playblast) + + self.btn_playblast.clicked.connect(self.playblast_callback) + + # Progress bar + self.progressbar = QtWidgets.QProgressBar(self) + self.progressbar.setFormat("Not started...") + self.vlayout.addWidget(self.progressbar) + + def _update_fit(self): + if "New: Framing Camera" in self.cbox_camera.currentText(): + self.spinbox_fit.setDisabled(False) + self.lbl_fit.setDisabled(False) + else: + self.spinbox_fit.setDisabled(True) + self.lbl_fit.setDisabled(True) + + def _update_resolution(self, res_tuple: tuple[int,int]): + self.spinbox_horresolution.setValue(res_tuple[0]) + self.spinbox_verresolution.setValue(res_tuple[1]) + + def _update_framerange_options(self): + index = self.cbox_framerange_options.currentIndex() + if index == 0: + self.spinbox_frame_start.setDisabled(False) + self.spinbox_frame_end.setDisabled(True) + self.spinbox_frame_stride.setDisabled(True) + elif index == 1: + self.spinbox_frame_start.setDisabled(False) + self.spinbox_frame_end.setDisabled(False) + self.spinbox_frame_stride.setDisabled(False) + elif index == 2: + self.spinbox_frame_start.setDisabled(True) + self.spinbox_frame_end.setDisabled(True) + self.spinbox_frame_stride.setDisabled(True) + + def _prompt_renderoutput(self): + filename = prompt_output_path("Render result to...", + os.path.dirname(self.txt_filename.text())) + if filename: + self.txt_filename.setText(os.path.normpath(filename)) + + def _gather_purposes(self) -> list[str]: + purposes = [] + + if self.chk_purpose_default.isChecked(): + purposes.append("default") + + if self.chk_purpose_render.isChecked(): + purposes.append("render") + + if self.chk_purpose_proxy.isChecked(): + purposes.append("proxy") + + if self.chk_purpose_guide.isChecked(): + purposes.append("guide") + + return purposes + + def _set_total_frames(self, frames: int): + """ + Update progress bar with reported maximum frames + """ + self.progressbar.setFormat(f"Rendering %v / {frames} frames...") + self.progressbar.setMinimum(1) + self.progressbar.setMaximum(frames) + + def _set_render_progress(self, frame: int): + """ + Increment progress bar with reported rendered frames. + """ + self.progressbar.setValue(frame) + + def _construct_frames_argument(self) -> str: + start = self.spinbox_frame_start.value() + end = self.spinbox_frame_end.value() + stride = self.spinbox_frame_stride.value() + + opt_index = self.cbox_framerange_options.currentIndex() + + if opt_index == 0: # Single Frame + return f"{start}" + elif opt_index == 1: # Frame range + return playblast.get_frames_string(start,end,stride) + elif opt_index == 2: # Frame from Viewer + if self._stageview: + return playblast.get_stageview_frame(self._stageview) + + def _get_camera(self) -> tuple[UsdGeom.Camera,bool]: + """ + Returns a camera and whether it should be destroyed afterwards. + -> UsdGeom.Camera, should_destroy() + """ + + box_text = self.cbox_camera.currentText() + data = self.cbox_camera.currentData() + + width = self.spinbox_horresolution.value() + height = self.spinbox_verresolution.value() + + aspect_ratio: float = float(width) / float(height) + + if data is not None: + data = UsdGeom.Camera(data) + v_aperture = data.GetVerticalApertureAttr() + # ensure that camera can render desired aspect ratio. + if not v_aperture.IsValid(): + v_aperture = 24 + else: + v_aperture = v_aperture.Get(0) + + data.CreateHorizontalApertureAttr(v_aperture * aspect_ratio) + data.CreateHorizontalApertureOffsetAttr(0) + data.CreateVerticalApertureAttr(v_aperture) + data.CreateVerticalApertureOffsetAttr(0) + + # Camera is in scene, doesn't need to be deleted. + return data, False + + elif "New: Framing Camera" in box_text: + camera = framing_camera.create_framing_camera_in_stage( + self._stage, + name="Playblast_framingCam", + fit=self.spinbox_fit.value(), + width=width, + height=height + ) + return camera, True + elif "New: Camera from View" in box_text: + camera = playblast.camera_from_stageview(self._stage, self._stageview, "Playblast_viewerCam") + # ensure camera aspect ratio + # Aperture size (24) is based on the size of a full frame SLR camera sensor + # https://en.wikipedia.org/wiki/Image_sensor_format#Common_image_sensor_formats + aspect_ratio: float = width / float(height) + camera.CreateHorizontalApertureAttr(24 * aspect_ratio) + camera.CreateHorizontalApertureOffsetAttr(0) + camera.CreateVerticalApertureAttr(24) + camera.CreateVerticalApertureOffsetAttr(0) + return camera, True + + return None, False + + class _CameraContext: + def __init__(self, parent): + self._camera: UsdGeom.Camera + self._camera, self._delete = parent._get_camera() + self._parent = parent + + def __enter__(self) -> UsdGeom.Camera: + return self._camera + + def __exit__(self, *args): + if self._delete: + self._parent._stage.RemovePrim(self._camera.GetPath()) + + + def playblast_callback(self): + frames = self._construct_frames_argument() + with self._CameraContext(self) as camera: + path = self.txt_filename.text() + + if not path: + return + + width = self.spinbox_horresolution.value() + complexity = self.cbox_complexity.currentText() + render_engine = self.cbox_renderer.currentText() + purposes = self._gather_purposes() + + playblast.render_playblast(stage=self._stage, + outputpath=path, + frames=frames, + width=width, + camera=camera, + complexity=complexity, + renderer=render_engine, + colormode="sRGB", + purposes=purposes, + qt_report_instance=self + ) + + self.progressbar.setFormat("Rendered %v frames!") + + def frame_range_callback(self, formlayout: QtWidgets.QFormLayout): + """ + Override this hook to change frame range widget + """ + self.cbox_framerange_options = QtWidgets.QComboBox() + self.cbox_framerange_options.addItems(("Single frame", "Frame range")) + + if self._has_viewer: + self.cbox_framerange_options.addItem("Frame from view") + + self.cbox_framerange_options.setCurrentIndex(0) + + self.formlayout.addRow("Frame range options",self.cbox_framerange_options) + + self.spinbox_frame_start = QtWidgets.QSpinBox() + self.spinbox_frame_end = QtWidgets.QSpinBox() + self.spinbox_frame_stride = QtWidgets.QDoubleSpinBox() + + self.spinbox_frame_start.setMinimum(-9999) + self.spinbox_frame_start.setMaximum(9999) + self.spinbox_frame_end.setMinimum(-9999) + self.spinbox_frame_end.setMaximum(9999) + + self.spinbox_frame_start.setValue(0) + self.spinbox_frame_end.setValue(100) + self.spinbox_frame_stride.setValue(1) + + self.cbox_framerange_options.currentIndexChanged.connect(self._update_framerange_options) + self._update_framerange_options() + + framerange_hlayout = QtWidgets.QHBoxLayout() + framerange_hlayout.addWidget(self.spinbox_frame_start) + framerange_hlayout.addWidget(self.spinbox_frame_end) + framerange_hlayout.addWidget(self.spinbox_frame_stride) + formlayout.addRow("Frame Start / End / Stride", framerange_hlayout) + + def populate_camera_combobox(self, cbox_camera: QtWidgets.QComboBox): + """ + Override hook to populate camera choices. + """ + + for cam in playblast.iter_stage_cameras(self._stage): + cam: UsdGeom.Camera + cam_name = os.path.basename(cam.GetPath().pathString) + cbox_camera.addItem(f"Cam: {cam_name}", cam) + + cbox_camera.addItem("New: Framing Camera") + if self._has_viewer: + cbox_camera.addItem("New: Camera from View") + + cbox_camera.setCurrentIndex(0) + + def ui_pre_hook(self, vlayout: QtWidgets.QVBoxLayout): + """ + Override hook to insert QtWidgets BEFORE the main playblast interface. + """ + pass + # Example: add some text + # txt = QtWidgets.QLabel() + # txt.setText("I go before the interface!") + # txt.setFixedHeight(30) + # vlayout.addWidget(txt) + + def ui_post_hook(self, vlayout: QtWidgets.QVBoxLayout): + """ + Override hook to insert QtWidgets after the main playblast interface, + but before the playblast button. + """ + pass + # Example: add some text + # txt = QtWidgets.QLabel() + # txt.setText("I go after the interface!") + # txt.setFixedHeight(30) + # vlayout.addWidget(txt) + + +class TurntableDialog(PlayblastDialog): + def __init__(self, parent: QtCore.QObject, + stage: Usd.Stage, + stageview: StageView = None): + self._turntablefile = R"./assets/turntable/turntable_preset.usda" + + super(TurntableDialog,self).__init__(parent,stage,stageview) + self.setWindowTitle("USD Turntable Playblast") + + repopulate_cam = partial(self.populate_camera_combobox,self.cbox_camera) + self.cbox_turntable_type.currentIndexChanged.connect( + repopulate_cam + ) + + # if turntable filename loses focus, attempt to repopulate camera field. + self.txt_turntable_filename.editingFinished.connect(repopulate_cam) + self.btn_playblast.setText("Playblast Turntable!") + + def _prompt_turntablefile(self): + filename = prompt_input_path( + "Get Turntable from...", + os.path.dirname(self._turntablefile) + ) + if filename: + self.txt_turntable_filename.setText(os.path.normpath(filename)) + self.populate_camera_combobox(self.cbox_camera) + + def populate_camera_combobox(self, + cbox_camera: QtWidgets.QComboBox, + index: int = None): + """ + (re)populate camera box when it's needed. + Catches a signal argument in index. + """ + if index is None or not isinstance(index, int): + index = self.cbox_turntable_type.currentIndex() + + if index == 2: + cbox_camera.clear() + cbox_camera.setDisabled(False) + self.btn_playblast.setDisabled(False) + + self._turntablefile = self.txt_turntable_filename.text() + + if not self._turntablefile: + self._turntablefile = R"./assets/turntable/turntable_preset.usda" + + if os.path.isfile(self._turntablefile): + cams = playblast.get_file_cameras(self._turntablefile) + cams_string = (str(c.pathString)\ + .replace("turntable", "turntable_reference") + for c in cams) + cams = [Sdf.Path(c) for c in cams_string] + + if not cams: + # No camera, disable + cbox_camera.addItem("No camera found...") + cbox_camera.setDisabled(True) + self.btn_playblast.setDisabled(True) + else: + for cam in cams: + cam_name = os.path.basename(cam.pathString) + # store path + string in camera combobox + cbox_camera.addItem(f"Cam: {cam_name}",cam) + else: + # No camera, disable + cbox_camera.addItem("Turntable file not valid") + cbox_camera.setDisabled(True) + self.btn_playblast.setDisabled(True) + else: + cbox_camera.clear() + cbox_camera.setDisabled(False) + for cam in playblast.iter_stage_cameras(self._stage): + cam: UsdGeom.Camera + campath = cam.GetPath().pathString + cam_name = os.path.basename(campath) + cbox_camera.addItem(f"Cam: {cam_name}", Sdf.Path(campath)) + + cbox_camera.addItem("New: Framing Camera") + if self._has_viewer: + cbox_camera.addItem("New: Camera from View") + # cbox_camera.setDisabled(True) + + cbox_camera.setCurrentIndex(0) + self.update_textfield_turntablefile(index) + + def update_textfield_turntablefile(self, index: int = 0): + if index == 2: + self.txt_turntable_filename.setDisabled(False) + self.btn_browse_turntable.setDisabled(False) + self.lbl_turntable_file.setDisabled(False) + else: + self.txt_turntable_filename.setDisabled(True) + self.btn_browse_turntable.setDisabled(True) + self.lbl_turntable_file.setDisabled(True) + + def frame_range_callback(self, formlayout: QtWidgets.QFormLayout): + """ + Frame range is a different story for turntables. + It's defined by a starting frame, and a length + """ + + self.spinbox_frame_start = QtWidgets.QSpinBox() + self.spinbox_frame_length = QtWidgets.QSpinBox() + + self.spinbox_frame_start.setMinimum(-9999) + self.spinbox_frame_start.setMaximum(9999) + self.spinbox_frame_length.setMinimum(1) + self.spinbox_frame_length.setMaximum(9999) + + self.spinbox_frame_start.setValue(1) + self.spinbox_frame_length.setValue(100) + + framerange_hlayout = QtWidgets.QHBoxLayout() + framerange_hlayout.addWidget(self.spinbox_frame_start) + framerange_hlayout.addWidget(self.spinbox_frame_length) + + formlayout.addRow("Starting Frame / Length", framerange_hlayout) + + self.spinbox_loops = QtWidgets.QSpinBox() + self.spinbox_loops.setMinimum(1) + self.spinbox_loops.setMaximum(99) + formlayout.addRow("Repetitions", self.spinbox_loops) + + def ui_pre_hook(self, vlayout: QtWidgets.QVBoxLayout): + + pre_form = QtWidgets.QFormLayout() + pre_form.setHorizontalSpacing(150) + + # Turntable type chooser + self.cbox_turntable_type = QtWidgets.QComboBox() + turntable_types = ("Rotate camera", + "Rotate subject", + "Preset from file") + self.cbox_turntable_type.addItems(turntable_types) + pre_form.addRow("Turntable Type", self.cbox_turntable_type) + + # Turntable file chooser + self.lbl_turntable_file = QtWidgets.QLabel(self) + self.lbl_turntable_file.setText("Path to get turntable from...") + self.lbl_turntable_file.setFixedHeight(30) + pre_form.addRow(self.lbl_turntable_file) + + self.txt_turntable_filename = QtWidgets.QLineEdit() + self.txt_turntable_filename.setPlaceholderText("Empty - Use internal preset") + self.btn_browse_turntable = QtWidgets.QPushButton(icon=get_icon("folder")) + self.btn_browse_turntable.setFixedSize(QtCore.QSize(30, 30)) + self.btn_browse_turntable.clicked.connect(self._prompt_turntablefile) + + turntable_filename_hlayout = QtWidgets.QHBoxLayout() + turntable_filename_hlayout.addWidget(self.txt_turntable_filename) + turntable_filename_hlayout.addWidget(self.btn_browse_turntable) + pre_form.addRow(turntable_filename_hlayout) + + vlayout.addLayout(pre_form) + self.vlayout.addSpacing(15) + + def playblast_callback(self): + """ + Turntable playblast! + """ + turn_length = self.spinbox_frame_length.value() + frame_start = self.spinbox_frame_start.value() + repetition = self.spinbox_loops.value() + + frames_string = turntable.get_turntable_frames_string( + turn_length, + frame_start, + repetition + ) + + fit = self.spinbox_fit.value() + width = self.spinbox_horresolution.value() + height = self.spinbox_verresolution.value() + + render_path = self.txt_filename.text() + render_engine = self.cbox_renderer.currentText() + + ttable_type = self.cbox_turntable_type.currentIndex() + if ttable_type == 0: + # Rotate camera around scene + + turntable_xform = turntable\ + .create_turntable_xform( + self._stage, + "/", + "turntabledialog_xform", + turn_length, + frame_start, + repetition) + + path: Sdf.Path = self.cbox_camera.currentData() + render_camera: UsdGeom.Camera = None + cam_name = "turntabledialog_cam" + # get camera state, to create a valid camera + if path: + # take new root into account, split off the old scene root. + # TODO: support animated cameras from scene? + # grab camera state + camera_stage = self._stage.GetPrimAtPath(path) + camera_geom = UsdGeom.Camera(camera_stage) + camera_state = camera_geom.GetCamera(frame_start) + render_camera = UsdGeom.Camera.Define( + self._stage, + f"/turntabledialog_xform/{cam_name}") + else: + if "New: Framing Camera" in self.cbox_camera.currentText(): + render_camera = framing_camera\ + .create_framing_camera_in_stage(self._stage, + "/turntabledialog_xform", + cam_name, + fit, + width, + height + ) + + elif "New: Camera from View" in self.cbox_camera.currentText(): + cam = playblast.camera_from_stageview( + self._stage, + self._stageview, + f"viewcam") + camera_state = cam.GetCamera(frame_start) + self._stage.RemovePrim(cam.GetPath()) + render_camera = UsdGeom.Camera.Define( + self._stage, + f"/turntabledialog_xform/{cam_name}") + render_camera.SetFromCamera(camera_state) + + render_camera = framing_camera.camera_conform_sensor_to_aspect( + render_camera, + width, + height) + with ExitStack() as stack: + stack.enter_context(defer_primpath_deletion( + self._stage, render_camera.GetPath())) + stack.enter_context(defer_primpath_deletion( + self._stage, turntable_xform.GetPath())) + + playblast.render_playblast(self._stage, + render_path, + frames=frames_string, + width=width, + camera=render_camera, + renderer=render_engine, + qt_report_instance=self) + + self.progressbar.setFormat("Rendered %v frames!") + elif ttable_type == 1: + # Create temporary stage where the entire stage rotates in front + # of a camera + + # make temporary folder to cache current subject session to. + if not os.path.isdir("./temp"): + os.mkdir("./temp") + + @using_tempfolder + def routine_rotate_subject(): + tempfolder = get_tempfolder() + + # collect info about subject + subject_upaxis = framing_camera.get_stage_up(self._stage) + + # export subject + subject_filename = R"subject.usda" + subject_filename = os.path.join(tempfolder,subject_filename) + subject_filename = os.path.abspath(subject_filename) + + self._stage.Export(subject_filename) + + assemble_stage = Usd.Stage.CreateInMemory() + UsdGeom.SetStageUpAxis(assemble_stage,subject_upaxis) + + bounds = framing_camera.get_stage_boundingbox(self._stage) + + # Put stage in turntable primitive. + turntable_xform = turntable\ + .create_turntable_xform( + assemble_stage, + "/", + "turntabledialog_xform", + turn_length, + frame_start, + repetition, + bounds) + # reference root in stage + root_override= assemble_stage\ + .OverridePrim("/turntabledialog_xform/root") + root_override.GetReferences().AddReference(subject_filename) + + path: Sdf.Path = self.cbox_camera.currentData() + camera_state = None + + # get camera states, to create a valid camera in in-memory stage. + with ExitStack() as stack: + if path: + # take new root into account, split off the old scene root. + # TODO: support animated cameras from scene? + # grab camera state + camera_stage = self._stage.GetPrimAtPath(path) + camera_geom = UsdGeom.Camera(camera_stage) + camera_state = camera_geom.GetCamera(frame_start) + else: + if "New: Framing Camera" in self.cbox_camera.currentText(): + cam = framing_camera\ + .create_framing_camera_in_stage(self._stage, + "/", + "framingcam", + fit, + width, + height + ) + camera_state = cam.GetCamera(frame_start) + # immediatly remove here, because we can. + self._stage.RemovePrim(cam.GetPath()) + elif "New: Camera from View" in self.cbox_camera.currentText(): + cam = playblast.camera_from_stageview(self._stage, + self._stageview, + "viewcam") + camera_state = cam.GetCamera(frame_start) + # immediatly remove here, because we can. + self._stage.RemovePrim(cam.GetPath()) + + render_camera: UsdGeom.Camera = None + render_camera_name = "turntabledialog_cam" + + # use camera state to generate proper camera in assemble_stage + render_camera = UsdGeom.Camera\ + .Define(assemble_stage,f"/{render_camera_name}") + + # Defer deletion of render camera defined from data + stack.enter_context( + defer_primpath_deletion(self._stage, + render_camera.GetPath())) + + render_camera.SetFromCamera(camera_state) + + render_camera = framing_camera.camera_conform_sensor_to_aspect( + render_camera, + width, + height + ) + + # We should now have an assembled stage. + + realstage_filename = R"turntable_assembly.usd" + realstage_filename = os.path.join(tempfolder, realstage_filename) + realstage_filename = os.path.abspath(realstage_filename) + + assemble_stage.Export(realstage_filename) + + del assemble_stage + + stack.enter_context(defer_file_deletion(subject_filename)) + stack.enter_context(defer_file_deletion(realstage_filename)) + + real_stage = stack.enter_context(TempStageOpen(realstage_filename)) + + real_render_camera = real_stage.GetPrimAtPath(f"/{render_camera_name}") + real_render_camera = UsdGeom.Camera(real_render_camera) + + playblast.render_playblast(real_stage, + render_path, + frames=frames_string, + width=width, + camera=real_render_camera, + renderer=render_engine, + qt_report_instance=self) + + # Can't go without this, sorry. + # All references to the opened stage have to be deleted + # for the file to be free. + del real_stage + + routine_rotate_subject() #IIFE ;) + + self.progressbar.setFormat("Rendered %v frames!") + + elif ttable_type == 2: + camera_path = self.cbox_camera.currentData() + turntable.turntable_from_file(self._stage, + self._turntablefile, + export_path=render_path, + renderer=render_engine, + length=turn_length, + frame_start=frame_start, + repeats=repetition, + width=width, + height=height, + camera_path=camera_path, + qt_report_instance=self + ) + self.progressbar.setFormat("Rendered %v frames!") diff --git a/usd_qtpy/render_util/framing_camera.py b/usd_qtpy/render_util/framing_camera.py new file mode 100644 index 0000000..fcbdf0e --- /dev/null +++ b/usd_qtpy/render_util/framing_camera.py @@ -0,0 +1,283 @@ +# Generates Stage framing camera. +# heavy inspiration taken from: +# https://github.com/beersandrew/assets/tree/1df93f4da686e9040093027df1e42ff9ea694866/scripts/thumbnail-generator + +import math +from typing import Union + +from pxr import Usd, UsdGeom, Sdf, Gf + + +def get_stage_up(stage: Usd.Stage) -> str: + """Return Usd.Stage up axis""" + return UsdGeom.GetStageUpAxis(stage) + + +def create_framing_camera_in_stage(stage: Usd.Stage, + root: Union[Sdf.Path, str] = Sdf.Path("/"), + name: str = "framingCam", + fit: float = 1, + width: int = 16, + height: int = 9) -> UsdGeom.Camera: + """ + Adds a camera that frames the whole stage. + Can be specified to have a different aspect ratio, this will affect the sensor size internally. + """ + if isinstance(root, str): + root = Sdf.Path(root) + + # create camera + camera_path = root.AppendChild(name) + camera = create_perspective_camera_in_stage(stage, camera_path, width, height) + + # Do prerequisite math so that functions don't have to run these same operations. + bounds = get_stage_boundingbox(stage) + + is_z_up = (get_stage_up(stage) == "Z") + + distance_to_stage = calculate_distance_to_fit_bounds(camera, bounds, is_z_up, fit) + + # setup attributes in camera + set_camera_clippingplanes_from_bounds(camera, bounds, is_z_up, distance_to_stage) + + translation = calculate_camera_position(bounds, is_z_up, distance_to_stage) + set_first_translation(camera, translation) + + if is_z_up: + _orient_to_z_up(camera) + + return camera + + +def create_perspective_camera_in_stage(stage: Usd.Stage, + path: Sdf.Path, + width: int = 16, + height: int = 9) -> UsdGeom.Camera: + """ + Creates a camera in the scene with a certain sensor size. + Defaults to 16:9 aspect ratio. + """ + # Calculate aspect ratio. Cast divisor to float to prevent integer division + aspect_ratio: float = width / float(height) + + camera = UsdGeom.Camera.Define(stage, path) + + # Focus at infinity + camera.CreateFocusDistanceAttr(168.60936) + camera.CreateFStopAttr(0) + + # Aperture size (24) is based on the size of a full frame SLR camera sensor + # https://en.wikipedia.org/wiki/Image_sensor_format#Common_image_sensor_formats + camera.CreateHorizontalApertureAttr(24 * aspect_ratio) + camera.CreateHorizontalApertureOffsetAttr(0) + camera.CreateVerticalApertureAttr(24) + camera.CreateVerticalApertureOffsetAttr(0) + + camera.CreateProjectionAttr("perspective") + + return camera + + +def camera_conform_sensor_to_aspect(camera: UsdGeom.Camera, + width: int = 16, + height: int = 9) -> UsdGeom.Camera: + """ + Conforms an existing camera's sensor size to render with desired dimensions + """ + + aspect_ratio: float = width / float(height) + + # Focus at infinity + camera.CreateFocusDistanceAttr(168.60936) + camera.CreateFStopAttr(0) + + # Aperture size (24) is based on the size of a full frame SLR camera sensor + # https://en.wikipedia.org/wiki/Image_sensor_format#Common_image_sensor_formats + camera.CreateHorizontalApertureAttr(24 * aspect_ratio) + camera.CreateHorizontalApertureOffsetAttr(0) + camera.CreateVerticalApertureAttr(24) + camera.CreateVerticalApertureOffsetAttr(0) + + return camera + + +def _orient_to_z_up(xformable: UsdGeom.Xformable): + """Rotate around X-axis by 90 degrees to orient for Z-up axis.""" + xformable.AddRotateXOp(UsdGeom.XformOp.PrecisionDouble).Set(90) + + +def set_first_translation(xformable: UsdGeom.Xformable, + translation: Gf.Vec3d) -> UsdGeom.XformOp: + """Apply translation to first found translation operation in given Camera. + + If no translation op is found then one will be added. + """ + # check for existing translation operation, if not found, add one to stack. + for op in xformable.GetOrderedXformOps(): + op: UsdGeom.XformOp + if op.GetOpType() == UsdGeom.XformOp.TypeTranslate: + translate_op = op + break + else: + translate_op = xformable.AddTranslateOp() + + translate_op.Set(translation) + return translate_op + + +def set_camera_clippingplanes_from_bounds(camera: UsdGeom.Camera, + bounds: Gf.Range3d, + is_z_up: bool = None, + distance: float = None): + """ + Set camera clipping plane attributes to fit the stage bounds. + """ + bounds_min = bounds.GetMin() + bounds_max = bounds.GetMax() + vertical_axis_index = 2 if is_z_up else 1 + + # expand clipping planes out + near_clip = max((distance + bounds_min[vertical_axis_index]) * 0.5, + 0.0000001) + far_clip = (distance + bounds_max[vertical_axis_index]) * 2 + + clipping_planes = Gf.Vec2f(near_clip, far_clip) + camera.GetClippingRangeAttr().Set(clipping_planes) + + +def get_stage_boundingbox(stage: Usd.Stage, + time: Usd.TimeCode = Usd.TimeCode.EarliestTime(), + purpose_tokens: list[str] = None) -> Gf.Range3d: + """ + Caclulate a stage's bounding box, with optional time and purposes. + The default for time is the earliest registered TimeCode in the stage's animation. + The default for purpose tokens is ["default"], + valid values are: default, proxy, render, guide. + """ + if not purpose_tokens: + purpose_tokens = ["default"] + + bbox_cache = UsdGeom.BBoxCache(time, purpose_tokens) + stage_root = stage.GetPseudoRoot() + return bbox_cache.ComputeWorldBound(stage_root).GetBox() + + +def calculate_camera_position(bounds: Gf.Range3d, + is_z_up: bool, + distance: float) -> Gf.Vec3d: + """ + Calculate the world position for the camera based off of the size of the stage and the camera attributes. + Bounds and distance can be calculated beforehand so this function does less work. + + Suppose a scene with a cone, + ```txt + .. + ../ | /\\ + O O / | / \\ + [cam]<| ------| /I am\\ + \.. | / cone \\ + \..|/ fear me\\ + ^ + |- The focus plane will be here, at the closest depth of the bounds + of the scene the camera is pointed at. + ``` + The center of the camera will be positioned at the center of the vertical and horizontal axis, + (Y and X respectively, assuming y up) + and positioned back along the with the calculated frustrum-filling distance along the depth axis, + (Z, assuming y up). + """ + bounds_min = bounds.GetMin() + bounds_max = bounds.GetMax() + centroid = bounds.GetMidpoint() + + if is_z_up: + camera_position = Gf.Vec3d(centroid[0], + bounds_min[1] - distance, + centroid[2]) + else: + camera_position = Gf.Vec3d(centroid[0], + centroid[1], + bounds_max[2] + distance) + + return camera_position + + +def calculate_distance_to_fit_bounds(camera: UsdGeom.Camera, + bounds: Gf.Range3d, + is_z_up: bool = None, + fit: float = 1) -> float: + """ + Calculates a distance from the centroid of the stage that would allow + a camera to frame it perfectly. + + Returns distance in stage units. + """ + + focal_length = camera.GetFocalLengthAttr().Get() + hor_aperture = camera.GetHorizontalApertureAttr().Get() + ver_aperture = camera.GetVerticalApertureAttr().Get() + + vertical_axis_index = 2 if is_z_up else 1 + + # get size of bounds + bounds_max = bounds.GetMax() + bounds_min = bounds.GetMin() + d_hor = bounds_max[0] - bounds_min[0] + d_ver = bounds_max[vertical_axis_index] - bounds_min[vertical_axis_index] + + fov_hor = calculate_field_of_view(focal_length, hor_aperture) + fov_ver = calculate_field_of_view(focal_length, ver_aperture) + + # calculate capture size. the sensor size was given in mm (24 mm sensor) + # so we need to pass in cm units from the scene as mm units for correct calculation. + capturesize_hor = calculate_perspective_distance(d_hor * 10, fov_hor, fit) + capturesize_ver = calculate_perspective_distance(d_ver * 10, fov_ver, fit) + + # return units back to cm on return + return max(capturesize_hor, capturesize_ver) / 10 + + +def calculate_field_of_view(focal_length, sensor_size) -> float: + """ + Calculates field of view for 1 measurement of the sensor size (width or height) + Returns field of view in radians. + + With H being the full lens height, we need to divide H by 2 + ``` + H / 2 + AFOV = 2 * atan( _______ ) + f + ``` + multiply by 2 because we're only getting the angle towards 1 half of the + lens from the center, getting the apex angle of an isosceles triangle. + + This expression is rewritten as `2 * atan(h * (2 * f))`, + this is mathematically the same. + + More details, see math: + https://sdk-forum.dji.net/hc/en-us/articles/11317874071065-How-to-calculate-the-FoV-of-the-camera-lens- + + """ + + return 2 * math.atan(sensor_size / (2 * focal_length)) + + +def calculate_perspective_distance(subject_size: float, + field_of_view: float, + fit: float = 1) -> float: + """ + Calculate appropriate distance towards the subject, so it can fill the view. + Essentially, the inverse of calculate_field_of_view. + + We're treating the subject_size as if it was the size of a lens here, + and calculating a focal length that would match it. + + Keep in mind that we're drawing a right triangle towards the center of the subject, + that is why we are dividing the size in half. + + The field of view is also divided in half, because the whole FOV represents the apex + angle of the isosceles traingle. + """ + + subject_size *= fit + return (subject_size / 2) / math.tan(field_of_view / 2) \ No newline at end of file diff --git a/usd_qtpy/render_util/playblast.py b/usd_qtpy/render_util/playblast.py new file mode 100644 index 0000000..a27120d --- /dev/null +++ b/usd_qtpy/render_util/playblast.py @@ -0,0 +1,316 @@ +# Playblast framework + +import logging +import sys +from typing import Union, Optional +from collections.abc import Generator +import os + +from qtpy import QtCore +from pxr import Tf, Sdf, Usd, UsdGeom, UsdAppUtils +from pxr.Usdviewq.stageView import StageView + +from .base import RenderReportable, TempStageOpen + + +def _setup_opengl_widget(width: int, height: int, samples: int = 4): + """ + Utility function to produce a Qt openGL widget capable of catching + the output of a render + + Returns: + QtOpenGL.QGLWidget: A Qt QGLWidget. + + """ + + from qtpy import QtOpenGL + + # format object contains information about the Qt OpenGL buffer. + QGLformat = QtOpenGL.QGLFormat() + QGLformat.setSampleBuffers(True) # Enable multisample buffer + QGLformat.setSamples(samples) # default samples is 4 / px + + GLWidget = QtOpenGL.QGLWidget(QGLformat) + GLWidget.setFixedSize(QtCore.QSize(width, height)) + + GLWidget.makeCurrent() # bind widget buffer as target for OpenGL operations. + + return GLWidget + + +def iter_stage_cameras(stage: Usd.Stage, + traverse_all: bool = True) -> Generator[UsdGeom.Camera]: + """ + Return a generator of all camera primitives. + TraverseAll is on by default. This means that inactive cameras will also be shown. + """ + # Ref on differences between traversal functions: + # https://openusd.org/dev/api/class_usd_stage.html#adba675b55f41cc1b305bed414fc4f178 + + if traverse_all: + gen = stage.TraverseAll() + else: + gen = stage.Traverse() + + for prim in gen: + if prim.IsA(UsdGeom.Camera): + yield prim + + +def get_file_cameras(path: str) -> list[Sdf.Path]: + """ + Get USD cameras from USD file + Returns a list of paths + """ + # cast to list, because the virtual loaded scene goes out of scope. + with TempStageOpen(path) as stage: + cameras = [c.GetPath() for c in iter_stage_cameras(stage)] + return cameras + + +def camera_from_stageview(stage: Usd.Stage, + stageview: StageView, + name: str = "playblastCam") -> UsdGeom.Camera: + """Create Stage View's current free camera as a regular UsdGeom.Camera. + + Basically calls stage view's `ExportFreeCameraToStage` method. + + The `pxr.UsdViewq.ExportFreeCameraToStage` will export the camera from + the view. A FreeCamera (`pxr.Gf.Camera`), which is purely OpenGL. + """ + stageview.ExportFreeCameraToStage(stage, name) + return UsdGeom.Camera.Get(stage, Sdf.Path(f"/{name}")) + +def get_stageview_frame(stageview: StageView): + time: Usd.TimeCode = stageview._dataModel.currentFrame + return time.GetValue() + +# Source: UsdAppUtils.colorArgs.py +def get_color_args() -> set[str]: + return {"disabled", "sRGB", "openColorIO"} + + +def get_complexity_levels() -> Generator[str]: + """ + Returns a generator that iterates through all registered complexity presets in UsdAppUtils.complexityArgs + """ + from pxr.UsdAppUtils.complexityArgs import RefinementComplexities + return (item.name for item in RefinementComplexities.ordered()) + + +def iter_renderplugin_names() -> Generator[str]: + """ + Returns a generator that will iterate through all names of Render Engine Plugin / Hydra Delegates + """ + from pxr.UsdImagingGL import Engine + return ( + Engine.GetRendererDisplayName(pluginId) + for pluginId in Engine.GetRendererPlugins() + ) + + +def get_renderplugin_by_display_name(render_display_name: str) -> Optional[str]: + """Return renderer plugin from the plugin's nice display name""" + from pxr.UsdImagingGL import Engine + for plug in Engine.GetRendererPlugins(): + if render_display_name == Engine.GetRendererDisplayName(plug): + return plug + return None + + +def get_frames_string(start_time: int, + end_time: int = None, + frame_stride: float = None) -> str: + """ + Takes a set of numbers and structures it so that it can be passed as frame string argument to e.g. render_playblast + Given only a start time, it'll render a frame at that frame. + Given a start and end time, it'll render a range from start to end, including end. (0-100 = 101 frames) + Given a start, end, and stride argument, it'll render a range with a different frame interval. + (rendering every other frame can be done by setting this to 2.) + Output for 1, 2 and 3 arguments respectively: + 'start_time', 'start_time:end_time', 'start_time:end_timexframe_stride' + as defined by the USD standard. + """ + # Keep adhering to USD standard as internally defined. + from pxr.UsdUtils import TimeCodeRange + range_token = TimeCodeRange.Tokens.RangeSeparator # ":" + stride_token = TimeCodeRange.Tokens.StrideSeparator # "x" + + collect = f"{start_time}" + + if end_time is not None: + collect += f"{range_token}{end_time}" + if frame_stride is not None: + collect += f"{stride_token}{frame_stride}" + + return collect + + +def tuples_to_frames_string( + time_tuples: list[Union[tuple[int], + tuple[int, int], + tuple[int, int, float]]]) -> str: + """ + Convert an iterable (e.g. list/generator) of tuples containing structured frame data: + tuple(start_time, end_time, frame_stride), same as the arguments to get_frames_string, + to a single string that can be parsed as a frames_string argument for multiple frames. + example input: (1,) , (1, 50, 0.5), (8, 10) + example output: '1,1:50x0.5,8:10' + (according to standards defined for UsdAppUtils.FrameRecorder) + """ + # keep adhering to USD standard as internally defined. + from pxr.UsdAppUtils.framesArgs import FrameSpecIterator + separator_token = FrameSpecIterator.FRAMESPEC_SEPARATOR # "," + + def tuple_gen(tuple_iterable): + for val in tuple_iterable: + if len(val) <= 3: + yield get_frames_string(*val) + + return separator_token.join(tuple_gen(time_tuples)) + + +def render_playblast(stage: Usd.Stage, + outputpath: str, + frames: str, + width: int, + camera: UsdGeom.Camera = None, + complexity: Union[str, int] = "High", + renderer: str = None, + colormode: str = "sRGB", + purposes: list[str] = None, + qt_report_instance: RenderReportable = None + ) -> list[str]: + """ + Render one or multiple frames from a usd stage's camera. + + Arguments: + stage: The stage to process. + outputpath (str): Output filepath to write to. + frames (str): The frames to render as a string. + width (int): The resolution width to output. + The height will be based on camera properties. + camera (UsdGeom.Camera): The camera to render from. + complexity (Union[str, int]): Complexity to render, defaults to "High" + renderer (str): The renderer to render with. Defaults to the current + platform's default renderer, GL or Metal (osx) + colormode (str): The color management mode to render with. + Defaults to "sRGB". See `get_color_args` for available options. + purposes (list[str]): List of purposes to render. + Valid arguments in list are: 'default', 'render', 'proxy', 'guide' + qt_report_instance: a Qt object to report progress back to, through + render_progress -> QtCore.Signal(int), + total_frames -> QtCore.Signal(int), + which are implemented in mixin class + render_util.dialog.RenderReportable. + + Returns: + list[str]: The rendered output files. + + """ + from pxr.UsdAppUtils.framesArgs import \ + FrameSpecIterator, ConvertFramePlaceholderToFloatSpec + from pxr.UsdAppUtils.complexityArgs import RefinementComplexities + from pxr import UsdUtils + + # check existence of directory. + directory = os.path.dirname(outputpath) + if not os.path.exists(directory): + raise FileNotFoundError( + f"Directory '{directory}' not found, directory must exist " + "before rendering to it." + ) + + # Rectify pathname for use in .format with path.format(frame = timeCode.getValue()) + if not (outputpath := ConvertFramePlaceholderToFloatSpec(outputpath)): + raise ValueError("Invalid/Empty filepath for rendering") + + # Ensure right complexity object is picked. + # The internal _RefinementComplexity.value is used to set rendering quality + if isinstance(complexity, str): + # ensure key correctness + complexity = complexity.lower() # set all to lowercase + complexity = complexity.title() # Uppercase Each Word (In Case Of "Very High") + if complexity not in get_complexity_levels(): + raise ValueError(f"Value: {complexity} entered for complexity is not valid") + + complex_level = RefinementComplexities.fromName(complexity) + elif isinstance(complexity, int): + complexity = min(max(complexity, 0), 3) # clamp to range of 0-3, 4 elements + complex_level = RefinementComplexities.ordered()[complexity] + else: + raise TypeError("Complexity must be either `str` or `int`") + + complex_level: float = complex_level.value + + # deduce default renderer based on platform, if render argument is not specified. + if renderer is None: + if sys.platform == "nt" or sys.platform == "win32": + renderer = "GL" + elif sys.platform == "darwin": + renderer = "Metal" + else: + renderer = "GL" + + # validate render engine + renderer_plugin = get_renderplugin_by_display_name(renderer) + if not renderer_plugin: + raise ValueError(f"Render plugin argument invalid: {renderer}") + + # No Camera: Assume scene wide camera (same behavior as usdrecord) + if not camera: + # Same procedure as default for pxr.UsdAppUtils.cameraArgs.py + print("No cam specified, using PrimaryCamera") + path = Sdf.Path(UsdUtils.GetPrimaryCameraName()) + camera = UsdAppUtils.GetCameraAtPath(stage, path) + + if colormode not in get_color_args(): + raise ValueError("Color correction mode specifier is invalid.") + + # Set up OpenGL FBO to write to within Widget, actual size doesn't matter + # Widgets needs to be stored in a variable to avoid garbage collecting + ogl_widget = _setup_opengl_widget(width, width) # noqa + + if purposes is None: + purposes = ["default","render","proxy"] + + # Create FrameRecorder + frame_recorder = UsdAppUtils.FrameRecorder() + frame_recorder.SetRendererPlugin(renderer_plugin) + frame_recorder.SetImageWidth(width) # Only width is needed, height will be computed from camera properties. + frame_recorder.SetComplexity(complex_level) + frame_recorder.SetColorCorrectionMode(colormode) + frame_recorder.SetIncludedPurposes(purposes) # set to all purposes for now. + + # Use Usds own frame specification parser + # The following are examples of valid FrameSpecs: + # 123 - 101:105 - 105:101 - 101:109x2 - 101:110x2 - 101:104x0.5 + frame_iterator = FrameSpecIterator(frames) + + if not frame_iterator or not frames: + frame_iterator = [Usd.TimeCode.EarliestTime()] + + if qt_report_instance: + total_frames = len([f for f in frame_iterator]) + qt_report_instance.total_frames.emit(total_frames) + + output_files = [] + for frame_nr, time_code in enumerate(frame_iterator): + current_frame = outputpath.format(frame=time_code.GetValue()) + + if qt_report_instance: + qt_report_instance.render_progress.emit(frame_nr + 1) + + try: + frame_recorder.Record(stage, camera, time_code, current_frame) + except Tf.ErrorException as e: + logging.error("Recording aborted due to the following " + "failure at time code %s: %s", time_code, e) + break + logging.debug("Rendered frame: %s", current_frame) + output_files.append(current_frame) + + # Set reference to None so that it can be collected before Qt context. + frame_recorder = None + + return output_files diff --git a/usd_qtpy/render_util/turntable.py b/usd_qtpy/render_util/turntable.py new file mode 100644 index 0000000..9cb67e9 --- /dev/null +++ b/usd_qtpy/render_util/turntable.py @@ -0,0 +1,335 @@ +# Turn table utilities. + +from typing import Union +import os +from contextlib import ExitStack + +from pxr import Usd, UsdGeom, Sdf, Gf + +from . import framing_camera, playblast +from .base import (RenderReportable, + TempStageOpen, + defer_file_deletion, + get_tempfolder, + using_tempfolder) + + +def create_turntable_xform(stage: Usd.Stage, + path: Union[Sdf.Path, str], + name: str = "turntableXform", + length: int = 100, + frame_start: int = 0, + repeats: int = 1, + bounds: Gf.Range3d = None) -> UsdGeom.Xform: + """ + Creates a turntable Xform that contains animation spinning around the up axis, in the center floor of the stage. + We repeat the entire duration when repeats are given as an arguement. + A length of 100 with 3 repeats will result in a 300 frame long sequence + """ + from pxr.UsdGeom import XformOp + + if isinstance(path, str): + path = Sdf.Path(path) + + path = path.AppendPath(name) + + is_z_up = framing_camera.get_stage_up(stage) == "Z" + + if bounds is None: + bounds = framing_camera.get_stage_boundingbox(stage) + centroid = bounds.GetMidpoint() + + xform = UsdGeom.Xform.Define(stage, path) + + if is_z_up: + translate = Gf.Vec3d(centroid[0], centroid[1], 0) # Z axis = floor normal + else: + translate = Gf.Vec3d(centroid[0], 0, centroid[2]) # Y axis = floor normal + + # Move to centroid of bounds, rotate, move back to origin + xform.AddTranslateOp(XformOp.PrecisionDouble, "rotPivot").Set(translate) + add_turntable_spin_op(xform, length, frame_start, repeats, is_z_up) + xform.AddTranslateOp(XformOp.PrecisionDouble, "rotPivot", isInverseOp=True) + + return xform + + +def create_turntable_camera(stage: Usd.Stage, + root: Union[Sdf.Path, str] = Sdf.Path("/"), + name: str = "turntableCam", + fit: float = 1.1, + width: int = 16, + height: int = 9, + length: int = 100, + frame_start: int = 0) -> UsdGeom.Camera: + """ + Creates a complete setup with a stage framing perspective camera, within an animated, rotating Xform. + """ + if isinstance(root, str): + root = Sdf.Path(root) + + xform = create_turntable_xform( + stage, root, length=length, frame_start=frame_start + ) + xform_path = xform.GetPath() + + cam = framing_camera.create_framing_camera_in_stage( + stage, xform_path, name, fit, width, height) + + return cam + + +def add_turntable_spin_op(xformable: UsdGeom.Xformable, + length: int = 100, + frame_start: int = 0, + repeats: int = 1, + is_z_up: bool = False) -> UsdGeom.XformOp: + """Add Rotate XformOp with 360 degrees turntable rotation keys to prim""" + from pxr.UsdGeom import XformOp + # TODO: Maybe check for existing operations before blatantly adding one. + if is_z_up: + spin_op = xformable.AddRotateZOp(XformOp.PrecisionDouble) + else: + spin_op = xformable.AddRotateYOp(XformOp.PrecisionDouble) + + spin_op.Set(time=frame_start, value=0) + + # Avoid having the last frame the same as the first frame so the cycle + # works out nicely over the full length. As such, we remove one step + frame_end = frame_start + (length * repeats) - 1 + step_per_frame = 360 / length + spin_op.Set(time=frame_end, value=(repeats * 360) - step_per_frame) + + return spin_op + + +def get_turntable_frames_string(length: int = 100, + frame_start: int = 0, + repeats: int = 1) -> str: + """ + Get a usable string argument for frames from turntable time params. + """ + frame_end = frame_start + (length * repeats) - 1 + return playblast.get_frames_string(frame_start,frame_end,1) + + +@using_tempfolder +def turntable_from_file(stage: Usd.Stage, + turntable_filename: str = R"./assets/turntable/turntable_preset.usda", + export_path: str = R"./temp/render", + renderer: str = "GL", + length: int = 100, + frame_start: int = 1, + repeats: int = 1, + width: int = 16, + height: int = 9, + camera_path : Union[str, Sdf.Path] = None, + qt_report_instance: RenderReportable = None): + """ + Generates a turntable from a preset USD file, not unlike Prism. + + The turntable must have the following structure: + - /turntable <- default primitive Xform + - /turntable/parent <- Xform that rotates + - a camera somewhere under /turntable/ + + Optional: + - /turntable/bounds/bound_box <- a geometry primitive + that scales input to fit itself. + """ + + # TODO: Infer frame range from turntable stage. + + # collect info about subject + subject_zup = framing_camera.get_stage_up(stage) == "Z" + + # get tempfolder + tempfolder = get_tempfolder() + + # export subject + # turntable_filename = R"./assets/turntable_preset.usd" + subject_filename = R"subject.usda" + subject_filename = os.path.join(tempfolder,subject_filename) + subject_filename = os.path.abspath(subject_filename) + + + stage.Export(subject_filename) + + # create scene in memory + ttable_stage = Usd.Stage.CreateInMemory() + + turntable_ref = ttable_stage.OverridePrim("/turntable_reference") + turntable_ref.GetReferences().AddReference(turntable_filename) + + # conform turntable to Y up + turntable_zup = file_is_zup(turntable_filename) + + if turntable_zup: + turntable_ref_xformable = UsdGeom.Xformable(turntable_ref) + turntable_ref_xformable.AddRotateXOp().Set(-90) + + # check if required prims are actually there + turntable_parent_prim = ttable_stage.GetPrimAtPath("/turntable_reference/parent") + + turntable_camera = next(playblast.iter_stage_cameras(ttable_stage), None) + + if camera_path is not None: + if isinstance(camera_path, Sdf.Path): + camera_path = camera_path.pathString + + # Reroute root (say that 10 times) + camera_path.replace("turntable","turntable_reference") + camera_path = Sdf.Path(camera_path) + + camera_prim = ttable_stage.GetPrimAtPath(camera_path) + if camera_prim.IsValid(): + turntable_camera = UsdGeom.Camera(camera_prim) + else: + raise RuntimeError(f"Turntable Camera at " + f"{camera_path.pathString} is missing.") + + + # Validate + missing = [] + if not turntable_parent_prim.IsValid(): + missing.append("Missing: /turntable/parent") + if turntable_camera is None: + missing.append("Missing: Usd Camera") + if missing: + raise RuntimeError( + "Turntable file doesn't have all necessary components." + "\n" + "\n".join(missing) + ) + + # Create a reference within the parent of the new turntable stage + # References do need xformables created. + ref_adress ="/turntable_reference/parent/subject_reference" + subject_ref = ttable_stage.OverridePrim(ref_adress) + subject_ref.GetReferences().AddReference(subject_filename) + subject_prim = ttable_stage.GetPrimAtPath("/turntable_reference/parent") + + subject_ref_xformable = UsdGeom.Xformable(subject_ref) + + if subject_zup: + subject_ref_xformable.AddRotateXOp().Set(-90) + + # get bbox of subject and center stage + timecode = 0 + bbox_cache = UsdGeom.BBoxCache(timecode, ["default"]) + subject_nofit_bbox = bbox_cache.ComputeWorldBound(subject_prim).GetBox() + + subject_nofit_size = subject_nofit_bbox.GetSize() + + # Get goal geometry boundingbox if it exists, and fit primitive to it + + bbox_prim = ttable_stage.GetPrimAtPath("/turntable_reference/bounds") + + if bbox_prim.IsValid(): + goal_bbox = bbox_cache.ComputeWorldBound(bbox_prim).GetBox() + goal_size = goal_bbox.GetSize() + min_sizediff = goal_size[0] / subject_nofit_size[0] + for index in range(1, 3): + min_sizediff = min(goal_size[index] / subject_nofit_size[index], + min_sizediff) + + # SCALE + subject_ref_xformable.AddScaleOp(UsdGeom.XformOp.PrecisionDouble)\ + .Set(Gf.Vec3d(min_sizediff)) + else: + min_sizediff = 1 + + subject_prim = ttable_stage.GetPrimAtPath("/turntable_reference/parent") + + # clear bboxcache + bbox_cache.Clear() + + # get bbox of subject and center stage + subject_bbox = bbox_cache.ComputeWorldBound(subject_prim).GetBox() + subject_bounds_min = subject_bbox.GetMin() + subject_centroid = subject_bbox.GetMidpoint() + + # center geometry. + if subject_zup: + subject_center_translate = Gf.Vec3d( + -subject_centroid[0] / min_sizediff, + subject_centroid[2] / min_sizediff, + -subject_bounds_min[1] / min_sizediff + ) + else: + subject_center_translate = Gf.Vec3d( + -subject_centroid[0] / min_sizediff, + -subject_bounds_min[1] / min_sizediff, + -subject_centroid[2] / min_sizediff + ) + + subject_ref_xformable.AddTranslateOp( + UsdGeom.XformOp.PrecisionDouble,"center_centroid")\ + .Set(subject_center_translate) + + # turn off the lights if GL + if renderer == "GL": + lights_prim = ttable_stage.GetPrimAtPath("/turntable_reference/scene/lights") + if lights_prim.IsValid(): + lights_prim.GetAttribute("visibility").Set("invisible",0) + + realstage_filename = R"turntable_assembly.usd" + realstage_filename = os.path.join(tempfolder, realstage_filename) + realstage_filename = os.path.abspath(realstage_filename) + + ttable_stage.Export(realstage_filename) + + # frame range 1-100 in standard file + # get_file_timerange_as_string should be preferred, but it doesn't work atm. + frames_string = get_turntable_frames_string(length,frame_start,repeats) + render_path = os.path.abspath(export_path) + + print("Rendering",frames_string,render_path) + + # create an exit stack that will neatly clean up all the things in order. + with ExitStack() as stack: + # enter stage context, and also enter context for deferring + # subject file to be deleted. + realstage = stack.enter_context(TempStageOpen(realstage_filename, True)) + stack.enter_context(defer_file_deletion(subject_filename)) + + turntable_camera = next(playblast.iter_stage_cameras(realstage),None) + turntable_camera = UsdGeom.Camera(turntable_camera) + turntable_camera = framing_camera.camera_conform_sensor_to_aspect( + turntable_camera, + width, + height + ) + + playblast.render_playblast(realstage, + render_path, + frames=frames_string, + width=width, + camera=turntable_camera, + renderer=renderer, + qt_report_instance=qt_report_instance) + # remove reference count of realstage within this scope. + # This is essential to let garbage collection take place. + del realstage + + +def file_is_zup(path: str) -> bool: + stage = Usd.Stage.CreateInMemory(path) + return framing_camera.get_stage_up(stage) == "Z" + + +def get_file_timerange_as_string(path: str) -> str: + """ + Attempt to get timerange from a USD file. + """ + start = 0 + end = 100 + + with TempStageOpen(path) as stage: + + if stage.HasAuthoredTimeCodeRange(): + start = int(stage.GetStartTimeCode()) + end = int(stage.GetEndTimeCode()) + else: + print("No Timecode found") + + return playblast.get_frames_string(start,end) diff --git a/usd_qtpy/resources/feathericons/chevron-down.svg b/usd_qtpy/resources/feathericons/chevron-down.svg new file mode 100644 index 0000000..9c804a9 --- /dev/null +++ b/usd_qtpy/resources/feathericons/chevron-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/usd_qtpy/style/resources.qrc b/usd_qtpy/style/resources.qrc index 077f074..46cc7c4 100644 --- a/usd_qtpy/style/resources.qrc +++ b/usd_qtpy/style/resources.qrc @@ -33,4 +33,4 @@ images/checkbox_indeterminate_disabled.png images/transparent.png - + \ No newline at end of file diff --git a/usd_qtpy/style/resources_rc.py b/usd_qtpy/style/resources_rc.py new file mode 100644 index 0000000..9b9b760 --- /dev/null +++ b/usd_qtpy/style/resources_rc.py @@ -0,0 +1,1520 @@ +# Resource object code (Python 3) +# Created by: object code +# Created by: The Resource Compiler for Qt version 5.15.2 +# WARNING! All changes made in this file will be lost! + +from PySide2 import QtCore + +qt_resource_data = b"\ +\x00\x00\x00\x9f\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x14\x1f\xf9\ +#\xd9\x0b\x00\x00\x00#IDAT\x08\xd7c`\xc0\ +\x0d\xe6|\x80\xb1\x18\x91\x05R\x04\xe0B\x08\x15)\x02\ +\x0c\x0c\x8c\xc8\x02\x08\x95h\x00\x00\xac\xac\x07\x90Ne\ +4\xac\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x03\xfb\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x03\xadIDATh\x81\xed\ +\x9aO\xa8\x15U\x1c\xc7?\xf7\xbe\xab\xf2 \xa3\x22m\ +\xa1|!\x09*K(\xdaD\xb9\x88RL\xccjQ\ +\xf9\xa4\x85\xf1\xa0\x16Q\xe4.\x10tQD\x8b\x16\x15\ +%\x81\xb5(\x04\xad\xc0\xe2ad\xf6\x97\xe0E\x10\xb4\ +\xa9'DE\xc4\x17\xa2\x125\x0a*\xff<\xab\xc5\x99\ +[\xd7y3s\xce\xdcko\xee\x05?\xbb9\xf3;\ +\xbf\xf3\xfb\x9d3\xe7\x9c\xef\x9c\x99\x16\x19\xb6/\x06v\ +\x00\xab\x81\xab\x81\x05\x0c\x17\xa7\x80\x19`\x1axL\xd2\ +\x11\x80\x16\x80\xed\x9b\x81\xbd\xc0\xd2\xc6\xc2\xab\xc7a`\ +\xb3\xa4\x0f[Y\xcf\x1fbt\x82\xefr\x18\xb8\xaaM\ +xlF-x\x081o\xef\x10\x9e\xf9<\xa7\xe79\ +\x98T\xc6r\xd7\xab;\x84\x09\xdb\xcbiI\x9dy\x0a\ +\xa8\x16\xb6g93\x89Um\x86o\xb5\xa9\xc3\x82v\ +\xd3\x11\x0c\xca\xb9\x04\x9a\xe6\x5c\x02\xff\x07\xb6\xef\xb6\xbd\ +\xd7\xf6\xda\x98\xed\xd0%`\xfb\x11\xe0u`\x028h\ +{\xa7\xed\xd2\x95r\xa8\x12\xb0=\x01<\xddS\xd4\x02\ +\x1e\x04^,\xab34\x1b\x96\xed5\xc0+d\x023\ +\xc7\x16\xdb_\x16\xd5\x1b\x8a\x11\xb0}\x1d\xf0\x06\xb0\xb0\ +\xc2l}Qa\xe3\x09\xd8\xbe\x0cx\x1bX\x1c1}\ +\xa9\xa8\xb0\xd1\x04l_\x02\x1c$\xae\x86\x9f\x92\xf4j\ +\xd1\x8d\xc6\x12\xb0\xbd\x188\x00\xac\x88\x98\xee\x06\x1e-\ +\xbb\xd9H\x02\xb6\x17\x02o\x02\xd7FL\xdf\x01&%\ +\xfd]f0\xef\x09\xd8n\x13z\xf5\x96\x88\xe9g\xc0\ +]\x92f\xab\x8c\x9a\x18\x81g\x80{\x226_\x03\x1b\ +$\xfd\x1es\x96\x94\x80\xedV\xd6s\x03a{\x1b\xf0\ +p\xc4\xecG`]\xf7\xd4!FePY\xe0[\x81\ +?\x81\x19\xdb\xab\x92\x22-\xf65\x09<\x111\xfb\x15\ +\xb8U\xd2\xf7\xa9~K\x13\xc8\xf4\xc7\x14ak_\x04\ +\x5c\x09\xbco\xfb\xf2T\xe7=\xbe6\x02\xbb\x22f'\ +\x80;$}Q\xc7w\xd5\x08<\x0fl\xcc\x95-\x05\ +>\xb0}ij\x03\xb6o\x00^c\xee\x0by/\x7f\ +\x01\xf7J\xfa8\xd5o\x97\xc2\x04\xb2\x1e{\xa0\xa4\xce\ +2\xc2H,\x8b9\xb7\xbd\x12\xd8\x0f\x8cGL\x1f\x92\ +\xb4/\xe6\xaf\x88\xb2\x11\xb8(Ro\x05!\x89%e\ +\x06\xb6\x97\x13v\xd9\x98\xaf\xc7%\xbd\x10\xb1)\xa5,\ +\x81=\x84u\xb8\x8a+\x80wm_\x90\xbfa\xfbB\ +B\xf0\xcb#>vI\xda\x11\x8d\xb2\x82\xc2\x04$\x9d\ +\x22\xa8\xbfB\x09\xdb\xc35\xc0\x01\xdb\xe7u\x0bl\x8f\ +\x13\x1e\x9b\x95\x91\xbaS\x04\xad?\x10\xa5\x93X\xd21\ +`-\xf0M\xc4\xc7\xf5\xc0~\xdb\xe3\xb6\xc7\x08\x13\xf6\ +\xc6H\x9di`B\xd2\xc0'\x80\x95\xfb\x80\xa4\x9f\x81\ +5\x80#~n\x02\xf6\x11\x96\xca\xfc\xca\x95g\x06\xb8\ +]\xd2\xf1\xc4\x18+\x89\xee\xae\x92L\xd0-?EL\ +\xd7\x03\x93\x11\x1b\x136\xaa_\xd2\xc2\x8b\x93$\x0f$\ +}K\x18\x89\xa3\x03\xb4u\x8c \x11~\x18\xc0\xc7\x1c\ +\x92\xf5\x8d\xa4C\xc0:\xe0\xb7>\xda\xf9\x03\xb8M\xd2\ +W}\xd4\xad\xa4\x96@\x93\xf49\xb0!\x0b(\x95Y\ +`\x93\xa4O\xeb\xb4\x95Jm\x85)i\x1a\xb8\x93\xa0\ +]R\xb8_\xd2[u\xdbI\xa5/\x89,\xe9=`\ +\x13\xa1w\xab\xd8&\xe9\xe5~\xdaH\xa5o\x8d/i\ +\x0a\xd8B\x10bE<'\xe9\xc9~\xfd\xa72\xd0K\ +\x8a\xa4=\xc0}\xcc\x9d\x13;\x81\xad\x83\xf8Ne\xe0\ +\x939I\xbbm\x7fB\xd8\xc0\xce\x07>\xca\xe6\xc9\xbc\ +pV\x8e\x16%}\x07<{6|\xd5\xa5M\xf8\x02\ +>\xaa\x9c\xec\x10\xb4I\xef\xf9\xccX\xf65p\x18\xc9\ +\xbf\xd5\xcdt\x08\xca0\x7f\xc0T\xf5\xfa7LL\x8f\ +\xfe\xaf\x06\xd9\xf9\xcb\xe6\xac`T\xe8\xfe\xecq\xe4\xdf\ +\x8f\x09\xd9Hl\xe7\xbf\xdfm\xaa\xce\xea\x9b\xe0$g\ +\xfens\x14\xe0\x1f\x0aC\x12kO\xfd?\x13\x00\x00\ +\x00\x00IEND\xaeB`\x82\ +\x00\x00\x043\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x03\xe5IDATh\x81\xed\ +\x9aM\x88\x1cE\x14\xc7\x7f3;\x89.\x18\xf13\x1e\ +\x92\x8b\x8b\xa2&\x06\x14/\xa29\x88\x15\x89\xa9\x18\x15\ +\xd1\xca\x06\x0f\x91\x05=\x88bnB\xc0\x1c\x12\xc4\x83\ +\x07\x15\x0dB\x14\x89\x04\xa2\x96DY\x22/F}\x8a\ +\xb0\x22\x08\x1e4\xbb\x22F\x8c,\x88\xba\xc4\x88\x82_\ +\xc9F=T\x0f\x8c\xbd\xdd]\xdd\xd3a\xa7\x07\xfc\xdd\ +\xa6\xfa\xd5\xab\xf7\xea\xf3\xdf\xd5\xd3\x22\xc1Xw\x11\xb0\ +\x03X\x0b\x5c\x0d,\xa1Y\x9c\x02\xa6\x81)`\xa7\x8a\ +?\x0e\xd0\x020\xd6\xdd\x0c\xbc\x02,\x1fXx\xd5\x98\ +\x03\xb6\xa8\xf8\xf7[I\xcf\xcf0<\xc1w\x99\x03V\ +\xb7\x09\xd3f\xd8\x82\x87\x10\xf3c\x1d\xc2\x9cOsz\ +\x91\x83)\xcbH\xea\xf7\xda\x0ea\xc1\xf6rZ\xc5w\ +\x16)\xa0J\x18\xeb\xe6\xf9o\x12k\xda4o\xb7\xa9\ +\xc2\x92\xf6\xa0#\xa8\xcb\xff\x09\x0c\x9a\xa1O\xa0\xa9\xbb\ +\xcd=\xc0]\xc0K*\xfe\xdd\x22\xdb\xc6\x8d\x80\xb1\xee\ +\x11\xc0\x03\xe3\xc0ac\xddnc]\xeeN\xd9\xa8\x04\ +\x8cu\xe3\xc0S=E-\xe0A\xe0\x85\xbc:\x8d\x99\ +B\xc6\xbau\xc0\xcb$\x023\xc5Vc\xdd\x91\xacz\ +\x8d\x18\x01c\xddu\xc0\x1b\xc0\xd2\x02\xb3\x0dY\x85\x03\ +O\xc0Xw\x19 \xc0\xb2\x88\xe9\x8bY\x85\x03M\xc0\ +Xw\x09p\x98\xb8\x1a~R\xc5\xbf\x9a\xf5``\x09\ +\x18\xeb\x96\x01\x87\x80\xb1\x88\xe9>\xe0\xd1\xbc\x87\x03I\ +\xc0X\xb7\x14x\x13\xb86b\xfa60\xa1\xe2\xff\xc9\ +3X\xf4\x04\x8cumB\xaf\x9a\x88\xe9'\xc0\xdd*\ +~\xbe\xc8h\x10#\xf04\xe0\x226_\x01\x1bU\xfc\ +o1g\xa5\x120\xd6\xb5\x92\x9e\xab\x85\xb1n;\xf0\ +p\xc4\xec{`}\xf7\xd6!FaPI\xe0\xdb\x80\ +?\x80ic\xdd\x9aR\x91f\xfb\x9a\x00\x1e\x8f\x98\xfd\ +\x02\xdc\xaa\xe2\xbf-\xeb77\x81D\x7fL\x12\x8e\xf6\ +\xb3\x80\xab\x80\xf7\x8cuW\x94u\xde\xe3k\x13\xb0'\ +b\xf6\x17p\x87\x8a\xff\xbc\x8a\xef\xa2\x11x\x0e\xd8\x94\ +*[\x0e\xa8\xb1\xee\xd2\xb2\x0d\x18\xebn\x00^c\xe1\ +\x0by/\x7f\x03\xf7\xaa\xf8\x0f\xcb\xfa\xed\x92\x99@\xd2\ +c\x0f\xe4\xd4YA\x18\x89\x151\xe7\xc6\xbaU\xc0A\ +`4b\xfa\x90\x8a?\x10\xf3\x97E\xde\x08\x5c\x10\xa9\ +7FH\xe2\xe2<\x03c\xddJ\xc2)\x1b\xf3\xb5K\ +\xc5?\x1f\xb1\xc9%/\x81\xfd\x84}\xb8\x88+\x81w\ +\x8cu\xe7\xa5\x1f\x18\xeb\xce'\x04\xbf2\xe2c\x8f\x8a\ +\xdf\x11\x8d\xb2\x80\xcc\x04T\xfc)\x82\xfa\xcb\x94\xb0=\ +\x5c\x03\x1c2\xd6\x9d\xd3-0\xd6\x8d\x12\xa6\xcd\xaaH\ +\xddI\x82\xd6\xafE\xee\x22V\xf1'\x80[\x80\xa3\x11\ +\x1f\xd7\x03\x07\x8du\xa3\xc6\xba\x11\xc2\x82\xbd1Rg\ +\x0a\x18W\xf1\xb5o\x00\x0b\xcf\x01\x15\xff#\xb0\x0e\x98\ +\x8d\xf8\xb9\x098@\xd8*\xd3;W\x9ai\xe0v\x15\ +\xffg\xc9\x18\x0b\x89\x9e\xae*~\x96\xa0[~\x88\x98\ +n\x00&\x226\xb3\x84\x83\xea\xe7r\xe1\xc5)%\x0f\ +T\xfc\xd7\x84\x91\xf8\xa9F['\x08\x12\xe1\xbb\x1a>\ +\x16PZ\xdf\xa8\xf8\x19`=\xf0k\x1f\xed\xfc\x0e\xdc\ +\xa6\xe2\xbf\xec\xa3n!\x95\x04\x9a\x8a\xff\x14\xd8\x98\x04\ +T\x96y`\xb3\x8a\xff\xb8J[e\xa9\xac0U\xfc\ +\x14p'A\xbb\x94\xe1~\x15\xffV\xd5v\xca\xd2\x97\ +DNn\xcb6\x13z\xb7\x88\xed*~o?m\x94\ +\xa5o\x8d\xaf\xe2'\x81\xad\x04!\x96\xc5\xb3*\xfe\x89\ +~\xfd\x97\xa5\xd6K\x8a\x8a\xdf\x0f\xdc\xc7\xc25\xb1\x1b\ +\xd8V\xc7wYj\xdf\xcc\xa9\xf8}\xc6\xba\x8f\x08\x07\ +\xd8\xb9\xc0\x07\xc9:Y\x14\xce\xc8\xd5\xa2\x8a\xff\x06x\ +\xe6L\xf8\xaaJ\x9b\xf0\x05|X9\xd9!h\x93\xde\ +\xfb\x99\x91\xe4k`\x13I\xbf\xd5Mw\x08\xca0}\ +\xc1T\xf4\xfa\xd7$\xa6\xda\xc0N\xc2g\xfbac\x0e\ +\xd8\xd5N\xee_\xb60\x5cIt\xff\xecq|\x04\xe0\ +\xd8\xd1\x99cc\x97\xaf\xde\x0b\x9cM\xf8\xf0}!\xcd\ +\x9bF'\x81\xcf\x80\xd7\x01\xa7\xe2\xbf\x00\xf8\x17]\x81\ +\x0b8\xb3\xfa \x9c\x00\x00\x00\x00IEND\xaeB\ +`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x00\xa5\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ +\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ +200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ +\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ +\xaeB`\x82\ +\x00\x00\x03\xff\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x03\xb1IDATh\x81\xed\ +\x9aOh\x1eE\x18\xc6\x7f\x9b&\x85\x82\x15\x15\xabB\ +\xcb\x03\x06\x05\xa9\x0a\x8a\xb7R<\xd4\x96\xaa\xb5\xe0A\ +\xad\xc5C%\xa0\x07Q\xccM(\xb4\x07E\x80\xae9\x1f\xc0\xff\ +\x81\xed\xbbm\xbff{W\xca6\x0b!\x84BY\xa7\ +\xdb\xa8\xedG\x81#\xf9\xcf\x00\x1c\x05&%-\x94l\ +\xa3\xc35\x03\xb6\xef\x05\x9e\xe9)\xca\x80\x87\x80\x17\xab\ +\xda\x0c\xcd\x81e{'\xf0\x0aQt\x91\x03\xb6\xbf*\ +k7\x143`\xfb&\xe0M`}\x8d\xd9me\x85\ +\x9d\x07`\xfb*\xe0]`c\xc2\xf4\xa5\xb2\xc2N\x03\ +\xb0}9\xf0>\xe9l\xf8iI\xaf\x97Ut\x16\x80\ +\xed\x8d\xc0\x140\x9e0}\x15x\xac\xaa\xb2\x93\x00l\ +\xaf\x07\xde\x02nL\x98\xbe\x07LH*n\xf5K\xac\ +z\x00\xb6G\x88\xa3zK\xc2\xf4\x0b\xe0.I\x8bu\ +F]\xcc\xc0\x11\xe0\x9e\x84\xcd\xb7\xc0\x1eI\xbf\xa5\x9c\ +5\x0a\xc0v\x96\x8f\xdc@\xd8>\x08<\x920\xfb\x11\ +\xd8-i.a\x07$\x02\xc8\x85O\x02\x7f\x003\xb6\ +\xafo\xa4\xb4\xdc\xd7\x04\xf0d\xc2\xec\x17\xe0VI\xdf\ +7\xf5[\x99\x0b\xd9\x1e\x03\x8e\x03{{\xeaf\x81\x9b\ +%}\xd3\xb4\x03\x00\xdb{\x89\x8b\xb6x\xa7\xed\xe5,\ +q\xe4?\xab2\xe87\x17z\x8e\xe5\xe2!\xee\xd7\x1f\ +\xdb\xbe\xb2Vq\x0f\xb6\xb7\x01o\x14;.\xf0\x17p\ +_\x9d\xf8*J\x03\xc8G\xec\xc1\x8a6\x9b\x81\x8fl\ +oN9\xb7\xbd\x15x\x1b\xd8\x900}X\xd2\xf1\x94\ +\xbf2\xaaf\xe0\x92D\xbbqb\x10\x9b\xaa\x0clo\ +!\x9e\xb2)_OH:\x9a\xb0\xa9\xa4*\x80c\xc4\ +}\xb8\x8ek\x80\x0fl_T\xac\xb0}1Q\xfc\x96\ +\x84\x8f\x17$\x1dN\xaa\xac\xa14\x00I\x0b\xc4\xec\xaf\ +4\x85\xed\xe1\x06`\xca\xf6\x05\xff\x14\xd8\xde@|l\ +\xb6&\xda\x9e \xe6\xfa\x03Q{#\xcb\x93\xad\x93\xc0\ +\xd5\x09?\x9f\x02\xb7\x03\xf3\xc4\xdd\xa6\xb8\xf8\x8bL\x03\ +\xbb$\xfd\xd9\x8f\xd8\xb2](y\xa5\xb4-b\x10J\ +\xf8\x9f\x22\x1eB\x13\x09\xbb\x19\xe2V\xfcs#\xd5=\ +\xb4\x0a\x00\x96r\xf6\x93\xc0\x15\xfdvZ\xc0\xc06I\ +?\xb4i\xdc\xfaN,\xe9;`'p\xa6M\xc79\ +?\x11\x0f\xaaV\xe2\xabh\x9c\xdfH:\x05\xec\x06~\ +m\xd1\xcf\xef\xc0\x1d\x92\xben\xd1\xb6\x96\xbe\x124I\ +_\x02{rAMY\x04\xf6I\xfa\xbc\x9f\xbe\x9a\xd2\ +w\x86)i\x1a\xb8\x93\x98\xbb4\xe1\x01I\xef\xf4\xdb\ +OSZ\xa5\xc8\x92>\x04\xf6\x11G\xb7\x8e\x83\x92^\ +n\xd3GSZ\xe7\xf8\x92N\x00\x07\x88\x89X\x19\xcf\ +Jz\xaa\xad\xff\xa6\x0ctI\x91t\x0c\xb8\x9f\xff\xae\ +\x89\xe7\x81\xc9A|7eE\xde\x8d\xda\x1e'\x9e\xbe\ +\x17\x02\x9f\xe4\xebd\xc5i}\x90\x0d\x0bU\x07\xd9B\ +7rV\x84\xf9Qbn\xd2\xfb~f]\x1e\xe90\ +R\xbc\xd5\xcd\x8c\x123\xc3\xe2\x0b\xa6\xba\xeb\xdf01\ +\xbd\xf6?5\xc8\xbf\xfa\xd8\x9f\x17\xac\x15f\x81\xfdY\ +\x96\xcd-\xfd\x99\x90\xcf\xc4!\xfe\xfd\xdc\xa6\xee]}\ +\x17\xcc\xb3\xfcs\x9b3\x00\x7f\x03\xd9\x1a\xfb\xdb\xbb\xa7\ +\x8f\x07\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x05~\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x05\x17iTXtXML\ +:com.adobe.xmp\x00\x00\ +\x00\x00\x00 \ + \x07b\x0c\x81\x00\x00\x00\x0dIDAT\ +\x08\x1dc\xf8\xff\xff?\x03\x00\x08\xfc\x02\xfe\xe6\x0c\xff\ +\xab\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa5\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ +\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ +200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ +\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ +\xaeB`\x82\ +\x00\x00\x01\xfc\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01\xaeIDATh\x81\xed\ +\x9a\xbdJ\x03A\x14FO6\x1b\xb0\xd0J\xf1\x01\x14\ +\xabh\x91\xc6*X\xb8\x16\xb2\x88v\x0b\xe9}\x01\x1f\ +@\x8b\xf8\x00\xbe\x80\x85\x9d0b\xa32U\xc6B\xf2\ +\x02B\x92F\x83}H'6\xf9\x01\x8b\xdd@\x12\xb2\ +\x89k~f7\xcc\xe9v\xef\x14\xdfY\xee\x0c\x0bw\ +R\x048\xae\xb7\x01\x5c\x01y`\x17\xc8\x10/\xda@\ +\x05(\x03E%E\x13 \x05\xe0\xb8\xde!p\x0fl\ +j\x8b\x17\x8d\x06PPR\xbc\xa6\x82/_%9\xe1\ +{4\x80\xac\x85\xdf6I\x0b\x0f~\xe6K\x1b\xbf\xe7\ +\x87\xe9.8\xcc_I\x0f=\xe7m\xfc\x0d\xdbOW\ +Ia/(P$\x1c\xd7\xeb0(\xb1g\x11\xbf\xd3\ +&\x0a\x19Kw\x82i1\x02\xba1\x02\xba1\x02\xba\ +1\x02\xba1\x02\xba1\x02\xba\x99\xf8\xdb\xec\xb8\xde\x11\ +\xb0\x0f\xac\xce?\xce\x00\x1d\xa0\x06<+)~\xc2\x16\ +\x85\x0a8\xaeg\x03\x8f\xc0\xe9\xec\xb3E\xa2\xee\xb8\xde\ +\xb1\x92\xe2sTq\x5c\x0b]\xa0?<\xc06p\x1b\ +V\x1c'p2\xfb,\xff\xe6\xc0q\xbd\xb5Q\x85\xc4\ +o\xe2q\x02/\x0bK1\x997%\xc5\xf7\xa8\xc28\ +\x81\x1b\xe0i>y\x22Q\x07\xce\xc3\x8a\xa1\xa7\x90\x92\ +\xa2\x03\x9c%\xf6\x18\xed\xa1\xa4(\x01\xa5\x19\x06\x9b)\ +K\xbd\x89\x13\x81\x11\xd0\x8d\x11\xd0\x8d\x11\xd0\x8d\x11\xd0\ +\x8d\x11\xd0\xcdR\x08\xb4u\x87\x98\x82\x96\x8d?\xbe\xcf\ +\xf5\xbdL\x07\xd3\xc082\xaa_[\ +;\xd9;`\x05\x7f\xf0\xbdN\xfc\xda\xa8\x05\xbc\x03\x0f\ +\x80\xa7\xa4\xa8\x01\xfc\x02Q\xab\x5c\x8a?\xde\xe3Y\x00\ +\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa0\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f\x0d\xfc\ +R+\x9c\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05s>\xc0XL\xc8\x5c&dY&d\xc5pN\ +\x8a\x00\x9c\x93\x22\x80a\x1a\x0a\x00\x00)\x95\x08\xaf\x88\ +\xac\xba4\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x01[\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01\x0dIDATh\x81\xed\ +\xda\xb1m\x02A\x10F\xe1w\xc7\xe2\x0a,\x87\xd3\x00\ +8 'r\x17\x14\x83\x037\xe3.\x1cQ\x0240\ +!\xc2\x0d`\x90\x1c\xec\x9e\x0c'Y\xf6\x09\x89\xffV\ +\x9a/cE0\x0f\x0e\x92\x9d\x86\xc2\xdd\x1f\x81W`\ +\x09\xcc\x81)\xe3\xf2\x05l\x81\x0d\xf0ff\x07\x80\x06\ +\xc0\xdd_\x80w\xe0I6\xde0{`ef\x1fM\ +\xf9\xe4w\xd43|g\x0f\xccZ\xf2cS\xdb\xf0\x90\ +g^'\xf23\xdfw\xbe\xf30\xff5\xe9\xbd^&\ +\xf2\x0f\xf6\xd2\xd9\xcc\xd2\x9d\x06\x1a\xc4\xddO\x5cG<\ +\xb7\x8c\xef\xdff\x88i\xab\x9e\xe0V\x11\xa0\x16\x01j\ +\x11\xa0\x16\x01j\x11\xa0\x16\x01j\x11\xa0\x16\x01j\x11\ +\xa0\x16\x01j\x11\xa0\x16\x01j\x11\xa0\x16\x01j\x11\xa0\ +\x16\x01j\x11\xa0\xd6\x92o\xc0kuL\xe4\xeb\xfb\xc5\ +\xc5\xe1\xa4\xdc\x06\x8eQ\xff\x9au\x9b\xc8\xbb\x07\x8b?\ +\xde8V\x9b\xfaW\x0d\xca\xd6\xc7\xaa\x1c\xd4\xa2[\xf6\ +84\xddI\xf9&\xd6\xfc\xac\xdb<\x88\x86\xfb\xcd\x91\ +\xebu\x9bO\x80oV\x016\x1ew\x0d\xa5B\x00\x00\ +\x00\x00IEND\xaeB`\x82\ +\x00\x00\x01\xe1\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01\x93IDATh\x81\xed\ +\x9a;N\xc3@\x10\x86\xbfq\x1c*\xe8\x10\xe56\x94\ +\xd0\xa4\xa1\x8a(\x22\x0a\x0aD\x9f\x9e\x0bp\x80Pp\ +\x01.\xc0\x15h\x80\x13\xa0\x1c!P\x91f\xbbD\xa1\ +B4yh(l\x1e\xb1\xfcH\x08\xc9\xda\xd2~\x9d\ +w\x5c\xfc\x9f\xb3\x1e9\xda\x11bTu\x17\xb8\x02\x9a\ +\xc0!P\xa7\x5cL\x80\x1e\xd0\x05\xaeEd\xf4]Q\ +\xd5\x96\xaa\x0e\xb4:\x0cT\xb5\x05 \x1a=\xf9g`\ +\xcf\xc5c]\x81!p\x10\x10m\x9b\xaa\x85\x87(s\ +'$\xda\xf3If\x1b\x0e\xb3(\xb5\xc4uSTu\ +\xcc\xfc\x0b;\x13\x91p\x83\xa1\x16FU\xa7\xccKL\ +\x02\xca\xd7m\x96\xa1\x1e\xb8N\xb0*^\xc05^\xc0\ +5^\xc05^\xc05^\xc05^\xc05\x85\x9f\xcd\ +\xd6\xda\x13\xe0\x08\xd8^\x7f\x9c9\xa6\xc0\x0b\xf0`\x8c\ +\xf9\xc8\xbaITU\x13k3\x11\x09\xad\xb5!p\x07\ +\x9c\xaf1\xe4\x22\xf4\x81Sc\xcck\xca\xff\x81\xdc-\ +t\x89\xfb\xf0\x00\xfb\xc0mV1O\xe0\xec\xff\xb3\xfc\ +\x99ck\xedNZ\xa1\xf2/q\x9e\xc0\xe3\xc6R\x14\ +\xf3d\x8cyO+\xe4\x09\xdc\x00\xf7\xeb\xc9\xb3\x14}\ +\xe0\x22\xab\x98\xd9\x85\xbe.\xca\xd4F\xd3\xbaP\xa1@\ +\x99X\xb6\x8dV\x02/\xe0\x1a/\xe0\x1a/\xe0\x1a/\ +\xe0\x1a/\xe0\x1a/\xe0\x9a\x80\xe8\x04\xbc\xaa\x8cC\xa2\ +\xe3\xfb\xc6\xaf\xc5Z\xfc\xd9ZF\x92\xc7\xac\xbd\x90h\ +\xf6\xa0QpcY\xe9V\x7f\xd4 \x9e\xfah\xc7\x0b\ +Ua\x08\xb4Ed$_+\xf1/\xd1\xe1g\xdcf\ +\xcbQ\xb8,\xc6\xcc\x8f\xdb\xbc\x01|\x02mw#\xb3\ +\xd4\x95Sv\x00\x00\x00\x00IEND\xaeB`\x82\ +\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1d\x00\xb0\ +\xd55\xa3\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x06\xfe\x9fg``B0\xa1\x1c\x08\x93\x81\x81\x09\xc1\ +d``b``4D\xe2 s\x19\x90\x8d@\x02\ +\x00d@\x09u\x86\xb3\xad\x9c\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x04\x12\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x03\xc4IDATh\x81\xed\ +\x9a_\x88\x94U\x18\xc6\x7f3;\x1a\x0b\x19\x15f\x17\ +\xca\x03IPM\x09J7Q^D)&f\x05[\ +\xb9\xd2\x82\xb1P\x17\x91$t\x11\x08z\xa1D\x17]\ +T\x94\x04\xd6E\xe1\xa2\x15L\xb1\x18\x99\xfd%\xd8\x08\ +\x82nj]\xa4\x22\xe2\x81\xa8\x96\xd5(\xe8\x9f\xae\xd5\ +\xc5\xf9\xb6\xc6\xd9\xf9\xbesf\xc6vf\xc0\xdf\xdd\x9c\ +\xef=\xefy\x9fs\xe6\x9c\xf3~\xdf9%2Fj\ +SK\x81\xdd\xc0Z\xe0:`\x11\xbd\xc5i`\x12\x98\ +\x00\xf6\x8c\x0dUg\x00J\x00#\xb5\xa9[\x80C\xc0\ +\xb2\xae\x85\xd7\x1a\xd3\xc0\xd6\xb1\xa1\xea\x07\xa5\xac\xe7\x8f\ +\xd1?\xc1\xcf1\x0d\x5c[&\xfcm\xfa-x\x081\ +\xef\xaa\x10\xfe\xf3\x8d\x9cY\xe0`R\x19h\xf8\xbd\xb6\ +B\x98\xb0\xf5\x9c\x19\x1b\xaaV\x16(\xa0\x96\x18\xa9M\ +\xcdr\xb6\x88Uezo\xb5i\x85E\xe5nG\xd0\ +)\xe7\x05t\x9b\xf3\x02\xfe\x0fl\xdfc\xfb\x90\xed\xf5\ +1\xdb\x9e\x13`\xfb\x11\xe05`\x188j{\x9f\xed\ +\xdc\x95\xb2\xa7\x04\xd8\x1e\x06\x9e\xaa+*\x01\x0f\x01/\ +\xe4\xd5\xe9\x19\x01\xb6\xd7\x01/\x93%\x98\x0dl\xb3\xfd\ +h\xb3z=!\xc0\xf6\xf5\xc0\xeb\xc0\xe2\x02\xb3\x8d\xcd\ +\x0a\xbb.\xc0\xf6\x95\xc0[\xc0\x92\x88\xe9\x8b\xcd\x0a\xbb\ +*\xc0\xf6\xe5\xc0Q\xe2\xd9\xf0\x93\x92^i\xf6\xa0k\ +\x02l/\x01\x8e\x00+#\xa6\x07\x80\xc7\xf2\x1evE\ +\x80\xed\xc5\xc0\x1b\xc0\x9a\x88\xe9\xdb\xc0\xa8\xa4\xbf\xf3\x0c\ +\x16\x5c\x80\xed2\xa1Wo\x8d\x98~\x0a\xdc-i\xb6\ +\xc8\xa8\x1b#\xf04po\xc4\xe6K`\x93\xa4_c\ +\xce\x92\x04\xd8.e=\xd7\x11\xb6w\x02\xdb#f\xdf\ +\x03\x1b$\xcd\xa4\xf8,\x0c*\x0b|\x07\xf0;0i\ +{UR\xa4\xcd}\x8d\x02\x8fG\xcc~\x06n\x93\xf4\ +m\xaa\xdf\x5c\x01Y\xfe1N\xd8\xda/\x00\xae\x01\xde\ +\xb3}U\xaa\xf3:_\x9b\x81\xfd\x11\xb3?\x81;%\ +}\xde\x8a\xef\xa2\x11x\x0e\xd8\xdcP\xb6\x0cx\xdf\xf6\ +\x15\xa9\x0d\xd8\xbe\x11x\x95\xf9/\xe4\xf5\xfc\x05\xdc'\ +\xe9\xa3T\xbfs4\x15\x90\xf5\xd8\x839u\x96\x13F\ +by\xcc\xb9\xed*p\x18\x18\x8c\x98>,\xa9\x16\xf3\ +\xd7\x8c\xbc\x11\xb84Ro%A\xc4ey\x06\xb6W\ +\x10v\xd9\x98\xaf\xbd\x92\x9e\x8f\xd8\xe4\x92'\xe0 a\ +\x1d.\xe2j\xe0\x1d\xdb\x177>\xb0}\x09!\xf8\x15\ +\x11\x1f\xfb%\xed\x8eFY@S\x01\x92N\x13\xb2\xbf\ +/\x22\xf5W\x03Gl_8W`{\x90\xf0\xb7\xa9\ +F\xea\x8e\x13r\xfd\x8e\xc8\x9d\xc4\x92N\x02\xeb\x81\xaf\ +\x22>n\x00\x0e\xdb\x1e\xb4=@\x98\xb07E\xeaL\ +\x00\xc3\x92:\xfe\x02X\xb8\x0fH\xfa\x11X\x078\xe2\ +\xe7f\xa0FX*\x1bW\xaeF&\x81;$\xfd\x91\ +\x18c!\xd1\xddU\x92\x09y\xcb\x0f\x11\xd3\x8d\xc0h\ +\xc4\xc6\x84\x8d\xea\xa7\xb4\xf0\xe2$\xa5\x07\x92\xbe&\x8c\ +\xc4\x89\x0e\xda:IH\x11\xbe\xeb\xc0\xc7<\x92\xf3\x1b\ +I\xc7\x80\x0d\xc0/m\xb4\xf3\x1bp\xbb\xa4\xe3m\xd4\ +-\xa4\xa5\x04M\xd2g\xc0\xa6,\xa0Tf\x81-\x92\ +>i\xa5\xadTZ\xce0%M\x00w\x11r\x97\x14\ +\x1e\x90\xf4f\xab\xed\xa4\xd2V\x8a,\xe9]`\x0b\xa1\ +w\x8b\xd8)\xe9\xa5v\xdaH\xa5\xed\x1c_\xd28\xb0\ +\x8d\x90\x885\xe3YIO\xb4\xeb?\x95\x8e^R$\ +\x1d\x04\xeeg\xfe\x9c\xd8\x07\xec\xe8\xc4w*\x1d\x1f%\ +I:`\xfbc\xc2\x06v\x11\xf0a6O\x16\x84s\ +r\x16&\xe9\x1b\xe0\x99s\xe1\xabU\xca\x84\x13\xf0~\ +\xe5T\x85\x90\x9b\xd4\x7f\x9f\x19\xc8N\x03{\x91\xc6\xb7\ +\xba\xc9\x0a!3l\xfc\xc0T\xf4\xfa\xd7KL\x94\x81\ +=\x84c\xfb~c\x1a\xd8[\xcen}l\xa5\xbfD\ +\xcc]\xf6\x98\xf9\xf70!\xbb\xf4\xb1\x8b\xff\xae\xdb\x14\ +}\xab\xef\x06\xa78\xfb\xba\xcd\x09\x80\x7f\x00\xc4\x1e\x10\ +)3[\x85\xf7\x00\x00\x00\x00IEND\xaeB`\ +\x82\ +\x00\x00\x01W\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01\x09IDATh\x81\xed\ +\xda\xcdm\xc2@\x14E\xe1\xf3\x8cI\x05Q\x9aH6\ +\xecY\xd1\x05\xc5\x90Ej\xa3\x04R\x04\x884`\x82\ +n\x163\xf9\xb1\xa5(DH\x5c[z\xdf\x8e\xc1\x8b\ +w\x8c\xcdf&\xa8$\xdd\x03\xcf\xc0\x12x\x02\xe6\x8c\ +\xcb\x09\xd8\x01[\xe0%\x22\x8e_\xdfHZI\xdak\ +:\xf6\x92V\x00\xa1r\xe7_\x81\x07\xc7m\xbd\xc2\x01\ +xl(\x8f\xcd\xd4\x86\x872\xf3\xa6\xa5<\xf3C\xe7\ +\x1b\x0fs\xa9\xd9\xe0\xf32$u\xf4_\xd8sD\xb4\ +7\x1c\xeab\x92\xde\xe9G\x9c\x1a\xc6\xf7o\xf3\x1f\xf3\ +\xc6=\xc1\xb52\xc0-\x03\xdc2\xc0-\x03\xdc2\xc0\ +-\x03\xdc2\xc0-\x03\xdc2\xc0-\x03\xdc2\xc0-\ +\x03\xdc2\xc0-\x03\xdc2\xc0-\x03\xdc2\xc0\xad\xa1\ +\xec\x80OU\xd7R\xb6\xef\x17?\x16gu7p\x8c\ +\x86\xdb\xac\xbb\x96r\xf6`\xf1\xc7\x85c\xb5\x9d\xfeQ\ +\x83z\xeac]\x17\xa6\xe2\x00\xac#\xe2\x18\x9f+\xf5\ +\x97\xd8\xf0}\xdc\xe6\xce4\xdco:\xfa\xc7m\xde\x00\ +>\x00G\xd7\xea\xb1\xadi\xe1\xd6\x00\x00\x00\x00IE\ +ND\xaeB`\x82\ +\x00\x00\x00\x9e\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ +\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ +\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ +\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ +\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\x9e\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15\x0f\xfd\ +\x8f\xf8.\x00\x00\x00\x22IDAT\x08\xd7c`\xc0\ +\x0d\xfe\x9f\x87\xb1\x18\x91\x05\x18\x0d\xe1BH*\x0c\x19\ +\x18\x18\x91\x05\x10*\xd1\x00\x00\xca\xb5\x07\xd2v\xbb\xb2\ +\xc5\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x07\x06\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ +\x00\x00\x04\xb0iTXtXML:com.\ +adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0a\x85\x9d\x9f\x08\x00\x00\x01\x83\ +iCCPsRGB IEC6196\ +6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ +\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ +\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ +x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ +Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ +;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ +\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ +\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ +\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ +\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ +RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ +?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ +\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ +\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ +\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ +\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ +\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ +\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ +vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ +\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ +8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ +S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ +\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ +Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00mIDAT\x18\x95u\xcf\xc1\x09\xc2P\ +\x10\x84\xe1\xd7\x85\x07\x9b\xd0C@\xd2\x82x\x14{0\ +W!\x8d\x84`?bKzH\xcc\x97\x83\xfb0\x04\ +\xdf\x9c\x86\x7fg\x99\xdd\x84\x0d\xaaT\x10jl\x13\x1e\ +\xbe\xba\xfe\x0951{\xe6\x8d\x0f&\x1c\x17\xa1S\xb0\ +\x11\x87\x0c/\x01\x07\xec\xb0\x0f?\xe1\xbc\xaei\xa3\xe6\ +\x85w\xf8[\xe9\xf0\xbb\x9f\xfa\xd2\x839\xdc\xa3[\xf3\ +\x19.\xa8\x89\xb50\xf7C\xa0\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x01\xef\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01\xa1IDATh\x81\xed\ +\x9a\xbfN\xc2P\x14\x87\xbf\x96\xe2\xa4\x9bq\xbc\x8b\x1b\ +\xea\xc0\xe2D\x1c\x8c\x83\x83\xd1\x81\x89\x84\xd1\x17\xf0\x01\ +p\xc0\x07\xf0\x05\x1cI\x9c\xba\xa8#q0<\x02v\ +\x92\xe5\x8e\x04'\xe3\xc2\x9f\xc4\xa1m\x04B\x8b\x95\xc2\ +\xa1\xe4~[{\xee\xf0\xfb\x9a{o\x9a\x9cc\x11P\ +u\xbd]\xe0\x16(\x01\x87@\x9e\xf5b\x00\xb4\x81\x16\ +Po\x94\x0b=\x00\x0b\xa0\xeaz\xa7\xc0#\xb0'\x16\ +/\x19]\xa0\xd2(\x17^\xad\xe0\xcb\xbf\x93\x9d\xf0!\ +]\xe0\xc0\xc6\xdf6Y\x0b\x0f~\xe6\x9a\x83\xbf\xe7\xa7\ +\x19\xad8\xcc_\xc9M=\x97\x1c\xfc\x03;\xce\xa8Q\ +.8+\x0a\x94\x88\xaa\xeb\x0d\x99\x948\xb2Y\xbf\xdb\ +&\x09y[:\xc1\xa2\x18\x01i\x8c\x804F@\x1a\ +# \x8d\x11\x90\xc6\x08H3\xf7\xb7Yk}\x06\x1c\ +\x03\xdb\xcb\x8f3\xc1\x10\xf0\x80g\xa5\xd4w\xd4\xa2H\ +\x01\xad\xb5\x03\xb8\xc0e\xfa\xd9\x12\xd1\xd1Z\x9f+\xa5\ +>f\x15\xe3\xb6\xd0\x0d\xf2\xe1\x01\xf6\x81\x87\xa8b\x9c\ +\xc0E\xfaY\xfe\xcd\x89\xd6zgV!\xf3\x878N\ +\xe0ee)\xe6\xf3\xa6\x94\xfa\x9aU\x88\x13\xb8\x07\x9e\ +\x96\x93'\x11\x1d\xe0:\xaa\x18y\x0b)\xa5\x86\xc0U\ +f\xaf\xd1\x10\xa5T\x13h\xa6\x18,U6\xfa\x10g\ +\x02# \x8d\x11\x90\xc6\x08Hc\x04\xa41\x02\xd2l\ +\x84\xc0@:\xc4\x02\xf4\x1d\xfc\xf6}q\xece.\xe8\ +\x06\xae#\xd3m\xd6\xb6\x83?{P\x9c\xb3p]i\ +\xd9@\x1d\xbfm\x9f5\xba\xc0\x9d\x1dL}T\xc8\x96\ +D8\xec\xd1\xb3\xc27\xc1\xd0G\x8d\xdfq\x9b-\xa1\ +pQ\xf4\x99\x1c\xb7\xf9\x04\xf8\x01o\xedXc-\xfd\ +\xb2Y\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1f \xb9\ +\x8dw\xe9\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x06\xe6|```B0\xa1\x1c\x08\x93\x81\x81\x09\xc1\ +d``b`H\x11@\xe2 s\x19\x90\x8d@\x02\ +\x00#\xed\x08\xafd\x9f\x0f\x15\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x01i\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01\x1bIDATh\x81\xed\ +\xda\xb1m\xc2@\x14\x87\xf1\xcf\xc7\x91\x09P\x86pB\ +AO\xc5\x0a\xae\x90\xbc\x0a)\xc8*\x96Ry\x05*\ +F \x1e\xc2\x82\x05H\x90R\xdcY\x01KQbE\ +\xe2\xef\x93\xde\xaf\xb3E\xf1>\xcb\xa6\xb9\x97\x11\x95u\ +3\x03^\x80%\xf0\x0cL\x19\x97\x0f\xe0\x00\xec\x81m\ +U\xe4G\x80\x0c\xa0\xac\x9b\x15\xf0\x06<\xca\xc6\x1b\xa6\ +\x05\xd6U\x91\xef\xb2\xf8\xe4\xdfIg\xf8N\x0b<9\ +\xc2k\x93\xda\xf0\x10f\xdex\xc2;\xdfw\xb9\xf30\ +\x7f5\xe9]/=\xe1\x83\xbdv\xa9\x8a\xdc\xdfi\xa0\ +A\xca\xba\xf9\xe46b\xee\x18\xdf\xbf\xcd\x10S\xa7\x9e\ +\xe0\xbf,@\xcd\x02\xd4,@\xcd\x02\xd4,@\xcd\x02\ +\xd4,@\xcd\x02\xd4,@\xcd\x02\xd4,@\xcd\x02\xd4\ +,@\xcd\x02\xd4,@\xcd\x02\xd4,@\xcd\x11N\xc0\ +Su\xf6\x84\xe3\xfb\xc5\xd5\xcdI<\x0d\x1c\xa3\xfe1\ +\xeb\xc1\x13v\x0f\x16\xbf\xfcp\xac\xf6\x0e\xd8\x12\x8e\xed\ +S\xd3\x02\xaf.n}\xacI+\xa2[\xf68f\xdd\ +\x9d\xb8\xf4\xb1\xe1{\xdd\xe6A4\xdcO\xce\xdc\xae\xdb\ +\x9c\x00\xbe\x00\x9f\xf64>6O7\x81\x00\x00\x00\x00\ +IEND\xaeB`\x82\ +\x00\x00\x01v\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01(IDATh\x81\xed\ +\xda\xb1J\xc3P\x14\x87\xf1/7\xb7\xe0\xae\xf8\x00\x82\ +Su\xe8\xde\xc9ly\x80@\x1fF\x87\xfa\x22nB\ +\xdc\xb3\xc5\xa9/ \xb4]:t\x0f}\x82j\xc1\xe1\ +\xa6P\xb3h\x10\xfa\xcf\x85\xf3\xdbR:\x9c\xaf\xdcf\ +97\xa1\x95\xe5\xc5\x15\xf0\x04L\x81;`\xc4\xb0|\ +\x02K`\x01\xcc\xeb\xaa\xdc\x01$\x00Y^<\x00\xaf\ +\xc0\xb5l\xbc~\x1a`VW\xe5{\xd2\xfe\xf2+\xe2\ +\x19\xfe\xa8\x01\xc6\x8eplb\x1b\x1e\xc2\xcc\x8f\x9ep\ +\xe6\xbb\x0eg\x1e\xe6\xaf\xd2\xce\xf3\xd4\x13\xfe\xb0\xa7\x0e\ +uU\xfa3\x0d\xd4K\x96\x17_\xfc\x8c\xb8w\x0c\xef\ +m\xd3\xc7\xc8\xa9'\xf8/\x0bP\xb3\x005\x0bP\xb3\ +\x005\x0bP\xb3\x005\x0bP\xb3\x005\x0bP\xb3\x00\ +5\x0bP\xb3\x005\x0bP\xb3\x005\x0bP\xb3\x005\ +\x0bPs\x84\x0dx\xac\xf6\x9e\xb0\xbe\x9f\x9c|\x98\xb6\ +\xdb\xc0!\xea\xaeY\x97\x9ep\xf7`\xf2\xcb\x17\x87j\ +\xe1\x809am\x1f\x9b\x06xv\xed\xad\x8f\x19qE\ +\x1c/{\xecR\x80\xedf\xb5\xbd\xb9\x1d\xbf\x00\x17\x84\ +\xc5\xf7%\xc3;F{\xe0\x03x\x03\x8a\xba*\xd7\x00\ +\xdf\xa4\xb56\xa2\xca\x99tG\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x07\xdd\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x07\x00\x00\x00\x0a\x08\x06\x00\x00\x00x\xccD\x0d\ +\x00\x00\x05RiTXtXML:com.\ +adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \ +\x0a branch_close<\ +/rdf:li>\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a <\ +/rdf:RDF>\x0a\x0aX\xad\xf2\x80\x00\x00\ +\x01\x83iCCPsRGB IEC61\ +966-2.1\x00\x00(\x91u\x91\xcf+D\ +Q\x14\xc7?fh\xfc\x18\x8dba1e\x12\x16B\ +\x83\x12\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3\ +j\xdex\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\ +\xc0VY+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\ +\x99s;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8a\ +fV\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\ +\xa8\xa2\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\ +\xb7T\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\ +\xa8\xa8\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\ +\x12nRR\xb1E\xe1\x13\xe1.C.(|c\xeb\ +\xf1\x22?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0\ +/\xf9\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\ +\xfc\xdc\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&\ +D\x00\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>z\ +dE\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0\ +D\x92\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19i\ +rv\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\ +\xac\xd7vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\ +\x0fp\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\ +\x9eu8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\ +\x0a\x92S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\ +\xc5\x9e\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e\ +9\xefY\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\ +\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\ +\x9c\x18\x00\x00\x00\xa2IDAT\x18\x95U\xcf\xb1J\ +\xc31\x00\xc4\xe1/\xff\xb9\x93\xa3\x93\xb8\xa5\x8b\x0f \ +UD\x10\x5c:\x84,\x1d\x5c|\x0f\xb7\x8e>J\x88\ +\xa3\xb8\x08m\x05\xbbw\xc8\xea\xe2\x0bto\xe9\xd2B\ +zpp\xf0\xe3\x0e.\xa4\xd2\xae\xf0\x8a\xf7\x9a\xe3V\ +\xa7\x01\xd7x\xc32\x95vy\x06k\x8e\xdfx\xc1\x18\ +\xbf\xa9\xb4\xf1\x09\x86SH\xa5=\xe2\x03;Lk\x8e\ +\xab\xd0\xcf\xa4\xd2n\xf0\x89\x0b\xdc\x0f\xce\xb5?: \ +\x0c]\xeb\x01?\x18\xe1\xa9\xe6\xb8\x1e\x8e`\x86/l\ +q[s\x5c@H\xa5\xdda\x81\x0d\x9ek\x8e\xff\xfd\ +\xcf?\xcc1\xe9\x01\x1c\x00sR-q\xe4J\x1bi\ +\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x07\xad\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x07\x00\x00\x00\x0a\x08\x06\x00\x00\x00x\xccD\x0d\ +\x00\x00\x05RiTXtXML:com.\ +adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \ +\x0a branch_close<\ +/rdf:li>\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a <\ +/rdf:RDF>\x0a\x0a$\xe15\x97\x00\x00\ +\x01\x83iCCPsRGB IEC61\ +966-2.1\x00\x00(\x91u\x91\xcf+D\ +Q\x14\xc7?fh\xfc\x18\x8dba1e\x12\x16B\ +\x83\x12\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3\ +j\xdex\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\ +\xc0VY+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\ +\x99s;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8a\ +fV\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\ +\xa8\xa2\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\ +\xb7T\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\ +\xa8\xa8\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\ +\x12nRR\xb1E\xe1\x13\xe1.C.(|c\xeb\ +\xf1\x22?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0\ +/\xf9\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\ +\xfc\xdc\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&\ +D\x00\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>z\ +dE\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0\ +D\x92\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19i\ +rv\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\ +\xac\xd7vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\ +\x0fp\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\ +\x9eu8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\ +\x0a\x92S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\ +\xc5\x9e\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e\ +9\xefY\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\ +\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\ +\x9c\x18\x00\x00\x00rIDAT\x18\x95m\xcf1\x0a\ +\xc2P\x14D\xd1\xe8\x02\xb4W\x08\xd6Ia\x99JC\ +t\x15\x82\xabI6(\xee@\x04\xdb\xa8\x95Xx,\ +\xf2\x09\xe1\xf3\x07\xa6\x9a\xfb\xe0\xbe\x0c\x1b\xb4Xdq\ +p0\xe4\x82U\x0a8\xe3\x8b\x1b\x8a\x14p\xc4\x1b=\ +v)`\x8b\x07>\xa8\xe6\xd1\xfe\x0b\x9d\x85\x8eW\x0d\ +^x\xa2\x9e\x0e\xa7 tG9\x1d\xf6\xe1\x95+\xd6\ +\xb1D\x8e\x0e\xcbX\xf0\x0fR\x8ay\x18\xdc\xe2\x02p\ +\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1d\x00\xb0\ +\xd55\xa3\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x06\xfe\x9fg``B0\xa1\x1c\x08\x93\x81\x81\x09\xc1\ +d``b``4D\xe2 s\x19\x90\x8d@\x02\ +\x00d@\x09u\x86\xb3\xad\x9c\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x00\xa5\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\x9cS4\xfc]\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x0b\x02\x04m\ +\x98\x1bi\x00\x00\x00)IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0c\xff\xcf\xa3\x08\x18220 \x0b2\x1a\ +200B\x98\x10AFC\x14\x13P\xb5\xa3\x01\x00\ +\xd6\x10\x07\xd2/H\xdfJ\x00\x00\x00\x00IEND\ +\xaeB`\x82\ +\x00\x00\x00\xa0\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ +\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ +\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ +\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x070\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x0a\x00\x00\x00\x07\x08\x06\x00\x00\x001\xac\xdcc\ +\x00\x00\x04\xb0iTXtXML:com.\ +adobe.xmp\x00\x00\x00\x00\x00\x0a\x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a \x0a\x0aH\x8b[^\x00\x00\x01\x83\ +iCCPsRGB IEC6196\ +6-2.1\x00\x00(\x91u\x91\xcf+DQ\x14\ +\xc7?fh\xfc\x18\x8dba1e\x12\x16B\x83\x12\ +\x1b\x8b\x99\x18\x0a\x8b\x99Q~mf\x9ey3j\xde\ +x\xbd7\xd2d\xabl\xa7(\xb1\xf1k\xc1_\xc0V\ +Y+E\xa4d\xa7\xac\x89\x0dz\xce\x9bQ#\x99s\ +;\xf7|\xee\xf7\xdes\xba\xf7\x5cpD\xd3\x8afV\ +\xfaA\xcbd\x8dp(\xe0\x9b\x99\x9d\xf3\xb9\x9e\xa8\xa2\ +\x85\x1a:\xf1\xc6\x14S\x9f\x8c\x8cF)k\xef\xb7T\ +\xd8\xf1\xba\xdb\xaeU\xfe\xdc\xbfV\xb7\x980\x15\xa8\xa8\ +\x16\x1eVt#+<&<\xb1\x9a\xd5m\xde\x12n\ +RR\xb1E\xe1\x13\xe1.C.(|c\xeb\xf1\x22\ +?\xdb\x9c,\xf2\xa7\xcdF4\x1c\x04G\x83\xb0/\xf9\ +\x8b\xe3\xbfXI\x19\x9a\xb0\xbc\x9c6-\xbd\xa2\xfc\xdc\ +\xc7~\x89;\x91\x99\x8eHl\x15\xf7b\x12&D\x00\ +\x1f\xe3\x8c\x10d\x80^\x86d\x1e\xa0\x9b>zdE\ +\x99|\x7f!\x7f\x8ae\xc9Ud\xd6\xc9a\xb0D\x92\ +\x14Y\xbaD]\x91\xea\x09\x89\xaa\xe8\x09\x19irv\ +\xff\xff\xf6\xd5T\xfb\xfb\x8a\xd5\xdd\x01\xa8z\xb4\xac\xd7\ +vpm\xc2W\xde\xb2>\x0e,\xeb\xeb\x10\x9c\x0fp\ +\x9e)\xe5/\xef\xc3\xe0\x9b\xe8\xf9\x92\xd6\xb6\x07\x9eu\ +8\xbd(i\xf1m8\xdb\x80\xe6{=f\xc4\x0a\x92\ +S\xdc\xa1\xaa\xf0r\x0c\xf5\xb3\xd0x\x05\xb5\xf3\xc5\x9e\ +\xfd\xecst\x07\xd15\xf9\xaaK\xd8\xd9\x85\x0e9\xef\ +Y\xf8\x06\x8e\xfdg\xf8\xfd\x8a\x18\x97\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x97IDAT\x18\x95m\xcf\xb1j\x02A\ +\x14\x85\xe1o\xb7\xb6\xd0'H=Vi\x03\xb1\xb4H\ +;l\xa5\xf19\xf6Y\x02VB\xbaa\x0a\x0b;\x1b\ +\x1bkA\x18\x02)m\xe3\xbe\x82\xcd\x06\x16\xd9\xdb\xdd\ +\x9f\xff\x5c\xee\xa9b*\x13Ls\x13nF&\xa6\xf2\ +\x82\xaeF\x8b\xdf\x98\xca\xfb\x88\xb4\xc0\x0f\xda\x1a[t\ +\xd8\xc7T\xc2@\x9ac\x8f?|U=|\xc5\x09w\ +\xbc\xa1\xc2\x193,r\x13.\xd5\xe0\xc2\x12\x07\x5cQ\ +#\xe0#7\xe1\xa8O\x0e\x7f\xda`\xd7\xaf\x9f\xb9\x09\ +\xdfc\x05\xff\xe5uLe\xf5\xcc\x1f\x0d3,\x83\xb6\ +\x06D\x83\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x01\xdc\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\ +\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\ +\x01\x00\x9a\x9c\x18\x00\x00\x01\x8eIDATh\x81\xed\ +\x9a\xafN\xc3P\x14\x87\xbfn\x1d\x0a\x1cA\x1e\x83\x04\ +\xc4\x0cjA\x10\x04\x82\x80\x9e\xe7\x05x\x80!x\x01\ +^\x00\x8f\xc2\x00rA\x90=\xc2@1s\xe42\x14\ +\xc1\xecO\x82h\x1b\xb6e\xed(\xebv\xda\xe5~\xae\ +\xf7\x5c\xf1\xfb\xda{o\x9a\xdc\xe3\x11\xa2\xaa\xdb\xc05\ +P\x03\xf6\x81\x0a\xf9b\x00\xb4\x81\x16p#\x22=\x00\ +\x0f@U\x8f\x81{`\xc7,^:\xba@]D^\ +\xbc\xf0\xcd\xbfQ\x9c\xf0\x11]`\xafD\xb0l\x8a\x16\ +\x1e\x82\xcc\x0d\x9f`\xcdO3Zq\x98\xbfR\x9ez\ +\xae\xf9\x04\x1bv\x9c\x91\x88\xf8+\x0a\x94\x0aU\x1d2\ +)qP\x22\x7f\xa7M\x1a*%\xeb\x04\x8b\xe2\x04\xac\ +q\x02\xd68\x01k\x9c\x805N\xc0\x1a'`\xcd\xdc\ +\xdffU=\x01\x0e\x81\xcd\xe5\xc7\x99`\x08\xbc\x03O\ +\x22\xf2\x1d7)V@U}\xe0\x018\xcf>[*\ +:\xaaz*\x22\x1f\xb3\x8aIK\xe8\x0a\xfb\xf0\x00\xbb\ +\xc0]\x5c1I\xe0,\xfb,\xff\xe6HU\xb7f\x15\ +\x0a\xbf\x89\x93\x04\x9eW\x96b>\xaf\x22\xf25\xab\x90\ +$p\x0b<.'O*:\xc0e\x5c1\xf6\x14\x12\ +\x91!pQ\xd8c4BD\x9a@3\xc3`\x99\xb2\ +\xd6\x9b\xb8\x108\x01k\x9c\x805N\xc0\x1a'`\x8d\ +\x13\xb0f-\x04\x06\xd6!\x16\xa0\xef\x13\x5c\xdfW\xc7\ +\x06\xcb\xe1m`\x1e\x99\xbefm\xfb\x04\xbd\x07\xd59\ +\x13\xf3J\xab\xf8\xad\x06a\xd7G=\x1c(\x0aQ\xb3\ +G\xcf\x8bF\xc2/\xd1\xe0\xb7\xddf\xc3(\x5c\x1c}\ +&\xdbm>\x01~\x00%\xf8ZCUN:\x7f\x00\ +\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +\x00\x00\x00\xa0\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x06\x00\x00\x00\x09\x08\x04\x00\x00\x00\xbb\x93\x95\x16\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x14\x1c\x1f$\ +\xc6\x09\x17\x00\x00\x00$IDAT\x08\xd7c`@\ +\x05\xff\xcf\xc3XL\xc8\x5c&dY&d\xc5p\x0e\ +\xa3!\x9c\xc3h\x88a\x1a\x0a\x00\x00m\x84\x09u7\ +\x9e\xd9#\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x00\xa6\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00\x09\x00\x00\x00\x06\x08\x04\x00\x00\x00\xbb\xce|N\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x02bKGD\x00\xff\x87\x8f\xcc\xbf\x00\x00\x00\x09p\ +HYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\ +\x00\x00\x00\x07tIME\x07\xdc\x08\x17\x08\x15;\xdc\ +;\x0c\x9b\x00\x00\x00*IDAT\x08\xd7c`\xc0\ +\x00\x8c\x0c\x0cs> \x0b\xa4\x08020 \x0b\xa6\ +\x08000B\x98\x10\xc1\x14\x01\x14\x13P\xb5\xa3\x01\ +\x00\xc6\xb9\x07\x90]f\x1f\x83\x00\x00\x00\x00IEN\ +D\xaeB`\x82\ +" + +qt_resource_name = b"\ +\x00\x08\ +\x06\xc5\x8e\xa5\ +\x00o\ +\x00p\x00e\x00n\x00p\x00y\x00p\x00e\ +\x00\x06\ +\x07\x03}\xc3\ +\x00i\ +\x00m\x00a\x00g\x00e\x00s\ +\x00\x15\ +\x0f\xf3\xc0\x07\ +\x00u\ +\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\ +\x00.\x00p\x00n\x00g\ +\x00\x14\ +\x07\xec\xd1\xc7\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00c\x00h\x00e\x00c\x00k\x00e\x00d\x00.\ +\x00p\x00n\x00g\ +\x00\x1d\ +\x09\x07\x81\x07\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00c\x00h\x00e\x00c\x00k\x00e\x00d\x00_\ +\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x12\ +\x01.\x03'\ +\x00c\ +\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\ +\x00g\ +\x00\x0e\ +\x04\xa2\xfc\xa7\ +\x00d\ +\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x1a\ +\x05\x11\xe0\xe7\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00c\x00h\x00e\x00c\x00k\x00e\x00d\x00_\ +\x00f\x00o\x00c\x00u\x00s\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x0c\xe2hg\ +\x00t\ +\x00r\x00a\x00n\x00s\x00p\x00a\x00r\x00e\x00n\x00t\x00.\x00p\x00n\x00g\ +\x00\x1b\ +\x03Z2'\ +\x00c\ +\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\ +\x00s\x00a\x00b\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00#\ +\x06\xf2\x1aG\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00i\x00n\x00d\x00e\x00t\x00e\x00r\x00m\ +\x00i\x00n\x00a\x00t\x00e\x00_\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\x00.\x00p\ +\x00n\x00g\ +\x00\x18\ +\x03\x8e\xdeg\ +\x00r\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\ +\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x16\ +\x01u\xcc\x87\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00u\x00n\x00c\x00h\x00e\x00c\x00k\x00e\ +\x00d\x00.\x00p\x00n\x00g\ +\x00 \ +\x09\xd7\x1f\xa7\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00i\x00n\x00d\x00e\x00t\x00e\x00r\x00m\ +\x00i\x00n\x00a\x00t\x00e\x00_\x00f\x00o\x00c\x00u\x00s\x00.\x00p\x00n\x00g\ +\x00\x11\ +\x00\xb8\x8c\x07\ +\x00l\ +\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ +\ +\x00\x1a\ +\x03\x0e\xe4\x87\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00c\x00h\x00e\x00c\x00k\x00e\x00d\x00_\ +\x00h\x00o\x00v\x00e\x00r\x00.\x00p\x00n\x00g\ +\x00\x1c\ +\x08?\xdag\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00u\x00n\x00c\x00h\x00e\x00c\x00k\x00e\ +\x00d\x00_\x00f\x00o\x00c\x00u\x00s\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x01s\x8b\x07\ +\x00u\ +\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ +\x00\x0c\ +\x06\xe6\xe6g\ +\x00u\ +\x00p\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x0f\ +\x06S%\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00.\x00p\x00n\x00g\ +\x00 \ +\x0f\xd4\x1b\xc7\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00i\x00n\x00d\x00e\x00t\x00e\x00r\x00m\ +\x00i\x00n\x00a\x00t\x00e\x00_\x00h\x00o\x00v\x00e\x00r\x00.\x00p\x00n\x00g\ +\x00\x17\ +\x0ce\xce\x07\ +\x00l\ +\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ +\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x1c\ +\x0e<\xde\x07\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00u\x00n\x00c\x00h\x00e\x00c\x00k\x00e\ +\x00d\x00_\x00h\x00o\x00v\x00e\x00r\x00.\x00p\x00n\x00g\ +\x00\x1f\ +\x0a\xae'G\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00u\x00n\x00c\x00h\x00e\x00c\x00k\x00e\ +\x00d\x00_\x00d\x00i\x00s\x00a\x00b\x00l\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x14\ +\x04^-\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00_\x00o\x00n\x00.\ +\x00p\x00n\x00g\ +\x00\x11\ +\x0b\xda0\xa7\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00c\x00l\x00o\x00s\x00e\x00d\x00.\x00p\x00n\x00g\ +\ +\x00\x0e\ +\x0e\xde\xfa\xc7\ +\x00l\ +\x00e\x00f\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x11\ +\x01\x1f\xc3\x87\ +\x00d\ +\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\x00g\ +\ +\x00\x0f\ +\x02\x9f\x05\x87\ +\x00r\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00.\x00p\x00n\x00g\ +\x00\x12\ +\x05\x8f\x9d\x07\ +\x00b\ +\x00r\x00a\x00n\x00c\x00h\x00_\x00o\x00p\x00e\x00n\x00_\x00o\x00n\x00.\x00p\x00n\ +\x00g\ +\x00\x1a\ +\x01\x87\xaeg\ +\x00c\ +\x00h\x00e\x00c\x00k\x00b\x00o\x00x\x00_\x00i\x00n\x00d\x00e\x00t\x00e\x00r\x00m\ +\x00i\x00n\x00a\x00t\x00e\x00.\x00p\x00n\x00g\ +\x00\x17\ +\x0c\xabQ\x07\ +\x00d\ +\x00o\x00w\x00n\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00d\x00i\x00s\x00a\x00b\x00l\ +\x00e\x00d\x00.\x00p\x00n\x00g\ +\x00\x12\ +\x03\x8d\x04G\ +\x00r\ +\x00i\x00g\x00h\x00t\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\x00.\x00p\x00n\ +\x00g\ +\x00\x15\ +\x03'rg\ +\x00c\ +\x00o\x00m\x00b\x00o\x00b\x00o\x00x\x00_\x00a\x00r\x00r\x00o\x00w\x00_\x00o\x00n\ +\x00.\x00p\x00n\x00g\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x16\x00\x02\x00\x00\x00 \x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x02\xa6\x00\x00\x00\x00\x00\x01\x00\x00\x1aB\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x05 \x00\x00\x00\x00\x00\x01\x00\x00>k\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x00\xc6\x00\x00\x00\x00\x00\x01\x00\x00\x08\xd9\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x03F\x00\x00\x00\x00\x00\x01\x00\x00 ]\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x02.\x00\x00\x00\x00\x00\x01\x00\x00\x16\xfe\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x05\x96\x00\x00\x00\x00\x00\x01\x00\x00F\xec\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x05H\x00\x00\x00\x00\x00\x01\x00\x00?\x14\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x02\xce\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xec\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x06.\x00\x00\x00\x00\x00\x01\x00\x00J\x1a\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x01p\x00\x00\x00\x00\x00\x01\x00\x00\x13\xb1\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x06\x04\x00\x00\x00\x00\x00\x01\x00\x00Iv\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x01\xf8\x00\x00\x00\x00\x00\x01\x00\x00\x16Z\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x04\xa8\x00\x00\x00\x00\x00\x01\x00\x00./\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x09\x83\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x01\x12\x00\x00\x00\x00\x00\x01\x00\x00\x0a,\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x05l\x00\x00\x00\x00\x00\x01\x00\x00?\xb8\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x03\x88\x00\x00\x00\x00\x00\x01\x00\x00!\xa1\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x03j\x00\x00\x00\x00\x00\x01\x00\x00 \xff\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x01\xac\x00\x00\x00\x00\x00\x01\x00\x00\x14Z\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x00X\x00\x00\x00\x00\x00\x01\x00\x00\x00\xa3\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x03\x08\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x02\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x00\x86\x00\x00\x00\x00\x00\x01\x00\x00\x04\xa2\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x02`\x00\x00\x00\x00\x00\x01\x00\x00\x18]\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x04d\x00\x00\x00\x00\x00\x01\x00\x00,\xb5\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x04\xd6\x00\x00\x00\x00\x00\x01\x00\x006\x10\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x03\xf2\x00\x00\x00\x00\x00\x01\x00\x00*\x9e\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x05\xd0\x00\x00\x00\x00\x00\x01\x00\x00H\xcc\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x01L\x00\x00\x00\x00\x00\x01\x00\x00\x0e/\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x04&\x00\x00\x00\x00\x00\x01\x00\x00+H\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x04\xfe\x00\x00\x00\x00\x00\x01\x00\x00=\xc1\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x03\xac\x00\x00\x00\x00\x00\x01\x00\x00(\xab\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +\x00\x00\x00(\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x8c\x1b\xa4/\x10\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources()