void export_multistream_avi_info_attr( media_multistream_format::avi_info f, ExportContext& context) { context.writeAttr(gKey_us_per_frame, f.us_per_frame); context.writeAttr(gKey_width, (uint32)f.width); context.writeAttr(gKey_height, (uint32)f.height); }
void export_raw_video_content( const media_raw_video_format& f, ExportContext& context) { context.beginContent(); context.beginElement(MediaFormatIO::s_video_display_info_tag); export_video_display_info_attr(f.display, context); context.endElement(); }
void export_encoded_video_content( const media_encoded_video_format& f, ExportContext& context) { context.beginContent(); context.beginElement(MediaFormatIO::s_raw_video_tag); export_raw_video_attr(f.output, context); context.endElement(); }
// -------------------------------------------------------- // void ConnectionIO::xmlExportBegin( ExportContext& context) const { if(!m_exportValid) { context.reportError( "ConnectionIO::xmlExportBegin():\n" "*** invalid ***\n"); return; } context.beginElement(_CONNECTION_ELEMENT); }
void export_multistream_flags_attr( uint32 flags, ExportContext& context) { if(flags & media_multistream_format::B_HEADER_HAS_FLAGS) context.writeAttr(gKey_header_has_flags, (int32)1); if(flags & media_multistream_format::B_CLEAN_BUFFERS) context.writeAttr(gKey_clean_buffers, (int32)1); if(flags & media_multistream_format::B_HOMOGENOUS_BUFFERS) context.writeAttr(gKey_homogenous_buffers, (int32)1); }
void export_raw_video_attr( const media_raw_video_format& f, ExportContext& context) { media_raw_video_format& w = media_raw_video_format::wildcard; // attributes if(f.field_rate != w.field_rate) context.writeAttr(gKey_field_rate, f.field_rate); if(f.interlace != w.interlace) context.writeAttr(gKey_interlace, f.interlace); if(f.first_active != w.first_active) context.writeAttr(gKey_first_active, f.first_active); if(f.last_active != w.last_active) context.writeAttr(gKey_last_active, f.last_active); if(f.pixel_width_aspect != w.pixel_width_aspect) context.writeAttr(gKey_pixel_width_aspect, (uint32)f.pixel_width_aspect); if(f.pixel_height_aspect != w.pixel_height_aspect) context.writeAttr(gKey_pixel_height_aspect, (uint32)f.pixel_height_aspect); switch(f.orientation) { case B_VIDEO_TOP_LEFT_RIGHT: context.writeAttr(gKey_orientation, "B_VIDEO_TOP_LEFT_RIGHT"); break; case B_VIDEO_BOTTOM_LEFT_RIGHT: context.writeAttr(gKey_orientation, "B_VIDEO_BOTTOM_LEFT_RIGHT"); break; default: break; } }
void export_multistream_content( const media_multistream_format& f, ExportContext& context) { context.beginContent(); // write flags context.beginElement(MediaFormatIO::s_multistream_flags_tag); export_multistream_flags_attr(f.flags, context); context.endElement(); // write format-specific info if(f.format == media_multistream_format::B_VID) { context.beginElement(MediaFormatIO::s_multistream_vid_info_tag); export_multistream_vid_info_attr(f.u.vid, context); context.endElement(); } else if(f.format == media_multistream_format::B_AVI) { context.beginElement(MediaFormatIO::s_multistream_avi_info_tag); export_multistream_avi_info_attr(f.u.avi, context); context.beginContent(); export_multistream_avi_info_content(f.u.avi, context); context.endElement(); } }
void export_encoded_audio_content( const media_encoded_audio_format& f, ExportContext& context) { context.beginContent(); context.beginElement(MediaFormatIO::s_raw_audio_tag); export_raw_audio_attr(f.output, context); #if B_BEOS_VERSION > B_BEOS_VERSION_4_5 export_multi_audio_info_attr(f.multi_info, context); #endif context.endElement(); }
void export_multi_audio_info_attr( const media_multi_audio_info& f, ExportContext& context) { media_multi_audio_format& w = media_multi_audio_format::wildcard; if(f.channel_mask != w.channel_mask) context.writeAttr(gKey_channel_mask, f.channel_mask); if(f.valid_bits != w.valid_bits) context.writeAttr(gKey_valid_bits, f.valid_bits); if(f.matrix_mask != w.matrix_mask) context.writeAttr(gKey_matrix_mask, f.matrix_mask); }
void export_multistream_avi_info_content( media_multistream_format::avi_info f, ExportContext& context) { context.beginContent(); for(uint16 n = 0; n < f.type_count; ++n) write_media_type(f.types[n], context); }
__USE_CORTEX_NAMESPACE // -------------------------------------------------------- // // EXPORT [not implemented] // -------------------------------------------------------- // void StringContent::xmlExportBegin( ExportContext& context) const { context.reportError("StringContent: no export"); }
void FlatMessageIO::xmlExportContent( ExportContext& context) const { context.beginContent(); // convert message to base64 ASSERT(m_message); ssize_t flatSize = m_message->FlattenedSize(); ASSERT(flatSize); char* flatData = new char[flatSize]; status_t err = m_message->Flatten(flatData, flatSize); ASSERT(err == B_OK); // make plenty of room for encoded content (encode_base64 adds newlines) ssize_t base64Size = ((flatSize * 3) / 2); char* base64Data = new char[base64Size]; ssize_t base64Used = encode_base64(base64Data, flatData, flatSize); base64Data[base64Used] = '\0'; // write the data const char* pos = base64Data; while(*pos) { ssize_t chunk = 0; const char* nextBreak = strchr(pos, '\n'); if(!nextBreak) chunk = strlen(pos); else chunk = nextBreak - pos; context.writeString(context.indentString()); context.writeString(pos, chunk); context.writeString("\n"); pos += chunk; if(*pos == '\n') ++pos; } // clean up delete [] flatData; delete [] base64Data; }
void export_video_display_info_attr( const media_video_display_info& d, ExportContext& context) { media_video_display_info& w = media_video_display_info::wildcard; if(d.line_width != w.line_width) context.writeAttr(gKey_line_width, d.line_width); if(d.line_count != w.line_count) context.writeAttr(gKey_line_count, d.line_count); if(d.bytes_per_row != w.bytes_per_row) context.writeAttr(gKey_bytes_per_row, d.bytes_per_row); if(d.pixel_offset != w.pixel_offset) context.writeAttr(gKey_pixel_offset, d.pixel_offset); if(d.line_offset != w.line_offset) context.writeAttr(gKey_line_offset, d.line_offset); if(d.format != w.format) write_colorspace_attr(gKey_format, d.format, context); }
void export_encoded_audio_attr( const media_encoded_audio_format& f, ExportContext& context) { media_encoded_audio_format& w = media_encoded_audio_format::wildcard; switch(f.encoding) { case media_encoded_audio_format::B_ANY: context.writeAttr(gKey_encoding, "B_ANY"); break; default: break; } if(f.bit_rate != w.bit_rate) context.writeAttr(gKey_bit_rate, f.bit_rate); if(f.frame_size != w.frame_size) context.writeAttr(gKey_frame_size, f.frame_size); }
void export_encoded_video_attr( const media_encoded_video_format& f, ExportContext& context) { media_encoded_video_format& w = media_encoded_video_format::wildcard; switch(f.encoding) { case media_encoded_video_format::B_ANY: context.writeAttr(gKey_encoding, "B_ANY"); break; default: break; } if(f.avg_bit_rate != w.avg_bit_rate) context.writeAttr(gKey_avg_bit_rate, f.avg_bit_rate); if(f.max_bit_rate != w.max_bit_rate) context.writeAttr(gKey_max_bit_rate, f.max_bit_rate); if(f.frame_size != w.frame_size) context.writeAttr(gKey_frame_size, f.frame_size); if(f.forward_history != w.forward_history) context.writeAttr(gKey_forward_history, (int32)f.forward_history); if(f.backward_history != w.backward_history) context.writeAttr(gKey_backward_history, (int32)f.backward_history); }
void MediaFormatIO::xmlExportBegin( ExportContext& context) const { switch(m_format.type) { case B_MEDIA_RAW_AUDIO: context.beginElement(s_raw_audio_tag); break; case B_MEDIA_RAW_VIDEO: context.beginElement(s_raw_video_tag); break; case B_MEDIA_MULTISTREAM: context.beginElement(s_multistream_tag); break; case B_MEDIA_ENCODED_AUDIO: context.beginElement(s_encoded_audio_tag); break; case B_MEDIA_ENCODED_VIDEO: context.beginElement(s_encoded_video_tag); break; default: // +++++ not very polite context.reportError("MediaFormatIO: type not supported\n"); break; } }
void RouteAppNodeManager::xmlExportBegin( ExportContext& context) const { status_t err; try { NodeSetIOContext& set = dynamic_cast<NodeSetIOContext&>(context); context.beginElement(_NODE_SET_ELEMENT); // validate the node set for(int n = set.countNodes()-1; n >= 0; --n) { media_node_id id = set.nodeAt(n); ASSERT(id != media_node::null.node); // fetch node NodeRef* ref; err = getNodeRef(id, &ref); if(err < B_OK) { D_SETTINGS(( "! RVNM::xmlExportBegin(): node %ld doesn't exist\n", id)); set.removeNodeAt(n); continue; } // skip unless internal if(!ref->isInternal()) { D_SETTINGS(( "! RVNM::xmlExportBegin(): node %ld not internal; skipping.\n", id)); set.removeNodeAt(n); continue; } } } catch(bad_cast& e) { context.reportError("RouteAppNodeManager: expected a NodeSetIOContext\n"); } }
void export_raw_audio_attr( const media_raw_audio_format& f, ExportContext& context) { media_raw_audio_format& w = media_raw_audio_format::wildcard; if(f.frame_rate != w.frame_rate) context.writeAttr(gKey_frame_rate, f.frame_rate); if(f.channel_count != w.channel_count) context.writeAttr(gKey_channel_count, f.channel_count); if(f.buffer_size != w.buffer_size) context.writeAttr(gKey_buffer_size, f.buffer_size); switch(f.format) { case media_raw_audio_format::B_AUDIO_UCHAR: context.writeAttr(gKey_format, "B_AUDIO_UCHAR"); break; case media_raw_audio_format::B_AUDIO_SHORT: context.writeAttr(gKey_format, "B_AUDIO_SHORT"); break; case media_raw_audio_format::B_AUDIO_FLOAT: context.writeAttr(gKey_format, "B_AUDIO_FLOAT"); break; case media_raw_audio_format::B_AUDIO_INT: context.writeAttr(gKey_format, "B_AUDIO_INT"); break; default: break; } switch(f.byte_order) { case B_MEDIA_BIG_ENDIAN: context.writeAttr(gKey_byte_order, "B_MEDIA_BIG_ENDIAN"); break; case B_MEDIA_LITTLE_ENDIAN: context.writeAttr(gKey_byte_order, "B_MEDIA_LITTLE_ENDIAN"); break; default: break; } }
void export_multistream_attr( const media_multistream_format& f, ExportContext& context) { media_multistream_format& w = media_multistream_format::wildcard; // attributes switch(f.format) { case media_multistream_format::B_ANY: context.writeAttr(gKey_multistream_format, "B_ANY"); break; case media_multistream_format::B_VID: context.writeAttr(gKey_multistream_format, "B_VID"); break; case media_multistream_format::B_AVI: context.writeAttr(gKey_multistream_format, "B_AVI"); break; case media_multistream_format::B_MPEG1: context.writeAttr(gKey_multistream_format, "B_MPEG1"); break; case media_multistream_format::B_MPEG2: context.writeAttr(gKey_multistream_format, "B_MPEG2"); break; case media_multistream_format::B_QUICKTIME: context.writeAttr(gKey_multistream_format, "B_QUICKTIME"); break; default: if(f.format != w.format) { // write numeric value context.writeAttr(gKey_multistream_format, f.format); } break; } if(f.avg_bit_rate != w.avg_bit_rate) context.writeAttr(gKey_avg_bit_rate, f.avg_bit_rate); if(f.max_bit_rate != w.max_bit_rate) context.writeAttr(gKey_max_bit_rate, f.max_bit_rate); if(f.avg_chunk_size != w.avg_chunk_size) context.writeAttr(gKey_avg_chunk_size, f.avg_chunk_size); if(f.max_chunk_size != w.max_chunk_size) context.writeAttr(gKey_max_chunk_size, f.max_chunk_size); }
void MediaFormatIO::xmlExportEnd( ExportContext& context) const { context.endElement(); }
void StringContent::xmlExportEnd( ExportContext& context) const { context.reportError("StringContent: no export"); }
void NodeKey::xmlExportEnd( ExportContext& context) const { context.endElement(); }
void write_colorspace_attr( const char* key, color_space c, ExportContext& context) { switch(c) { case B_RGB32: context.writeAttr(key, "B_RGB32"); break; case B_RGBA32: context.writeAttr(key, "B_RGBA32"); break; case B_RGB24: context.writeAttr(key, "B_RGB24"); break; case B_RGB16: context.writeAttr(key, "B_RGB16"); break; case B_RGB15: context.writeAttr(key, "B_RGB15"); break; case B_RGBA15: context.writeAttr(key, "B_RGBA15"); break; case B_CMAP8: context.writeAttr(key, "B_CMAP8"); break; case B_GRAY8: context.writeAttr(key, "B_GRAY8"); break; case B_GRAY1: context.writeAttr(key, "B_GRAY1"); break; case B_RGB32_BIG: context.writeAttr(key, "B_RGB32_BIG"); break; case B_RGBA32_BIG: context.writeAttr(key, "B_RGBA32_BIG"); break; case B_RGB24_BIG: context.writeAttr(key, "B_RGB24_BIG"); break; case B_RGB16_BIG: context.writeAttr(key, "B_RGB16_BIG"); break; case B_RGB15_BIG: context.writeAttr(key, "B_RGB15_BIG"); break; case B_RGBA15_BIG: context.writeAttr(key, "B_RGBA15_BIG"); break; case B_YCbCr422: context.writeAttr(key, "B_YCbCr422"); break; case B_YCbCr411: context.writeAttr(key, "B_YCbCr411"); break; case B_YCbCr444: context.writeAttr(key, "B_YCbCr444"); break; case B_YCbCr420: context.writeAttr(key, "B_YCbCr420"); break; case B_YUV422: context.writeAttr(key, "B_YUV422"); break; case B_YUV411: context.writeAttr(key, "B_YUV411"); break; case B_YUV444: context.writeAttr(key, "B_YUV444"); break; case B_YUV420: context.writeAttr(key, "B_YUV420"); break; case B_YUV9: context.writeAttr(key, "B_YUV9"); break; case B_YUV12: context.writeAttr(key, "B_YUV12"); break; case B_UVL24: context.writeAttr(key, "B_UVL24"); break; case B_UVL32: context.writeAttr(key, "B_UVL32"); break; case B_UVLA32: context.writeAttr(key, "B_UVLA32"); break; case B_LAB24: context.writeAttr(key, "B_LAB24"); break; case B_LAB32: context.writeAttr(key, "B_LAB32"); break; case B_LABA32: context.writeAttr(key, "B_LABA32"); break; case B_HSI24: context.writeAttr(key, "B_HSI24"); break; case B_HSI32: context.writeAttr(key, "B_HSI32"); break; case B_HSIA32: context.writeAttr(key, "B_HSIA32"); break; case B_HSV24: context.writeAttr(key, "B_HSV24"); break; case B_HSV32: context.writeAttr(key, "B_HSV32"); break; case B_HSVA32: context.writeAttr(key, "B_HSVA32"); break; case B_HLS24: context.writeAttr(key, "B_HLS24"); break; case B_HLS32: context.writeAttr(key, "B_HLS32"); break; case B_HLSA32: context.writeAttr(key, "B_HLSA32"); break; case B_CMY24: context.writeAttr(key, "B_CMY24"); break; case B_CMY32: context.writeAttr(key, "B_CMY32"); break; case B_CMYA32: context.writeAttr(key, "B_CMYA32"); break; case B_CMYK32: context.writeAttr(key, "B_CMYK32"); break; default: break; } }
void ConnectionIO::xmlExportContent( ExportContext& context) const { context.beginContent(); // write output { context.beginElement(_OUTPUT_ELEMENT); context.beginContent(); // describe the node // LiveNodeIO nodeIO( // m_manager, // dynamic_cast<NodeSetIOContext*>(&context), // m_outputNode); context.writeObject(m_outputNodeIO); // context.beginElement(_LIVE_NODE_ELEMENT); // if(m_outputNodeKey.Length()) { // context.writeAttr("key", m_outputNodeKey); // } // else { // _write_simple("name", m_outputNodeName.String(), context); // _write_node_kinds(m_outputNodeKind, context); // } // context.endElement(); // _LIVE_NODE_ELEMENT // describe the output _write_simple("name", m_outputName.String(), context); if(m_outputFormat.type > B_MEDIA_UNKNOWN_TYPE) { MediaFormatIO io(m_outputFormat); context.writeObject(&io); } context.endElement(); // _OUTPUT_ELEMENT } // write input { context.beginElement(_INPUT_ELEMENT); context.beginContent(); // describe the node // LiveNodeIO nodeIO( // m_manager, // dynamic_cast<NodeSetIOContext*>(&context), // m_inputNode); context.writeObject(m_inputNodeIO); // context.beginElement(_LIVE_NODE_ELEMENT); // if(m_inputNodeKey.Length()) { // context.writeAttr("key", m_inputNodeKey); // } // else { // _write_simple("name", m_inputNodeName.String(), context); // _write_node_kinds(m_inputNodeKind, context); // } // context.endElement(); // _LIVE_NODE_ELEMENT // describe the input _write_simple("name", m_inputName.String(), context); if(m_inputFormat.type > B_MEDIA_UNKNOWN_TYPE) { MediaFormatIO io(m_inputFormat); context.writeObject(&io); } context.endElement(); // _INPUT_ELEMENT } // write requested format if(m_requestedFormat.type > B_MEDIA_UNKNOWN_TYPE) { MediaFormatIO io(m_requestedFormat); BString comment = "\n"; comment << context.indentString(); comment << "<!-- initial requested format -->"; context.writeString(comment); context.writeObject(&io); } }
static void ExportMeshLod(ExportContext& Context, const CBaseMeshLod& Lod, const CMeshVertex* Verts, FArchive& Ar, FArchive& Ar2) { guard(ExportMeshLod); // Opening brace Ar.Printf("{\n"); // Asset Ar.Printf( " \"asset\" : {\n" " \"generator\" : \"UE Viewer (umodel) build %s\",\n" " \"version\" : \"2.0\"\n" " },\n", STR(GIT_REVISION)); // Scene Ar.Printf( " \"scene\" : 0,\n" " \"scenes\" : [\n" " {\n" " \"nodes\" : [ 0 ]\n" " }\n" " ],\n" ); // Nodes if (!Context.IsSkeletal()) { Ar.Printf( " \"nodes\" : [\n" " {\n" " \"name\" : \"%s\",\n" " \"mesh\" : 0\n" " }\n" " ],\n", Context.MeshName ); } else { ExportSkinData(Context, static_cast<const CSkelMeshLod&>(Lod), Ar); } // Materials Ar.Printf(" \"materials\" : [\n"); for (int i = 0; i < Lod.Sections.Num(); i++) { ExportMaterial(Lod.Sections[i].Material, Ar, i, i == Lod.Sections.Num() - 1); } Ar.Printf(" ],\n"); // Meshes Ar.Printf( " \"meshes\" : [\n" " {\n" " \"primitives\" : [\n" ); for (int i = 0; i < Lod.Sections.Num(); i++) { ExportSection(Context, Lod, Verts, i, Ar); } Ar.Printf( " ],\n" " \"name\" : \"%s\"\n" " }\n" " ],\n", Context.MeshName ); // Write animations if (Context.IsSkeletal() && Context.SkelMesh->Anim) { ExportAnimations(Context, Ar); } // Write buffers int bufferLength = 0; for (int i = 0; i < Context.Data.Num(); i++) { bufferLength += Context.Data[i].DataSize; } Ar.Printf( " \"buffers\" : [\n" " {\n" " \"uri\" : \"%s.bin\",\n" " \"byteLength\" : %d\n" " }\n" " ],\n", Context.MeshName, bufferLength ); // Write bufferViews Ar.Printf( " \"bufferViews\" : [\n" ); int bufferOffset = 0; for (int i = 0; i < Context.Data.Num(); i++) { const BufferData& B = Context.Data[i]; Ar.Printf( " {\n" " \"buffer\" : 0,\n" " \"byteOffset\" : %d,\n" " \"byteLength\" : %d\n" " }%s\n", bufferOffset, B.DataSize, i == (Context.Data.Num()-1) ? "" : "," ); bufferOffset += B.DataSize; } Ar.Printf( " ],\n" ); // Write accessors Ar.Printf( " \"accessors\" : [\n" ); for (int i = 0; i < Context.Data.Num(); i++) { const BufferData& B = Context.Data[i]; Ar.Printf( " {\n" " \"bufferView\" : %d,\n", i ); if (B.bNormalized) { Ar.Printf(" \"normalized\" : true,\n"); } if (B.BoundsMin.Len()) { Ar.Printf( " \"min\" : %s,\n" " \"max\" : %s,\n", *B.BoundsMin, *B.BoundsMax ); } Ar.Printf( " \"componentType\" : %d,\n" " \"count\" : %d,\n" " \"type\" : \"%s\"\n" " }%s\n", B.ComponentType, B.Count, B.Type, i == (Context.Data.Num()-1) ? "" : "," ); } Ar.Printf( " ]\n" ); // Write binary data guard(WriteBIN); for (int i = 0; i < Context.Data.Num(); i++) { const BufferData& B = Context.Data[i]; #if MAX_DEBUG assert(B.FillCount == B.Count); #endif Ar2.Serialize(B.Data, B.DataSize); } unguard; // Closing brace Ar.Printf("}\n"); unguard; }
void export_multistream_vid_info_attr( media_multistream_format::vid_info f, ExportContext& context) { // +++++ no wildcard to compare against (assume 0 == wildcard?) context.writeAttr(gKey_frame_rate, f.frame_rate); context.writeAttr(gKey_width, (uint32)f.width); context.writeAttr(gKey_height, (uint32)f.height); write_colorspace_attr(gKey_space, f.space, context); context.writeAttr(gKey_sampling_rate, f.sampling_rate); switch(f.sample_format) { case B_UNDEFINED_SAMPLES: context.writeAttr(gKey_sample_format, "B_UNDEFINED_SAMPLES"); break; case B_LINEAR_SAMPLES: context.writeAttr(gKey_sample_format, "B_LINEAR_SAMPLES"); break; case B_FLOAT_SAMPLES: context.writeAttr(gKey_sample_format, "B_FLOAT_SAMPLES"); break; case B_MULAW_SAMPLES: context.writeAttr(gKey_sample_format, "B_MULAW_SAMPLES"); break; default: break; } switch(f.byte_order) { case B_MEDIA_BIG_ENDIAN: context.writeAttr(gKey_byte_order, "B_MEDIA_BIG_ENDIAN"); break; case B_MEDIA_LITTLE_ENDIAN: context.writeAttr(gKey_byte_order, "B_MEDIA_LITTLE_ENDIAN"); break; default: break; } context.writeAttr(gKey_channel_count, (uint32)f.channel_count); }
void ConnectionIO::xmlExportEnd( ExportContext& context) const { context.endElement(); // _CONNECTION_ELEMENT }
void write_media_type( media_type t, ExportContext& context) { context.beginElement(MediaFormatIO::s_media_type_tag); context.beginContent(); switch(t) { case B_MEDIA_NO_TYPE: context.writeString("B_MEDIA_NO_TYPE"); break; case B_MEDIA_UNKNOWN_TYPE: context.writeString("B_MEDIA_UNKNOWN_TYPE"); break; case B_MEDIA_RAW_AUDIO: context.writeString("B_MEDIA_RAW_AUDIO"); break; case B_MEDIA_RAW_VIDEO: context.writeString("B_MEDIA_RAW_VIDEO"); break; case B_MEDIA_VBL: context.writeString("B_MEDIA_VBL"); break; case B_MEDIA_TIMECODE: context.writeString("B_MEDIA_TIMECODE"); break; case B_MEDIA_MIDI: context.writeString("B_MEDIA_MIDI"); break; case B_MEDIA_TEXT: context.writeString("B_MEDIA_TEXT"); break; case B_MEDIA_HTML: context.writeString("B_MEDIA_HTML"); break; case B_MEDIA_MULTISTREAM: context.writeString("B_MEDIA_MULTISTREAM"); break; case B_MEDIA_PARAMETERS: context.writeString("B_MEDIA_PARAMETERS"); break; case B_MEDIA_ENCODED_AUDIO: context.writeString("B_MEDIA_ENCODED_AUDIO"); break; case B_MEDIA_ENCODED_VIDEO: context.writeString("B_MEDIA_ENCODED_VIDEO"); break; default: { BString val; val << (uint32)t; context.writeString(val); } } context.endElement(); }
static void ExportSection(ExportContext& Context, const CBaseMeshLod& Lod, const CMeshVertex* Verts, int SectonIndex, FArchive& Ar) { guard(ExportSection); int VertexSize = Context.IsSkeletal() ? sizeof(CSkelMeshVertex) : sizeof(CStaticMeshVertex); const CMeshSection& S = Lod.Sections[SectonIndex]; bool bLast = (SectonIndex == Lod.Sections.Num()-1); // Remap section indices to local indices CIndexBuffer::IndexAccessor_t GetIndex = Lod.Indices.GetAccessor(); TArray<int> indexRemap; // old vertex index -> new vertex index indexRemap.Init(-1, Lod.NumVerts); int numLocalVerts = 0; int numLocalIndices = S.NumFaces * 3; for (int idx = 0; idx < numLocalIndices; idx++) { int vertIndex = GetIndex(S.FirstIndex + idx); if (indexRemap[vertIndex] == -1) { indexRemap[vertIndex] = numLocalVerts++; } } // Prepare buffers int IndexBufIndex = Context.Data.AddZeroed(); int PositionBufIndex = Context.Data.AddZeroed(); int NormalBufIndex = Context.Data.AddZeroed(); int TangentBufIndex = Context.Data.AddZeroed(); int BonesBufIndex = -1; int WeightsBufIndex = -1; if (Context.IsSkeletal()) { BonesBufIndex = Context.Data.AddZeroed(); WeightsBufIndex = Context.Data.AddZeroed(); } int UVBufIndex[MAX_MESH_UV_SETS]; for (int i = 0; i < Lod.NumTexCoords; i++) { UVBufIndex[i] = Context.Data.AddZeroed(); } BufferData& IndexBuf = Context.Data[IndexBufIndex]; BufferData& PositionBuf = Context.Data[PositionBufIndex]; BufferData& NormalBuf = Context.Data[NormalBufIndex]; BufferData& TangentBuf = Context.Data[TangentBufIndex]; BufferData* UVBuf[MAX_MESH_UV_SETS]; BufferData* BonesBuf = NULL; BufferData* WeightsBuf = NULL; PositionBuf.Setup(numLocalVerts, "VEC3", BufferData::FLOAT, sizeof(CVec3)); NormalBuf.Setup(numLocalVerts, "VEC3", BufferData::FLOAT, sizeof(CVec3)); TangentBuf.Setup(numLocalVerts, "VEC4", BufferData::FLOAT, sizeof(CVec4)); for (int i = 0; i < Lod.NumTexCoords; i++) { UVBuf[i] = &Context.Data[UVBufIndex[i]]; UVBuf[i]->Setup(numLocalVerts, "VEC2", BufferData::FLOAT, sizeof(CMeshUVFloat)); } if (Context.IsSkeletal()) { BonesBuf = &Context.Data[BonesBufIndex]; WeightsBuf = &Context.Data[WeightsBufIndex]; BonesBuf->Setup(numLocalVerts, "VEC4", BufferData::UNSIGNED_SHORT, sizeof(uint16)*4); WeightsBuf->Setup(numLocalVerts, "VEC4", BufferData::UNSIGNED_BYTE, sizeof(uint32), /*InNormalized=*/ true); } // Prepare and build indices TArray<int> localIndices; localIndices.AddUninitialized(numLocalIndices); int* pIndex = localIndices.GetData(); for (int i = 0; i < numLocalIndices; i++) { *pIndex++ = GetIndex(S.FirstIndex + i); } if (numLocalVerts <= 65536) { IndexBuf.Setup(numLocalIndices, "SCALAR", BufferData::UNSIGNED_SHORT, sizeof(uint16)); for (int idx = 0; idx < numLocalIndices; idx++) { IndexBuf.Put<uint16>(indexRemap[localIndices[idx]]); } } else { IndexBuf.Setup(numLocalIndices, "SCALAR", BufferData::UNSIGNED_INT, sizeof(uint32)); for (int idx = 0; idx < numLocalIndices; idx++) { IndexBuf.Put<uint32>(indexRemap[localIndices[idx]]); } } // Build reverse index map for fast lookup of vertex by its new index. // It maps new vertex index to old vertex index. TArray<int> revIndexMap; revIndexMap.AddUninitialized(numLocalVerts); for (int i = 0; i < indexRemap.Num(); i++) { int newIndex = indexRemap[i]; if (newIndex != -1) { revIndexMap[newIndex] = i; } } // Build vertices for (int i = 0; i < numLocalVerts; i++) { int vertIndex = revIndexMap[i]; const CMeshVertex& V = VERT(vertIndex); CVec3 Position = V.Position; CVec4 Normal, Tangent; Unpack(Normal, V.Normal); Unpack(Tangent, V.Tangent); // Unreal (and we are) using normal.w for computing binormal. glTF // uses tangent.w for that. Make this value exactly 1.0 of -1.0 to make glTF // validator happy. #if 0 // There's some problem: V.Normal.W == 0x80 -> -1.008 instead of -1.0 if (Normal.w > 1.001 || Normal.w < -1.001) { appError("%X -> %g\n", V.Normal.Data, Normal.w); } #endif Tangent.w = (Normal.w < 0) ? -1 : 1; TransformPosition(Position); TransformDirection(Normal); TransformDirection(Tangent); Normal.Normalize(); Tangent.Normalize(); // Fill buffers PositionBuf.Put(Position); NormalBuf.Put(Normal.xyz); TangentBuf.Put(Tangent); UVBuf[0]->Put(V.UV); } // Compute bounds for PositionBuf CVec3 Mins, Maxs; ComputeBounds((CVec3*)PositionBuf.Data, numLocalVerts, sizeof(CVec3), Mins, Maxs); char buf[256]; appSprintf(ARRAY_ARG(buf), "[ %g, %g, %g ]", VECTOR_ARG(Mins)); PositionBuf.BoundsMin = buf; appSprintf(ARRAY_ARG(buf), "[ %g, %g, %g ]", VECTOR_ARG(Maxs)); PositionBuf.BoundsMax = buf; if (Context.IsSkeletal()) { for (int i = 0; i < numLocalVerts; i++) { int vertIndex = revIndexMap[i]; const CMeshVertex& V0 = VERT(vertIndex); const CSkelMeshVertex& V = static_cast<const CSkelMeshVertex&>(V0); int16 Bones[NUM_INFLUENCES]; static_assert(NUM_INFLUENCES == 4, "Code designed for 4 influences"); static_assert(sizeof(Bones) == sizeof(V.Bone), "Unexpected V.Bones size"); memcpy(Bones, V.Bone, sizeof(Bones)); for (int j = 0; j < NUM_INFLUENCES; j++) { // We have INDEX_NONE as list terminator, should replace with something else for glTF if (Bones[j] == INDEX_NONE) { Bones[j] = 0; } } BonesBuf->Put(*(uint64*)&Bones); WeightsBuf->Put(V.PackedWeights); } } // Secondary UVs for (int uvIndex = 1; uvIndex < Lod.NumTexCoords; uvIndex++) { BufferData* pBuf = UVBuf[uvIndex]; const CMeshUVFloat* srcUV = Lod.ExtraUV[uvIndex-1]; for (int i = 0; i < numLocalVerts; i++) { int vertIndex = revIndexMap[i]; pBuf->Put(srcUV[vertIndex]); } } // Write primitive information to json Ar.Printf( " {\n" " \"attributes\" : {\n" " \"POSITION\" : %d,\n" " \"NORMAL\" : %d,\n" " \"TANGENT\" : %d,\n", PositionBufIndex, NormalBufIndex, TangentBufIndex ); if (Context.IsSkeletal()) { Ar.Printf( " \"JOINTS_0\" : %d,\n" " \"WEIGHTS_0\" : %d,\n", BonesBufIndex, WeightsBufIndex ); } for (int i = 0; i < Lod.NumTexCoords; i++) { Ar.Printf( " \"TEXCOORD_%d\" : %d%s\n", i, UVBufIndex[i], i < (Lod.NumTexCoords-1) ? "," : "" ); } Ar.Printf( " },\n" " \"indices\" : %d,\n" " \"material\" : %d\n" " }%s\n", IndexBufIndex, SectonIndex, SectonIndex < (Lod.Sections.Num()-1) ? "," : "" ); unguard; }
static void ExportAnimations(ExportContext& Context, FArchive& Ar) { guard(ExportAnimations); const CAnimSet* Anim = Context.SkelMesh->Anim; int NumBones = Context.SkelMesh->RefSkeleton.Num(); // Build mesh to anim bone map TArray<int> BoneMap; BoneMap.Init(-1, NumBones); TArray<int> AnimBones; AnimBones.Empty(NumBones); for (int i = 0; i < NumBones; i++) { const CSkelMeshBone &B = Context.SkelMesh->RefSkeleton[i]; for (int j = 0; j < Anim->TrackBoneNames.Num(); j++) { if (!stricmp(B.Name, Anim->TrackBoneNames[j])) { BoneMap[i] = j; // lookup CAnimSet bone by mesh bone index AnimBones.Add(i); // indicate that the bone has animation break; } } } Ar.Printf( " \"animations\" : [\n" ); int FirstDataIndex = Context.Data.Num(); // Iterate over all animations for (int SeqIndex = 0; SeqIndex < Anim->Sequences.Num(); SeqIndex++) { const CAnimSequence &Seq = *Anim->Sequences[SeqIndex]; Ar.Printf( " {\n" " \"name\" : \"%s\",\n", *Seq.Name ); struct AnimSampler { enum ChannelType { TRANSLATION, ROTATION }; int BoneNodeIndex; ChannelType Type; const CAnimTrack* Track; }; TArray<AnimSampler> Samplers; Samplers.Empty(AnimBones.Num() * 2); //!! Optimization: //!! 1. there will be missing tracks (AnimRotationOnly etc) - drop such samplers //!! 2. store all time tracks in a single BufferView, all rotation tracks in another, and all position track in 3rd one - this //!! will reduce amount of BufferViews in json text (combine them by data type) // Prepare channels array Ar.Printf(" \"channels\" : [\n"); for (int BoneIndex = 0; BoneIndex < AnimBones.Num(); BoneIndex++) { int MeshBoneIndex = AnimBones[BoneIndex]; int AnimBoneIndex = BoneMap[MeshBoneIndex]; const CAnimTrack* Track = Seq.Tracks[AnimBoneIndex]; int TranslationSamplerIndex = Samplers.Num(); AnimSampler* Sampler = new (Samplers) AnimSampler; Sampler->Type = AnimSampler::TRANSLATION; Sampler->BoneNodeIndex = MeshBoneIndex + FIRST_BONE_NODE; Sampler->Track = Track; int RotationSamplerIndex = Samplers.Num(); Sampler = new (Samplers) AnimSampler; Sampler->Type = AnimSampler::ROTATION; Sampler->BoneNodeIndex = MeshBoneIndex + FIRST_BONE_NODE; Sampler->Track = Track; // Print glTF information. Not using usual formatting here to make output a little bit more compact. Ar.Printf( " { \"sampler\" : %d, \"target\" : { \"node\" : %d, \"path\" : \"%s\" } },\n", TranslationSamplerIndex, MeshBoneIndex + FIRST_BONE_NODE, "translation" ); Ar.Printf( " { \"sampler\" : %d, \"target\" : { \"node\" : %d, \"path\" : \"%s\" } }%s\n", RotationSamplerIndex, MeshBoneIndex + FIRST_BONE_NODE, "rotation", BoneIndex == AnimBones.Num()-1 ? "" : "," ); } Ar.Printf(" ],\n"); // Prepare samplers Ar.Printf(" \"samplers\" : [\n"); for (int SamplerIndex = 0; SamplerIndex < Samplers.Num(); SamplerIndex++) { const AnimSampler& Sampler = Samplers[SamplerIndex]; // Prepare time array const TArray<float>* TimeArray = (Sampler.Type == AnimSampler::TRANSLATION) ? &Sampler.Track->KeyPosTime : &Sampler.Track->KeyQuatTime; if (TimeArray->Num() == 0) { // For this situation, use track's time array TimeArray = &Sampler.Track->KeyTime; } int NumKeys = Sampler.Type == (AnimSampler::TRANSLATION) ? Sampler.Track->KeyPos.Num() : Sampler.Track->KeyQuat.Num(); int TimeBufIndex = Context.Data.AddZeroed(); BufferData& TimeBuf = Context.Data[TimeBufIndex]; TimeBuf.Setup(NumKeys, "SCALAR", BufferData::FLOAT, sizeof(float)); float RateScale = 1.0f / Seq.Rate; float LastFrameTime = 0; if (TimeArray->Num() == 0 || NumKeys == 1) { // Fill with equally spaced values for (int i = 0; i < NumKeys; i++) { TimeBuf.Put(i * RateScale); } LastFrameTime = NumKeys-1; } else { for (int i = 0; i < TimeArray->Num(); i++) { TimeBuf.Put((*TimeArray)[i] * RateScale); } LastFrameTime = (*TimeArray)[TimeArray->Num()-1]; } // Prepare min/max values for time track, it's required by glTF standard TimeBuf.BoundsMin = "[ 0 ]"; char buf[64]; appSprintf(ARRAY_ARG(buf), "[ %g ]", LastFrameTime * RateScale); TimeBuf.BoundsMax = buf; // Try to reuse TimeBuf from previous tracks TimeBufIndex = Context.GetFinalIndexForLastBlock(FirstDataIndex); // Prepare data int DataBufIndex = Context.Data.AddZeroed(); BufferData& DataBuf = Context.Data[DataBufIndex]; if (Sampler.Type == AnimSampler::TRANSLATION) { // Translation track DataBuf.Setup(NumKeys, "VEC3", BufferData::FLOAT, sizeof(CVec3)); for (int i = 0; i < NumKeys; i++) { CVec3 Pos = Sampler.Track->KeyPos[i]; TransformPosition(Pos); DataBuf.Put(Pos); } } else { // Rotation track DataBuf.Setup(NumKeys, "VEC4", BufferData::FLOAT, sizeof(CQuat)); for (int i = 0; i < NumKeys; i++) { CQuat Rot = Sampler.Track->KeyQuat[i]; TransformRotation(Rot); if (Sampler.BoneNodeIndex - FIRST_BONE_NODE == 0) { Rot.Conjugate(); } DataBuf.Put(Rot); } } // Try to reuse data block as well DataBufIndex = Context.GetFinalIndexForLastBlock(FirstDataIndex); // Write glTF info Ar.Printf( " { \"input\" : %d, \"output\" : %d }%s\n", TimeBufIndex, DataBufIndex, SamplerIndex == Samplers.Num()-1 ? "" : "," ); } Ar.Printf(" ]\n"); Ar.Printf(" }%s\n", SeqIndex == Anim->Sequences.Num()-1 ? "" : ","); } Ar.Printf(" ],\n"); unguard; }