Repository: ousnius/BodySlide-and-Outfit-Studio Branch: dev Commit: ea1432f31995 Files: 845 Total size: 8.8 MB Directory structure: gitextract_0z1ve9fu/ ├── .clang-format ├── .github/ │ └── ISSUE_TEMPLATE/ │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .gitmodules ├── BS_OS.sln ├── BodySlide.manifest ├── BodySlide.rc ├── BodySlide.vcxproj ├── BodySlide.vcxproj.filters ├── BodySlide.xml ├── BuildSelection.xml ├── CMakeLists.txt ├── CONTRIBUTING.md ├── Config.xml ├── LICENSE ├── OutfitStudio.manifest ├── OutfitStudio.rc ├── OutfitStudio.vcxproj ├── OutfitStudio.vcxproj.filters ├── OutfitStudio.xml ├── README.md ├── Readme-linux.txt ├── RefTemplates.xml ├── Resource.h ├── lang/ │ ├── BodySlide.pot │ ├── af/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── an/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ar/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ca/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── cs/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── da/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── de/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── el/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── es/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── eu/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── fi/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── fr/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── hi/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── hu/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── id/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── it/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ja/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ko/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── lt/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── lv/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ms/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── nb/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ne/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── nl/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── pl/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── pt/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ro/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ru/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── sk/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── sl/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── sq/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── sv/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── ta/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── tr/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── uk/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── vi/ │ │ ├── BodySlide.mo │ │ └── BodySlide.po │ ├── xrctext.cpp │ └── zh/ │ ├── BodySlide.mo │ └── BodySlide.po ├── lib/ │ ├── DDS.h │ ├── FSEngine/ │ │ ├── FSBSA.cpp │ │ ├── FSBSA.h │ │ ├── FSEngine.cpp │ │ ├── FSEngine.h │ │ ├── FSManager.cpp │ │ └── FSManager.h │ ├── LZ4F/ │ │ ├── lz4.c │ │ ├── lz4.h │ │ ├── lz4file.c │ │ ├── lz4file.h │ │ ├── lz4frame.c │ │ ├── lz4frame.h │ │ ├── lz4frame_static.h │ │ ├── lz4hc.c │ │ ├── lz4hc.h │ │ ├── xxhash.c │ │ └── xxhash.h │ ├── SOIL2/ │ │ ├── SOIL2.c │ │ ├── SOIL2.h │ │ ├── image_DXT.c │ │ ├── image_DXT.h │ │ ├── image_helper.c │ │ ├── image_helper.h │ │ ├── pkm_helper.h │ │ ├── pvr_helper.h │ │ ├── stb_image.h │ │ ├── stb_image_write.h │ │ ├── stbi_DDS.h │ │ ├── stbi_DDS_c.h │ │ ├── stbi_ext.h │ │ ├── stbi_ext_c.h │ │ ├── stbi_pkm.h │ │ ├── stbi_pkm_c.h │ │ ├── stbi_pvr.h │ │ ├── stbi_pvr_c.h │ │ ├── stbi_qoi.h │ │ ├── stbi_qoi_c.h │ │ ├── stbi_qoi_write.h │ │ ├── wfETC.c │ │ └── wfETC.h │ ├── TinyXML-2/ │ │ ├── tinyxml2.cpp │ │ └── tinyxml2.h │ ├── fkYAML/ │ │ └── include/ │ │ └── fkYAML/ │ │ ├── fkyaml_fwd.hpp │ │ └── node.hpp │ ├── gli/ │ │ ├── clear.hpp │ │ ├── comparison.hpp │ │ ├── convert.hpp │ │ ├── copy.hpp │ │ ├── core/ │ │ │ ├── bc.hpp │ │ │ ├── bc.inl │ │ │ ├── clear.hpp │ │ │ ├── clear.inl │ │ │ ├── comparison.inl │ │ │ ├── convert.inl │ │ │ ├── convert_func.hpp │ │ │ ├── coord.hpp │ │ │ ├── copy.inl │ │ │ ├── dummy.cpp │ │ │ ├── duplicate.inl │ │ │ ├── dx.inl │ │ │ ├── file.hpp │ │ │ ├── file.inl │ │ │ ├── filter.hpp │ │ │ ├── filter.inl │ │ │ ├── filter_compute.hpp │ │ │ ├── flip.hpp │ │ │ ├── flip.inl │ │ │ ├── format.inl │ │ │ ├── generate_mipmaps.inl │ │ │ ├── gl.inl │ │ │ ├── image.inl │ │ │ ├── levels.inl │ │ │ ├── load.inl │ │ │ ├── load_dds.inl │ │ │ ├── load_kmg.inl │ │ │ ├── load_ktx.inl │ │ │ ├── make_texture.inl │ │ │ ├── mipmaps_compute.hpp │ │ │ ├── reduce.inl │ │ │ ├── s3tc.hpp │ │ │ ├── s3tc.inl │ │ │ ├── sampler.inl │ │ │ ├── sampler1d.inl │ │ │ ├── sampler1d_array.inl │ │ │ ├── sampler2d.inl │ │ │ ├── sampler2d_array.inl │ │ │ ├── sampler3d.inl │ │ │ ├── sampler_cube.inl │ │ │ ├── sampler_cube_array.inl │ │ │ ├── save.inl │ │ │ ├── save_dds.inl │ │ │ ├── save_kmg.inl │ │ │ ├── save_ktx.inl │ │ │ ├── storage_linear.hpp │ │ │ ├── storage_linear.inl │ │ │ ├── texture.inl │ │ │ ├── texture1d.inl │ │ │ ├── texture1d_array.inl │ │ │ ├── texture2d.inl │ │ │ ├── texture2d_array.inl │ │ │ ├── texture3d.inl │ │ │ ├── texture_cube.inl │ │ │ ├── texture_cube_array.inl │ │ │ ├── transform.inl │ │ │ └── view.inl │ │ ├── duplicate.hpp │ │ ├── dx.hpp │ │ ├── format.hpp │ │ ├── generate_mipmaps.hpp │ │ ├── gl.hpp │ │ ├── gli.hpp │ │ ├── glm/ │ │ │ ├── common.hpp │ │ │ ├── detail/ │ │ │ │ ├── _features.hpp │ │ │ │ ├── _fixes.hpp │ │ │ │ ├── _noise.hpp │ │ │ │ ├── _swizzle.hpp │ │ │ │ ├── _swizzle_func.hpp │ │ │ │ ├── _vectorize.hpp │ │ │ │ ├── compute_common.hpp │ │ │ │ ├── compute_vector_relational.hpp │ │ │ │ ├── func_common.inl │ │ │ │ ├── func_common_simd.inl │ │ │ │ ├── func_exponential.inl │ │ │ │ ├── func_exponential_simd.inl │ │ │ │ ├── func_geometric.inl │ │ │ │ ├── func_geometric_simd.inl │ │ │ │ ├── func_integer.inl │ │ │ │ ├── func_integer_simd.inl │ │ │ │ ├── func_matrix.inl │ │ │ │ ├── func_matrix_simd.inl │ │ │ │ ├── func_packing.inl │ │ │ │ ├── func_packing_simd.inl │ │ │ │ ├── func_trigonometric.inl │ │ │ │ ├── func_trigonometric_simd.inl │ │ │ │ ├── func_vector_relational.inl │ │ │ │ ├── func_vector_relational_simd.inl │ │ │ │ ├── glm.cpp │ │ │ │ ├── qualifier.hpp │ │ │ │ ├── setup.hpp │ │ │ │ ├── type_float.hpp │ │ │ │ ├── type_half.hpp │ │ │ │ ├── type_half.inl │ │ │ │ ├── type_mat2x2.hpp │ │ │ │ ├── type_mat2x2.inl │ │ │ │ ├── type_mat2x3.hpp │ │ │ │ ├── type_mat2x3.inl │ │ │ │ ├── type_mat2x4.hpp │ │ │ │ ├── type_mat2x4.inl │ │ │ │ ├── type_mat3x2.hpp │ │ │ │ ├── type_mat3x2.inl │ │ │ │ ├── type_mat3x3.hpp │ │ │ │ ├── type_mat3x3.inl │ │ │ │ ├── type_mat3x4.hpp │ │ │ │ ├── type_mat3x4.inl │ │ │ │ ├── type_mat4x2.hpp │ │ │ │ ├── type_mat4x2.inl │ │ │ │ ├── type_mat4x3.hpp │ │ │ │ ├── type_mat4x3.inl │ │ │ │ ├── type_mat4x4.hpp │ │ │ │ ├── type_mat4x4.inl │ │ │ │ ├── type_mat4x4_simd.inl │ │ │ │ ├── type_quat.hpp │ │ │ │ ├── type_quat.inl │ │ │ │ ├── type_quat_simd.inl │ │ │ │ ├── type_vec1.hpp │ │ │ │ ├── type_vec1.inl │ │ │ │ ├── type_vec2.hpp │ │ │ │ ├── type_vec2.inl │ │ │ │ ├── type_vec3.hpp │ │ │ │ ├── type_vec3.inl │ │ │ │ ├── type_vec4.hpp │ │ │ │ ├── type_vec4.inl │ │ │ │ └── type_vec4_simd.inl │ │ │ ├── exponential.hpp │ │ │ ├── ext/ │ │ │ │ ├── matrix_clip_space.hpp │ │ │ │ ├── matrix_clip_space.inl │ │ │ │ ├── matrix_common.hpp │ │ │ │ ├── matrix_common.inl │ │ │ │ ├── matrix_double2x2.hpp │ │ │ │ ├── matrix_double2x2_precision.hpp │ │ │ │ ├── matrix_double2x3.hpp │ │ │ │ ├── matrix_double2x3_precision.hpp │ │ │ │ ├── matrix_double2x4.hpp │ │ │ │ ├── matrix_double2x4_precision.hpp │ │ │ │ ├── matrix_double3x2.hpp │ │ │ │ ├── matrix_double3x2_precision.hpp │ │ │ │ ├── matrix_double3x3.hpp │ │ │ │ ├── matrix_double3x3_precision.hpp │ │ │ │ ├── matrix_double3x4.hpp │ │ │ │ ├── matrix_double3x4_precision.hpp │ │ │ │ ├── matrix_double4x2.hpp │ │ │ │ ├── matrix_double4x2_precision.hpp │ │ │ │ ├── matrix_double4x3.hpp │ │ │ │ ├── matrix_double4x3_precision.hpp │ │ │ │ ├── matrix_double4x4.hpp │ │ │ │ ├── matrix_double4x4_precision.hpp │ │ │ │ ├── matrix_float2x2.hpp │ │ │ │ ├── matrix_float2x2_precision.hpp │ │ │ │ ├── matrix_float2x3.hpp │ │ │ │ ├── matrix_float2x3_precision.hpp │ │ │ │ ├── matrix_float2x4.hpp │ │ │ │ ├── matrix_float2x4_precision.hpp │ │ │ │ ├── matrix_float3x2.hpp │ │ │ │ ├── matrix_float3x2_precision.hpp │ │ │ │ ├── matrix_float3x3.hpp │ │ │ │ ├── matrix_float3x3_precision.hpp │ │ │ │ ├── matrix_float3x4.hpp │ │ │ │ ├── matrix_float3x4_precision.hpp │ │ │ │ ├── matrix_float4x2.hpp │ │ │ │ ├── matrix_float4x2_precision.hpp │ │ │ │ ├── matrix_float4x3.hpp │ │ │ │ ├── matrix_float4x3_precision.hpp │ │ │ │ ├── matrix_float4x4.hpp │ │ │ │ ├── matrix_float4x4_precision.hpp │ │ │ │ ├── matrix_int2x2.hpp │ │ │ │ ├── matrix_int2x2_sized.hpp │ │ │ │ ├── matrix_int2x3.hpp │ │ │ │ ├── matrix_int2x3_sized.hpp │ │ │ │ ├── matrix_int2x4.hpp │ │ │ │ ├── matrix_int2x4_sized.hpp │ │ │ │ ├── matrix_int3x2.hpp │ │ │ │ ├── matrix_int3x2_sized.hpp │ │ │ │ ├── matrix_int3x3.hpp │ │ │ │ ├── matrix_int3x3_sized.hpp │ │ │ │ ├── matrix_int3x4.hpp │ │ │ │ ├── matrix_int3x4_sized.hpp │ │ │ │ ├── matrix_int4x2.hpp │ │ │ │ ├── matrix_int4x2_sized.hpp │ │ │ │ ├── matrix_int4x3.hpp │ │ │ │ ├── matrix_int4x3_sized.hpp │ │ │ │ ├── matrix_int4x4.hpp │ │ │ │ ├── matrix_int4x4_sized.hpp │ │ │ │ ├── matrix_projection.hpp │ │ │ │ ├── matrix_projection.inl │ │ │ │ ├── matrix_relational.hpp │ │ │ │ ├── matrix_relational.inl │ │ │ │ ├── matrix_transform.hpp │ │ │ │ ├── matrix_transform.inl │ │ │ │ ├── matrix_uint2x2.hpp │ │ │ │ ├── matrix_uint2x2_sized.hpp │ │ │ │ ├── matrix_uint2x3.hpp │ │ │ │ ├── matrix_uint2x3_sized.hpp │ │ │ │ ├── matrix_uint2x4.hpp │ │ │ │ ├── matrix_uint2x4_sized.hpp │ │ │ │ ├── matrix_uint3x2.hpp │ │ │ │ ├── matrix_uint3x2_sized.hpp │ │ │ │ ├── matrix_uint3x3.hpp │ │ │ │ ├── matrix_uint3x3_sized.hpp │ │ │ │ ├── matrix_uint3x4.hpp │ │ │ │ ├── matrix_uint3x4_sized.hpp │ │ │ │ ├── matrix_uint4x2.hpp │ │ │ │ ├── matrix_uint4x2_sized.hpp │ │ │ │ ├── matrix_uint4x3.hpp │ │ │ │ ├── matrix_uint4x3_sized.hpp │ │ │ │ ├── matrix_uint4x4.hpp │ │ │ │ ├── matrix_uint4x4_sized.hpp │ │ │ │ ├── quaternion_common.hpp │ │ │ │ ├── quaternion_common.inl │ │ │ │ ├── quaternion_common_simd.inl │ │ │ │ ├── quaternion_double.hpp │ │ │ │ ├── quaternion_double_precision.hpp │ │ │ │ ├── quaternion_exponential.hpp │ │ │ │ ├── quaternion_exponential.inl │ │ │ │ ├── quaternion_float.hpp │ │ │ │ ├── quaternion_float_precision.hpp │ │ │ │ ├── quaternion_geometric.hpp │ │ │ │ ├── quaternion_geometric.inl │ │ │ │ ├── quaternion_relational.hpp │ │ │ │ ├── quaternion_relational.inl │ │ │ │ ├── quaternion_transform.hpp │ │ │ │ ├── quaternion_transform.inl │ │ │ │ ├── quaternion_trigonometric.hpp │ │ │ │ ├── quaternion_trigonometric.inl │ │ │ │ ├── scalar_common.hpp │ │ │ │ ├── scalar_common.inl │ │ │ │ ├── scalar_constants.hpp │ │ │ │ ├── scalar_constants.inl │ │ │ │ ├── scalar_int_sized.hpp │ │ │ │ ├── scalar_integer.hpp │ │ │ │ ├── scalar_integer.inl │ │ │ │ ├── scalar_packing.hpp │ │ │ │ ├── scalar_packing.inl │ │ │ │ ├── scalar_relational.hpp │ │ │ │ ├── scalar_relational.inl │ │ │ │ ├── scalar_uint_sized.hpp │ │ │ │ ├── scalar_ulp.hpp │ │ │ │ ├── scalar_ulp.inl │ │ │ │ ├── vector_bool1.hpp │ │ │ │ ├── vector_bool1_precision.hpp │ │ │ │ ├── vector_bool2.hpp │ │ │ │ ├── vector_bool2_precision.hpp │ │ │ │ ├── vector_bool3.hpp │ │ │ │ ├── vector_bool3_precision.hpp │ │ │ │ ├── vector_bool4.hpp │ │ │ │ ├── vector_bool4_precision.hpp │ │ │ │ ├── vector_common.hpp │ │ │ │ ├── vector_common.inl │ │ │ │ ├── vector_double1.hpp │ │ │ │ ├── vector_double1_precision.hpp │ │ │ │ ├── vector_double2.hpp │ │ │ │ ├── vector_double2_precision.hpp │ │ │ │ ├── vector_double3.hpp │ │ │ │ ├── vector_double3_precision.hpp │ │ │ │ ├── vector_double4.hpp │ │ │ │ ├── vector_double4_precision.hpp │ │ │ │ ├── vector_float1.hpp │ │ │ │ ├── vector_float1_precision.hpp │ │ │ │ ├── vector_float2.hpp │ │ │ │ ├── vector_float2_precision.hpp │ │ │ │ ├── vector_float3.hpp │ │ │ │ ├── vector_float3_precision.hpp │ │ │ │ ├── vector_float4.hpp │ │ │ │ ├── vector_float4_precision.hpp │ │ │ │ ├── vector_int1.hpp │ │ │ │ ├── vector_int1_sized.hpp │ │ │ │ ├── vector_int2.hpp │ │ │ │ ├── vector_int2_sized.hpp │ │ │ │ ├── vector_int3.hpp │ │ │ │ ├── vector_int3_sized.hpp │ │ │ │ ├── vector_int4.hpp │ │ │ │ ├── vector_int4_sized.hpp │ │ │ │ ├── vector_integer.hpp │ │ │ │ ├── vector_integer.inl │ │ │ │ ├── vector_packing.hpp │ │ │ │ ├── vector_packing.inl │ │ │ │ ├── vector_relational.hpp │ │ │ │ ├── vector_relational.inl │ │ │ │ ├── vector_uint1.hpp │ │ │ │ ├── vector_uint1_sized.hpp │ │ │ │ ├── vector_uint2.hpp │ │ │ │ ├── vector_uint2_sized.hpp │ │ │ │ ├── vector_uint3.hpp │ │ │ │ ├── vector_uint3_sized.hpp │ │ │ │ ├── vector_uint4.hpp │ │ │ │ ├── vector_uint4_sized.hpp │ │ │ │ ├── vector_ulp.hpp │ │ │ │ └── vector_ulp.inl │ │ │ ├── ext.hpp │ │ │ ├── fwd.hpp │ │ │ ├── geometric.hpp │ │ │ ├── glm.hpp │ │ │ ├── gtc/ │ │ │ │ ├── bitfield.hpp │ │ │ │ ├── bitfield.inl │ │ │ │ ├── color_space.hpp │ │ │ │ ├── color_space.inl │ │ │ │ ├── constants.hpp │ │ │ │ ├── constants.inl │ │ │ │ ├── epsilon.hpp │ │ │ │ ├── epsilon.inl │ │ │ │ ├── integer.hpp │ │ │ │ ├── integer.inl │ │ │ │ ├── matrix_access.hpp │ │ │ │ ├── matrix_access.inl │ │ │ │ ├── matrix_integer.hpp │ │ │ │ ├── matrix_inverse.hpp │ │ │ │ ├── matrix_inverse.inl │ │ │ │ ├── matrix_transform.hpp │ │ │ │ ├── matrix_transform.inl │ │ │ │ ├── noise.hpp │ │ │ │ ├── noise.inl │ │ │ │ ├── packing.hpp │ │ │ │ ├── packing.inl │ │ │ │ ├── quaternion.hpp │ │ │ │ ├── quaternion.inl │ │ │ │ ├── quaternion_simd.inl │ │ │ │ ├── random.hpp │ │ │ │ ├── random.inl │ │ │ │ ├── reciprocal.hpp │ │ │ │ ├── reciprocal.inl │ │ │ │ ├── round.hpp │ │ │ │ ├── round.inl │ │ │ │ ├── type_aligned.hpp │ │ │ │ ├── type_precision.hpp │ │ │ │ ├── type_precision.inl │ │ │ │ ├── type_ptr.hpp │ │ │ │ ├── type_ptr.inl │ │ │ │ ├── ulp.hpp │ │ │ │ ├── ulp.inl │ │ │ │ └── vec1.hpp │ │ │ ├── gtx/ │ │ │ │ ├── associated_min_max.hpp │ │ │ │ ├── associated_min_max.inl │ │ │ │ ├── bit.hpp │ │ │ │ ├── bit.inl │ │ │ │ ├── closest_point.hpp │ │ │ │ ├── closest_point.inl │ │ │ │ ├── color_encoding.hpp │ │ │ │ ├── color_encoding.inl │ │ │ │ ├── color_space.hpp │ │ │ │ ├── color_space.inl │ │ │ │ ├── color_space_YCoCg.hpp │ │ │ │ ├── color_space_YCoCg.inl │ │ │ │ ├── common.hpp │ │ │ │ ├── common.inl │ │ │ │ ├── compatibility.hpp │ │ │ │ ├── compatibility.inl │ │ │ │ ├── component_wise.hpp │ │ │ │ ├── component_wise.inl │ │ │ │ ├── dual_quaternion.hpp │ │ │ │ ├── dual_quaternion.inl │ │ │ │ ├── easing.hpp │ │ │ │ ├── easing.inl │ │ │ │ ├── euler_angles.hpp │ │ │ │ ├── euler_angles.inl │ │ │ │ ├── extend.hpp │ │ │ │ ├── extend.inl │ │ │ │ ├── extended_min_max.hpp │ │ │ │ ├── extended_min_max.inl │ │ │ │ ├── exterior_product.hpp │ │ │ │ ├── exterior_product.inl │ │ │ │ ├── fast_exponential.hpp │ │ │ │ ├── fast_exponential.inl │ │ │ │ ├── fast_square_root.hpp │ │ │ │ ├── fast_square_root.inl │ │ │ │ ├── fast_trigonometry.hpp │ │ │ │ ├── fast_trigonometry.inl │ │ │ │ ├── float_notmalize.inl │ │ │ │ ├── functions.hpp │ │ │ │ ├── functions.inl │ │ │ │ ├── gradient_paint.hpp │ │ │ │ ├── gradient_paint.inl │ │ │ │ ├── handed_coordinate_space.hpp │ │ │ │ ├── handed_coordinate_space.inl │ │ │ │ ├── hash.hpp │ │ │ │ ├── hash.inl │ │ │ │ ├── integer.hpp │ │ │ │ ├── integer.inl │ │ │ │ ├── intersect.hpp │ │ │ │ ├── intersect.inl │ │ │ │ ├── io.hpp │ │ │ │ ├── io.inl │ │ │ │ ├── log_base.hpp │ │ │ │ ├── log_base.inl │ │ │ │ ├── matrix_cross_product.hpp │ │ │ │ ├── matrix_cross_product.inl │ │ │ │ ├── matrix_decompose.hpp │ │ │ │ ├── matrix_decompose.inl │ │ │ │ ├── matrix_factorisation.hpp │ │ │ │ ├── matrix_factorisation.inl │ │ │ │ ├── matrix_interpolation.hpp │ │ │ │ ├── matrix_interpolation.inl │ │ │ │ ├── matrix_major_storage.hpp │ │ │ │ ├── matrix_major_storage.inl │ │ │ │ ├── matrix_operation.hpp │ │ │ │ ├── matrix_operation.inl │ │ │ │ ├── matrix_query.hpp │ │ │ │ ├── matrix_query.inl │ │ │ │ ├── matrix_transform_2d.hpp │ │ │ │ ├── matrix_transform_2d.inl │ │ │ │ ├── mixed_product.hpp │ │ │ │ ├── mixed_product.inl │ │ │ │ ├── norm.hpp │ │ │ │ ├── norm.inl │ │ │ │ ├── normal.hpp │ │ │ │ ├── normal.inl │ │ │ │ ├── normalize_dot.hpp │ │ │ │ ├── normalize_dot.inl │ │ │ │ ├── number_precision.hpp │ │ │ │ ├── number_precision.inl │ │ │ │ ├── optimum_pow.hpp │ │ │ │ ├── optimum_pow.inl │ │ │ │ ├── orthonormalize.hpp │ │ │ │ ├── orthonormalize.inl │ │ │ │ ├── perpendicular.hpp │ │ │ │ ├── perpendicular.inl │ │ │ │ ├── polar_coordinates.hpp │ │ │ │ ├── polar_coordinates.inl │ │ │ │ ├── projection.hpp │ │ │ │ ├── projection.inl │ │ │ │ ├── quaternion.hpp │ │ │ │ ├── quaternion.inl │ │ │ │ ├── range.hpp │ │ │ │ ├── raw_data.hpp │ │ │ │ ├── raw_data.inl │ │ │ │ ├── rotate_normalized_axis.hpp │ │ │ │ ├── rotate_normalized_axis.inl │ │ │ │ ├── rotate_vector.hpp │ │ │ │ ├── rotate_vector.inl │ │ │ │ ├── scalar_multiplication.hpp │ │ │ │ ├── scalar_relational.hpp │ │ │ │ ├── scalar_relational.inl │ │ │ │ ├── spline.hpp │ │ │ │ ├── spline.inl │ │ │ │ ├── std_based_type.hpp │ │ │ │ ├── std_based_type.inl │ │ │ │ ├── string_cast.hpp │ │ │ │ ├── string_cast.inl │ │ │ │ ├── texture.hpp │ │ │ │ ├── texture.inl │ │ │ │ ├── transform.hpp │ │ │ │ ├── transform.inl │ │ │ │ ├── transform2.hpp │ │ │ │ ├── transform2.inl │ │ │ │ ├── type_aligned.hpp │ │ │ │ ├── type_aligned.inl │ │ │ │ ├── type_trait.hpp │ │ │ │ ├── type_trait.inl │ │ │ │ ├── vec_swizzle.hpp │ │ │ │ ├── vector_angle.hpp │ │ │ │ ├── vector_angle.inl │ │ │ │ ├── vector_query.hpp │ │ │ │ ├── vector_query.inl │ │ │ │ ├── wrap.hpp │ │ │ │ └── wrap.inl │ │ │ ├── integer.hpp │ │ │ ├── mat2x2.hpp │ │ │ ├── mat2x3.hpp │ │ │ ├── mat2x4.hpp │ │ │ ├── mat3x2.hpp │ │ │ ├── mat3x3.hpp │ │ │ ├── mat3x4.hpp │ │ │ ├── mat4x2.hpp │ │ │ ├── mat4x3.hpp │ │ │ ├── mat4x4.hpp │ │ │ ├── matrix.hpp │ │ │ ├── packing.hpp │ │ │ ├── simd/ │ │ │ │ ├── common.h │ │ │ │ ├── exponential.h │ │ │ │ ├── geometric.h │ │ │ │ ├── integer.h │ │ │ │ ├── matrix.h │ │ │ │ ├── neon.h │ │ │ │ ├── packing.h │ │ │ │ ├── platform.h │ │ │ │ ├── trigonometric.h │ │ │ │ └── vector_relational.h │ │ │ ├── trigonometric.hpp │ │ │ ├── vec2.hpp │ │ │ ├── vec3.hpp │ │ │ ├── vec4.hpp │ │ │ └── vector_relational.hpp │ │ ├── image.hpp │ │ ├── levels.hpp │ │ ├── load.hpp │ │ ├── load_dds.hpp │ │ ├── load_kmg.hpp │ │ ├── load_ktx.hpp │ │ ├── make_texture.hpp │ │ ├── reduce.hpp │ │ ├── sampler.hpp │ │ ├── sampler1d.hpp │ │ ├── sampler1d_array.hpp │ │ ├── sampler2d.hpp │ │ ├── sampler2d_array.hpp │ │ ├── sampler3d.hpp │ │ ├── sampler_cube.hpp │ │ ├── sampler_cube_array.hpp │ │ ├── save.hpp │ │ ├── save_dds.hpp │ │ ├── save_kmg.hpp │ │ ├── save_ktx.hpp │ │ ├── target.hpp │ │ ├── texture.hpp │ │ ├── texture1d.hpp │ │ ├── texture1d_array.hpp │ │ ├── texture2d.hpp │ │ ├── texture2d_array.hpp │ │ ├── texture3d.hpp │ │ ├── texture_cube.hpp │ │ ├── texture_cube_array.hpp │ │ ├── transform.hpp │ │ ├── type.hpp │ │ └── view.hpp │ └── nlohmannjson/ │ └── include/ │ └── nlohmann/ │ ├── json.hpp │ └── json_fwd.hpp ├── res/ │ ├── Maya FBX FO4 Fix.txt │ ├── Maya FBX Skyrim Fix.txt │ ├── shaders/ │ │ ├── default.frag │ │ ├── default.vert │ │ ├── fo4_default.frag │ │ ├── fo4_default.vert │ │ ├── fullscreentri.frag │ │ ├── fullscreentri.vert │ │ ├── normalshade.frag │ │ ├── normalshade.vert │ │ ├── ob_default.frag │ │ ├── ob_default.vert │ │ ├── points.frag │ │ ├── points.vert │ │ ├── primitive.frag │ │ └── primitive.vert │ ├── skeleton_female_sf.nif │ ├── skeleton_female_sk.hkx │ ├── skeleton_female_sk.nif │ ├── skeleton_female_sse.hkx │ ├── skeleton_female_sse.nif │ ├── skeleton_fo3nv.nif │ ├── skeleton_fo4.hkx │ ├── skeleton_fo4.nif │ ├── skeleton_male_sf.nif │ ├── skeleton_male_sk.hkx │ ├── skeleton_male_sk.nif │ ├── skeleton_male_sse.hkx │ ├── skeleton_male_sse.nif │ ├── skeleton_ob.nif │ └── xrc/ │ ├── About.xrc │ ├── Actions.xrc │ ├── Automation.xrc │ ├── BatchBuild.xrc │ ├── BodySlide.xrc │ ├── ConvertBodyReference.xrc │ ├── EditUV.xrc │ ├── GroupManager.xrc │ ├── ImportDialog.xrc │ ├── NormalsGenDlg.xrc │ ├── OutfitStudio.xrc │ ├── Project.xrc │ ├── SavePreset.xrc │ ├── Settings.xrc │ ├── Setup.xrc │ ├── ShapeProperties.xrc │ ├── Skeleton.xrc │ ├── Slider.xrc │ ├── SliderDataImport.xrc │ └── WeightCopy.xrc ├── run-wxrc.bat └── src/ ├── components/ │ ├── Anim.cpp │ ├── Anim.h │ ├── Automation.cpp │ ├── Automation.h │ ├── Automorph.cpp │ ├── Automorph.h │ ├── BuildSelection.cpp │ ├── BuildSelection.h │ ├── ClippingFixer.cpp │ ├── ClippingFixer.h │ ├── DiffData.cpp │ ├── DiffData.h │ ├── Mesh.cpp │ ├── Mesh.h │ ├── NormalGenLayers.cpp │ ├── NormalGenLayers.h │ ├── PoseData.cpp │ ├── PoseData.h │ ├── PoseDataHkx.cpp │ ├── PoseDataJson.cpp │ ├── PoseDataYaml.cpp │ ├── RefTemplates.cpp │ ├── RefTemplates.h │ ├── SliderCategories.cpp │ ├── SliderCategories.h │ ├── SliderData.cpp │ ├── SliderData.h │ ├── SliderGroup.cpp │ ├── SliderGroup.h │ ├── SliderManager.cpp │ ├── SliderManager.h │ ├── SliderPresets.cpp │ ├── SliderPresets.h │ ├── SliderSet.cpp │ ├── SliderSet.h │ ├── TweakBrush.cpp │ ├── TweakBrush.h │ ├── UndoHistory.cpp │ ├── UndoHistory.h │ ├── UndoState.h │ ├── WeightNorm.cpp │ └── WeightNorm.h ├── files/ │ ├── FBXWrangler.cpp │ ├── FBXWrangler.h │ ├── HkxFile.cpp │ ├── HkxFile.h │ ├── MaskFile.cpp │ ├── MaskFile.h │ ├── MaterialFile.cpp │ ├── MaterialFile.h │ ├── ObjFile.cpp │ ├── ObjFile.h │ ├── ResourceLoader.cpp │ ├── ResourceLoader.h │ ├── SFMorphFile.cpp │ ├── SFMorphFile.h │ ├── TriFile.cpp │ ├── TriFile.h │ ├── wxDDSImage.cpp │ └── wxDDSImage.h ├── program/ │ ├── AutomationDialog.cpp │ ├── AutomationDialog.h │ ├── BodySlideApp.cpp │ ├── BodySlideApp.h │ ├── ConvertBodyReferenceDialog.cpp │ ├── ConvertBodyReferenceDialog.h │ ├── EditUV.cpp │ ├── EditUV.h │ ├── FBXImportDialog.cpp │ ├── FBXImportDialog.h │ ├── FBXImportOptions.h │ ├── GroupManager.cpp │ ├── GroupManager.h │ ├── NormalsGenDialog.cpp │ ├── NormalsGenDialog.h │ ├── OBJImportOptions.h │ ├── ObjImportDialog.cpp │ ├── ObjImportDialog.h │ ├── OutfitProject.cpp │ ├── OutfitProject.h │ ├── OutfitStudio.cpp │ ├── OutfitStudio.h │ ├── PresetSaveDialog.cpp │ ├── PresetSaveDialog.h │ ├── PreviewWindow.cpp │ ├── PreviewWindow.h │ ├── ShaderFlagDefs.h │ ├── ShapeProperties.cpp │ ├── ShapeProperties.h │ ├── SliderDataImportDialog.cpp │ └── SliderDataImportDialog.h ├── render/ │ ├── GLCanvas.cpp │ ├── GLCanvas.h │ ├── GLDialog.cpp │ ├── GLDialog.h │ ├── GLExtensions.cpp │ ├── GLExtensions.h │ ├── GLMaterial.cpp │ ├── GLMaterial.h │ ├── GLOffscreenBuffer.cpp │ ├── GLOffscreenBuffer.h │ ├── GLShader.cpp │ ├── GLShader.h │ ├── GLSurface.cpp │ └── GLSurface.h ├── ui/ │ ├── PreviewPanel.cpp │ ├── PreviewPanel.h │ ├── WeightCopyDialog.cpp │ ├── WeightCopyDialog.h │ ├── wxBrushSettingsPopup.cpp │ ├── wxBrushSettingsPopup.h │ ├── wxNormalsGenDlg.cpp │ ├── wxNormalsGenDlg.h │ ├── wxSliderPanel.cpp │ ├── wxSliderPanel.h │ ├── wxStateButton.cpp │ └── wxStateButton.h └── utils/ ├── AABBTree.cpp ├── AABBTree.h ├── ConfigDialogUtil.h ├── ConfigurationManager.cpp ├── ConfigurationManager.h ├── Log.cpp ├── Log.h ├── PlatformUtil.cpp ├── PlatformUtil.h ├── StringStuff.cpp └── StringStuff.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ --- Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: true AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: true AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BraceWrapping: AfterCaseLabel: false AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: false AfterNamespace: false AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: true BeforeElse: true IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: All BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 180 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - forever - foreach - Q_FOREACH - BOOST_FOREACH IncludeBlocks: Preserve IncludeCategories: - Regex: '^ true ================================================ FILE: BodySlide.vcxproj ================================================ Debug Win32 Debug x64 Release Win32 Release x64 {F7E444AD-893D-4E93-8897-AF050C1C6A48} BodySlide Win32Proj 10.0 Application v145 Unicode true false false Application v145 Unicode true false false Application v145 Unicode Application v145 Unicode <_ProjectFileVersion>11.0.61030.0 $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ $(ProjectName) Debug true $(SolutionDir)build\$(Configuration)\$(Platform)\ $(ProjectName) $(Platform) Debug true $(SolutionDir)build\$(Configuration)\$(Platform)\ $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ $(SolutionDir)build\$(Configuration)\$(Platform)\ $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ false false $(ProjectName) $(Platform) $(SolutionDir)build\$(Configuration)\$(Platform)\ $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ Disabled ..\wxWidgets\include\msvc;..\wxWidgets\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2 WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug Level4 true /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) true Windows false libcmt.lib AsInvoker PerMonitorHighDPIAware BodySlide.manifest Disabled ..\wxWidgets\include\msvc;..\wxWidgets\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2 WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug Level4 true /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) true Windows false libcmt.lib AsInvoker PerMonitorHighDPIAware BodySlide.manifest MaxSpeed true ..\wxWidgets\include\msvc;..\wxWidgets\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2 WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded Level4 true ProgramDatabase /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) false true Windows true true AsInvoker /pdbaltpath:%_PDB% %(AdditionalOptions) PerMonitorHighDPIAware BodySlide.manifest MaxSpeed true ..\wxWidgets\include\msvc;..\wxWidgets\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2 WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded Level4 true ProgramDatabase /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) false true Windows true true AsInvoker /pdbaltpath:%_PDB% %(AdditionalOptions) PerMonitorHighDPIAware BodySlide.manifest ================================================ FILE: BodySlide.vcxproj.filters ================================================  {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav {6d6b425f-03aa-4210-b6af-ac49bf12352d} {6f3ea695-40d7-4be2-a951-168ba3339081} {e366b310-4d8d-4f5e-b43d-0aa7f0edeef1} {fd5a7d0f-084f-4202-b4d6-67732f2c2302} {5857b5e3-d66f-4467-ab4d-f70856237a1a} {cf289f86-ccae-4cd8-81db-71adb8328b06} {9222d26f-5381-4e83-b3d9-bbef711a1f09} {18fc42a9-9067-4638-bb32-7a671746137a} {5359067a-dabf-4cb9-a13d-bb37b483c638} {8e852d2f-5f87-416d-be07-c75179e8f57e} {782be5c1-aa6f-4e54-acb4-c89dc11d2fcb} {82ef2505-7b08-4871-b498-b758d860f25c} {def5c486-38d5-46f3-87b8-5d17825c309e} {0e8c63ba-3164-40f0-a35e-7feb262c883b} {575c3247-33ba-4a9b-8af4-649cb8b54d10} {1dd6227a-2c07-441b-a703-df5e11788296} {746df173-aa97-45f5-9200-676a6b050846} {7208f4f1-7c43-4c83-b503-8677eceb8c70} {e8f5c7ec-6703-40f1-8df0-82794ab63125} {04ceb037-1b27-4876-8d21-d93a532d5246} {a4a64824-9052-40c3-9138-04fab014641c} Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Resources Libraries\TinyXML-2 Libraries\FSEngine Libraries\FSEngine Libraries\FSEngine Components Components Components Components Components Components Components Components Components Files Files Files Files Program Program Program Program Rendering Rendering UI Utilities Utilities Utilities Libraries Components Rendering Libraries\LZ4F Libraries\LZ4F Rendering Rendering Program UI UI Components Utilities Utilities Files Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\LZ4F Libraries\LZ4F Libraries\LZ4F Components Components Components Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\LZ4F Libraries\TinyXML-2 Libraries\FSEngine Libraries\FSEngine Libraries\FSEngine Components Components Components Components Components Components Components Components Components Files Files Files Files Program Program Program Program Rendering Rendering UI Utilities Utilities Utilities Components Rendering Libraries\LZ4F Libraries\LZ4F Rendering Rendering Program UI UI Components Utilities Utilities Files Libraries\gli\core Libraries\gli\glm\detail Libraries\LZ4F Libraries\LZ4F Components Components Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\LZ4F Libraries\nifly\src Resources ================================================ FILE: BodySlide.xml ================================================ false ================================================ FILE: BuildSelection.xml ================================================  ================================================ FILE: CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.11) project(BSOS) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) find_package(wxWidgets REQUIRED gl core base net xrc adv qa html propgrid) find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) set(fbxsdk_dir ../fbxsdk) find_library(fbxsdk fbxsdk PATHS ${fbxsdk_dir}/lib/gcc/x64/release) set(commonsources lib/FSEngine/FSBSA.cpp lib/FSEngine/FSEngine.cpp lib/FSEngine/FSManager.cpp lib/gli/glm/detail/glm.cpp lib/LZ4F/lz4.c lib/LZ4F/lz4frame.c lib/LZ4F/lz4hc.c lib/LZ4F/xxhash.c lib/nifly/src/Animation.cpp lib/nifly/src/BasicTypes.cpp lib/nifly/src/bhk.cpp lib/nifly/src/ExtraData.cpp lib/nifly/src/Factory.cpp lib/nifly/src/Geometry.cpp lib/nifly/src/NifFile.cpp lib/nifly/src/NifUtil.cpp lib/nifly/src/Nodes.cpp lib/nifly/src/Object3d.cpp lib/nifly/src/Objects.cpp lib/nifly/src/Particles.cpp lib/nifly/src/Shaders.cpp lib/nifly/src/Skin.cpp lib/SOIL2/wfETC.c lib/SOIL2/image_DXT.c lib/SOIL2/image_helper.c lib/SOIL2/SOIL2.c lib/TinyXML-2/tinyxml2.cpp src/components/Anim.cpp src/components/Automorph.cpp src/components/ClippingFixer.cpp src/components/DiffData.cpp src/components/Mesh.cpp src/components/NormalGenLayers.cpp src/components/SliderCategories.cpp src/components/SliderData.cpp src/components/SliderGroup.cpp src/components/SliderManager.cpp src/components/SliderPresets.cpp src/components/SliderSet.cpp src/files/MaskFile.cpp src/files/MaterialFile.cpp src/files/ResourceLoader.cpp src/files/TriFile.cpp src/program/GroupManager.cpp src/program/PresetSaveDialog.cpp src/render/GLExtensions.cpp src/render/GLMaterial.cpp src/render/GLOffscreenBuffer.cpp src/render/GLShader.cpp src/render/GLSurface.cpp src/render/GLCanvas.cpp src/render/GLDialog.cpp src/ui/wxStateButton.cpp src/ui/wxSliderPanel.cpp src/utils/AABBTree.cpp src/utils/ConfigurationManager.cpp src/utils/Log.cpp src/utils/PlatformUtil.cpp src/utils/StringStuff.cpp ) set(OSsources ${commonsources} src/components/PoseData.cpp src/components/PoseDataYaml.cpp src/components/PoseDataJson.cpp src/components/PoseDataHkx.cpp src/components/RefTemplates.cpp src/components/Automation.cpp src/components/TweakBrush.cpp src/components/UndoHistory.cpp src/components/WeightNorm.cpp src/files/FBXWrangler.cpp src/files/HkxFile.cpp src/files/ObjFile.cpp src/files/SFMorphFile.cpp src/ui/wxBrushSettingsPopup.cpp src/ui/WeightCopyDialog.cpp src/program/EditUV.cpp src/program/FBXImportDialog.cpp src/program/ObjImportDialog.cpp src/program/OutfitProject.cpp src/program/OutfitStudio.cpp src/program/ShapeProperties.cpp src/program/ConvertBodyReferenceDialog.cpp src/program/AutomationDialog.cpp src/program/SliderDataImportDialog.cpp ) set(BSsources ${commonsources} src/files/wxDDSImage.cpp src/program/BodySlideApp.cpp src/program/NormalsGenDialog.cpp src/program/PreviewWindow.cpp src/ui/PreviewPanel.cpp src/ui/wxNormalsGenDlg.cpp src/components/BuildSelection.cpp ) add_executable(OutfitStudio ${OSsources}) add_executable(BodySlide ${BSsources}) target_compile_definitions(OutfitStudio PRIVATE USE_FBXSDK) include(${wxWidgets_USE_FILE}) target_include_directories(OutfitStudio SYSTEM PRIVATE ${fbxsdk_dir}/include /usr/include/wine/windows ) target_include_directories(BodySlide SYSTEM PRIVATE /usr/include/wine/windows ) target_include_directories(OutfitStudio PUBLIC lib/gli lib/nifly/include lib/nifly/external lib/TinyXML-2 lib/fkYAML/include lib/nlohmannjson/include ) target_include_directories(BodySlide PUBLIC lib/gli lib/nifly/include lib/nifly/external lib/TinyXML-2 ) target_link_libraries(OutfitStudio ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} ${fbxsdk} xml2) target_link_libraries(BodySlide ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} xml2) ================================================ FILE: CONTRIBUTING.md ================================================ Request new features or report bugs by opening an issue on GitHub or commenting on the NexusMods mod pages. To submit a patch, please open a pull request on GitHub. If you are thinking of making a large contribution, open an issue for it before starting work. Please note the license of the project before committing your work. To make it easier to review and accept your pull request, please follow these guidelines: 1. Make a new branch on your fork and use that to open a pull request of your changes. 2. No trailing whitespaces. 3. Save your indentation as spaces. Tab size is 4 spaces. 4. Use the following format for curly brackets to be consistent with the rest: ```cpp if (true) { doThing(1); doThing(2); } ``` ================================================ FILE: Config.xml ================================================ -1 true true Anchorage - Sounds.bsa; BrokenSteel - Sounds.bsa; Fallout - MenuVoices.bsa; Fallout - Meshes.bsa; Fallout - Misc.bsa; Fallout - Sounds.bsa; Fallout - Voices.bsa; PointLookout - Sounds.bsa; ThePitt - Sounds.bsa; Zeta - Sounds.bsa DeadMoney - Sounds.bsa; Fallout - Meshes.bsa; Fallout - Misc.bsa; Fallout - Sound.bsa; Fallout - Voices1.bsa; GunRunnersArsenal - Sounds.bsa; HonestHearts - Sounds.bsa; LonesomeRoad - Sounds.bsa; OldWorldBlues - Sounds.bsa Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices.bsa; Skyrim - VoicesExtra.bsa Fallout4 - Animations.ba2; Fallout4 - Interface.ba2; Fallout4 - Meshes.ba2; Fallout4 - MeshesExtra.ba2; Fallout4 - Misc.ba2; Fallout4 - Nvflex.ba2; Fallout4 - Shaders.ba2; Fallout4 - Sounds.ba2; Fallout4 - Startup.ba2; Fallout4 - Voices_en.ba2; DLCCoast - Voices_en.ba2; DLCNukaWorld - Voices_en.ba2; DLCRobot - Voices_en.ba2; DLCworkshop03 - Voices_en.ba2; Fallout4 - Voices_de.ba2; DLCCoast - Voices_de.ba2; DLCNukaWorld - Voices_de.ba2; DLCRobot - Voices_de.ba2; DLCworkshop03 - Voices_de.ba2; DLCUltraHighResolution - Textures01.ba2; DLCUltraHighResolution - Textures02.ba2; DLCUltraHighResolution - Textures03.ba2; DLCUltraHighResolution - Textures04.ba2; DLCUltraHighResolution - Textures05.ba2; DLCUltraHighResolution - Textures06.ba2; DLCUltraHighResolution - Textures07.ba2; DLCUltraHighResolution - Textures08.ba2; DLCUltraHighResolution - Textures09.ba2; DLCUltraHighResolution - Textures10.ba2; DLCUltraHighResolution - Textures11.ba2; DLCUltraHighResolution - Textures12.ba2; DLCUltraHighResolution - Textures13.ba2; DLCUltraHighResolution - Textures14.ba2; DLCUltraHighResolution - Textures15.ba2 Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes0.bsa; Skyrim - Meshes1.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices_en0.bsa; Skyrim - Voices_de0.bsa Fallout4 - Animations.ba2; Fallout4 - Interface.ba2; Fallout4 - Meshes.ba2; Fallout4 - MeshesExtra.ba2; Fallout4 - Misc.ba2; Fallout4 - Misc - Beta.ba2; Fallout4 - Misc - Debug.ba2; Fallout4 - Shaders.ba2; Fallout4 - Sounds.ba2; Fallout4 - Startup.ba2; Fallout4 - Voices.ba2; Fallout4 - Voices_en.ba2; Fallout4 - Voices_de.ba2; Fallout4_VR - Shaders.ba2 Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes0.bsa; Skyrim - Meshes1.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices_en0.bsa; Skyrim - Voices_de0.bsa; Skyrim_VR - Main.bsa Oblivion - Misc.bsa; Oblivion - Sounds.bsa; Oblivion - Voices1.bsa; Oblivion - Voices2.bsa; DLCShiveringIsles - Sounds.bsa; DLCShiveringIsles - Voices.bsa Starfield - Animations.ba2; Starfield - DensityMaps.ba2; Starfield - FaceAnimation01.ba2; Starfield - FaceAnimation02.ba2; Starfield - FaceAnimation03.ba2; Starfield - FaceAnimation04.ba2; Starfield - FaceAnimationPatch.ba2; Starfield - GeneratedTextures.ba2; Starfield - Interface.ba2; Starfield - LODMeshes.ba2; Starfield - LODMeshesPatch.ba2; Starfield - LODTextures01.ba2; Starfield - LODTextures02.ba2; Starfield - Localization.ba2; Starfield - Misc.ba2; Starfield - Particles.ba2; Starfield - PlanetData.ba2; Starfield - Shaders.ba2; Starfield - Terrain01.ba2; Starfield - Terrain02.ba2; Starfield - Terrain03.ba2; Starfield - Terrain04.ba2; Starfield - TerrainPatch.ba2; Starfield - Voices01.ba2; Starfield - Voices02.ba2; Starfield - VoicesPatch.ba2; Starfield - WwiseSounds01.ba2; Starfield - WwiseSounds02.ba2; Starfield - WwiseSounds03.ba2; Starfield - WwiseSounds04.ba2; Starfield - WwiseSounds05.ba2; Starfield - WwiseSoundsPatch.ba2; BlueprintShips-Starfield - Localization.ba2; Constellation - Localization.ba2; OldMars - Localization.ba2; SFBGS003 - Voices_de.ba2; SFBGS003 - Voices_en.ba2; SFBGS003 - Voices_es.ba2; SFBGS003 - Voices_fr.ba2; SFBGS003 - Voices_ja.ba2; SFBGS004 - Voices_de.ba2; SFBGS004 - Voices_en.ba2; SFBGS004 - Voices_es.ba2; SFBGS004 - Voices_fr.ba2; SFBGS004 - Voices_ja.ba2 3 -1 0 100 false 20 20 60 60 85 ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: OutfitStudio.manifest ================================================ true ================================================ FILE: OutfitStudio.vcxproj ================================================ Debug Win32 Debug x64 Release Win32 Release x64 {C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771} Outfit Studio Win32Proj 10.0 Application v145 Unicode true false false Application v145 Unicode true false false Application v145 Unicode Application v145 Unicode <_ProjectFileVersion>11.0.61030.0 $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ $(ProjectName) Debug false $(SolutionDir)build\$(Configuration)\$(Platform)\ $(ProjectName) $(Platform) Debug false $(SolutionDir)build\$(Configuration)\$(Platform)\ $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ $(SolutionDir)build\$(Configuration)\$(Platform)\ $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ false false $(ProjectName) $(Platform) $(SolutionDir)build\$(Configuration)\$(Platform)\ $(SolutionDir)build\tmp_$(ProjectName)\$(Configuration)\$(Platform)\ Disabled ..\wxWidgets\include\msvc;..\wxWidgets\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2;lib\fkYAML\include;lib\nlohmannjson\include WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug Level4 true /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) true Windows false libcmt.lib AsInvoker /ignore:4099 %(AdditionalOptions) PerMonitorHighDPIAware OutfitStudio.manifest Disabled ..\wxWidgets\include\msvc;..\wxWidgets\include;..\FBX SDK\2020.3.7\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2;lib\fkYAML\include;lib\nlohmannjson\include WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;USE_FBXSDK;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDebug Level4 true /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies) ..\FBX SDK\2020.3.7\lib\x64\debug;..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) true Windows false libcmt.lib AsInvoker /ignore:4099 %(AdditionalOptions) PerMonitorHighDPIAware OutfitStudio.manifest MaxSpeed true ..\wxWidgets\include\msvc;..\wxWidgets\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2;lib\fkYAML\include;lib\nlohmannjson\include WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions) MultiThreaded Level4 true ProgramDatabase /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;%(AdditionalDependencies) ..\wxWidgets\lib\vc_lib;%(AdditionalLibraryDirectories) false true Windows true true AsInvoker /pdbaltpath:%_PDB% /ignore:4099 %(AdditionalOptions) PerMonitorHighDPIAware OutfitStudio.manifest MaxSpeed true ..\wxWidgets\include\msvc;..\wxWidgets\include;..\FBX SDK\2020.3.7\include;lib\gli;lib\nifly\include;lib\nifly\external;lib\TinyXML-2;lib\fkYAML\include;lib\nlohmannjson\include WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;USE_FBXSDK;%(PreprocessorDefinitions) MultiThreaded Level4 true ProgramDatabase /bigobj /wd26812 %(AdditionalOptions) stdcpp17 true Level1 glu32.lib;opengl32.lib;libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies) ..\FBX SDK\2020.3.7\lib\x64\release;..\wxWidgets\lib\vc_x64_lib;%(AdditionalLibraryDirectories) false true Windows true true AsInvoker /pdbaltpath:%_PDB% /ignore:4099 %(AdditionalOptions) PerMonitorHighDPIAware OutfitStudio.manifest ================================================ FILE: OutfitStudio.vcxproj.filters ================================================  {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav {6d6b425f-03aa-4210-b6af-ac49bf12352d} {6f3ea695-40d7-4be2-a951-168ba3339081} {e366b310-4d8d-4f5e-b43d-0aa7f0edeef1} {fd5a7d0f-084f-4202-b4d6-67732f2c2302} {5857b5e3-d66f-4467-ab4d-f70856237a1a} {cf289f86-ccae-4cd8-81db-71adb8328b06} {9222d26f-5381-4e83-b3d9-bbef711a1f09} {18fc42a9-9067-4638-bb32-7a671746137a} {5359067a-dabf-4cb9-a13d-bb37b483c638} {8e852d2f-5f87-416d-be07-c75179e8f57e} {782be5c1-aa6f-4e54-acb4-c89dc11d2fcb} {82ef2505-7b08-4871-b498-b758d860f25c} {def5c486-38d5-46f3-87b8-5d17825c309e} {0e8c63ba-3164-40f0-a35e-7feb262c883b} {575c3247-33ba-4a9b-8af4-649cb8b54d10} {1dd6227a-2c07-441b-a703-df5e11788296} {746df173-aa97-45f5-9200-676a6b050846} {29047cf6-171b-41a4-9dd3-9725559f19dd} {c651ea53-1ed3-4f8d-8e11-0aa04e6b9ad6} {1e51341d-129d-409d-90b0-f83a0c40f24d} {d95f2d14-c32c-42eb-8742-c174b699d5fe} {3f339eee-e545-4d1d-a050-a3d2fbb686cd} {dccfbf1e-b15e-4cf8-a112-7c543d854aa8} Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Resources Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Resources Resources Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Resources Resources Resources Libraries\TinyXML-2 Libraries\FSEngine Libraries\FSEngine Libraries\FSEngine Components Components Components Components Components Components Components Components Components Components Components Components Components Components Files Files Files Files Files Files Files Program Program Program Program Rendering Rendering UI Utilities Utilities Utilities Libraries Components Program Rendering Libraries\LZ4F Rendering Rendering Components Utilities Utilities Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli\core Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\detail Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\simd Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtc Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\gli\glm\gtx Libraries\LZ4F Libraries\LZ4F Libraries\LZ4F Libraries\LZ4F Program Program Components Components UI UI UI Program Program Components Utilities Program Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\ext Libraries\gli\glm\simd Rendering Rendering Program Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\LZ4F Files Libraries\fkYAML Libraries\fkYAML Libraries\nlohmannjson Libraries\nlohmannjson Libraries\TinyXML-2 Libraries\FSEngine Libraries\FSEngine Libraries\FSEngine Components Components Components Components Components Components Components Components Components Components Components Components Components Files Files Files Files Files Files Files Program Program Program Program Rendering Rendering UI Utilities Utilities Utilities Components Program Rendering Libraries\LZ4F Libraries\LZ4F Rendering Rendering Components Utilities Utilities Libraries\gli\core Libraries\gli\glm\detail Libraries\LZ4F Libraries\LZ4F Program Program Components Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Libraries\nifly\src Components Components Components Components UI UI UI Program Program Components Program Rendering Rendering Program Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\SOIL2 Libraries\LZ4F Files Libraries\nifly\src Resources Resources ================================================ FILE: OutfitStudio.xml ================================================ ================================================ FILE: README.md ================================================ BodySlide-and-Outfit-Studio =========================== BodySlide and Outfit Studio, a tool to convert, create, and customize outfits and bodies for The Elder Scrolls and Fallout. **Created by and/or with the help of:** * Caliente * ousnius * jonwd7 for NIF and general help * degenerated1123 for help with shaders * NifTools team **Libraries used:** * OpenGL * OpenGL Image (GLI) * Simple OpenGL Image Library 2 (SOIL2) * TinyXML-2 * FSEngine (BSA/BA2 library) * Autodesk FBX SDK * half - IEEE 754-based half-precision floating point library * Miniball * LZ4(F) * wxWidgets https://github.com/ousnius/BodySlide-and-Outfit-Studio/wiki ================================================ FILE: Readme-linux.txt ================================================ Building BodySlide and Outfit Studio on Linux There's just one file that specifies the build process: CMakeLists.txt. Install wxWidgets 3.1.3 or newer. If you get errors about an ABI mismatch, that means you compiled wxWidgets with a different compiler version than BS&OS. Either gtk2 or gtk3 works. With gtk2, you have more background color problems; with gtk3, many widgets are distorted because they don't have enough space. Note that many of wxWidget's configure options (such as --enable-universal) result in a broken wxWidgets library, so prefer to use as few options as possible. Also note that some distribution-provided wxWidgets packages are broken, so it's likely that you'll have to build wxWidgets yourself (which is really easy). Install FBX SDK. Put the path to your FBX SDK installation in the fbxsdk_dir variable in CMakeLists.txt. Make sure GLEW is installed. Then go to your BodySlide-and-Outfit-Studio directory and do: mkdir Release cd Release cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-Wall" .. make The possible values for CMAKE_BUILD_TYPE: Release RelWithDebInfo Debug MinSizeRel (nothing) The -Wall option is optional. If you don't care about compiler warnings, you should probably skip this option. To specify the compiler, set CC and CXX before running cmake. The build directory must be completely empty, or cmake will ignore CC and CXX and use the same compilers as it did last time. Don't forget to build wxWidgets with the same compiler; the wxWidgets configure script also uses the CC and CXX environment variables. Some useful make options: make VERBOSE=1 make -j 4 The BodySlide and OutfitStudio executables need to be able to find the res directory, which contains important program data such as xrc files and icons. By default, the executables search for the res directory in the same directory as the executables. So, when you copy the executables into the BodySlide directory within your game, you need to copy the entire res directory too. If you don't want to copy the executables to the BodySlide directory within your game, set WX_BODYSLIDE_DATA_DIR and WX_OUTFITSTUDIO_DATA_DIR to the BodySlide directory. The res directory must still be copied into the BodySlide directory. ================================================ FILE: RefTemplates.xml ================================================ ================================================ FILE: lang/BodySlide.pot ================================================ #, fuzzy msgid "" msgstr "" "Project-Id-Version: BodySlide\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" "Language: en\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.9\n" "X-Poedit-KeywordsList: _\n" "X-Poedit-Basepath: ..\n" "X-Poedit-SearchPath-0: src\n" "X-Poedit-SearchPath-1: lang/xrctext.cpp\n" #: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:510 msgid "About" msgstr "" #: res/xrc/About.xrc:145 res/xrc/Automation.xrc:2554 #: res/xrc/GroupManager.xrc:189 msgid "Close" msgstr "" #: res/xrc/Actions.xrc:6 msgid "Apply a vertex position" msgstr "" #: res/xrc/Actions.xrc:15 msgid "This permanently moves a single vertex straight to the given location." msgstr "" #: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499 #: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:862 res/xrc/Actions.xrc:938 #: res/xrc/Actions.xrc:1014 res/xrc/Actions.xrc:1062 res/xrc/Actions.xrc:1341 #: res/xrc/Actions.xrc:1442 res/xrc/BatchBuild.xrc:127 res/xrc/EditUV.xrc:32 #: res/xrc/EditUV.xrc:258 res/xrc/EditUV.xrc:333 res/xrc/EditUV.xrc:454 #: res/xrc/EditUV.xrc:588 res/xrc/ImportDialog.xrc:174 res/xrc/Project.xrc:778 #: res/xrc/Project.xrc:955 res/xrc/Settings.xrc:524 #: res/xrc/ShapeProperties.xrc:831 res/xrc/Skeleton.xrc:36 #: res/xrc/Skeleton.xrc:259 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238 #: res/xrc/SliderDataImport.xrc:90 res/xrc/WeightCopy.xrc:228 msgid "&OK" msgstr "" #: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506 #: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:869 res/xrc/Actions.xrc:945 #: res/xrc/Actions.xrc:1021 res/xrc/Actions.xrc:1069 res/xrc/Actions.xrc:1348 #: res/xrc/Actions.xrc:1449 res/xrc/Actions.xrc:1780 res/xrc/BatchBuild.xrc:57 #: res/xrc/BatchBuild.xrc:135 res/xrc/EditUV.xrc:39 res/xrc/EditUV.xrc:265 #: res/xrc/EditUV.xrc:340 res/xrc/EditUV.xrc:461 res/xrc/EditUV.xrc:595 #: res/xrc/ImportDialog.xrc:181 res/xrc/Project.xrc:570 res/xrc/Project.xrc:785 #: res/xrc/Project.xrc:962 res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:531 #: res/xrc/Setup.xrc:302 res/xrc/ShapeProperties.xrc:838 #: res/xrc/Skeleton.xrc:43 res/xrc/Skeleton.xrc:266 res/xrc/Slider.xrc:71 #: res/xrc/Slider.xrc:246 res/xrc/SliderDataImport.xrc:97 #: res/xrc/WeightCopy.xrc:236 msgid "&Cancel" msgstr "" #: res/xrc/Actions.xrc:110 msgid "Move Shape" msgstr "" #: res/xrc/Actions.xrc:254 msgid "Mirror Axis" msgstr "" #: res/xrc/Actions.xrc:320 msgid "Scale Shape" msgstr "" #: res/xrc/Actions.xrc:329 msgid "Scaling will adjust the size of a mesh. This permanently affects vertices." msgstr "" #: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667 #: res/xrc/ShapeProperties.xrc:711 res/xrc/Skeleton.xrc:133 msgid "Origin" msgstr "" #: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678 msgid "Zero (0, 0, 0)" msgstr "" #: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679 msgid "Center of selected shapes(s)" msgstr "" #: res/xrc/Actions.xrc:484 res/xrc/Actions.xrc:847 msgid "Uniform (XYZ)" msgstr "" #: res/xrc/Actions.xrc:517 msgid "Rotate Shape" msgstr "" #: res/xrc/Actions.xrc:712 msgid "Inflate Shape" msgstr "" #: res/xrc/Actions.xrc:721 msgid "Inflate/deflate a mesh along its normals. This permanently affects vertices." msgstr "" #: res/xrc/Actions.xrc:880 res/xrc/Automation.xrc:1577 msgid "Mirror Shape" msgstr "" #: res/xrc/Actions.xrc:924 msgid "Swap bones on X axis (L/R)" msgstr "" #: res/xrc/Actions.xrc:956 msgid "Smooth Seams" msgstr "" #: res/xrc/Actions.xrc:1032 msgid "Set Shape Textures" msgstr "" #: res/xrc/Actions.xrc:1079 msgid "Conforming..." msgstr "" #: res/xrc/Actions.xrc:1088 msgid "Each vertex of the reference will copy its slider data to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become conformed and work well. Often, the default values are sufficient." msgstr "" #: res/xrc/Actions.xrc:1108 res/xrc/WeightCopy.xrc:35 msgid "Search Radius" msgstr "" #: res/xrc/Actions.xrc:1137 res/xrc/WeightCopy.xrc:64 msgid "Max Vertex Targets" msgstr "" #: res/xrc/Actions.xrc:1166 res/xrc/WeightCopy.xrc:95 msgid "No Target Limit" msgstr "" #: res/xrc/Actions.xrc:1189 msgid "No Squeeze" msgstr "" #: res/xrc/Actions.xrc:1212 msgid "Solid Mode" msgstr "" #: res/xrc/Actions.xrc:1235 msgid "Axis" msgstr "" #: res/xrc/Actions.xrc:1285 res/xrc/BodySlide.xrc:97 #: res/xrc/NormalsGenDlg.xrc:191 src/ui/PreviewPanel.cpp:41 msgid "Preset" msgstr "" #: res/xrc/Actions.xrc:1301 src/program/OutfitStudio.cpp:8844 msgid "Default" msgstr "" #: res/xrc/Actions.xrc:1310 msgid "Even Movement" msgstr "" #: res/xrc/Actions.xrc:1319 msgid "Solid Object" msgstr "" #: res/xrc/Actions.xrc:1358 msgid "Merge Geometry" msgstr "" #: res/xrc/Actions.xrc:1367 msgid "This function copies vertices and triangles from one shape to another. Partitions/segments of source and target shapes must match. It is the user's responsibility to check that all other shape and shader properties are compatible, or merging will likely have side effects." msgstr "" #: res/xrc/Actions.xrc:1382 msgid "Source" msgstr "" #: res/xrc/Actions.xrc:1400 src/program/AutomationDialog.cpp:88 msgid "Target" msgstr "" #: res/xrc/Actions.xrc:1429 msgid "Delete source shape" msgstr "" #: res/xrc/Actions.xrc:1459 msgid "Mask symmetric vertices" msgstr "" #: res/xrc/Actions.xrc:1468 msgid "Masks all vertices that do not have any of the selected asymmetries." msgstr "" #: res/xrc/Actions.xrc:1494 msgid "Vertices currently unmasked:" msgstr "" #: res/xrc/Actions.xrc:1522 msgid "Unmatched Vertices:" msgstr "" #: res/xrc/Actions.xrc:1544 msgid "Vertex Data Asymmetries" msgstr "" #: res/xrc/Actions.xrc:1577 res/xrc/OutfitStudio.xrc:808 #: res/xrc/OutfitStudio.xrc:1072 res/xrc/ShapeProperties.xrc:84 #: res/xrc/ShapeProperties.xrc:620 src/program/AutomationDialog.cpp:87 msgid "Type" msgstr "" #: res/xrc/Actions.xrc:1586 msgid "Average" msgstr "" #: res/xrc/Actions.xrc:1595 msgid "Count" msgstr "" #: res/xrc/Actions.xrc:1613 msgid "Position" msgstr "" #: res/xrc/Actions.xrc:1681 res/xrc/Automation.xrc:1501 res/xrc/Project.xrc:746 msgid "Sliders" msgstr "" #: res/xrc/Actions.xrc:1728 res/xrc/OutfitStudio.xrc:393 #: res/xrc/OutfitStudio.xrc:2539 res/xrc/OutfitStudio.xrc:2583 msgid "Bones" msgstr "" #: res/xrc/Actions.xrc:1747 msgid "Vertices that will still be unmasked:" msgstr "" #: res/xrc/Actions.xrc:1773 msgid "&Mask" msgstr "" #: res/xrc/Automation.xrc:5 msgid "Automation Script" msgstr "" #: res/xrc/Automation.xrc:22 msgid "Automation:" msgstr "" #: res/xrc/Automation.xrc:30 msgid "Select an automation to load, or type a name for a new one" msgstr "" #: res/xrc/Automation.xrc:31 msgid "Automation name..." msgstr "" #: res/xrc/Automation.xrc:39 res/xrc/BodySlide.xrc:143 #: res/xrc/GroupManager.xrc:44 res/xrc/OutfitStudio.xrc:1272 #: res/xrc/OutfitStudio.xrc:1349 msgid "Save" msgstr "" #: res/xrc/Automation.xrc:40 msgid "Save the automation script" msgstr "" #: res/xrc/Automation.xrc:48 res/xrc/OutfitStudio.xrc:1281 #: res/xrc/OutfitStudio.xrc:1367 res/xrc/OutfitStudio.xrc:2563 msgid "Delete" msgstr "" #: res/xrc/Automation.xrc:49 msgid "Delete the current automation script" msgstr "" #: res/xrc/Automation.xrc:57 msgid "Open Folder" msgstr "" #: res/xrc/Automation.xrc:58 msgid "Open the Automations folder in file explorer" msgstr "" #: res/xrc/Automation.xrc:99 msgid "Step Settings" msgstr "" #: res/xrc/Automation.xrc:114 msgid "Type:" msgstr "" #: res/xrc/Automation.xrc:121 msgid "Bones: Add Custom Bone" msgstr "" #: res/xrc/Automation.xrc:122 msgid "Bones: Copy Bone Weights" msgstr "" #: res/xrc/Automation.xrc:123 msgid "Bones: Delete Bones" msgstr "" #: res/xrc/Automation.xrc:124 msgid "Bones: Edit Custom Bone" msgstr "" #: res/xrc/Automation.xrc:125 msgid "Bones: Remove Skinning" msgstr "" #: res/xrc/Automation.xrc:126 msgid "Export: File" msgstr "" #: res/xrc/Automation.xrc:127 msgid "Export: Save Project" msgstr "" #: res/xrc/Automation.xrc:128 msgid "Import: File" msgstr "" #: res/xrc/Automation.xrc:129 msgid "Import: Slider Data" msgstr "" #: res/xrc/Automation.xrc:130 msgid "Project: Add Project" msgstr "" #: res/xrc/Automation.xrc:131 msgid "Project: Clear Project" msgstr "" #: res/xrc/Automation.xrc:132 msgid "Project: Clear Reference" msgstr "" #: res/xrc/Automation.xrc:133 msgid "Project: Load Reference" msgstr "" #: res/xrc/Automation.xrc:134 msgid "Project: Set Base Shape" msgstr "" #: res/xrc/Automation.xrc:135 msgid "Project: Set Reference Shape" msgstr "" #: res/xrc/Automation.xrc:136 msgid "Shapes: Apply Pose" msgstr "" #: res/xrc/Automation.xrc:137 msgid "Shapes: Delete Shape" msgstr "" #: res/xrc/Automation.xrc:138 msgid "Shapes: Duplicate Shape" msgstr "" #: res/xrc/Automation.xrc:139 msgid "Shapes: Fix Clipping" msgstr "" #: res/xrc/Automation.xrc:140 msgid "Shapes: Invert UVs" msgstr "" #: res/xrc/Automation.xrc:141 msgid "Shapes: Mirror Shape" msgstr "" #: res/xrc/Automation.xrc:142 msgid "Shapes: Refine Mesh" msgstr "" #: res/xrc/Automation.xrc:143 msgid "Shapes: Rename Shape" msgstr "" #: res/xrc/Automation.xrc:144 msgid "Shapes: Reset Transforms" msgstr "" #: res/xrc/Automation.xrc:145 msgid "Shapes: Transform Shape" msgstr "" #: res/xrc/Automation.xrc:146 msgid "Sliders: Conform Sliders" msgstr "" #: res/xrc/Automation.xrc:147 msgid "Sliders: Delete Slider" msgstr "" #: res/xrc/Automation.xrc:148 msgid "Sliders: Set Slider Values" msgstr "" #: res/xrc/Automation.xrc:149 msgid "Sliders: Set Slider Properties" msgstr "" #: res/xrc/Automation.xrc:150 msgid "Masks: Load Mask" msgstr "" #: res/xrc/Automation.xrc:151 msgid "Nodes: Remove Unused Nodes" msgstr "" #: res/xrc/Automation.xrc:159 msgid "Active:" msgstr "" #: res/xrc/Automation.xrc:165 msgid "Execute this step" msgstr "" #: res/xrc/Automation.xrc:173 msgid "Target Shapes:" msgstr "" #: res/xrc/Automation.xrc:185 msgid "Comma-separated list of shape names. Leave empty to target all shapes." msgstr "" #: res/xrc/Automation.xrc:186 res/xrc/Automation.xrc:934 msgid "Comma-separated shape list" msgstr "" #: res/xrc/Automation.xrc:192 res/xrc/Automation.xrc:2451 #: res/xrc/Automation.xrc:2502 msgid "Regex" msgstr "" #: res/xrc/Automation.xrc:193 msgid "Use regex matching for target shape names" msgstr "" #: res/xrc/Automation.xrc:202 msgid "Note:" msgstr "" #: res/xrc/Automation.xrc:210 msgid "A note to describe what this step does and how to configure it." msgstr "" #: res/xrc/Automation.xrc:211 msgid "Description of this step..." msgstr "" #: res/xrc/Automation.xrc:232 res/xrc/Skeleton.xrc:53 msgid "Add Custom Bone" msgstr "" #: res/xrc/Automation.xrc:246 res/xrc/Automation.xrc:489 msgid "Bone Name:" msgstr "" #: res/xrc/Automation.xrc:252 res/xrc/Automation.xrc:496 msgid "Bone name" msgstr "" #: res/xrc/Automation.xrc:259 res/xrc/Automation.xrc:503 msgid "Parent Bone:" msgstr "" #: res/xrc/Automation.xrc:265 res/xrc/Automation.xrc:509 msgid "Name of the parent bone (leave empty for no parent)" msgstr "" #: res/xrc/Automation.xrc:266 res/xrc/Automation.xrc:510 msgid "Parent bone name" msgstr "" #: res/xrc/Automation.xrc:273 res/xrc/Automation.xrc:517 msgid "Translation:" msgstr "" #: res/xrc/Automation.xrc:314 res/xrc/Automation.xrc:558 msgid "Rotation:" msgstr "" #: res/xrc/Automation.xrc:362 res/xrc/ConvertBodyReference.xrc:183 #: res/xrc/OutfitStudio.xrc:2017 res/xrc/OutfitStudio.xrc:2495 #: res/xrc/WeightCopy.xrc:6 msgid "Copy Bone Weights" msgstr "" #: res/xrc/Automation.xrc:376 res/xrc/Automation.xrc:1869 msgid "Proximity Radius:" msgstr "" #: res/xrc/Automation.xrc:390 res/xrc/Automation.xrc:1883 msgid "Max Results:" msgstr "" #: res/xrc/Automation.xrc:404 msgid "Bone List:" msgstr "" #: res/xrc/Automation.xrc:410 msgid "Comma-separated list of bone names. Leave empty to copy all bones." msgstr "" #: res/xrc/Automation.xrc:411 res/xrc/Automation.xrc:446 msgid "Comma-separated bone list" msgstr "" #: res/xrc/Automation.xrc:425 msgid "Delete Bones" msgstr "" #: res/xrc/Automation.xrc:439 msgid "Bone Names:" msgstr "" #: res/xrc/Automation.xrc:445 msgid "Comma-separated list of bone names to delete" msgstr "" #: res/xrc/Automation.xrc:453 res/xrc/Automation.xrc:962 #: res/xrc/Automation.xrc:1025 res/xrc/Automation.xrc:1493 msgid "Mode:" msgstr "" #: res/xrc/Automation.xrc:459 msgid "Delete bone entirely from project" msgstr "" #: res/xrc/Automation.xrc:461 msgid "If checked, deletes the bone from all shapes and the NIF. If unchecked, only removes bone weights from target shapes." msgstr "" #: res/xrc/Automation.xrc:475 msgid "Edit Bone" msgstr "" #: res/xrc/Automation.xrc:495 msgid "Name of the custom bone to edit" msgstr "" #: res/xrc/Automation.xrc:606 res/xrc/OutfitStudio.xrc:1902 msgid "Remove Skinning" msgstr "" #: res/xrc/Automation.xrc:612 msgid "" "Removes skinning from target shapes (or all shapes if Target Meshes is empty).\n" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tThis deletes all bone weights and skinning data from the shapes." msgstr "" #: res/xrc/Automation.xrc:626 msgid "Export File" msgstr "" #: res/xrc/Automation.xrc:640 src/program/AutomationDialog.cpp:3596 msgid "Export File Path:" msgstr "" #: res/xrc/Automation.xrc:650 msgid "Select export file path" msgstr "" #: res/xrc/Automation.xrc:658 msgid "Select export folder" msgstr "" #: res/xrc/Automation.xrc:668 res/xrc/Automation.xrc:834 #: res/xrc/Automation.xrc:1067 res/xrc/Automation.xrc:1143 #: res/xrc/Automation.xrc:1277 res/xrc/Automation.xrc:1897 #: res/xrc/Automation.xrc:2419 msgid "Options:" msgstr "" #: res/xrc/Automation.xrc:677 msgid "Use original file path from batch operation" msgstr "" #: res/xrc/Automation.xrc:682 msgid "Export with reference shape (.nif only)" msgstr "" #: res/xrc/Automation.xrc:692 msgid "Filename Prefix:" msgstr "" #: res/xrc/Automation.xrc:698 #, c++-format msgid "Prefix to add before the filename. Supports {{PLACEHOLDER}} variables." msgstr "" #: res/xrc/Automation.xrc:699 msgid "e.g. prefix_" msgstr "" #: res/xrc/Automation.xrc:706 msgid "Filename Suffix:" msgstr "" #: res/xrc/Automation.xrc:712 #, c++-format msgid "Suffix to add after the filename before the extension. Supports {{PLACEHOLDER}} variables." msgstr "" #: res/xrc/Automation.xrc:713 msgid "e.g. &suffix" msgstr "" #: res/xrc/Automation.xrc:727 msgid "Save Project" msgstr "" #: res/xrc/Automation.xrc:733 msgid "Use original project from batch" msgstr "" #: res/xrc/Automation.xrc:750 msgid "Display Name:" msgstr "" #: res/xrc/Automation.xrc:756 #, c++-format msgid "Name shown in BodySlide (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:757 msgid "Display name" msgstr "" #: res/xrc/Automation.xrc:764 msgid "Output File Name:" msgstr "" #: res/xrc/Automation.xrc:770 #, c++-format msgid "Base filename for the output NIF (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:771 msgid "Output filename" msgstr "" #: res/xrc/Automation.xrc:778 msgid "Output Data Path:" msgstr "" #: res/xrc/Automation.xrc:784 #, c++-format msgid "Game data path for output (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:792 msgid "Slider Set File:" msgstr "" #: res/xrc/Automation.xrc:798 #, c++-format msgid "Slider set project file (.osp) (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:806 msgid "Shape Data Folder:" msgstr "" #: res/xrc/Automation.xrc:812 #, c++-format msgid "Folder for slider data files (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:820 msgid "Shape Data File:" msgstr "" #: res/xrc/Automation.xrc:826 #, c++-format msgid "Base NIF filename (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:843 msgid "Generate low/high weight outputs" msgstr "" #: res/xrc/Automation.xrc:849 msgid "Copy reference to output" msgstr "" #: res/xrc/Automation.xrc:873 msgid "Replace (from):" msgstr "" #: res/xrc/Automation.xrc:879 msgid "Text to find and replace in original project fields (batch only)" msgstr "" #: res/xrc/Automation.xrc:880 msgid "Find text" msgstr "" #: res/xrc/Automation.xrc:887 msgid "Replace (to):" msgstr "" #: res/xrc/Automation.xrc:893 msgid "Replacement text for matching text in original project fields (batch only)" msgstr "" #: res/xrc/Automation.xrc:894 msgid "Replace with" msgstr "" #: res/xrc/Automation.xrc:901 msgid "Suffix:" msgstr "" #: res/xrc/Automation.xrc:907 msgid "Suffix to append to Display Name, Shape Data Folder, and Shape Data File name (batch only)" msgstr "" #: res/xrc/Automation.xrc:908 msgid "e.g. &modified" msgstr "" #: res/xrc/Automation.xrc:924 msgid "Copy reference based on loaded project" msgstr "" #: res/xrc/Automation.xrc:925 msgid "If the loaded project had a reference shape, include it in the output. Otherwise, exclude it. Overrides the option above. (batch only)" msgstr "" #: res/xrc/Automation.xrc:933 msgid "Only treat these shape names as the reference (comma-separated). Leave empty to use any reference shape." msgstr "" #: res/xrc/Automation.xrc:948 msgid "Import File" msgstr "" #: res/xrc/Automation.xrc:968 msgid "Import all files from folder" msgstr "" #: res/xrc/Automation.xrc:975 msgid "File:" msgstr "" #: res/xrc/Automation.xrc:981 msgid "Select file to import" msgstr "" #: res/xrc/Automation.xrc:990 res/xrc/Automation.xrc:1053 #: res/xrc/Automation.xrc:2390 msgid "Folder:" msgstr "" #: res/xrc/Automation.xrc:996 msgid "Select folder to import from" msgstr "" #: res/xrc/Automation.xrc:1011 msgid "Import Slider Data" msgstr "" #: res/xrc/Automation.xrc:1031 msgid "Import all files from folder (ShapeName#SliderName.ext)" msgstr "" #: res/xrc/Automation.xrc:1038 msgid "Slider Data File:" msgstr "" #: res/xrc/Automation.xrc:1044 msgid "Select slider data file" msgstr "" #: res/xrc/Automation.xrc:1059 msgid "Select folder with slider data files" msgstr "" #: res/xrc/Automation.xrc:1073 msgid "Merge into existing sliders" msgstr "" #: res/xrc/Automation.xrc:1080 res/xrc/Automation.xrc:1526 #: res/xrc/Automation.xrc:1955 res/xrc/Automation.xrc:2038 #: res/xrc/Automation.xrc:2088 msgid "Slider Names:" msgstr "" #: res/xrc/Automation.xrc:1086 msgid "Comma-separated list of slider names. Leave empty to import all sliders." msgstr "" #: res/xrc/Automation.xrc:1087 res/xrc/Automation.xrc:1533 #: res/xrc/Automation.xrc:1962 res/xrc/Automation.xrc:2045 #: res/xrc/Automation.xrc:2095 msgid "Comma-separated slider list" msgstr "" #: res/xrc/Automation.xrc:1101 msgid "Add Project" msgstr "" #: res/xrc/Automation.xrc:1115 res/xrc/Automation.xrc:1236 msgid "Source File:" msgstr "" #: res/xrc/Automation.xrc:1121 msgid "Select project file" msgstr "" #: res/xrc/Automation.xrc:1130 res/xrc/Automation.xrc:1251 #: res/xrc/Project.xrc:106 res/xrc/Project.xrc:672 msgid "Slider Set:" msgstr "" #: res/xrc/Automation.xrc:1136 msgid "Name of the slider set to add" msgstr "" #: res/xrc/Automation.xrc:1152 res/xrc/Automation.xrc:1304 #: res/xrc/Project.xrc:756 msgid "Append new sliders" msgstr "" #: res/xrc/Automation.xrc:1169 msgid "Clear Project" msgstr "" #: res/xrc/Automation.xrc:1175 msgid "" "Clears the current project (removes all shapes, sliders, and references).\n" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNo additional parameters needed." msgstr "" #: res/xrc/Automation.xrc:1189 res/xrc/Project.xrc:146 res/xrc/Project.xrc:712 msgid "Clear Reference" msgstr "" #: res/xrc/Automation.xrc:1195 msgid "" "Removes the current reference/base shape from the project. Slider data for the reference is moved to the morpher.\n" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNo additional parameters needed." msgstr "" #: res/xrc/Automation.xrc:1209 res/xrc/Project.xrc:579 msgid "Load Reference" msgstr "" #: res/xrc/Automation.xrc:1223 msgid "Template:" msgstr "" #: res/xrc/Automation.xrc:1229 msgid "Select a reference template to auto-fill the fields below" msgstr "" #: res/xrc/Automation.xrc:1242 msgid "Select reference file" msgstr "" #: res/xrc/Automation.xrc:1257 msgid "Name of the slider set within the source file" msgstr "" #: res/xrc/Automation.xrc:1264 res/xrc/Project.xrc:124 res/xrc/Project.xrc:690 msgid "Shape:" msgstr "" #: res/xrc/Automation.xrc:1270 msgid "Name of the reference shape" msgstr "" #: res/xrc/Automation.xrc:1286 msgid "Load all shapes" msgstr "" #: res/xrc/Automation.xrc:1292 msgid "Merge sliders" msgstr "" #: res/xrc/Automation.xrc:1298 msgid "Merge zaps" msgstr "" #: res/xrc/Automation.xrc:1321 res/xrc/OutfitStudio.xrc:2079 msgid "Set Base Shape" msgstr "" #: res/xrc/Automation.xrc:1327 msgid "" "Bakes the current slider values into the base geometry of all shapes and zeros all sliders.\n" "\n" "Equivalent to \"Slider -> Set Base Shape\" in the menu." msgstr "" #: res/xrc/Automation.xrc:1342 msgid "Set Reference Shape" msgstr "" #: res/xrc/Automation.xrc:1356 msgid "Shape Name:" msgstr "" #: res/xrc/Automation.xrc:1362 msgid "Name of the shape to set as reference (highlighted green)." msgstr "" #: res/xrc/Automation.xrc:1363 msgid "Shape name" msgstr "" #: res/xrc/Automation.xrc:1373 msgid "Unset Reference" msgstr "" #: res/xrc/Automation.xrc:1374 msgid "Unset the reference shape instead of setting one. Morph data will be moved." msgstr "" #: res/xrc/Automation.xrc:1388 msgid "Apply Pose" msgstr "" #: res/xrc/Automation.xrc:1402 msgid "Pose Name:" msgstr "" #: res/xrc/Automation.xrc:1408 msgid "Name of the pose from PoseData to apply to meshes" msgstr "" #: res/xrc/Automation.xrc:1409 msgid "Pose name" msgstr "" #: res/xrc/Automation.xrc:1423 msgid "Delete Shape" msgstr "" #: res/xrc/Automation.xrc:1429 msgid "" "Deletes the shapes specified in the Target Meshes field above.\n" "\n" "If Target Meshes is empty, all non-reference shapes are deleted. Use Regex mode for pattern matching." msgstr "" #: res/xrc/Automation.xrc:1444 src/program/OutfitStudio.cpp:10348 msgid "Duplicate Shape" msgstr "" #: res/xrc/Automation.xrc:1458 res/xrc/Automation.xrc:1670 msgid "New Name:" msgstr "" #: res/xrc/Automation.xrc:1464 #, c++-format msgid "Name for the duplicated shape. Supports {{PLACEHOLDER}} variables." msgstr "" #: res/xrc/Automation.xrc:1465 res/xrc/Automation.xrc:1677 msgid "New shape name" msgstr "" #: res/xrc/Automation.xrc:1479 res/xrc/BodySlide.xrc:432 #: src/program/OutfitStudio.cpp:8938 src/program/OutfitStudio.cpp:8996 #: src/program/OutfitStudio.cpp:9002 src/program/OutfitStudio.cpp:10067 msgid "Fix Clipping" msgstr "" #: res/xrc/Automation.xrc:1500 msgid "Shapes" msgstr "" #: res/xrc/Automation.xrc:1504 msgid "Shapes: fix base geometry of target shapes. Sliders: fix clipping for each slider individually." msgstr "" #: res/xrc/Automation.xrc:1511 msgid "Strength (0 - 100):" msgstr "" #: res/xrc/Automation.xrc:1518 msgid "Clipping fix strength between 0 and 100." msgstr "" #: res/xrc/Automation.xrc:1532 msgid "Comma-separated list of slider names to fix clipping for (Sliders mode only). Leave empty to process all non-zap/non-UV sliders." msgstr "" #: res/xrc/Automation.xrc:1547 msgid "Invert UVs" msgstr "" #: res/xrc/Automation.xrc:1556 res/xrc/ImportDialog.xrc:53 msgid "Invert U" msgstr "" #: res/xrc/Automation.xrc:1563 res/xrc/ImportDialog.xrc:62 msgid "Invert V" msgstr "" #: res/xrc/Automation.xrc:1586 msgid "Mirror X" msgstr "" #: res/xrc/Automation.xrc:1594 msgid "Mirror Y" msgstr "" #: res/xrc/Automation.xrc:1601 msgid "Mirror Z" msgstr "" #: res/xrc/Automation.xrc:1608 msgid "Swap bones left/right (X axis)" msgstr "" #: res/xrc/Automation.xrc:1622 res/xrc/OutfitStudio.xrc:1963 #: res/xrc/OutfitStudio.xrc:2461 msgid "Refine Mesh" msgstr "" #: res/xrc/Automation.xrc:1628 msgid "" "Subdivides/refines meshes by splitting edges.\n" "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAll unmasked vertices are refined. Use the Target Meshes field above to select which shapes to refine." msgstr "" #: res/xrc/Automation.xrc:1642 src/program/OutfitStudio.cpp:5150 #: src/program/OutfitStudio.cpp:9335 msgid "Rename Shape" msgstr "" #: res/xrc/Automation.xrc:1656 msgid "Old Name:" msgstr "" #: res/xrc/Automation.xrc:1662 #, c++-format msgid "Current name of the shape (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:1663 msgid "Current shape name" msgstr "" #: res/xrc/Automation.xrc:1676 #, c++-format msgid "New name for the shape (supports {{PLACEHOLDER}} variables)" msgstr "" #: res/xrc/Automation.xrc:1691 res/xrc/OutfitStudio.xrc:1894 msgid "Reset Transforms" msgstr "" #: res/xrc/Automation.xrc:1697 msgid "Resets global-to-skin transforms for all skinned meshes. No additional parameters needed." msgstr "" #: res/xrc/Automation.xrc:1710 msgid "Transform Shape" msgstr "" #: res/xrc/Automation.xrc:1724 msgid "Move:" msgstr "" #: res/xrc/Automation.xrc:1731 msgid "Move X" msgstr "" #: res/xrc/Automation.xrc:1739 msgid "Move Y" msgstr "" #: res/xrc/Automation.xrc:1747 msgid "Move Z" msgstr "" #: res/xrc/Automation.xrc:1755 msgid "Rotate (°):" msgstr "" #: res/xrc/Automation.xrc:1762 msgid "Rotate X (degrees)" msgstr "" #: res/xrc/Automation.xrc:1770 msgid "Rotate Y (degrees)" msgstr "" #: res/xrc/Automation.xrc:1778 msgid "Rotate Z (degrees)" msgstr "" #: res/xrc/Automation.xrc:1786 msgid "Scale:" msgstr "" #: res/xrc/Automation.xrc:1793 msgid "Scale X" msgstr "" #: res/xrc/Automation.xrc:1801 msgid "Scale Y" msgstr "" #: res/xrc/Automation.xrc:1809 msgid "Scale Z" msgstr "" #: res/xrc/Automation.xrc:1817 msgid "Inflate:" msgstr "" #: res/xrc/Automation.xrc:1824 msgid "Inflate X (along normals)" msgstr "" #: res/xrc/Automation.xrc:1832 msgid "Inflate Y (along normals)" msgstr "" #: res/xrc/Automation.xrc:1840 msgid "Inflate Z (along normals)" msgstr "" #: res/xrc/Automation.xrc:1855 res/xrc/ConvertBodyReference.xrc:165 msgid "Conform Sliders" msgstr "" #: res/xrc/Automation.xrc:1906 msgid "No squeeze" msgstr "" #: res/xrc/Automation.xrc:1911 msgid "Solid mode" msgstr "" #: res/xrc/Automation.xrc:1920 msgid "Axes:" msgstr "" #: res/xrc/Automation.xrc:1931 msgid "X" msgstr "" #: res/xrc/Automation.xrc:1939 msgid "Y" msgstr "" #: res/xrc/Automation.xrc:1945 msgid "Z" msgstr "" #: res/xrc/Automation.xrc:1961 msgid "Comma-separated list of slider names to conform. Leave empty to conform all visible sliders." msgstr "" #: res/xrc/Automation.xrc:1976 msgid "Delete Slider" msgstr "" #: res/xrc/Automation.xrc:1990 msgid "Slider Name:" msgstr "" #: res/xrc/Automation.xrc:1996 msgid "Name of the slider to delete. If regex is checked, matches slider names by pattern." msgstr "" #: res/xrc/Automation.xrc:1997 msgid "Slider name or pattern" msgstr "" #: res/xrc/Automation.xrc:2004 msgid "Regex:" msgstr "" #: res/xrc/Automation.xrc:2010 msgid "Match slider names by regex pattern" msgstr "" #: res/xrc/Automation.xrc:2024 msgid "Set Slider Values" msgstr "" #: res/xrc/Automation.xrc:2044 msgid "Comma-separated list of slider names. Leave empty to set all visible sliders." msgstr "" #: res/xrc/Automation.xrc:2052 msgid "Value (0 - 100):" msgstr "" #: res/xrc/Automation.xrc:2059 msgid "Slider value between 0 and 100 (percentage)" msgstr "" #: res/xrc/Automation.xrc:2074 msgid "Set Slider Properties" msgstr "" #: res/xrc/Automation.xrc:2094 msgid "Comma-separated list of slider names. Leave empty to apply to all sliders." msgstr "" #: res/xrc/Automation.xrc:2102 msgid "Zap:" msgstr "" #: res/xrc/Automation.xrc:2109 res/xrc/Automation.xrc:2127 #: res/xrc/Automation.xrc:2145 msgid "No change" msgstr "" #: res/xrc/Automation.xrc:2110 res/xrc/Automation.xrc:2128 #: src/program/OutfitStudio.cpp:548 src/program/ShapeProperties.cpp:135 msgid "No" msgstr "" #: res/xrc/Automation.xrc:2111 res/xrc/Automation.xrc:2129 #: src/program/OutfitStudio.cpp:546 src/program/ShapeProperties.cpp:135 msgid "Yes" msgstr "" #: res/xrc/Automation.xrc:2113 msgid "Set the zap flag on matching sliders." msgstr "" #: res/xrc/Automation.xrc:2120 msgid "Hidden:" msgstr "" #: res/xrc/Automation.xrc:2131 msgid "Set the hidden flag on matching sliders." msgstr "" #: res/xrc/Automation.xrc:2138 msgid "Default Zapped:" msgstr "" #: res/xrc/Automation.xrc:2146 msgid "Not zapped" msgstr "" #: res/xrc/Automation.xrc:2147 res/xrc/Slider.xrc:148 msgid "Zapped" msgstr "" #: res/xrc/Automation.xrc:2149 msgid "Whether matching zap sliders are zapped by default." msgstr "" #: res/xrc/Automation.xrc:2155 msgid "Default (Small):" msgstr "" #: res/xrc/Automation.xrc:2161 msgid "Default small value (0-100). Leave empty for no change." msgstr "" #: res/xrc/Automation.xrc:2169 msgid "Default (Big):" msgstr "" #: res/xrc/Automation.xrc:2175 msgid "Default big value (0-100). Leave empty for no change." msgstr "" #: res/xrc/Automation.xrc:2190 msgid "Load Mask" msgstr "" #: res/xrc/Automation.xrc:2204 msgid "Mask File:" msgstr "" #: res/xrc/Automation.xrc:2210 msgid "Select a mask XML file" msgstr "" #: res/xrc/Automation.xrc:2219 msgid "Mask Name:" msgstr "" #: res/xrc/Automation.xrc:2225 msgid "Select a mask entry from the loaded mask file." msgstr "" #: res/xrc/Automation.xrc:2239 msgid "Remove Unused Nodes" msgstr "" #: res/xrc/Automation.xrc:2245 msgid "Removes all unreferenced nodes from the NIF." msgstr "" #: res/xrc/Automation.xrc:2265 msgid "Placeholder Variables" msgstr "" #: res/xrc/Automation.xrc:2274 #, c++-format msgid "Define {{KEY}} = Value pairs. These are substituted in all text fields before execution." msgstr "" #: res/xrc/Automation.xrc:2291 msgid "Key:" msgstr "" #: res/xrc/Automation.xrc:2297 msgid "Value:" msgstr "" #: res/xrc/Automation.xrc:2304 msgid "KEY" msgstr "" #: res/xrc/Automation.xrc:2310 res/xrc/ShapeProperties.xrc:638 msgid "Value" msgstr "" #: res/xrc/Automation.xrc:2323 msgid "+ Add" msgstr "" #: res/xrc/Automation.xrc:2331 msgid "- Remove" msgstr "" #: res/xrc/Automation.xrc:2348 msgid "Batch Operation" msgstr "" #: res/xrc/Automation.xrc:2358 msgid "Mode" msgstr "" #: res/xrc/Automation.xrc:2361 msgid "None (run on current project)" msgstr "" #: res/xrc/Automation.xrc:2362 msgid "Folder scan (repeat on files in folder)" msgstr "" #: res/xrc/Automation.xrc:2363 msgid "Slider sets (repeat on installed slider sets)" msgstr "" #: res/xrc/Automation.xrc:2377 msgid "Folder Scan Settings" msgstr "" #: res/xrc/Automation.xrc:2396 msgid "Select folder to scan" msgstr "" #: res/xrc/Automation.xrc:2404 msgid "Extension:" msgstr "" #: res/xrc/Automation.xrc:2411 msgid "File extension to scan for (e.g. .nif, .obj)" msgstr "" #: res/xrc/Automation.xrc:2425 msgid "Include subdirectories" msgstr "" #: res/xrc/Automation.xrc:2432 msgid "File Filter:" msgstr "" #: res/xrc/Automation.xrc:2444 msgid "Filter file/folder names (substring or regex)" msgstr "" #: res/xrc/Automation.xrc:2445 res/xrc/Automation.xrc:2496 msgid "Filter pattern..." msgstr "" #: res/xrc/Automation.xrc:2470 msgid "Slider Set Settings" msgstr "" #: res/xrc/Automation.xrc:2483 msgid "Filter:" msgstr "" #: res/xrc/Automation.xrc:2495 msgid "Filter slider set names (substring or regex). Leave empty for all." msgstr "" #: res/xrc/Automation.xrc:2526 msgid "Output Log" msgstr "" #: res/xrc/Automation.xrc:2543 src/program/AutomationDialog.cpp:1531 msgid "Execute" msgstr "" #: res/xrc/Automation.xrc:2544 msgid "Execute all active steps in order" msgstr "" #: res/xrc/BatchBuild.xrc:6 msgid "Batch Build" msgstr "" #: res/xrc/BatchBuild.xrc:21 msgid "Select the slider sets for the batch build process. Use the group and outfit filters to show the outfits you want!" msgstr "" #: res/xrc/BatchBuild.xrc:50 msgid "&Build" msgstr "" #: res/xrc/BatchBuild.xrc:67 msgid "Choose output set" msgstr "" #: res/xrc/BatchBuild.xrc:78 msgid "" "The following sets will override the same files.\n" "Please decide which one to use and select it in the list below." msgstr "" #: res/xrc/BatchBuild.xrc:88 msgid "Type and hit enter to choose output..." msgstr "" #: res/xrc/BatchBuild.xrc:114 res/xrc/WeightCopy.xrc:204 msgid "&Preview" msgstr "" #: res/xrc/BatchBuild.xrc:115 msgid "Open a preview window showing the conflicting outfits for the selected group" msgstr "" #: res/xrc/BodySlide.xrc:7 msgid "BodySlide" msgstr "" #: res/xrc/BodySlide.xrc:28 src/ui/PreviewPanel.cpp:36 msgid "Outfit/Body" msgstr "" #: res/xrc/BodySlide.xrc:44 msgid "Select an outfit to modify" msgstr "" #: res/xrc/BodySlide.xrc:58 msgid "Deletes a project from its project file" msgstr "" #: res/xrc/BodySlide.xrc:74 msgid "Opens the current project in Outfit Studio" msgstr "" #: res/xrc/BodySlide.xrc:113 msgid "Choose from a list of slider settings presets" msgstr "" #: res/xrc/BodySlide.xrc:127 msgid "Deletes a preset from its preset file" msgstr "" #: res/xrc/BodySlide.xrc:142 msgid "Saves the new slider values to the currently selected preset" msgstr "" #: res/xrc/BodySlide.xrc:153 msgid "Save the current slider settings as a new preset" msgstr "" #: res/xrc/BodySlide.xrc:154 res/xrc/GroupManager.xrc:53 #: res/xrc/OutfitStudio.xrc:1358 msgid "Save As..." msgstr "" #: res/xrc/BodySlide.xrc:165 msgid "Opens the group manager where you can edit existing or create new groups" msgstr "" #: res/xrc/BodySlide.xrc:166 res/xrc/GroupManager.xrc:7 #: res/xrc/Project.xrc:1084 msgid "Group Manager" msgstr "" #: res/xrc/BodySlide.xrc:240 msgid "Single Weight" msgstr "" #: res/xrc/BodySlide.xrc:267 msgid "Low Weight" msgstr "" #: res/xrc/BodySlide.xrc:284 msgid "High Weight" msgstr "" #: res/xrc/BodySlide.xrc:325 msgid "Copy the low weight slider values to the high weight section." msgstr "" #: res/xrc/BodySlide.xrc:342 msgid "Default outfit choice in Batch Build" msgstr "" #: res/xrc/BodySlide.xrc:353 msgid "Output Path (which the game would use for this outfit)" msgstr "" #: res/xrc/BodySlide.xrc:365 msgid "(right-click to view alternatives)" msgstr "" #: res/xrc/BodySlide.xrc:385 msgid "" "Build multiple outfits using the currently active slider values.\n" "\n" "Hold CTRL = Build to custom directory\n" "Hold ALT = Delete from output directory" msgstr "" #: res/xrc/BodySlide.xrc:386 msgid "Batch Build..." msgstr "" #: res/xrc/BodySlide.xrc:401 msgid "Build Morphs" msgstr "" #: res/xrc/BodySlide.xrc:402 msgid "Builds a morphs (.tri) file alongside the meshes for accessing the sliders in-game. Requires other mods to make use of the morph data." msgstr "" #: res/xrc/BodySlide.xrc:412 msgid "Force Body Normals" msgstr "" #: res/xrc/BodySlide.xrc:413 msgid "Adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod." msgstr "" #: res/xrc/BodySlide.xrc:442 msgid "Controls how far outfit vertices are pushed away from the body surface." msgstr "" #: res/xrc/BodySlide.xrc:460 msgid "Show a preview window for this outfit." msgstr "" #: res/xrc/BodySlide.xrc:461 res/xrc/NormalsGenDlg.xrc:166 #: src/program/PreviewWindow.cpp:19 src/program/PreviewWindow.cpp:33 msgid "Preview" msgstr "" #: res/xrc/BodySlide.xrc:479 msgid "" "Creates the currently selected outfit/body.\n" "\n" "Hold CTRL = Build to working directory\n" "Hold ALT = Delete from output directory" msgstr "" #: res/xrc/BodySlide.xrc:480 msgid "Build" msgstr "" #: res/xrc/BodySlide.xrc:492 msgid "Copy the high weight slider values to the low weight section." msgstr "" #: res/xrc/BodySlide.xrc:519 res/xrc/OutfitStudio.xrc:1815 msgid "Open settings dialog." msgstr "" #: res/xrc/BodySlide.xrc:520 res/xrc/OutfitStudio.xrc:1814 #: res/xrc/Settings.xrc:5 msgid "Settings" msgstr "" #: res/xrc/BodySlide.xrc:529 msgid "Open Outfit Studio, a full-featured tool for creating and converting outfits." msgstr "" #: res/xrc/BodySlide.xrc:530 res/xrc/OutfitStudio.xrc:7 msgid "Outfit Studio" msgstr "" #: res/xrc/BodySlide.xrc:540 res/xrc/BodySlide.xrc:552 msgid "Filter Options" msgstr "" #: res/xrc/BodySlide.xrc:542 msgid "Choose groups..." msgstr "" #: res/xrc/BodySlide.xrc:543 msgid "Choose groups to display in the Outfit menu" msgstr "" #: res/xrc/BodySlide.xrc:547 msgid "Refresh Groups" msgstr "" #: res/xrc/BodySlide.xrc:548 msgid "Refresh group information" msgstr "" #: res/xrc/BodySlide.xrc:554 msgid "Refresh Outfits" msgstr "" #: res/xrc/BodySlide.xrc:555 msgid "Reloads outfit list" msgstr "" #: res/xrc/BodySlide.xrc:559 msgid "Regular Expressions" msgstr "" #: res/xrc/BodySlide.xrc:560 msgid "Allow the use of regular expressions (regex) for filtering." msgstr "" #: res/xrc/BodySlide.xrc:564 msgid "Has Zap Options" msgstr "" #: res/xrc/BodySlide.xrc:565 msgid "Show only outfits that have zap options." msgstr "" #: res/xrc/BodySlide.xrc:570 msgid "Browse outfit folder..." msgstr "" #: res/xrc/BodySlide.xrc:571 msgid "Browses to the shape data folder of the current outfit in the file explorer." msgstr "" #: res/xrc/BodySlide.xrc:574 msgid "Save Outfit list as group..." msgstr "" #: res/xrc/BodySlide.xrc:575 msgid "Save the current filtered outfit list as a group" msgstr "" #: res/xrc/BodySlide.xrc:580 res/xrc/Project.xrc:1101 #: res/xrc/SliderDataImport.xrc:106 src/program/AutomationDialog.cpp:1525 msgid "Select None" msgstr "" #: res/xrc/BodySlide.xrc:583 res/xrc/EditUV.xrc:118 res/xrc/Project.xrc:1104 #: res/xrc/SliderDataImport.xrc:109 src/program/AutomationDialog.cpp:1524 msgid "Select All" msgstr "" #: res/xrc/BodySlide.xrc:586 res/xrc/EditUV.xrc:122 res/xrc/Project.xrc:1107 #: res/xrc/SliderDataImport.xrc:112 src/program/AutomationDialog.cpp:1526 msgid "Invert Selection" msgstr "" #: res/xrc/ConvertBodyReference.xrc:6 msgid "Convert / Replace Body Reference" msgstr "" #: res/xrc/ConvertBodyReference.xrc:16 res/xrc/ConvertBodyReference.xrc:219 msgid "This wizard aids in the conversion to another body/reference.." msgstr "" #: res/xrc/ConvertBodyReference.xrc:25 msgid "Reference Bodies" msgstr "" #: res/xrc/ConvertBodyReference.xrc:36 msgid "Select a conversion reference (or 'None' to skip converting):" msgstr "" #: res/xrc/ConvertBodyReference.xrc:58 msgid "Conversion Body Reference" msgstr "" #: res/xrc/ConvertBodyReference.xrc:78 msgid "Select a body reference to convert to:" msgstr "" #: res/xrc/ConvertBodyReference.xrc:100 msgid "New Body Reference" msgstr "" #: res/xrc/ConvertBodyReference.xrc:130 res/xrc/NormalsGenDlg.xrc:108 #: res/xrc/Slider.xrc:161 msgid "Options" msgstr "" #: res/xrc/ConvertBodyReference.xrc:136 res/xrc/SliderDataImport.xrc:77 msgid "Merge Sliders" msgstr "" #: res/xrc/ConvertBodyReference.xrc:145 msgid "Merge Zaps" msgstr "" #: res/xrc/ConvertBodyReference.xrc:174 msgid "Skip conform popup (use default settings)" msgstr "" #: res/xrc/ConvertBodyReference.xrc:192 msgid "Skip bone weights popup (use default settings)" msgstr "" #: res/xrc/ConvertBodyReference.xrc:203 msgid "Delete reference after completion" msgstr "" #: res/xrc/ConvertBodyReference.xrc:228 msgid "Rename Project (optional)" msgstr "" #: res/xrc/ConvertBodyReference.xrc:239 msgid "Specify text to be removed from the project name (comma-delimited):" msgstr "" #: res/xrc/ConvertBodyReference.xrc:260 msgid "Remove from project name" msgstr "" #: res/xrc/ConvertBodyReference.xrc:277 msgid "Specify any text to be prepended to project name:" msgstr "" #: res/xrc/ConvertBodyReference.xrc:298 msgid "Prepend to project name" msgstr "" #: res/xrc/ConvertBodyReference.xrc:315 msgid "NOTE: Game file output path is unaffected by this" msgstr "" #: res/xrc/ConvertBodyReference.xrc:326 msgid "Extras (optional)" msgstr "" #: res/xrc/ConvertBodyReference.xrc:337 msgid "Remove the following shapes before conversion (comma-delimited):" msgstr "" #: res/xrc/ConvertBodyReference.xrc:359 msgid "Shapes to delete" msgstr "" #: res/xrc/ConvertBodyReference.xrc:375 msgid "Add the following bones after conversion (comma-delimited):" msgstr "" #: res/xrc/ConvertBodyReference.xrc:396 msgid "Bones to add" msgstr "" #: res/xrc/EditUV.xrc:5 msgid "Edit UV" msgstr "" #: res/xrc/EditUV.xrc:52 msgid "Box Selection" msgstr "" #: res/xrc/EditUV.xrc:53 msgid "" "Box Selection\n" "Shortcut: 1" msgstr "" #: res/xrc/EditUV.xrc:60 msgid "Vertex Selection" msgstr "" #: res/xrc/EditUV.xrc:61 msgid "" "Vertex Selection\n" "Shortcut: 2" msgstr "" #: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:78 #: res/xrc/OutfitStudio.xrc:2234 msgid "Move" msgstr "" #: res/xrc/EditUV.xrc:68 msgid "" "Move\n" "Shortcut: 3" msgstr "" #: res/xrc/EditUV.xrc:74 res/xrc/EditUV.xrc:350 res/xrc/ImportDialog.xrc:71 #: res/xrc/OutfitStudio.xrc:1590 res/xrc/ShapeProperties.xrc:672 #: src/program/NormalsGenDialog.cpp:304 msgid "Scale" msgstr "" #: res/xrc/EditUV.xrc:75 msgid "" "Scale\n" "Shortcut: 4" msgstr "" #: res/xrc/EditUV.xrc:81 res/xrc/EditUV.xrc:275 msgid "Rotate" msgstr "" #: res/xrc/EditUV.xrc:82 msgid "" "Rotate\n" "Shortcut: 5" msgstr "" #: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89 msgid "Show Seam Edges" msgstr "" #: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1696 msgid "Menu" msgstr "" #: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1698 res/xrc/Settings.xrc:457 #: src/program/NormalsGenDialog.cpp:288 msgid "File" msgstr "" #: res/xrc/EditUV.xrc:101 msgid "Export UV Template...\tCtrl+E" msgstr "" #: res/xrc/EditUV.xrc:102 msgid "Export the UV layout as an image file." msgstr "" #: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:1823 msgid "Edit" msgstr "" #: res/xrc/EditUV.xrc:108 res/xrc/OutfitStudio.xrc:1825 msgid "Undo\tCtrl+Z" msgstr "" #: res/xrc/EditUV.xrc:109 res/xrc/OutfitStudio.xrc:1826 msgid "Undo the previous action." msgstr "" #: res/xrc/EditUV.xrc:112 res/xrc/OutfitStudio.xrc:1829 msgid "Redo\tCtrl+Y" msgstr "" #: res/xrc/EditUV.xrc:113 res/xrc/OutfitStudio.xrc:42 #: res/xrc/OutfitStudio.xrc:1830 msgid "Redo the next undone action." msgstr "" #: res/xrc/EditUV.xrc:117 msgid "Select All\tCtrl+A" msgstr "" #: res/xrc/EditUV.xrc:121 msgid "Invert Selection\tCtrl+I" msgstr "" #: res/xrc/EditUV.xrc:125 msgid "Select Less\tA" msgstr "" #: res/xrc/EditUV.xrc:126 msgid "Select less adjacent points in the selected islands." msgstr "" #: res/xrc/EditUV.xrc:129 msgid "Select More\tD" msgstr "" #: res/xrc/EditUV.xrc:130 msgid "Select more adjacent points in the selected islands." msgstr "" #: res/xrc/EditUV.xrc:134 msgid "Mask Selection" msgstr "" #: res/xrc/EditUV.xrc:135 msgid "Create a mask from the current UV selection for the mesh in the main viewport." msgstr "" #: res/xrc/EditUV.xrc:139 msgid "Translate...\tT" msgstr "" #: res/xrc/EditUV.xrc:140 msgid "Show a dialog to translate the current selection." msgstr "" #: res/xrc/EditUV.xrc:143 msgid "Rotate...\tR" msgstr "" #: res/xrc/EditUV.xrc:144 msgid "Show a dialog to rotate the current selection." msgstr "" #: res/xrc/EditUV.xrc:147 msgid "Scale...\tS" msgstr "" #: res/xrc/EditUV.xrc:148 msgid "Show a dialog to scale the current selection." msgstr "" #: res/xrc/EditUV.xrc:155 msgid "Translate" msgstr "" #: res/xrc/EditUV.xrc:296 msgid "Angle" msgstr "" #: res/xrc/EditUV.xrc:439 msgid "Uniform (UV)" msgstr "" #: res/xrc/EditUV.xrc:470 msgid "Export UV Template" msgstr "" #: res/xrc/EditUV.xrc:487 src/program/NormalsGenDialog.cpp:271 msgid "Resolution" msgstr "" #: res/xrc/EditUV.xrc:507 msgid "Wire Color" msgstr "" #: res/xrc/EditUV.xrc:520 res/xrc/Settings.xrc:341 msgid "Background Color" msgstr "" #: res/xrc/EditUV.xrc:535 msgid "Transparent Background" msgstr "" #: res/xrc/EditUV.xrc:545 msgid "Include Texture" msgstr "" #: res/xrc/EditUV.xrc:553 msgid "Wrap Mode" msgstr "" #: res/xrc/EditUV.xrc:561 msgid "Wrap" msgstr "" #: res/xrc/EditUV.xrc:562 msgid "Clamp" msgstr "" #: res/xrc/EditUV.xrc:573 msgid "Anti-Aliasing" msgstr "" #: res/xrc/GroupManager.xrc:17 msgid "Choose a group and add or remove members by selecting them in the lists." msgstr "" #: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:1016 msgid "Select a group XML file" msgstr "" #: res/xrc/GroupManager.xrc:71 msgid "Groups" msgstr "" #: res/xrc/GroupManager.xrc:101 msgid "Add Group" msgstr "" #: res/xrc/GroupManager.xrc:110 msgid "Remove Group" msgstr "" #: res/xrc/GroupManager.xrc:122 msgid "Members" msgstr "" #: res/xrc/GroupManager.xrc:137 msgid "Remove >>" msgstr "" #: res/xrc/GroupManager.xrc:151 msgid "Outfits" msgstr "" #: res/xrc/GroupManager.xrc:172 msgid "<< Add" msgstr "" #: res/xrc/ImportDialog.xrc:5 msgid "Import Options..." msgstr "" #: res/xrc/ImportDialog.xrc:89 msgid "Rotate (X)" msgstr "" #: res/xrc/ImportDialog.xrc:98 msgid "Choose X rotation." msgstr "" #: res/xrc/ImportDialog.xrc:113 msgid "Rotate (Y)" msgstr "" #: res/xrc/ImportDialog.xrc:122 msgid "Choose Y rotation." msgstr "" #: res/xrc/ImportDialog.xrc:137 msgid "Rotate (Z)" msgstr "" #: res/xrc/ImportDialog.xrc:146 msgid "Choose Z rotation." msgstr "" #: res/xrc/NormalsGenDlg.xrc:6 msgid "Normal Map Generator" msgstr "" #: res/xrc/NormalsGenDlg.xrc:21 msgid "Layers" msgstr "" #: res/xrc/NormalsGenDlg.xrc:37 msgid "Load or save preset layer settings." msgstr "" #: res/xrc/NormalsGenDlg.xrc:61 msgid "Add a new layer after the current one in the layer list." msgstr "" #: res/xrc/NormalsGenDlg.xrc:62 msgid "Add Layer" msgstr "" #: res/xrc/NormalsGenDlg.xrc:71 msgid "Move selected layer up one position." msgstr "" #: res/xrc/NormalsGenDlg.xrc:72 src/program/AutomationDialog.cpp:403 msgid "Move Up" msgstr "" #: res/xrc/NormalsGenDlg.xrc:87 msgid "Delete the selected layer." msgstr "" #: res/xrc/NormalsGenDlg.xrc:88 msgid "Delete Layer" msgstr "" #: res/xrc/NormalsGenDlg.xrc:114 msgid "Save a copy of an existing normal map if one already exists. File is saved in the original directory." msgstr "" #: res/xrc/NormalsGenDlg.xrc:115 msgid "Backup destination file" msgstr "" #: res/xrc/NormalsGenDlg.xrc:124 msgid "Compress output file using BC7 compression. This can make saving the file take a VERY long time!" msgstr "" #: res/xrc/NormalsGenDlg.xrc:125 msgid "Compress output " msgstr "" #: res/xrc/NormalsGenDlg.xrc:134 msgid "Use the file name specified in the background layer to save the normal map." msgstr "" #: res/xrc/NormalsGenDlg.xrc:135 msgid "Save to background layer file" msgstr "" #: res/xrc/NormalsGenDlg.xrc:145 msgid "Choose an output file..." msgstr "" #: res/xrc/NormalsGenDlg.xrc:149 msgid "Location to save normal map to." msgstr "" #: res/xrc/NormalsGenDlg.xrc:165 msgid "Display current settings on mesh in preview window." msgstr "" #: res/xrc/NormalsGenDlg.xrc:181 msgid "Generate and save the normal map file." msgstr "" #: res/xrc/NormalsGenDlg.xrc:182 msgid "Generate" msgstr "" #: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2084 msgid "Load Preset..." msgstr "" #: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2088 msgid "Save Preset..." msgstr "" #: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5 msgid "New Project" msgstr "" #: res/xrc/OutfitStudio.xrc:23 msgid "Create a new project by selecting a reference body slider set, and outfit model files." msgstr "" #: res/xrc/OutfitStudio.xrc:28 msgid "Load Project" msgstr "" #: res/xrc/OutfitStudio.xrc:29 msgid "Load a previously created slider set for editing." msgstr "" #: res/xrc/OutfitStudio.xrc:34 msgid "Undo" msgstr "" #: res/xrc/OutfitStudio.xrc:35 msgid "Undo a previous action." msgstr "" #: res/xrc/OutfitStudio.xrc:41 msgid "Redo" msgstr "" #: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2213 msgid "Select" msgstr "" #: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2214 msgid "Navigate and select meshes (or vertices in vertex mode)." msgstr "" #: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2218 #: src/program/NormalsGenDialog.cpp:295 msgid "Mask" msgstr "" #: res/xrc/OutfitStudio.xrc:58 res/xrc/OutfitStudio.xrc:2219 msgid "" "Mask vertices to prevent them from being transformed.\n" "Hold down the ALT key to remove masking." msgstr "" #: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2223 msgid "Inflate" msgstr "" #: res/xrc/OutfitStudio.xrc:65 res/xrc/OutfitStudio.xrc:2224 msgid "Increase mesh volume in an area." msgstr "" #: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2229 msgid "Deflate" msgstr "" #: res/xrc/OutfitStudio.xrc:72 res/xrc/OutfitStudio.xrc:2230 msgid "Decrease mesh volume in an area." msgstr "" #: res/xrc/OutfitStudio.xrc:79 res/xrc/OutfitStudio.xrc:2235 msgid "Move vertices over a plane parallel to the view." msgstr "" #: res/xrc/OutfitStudio.xrc:85 res/xrc/OutfitStudio.xrc:2239 msgid "Smooth" msgstr "" #: res/xrc/OutfitStudio.xrc:86 res/xrc/OutfitStudio.xrc:2240 msgid "Smooth an area of a mesh." msgstr "" #: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2244 msgid "Undiff" msgstr "" #: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2245 msgid "Undiff an area of a slider." msgstr "" #: res/xrc/OutfitStudio.xrc:99 res/xrc/OutfitStudio.xrc:2249 msgid "Weight Paint" msgstr "" #: res/xrc/OutfitStudio.xrc:100 msgid "" "Apply animation weight values for currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" #: res/xrc/OutfitStudio.xrc:107 res/xrc/OutfitStudio.xrc:2255 msgid "Color Paint" msgstr "" #: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2256 msgid "" "Apply vertex colors.\n" "Hold down the ALT key to remove colors." msgstr "" #: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2261 msgid "Alpha Paint" msgstr "" #: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2262 msgid "" "Apply vertex alpha.\n" "Hold down the ALT key to remove alpha." msgstr "" #: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2267 msgid "Collapse Vertex" msgstr "" #: res/xrc/OutfitStudio.xrc:124 res/xrc/OutfitStudio.xrc:2268 msgid "Deletes vertices with no more than three connections, without creating a hole." msgstr "" #: res/xrc/OutfitStudio.xrc:130 res/xrc/OutfitStudio.xrc:2272 msgid "Flip Edge" msgstr "" #: res/xrc/OutfitStudio.xrc:131 res/xrc/OutfitStudio.xrc:2273 msgid "Flips mesh edges so that the opposite pair of vertices is connected." msgstr "" #: res/xrc/OutfitStudio.xrc:137 res/xrc/OutfitStudio.xrc:2277 msgid "Split Edge" msgstr "" #: res/xrc/OutfitStudio.xrc:138 res/xrc/OutfitStudio.xrc:2278 msgid "Splits a mesh edge in two with a new vertex." msgstr "" #: res/xrc/OutfitStudio.xrc:144 res/xrc/OutfitStudio.xrc:2282 msgid "Move Vertex" msgstr "" #: res/xrc/OutfitStudio.xrc:145 res/xrc/OutfitStudio.xrc:2283 msgid "Moves a vertex." msgstr "" #: res/xrc/OutfitStudio.xrc:152 msgid "Depth Clip" msgstr "" #: res/xrc/OutfitStudio.xrc:154 msgid "Simulates lower depth buffer precision to help with depth-related clipping" msgstr "" #: res/xrc/OutfitStudio.xrc:161 msgid "Field of View" msgstr "" #: res/xrc/OutfitStudio.xrc:165 msgid "Field of View: 65" msgstr "" #: res/xrc/OutfitStudio.xrc:170 msgid "Brush Settings" msgstr "" #: res/xrc/OutfitStudio.xrc:175 msgid "Open Discord invite link." msgstr "" #: res/xrc/OutfitStudio.xrc:180 msgid "Open GitHub link." msgstr "" #: res/xrc/OutfitStudio.xrc:185 msgid "Open PayPal link." msgstr "" #: res/xrc/OutfitStudio.xrc:206 msgid "Transform" msgstr "" #: res/xrc/OutfitStudio.xrc:207 res/xrc/OutfitStudio.xrc:2289 msgid "Shows a transform tool to manipulate shapes and vertices with." msgstr "" #: res/xrc/OutfitStudio.xrc:213 msgid "Pivot" msgstr "" #: res/xrc/OutfitStudio.xrc:214 res/xrc/OutfitStudio.xrc:2294 msgid "Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale." msgstr "" #: res/xrc/OutfitStudio.xrc:220 msgid "Vertex Edit" msgstr "" #: res/xrc/OutfitStudio.xrc:221 msgid "" "Lets you select vertices to add to or remove from the mask.\n" "Click on a vertex to select/unmask it.\n" "Hold down CTRL to unselect/mask it." msgstr "" #: res/xrc/OutfitStudio.xrc:228 msgid "View Front" msgstr "" #: res/xrc/OutfitStudio.xrc:229 msgid "Change camera view to the front." msgstr "" #: res/xrc/OutfitStudio.xrc:233 msgid "View Back" msgstr "" #: res/xrc/OutfitStudio.xrc:234 msgid "Change camera view to the back." msgstr "" #: res/xrc/OutfitStudio.xrc:238 msgid "View Left" msgstr "" #: res/xrc/OutfitStudio.xrc:239 msgid "Change camera view to the left." msgstr "" #: res/xrc/OutfitStudio.xrc:243 msgid "View Right" msgstr "" #: res/xrc/OutfitStudio.xrc:244 msgid "Change camera view to the right." msgstr "" #: res/xrc/OutfitStudio.xrc:248 res/xrc/Settings.xrc:326 msgid "Perspective View" msgstr "" #: res/xrc/OutfitStudio.xrc:249 msgid "Toggle perspective view." msgstr "" #: res/xrc/OutfitStudio.xrc:255 msgid "Show Nodes" msgstr "" #: res/xrc/OutfitStudio.xrc:256 msgid "Toggle rendering of nodes." msgstr "" #: res/xrc/OutfitStudio.xrc:261 msgid "Show Bones" msgstr "" #: res/xrc/OutfitStudio.xrc:262 msgid "Toggle rendering of bones." msgstr "" #: res/xrc/OutfitStudio.xrc:267 msgid "Show Floor" msgstr "" #: res/xrc/OutfitStudio.xrc:268 msgid "Toggle rendering of the floor grid." msgstr "" #: res/xrc/OutfitStudio.xrc:274 msgid "X Mirror" msgstr "" #: res/xrc/OutfitStudio.xrc:275 res/xrc/OutfitStudio.xrc:1835 msgid "Mirror edits across the X axis." msgstr "" #: res/xrc/OutfitStudio.xrc:282 res/xrc/OutfitStudio.xrc:1841 msgid "Edit Connected Only\tC" msgstr "" #: res/xrc/OutfitStudio.xrc:283 msgid "Edit only vertices that are connected to the ones under the brush within the brush radius." msgstr "" #: res/xrc/OutfitStudio.xrc:289 res/xrc/OutfitStudio.xrc:1848 msgid "Merge Vertex" msgstr "" #: res/xrc/OutfitStudio.xrc:290 res/xrc/OutfitStudio.xrc:1849 msgid "Merges two vertices and fills any gaps." msgstr "" #: res/xrc/OutfitStudio.xrc:296 res/xrc/OutfitStudio.xrc:1855 msgid "Weld Vertex" msgstr "" #: res/xrc/OutfitStudio.xrc:297 res/xrc/OutfitStudio.xrc:1856 msgid "Welds two vertices while keeping the texture coordinates (UV) distinct." msgstr "" #: res/xrc/OutfitStudio.xrc:303 res/xrc/OutfitStudio.xrc:1862 msgid "Restrict To Surface" msgstr "" #: res/xrc/OutfitStudio.xrc:304 res/xrc/OutfitStudio.xrc:1863 msgid "Restricts motion to a mesh surface." msgstr "" #: res/xrc/OutfitStudio.xrc:310 res/xrc/OutfitStudio.xrc:1869 msgid "Restrict To Plane" msgstr "" #: res/xrc/OutfitStudio.xrc:311 res/xrc/OutfitStudio.xrc:1870 msgid "Restricts motion to parallel to the surface." msgstr "" #: res/xrc/OutfitStudio.xrc:317 res/xrc/OutfitStudio.xrc:1876 msgid "Restrict To Normal" msgstr "" #: res/xrc/OutfitStudio.xrc:318 res/xrc/OutfitStudio.xrc:1877 msgid "Restricts motion to perpendicular to the surface." msgstr "" #: res/xrc/OutfitStudio.xrc:381 msgid "Meshes" msgstr "" #: res/xrc/OutfitStudio.xrc:405 res/xrc/OutfitStudio.xrc:2597 #: res/xrc/OutfitStudio.xrc:2623 msgid "Segments" msgstr "" #: res/xrc/OutfitStudio.xrc:417 res/xrc/OutfitStudio.xrc:2630 #: res/xrc/OutfitStudio.xrc:2641 msgid "Partitions" msgstr "" #: res/xrc/OutfitStudio.xrc:429 msgid "Colors" msgstr "" #: res/xrc/OutfitStudio.xrc:441 msgid "Lights" msgstr "" #: res/xrc/OutfitStudio.xrc:481 msgid "Total Bones: 0" msgstr "" #: res/xrc/OutfitStudio.xrc:491 msgid "Shape Selection Bones: 0" msgstr "" #: res/xrc/OutfitStudio.xrc:521 msgid "Brush Color" msgstr "" #: res/xrc/OutfitStudio.xrc:530 msgid "Color of the brush." msgstr "" #: res/xrc/OutfitStudio.xrc:552 msgid "Clamp Max Value" msgstr "" #: res/xrc/OutfitStudio.xrc:595 src/program/OutfitStudio.cpp:3526 #: src/program/OutfitStudio.cpp:7385 msgid "Edit Alpha" msgstr "" #: res/xrc/OutfitStudio.xrc:604 msgid "Mask matching color" msgstr "" #: res/xrc/OutfitStudio.xrc:650 res/xrc/OutfitStudio.xrc:1054 #: res/xrc/OutfitStudio.xrc:1155 src/program/OutfitStudio.cpp:7100 #: src/program/OutfitStudio.cpp:12189 src/ui/wxBrushSettingsPopup.cpp:186 msgid "Reset" msgstr "" #: res/xrc/OutfitStudio.xrc:663 msgid "Ambient" msgstr "" #: res/xrc/OutfitStudio.xrc:688 msgid "Frontal" msgstr "" #: res/xrc/OutfitStudio.xrc:713 msgid "Directional 1" msgstr "" #: res/xrc/OutfitStudio.xrc:738 msgid "Directional 2" msgstr "" #: res/xrc/OutfitStudio.xrc:763 msgid "Directional 3" msgstr "" #: res/xrc/OutfitStudio.xrc:931 msgid "Slot" msgstr "" #: res/xrc/OutfitStudio.xrc:1006 src/program/OutfitStudio.cpp:6048 msgid "SSF File" msgstr "" #: res/xrc/OutfitStudio.xrc:1026 msgid "Set" msgstr "" #: res/xrc/OutfitStudio.xrc:1044 res/xrc/OutfitStudio.xrc:1145 #: src/program/OutfitStudio.cpp:7100 msgid "Apply" msgstr "" #: res/xrc/OutfitStudio.xrc:1173 msgid "De-/Select Sliders" msgstr "" #: res/xrc/OutfitStudio.xrc:1192 msgid "Fixed Weight Brush" msgstr "" #: res/xrc/OutfitStudio.xrc:1203 msgid "Normalize Weights" msgstr "" #: res/xrc/OutfitStudio.xrc:1220 msgid "X-Mirror Bone" msgstr "" #: res/xrc/OutfitStudio.xrc:1245 msgid "Masks" msgstr "" #: res/xrc/OutfitStudio.xrc:1297 msgid "Export..." msgstr "" #: res/xrc/OutfitStudio.xrc:1306 msgid "Import..." msgstr "" #: res/xrc/OutfitStudio.xrc:1322 msgid "Posing" msgstr "" #: res/xrc/OutfitStudio.xrc:1383 msgid "Show Pose" msgstr "" #: res/xrc/OutfitStudio.xrc:1401 msgid "Reset Bone" msgstr "" #: res/xrc/OutfitStudio.xrc:1421 msgid "Rotation X" msgstr "" #: res/xrc/OutfitStudio.xrc:1449 msgid "Rotation Y" msgstr "" #: res/xrc/OutfitStudio.xrc:1477 msgid "Rotation Z" msgstr "" #: res/xrc/OutfitStudio.xrc:1505 msgid "Offset X" msgstr "" #: res/xrc/OutfitStudio.xrc:1533 msgid "Offset Y" msgstr "" #: res/xrc/OutfitStudio.xrc:1561 msgid "Offset Z" msgstr "" #: res/xrc/OutfitStudio.xrc:1623 msgid "Reset All" msgstr "" #: res/xrc/OutfitStudio.xrc:1631 msgid "Apply to Mesh" msgstr "" #: res/xrc/OutfitStudio.xrc:1659 msgid "Notes" msgstr "" #: res/xrc/OutfitStudio.xrc:1700 msgid "New Project...\tCtrl+N" msgstr "" #: res/xrc/OutfitStudio.xrc:1701 msgid "Create a new outfit project." msgstr "" #: res/xrc/OutfitStudio.xrc:1704 msgid "Load Project..\tCtrl+O" msgstr "" #: res/xrc/OutfitStudio.xrc:1705 msgid "Load a project." msgstr "" #: res/xrc/OutfitStudio.xrc:1708 msgid "Add Project..\tCtrl+Shift+O" msgstr "" #: res/xrc/OutfitStudio.xrc:1709 msgid "Add a project without replacing the current one." msgstr "" #: res/xrc/OutfitStudio.xrc:1712 msgid "Unload Project...\tCtrl+W" msgstr "" #: res/xrc/OutfitStudio.xrc:1713 msgid "Unloads the project and creates an empty new one." msgstr "" #: res/xrc/OutfitStudio.xrc:1716 msgid "Recent Projects..." msgstr "" #: res/xrc/OutfitStudio.xrc:1721 msgid "Load Reference..." msgstr "" #: res/xrc/OutfitStudio.xrc:1722 msgid "Load a new reference slider set, replacing any current reference objects." msgstr "" #: res/xrc/OutfitStudio.xrc:1725 msgid "Load Outfit..." msgstr "" #: res/xrc/OutfitStudio.xrc:1726 msgid "Load a NIF file as the working outfit, replacing any current outfit objects." msgstr "" #: res/xrc/OutfitStudio.xrc:1730 msgid "Convert / Replace Reference...\tCtrl+Shift+R" msgstr "" #: res/xrc/OutfitStudio.xrc:1731 msgid "Convert to or replace an outfit's body/reference" msgstr "" #: res/xrc/OutfitStudio.xrc:1734 msgid "Open Automation...\tCtrl+Shift+A" msgstr "" #: res/xrc/OutfitStudio.xrc:1735 msgid "Open the automation dialog to create, load and execute automation scripts." msgstr "" #: res/xrc/OutfitStudio.xrc:1739 msgid "Save Project\tCtrl+S" msgstr "" #: res/xrc/OutfitStudio.xrc:1740 msgid "Save the project." msgstr "" #: res/xrc/OutfitStudio.xrc:1744 msgid "Save Project As...\tCtrl+Shift+S" msgstr "" #: res/xrc/OutfitStudio.xrc:1745 msgid "Save the project under a new name." msgstr "" #: res/xrc/OutfitStudio.xrc:1749 res/xrc/OutfitStudio.xrc:2106 #: src/program/OutfitStudio.cpp:8031 src/program/OutfitStudio.cpp:8142 #: src/program/OutfitStudio.cpp:8274 msgid "Import" msgstr "" #: res/xrc/OutfitStudio.xrc:1751 msgid "From NIF..." msgstr "" #: res/xrc/OutfitStudio.xrc:1752 msgid "Choose a NIF file to import into the project." msgstr "" #: res/xrc/OutfitStudio.xrc:1755 msgid "From OBJ..." msgstr "" #: res/xrc/OutfitStudio.xrc:1756 msgid "Import an OBJ file as a new shape in the outfit." msgstr "" #: res/xrc/OutfitStudio.xrc:1759 msgid "From FBX..." msgstr "" #: res/xrc/OutfitStudio.xrc:1760 msgid "Import an FBX file as a new shape in the outfit." msgstr "" #: res/xrc/OutfitStudio.xrc:1763 msgid "From TRI (Head)..." msgstr "" #: res/xrc/OutfitStudio.xrc:1764 msgid "Import shape and morphs from a head TRI file." msgstr "" #: res/xrc/OutfitStudio.xrc:1767 msgid "Import Data" msgstr "" #: res/xrc/OutfitStudio.xrc:1769 msgid "Import BSClothExtraData From HKX" msgstr "" #: res/xrc/OutfitStudio.xrc:1770 msgid "Choose an HKX file to import as a BSClothExtraData block into the project." msgstr "" #: res/xrc/OutfitStudio.xrc:1775 res/xrc/OutfitStudio.xrc:1909 #: res/xrc/OutfitStudio.xrc:2142 res/xrc/OutfitStudio.xrc:2407 msgid "Export" msgstr "" #: res/xrc/OutfitStudio.xrc:1777 msgid "To NIF...\tCtrl+E" msgstr "" #: res/xrc/OutfitStudio.xrc:1778 msgid "Save the current project as a NIF file (without reference)" msgstr "" #: res/xrc/OutfitStudio.xrc:1781 msgid "To NIF With Reference...\tCtrl+Alt+E" msgstr "" #: res/xrc/OutfitStudio.xrc:1782 msgid "Save the current project as a NIF file (including reference)" msgstr "" #: res/xrc/OutfitStudio.xrc:1785 res/xrc/OutfitStudio.xrc:1915 #: res/xrc/OutfitStudio.xrc:2413 msgid "To OBJ..." msgstr "" #: res/xrc/OutfitStudio.xrc:1786 msgid "Export the current project as an OBJ file." msgstr "" #: res/xrc/OutfitStudio.xrc:1789 res/xrc/OutfitStudio.xrc:1919 #: res/xrc/OutfitStudio.xrc:2417 msgid "To FBX..." msgstr "" #: res/xrc/OutfitStudio.xrc:1790 msgid "Export the current project as an FBX file." msgstr "" #: res/xrc/OutfitStudio.xrc:1793 res/xrc/OutfitStudio.xrc:1923 #: res/xrc/OutfitStudio.xrc:2421 msgid "To TRI (Head)..." msgstr "" #: res/xrc/OutfitStudio.xrc:1794 res/xrc/OutfitStudio.xrc:1924 #: res/xrc/OutfitStudio.xrc:2422 msgid "Export head morphs to a TRI file." msgstr "" #: res/xrc/OutfitStudio.xrc:1797 msgid "Export Data" msgstr "" #: res/xrc/OutfitStudio.xrc:1799 msgid "Export BSClothExtraData As HKX" msgstr "" #: res/xrc/OutfitStudio.xrc:1800 msgid "Save one of the currently loaded BSClothExtraData blocks to an HKX file." msgstr "" #: res/xrc/OutfitStudio.xrc:1805 msgid "Make Conversion Reference" msgstr "" #: res/xrc/OutfitStudio.xrc:1806 msgid "Using the current slider settings for the reference shape, create a new reference that will morph from the current shape back to the base shape." msgstr "" #: res/xrc/OutfitStudio.xrc:1810 res/xrc/Project.xrc:972 msgid "Pack Projects..." msgstr "" #: res/xrc/OutfitStudio.xrc:1811 msgid "Pack one or more projects into a folder or archive for sharing." msgstr "" #: res/xrc/OutfitStudio.xrc:1818 msgid "Exit\tAlt+F4" msgstr "" #: res/xrc/OutfitStudio.xrc:1819 msgid "Exit Outfit Studio." msgstr "" #: res/xrc/OutfitStudio.xrc:1834 msgid "X Mirror\tX" msgstr "" #: res/xrc/OutfitStudio.xrc:1842 msgid "Edit only vertices that are connected to the ones under the brush within the brush radius" msgstr "" #: res/xrc/OutfitStudio.xrc:1884 msgid "Recalculate Normals" msgstr "" #: res/xrc/OutfitStudio.xrc:1885 msgid "Recalculate normals on active mesh" msgstr "" #: res/xrc/OutfitStudio.xrc:1888 msgid "Disable Normals Calculation" msgstr "" #: res/xrc/OutfitStudio.xrc:1889 msgid "Turn off all automatic recalculation of normals on all meshes. Only applies to Outfit Studio." msgstr "" #: res/xrc/OutfitStudio.xrc:1895 msgid "Resets the shape and skin transforms." msgstr "" #: res/xrc/OutfitStudio.xrc:1898 src/program/OutfitStudio.cpp:11640 msgid "Delete Unreferenced Nodes" msgstr "" #: res/xrc/OutfitStudio.xrc:1899 msgid "Deletes all nodes from the project that aren't used in any other block." msgstr "" #: res/xrc/OutfitStudio.xrc:1903 msgid "Removes skinning of all shapes and all unused nodes." msgstr "" #: res/xrc/OutfitStudio.xrc:1907 res/xrc/OutfitStudio.xrc:2405 msgid "Shape" msgstr "" #: res/xrc/OutfitStudio.xrc:1911 res/xrc/OutfitStudio.xrc:2409 msgid "To NIF..." msgstr "" #: res/xrc/OutfitStudio.xrc:1912 res/xrc/OutfitStudio.xrc:2410 msgid "Export only the selected shapes to a NIF file." msgstr "" #: res/xrc/OutfitStudio.xrc:1916 res/xrc/OutfitStudio.xrc:2414 msgid "Export only the selected shapes to an OBJ file." msgstr "" #: res/xrc/OutfitStudio.xrc:1920 res/xrc/OutfitStudio.xrc:2418 msgid "Export only the selected shapes to an FBX file." msgstr "" #: res/xrc/OutfitStudio.xrc:1928 res/xrc/OutfitStudio.xrc:2426 #: res/xrc/Slider.xrc:200 msgid "UV" msgstr "" #: res/xrc/OutfitStudio.xrc:1930 res/xrc/OutfitStudio.xrc:2428 msgid "Edit..." msgstr "" #: res/xrc/OutfitStudio.xrc:1931 res/xrc/OutfitStudio.xrc:2429 msgid "Edit the texture coordinates." msgstr "" #: res/xrc/OutfitStudio.xrc:1934 msgid "Invert X (Mirror)" msgstr "" #: res/xrc/OutfitStudio.xrc:1935 msgid "Inverts the X-axis to mirror the texture coordinates." msgstr "" #: res/xrc/OutfitStudio.xrc:1938 msgid "Invert Y (Flip)" msgstr "" #: res/xrc/OutfitStudio.xrc:1939 msgid "Inverts the Y-axis to flip the texture coordinates." msgstr "" #: res/xrc/OutfitStudio.xrc:1943 res/xrc/OutfitStudio.xrc:2441 msgid "Delete Vertices...\tShift+Del" msgstr "" #: res/xrc/OutfitStudio.xrc:1944 res/xrc/OutfitStudio.xrc:2442 msgid "Deletes all unmasked vertices of the currently selected shapes." msgstr "" #: res/xrc/OutfitStudio.xrc:1947 res/xrc/OutfitStudio.xrc:2445 msgid "Separate Vertices...\tShift+S" msgstr "" #: res/xrc/OutfitStudio.xrc:1948 res/xrc/OutfitStudio.xrc:2446 msgid "Separate the current shape into two by using the mask." msgstr "" #: res/xrc/OutfitStudio.xrc:1951 res/xrc/OutfitStudio.xrc:2449 msgid "Mirror Shape..." msgstr "" #: res/xrc/OutfitStudio.xrc:1952 res/xrc/OutfitStudio.xrc:2450 msgid "Mirror the selected shapes on any axis." msgstr "" #: res/xrc/OutfitStudio.xrc:1955 res/xrc/OutfitStudio.xrc:2453 msgid "Merge Geometry..." msgstr "" #: res/xrc/OutfitStudio.xrc:1956 res/xrc/OutfitStudio.xrc:2454 msgid "Copies vertices and triangles from one shape to another." msgstr "" #: res/xrc/OutfitStudio.xrc:1959 res/xrc/OutfitStudio.xrc:2457 msgid "Duplicate..." msgstr "" #: res/xrc/OutfitStudio.xrc:1960 res/xrc/OutfitStudio.xrc:2458 msgid "Duplicate the current shape." msgstr "" #: res/xrc/OutfitStudio.xrc:1964 res/xrc/OutfitStudio.xrc:2462 msgid "Splits all edges between unmasked vertices" msgstr "" #: res/xrc/OutfitStudio.xrc:1967 res/xrc/OutfitStudio.xrc:2465 msgid "Rename...\tF2" msgstr "" #: res/xrc/OutfitStudio.xrc:1968 res/xrc/OutfitStudio.xrc:2466 msgid "Change the name of the current shape." msgstr "" #: res/xrc/OutfitStudio.xrc:1971 res/xrc/OutfitStudio.xrc:2469 msgid "Set Reference" msgstr "" #: res/xrc/OutfitStudio.xrc:1972 res/xrc/OutfitStudio.xrc:2470 msgid "Turn the shape into the reference shape of the project." msgstr "" #: res/xrc/OutfitStudio.xrc:1976 res/xrc/OutfitStudio.xrc:2474 msgid "Move..." msgstr "" #: res/xrc/OutfitStudio.xrc:1977 res/xrc/OutfitStudio.xrc:2475 msgid "Apply an offset adjustment to the mesh vertices. This permanently moves vertices." msgstr "" #: res/xrc/OutfitStudio.xrc:1980 res/xrc/OutfitStudio.xrc:2478 msgid "Scale..." msgstr "" #: res/xrc/OutfitStudio.xrc:1981 res/xrc/OutfitStudio.xrc:2479 msgid "Apply a scale adjustment to the shape. This permanently moves vertices." msgstr "" #: res/xrc/OutfitStudio.xrc:1984 res/xrc/OutfitStudio.xrc:2482 msgid "Rotate..." msgstr "" #: res/xrc/OutfitStudio.xrc:1985 res/xrc/OutfitStudio.xrc:2483 msgid "Apply a rotation to the mesh vertices. This permanently moves vertices." msgstr "" #: res/xrc/OutfitStudio.xrc:1988 res/xrc/OutfitStudio.xrc:2486 msgid "Inflate..." msgstr "" #: res/xrc/OutfitStudio.xrc:1989 res/xrc/OutfitStudio.xrc:2487 msgid "Inflates/deflates a shape along its normals. This permanently moves vertices." msgstr "" #: res/xrc/OutfitStudio.xrc:1992 res/xrc/OutfitStudio.xrc:2074 #: res/xrc/OutfitStudio.xrc:2490 msgid "Fix Clipping..." msgstr "" #: res/xrc/OutfitStudio.xrc:1993 res/xrc/OutfitStudio.xrc:2491 msgid "Fixes clipping of outfit vertices that penetrate the reference shape." msgstr "" #: res/xrc/OutfitStudio.xrc:1997 msgid "Normals" msgstr "" #: res/xrc/OutfitStudio.xrc:1999 msgid "Smooth Seam Normals" msgstr "" #: res/xrc/OutfitStudio.xrc:2000 msgid "Smooths edges of seams (usually found at texture borders), disable if this causes odd normals on the shape." msgstr "" #: res/xrc/OutfitStudio.xrc:2005 msgid "Edit Smoothing Angle..." msgstr "" #: res/xrc/OutfitStudio.xrc:2006 msgid "Angle, in degrees, that controls the threshold at which normal seams are smoothed." msgstr "" #: res/xrc/OutfitStudio.xrc:2009 msgid "Lock Normals" msgstr "" #: res/xrc/OutfitStudio.xrc:2010 msgid "Locks the mesh normals. Enable if you want to keep custom normals intact." msgstr "" #: res/xrc/OutfitStudio.xrc:2018 res/xrc/OutfitStudio.xrc:2496 msgid "Copies all bone weights from the reference shape to the current shape." msgstr "" #: res/xrc/OutfitStudio.xrc:2021 res/xrc/OutfitStudio.xrc:2499 msgid "Transfer Selected Weights" msgstr "" #: res/xrc/OutfitStudio.xrc:2022 res/xrc/OutfitStudio.xrc:2500 msgid "Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order." msgstr "" #: res/xrc/OutfitStudio.xrc:2025 res/xrc/OutfitStudio.xrc:2503 #: res/xrc/OutfitStudio.xrc:2578 msgid "Mask Weighted Vertices" msgstr "" #: res/xrc/OutfitStudio.xrc:2026 res/xrc/OutfitStudio.xrc:2504 msgid "Masks vertices with bone weights, so you can manually assign weights to unweighted vertices." msgstr "" #: res/xrc/OutfitStudio.xrc:2029 msgid "Check For Bad Bones..." msgstr "" #: res/xrc/OutfitStudio.xrc:2030 res/xrc/OutfitStudio.xrc:2508 msgid "Looks for bones with inconsistencies in their transforms. If any are found, a dialog is opened to give options for fixing them." msgstr "" #: res/xrc/OutfitStudio.xrc:2034 res/xrc/OutfitStudio.xrc:2512 msgid "Copy Partitions/Segments..." msgstr "" #: res/xrc/OutfitStudio.xrc:2035 res/xrc/OutfitStudio.xrc:2513 msgid "Copies partitions/segments and all triangle assignments from the reference shape to the current shape." msgstr "" #: res/xrc/OutfitStudio.xrc:2039 res/xrc/OutfitStudio.xrc:2517 msgid "Mask Symmetric Vertices..." msgstr "" #: res/xrc/OutfitStudio.xrc:2040 res/xrc/OutfitStudio.xrc:2518 msgid "Masks unmasked vertices that have a mirrored vertex with identical data." msgstr "" #: res/xrc/OutfitStudio.xrc:2043 res/xrc/OutfitStudio.xrc:2521 msgid "Symmetrize Vertices..." msgstr "" #: res/xrc/OutfitStudio.xrc:2044 res/xrc/OutfitStudio.xrc:2522 msgid "Changes vertex data to be identical to mirrored vertices." msgstr "" #: res/xrc/OutfitStudio.xrc:2047 res/xrc/OutfitStudio.xrc:2525 msgid "Mask Symmetric Triangles" msgstr "" #: res/xrc/OutfitStudio.xrc:2048 res/xrc/OutfitStudio.xrc:2526 msgid "Masks triangles that can be matched to a mirrored triangle." msgstr "" #: res/xrc/OutfitStudio.xrc:2052 res/xrc/OutfitStudio.xrc:2530 msgid "Delete\tDel" msgstr "" #: res/xrc/OutfitStudio.xrc:2053 res/xrc/OutfitStudio.xrc:2531 msgid "Removes the currently selected shape from the outfit." msgstr "" #: res/xrc/OutfitStudio.xrc:2059 res/xrc/OutfitStudio.xrc:2534 msgid "Properties..." msgstr "" #: res/xrc/OutfitStudio.xrc:2060 res/xrc/OutfitStudio.xrc:2535 msgid "Opens the properties dialog for shader, texture and more settings of the selected shape." msgstr "" #: res/xrc/OutfitStudio.xrc:2064 msgid "Slider" msgstr "" #: res/xrc/OutfitStudio.xrc:2066 msgid "Conform Selected\tCtrl+C" msgstr "" #: res/xrc/OutfitStudio.xrc:2067 msgid "Conform selected outfit shape to all checked sliders." msgstr "" #: res/xrc/OutfitStudio.xrc:2070 msgid "Conform All\tCtrl+Shift+C" msgstr "" #: res/xrc/OutfitStudio.xrc:2071 msgid "Conform all outfit shapes to all checked sliders." msgstr "" #: res/xrc/OutfitStudio.xrc:2075 msgid "Fixes clipping of outfit vertices that penetrate the reference shape for the active slider." msgstr "" #: res/xrc/OutfitStudio.xrc:2080 msgid "Set the current outfit shape as the base shape and clear slider data." msgstr "" #: res/xrc/OutfitStudio.xrc:2085 msgid "Load and preview a slider preset. Inverted sliders will have inverted values." msgstr "" #: res/xrc/OutfitStudio.xrc:2089 msgid "Save a slider preset with the current values. Inverted sliders will have inverted values." msgstr "" #: res/xrc/OutfitStudio.xrc:2093 msgid "New Slider" msgstr "" #: res/xrc/OutfitStudio.xrc:2094 msgid "Create a new shape transformation slider." msgstr "" #: res/xrc/OutfitStudio.xrc:2097 msgid "Coalesce sliders" msgstr "" #: res/xrc/OutfitStudio.xrc:2098 msgid "Create a new shape transformation slider based on the current slider values" msgstr "" #: res/xrc/OutfitStudio.xrc:2101 msgid "New Zap Slider" msgstr "" #: res/xrc/OutfitStudio.xrc:2102 msgid "Create a new Zap slider based on unmasked vertices" msgstr "" #: res/xrc/OutfitStudio.xrc:2108 msgid "Import OSD..." msgstr "" #: res/xrc/OutfitStudio.xrc:2109 msgid "Imports OSD file and creates sliders for shapes with a matching name." msgstr "" #: res/xrc/OutfitStudio.xrc:2112 msgid "Import TRI Morphs..." msgstr "" #: res/xrc/OutfitStudio.xrc:2113 msgid "Imports TRI morphs from a TRI file and creates sliders for shapes with a matching name." msgstr "" #: res/xrc/OutfitStudio.xrc:2116 msgid "Import Starfield morphs..." msgstr "" #: res/xrc/OutfitStudio.xrc:2117 msgid "Imports Starfield morph.dat file and creates sliders for shapes with a matching name." msgstr "" #: res/xrc/OutfitStudio.xrc:2121 msgid "Import to active slider" msgstr "" #: res/xrc/OutfitStudio.xrc:2123 msgid "Import NIF..." msgstr "" #: res/xrc/OutfitStudio.xrc:2124 msgid "Import a NIF file and overwrites the current shape's slider data." msgstr "" #: res/xrc/OutfitStudio.xrc:2127 msgid "Import BSD..." msgstr "" #: res/xrc/OutfitStudio.xrc:2128 msgid "Import a BodySlide BSD file and overwrites the current shape's slider data." msgstr "" #: res/xrc/OutfitStudio.xrc:2131 msgid "Import OBJ..." msgstr "" #: res/xrc/OutfitStudio.xrc:2132 msgid "Import an OBJ file matching the current shape's vertex count, and calculate slider data from the difference." msgstr "" #: res/xrc/OutfitStudio.xrc:2135 msgid "Import FBX..." msgstr "" #: res/xrc/OutfitStudio.xrc:2136 msgid "Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference." msgstr "" #: res/xrc/OutfitStudio.xrc:2144 msgid "Export OSD..." msgstr "" #: res/xrc/OutfitStudio.xrc:2145 msgid "Exports all currently loaded slider data to an OSD file." msgstr "" #: res/xrc/OutfitStudio.xrc:2148 msgid "Export TRI Morphs..." msgstr "" #: res/xrc/OutfitStudio.xrc:2149 msgid "Exports TRI morphs to a TRI file." msgstr "" #: res/xrc/OutfitStudio.xrc:2152 msgid "Export Starfield morphs..." msgstr "" #: res/xrc/OutfitStudio.xrc:2153 msgid "Exports Starfield morph.dat file." msgstr "" #: res/xrc/OutfitStudio.xrc:2156 msgid "Export to OBJs..." msgstr "" #: res/xrc/OutfitStudio.xrc:2157 msgid "Export all sliders to an OBJ file per slider." msgstr "" #: res/xrc/OutfitStudio.xrc:2161 msgid "Export active slider" msgstr "" #: res/xrc/OutfitStudio.xrc:2163 msgid "Export NIF..." msgstr "" #: res/xrc/OutfitStudio.xrc:2164 msgid "Exports the current slider's data as a NIF file." msgstr "" #: res/xrc/OutfitStudio.xrc:2167 msgid "Export BSD..." msgstr "" #: res/xrc/OutfitStudio.xrc:2168 msgid "Exports the current slider's data as a BodySlide BSD file." msgstr "" #: res/xrc/OutfitStudio.xrc:2171 msgid "Export OBJ..." msgstr "" #: res/xrc/OutfitStudio.xrc:2172 msgid "Exports the current slider's data as an OBJ file." msgstr "" #: res/xrc/OutfitStudio.xrc:2179 src/program/OutfitStudio.cpp:8681 msgid "Clone Slider" msgstr "" #: res/xrc/OutfitStudio.xrc:2180 msgid "Clones the current slider." msgstr "" #: res/xrc/OutfitStudio.xrc:2184 msgid "Negate Slider" msgstr "" #: res/xrc/OutfitStudio.xrc:2185 msgid "Negates the current slider, reversing it's effect" msgstr "" #: res/xrc/OutfitStudio.xrc:2189 msgid "Mask Affected Vertices" msgstr "" #: res/xrc/OutfitStudio.xrc:2190 msgid "Masks the vertices the slider is affecting for all selected shapes." msgstr "" #: res/xrc/OutfitStudio.xrc:2194 msgid "Clear Slider Data" msgstr "" #: res/xrc/OutfitStudio.xrc:2195 msgid "Erases the slider data without removing the slider itself. (Cannot be undone)" msgstr "" #: res/xrc/OutfitStudio.xrc:2198 msgid "Delete Slider\tCtrl+Del" msgstr "" #: res/xrc/OutfitStudio.xrc:2199 msgid "Delete the active slider from the project. (Cannot be undone)" msgstr "" #: res/xrc/OutfitStudio.xrc:2203 msgid "Properties...\tTab" msgstr "" #: res/xrc/OutfitStudio.xrc:2204 src/ui/wxSliderPanel.cpp:71 msgid "Display and edit the active slider's properties." msgstr "" #: res/xrc/OutfitStudio.xrc:2209 msgid "Tool" msgstr "" #: res/xrc/OutfitStudio.xrc:2211 msgid "Current Tool" msgstr "" #: res/xrc/OutfitStudio.xrc:2250 msgid "" "Apply animation weight values for the currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" #: res/xrc/OutfitStudio.xrc:2288 msgid "Transform\tF" msgstr "" #: res/xrc/OutfitStudio.xrc:2293 msgid "Pivot\tP" msgstr "" #: res/xrc/OutfitStudio.xrc:2298 msgid "Vertex Edit\tQ" msgstr "" #: res/xrc/OutfitStudio.xrc:2299 msgid "" "Shows vertex points and lets you mask/unmask them.\n" "Without any brush active, click on a vertex to unmask it.\n" "Hold down CTRL to mask it." msgstr "" #: res/xrc/OutfitStudio.xrc:2304 msgid "Increase Brush Size\tShift++" msgstr "" #: res/xrc/OutfitStudio.xrc:2305 msgid "Increase brush diameter" msgstr "" #: res/xrc/OutfitStudio.xrc:2308 msgid "Decrease Brush Size\tShift+-" msgstr "" #: res/xrc/OutfitStudio.xrc:2309 msgid "Decrease brush diameter" msgstr "" #: res/xrc/OutfitStudio.xrc:2312 msgid "Increase Brush Strength\tCtrl++" msgstr "" #: res/xrc/OutfitStudio.xrc:2313 msgid "Increase brush strength" msgstr "" #: res/xrc/OutfitStudio.xrc:2316 msgid "Decrease Brush Strength\tCtrl+-" msgstr "" #: res/xrc/OutfitStudio.xrc:2317 msgid "Decrease brush strength" msgstr "" #: res/xrc/OutfitStudio.xrc:2321 msgid "Mask Less\tA" msgstr "" #: res/xrc/OutfitStudio.xrc:2322 msgid "Mask Less" msgstr "" #: res/xrc/OutfitStudio.xrc:2325 msgid "Mask More\tD" msgstr "" #: res/xrc/OutfitStudio.xrc:2326 msgid "Mask More" msgstr "" #: res/xrc/OutfitStudio.xrc:2330 msgid "Invert Mask\tCtrl+I" msgstr "" #: res/xrc/OutfitStudio.xrc:2331 msgid "Invert Mask" msgstr "" #: res/xrc/OutfitStudio.xrc:2334 msgid "Clear Mask\tCtrl+A" msgstr "" #: res/xrc/OutfitStudio.xrc:2335 msgid "Clear Mask" msgstr "" #: res/xrc/OutfitStudio.xrc:2339 msgid "View" msgstr "" #: res/xrc/OutfitStudio.xrc:2341 msgid "Front\tShift+1" msgstr "" #: res/xrc/OutfitStudio.xrc:2344 msgid "Back\tShift+2" msgstr "" #: res/xrc/OutfitStudio.xrc:2347 msgid "Left\tShift+3" msgstr "" #: res/xrc/OutfitStudio.xrc:2350 msgid "Right\tShift+4" msgstr "" #: res/xrc/OutfitStudio.xrc:2353 msgid "Perspective\tShift+5" msgstr "" #: res/xrc/OutfitStudio.xrc:2358 msgid "Toggle Rotation Center\tShift+R" msgstr "" #: res/xrc/OutfitStudio.xrc:2359 msgid "Switch between the different rotation center modes." msgstr "" #: res/xrc/OutfitStudio.xrc:2362 msgid "Show Nodes\tShift+N" msgstr "" #: res/xrc/OutfitStudio.xrc:2366 msgid "Show Bones\tShift+B" msgstr "" #: res/xrc/OutfitStudio.xrc:2370 msgid "Show Floor\tG" msgstr "" #: res/xrc/OutfitStudio.xrc:2375 msgid "Toggle Visibility\tE" msgstr "" #: res/xrc/OutfitStudio.xrc:2376 msgid "Switch between the different visibility modes for the selected shapes." msgstr "" #: res/xrc/OutfitStudio.xrc:2379 msgid "Show Wireframe\tW" msgstr "" #: res/xrc/OutfitStudio.xrc:2380 msgid "Show wireframe on all models." msgstr "" #: res/xrc/OutfitStudio.xrc:2384 msgid "Enable Lighting\tL" msgstr "" #: res/xrc/OutfitStudio.xrc:2385 msgid "Turn on or off lighting." msgstr "" #: res/xrc/OutfitStudio.xrc:2390 msgid "Enable Textures\tT" msgstr "" #: res/xrc/OutfitStudio.xrc:2391 msgid "Display texture maps on models." msgstr "" #: res/xrc/OutfitStudio.xrc:2396 msgid "Enable Vertex Colors" msgstr "" #: res/xrc/OutfitStudio.xrc:2397 msgid "Display vertex colors on models." msgstr "" #: res/xrc/OutfitStudio.xrc:2432 msgid "Invert X" msgstr "" #: res/xrc/OutfitStudio.xrc:2433 msgid "Inverts the X-axis of the texture coordinates." msgstr "" #: res/xrc/OutfitStudio.xrc:2436 msgid "Invert Y" msgstr "" #: res/xrc/OutfitStudio.xrc:2437 msgid "Inverts the Y-axis of the texture coordinates." msgstr "" #: res/xrc/OutfitStudio.xrc:2507 msgid "Check For Bad Bones" msgstr "" #: res/xrc/OutfitStudio.xrc:2541 msgid "Bad Bone" msgstr "" #: res/xrc/OutfitStudio.xrc:2543 msgid "Set Skin Transform From Node" msgstr "" #: res/xrc/OutfitStudio.xrc:2544 msgid "Fixes the bad bone by calculating a new skin-to-bone transform." msgstr "" #: res/xrc/OutfitStudio.xrc:2547 msgid "Set Node Transform From Skin" msgstr "" #: res/xrc/OutfitStudio.xrc:2548 msgid "Fixes the bad custom bone by calculating a new bone-to-global transform." msgstr "" #: res/xrc/OutfitStudio.xrc:2552 res/xrc/OutfitStudio.xrc:2585 #: res/xrc/ShapeProperties.xrc:280 res/xrc/ShapeProperties.xrc:438 #: res/xrc/ShapeProperties.xrc:611 msgid "Add" msgstr "" #: res/xrc/OutfitStudio.xrc:2554 res/xrc/OutfitStudio.xrc:2587 msgid "From Skeleton..." msgstr "" #: res/xrc/OutfitStudio.xrc:2555 res/xrc/OutfitStudio.xrc:2588 msgid "Choose a bone from the reference skeleton to add to the project." msgstr "" #: res/xrc/OutfitStudio.xrc:2558 res/xrc/OutfitStudio.xrc:2591 msgid "Custom Bone..." msgstr "" #: res/xrc/OutfitStudio.xrc:2559 res/xrc/OutfitStudio.xrc:2592 msgid "Add a custom bone to the project." msgstr "" #: res/xrc/OutfitStudio.xrc:2565 msgid "From Project" msgstr "" #: res/xrc/OutfitStudio.xrc:2566 msgid "Delete bone(s) from all shapes of the project." msgstr "" #: res/xrc/OutfitStudio.xrc:2569 msgid "From Selected Shapes" msgstr "" #: res/xrc/OutfitStudio.xrc:2570 msgid "Delete bone(s) from only the selected shapes." msgstr "" #: res/xrc/OutfitStudio.xrc:2574 msgid "Edit Bone..." msgstr "" #: res/xrc/OutfitStudio.xrc:2575 msgid "Edit a custom bone or view a standard bone." msgstr "" #: res/xrc/OutfitStudio.xrc:2579 msgid "Masks vertices with weights for the selected bones." msgstr "" #: res/xrc/OutfitStudio.xrc:2599 res/xrc/OutfitStudio.xrc:2625 msgid "Add Segment..." msgstr "" #: res/xrc/OutfitStudio.xrc:2600 res/xrc/OutfitStudio.xrc:2626 msgid "Choose a segment to add to the shape." msgstr "" #: res/xrc/OutfitStudio.xrc:2603 res/xrc/OutfitStudio.xrc:2614 msgid "Add Sub Segment..." msgstr "" #: res/xrc/OutfitStudio.xrc:2604 res/xrc/OutfitStudio.xrc:2615 msgid "Add a new sub segment to the currently selected segment." msgstr "" #: res/xrc/OutfitStudio.xrc:2607 msgid "Delete Segment..." msgstr "" #: res/xrc/OutfitStudio.xrc:2608 msgid "Delete segment and all of its sub segments from the shape." msgstr "" #: res/xrc/OutfitStudio.xrc:2612 msgid "Sub Segments" msgstr "" #: res/xrc/OutfitStudio.xrc:2618 msgid "Delete Sub Segment..." msgstr "" #: res/xrc/OutfitStudio.xrc:2619 msgid "Delete the selected sub segment." msgstr "" #: res/xrc/OutfitStudio.xrc:2632 res/xrc/OutfitStudio.xrc:2643 msgid "Add Partition..." msgstr "" #: res/xrc/OutfitStudio.xrc:2633 res/xrc/OutfitStudio.xrc:2644 msgid "Adds a new partition to the shape." msgstr "" #: res/xrc/OutfitStudio.xrc:2636 msgid "Delete Partition..." msgstr "" #: res/xrc/OutfitStudio.xrc:2637 msgid "Deletes the partition from the shape." msgstr "" #: res/xrc/Project.xrc:16 msgid "" "Welcome to the New Project wizard!\n" "\n" "First, please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" #: res/xrc/Project.xrc:32 res/xrc/Project.xrc:598 msgid "Reference" msgstr "" #: res/xrc/Project.xrc:50 res/xrc/Project.xrc:616 msgid "From Template" msgstr "" #: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272 #: res/xrc/Project.xrc:635 res/xrc/Project.xrc:851 res/xrc/Project.xrc:923 msgid "From File" msgstr "" #: res/xrc/Project.xrc:79 res/xrc/Project.xrc:645 msgid "Select a project or NIF file" msgstr "" #: res/xrc/Project.xrc:162 msgid "Next, select an outfit/mesh to work on and enter a display name for it." msgstr "" #: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:818 msgid "Display Name" msgstr "" #: res/xrc/Project.xrc:197 res/xrc/Project.xrc:838 msgid "Outfit/Mesh" msgstr "" #: res/xrc/Project.xrc:220 res/xrc/Project.xrc:861 msgid "Select a file to load as an outfit/mesh" msgstr "" #: res/xrc/Project.xrc:232 res/xrc/Project.xrc:873 msgid "Clear Outfit" msgstr "" #: res/xrc/Project.xrc:250 res/xrc/Project.xrc:901 msgid "Textures" msgstr "" #: res/xrc/Project.xrc:257 res/xrc/Project.xrc:908 msgid "Automatically search for textures" msgstr "" #: res/xrc/Project.xrc:282 res/xrc/Project.xrc:933 msgid "Select a texture file" msgstr "" #: res/xrc/Project.xrc:297 msgid "Save Project As..." msgstr "" #: res/xrc/Project.xrc:328 msgid "The name of the outfit and slider set, as it will appear in BodySlide." msgstr "" #: res/xrc/Project.xrc:337 msgid "Copies the current display name to the project text fields below." msgstr "" #: res/xrc/Project.xrc:338 msgid "To Project" msgstr "" #: res/xrc/Project.xrc:354 msgid "Output File Name" msgstr "" #: res/xrc/Project.xrc:363 msgid "The name of the outfit file that will end up in the game data path when BodySlide builds it. Should not include _1 or _0 in the name, e.g: lovelydress" msgstr "" #: res/xrc/Project.xrc:389 msgid "Output Data Path" msgstr "" #: res/xrc/Project.xrc:398 msgid "The location in the game's data path where BodySlide-built outfit files will be placed, e.g: meshes\\clothes\\lovelydress" msgstr "" #: res/xrc/Project.xrc:410 msgid "If this is enabled, BodySlide creates a low and high weight model when it generates the final outfit." msgstr "" #: res/xrc/Project.xrc:411 msgid "Low/High Weight Output" msgstr "" #: res/xrc/Project.xrc:419 msgid "If this is enabled, only one output file will be created (useful for single-weighted things like hair)." msgstr "" #: res/xrc/Project.xrc:420 msgid "Single Weight Output" msgstr "" #: res/xrc/Project.xrc:431 msgid "Project" msgstr "" #: res/xrc/Project.xrc:443 msgid "Slider Set File" msgstr "" #: res/xrc/Project.xrc:453 msgid "The .osp slider set project file" msgstr "" #: res/xrc/Project.xrc:454 msgid "Select slider set .osp file name" msgstr "" #: res/xrc/Project.xrc:472 msgid "Shape Data Folder" msgstr "" #: res/xrc/Project.xrc:482 msgid "The folder where all the slider data will go, as well as the base outfit NIF file." msgstr "" #: res/xrc/Project.xrc:483 msgid "Select slider data folder" msgstr "" #: res/xrc/Project.xrc:500 msgid "Shape Data File" msgstr "" #: res/xrc/Project.xrc:510 msgid "The name of the output's base NIF file." msgstr "" #: res/xrc/Project.xrc:511 msgid "Select output NIF file name" msgstr "" #: res/xrc/Project.xrc:523 msgid "Outfits require the reference body to be a part of the output file. Disable this if you've already copied the reference over or you don't want it included." msgstr "" #: res/xrc/Project.xrc:524 msgid "Copy reference shape into output" msgstr "" #: res/xrc/Project.xrc:533 msgid "Prevents the building of morph .tri files in BodySlide for this project." msgstr "" #: res/xrc/Project.xrc:534 msgid "Prevent morph file building in BodySlide" msgstr "" #: res/xrc/Project.xrc:543 msgid "Prevents the removal of fully zapped shapes when building in BodySlide. Useful when the shape order and count matters, like for retextures using texture sets." msgstr "" #: res/xrc/Project.xrc:544 msgid "Prevent removal of fully zapped shapes in BodySlide" msgstr "" #: res/xrc/Project.xrc:563 res/xrc/SavePreset.xrc:78 msgid "&Save" msgstr "" #: res/xrc/Project.xrc:588 msgid "Please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" #: res/xrc/Project.xrc:724 msgid "Merge" msgstr "" #: res/xrc/Project.xrc:736 msgid "Zaps" msgstr "" #: res/xrc/Project.xrc:737 msgid "Merge existing zaps with new sliders" msgstr "" #: res/xrc/Project.xrc:747 msgid "Merge new sliders with existing sliders" msgstr "" #: res/xrc/Project.xrc:757 msgid "Append new sliders that aren't in the project at the end of the list (or don't)" msgstr "" #: res/xrc/Project.xrc:794 msgid "Load Outfit" msgstr "" #: res/xrc/Project.xrc:803 msgid "Please select an outfit/mesh to work on and enter a display name for it." msgstr "" #: res/xrc/Project.xrc:882 msgid "Keep other shapes" msgstr "" #: res/xrc/Project.xrc:1006 msgid "Group file (optional):" msgstr "" #: res/xrc/Project.xrc:1015 msgid "Group file to pack (optional)." msgstr "" #: res/xrc/Project.xrc:1032 msgid "Merged file name:" msgstr "" #: res/xrc/Project.xrc:1040 msgid "File name to use for the merged project file." msgstr "" #: res/xrc/Project.xrc:1066 msgid "Pack Folder..." msgstr "" #: res/xrc/Project.xrc:1075 msgid "Pack Archive..." msgstr "" #: res/xrc/Project.xrc:1092 src/program/AutomationDialog.cpp:1532 #: src/program/OutfitStudio.cpp:4225 src/program/OutfitStudio.cpp:7100 #: src/program/OutfitStudio.cpp:8031 src/program/OutfitStudio.cpp:8142 #: src/program/OutfitStudio.cpp:8274 src/program/OutfitStudio.cpp:12189 #: src/program/ShapeProperties.cpp:135 msgid "Cancel" msgstr "" #: res/xrc/SavePreset.xrc:6 msgid "Enter preset name..." msgstr "" #: res/xrc/SavePreset.xrc:15 msgid "Please enter a name for the new preset:" msgstr "" #: res/xrc/SavePreset.xrc:38 msgid "Select groups to assign to the new preset:" msgstr "" #: res/xrc/Settings.xrc:15 msgid "Game" msgstr "" #: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:5793 msgid "Target Game" msgstr "" #: res/xrc/Settings.xrc:37 msgid "Choose the target game you want to use the program for here." msgstr "" #: res/xrc/Settings.xrc:67 msgid "Game Data Path" msgstr "" #: res/xrc/Settings.xrc:77 msgid "Select the data path of the game..." msgstr "" #: res/xrc/Settings.xrc:79 msgid "Data path to load textures from." msgstr "" #: res/xrc/Settings.xrc:91 msgid "Advanced" msgstr "" #: res/xrc/Settings.xrc:108 msgid "Output Path" msgstr "" #: res/xrc/Settings.xrc:118 msgid "Select the output path..." msgstr "" #: res/xrc/Settings.xrc:120 msgid "Data path to build files to. If empty, Game Data Path will be used instead." msgstr "" #: res/xrc/Settings.xrc:137 msgid "Project Path" msgstr "" #: res/xrc/Settings.xrc:147 msgid "Select the project path..." msgstr "" #: res/xrc/Settings.xrc:149 msgid "Project path where files related to BodySlide are loaded from. If empty, executable directory will be used instead." msgstr "" #: res/xrc/Settings.xrc:165 msgid "With this turned on, BodySlide receives a new checkbox \"Force Body Normals\". Using it when building adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod." msgstr "" #: res/xrc/Settings.xrc:166 msgid "Show 'Force Body Normals'" msgstr "" #: res/xrc/Settings.xrc:184 msgid "General" msgstr "" #: res/xrc/Settings.xrc:196 msgid "Enables/disables the dialog for choosing which set to build during a batch build if overrides happen." msgstr "" #: res/xrc/Settings.xrc:197 msgid "Override Warning" msgstr "" #: res/xrc/Settings.xrc:206 msgid "Enables/disables scanning BSAs in the game data folder for textures to load." msgstr "" #: res/xrc/Settings.xrc:207 msgid "BSA Textures" msgstr "" #: res/xrc/Settings.xrc:224 msgid "Enables/disables panning the camera with the left mouse button in Outfit Studio." msgstr "" #: res/xrc/Settings.xrc:225 msgid "Left Mouse Pan" msgstr "" #: res/xrc/Settings.xrc:234 msgid "Enables/disables opening the brush settings near the mouse cursor when hitting the 'space' key." msgstr "" #: res/xrc/Settings.xrc:235 msgid "Brush Settings Near Cursor" msgstr "" #: res/xrc/Settings.xrc:244 msgid "Enables/disables the undo history for the mask brush and vertex selection." msgstr "" #: res/xrc/Settings.xrc:245 msgid "Mask History" msgstr "" #: res/xrc/Settings.xrc:263 msgid "Single Instance" msgstr "" #: res/xrc/Settings.xrc:272 msgid "Controls behavior when opening files and another instance is already running." msgstr "" #: res/xrc/Settings.xrc:275 msgid "Ask (Message Box)" msgstr "" #: res/xrc/Settings.xrc:276 msgid "Open in Existing" msgstr "" #: res/xrc/Settings.xrc:277 msgid "Open in New" msgstr "" #: res/xrc/Settings.xrc:295 msgid "Language" msgstr "" #: res/xrc/Settings.xrc:304 msgid "Use the selected language for the program." msgstr "" #: res/xrc/Settings.xrc:319 msgid "Rendering" msgstr "" #: res/xrc/Settings.xrc:325 msgid "Enables/disables the perspective view in the rendering window." msgstr "" #: res/xrc/Settings.xrc:350 msgid "Background color of the renderer." msgstr "" #: res/xrc/Settings.xrc:367 msgid "Wireframe Color" msgstr "" #: res/xrc/Settings.xrc:376 msgid "Wireframe color of the renderer." msgstr "" #: res/xrc/Settings.xrc:393 msgid "Point Color (normal/masked)" msgstr "" #: res/xrc/Settings.xrc:402 msgid "Color of points in the renderer." msgstr "" #: res/xrc/Settings.xrc:411 msgid "Color of masked points in the renderer." msgstr "" #: res/xrc/Settings.xrc:426 msgid "Data Files" msgstr "" #: res/xrc/Settings.xrc:444 msgid "Reference Skeleton" msgstr "" #: res/xrc/Settings.xrc:467 msgid "Select a reference skeleton .nif file..." msgstr "" #: res/xrc/Settings.xrc:470 msgid "The reference skeleton file for Outfit Studio." msgstr "" #: res/xrc/Settings.xrc:487 msgid "Root Node" msgstr "" #: res/xrc/Settings.xrc:496 msgid "The root node name of the reference skeleton. Can differ from game to game." msgstr "" #: res/xrc/Setup.xrc:5 msgid "Setup" msgstr "" #: res/xrc/Setup.xrc:15 msgid "" "Please select the data folder and your target game.\n" "You can only choose one game at a time, but it is possible to change the selection in the settings." msgstr "" #: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102 #: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189 #: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247 res/xrc/Setup.xrc:276 msgid "Game not found! Select the data folder manually..." msgstr "" #: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103 #: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190 #: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248 res/xrc/Setup.xrc:277 msgid "Select a folder" msgstr "" #: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113 #: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200 #: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258 res/xrc/Setup.xrc:287 msgid "Choose Game" msgstr "" #: res/xrc/ShapeProperties.xrc:5 msgid "Shape Properties" msgstr "" #: res/xrc/ShapeProperties.xrc:16 msgid "Shader" msgstr "" #: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:629 #: res/xrc/Skeleton.xrc:94 msgid "Name" msgstr "" #: res/xrc/ShapeProperties.xrc:102 msgid "Specular Color" msgstr "" #: res/xrc/ShapeProperties.xrc:120 msgid "Specular Strength" msgstr "" #: res/xrc/ShapeProperties.xrc:139 msgid "Specular Power" msgstr "" #: res/xrc/ShapeProperties.xrc:179 msgid "Emissive Color" msgstr "" #: res/xrc/ShapeProperties.xrc:197 msgid "Emissive Multiple" msgstr "" #: res/xrc/ShapeProperties.xrc:216 msgid "Alpha" msgstr "" #: res/xrc/ShapeProperties.xrc:235 msgid "Vertex Colors" msgstr "" #: res/xrc/ShapeProperties.xrc:252 msgid "Double Sided" msgstr "" #: res/xrc/ShapeProperties.xrc:289 res/xrc/ShapeProperties.xrc:447 msgid "Remove" msgstr "" #: res/xrc/ShapeProperties.xrc:298 msgid "Textures..." msgstr "" #: res/xrc/ShapeProperties.xrc:310 msgid "Transparency" msgstr "" #: res/xrc/ShapeProperties.xrc:333 msgid "Threshold" msgstr "" #: res/xrc/ShapeProperties.xrc:373 msgid "Vertex Alpha" msgstr "" #: res/xrc/ShapeProperties.xrc:391 msgid "Alpha Test" msgstr "" #: res/xrc/ShapeProperties.xrc:409 msgid "Alpha Blend" msgstr "" #: res/xrc/ShapeProperties.xrc:460 msgid "Copy from shape..." msgstr "" #: res/xrc/ShapeProperties.xrc:468 msgid "Geometry" msgstr "" #: res/xrc/ShapeProperties.xrc:488 msgid "Full Precision" msgstr "" #: res/xrc/ShapeProperties.xrc:507 msgid "Sub Index" msgstr "" #: res/xrc/ShapeProperties.xrc:526 msgid "Skinned" msgstr "" #: res/xrc/ShapeProperties.xrc:544 msgid "Dynamic" msgstr "" #: res/xrc/ShapeProperties.xrc:590 msgid "Extra Data" msgstr "" #: res/xrc/ShapeProperties.xrc:648 msgid "Coordinates" msgstr "" #: res/xrc/ShapeProperties.xrc:657 msgid "Transform from shape to global coordinates:" msgstr "" #: res/xrc/ShapeProperties.xrc:720 res/xrc/Skeleton.xrc:142 msgid "Rotation" msgstr "" #: res/xrc/ShapeProperties.xrc:806 res/xrc/WeightCopy.xrc:187 msgid "Recalculate geometry's coordinates so it doesn't move" msgstr "" #: res/xrc/ShapeProperties.xrc:807 res/xrc/WeightCopy.xrc:188 msgid "Transform geometry so its position in global coordinates does not change." msgstr "" #: res/xrc/Skeleton.xrc:6 msgid "Select a bone to add" msgstr "" #: res/xrc/Skeleton.xrc:15 msgid "Bones in the current reference skeleton:" msgstr "" #: res/xrc/Skeleton.xrc:68 msgid "Parent" msgstr "" #: res/xrc/Skeleton.xrc:234 msgid "Add Count #" msgstr "" #: res/xrc/Slider.xrc:6 msgid "Select a slider preset" msgstr "" #: res/xrc/Slider.xrc:15 msgid "Choose a preset:" msgstr "" #: res/xrc/Slider.xrc:40 msgid "Low weight" msgstr "" #: res/xrc/Slider.xrc:49 msgid "High weight" msgstr "" #: res/xrc/Slider.xrc:81 msgid "Slider Properties" msgstr "" #: res/xrc/Slider.xrc:91 msgid "Slider Name" msgstr "" #: res/xrc/Slider.xrc:108 msgid "Default Values" msgstr "" #: res/xrc/Slider.xrc:114 msgid "Low" msgstr "" #: res/xrc/Slider.xrc:131 msgid "High" msgstr "" #: res/xrc/Slider.xrc:173 msgid "Invert" msgstr "" #: res/xrc/Slider.xrc:182 msgid "Hidden" msgstr "" #: res/xrc/Slider.xrc:191 msgid "Zap" msgstr "" #: res/xrc/Slider.xrc:211 msgid "Toggle Zaps:" msgstr "" #: res/xrc/SliderDataImport.xrc:6 msgid "Slider Data Import Options..." msgstr "" #: res/xrc/SliderDataImport.xrc:21 msgid "Select the shapes that slider data will be imported for:" msgstr "" #: res/xrc/SliderDataImport.xrc:52 msgid "Select the sliders to be imported" msgstr "" #: res/xrc/WeightCopy.xrc:15 msgid "Each vertex of the reference will copy its weights to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become weighted and work well. Often, the default values are sufficient." msgstr "" #: res/xrc/WeightCopy.xrc:104 msgid "Bones to copy (click to preview weights):" msgstr "" #: res/xrc/WeightCopy.xrc:127 msgid "Check All" msgstr "" #: res/xrc/WeightCopy.xrc:135 msgid "Uncheck All" msgstr "" #: res/xrc/WeightCopy.xrc:151 msgid "Pose:" msgstr "" #: res/xrc/WeightCopy.xrc:167 msgid "The skin coordinate system doesn't match the reference shape's. Do you want to copy the transforms?" msgstr "" #: res/xrc/WeightCopy.xrc:177 msgid "Copy skin transform from reference" msgstr "" #: res/xrc/WeightCopy.xrc:205 msgid "Run the weight copy and preview the results. Click again to update the preview." msgstr "" #: src/components/Anim.cpp:570 msgid "Bone information incomplete. Exported data will not contain correct bone entries! Be sure to load a reference NIF prior to export." msgstr "" #: src/components/Anim.cpp:571 msgid "Export Warning" msgstr "" #: src/components/Anim.cpp:794 #, c-format msgid "Failed to load skeleton '%s'!" msgstr "" #: src/components/Anim.cpp:802 #, c-format msgid "Root '%s' not found in skeleton '%s'!" msgstr "" #: src/program/AutomationDialog.cpp:86 msgid "Active" msgstr "" #: src/program/AutomationDialog.cpp:89 msgid "Note" msgstr "" #: src/program/AutomationDialog.cpp:95 msgid "Right-click to add steps..." msgstr "" #: src/program/AutomationDialog.cpp:150 src/program/AutomationDialog.cpp:321 msgid "Ready." msgstr "" #: src/program/AutomationDialog.cpp:291 src/program/BodySlideApp.cpp:3725 #: src/program/OutfitStudio.h:1105 msgid "Starting..." msgstr "" #: src/program/AutomationDialog.cpp:398 msgid "Add Step" msgstr "" #: src/program/AutomationDialog.cpp:401 msgid "Remove Step" msgstr "" #: src/program/AutomationDialog.cpp:404 msgid "Move Down" msgstr "" #: src/program/AutomationDialog.cpp:406 msgid "Execute Selected" msgstr "" #: src/program/AutomationDialog.cpp:1211 src/program/AutomationDialog.cpp:1286 msgid "" msgstr "" #: src/program/AutomationDialog.cpp:1254 #, c-format msgid "Failed to load automation script (error %d)." msgstr "" #: src/program/AutomationDialog.cpp:1254 src/program/AutomationDialog.cpp:1333 #: src/program/BodySlideApp.cpp:1122 src/program/BodySlideApp.cpp:2442 #: src/program/BodySlideApp.cpp:2755 src/program/BodySlideApp.cpp:4375 #: src/program/BodySlideApp.cpp:4382 src/program/BodySlideApp.cpp:5280 #: src/program/EditUV.cpp:276 src/program/OutfitStudio.cpp:1186 #: src/program/OutfitStudio.cpp:1192 src/program/OutfitStudio.cpp:1769 #: src/program/OutfitStudio.cpp:1780 src/program/OutfitStudio.cpp:1816 #: src/program/OutfitStudio.cpp:1827 src/program/OutfitStudio.cpp:1837 #: src/program/OutfitStudio.cpp:1846 src/program/OutfitStudio.cpp:1857 #: src/program/OutfitStudio.cpp:1868 src/program/OutfitStudio.cpp:1880 #: src/program/OutfitStudio.cpp:1919 src/program/OutfitStudio.cpp:1927 #: src/program/OutfitStudio.cpp:1934 src/program/OutfitStudio.cpp:1970 #: src/program/OutfitStudio.cpp:1978 src/program/OutfitStudio.cpp:1985 #: src/program/OutfitStudio.cpp:1995 src/program/OutfitStudio.cpp:2004 #: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2019 #: src/program/OutfitStudio.cpp:2030 src/program/OutfitStudio.cpp:2039 #: src/program/OutfitStudio.cpp:2046 src/program/OutfitStudio.cpp:2361 #: src/program/OutfitStudio.cpp:2398 src/program/OutfitStudio.cpp:2413 #: src/program/OutfitStudio.cpp:2499 src/program/OutfitStudio.cpp:2508 #: src/program/OutfitStudio.cpp:2516 src/program/OutfitStudio.cpp:2530 #: src/program/OutfitStudio.cpp:2539 src/program/OutfitStudio.cpp:2545 #: src/program/OutfitStudio.cpp:2582 src/program/OutfitStudio.cpp:4112 #: src/program/OutfitStudio.cpp:4119 src/program/OutfitStudio.cpp:4670 #: src/program/OutfitStudio.cpp:4865 src/program/OutfitStudio.cpp:4965 #: src/program/OutfitStudio.cpp:4984 src/program/OutfitStudio.cpp:5097 #: src/program/OutfitStudio.cpp:5116 src/program/OutfitStudio.cpp:5144 #: src/program/OutfitStudio.cpp:5195 src/program/OutfitStudio.cpp:5212 #: src/program/OutfitStudio.cpp:5219 src/program/OutfitStudio.cpp:5233 #: src/program/OutfitStudio.cpp:7842 src/program/OutfitStudio.cpp:7900 #: src/program/OutfitStudio.cpp:7909 src/program/OutfitStudio.cpp:7920 #: src/program/OutfitStudio.cpp:7934 src/program/OutfitStudio.cpp:7955 #: src/program/OutfitStudio.cpp:7966 src/program/OutfitStudio.cpp:7977 #: src/program/OutfitStudio.cpp:7990 src/program/OutfitStudio.cpp:8105 #: src/program/OutfitStudio.cpp:8118 src/program/OutfitStudio.cpp:8221 #: src/program/OutfitStudio.cpp:8237 src/program/OutfitStudio.cpp:8243 #: src/program/OutfitStudio.cpp:8345 src/program/OutfitStudio.cpp:8356 #: src/program/OutfitStudio.cpp:8373 src/program/OutfitStudio.cpp:8396 #: src/program/OutfitStudio.cpp:8408 src/program/OutfitStudio.cpp:8440 #: src/program/OutfitStudio.cpp:8463 src/program/OutfitStudio.cpp:8472 #: src/program/OutfitStudio.cpp:8483 src/program/OutfitStudio.cpp:8490 #: src/program/OutfitStudio.cpp:8501 src/program/OutfitStudio.cpp:8508 #: src/program/OutfitStudio.cpp:8522 src/program/OutfitStudio.cpp:8529 #: src/program/OutfitStudio.cpp:8665 src/program/OutfitStudio.cpp:8701 #: src/program/OutfitStudio.cpp:8717 src/program/OutfitStudio.cpp:8928 #: src/program/OutfitStudio.cpp:10390 src/program/OutfitStudio.cpp:10431 #: src/program/OutfitStudio.cpp:10436 src/program/OutfitStudio.cpp:10457 #: src/program/OutfitStudio.cpp:10475 src/program/OutfitStudio.cpp:10684 #: src/program/OutfitStudio.cpp:10692 src/program/OutfitStudio.cpp:10733 #: src/program/OutfitStudio.cpp:10992 src/program/OutfitStudio.cpp:11120 #: src/program/OutfitStudio.cpp:11125 src/program/OutfitStudio.cpp:11132 #: src/program/OutfitStudio.cpp:11254 src/program/OutfitStudio.cpp:11288 #: src/program/OutfitStudio.cpp:13434 src/program/OutfitStudio.cpp:13754 #: src/program/OutfitStudio.cpp:13793 src/program/OutfitStudio.cpp:13798 #: src/program/OutfitStudio.cpp:13811 src/program/OutfitStudio.cpp:15222 msgid "Error" msgstr "" #: src/program/AutomationDialog.cpp:1319 msgid "Please enter an automation name." msgstr "" #: src/program/AutomationDialog.cpp:1319 src/program/AutomationDialog.cpp:1344 #: src/program/AutomationDialog.cpp:1352 src/program/AutomationDialog.cpp:1578 #: src/program/AutomationDialog.cpp:1592 src/program/AutomationDialog.cpp:1606 #: src/program/AutomationDialog.cpp:1630 src/program/AutomationDialog.cpp:1643 #: src/program/AutomationDialog.cpp:1656 src/program/AutomationDialog.cpp:1679 #: src/program/AutomationDialog.cpp:1758 src/program/AutomationDialog.cpp:3924 #: src/program/AutomationDialog.cpp:4033 src/program/AutomationDialog.cpp:4038 #: src/program/AutomationDialog.cpp:4208 msgid "Automation" msgstr "" #: src/program/AutomationDialog.cpp:1333 #, c-format msgid "Failed to save automation script (error %d)." msgstr "" #: src/program/AutomationDialog.cpp:1344 msgid "No automation selected to delete." msgstr "" #: src/program/AutomationDialog.cpp:1352 msgid "Automation file not found." msgstr "" #: src/program/AutomationDialog.cpp:1357 #, c-format msgid "" "Delete automation '%s'?\n" "This cannot be undone." msgstr "" #: src/program/AutomationDialog.cpp:1358 src/program/OutfitStudio.cpp:10140 #: src/program/OutfitStudio.cpp:10483 src/program/OutfitStudio.cpp:10514 #: src/program/OutfitStudio.cpp:10524 src/program/OutfitStudio.cpp:10532 #: src/program/OutfitStudio.cpp:10539 msgid "Confirm Delete" msgstr "" #: src/program/AutomationDialog.cpp:1578 msgid "No active steps to execute." msgstr "" #: src/program/AutomationDialog.cpp:1592 src/program/AutomationDialog.cpp:3924 msgid "No files found matching the batch folder scan criteria." msgstr "" #: src/program/AutomationDialog.cpp:1602 msgid "Batch Files" msgstr "" #: src/program/AutomationDialog.cpp:1602 #, c-format msgid "Select files to process (%d found):" msgstr "" #: src/program/AutomationDialog.cpp:1606 msgid "No files selected." msgstr "" #: src/program/AutomationDialog.cpp:1619 #, c-format msgid "" "Folder: %s\n" "Extension: %s" msgstr "" #: src/program/AutomationDialog.cpp:1623 #, c-format msgid "" "\n" "File filter: %s%s" msgstr "" #: src/program/AutomationDialog.cpp:1630 src/program/AutomationDialog.cpp:4038 msgid "No slider sets found matching the filter criteria." msgstr "" #: src/program/AutomationDialog.cpp:1639 msgid "Batch Slider Sets" msgstr "" #: src/program/AutomationDialog.cpp:1639 #, c-format msgid "Select slider sets to process (%d found):" msgstr "" #: src/program/AutomationDialog.cpp:1643 msgid "No slider sets selected." msgstr "" #: src/program/AutomationDialog.cpp:1656 msgid "No items found matching the batch criteria." msgstr "" #: src/program/AutomationDialog.cpp:1660 #, c-format msgid "" "Execute %zu active step(s) on %d item(s)?\n" "\n" "%s\n" "\n" "This may take a while." msgstr "" #: src/program/AutomationDialog.cpp:1662 msgid "Batch Confirmation" msgstr "" #: src/program/AutomationDialog.cpp:1669 #, c-format msgid "Execute %zu active step(s) on the current project?" msgstr "" #: src/program/AutomationDialog.cpp:1669 msgid "Confirm Execution" msgstr "" #: src/program/AutomationDialog.cpp:1679 msgid "No step selected." msgstr "" #: src/program/AutomationDialog.cpp:1719 msgid "Running automation script..." msgstr "" #: src/program/AutomationDialog.cpp:1724 #, c-format msgid "Step %d/%d: %s" msgstr "" #: src/program/AutomationDialog.cpp:1734 #, c-format msgid "" "Step %d (%s) failed with error %d.\n" "\n" "%s\n" "\n" "Continue with remaining steps?" msgstr "" #: src/program/AutomationDialog.cpp:1740 msgid "Automation Error" msgstr "" #: src/program/AutomationDialog.cpp:1742 msgid "Automation aborted." msgstr "" #: src/program/AutomationDialog.cpp:1755 msgid "Automation complete." msgstr "" #: src/program/AutomationDialog.cpp:1757 #, c-format msgid "Automation completed: %d step(s) executed." msgstr "" #: src/program/AutomationDialog.cpp:3596 msgid "Export Folder:" msgstr "" #: src/program/AutomationDialog.cpp:3919 msgid "Preparing..." msgstr "" #: src/program/AutomationDialog.cpp:3938 src/program/AutomationDialog.cpp:4051 #, c-format msgid "Processing %d/%d: %s" msgstr "" #: src/program/AutomationDialog.cpp:4025 src/program/AutomationDialog.cpp:4200 msgid "Batch complete." msgstr "" #: src/program/AutomationDialog.cpp:4031 #, c-format msgid "Batch completed: %d/%d items processed successfully." msgstr "" #: src/program/AutomationDialog.cpp:4206 #, c-format msgid "Batch completed: %d/%d slider sets processed successfully." msgstr "" #: src/program/BodySlideApp.cpp:210 src/program/OutfitStudio.cpp:634 msgid "" "No read/write permission for game data path!\n" "\n" "Please launch the program with admin elevation and make sure the game data path in the settings is correct." msgstr "" #: src/program/BodySlideApp.cpp:211 src/program/BodySlideApp.cpp:221 #: src/program/BodySlideApp.cpp:2421 src/program/BodySlideApp.cpp:5498 #: src/program/OutfitStudio.cpp:635 src/program/OutfitStudio.cpp:645 #: src/program/OutfitStudio.cpp:845 src/program/OutfitStudio.cpp:852 msgid "Warning" msgstr "" #: src/program/BodySlideApp.cpp:220 src/program/OutfitStudio.cpp:644 msgid "" "No read/write permission for project path!\n" "\n" "Please launch the program with admin elevation and make sure the project path in the settings is correct." msgstr "" #: src/program/BodySlideApp.cpp:307 src/program/OutfitStudio.cpp:702 #, c-format msgid "Unexpected exception has occurred: %s, the program will terminate." msgstr "" #: src/program/BodySlideApp.cpp:307 src/program/OutfitStudio.cpp:702 msgid "Unexpected exception" msgstr "" #: src/program/BodySlideApp.cpp:330 src/program/OutfitStudio.cpp:722 #, c-format msgid "Unhandled exception has occurred: %s, the program will terminate." msgstr "" #: src/program/BodySlideApp.cpp:330 src/program/OutfitStudio.cpp:722 msgid "Unhandled exception" msgstr "" #: src/program/BodySlideApp.cpp:341 src/program/OutfitStudio.cpp:730 msgid "Fatal exception has occurred, the program will terminate." msgstr "" #: src/program/BodySlideApp.cpp:341 src/program/OutfitStudio.cpp:730 msgid "Fatal exception" msgstr "" #: src/program/BodySlideApp.cpp:1122 msgid "Failed to launch Outfit Studio executable!" msgstr "" #: src/program/BodySlideApp.cpp:2421 src/program/OutfitStudio.cpp:852 msgid "Failed to find game install path registry key or GameDataPath in the config." msgstr "" #: src/program/BodySlideApp.cpp:2667 src/program/OutfitStudio.cpp:1098 #, c-format msgid "System language '%d' is wrong." msgstr "" #: src/program/BodySlideApp.cpp:2676 src/program/OutfitStudio.cpp:1107 #, c-format msgid "The system language '%d' is not supported by your system. Try installing support for this language." msgstr "" #: src/program/BodySlideApp.cpp:2755 msgid "Failed to create group file." msgstr "" #: src/program/BodySlideApp.cpp:2769 msgid "That group already exists in the specified file, do you wish to overwrite the group?" msgstr "" #: src/program/BodySlideApp.cpp:2769 msgid "Group already exists" msgstr "" #: src/program/BodySlideApp.cpp:2984 msgid "WARNING: Game data path not configured. Would you like to show BodySlide where it is?" msgstr "" #: src/program/BodySlideApp.cpp:2985 src/program/BodySlideApp.cpp:3485 #: src/program/BodySlideApp.cpp:3490 msgid "Game not found" msgstr "" #: src/program/BodySlideApp.cpp:2993 msgid "Please choose a directory to set as your Data path" msgstr "" #: src/program/BodySlideApp.cpp:3011 msgid "" "WARNING: This will delete the output files from the output folder, potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" #: src/program/BodySlideApp.cpp:3012 msgid "Clean Build" msgstr "" #: src/program/BodySlideApp.cpp:3020 msgid "Removed the following files:\n" msgstr "" #: src/program/BodySlideApp.cpp:3032 src/program/BodySlideApp.cpp:3045 msgid " (no action)\n" msgstr "" #: src/program/BodySlideApp.cpp:3036 src/program/BodySlideApp.cpp:3048 #: src/program/BodySlideApp.cpp:3364 msgid "Process Successful" msgstr "" #: src/program/BodySlideApp.cpp:3251 #, c-format msgid "" "Failed to write TRI file to the following location\n" "\n" "%s" msgstr "" #: src/program/BodySlideApp.cpp:3251 src/program/BodySlideApp.cpp:3307 #: src/program/BodySlideApp.cpp:3342 msgid "Unable to process" msgstr "" #: src/program/BodySlideApp.cpp:3307 src/program/BodySlideApp.cpp:3342 #, c-format msgid "" "Failed to build set to the following location\n" "\n" "%s" msgstr "" #: src/program/BodySlideApp.cpp:3309 src/program/BodySlideApp.cpp:3344 msgid "Choose alternate file name" msgstr "" #: src/program/BodySlideApp.cpp:3356 msgid "Successfully processed the following files:\n" msgstr "" #: src/program/BodySlideApp.cpp:3436 #, c-format msgid "Preview - %s" msgstr "" #: src/program/BodySlideApp.cpp:3470 msgid "" "WARNING: This will delete the output files from the output folders, potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" #: src/program/BodySlideApp.cpp:3471 msgid "Clean Batch Build" msgstr "" #: src/program/BodySlideApp.cpp:3485 msgid "WARNING: Game data path not configured. Files can't be removed that way." msgstr "" #: src/program/BodySlideApp.cpp:3489 msgid "WARNING: Game data path not configured. Continue saving files to the working directory?" msgstr "" #: src/program/BodySlideApp.cpp:3542 msgid "Choice" msgstr "" #: src/program/BodySlideApp.cpp:3543 msgid "Source File" msgstr "" #: src/program/BodySlideApp.cpp:3574 msgid "" msgstr "" #: src/program/BodySlideApp.cpp:3725 msgid "Processing Outfits" msgstr "" #: src/program/BodySlideApp.cpp:3737 #, c-format msgid "Processing '%s' (%d of %d)..." msgstr "" #: src/program/BodySlideApp.cpp:3745 msgid "No recorded outfit name source" msgstr "" #: src/program/BodySlideApp.cpp:3756 msgid "Unable to get slider set from file: " msgstr "" #: src/program/BodySlideApp.cpp:3761 msgid "Unable to open slider set file: " msgstr "" #: src/program/BodySlideApp.cpp:3796 msgid "Unable to load input nif: " msgstr "" #: src/program/BodySlideApp.cpp:4084 msgid "Unable to create destination directory: " msgstr "" #: src/program/BodySlideApp.cpp:4161 src/program/BodySlideApp.cpp:4169 #: src/program/BodySlideApp.cpp:4180 msgid "Unable to save nif file: " msgstr "" #: src/program/BodySlideApp.cpp:4300 src/program/BodySlideApp.cpp:5628 msgid "The following sets failed" msgstr "" #: src/program/BodySlideApp.cpp:4300 src/program/BodySlideApp.cpp:5628 msgid "Failed" msgstr "" #: src/program/BodySlideApp.cpp:4375 msgid "Failed to load BodySlide.xrc file!" msgstr "" #: src/program/BodySlideApp.cpp:4382 msgid "Failed to load BodySlide frame!" msgstr "" #: src/program/BodySlideApp.cpp:4463 msgid "Filter groups..." msgstr "" #: src/program/BodySlideApp.cpp:4469 msgid "Filter outfits..." msgstr "" #: src/program/BodySlideApp.cpp:4475 msgid "Filter sliders..." msgstr "" #: src/program/BodySlideApp.cpp:4480 msgid "Filter presets..." msgstr "" #: src/program/BodySlideApp.cpp:4539 src/program/BodySlideApp.cpp:5462 msgid "Hide Preview" msgstr "" #: src/program/BodySlideApp.cpp:4541 src/program/BodySlideApp.cpp:5462 msgid "Show Preview" msgstr "" #: src/program/BodySlideApp.cpp:5154 msgid "Choose groups to filter outfit list" msgstr "" #: src/program/BodySlideApp.cpp:5154 msgid "Choose Groups" msgstr "" #: src/program/BodySlideApp.cpp:5190 msgid "Choose or create group file" msgstr "" #: src/program/BodySlideApp.cpp:5203 msgid "What would you like the new group to be called?" msgstr "" #: src/program/BodySlideApp.cpp:5203 msgid "New Group Name" msgstr "" #: src/program/BodySlideApp.cpp:5249 msgid "Do you really wish to delete the selected project?" msgstr "" #: src/program/BodySlideApp.cpp:5249 msgid "Delete Project" msgstr "" #: src/program/BodySlideApp.cpp:5258 msgid "Do you really wish to delete the selected preset?" msgstr "" #: src/program/BodySlideApp.cpp:5258 msgid "Delete Preset" msgstr "" #: src/program/BodySlideApp.cpp:5280 src/program/OutfitStudio.cpp:7900 #, c-format msgid "Failed to save preset (%d)!" msgstr "" #: src/program/BodySlideApp.cpp:5308 #, c-format msgid "Failed to save preset as '%s' (%d)!" msgstr "" #: src/program/BodySlideApp.cpp:5494 msgid "" "Fix Clipping is enabled for this batch build.\n" "\n" "Use this carefully: applying clipping fixes to many outfits at once can create unwelcome side effects on some meshes.\n" "\n" "Consider building outfits one-by-one and checking each result in Preview.\n" "\n" "Do you want to continue with batch build?" msgstr "" #: src/program/BodySlideApp.cpp:5603 msgid "Choose a folder to contain the saved files" msgstr "" #: src/program/BodySlideApp.cpp:5618 msgid "All sets processed successfully!" msgstr "" #: src/program/BodySlideApp.cpp:5618 msgid "Complete" msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:121 msgid "Starting conversion..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:139 msgid "Updating Project Output Settings" msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:178 msgid "Deleting Shapes..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:199 msgid "Loading conversion reference..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:201 #: src/program/ConvertBodyReferenceDialog.cpp:234 msgid "Load Error" msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:209 #: src/program/ConvertBodyReferenceDialog.cpp:253 msgid "Conforming outfit parts..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:213 #: src/program/ConvertBodyReferenceDialog.cpp:255 msgid "Conform Error" msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:216 msgid "Updating conversion Slider..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:220 msgid "Setting the base shape and removing the conversion reference" msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:227 msgid "Skipping conversion reference..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:232 msgid "Loading new reference..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:242 msgid "Missing Base Shape" msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:246 msgid "Copying bones..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:248 msgid "Copy Bone Weights Error" msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:260 msgid "Adding Bones..." msgstr "" #: src/program/ConvertBodyReferenceDialog.cpp:289 msgid "Conversion finished." msgstr "" #: src/program/EditUV.cpp:264 msgid "Save UV template image" msgstr "" #: src/program/EditUV.cpp:276 msgid "Failed to export UV template." msgstr "" #: src/program/EditUV.cpp:575 src/program/OutfitStudio.cpp:12438 msgid "Outfit Studio: OpenGL context is not OK." msgstr "" #: src/program/EditUV.cpp:575 src/program/OutfitStudio.cpp:12438 #: src/render/GLDialog.cpp:33 src/render/GLSurface.cpp:2266 #: src/render/GLSurface.cpp:2283 src/render/GLSurface.cpp:2300 #: src/ui/PreviewPanel.cpp:151 msgid "OpenGL Error" msgstr "" #: src/program/FBXImportDialog.cpp:163 src/program/ObjImportDialog.cpp:168 #: src/program/OutfitStudio.cpp:10431 src/program/OutfitStudio.cpp:13793 msgid "The shape has reached the vertex count limit." msgstr "" #: src/program/FBXImportDialog.cpp:167 src/program/ObjImportDialog.cpp:172 #: src/program/OutfitStudio.cpp:10436 src/program/OutfitStudio.cpp:13798 msgid "The shape has reached the triangle count limit." msgstr "" #: src/program/GroupManager.cpp:143 msgid "Please enter a new unique name for the group." msgstr "" #: src/program/GroupManager.cpp:143 msgid "Rename Group" msgstr "" #: src/program/GroupManager.cpp:323 msgid "Save changes to group file?" msgstr "" #: src/program/GroupManager.cpp:323 msgid "Save Changes" msgstr "" #: src/program/NormalsGenDialog.cpp:90 msgid "Enter a name for the new layer." msgstr "" #: src/program/NormalsGenDialog.cpp:90 msgid "Name new layer" msgstr "" #: src/program/NormalsGenDialog.cpp:209 msgid "Choose a normals generator preset file..." msgstr "" #: src/program/NormalsGenDialog.cpp:226 msgid "Save normals generator preset to..." msgstr "" #: src/program/NormalsGenDialog.cpp:244 msgid "Layer" msgstr "" #: src/program/NormalsGenDialog.cpp:267 msgid "Background File" msgstr "" #: src/program/NormalsGenDialog.cpp:268 msgid "File source for this layer." msgstr "" #: src/program/NormalsGenDialog.cpp:269 msgid "Color" msgstr "" #: src/program/NormalsGenDialog.cpp:270 msgid "Solid background color (if file is not set)." msgstr "" #: src/program/NormalsGenDialog.cpp:273 msgid "Output texture dimensions. By default all images will be scaled to fit this size." msgstr "" #: src/program/NormalsGenDialog.cpp:290 msgid "File containing normals data to combine. Note this file should fit the mesh UVs." msgstr "" #: src/program/NormalsGenDialog.cpp:292 msgid "Is Tangent Space?" msgstr "" #: src/program/NormalsGenDialog.cpp:293 msgid "True if the normals data in the layer file is in tangent space, false if they are in model space (msn)." msgstr "" #: src/program/NormalsGenDialog.cpp:296 msgid "A greyscale image used to mask updates to destination image." msgstr "" #: src/program/NormalsGenDialog.cpp:298 msgid "X Offset" msgstr "" #: src/program/NormalsGenDialog.cpp:299 src/program/NormalsGenDialog.cpp:302 msgid "Offset to apply to image position." msgstr "" #: src/program/NormalsGenDialog.cpp:301 msgid "Y Offset" msgstr "" #: src/program/NormalsGenDialog.cpp:305 msgid "If true, scale image to match background resolution." msgstr "" #: src/program/OutfitProject.cpp:60 msgid "Checking destination..." msgstr "" #: src/program/OutfitProject.cpp:121 msgid "Adding reference shapes..." msgstr "" #: src/program/OutfitProject.cpp:146 src/program/OutfitProject.cpp:2513 msgid "Adding outfit shapes..." msgstr "" #: src/program/OutfitProject.cpp:205 msgid "Calculating slider data..." msgstr "" #: src/program/OutfitProject.cpp:213 msgid "Creating slider set file..." msgstr "" #: src/program/OutfitProject.cpp:220 msgid "Failed to open or create slider set file: " msgstr "" #: src/program/OutfitProject.cpp:227 msgid "Saving slider set file..." msgstr "" #: src/program/OutfitProject.cpp:230 msgid "Failed to write to slider set file: " msgstr "" #: src/program/OutfitProject.cpp:234 msgid "Saving NIF file..." msgstr "" #: src/program/OutfitProject.cpp:267 msgid "Failed to write base .nif file: " msgstr "" #: src/program/OutfitProject.cpp:273 src/program/OutfitProject.cpp:1915 #: src/program/OutfitProject.cpp:1945 src/program/OutfitStudio.cpp:3972 msgid "Finished" msgstr "" #: src/program/OutfitProject.cpp:1809 src/program/OutfitProject.cpp:1901 msgid "Gathering bones..." msgstr "" #: src/program/OutfitProject.cpp:1837 msgid "Initializing proximity data..." msgstr "" #: src/program/OutfitProject.cpp:1883 src/program/OutfitStudio.cpp:11015 msgid "Copying bone weights..." msgstr "" #: src/program/OutfitProject.cpp:1921 src/program/OutfitStudio.cpp:11145 msgid "Transferring bone weights..." msgstr "" #: src/program/OutfitProject.cpp:2167 msgid "Template source entries are invalid." msgstr "" #: src/program/OutfitProject.cpp:2167 src/program/OutfitProject.cpp:2197 #: src/program/OutfitProject.cpp:2202 src/program/OutfitProject.cpp:2264 #: src/program/OutfitProject.cpp:2286 src/program/OutfitProject.cpp:2293 #: src/program/OutfitProject.cpp:2303 src/program/OutfitProject.cpp:2315 msgid "Reference Error" msgstr "" #: src/program/OutfitProject.cpp:2194 src/program/OutfitProject.cpp:2283 #: src/program/OutfitProject.cpp:5057 #, c-format msgid "" "NIF version not supported!\n" "\n" "File: %s\n" "%s" msgstr "" #: src/program/OutfitProject.cpp:2202 src/program/OutfitProject.cpp:2293 #, c-format msgid "Could not load reference NIF file '%s'!" msgstr "" #: src/program/OutfitProject.cpp:2244 src/program/OutfitProject.cpp:2392 msgid "The following shapes were deleted. Rename the duplicates yourself beforehand if you wish to keep them." msgstr "" #: src/program/OutfitProject.cpp:2245 src/program/OutfitProject.cpp:2394 msgid "Deleted Shapes" msgstr "" #: src/program/OutfitProject.cpp:2264 #, c-format msgid "Could not load slider set file '%s'!" msgstr "" #: src/program/OutfitProject.cpp:2303 #, c-format msgid "Reference NIF file '%s' does not contain any shapes." msgstr "" #: src/program/OutfitProject.cpp:2315 #, c-format msgid "Shape '%s' not found in reference NIF file '%s'!" msgstr "" #: src/program/OutfitProject.cpp:2403 msgid "Loading slider set..." msgstr "" #: src/program/OutfitProject.cpp:2410 src/program/OutfitProject.cpp:2503 msgid "Retrieving sliders..." msgstr "" #: src/program/OutfitProject.cpp:2420 msgid "Loading outfit shapes..." msgstr "" #: src/program/OutfitProject.cpp:2463 src/program/OutfitProject.cpp:2569 msgid "Updating slider data..." msgstr "" #: src/program/OutfitProject.cpp:2495 msgid "Adding slider set..." msgstr "" #: src/program/OutfitProject.cpp:2562 msgid "The following shapes were renamed and won't have slider data attached. Rename the duplicates yourself beforehand." msgstr "" #: src/program/OutfitProject.cpp:2564 msgid "Renamed Shapes" msgstr "" #: src/program/OutfitProject.cpp:5060 src/program/OutfitProject.cpp:5065 msgid "NIF Error" msgstr "" #: src/program/OutfitProject.cpp:5065 #, c-format msgid "Could not load NIF file '%s'!" msgstr "" #: src/program/OutfitProject.cpp:5203 msgid "There was cloth physics data loaded at some point (BSClothExtraData). Please choose all the origins to use in the output." msgstr "" #: src/program/OutfitProject.cpp:5204 msgid "Choose cloth data" msgstr "" #: src/program/OutfitProject.cpp:5405 msgid "No reference has been loaded. For correct bone transforms, you might need to load a reference before importing OBJ files." msgstr "" #: src/program/OutfitProject.cpp:5413 #, c-format msgid "Could not load OBJ file '%s'!" msgstr "" #: src/program/OutfitProject.cpp:5413 src/program/OutfitProject.cpp:5437 #: src/program/OutfitProject.cpp:5499 src/program/OutfitProject.cpp:5666 msgid "OBJ Error" msgstr "" #: src/program/OutfitProject.cpp:5419 src/program/OutfitProject.cpp:5585 msgid "The reference shape has a skin coordinate system that is different from the global coordinate system. Would you like to copy the reference's global-to-skin transform to the imported shapes?" msgstr "" #: src/program/OutfitProject.cpp:5421 src/program/OutfitProject.cpp:5587 msgid "Copy skin coordinates" msgstr "" #: src/program/OutfitProject.cpp:5437 #, c-format msgid "Could not copy data from OBJ file '%s'!" msgstr "" #: src/program/OutfitProject.cpp:5454 msgid "The vertex count of the selected .obj file matches the currently selected outfit shape. Do you wish to update the current shape? (click No to create a new shape)" msgstr "" #: src/program/OutfitProject.cpp:5456 src/program/OutfitProject.cpp:5613 msgid "Merge or New" msgstr "" #: src/program/OutfitProject.cpp:5460 src/program/OutfitProject.cpp:5617 msgid "Update Vertex Positions?" msgstr "" #: src/program/OutfitProject.cpp:5460 src/program/OutfitProject.cpp:5617 msgid "Vertex Position Update" msgstr "" #: src/program/OutfitProject.cpp:5465 src/program/OutfitProject.cpp:5622 msgid "Update Texture Coordinates?" msgstr "" #: src/program/OutfitProject.cpp:5465 src/program/OutfitProject.cpp:5622 msgid "UV Update" msgstr "" #: src/program/OutfitProject.cpp:5471 src/program/OutfitProject.cpp:5628 msgid "Update Normals?" msgstr "" #: src/program/OutfitProject.cpp:5471 src/program/OutfitProject.cpp:5628 msgid "Normals Update" msgstr "" #: src/program/OutfitProject.cpp:5481 src/program/OutfitProject.cpp:5644 msgid "Please specify a name for the new shape" msgstr "" #: src/program/OutfitProject.cpp:5481 src/program/OutfitProject.cpp:5644 msgid "New Shape Name" msgstr "" #: src/program/OutfitProject.cpp:5492 src/program/OutfitProject.cpp:5659 #, c-format msgid "" "The vertex or triangle limit for '%s' was exceeded.\n" "Remaining data was dropped.\n" "\n" "Vertices (current/max): %zu/%zu\n" "Triangles (current/max): %zu/%zu" msgstr "" #: src/program/OutfitProject.cpp:5573 msgid "No reference has been loaded. For correct bone transforms, you might need to load a reference before importing FBX files." msgstr "" #: src/program/OutfitProject.cpp:5611 msgid "The vertex count of the selected .fbx file matches the currently selected outfit shape. Do you wish to update the current shape? (click No to create a new shape)" msgstr "" #: src/program/OutfitProject.cpp:5635 msgid "Update Animation Weighting?" msgstr "" #: src/program/OutfitProject.cpp:5635 msgid "Animation Weight Update" msgstr "" #: src/program/OutfitProject.cpp:5793 msgid "Would you like Skyrim NIFs to be optimized for SSE during this session?" msgstr "" #: src/program/OutfitProject.cpp:5810 msgid "File format doesn't match the current game. Use FBX export, then start a new project and import the FBX file there." msgstr "" #: src/program/OutfitProject.cpp:5811 msgid "Version" msgstr "" #: src/program/OutfitProject.cpp:5824 #, c-format msgid "Unable to locate external mesh data for shape. Expected path: %s" msgstr "" #: src/program/OutfitProject.cpp:5825 msgid "External Mesh Data Load Failure" msgstr "" #: src/program/OutfitProject.cpp:5935 msgid "No Bad Bones Found." msgstr "" #: src/program/OutfitProject.cpp:5935 msgid "No Bad Bones" msgstr "" #: src/program/OutfitProject.cpp:6050 msgid "Bad Bones" msgstr "" #: src/program/OutfitProject.cpp:6071 msgid "Error in rotation" msgstr "" #: src/program/OutfitProject.cpp:6072 msgid "Error in translation" msgstr "" #: src/program/OutfitProject.cpp:6073 msgid "Error in scale" msgstr "" #: src/program/OutfitProject.cpp:6100 #, c-format msgid "Bad standard bones for shape \"%s\"" msgstr "" #: src/program/OutfitProject.cpp:6103 #, c-format msgid "%zu bones in shape \"%s\" had inconsistencies between their NIF skin transforms and the standard skeleton:\n" msgstr "" #: src/program/OutfitProject.cpp:6118 msgid "Update skin (recommended)" msgstr "" #: src/program/OutfitProject.cpp:6126 src/program/OutfitProject.cpp:6190 #: src/program/OutfitProject.cpp:6213 msgid "Details" msgstr "" #: src/program/OutfitProject.cpp:6126 msgid "Bone" msgstr "" #: src/program/OutfitProject.cpp:6131 src/program/OutfitProject.cpp:6227 msgid "Do nothing" msgstr "" #: src/program/OutfitProject.cpp:6143 #, c-format msgid "Bad Custom Bone \"%s\"" msgstr "" #: src/program/OutfitProject.cpp:6146 #, c-format msgid "" "Custom bone \"%s\" had inconsistent NIF node and skin transforms for the following shapes:\n" "\"" msgstr "" #: src/program/OutfitProject.cpp:6166 msgid "Trust node and skins \"" msgstr "" #: src/program/OutfitProject.cpp:6168 msgid "Trust node and skin \"" msgstr "" #: src/program/OutfitProject.cpp:6176 msgid "\", and update other skins (recommended)" msgstr "" #: src/program/OutfitProject.cpp:6179 msgid "Trust node, and update skins" msgstr "" #: src/program/OutfitProject.cpp:6181 msgid "Trust node, and update skin" msgstr "" #: src/program/OutfitProject.cpp:6190 msgid "Skin" msgstr "" #: src/program/OutfitProject.cpp:6199 msgid "Trust skin \"" msgstr "" #: src/program/OutfitProject.cpp:6201 msgid "\", and update node" msgstr "" #: src/program/OutfitProject.cpp:6203 msgid "\", and update node and other skins" msgstr "" #: src/program/OutfitProject.cpp:6213 msgid "With" msgstr "" #: src/program/OutfitProject.cpp:6214 msgid "Node" msgstr "" #: src/program/OutfitProject.cpp:6240 msgid "Fix nothing" msgstr "" #: src/program/OutfitStudio.cpp:403 src/program/OutfitStudio.cpp:404 #: src/program/OutfitStudio.cpp:15159 src/program/OutfitStudio.cpp:15160 msgid "Adding NIF file..." msgstr "" #: src/program/OutfitStudio.cpp:408 src/program/OutfitStudio.cpp:419 #: src/program/OutfitStudio.cpp:431 src/program/OutfitStudio.cpp:4749 #: src/program/OutfitStudio.cpp:15164 src/program/OutfitStudio.cpp:15175 #: src/program/OutfitStudio.cpp:15187 msgid "Refreshing GUI..." msgstr "" #: src/program/OutfitStudio.cpp:415 src/program/OutfitStudio.cpp:15171 msgid "Adding OBJ file..." msgstr "" #: src/program/OutfitStudio.cpp:426 src/program/OutfitStudio.cpp:427 #: src/program/OutfitStudio.cpp:15182 src/program/OutfitStudio.cpp:15183 msgid "Adding FBX file..." msgstr "" #: src/program/OutfitStudio.cpp:537 msgid "Open in existing instance?" msgstr "" #: src/program/OutfitStudio.cpp:542 msgid "An instance of Outfit Studio is already running. Open file(s) in the existing instance?" msgstr "" #: src/program/OutfitStudio.cpp:547 msgid "Yes (always)" msgstr "" #: src/program/OutfitStudio.cpp:549 msgid "No (never)" msgstr "" #: src/program/OutfitStudio.cpp:845 msgid "Failed to find game install path registry value or GameDataPath in the config." msgstr "" #: src/program/OutfitStudio.cpp:1186 msgid "Failed to load OutfitStudio.xrc file!" msgstr "" #: src/program/OutfitStudio.cpp:1192 msgid "Failed to load Outfit Studio frame!" msgstr "" #: src/program/OutfitStudio.cpp:1211 src/program/OutfitStudio.cpp:4241 #: src/program/OutfitStudio.h:1135 msgid "Ready!" msgstr "" #: src/program/OutfitStudio.cpp:1743 src/program/OutfitStudio.cpp:1748 msgid "Packing projects to folder..." msgstr "" #: src/program/OutfitStudio.cpp:1769 src/program/OutfitStudio.cpp:1816 #: src/program/OutfitStudio.cpp:1919 #, c-format msgid "Failed to open input file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1780 #, c-format msgid "Failed to copy input file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1827 #, c-format msgid "Failed to copy data file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1837 src/program/OutfitStudio.cpp:1995 #, c-format msgid "Failed to save merged project file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1846 src/program/OutfitStudio.cpp:2004 #, c-format msgid "Failed to open project file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1857 #, c-format msgid "Failed to copy merged project file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1868 src/program/OutfitStudio.cpp:2030 #, c-format msgid "Failed to open group file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1880 #, c-format msgid "Failed to copy group file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:1886 src/program/OutfitStudio.cpp:2052 msgid "Packing finished." msgstr "" #: src/program/OutfitStudio.cpp:1890 src/program/OutfitStudio.cpp:1895 msgid "Packing projects to archive..." msgstr "" #: src/program/OutfitStudio.cpp:1927 src/program/OutfitStudio.cpp:1978 #: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2039 msgid "Failed to put new entry into archive!" msgstr "" #: src/program/OutfitStudio.cpp:1934 src/program/OutfitStudio.cpp:1985 #: src/program/OutfitStudio.cpp:2019 src/program/OutfitStudio.cpp:2046 msgid "Failed to copy file contents to archive!" msgstr "" #: src/program/OutfitStudio.cpp:1970 #, c-format msgid "Failed to open data file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:2361 src/program/OutfitStudio.cpp:2413 #: src/program/OutfitStudio.cpp:4112 src/program/OutfitStudio.cpp:4119 #: src/program/OutfitStudio.cpp:5195 src/program/OutfitStudio.cpp:5219 #: src/program/OutfitStudio.cpp:7977 src/program/OutfitStudio.cpp:8105 #: src/program/OutfitStudio.cpp:8221 src/program/OutfitStudio.cpp:8472 #: src/program/OutfitStudio.cpp:8490 src/program/OutfitStudio.cpp:8508 #: src/program/OutfitStudio.cpp:8529 msgid "There are no valid shapes loaded!" msgstr "" #: src/program/OutfitStudio.cpp:2369 src/program/OutfitStudio.cpp:2555 #, c-format msgid "Saving project '%s'..." msgstr "" #: src/program/OutfitStudio.cpp:2399 src/program/OutfitStudio.cpp:2583 msgid "Saving failed." msgstr "" #: src/program/OutfitStudio.cpp:2404 src/program/OutfitStudio.cpp:2578 msgid "Saved." msgstr "" #: src/program/OutfitStudio.cpp:2499 msgid "Invalid or no slider set file specified! Please try again." msgstr "" #: src/program/OutfitStudio.cpp:2508 msgid "No outfit name specified! Please try again." msgstr "" #: src/program/OutfitStudio.cpp:2516 msgid "No data folder specified! Please try again." msgstr "" #: src/program/OutfitStudio.cpp:2530 msgid "An invalid or no base outfit .nif file name specified! Please try again." msgstr "" #: src/program/OutfitStudio.cpp:2539 msgid "No game file path specified! Please try again." msgstr "" #: src/program/OutfitStudio.cpp:2545 msgid "No game file name specified! Please try again." msgstr "" #: src/program/OutfitStudio.cpp:2595 #, c-format msgid "Failed to open '%s' as a slider set file!" msgstr "" #: src/program/OutfitStudio.cpp:2595 src/program/OutfitStudio.cpp:2659 msgid "Slider Set Error" msgstr "" #: src/program/OutfitStudio.cpp:2614 msgid "Please choose an outfit to load" msgstr "" #: src/program/OutfitStudio.cpp:2614 msgid "Load a slider set" msgstr "" #: src/program/OutfitStudio.cpp:2625 msgid "Loading project..." msgstr "" #: src/program/OutfitStudio.cpp:2645 msgid "Loading outfit data..." msgstr "" #: src/program/OutfitStudio.cpp:2659 #, c-format msgid "Failed to create project '%s' from file '%s' (%d)!" msgstr "" #: src/program/OutfitStudio.cpp:2673 #, c-format msgid "Loading reference shape '%s'..." msgstr "" #: src/program/OutfitStudio.cpp:2687 msgid "Loading textures..." msgstr "" #: src/program/OutfitStudio.cpp:2692 src/program/OutfitStudio.cpp:3954 #: src/program/OutfitStudio.cpp:4214 msgid "Creating outfit..." msgstr "" #: src/program/OutfitStudio.cpp:2696 src/program/OutfitStudio.cpp:3964 #: src/program/OutfitStudio.cpp:4102 #, c-format msgid "Creating %zu slider(s)..." msgstr "" #: src/program/OutfitStudio.cpp:2725 msgid "Creating sliders..." msgstr "" #: src/program/OutfitStudio.cpp:2728 msgid "Clearing old sliders..." msgstr "" #: src/program/OutfitStudio.cpp:2739 msgid "Loading slider: " msgstr "" #: src/program/OutfitStudio.cpp:2817 src/program/OutfitStudio.cpp:8649 msgid "Enter a name for the new slider:" msgstr "" #: src/program/OutfitStudio.cpp:2817 src/program/OutfitStudio.cpp:8649 msgid "Create New Slider" msgstr "" #: src/program/OutfitStudio.cpp:2958 #, c-format msgid "Total Bones: %zu" msgstr "" #: src/program/OutfitStudio.cpp:2973 #, c-format msgid "Shape Selection Bones: %zu" msgstr "" #: src/program/OutfitStudio.cpp:3537 msgid "Edit Color" msgstr "" #: src/program/OutfitStudio.cpp:3703 msgid "You are trying to edit a slider's morph with that slider set to zero. Do you wish to set the slider to one now?" msgstr "" #: src/program/OutfitStudio.cpp:3720 msgid "You can only use the undiff brush while editing a slider. Note, use the pencil button next to a slider to enable editing of that slider's morph." msgstr "" #: src/program/OutfitStudio.cpp:3731 msgid "You can only edit the base shape when all sliders are zero. Do you wish to set all sliders to zero now? Note, use the pencil button next to a slider to enable editing of that slider's morph." msgstr "" #: src/program/OutfitStudio.cpp:3818 #, c-format msgid "You have unsaved changes to '%s'. Would you like to save them now?" msgstr "" #: src/program/OutfitStudio.cpp:3819 msgid "Unsaved Changes" msgstr "" #: src/program/OutfitStudio.cpp:3874 #, c-format msgid "Creating project '%s'..." msgstr "" #: src/program/OutfitStudio.cpp:3891 src/program/OutfitStudio.cpp:4038 msgid "Loading reference..." msgstr "" #: src/program/OutfitStudio.cpp:3931 src/program/OutfitStudio.cpp:4170 #: src/program/OutfitStudio.cpp:4179 msgid "Loading outfit..." msgstr "" #: src/program/OutfitStudio.cpp:3979 msgid "Select a slider set to load" msgstr "" #: src/program/OutfitStudio.cpp:3996 msgid "Select a slider set to add" msgstr "" #: src/program/OutfitStudio.cpp:4013 src/program/OutfitStudio.cpp:4124 #: src/program/OutfitStudio.cpp:4139 src/program/OutfitStudio.cpp:10116 #: src/program/OutfitStudio.cpp:10169 src/program/OutfitStudio.cpp:10261 #: src/program/OutfitStudio.cpp:10385 msgid "You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again." msgstr "" #: src/program/OutfitStudio.cpp:4044 msgid "Loading reference set..." msgstr "" #: src/program/OutfitStudio.cpp:4098 msgid "Creating reference..." msgstr "" #: src/program/OutfitStudio.cpp:4224 msgid "Unload the project? All unsaved changes will be lost" msgstr "" #: src/program/OutfitStudio.cpp:4224 msgid "Unload Project" msgstr "" #: src/program/OutfitStudio.cpp:4225 msgid "Unload" msgstr "" #: src/program/OutfitStudio.cpp:4670 src/program/OutfitStudio.cpp:15222 msgid "There is no shape selected!" msgstr "" #: src/program/OutfitStudio.cpp:4736 msgid "Import NIF file" msgstr "" #: src/program/OutfitStudio.cpp:4743 src/program/OutfitStudio.cpp:4744 msgid "Importing NIF file..." msgstr "" #: src/program/OutfitStudio.cpp:4765 msgid "" "Starfield supports two modes for mesh geometry data:\n" "\n" "Internal: Mesh data is embedded directly in the NIF file.\n" "Simpler for modding - single file, no external dependencies.\n" "\n" "External: Mesh data is stored in separate .mesh files under geometries/.\n" "Can be streamed from BA2 archives for better game performance.\n" "\n" "Would you like to embed the geometry data in the NIF (internal)?\n" "Choose 'Yes' for internal or 'No' for external." msgstr "" #: src/program/OutfitStudio.cpp:4772 msgid "Starfield Geometry Mode" msgstr "" #: src/program/OutfitStudio.cpp:4786 msgid "Export outfit NIF" msgstr "" #: src/program/OutfitStudio.cpp:4806 #, c-format msgid "Failed to save NIF file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:4806 src/program/OutfitStudio.cpp:4840 #: src/program/OutfitStudio.cpp:4925 src/program/OutfitStudio.cpp:5053 #: src/program/OutfitStudio.cpp:5279 msgid "Export Error" msgstr "" #: src/program/OutfitStudio.cpp:4822 msgid "Export project NIF" msgstr "" #: src/program/OutfitStudio.cpp:4840 #, c-format msgid "Failed to save NIF file '%s' with reference!" msgstr "" #: src/program/OutfitStudio.cpp:4851 msgid "Export selected shapes to NIF" msgstr "" #: src/program/OutfitStudio.cpp:4865 msgid "Failed to export selected shapes to NIF file!" msgstr "" #: src/program/OutfitStudio.cpp:4870 msgid "Import .obj file for new shape" msgstr "" #: src/program/OutfitStudio.cpp:4908 msgid "Some of the shapes have coordinate systems that are not the same as the global coordinate system. Should the geometry be transformed to global coordinates in the OBJ? (This is not recommended.)" msgstr "" #: src/program/OutfitStudio.cpp:4910 src/program/OutfitStudio.cpp:4943 #: src/program/OutfitStudio.cpp:5038 src/program/OutfitStudio.cpp:5075 msgid "Transform to global" msgstr "" #: src/program/OutfitStudio.cpp:4917 msgid "Export project as an .obj file" msgstr "" #: src/program/OutfitStudio.cpp:4925 src/program/OutfitStudio.cpp:4965 #: src/program/OutfitStudio.cpp:4984 src/program/OutfitStudio.cpp:8463 msgid "Failed to export OBJ file!" msgstr "" #: src/program/OutfitStudio.cpp:4941 msgid "Some of the shapes have skin coordinate systems that are not the same as the global coordinate system. Should the geometry be transformed to global coordinates in the OBJ?" msgstr "" #: src/program/OutfitStudio.cpp:4952 msgid "Export selected shapes as an .obj file" msgstr "" #: src/program/OutfitStudio.cpp:4969 msgid "Export shape as an .obj file" msgstr "" #: src/program/OutfitStudio.cpp:4991 msgid "Import .fbx file for new shape" msgstr "" #: src/program/OutfitStudio.cpp:5017 src/program/OutfitStudio.cpp:5056 #: src/program/OutfitStudio.cpp:5120 src/program/OutfitStudio.cpp:8364 msgid "FBX is only supported in 64-bit builds of Outfit Studio. Start \"OutfitStudio x64\" instead." msgstr "" #: src/program/OutfitStudio.cpp:5017 src/program/OutfitStudio.cpp:5056 #: src/program/OutfitStudio.cpp:5120 src/program/OutfitStudio.cpp:5257 #: src/program/OutfitStudio.cpp:7122 src/program/OutfitStudio.cpp:7893 #: src/program/OutfitStudio.cpp:8364 msgid "Info" msgstr "" #: src/program/OutfitStudio.cpp:5036 msgid "Some of the shapes have skin coordinate systems that are not the same as the global coordinate system. Should the geometry be transformed to global coordinates in the FBX? (This is not recommended.)" msgstr "" #: src/program/OutfitStudio.cpp:5045 msgid "Export project as an .fbx file" msgstr "" #: src/program/OutfitStudio.cpp:5053 src/program/OutfitStudio.cpp:5097 #: src/program/OutfitStudio.cpp:5116 msgid "Failed to export FBX file!" msgstr "" #: src/program/OutfitStudio.cpp:5073 msgid "Some of the shapes have skin coordinate systems that are not the same as the global coordinate system. Should the geometry be transformed to global coordinates in the FBX?" msgstr "" #: src/program/OutfitStudio.cpp:5084 msgid "Export selected shapes as an .fbx file" msgstr "" #: src/program/OutfitStudio.cpp:5101 msgid "Export shape as an .fbx file" msgstr "" #: src/program/OutfitStudio.cpp:5125 src/program/OutfitStudio.cpp:8109 msgid "Import .tri morphs" msgstr "" #: src/program/OutfitStudio.cpp:5144 src/program/OutfitStudio.cpp:8118 msgid "Failed to load TRI file!" msgstr "" #: src/program/OutfitStudio.cpp:5150 src/program/OutfitStudio.cpp:9335 msgid "Please enter a new unique name for the shape." msgstr "" #: src/program/OutfitStudio.cpp:5202 src/program/OutfitStudio.cpp:5226 #: src/program/OutfitStudio.cpp:8494 msgid "Export .tri morphs" msgstr "" #: src/program/OutfitStudio.cpp:5212 src/program/OutfitStudio.cpp:5233 #: src/program/OutfitStudio.cpp:8501 msgid "Failed to export TRI file!" msgstr "" #: src/program/OutfitStudio.cpp:5238 msgid "Import physics data to project" msgstr "" #: src/program/OutfitStudio.cpp:5245 #, c-format msgid "Failed to import physics data file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:5245 msgid "Import Error" msgstr "" #: src/program/OutfitStudio.cpp:5257 msgid "There is no physics data loaded!" msgstr "" #: src/program/OutfitStudio.cpp:5265 msgid "Please choose the physics data source you want to export." msgstr "" #: src/program/OutfitStudio.cpp:5265 msgid "Choose physics data" msgstr "" #: src/program/OutfitStudio.cpp:5273 msgid "Export physics data" msgstr "" #: src/program/OutfitStudio.cpp:5279 #, c-format msgid "Failed to save physics data file '%s'!" msgstr "" #: src/program/OutfitStudio.cpp:5286 msgid "This function requires at least one slider position to be non-zero." msgstr "" #: src/program/OutfitStudio.cpp:5298 msgid "Create a conversion slider for the current slider settings with the following name: " msgstr "" #: src/program/OutfitStudio.cpp:5298 msgid "Create New Conversion Slider" msgstr "" #: src/program/OutfitStudio.cpp:6048 msgid "Please enter an SSF file path." msgstr "" #: src/program/OutfitStudio.cpp:6888 #, c-format msgid "Field of View: %d" msgstr "" #: src/program/OutfitStudio.cpp:7097 msgid "Your changes were not applied yet. Do you want to apply or reset them?" msgstr "" #: src/program/OutfitStudio.cpp:7098 msgid "Pending Changes" msgstr "" #: src/program/OutfitStudio.cpp:7122 msgid "You must have exactly one mesh selected in order to edit partitions or segments." msgstr "" #: src/program/OutfitStudio.cpp:7842 msgid "There are no sliders loaded!" msgstr "" #: src/program/OutfitStudio.cpp:7893 msgid "No changes were made to the sliders, so no preset was saved!" msgstr "" #: src/program/OutfitStudio.cpp:7909 src/program/OutfitStudio.cpp:7934 #: src/program/OutfitStudio.cpp:7955 src/program/OutfitStudio.cpp:8345 msgid "There is no slider in edit mode to import data to!" msgstr "" #: src/program/OutfitStudio.cpp:7913 msgid "Import .nif file for slider calculation" msgstr "" #: src/program/OutfitStudio.cpp:7920 msgid "No mesh found in the .nif file that matches currently selected shape!" msgstr "" #: src/program/OutfitStudio.cpp:7938 msgid "Import .bsd slider data" msgstr "" #: src/program/OutfitStudio.cpp:7959 msgid "Import .obj file for slider calculation" msgstr "" #: src/program/OutfitStudio.cpp:7966 src/program/OutfitStudio.cpp:8356 msgid "Vertex count of .obj file mesh does not match currently selected shape!" msgstr "" #: src/program/OutfitStudio.cpp:7981 msgid "Import .osd file" msgstr "" #: src/program/OutfitStudio.cpp:7990 msgid "Failed to import OSD file!" msgstr "" #: src/program/OutfitStudio.cpp:8030 src/program/OutfitStudio.cpp:8141 #: src/program/OutfitStudio.cpp:8273 msgid "This will delete all loaded sliders. Are you sure?" msgstr "" #: src/program/OutfitStudio.cpp:8030 src/program/OutfitStudio.cpp:8100 msgid "OSD Import" msgstr "" #: src/program/OutfitStudio.cpp:8100 src/program/OutfitStudio.cpp:8216 #: src/program/OutfitStudio.cpp:8336 #, c-format msgid "" "Added morphs for the following shapes:\n" "\n" "%s" msgstr "" #: src/program/OutfitStudio.cpp:8141 src/program/OutfitStudio.cpp:8216 msgid "TRI Import" msgstr "" #: src/program/OutfitStudio.cpp:8228 msgid "Import Starfield morph.dat file" msgstr "" #: src/program/OutfitStudio.cpp:8237 src/program/OutfitStudio.cpp:8243 msgid "Failed to import Starfield morph file!" msgstr "" #: src/program/OutfitStudio.cpp:8273 src/program/OutfitStudio.cpp:8336 msgid "Starfield Morph Import" msgstr "" #: src/program/OutfitStudio.cpp:8349 msgid "Import .fbx file for slider calculation" msgstr "" #: src/program/OutfitStudio.cpp:8373 src/program/OutfitStudio.cpp:8408 #: src/program/OutfitStudio.cpp:8440 msgid "There is no slider in edit mode to export data from!" msgstr "" #: src/program/OutfitStudio.cpp:8378 msgid "Export .nif slider data to directory" msgstr "" #: src/program/OutfitStudio.cpp:8389 msgid "Export .nif slider data" msgstr "" #: src/program/OutfitStudio.cpp:8396 msgid "Failed to export NIF file!" msgstr "" #: src/program/OutfitStudio.cpp:8413 msgid "Export .bsd slider data to directory" msgstr "" #: src/program/OutfitStudio.cpp:8424 msgid "Export .bsd slider data" msgstr "" #: src/program/OutfitStudio.cpp:8445 src/program/OutfitStudio.cpp:8533 msgid "Export .obj slider data to directory" msgstr "" #: src/program/OutfitStudio.cpp:8456 msgid "Export .obj slider data" msgstr "" #: src/program/OutfitStudio.cpp:8476 msgid "Export .osd file" msgstr "" #: src/program/OutfitStudio.cpp:8483 msgid "Failed to export OSD file!" msgstr "" #: src/program/OutfitStudio.cpp:8515 msgid "Export Starfield morph.dat" msgstr "" #: src/program/OutfitStudio.cpp:8522 msgid "Failed to export Starfield morph.dat file!" msgstr "" #: src/program/OutfitStudio.cpp:8560 msgid "Are you sure you wish to clear the unmasked slider data for the selected shapes? This action cannot be undone." msgstr "" #: src/program/OutfitStudio.cpp:8561 src/program/OutfitStudio.cpp:8566 msgid "Confirm data erase" msgstr "" #: src/program/OutfitStudio.cpp:8564 #, c-format msgid "Are you sure you wish to clear the unmasked slider data for the shape '%s'? This action cannot be undone." msgstr "" #: src/program/OutfitStudio.cpp:8618 msgid "Enter a name for the new zap:" msgstr "" #: src/program/OutfitStudio.cpp:8618 msgid "Create New Zap" msgstr "" #: src/program/OutfitStudio.cpp:8665 msgid "There is no slider in edit mode to clone!" msgstr "" #: src/program/OutfitStudio.cpp:8681 msgid "Enter a name for the cloned slider:" msgstr "" #: src/program/OutfitStudio.cpp:8701 msgid "There is no slider in edit mode to negate!" msgstr "" #: src/program/OutfitStudio.cpp:8717 msgid "There is no slider in edit mode to create a mask from!" msgstr "" #: src/program/OutfitStudio.cpp:8727 msgid "Are you sure you wish to delete the selected slider(s)?" msgstr "" #: src/program/OutfitStudio.cpp:8728 msgid "Confirm slider delete" msgstr "" #: src/program/OutfitStudio.cpp:8928 msgid "There is no slider in edit mode to show properties for!" msgstr "" #: src/program/OutfitStudio.cpp:8941 src/program/OutfitStudio.cpp:8946 #, c-format msgid "Strength: %d" msgstr "" #: src/program/OutfitStudio.cpp:8996 msgid "You must be in slider edit mode to fix clipping for a slider." msgstr "" #: src/program/OutfitStudio.cpp:9002 src/program/OutfitStudio.cpp:10067 msgid "No reference shape set." msgstr "" #: src/program/OutfitStudio.cpp:9070 src/program/OutfitStudio.cpp:9120 msgid "Conforming: " msgstr "" #: src/program/OutfitStudio.cpp:9101 msgid "Conforming shapes..." msgstr "" #: src/program/OutfitStudio.cpp:9131 msgid "All shapes conformed." msgstr "" #: src/program/OutfitStudio.cpp:10140 msgid "Are you sure you wish to delete parts of the selected shapes?" msgstr "" #: src/program/OutfitStudio.cpp:10181 msgid "Please enter a unique name for the new separated shape." msgstr "" #: src/program/OutfitStudio.cpp:10181 msgid "Separate Vertices..." msgstr "" #: src/program/OutfitStudio.cpp:10231 msgid "No errors found!" msgstr "" #: src/program/OutfitStudio.cpp:10237 msgid "Errors:" msgstr "" #: src/program/OutfitStudio.cpp:10239 msgid "Target must be different from source." msgstr "" #: src/program/OutfitStudio.cpp:10241 msgid "Partitions do not match. Make sure the amount of partitions and their slots match up." msgstr "" #: src/program/OutfitStudio.cpp:10243 msgid "Segments do not match. Make sure the amount of segments, sub segments and their info as well as the segmentation file match." msgstr "" #: src/program/OutfitStudio.cpp:10245 msgid "Resulting shape would have too many vertices." msgstr "" #: src/program/OutfitStudio.cpp:10247 msgid "Resulting shape would have too many triangles." msgstr "" #: src/program/OutfitStudio.cpp:10249 msgid "Shaders do not match. Make sure both shapes either have or don't have a shader and their shader type matches." msgstr "" #: src/program/OutfitStudio.cpp:10251 msgid "Base texture doesn't match. Make sure both shapes have the same base/diffuse texture path." msgstr "" #: src/program/OutfitStudio.cpp:10253 msgid "Alpha property mismatch. Make sure both shapes either have or don't have an alpha property and their flags + threshold match." msgstr "" #: src/program/OutfitStudio.cpp:10340 msgid "You can only copy shapes into an outfit, and there is no outfit in the current project. Load one first!" msgstr "" #: src/program/OutfitStudio.cpp:10348 msgid "Please enter a unique name for the duplicated shape." msgstr "" #: src/program/OutfitStudio.cpp:10390 msgid "There is more than one shape selected." msgstr "" #: src/program/OutfitStudio.cpp:10457 msgid "Some edges have multiple triangles of the same orientation. They have been highlighted and masked. Correct the orientations before refining." msgstr "" #: src/program/OutfitStudio.cpp:10475 msgid "Can't delete shape while in slider edit mode. Use CTRL+Delete to delete sliders instead." msgstr "" #: src/program/OutfitStudio.cpp:10483 msgid "Are you sure you wish to delete the selected shapes? This action cannot be undone." msgstr "" #: src/program/OutfitStudio.cpp:10514 msgid "Delete selected bones? This action cannot be undone." msgstr "" #: src/program/OutfitStudio.cpp:10524 msgid "Delete bones from selected shape(s)? This action cannot be undone." msgstr "" #: src/program/OutfitStudio.cpp:10532 msgid "Delete partition? This action cannot be undone." msgstr "" #: src/program/OutfitStudio.cpp:10539 msgid "Delete segment? This action cannot be undone." msgstr "" #: src/program/OutfitStudio.cpp:10684 msgid "No bone name was entered!" msgstr "" #: src/program/OutfitStudio.cpp:10692 src/program/OutfitStudio.cpp:10733 #, c-format msgid "Bone '%s' already exists in the project!" msgstr "" #: src/program/OutfitStudio.cpp:10791 msgid "View Standard Bone" msgstr "" #: src/program/OutfitStudio.cpp:10802 msgid "Edit Custom Bone" msgstr "" #: src/program/OutfitStudio.cpp:10885 msgid "The following shapes have unweighted vertices, which can cause issues. The affected vertices have been put under a mask. Do you want to save anyway?" msgstr "" #: src/program/OutfitStudio.cpp:10888 msgid "Unweighted Vertices" msgstr "" #: src/program/OutfitStudio.cpp:10992 src/program/OutfitStudio.cpp:11120 #: src/program/OutfitStudio.cpp:11254 msgid "There is no reference shape!" msgstr "" #: src/program/OutfitStudio.cpp:11001 msgid "Sorry, you can't copy weights from the reference shape to itself. Skipping this shape." msgstr "" #: src/program/OutfitStudio.cpp:11001 msgid "Can't copy weights" msgstr "" #: src/program/OutfitStudio.cpp:11125 msgid "Sorry, you can't copy weights from the reference shape to itself." msgstr "" #: src/program/OutfitStudio.cpp:11132 msgid "The vertex count of the reference and chosen shape is not the same!" msgstr "" #: src/program/OutfitStudio.cpp:11263 msgid "Sorry, you can't copy partitions/segments from the reference shape to itself. Skipping this shape." msgstr "" #: src/program/OutfitStudio.cpp:11263 msgid "Can't copy segments/partitions" msgstr "" #: src/program/OutfitStudio.cpp:11268 msgid "Triangles will be assigned to the partition/segment of the nearest triangle in the reference. Existing partitions/segments are cleared. This action can't be undone." msgstr "" #: src/program/OutfitStudio.cpp:11268 msgid "Copy Partitions/Segments" msgstr "" #: src/program/OutfitStudio.cpp:11277 msgid "Copying segments/partitions..." msgstr "" #: src/program/OutfitStudio.cpp:11288 #, c-format msgid "The partitions/segments could not be copied for '%s' because %d triangles could not be matched." msgstr "" #: src/program/OutfitStudio.cpp:11339 msgid " sliders" msgstr "" #: src/program/OutfitStudio.cpp:11341 msgid " bones" msgstr "" #: src/program/OutfitStudio.cpp:11477 msgid "Symmetrize Vertices" msgstr "" #: src/program/OutfitStudio.cpp:11479 msgid "Eliminates the selected asymmetries from unmasked vertices by adjusting vertex data to be consistent with mirror vertices." msgstr "" #: src/program/OutfitStudio.cpp:11481 msgid " (Hint: To choose which non-selected bones are adjusted during weight normalization, unlock them in the bones list in the Bones tab.)" msgstr "" #: src/program/OutfitStudio.cpp:11485 msgid "Vertices that will be symmetrized:" msgstr "" #: src/program/OutfitStudio.cpp:11486 msgid "&Symmetrize" msgstr "" #: src/program/OutfitStudio.cpp:11639 #, c-format msgid "%d unreferenced nodes were deleted." msgstr "" #: src/program/OutfitStudio.cpp:11944 msgid "No masks to export." msgstr "" #: src/program/OutfitStudio.cpp:11944 src/program/OutfitStudio.cpp:11948 #: src/program/OutfitStudio.cpp:11978 msgid "Export Masks" msgstr "" #: src/program/OutfitStudio.cpp:11978 msgid "Failed to save mask file." msgstr "" #: src/program/OutfitStudio.cpp:11982 src/program/OutfitStudio.cpp:11993 msgid "Import Masks" msgstr "" #: src/program/OutfitStudio.cpp:11993 msgid "Failed to load mask file." msgstr "" #: src/program/OutfitStudio.cpp:12000 msgid "Imported Mask" msgstr "" #: src/program/OutfitStudio.cpp:12188 msgid "Reset all bone poses?" msgstr "" #: src/program/OutfitStudio.cpp:12188 msgid "Reset Pose" msgstr "" #: src/program/OutfitStudio.cpp:12344 msgid "Please enter a new unique name for the pose." msgstr "" #: src/program/OutfitStudio.cpp:12344 msgid "New Pose" msgstr "" #: src/program/OutfitStudio.cpp:12395 #, c-format msgid "Are you sure you wish to delete the pose '%s'?" msgstr "" #: src/program/OutfitStudio.cpp:12396 msgid "Confirm pose delete" msgstr "" #: src/program/OutfitStudio.cpp:13434 msgid "The vertex picked has more than three connections." msgstr "" #: src/program/OutfitStudio.cpp:13669 msgid "Neither the selected nor target vertices are on the mesh boundary. It is recommended that you only weld or merge boundary vertices. Continue?" msgstr "" #: src/program/OutfitStudio.cpp:13670 msgid "The selected vertex is not on the mesh boundary. It is recommended that you only weld or merge boundary vertices. Continue?" msgstr "" #: src/program/OutfitStudio.cpp:13671 msgid "The target vertex is not on the mesh boundary. It is recommended that you only weld or merge boundary vertices. Continue?" msgstr "" #: src/program/OutfitStudio.cpp:13672 msgid "Weld/Merge Non-Boundary Vertices" msgstr "" #: src/program/OutfitStudio.cpp:13754 msgid "The edge picked is on the surface boundary. Pick an interior edge." msgstr "" #: src/program/OutfitStudio.cpp:13811 msgid "The edge picked has multiple triangles of the same orientation. Correct the orientations before splitting." msgstr "" #: src/program/OutfitStudio.cpp:15233 src/program/OutfitStudio.cpp:15234 msgid "Loading slider file..." msgstr "" #: src/program/ShapeProperties.cpp:104 msgid "Material" msgstr "" #: src/program/ShapeProperties.cpp:117 #, c-format msgid "%zu shapes selected" msgstr "" #: src/program/ShapeProperties.cpp:132 #, c-format msgid "This action will affect all %zu selected shapes. Are you sure?" msgstr "" #: src/program/ShapeProperties.cpp:133 msgid "Confirmation" msgstr "" #: src/program/ShapeProperties.cpp:352 msgid "Choose material file" msgstr "" #: src/program/ShapeProperties.cpp:666 msgid "Please choose a shape to copy from" msgstr "" #: src/program/ShapeProperties.cpp:666 msgid "Choose shape" msgstr "" #: src/render/GLDialog.cpp:33 src/ui/PreviewPanel.cpp:151 msgid "Preview failed: OpenGL context is not OK." msgstr "" #: src/ui/PreviewPanel.cpp:57 msgid "Show the Normal Map Generator dialog." msgstr "" #: src/ui/PreviewPanel.cpp:61 msgid "Lock Shape" msgstr "" #: src/ui/PreviewPanel.cpp:62 msgid "Set the current preview shape to both low and high weight sliders." msgstr "" #: src/ui/PreviewPanel.cpp:66 msgid "Show Reference" msgstr "" #: src/ui/PreviewPanel.cpp:67 msgid "Show the reference shape from the source project for clipping preview." msgstr "" #: src/ui/PreviewPanel.cpp:75 msgid "Pop out preview into a separate window" msgstr "" #: src/ui/PreviewPanel.cpp:103 msgid "Loading preview..." msgstr "" #: src/ui/wxBrushSettingsPopup.cpp:133 msgid "Size" msgstr "" #: src/ui/wxBrushSettingsPopup.cpp:137 msgid "Shortcut: 'S' + mouse wheel" msgstr "" #: src/ui/wxBrushSettingsPopup.cpp:146 msgid "Strength" msgstr "" #: src/ui/wxBrushSettingsPopup.cpp:158 msgid "Focus" msgstr "" #: src/ui/wxBrushSettingsPopup.cpp:170 msgid "Spacing" msgstr "" #: src/ui/wxSliderPanel.cpp:65 msgid "Turn on edit mode for this slider." msgstr "" #: src/ui/wxSliderPanel.cpp:77 msgid "Weaken slider data by 1%." msgstr "" #: src/ui/wxSliderPanel.cpp:84 msgid "Strengthen slider data by 1%." msgstr "" ================================================ FILE: lang/af/BodySlide.mo ================================================ ================================================ FILE: lang/af/BodySlide.po ================================================ ================================================ FILE: lang/an/BodySlide.mo ================================================ ================================================ FILE: lang/an/BodySlide.po ================================================ ================================================ FILE: lang/ar/BodySlide.mo ================================================ ================================================ FILE: lang/ar/BodySlide.po ================================================ ================================================ FILE: lang/ca/BodySlide.mo ================================================ ================================================ FILE: lang/ca/BodySlide.po ================================================ ================================================ FILE: lang/cs/BodySlide.mo ================================================ ================================================ FILE: lang/cs/BodySlide.po ================================================ ================================================ FILE: lang/da/BodySlide.mo ================================================ ================================================ FILE: lang/da/BodySlide.po ================================================ ================================================ FILE: lang/de/BodySlide.po ================================================ msgid "" msgstr "" "Project-Id-Version: BodySlide\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.5\n" "X-Poedit-KeywordsList: _\n" #: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:457 msgid "About" msgstr "Über" #: res/xrc/About.xrc:145 res/xrc/GroupManager.xrc:189 msgid "Close" msgstr "Schließen" #: res/xrc/Actions.xrc:6 msgid "Apply a vertex position" msgstr "Setzt eine Vertex Position" #: res/xrc/Actions.xrc:15 msgid "This permanently moves a single vertex straight to the given location." msgstr "Dies bewegt einen einzelnen Vertex permanent zur angegebenen Position." #: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499 #: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:862 res/xrc/Actions.xrc:938 #: res/xrc/Actions.xrc:1014 res/xrc/Actions.xrc:1062 res/xrc/Actions.xrc:1212 #: res/xrc/Actions.xrc:1491 res/xrc/Actions.xrc:1592 res/xrc/BatchBuild.xrc:112 #: res/xrc/EditUV.xrc:32 res/xrc/EditUV.xrc:251 res/xrc/EditUV.xrc:326 #: res/xrc/EditUV.xrc:447 res/xrc/ImportDialog.xrc:174 res/xrc/Project.xrc:773 #: res/xrc/Project.xrc:950 res/xrc/Settings.xrc:459 #: res/xrc/ShapeProperties.xrc:831 res/xrc/Skeleton.xrc:36 #: res/xrc/Skeleton.xrc:259 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238 #: res/xrc/SliderDataImport.xrc:90 msgid "&OK" msgstr "&OK" #: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506 #: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:869 res/xrc/Actions.xrc:945 #: res/xrc/Actions.xrc:1021 res/xrc/Actions.xrc:1069 res/xrc/Actions.xrc:1219 #: res/xrc/Actions.xrc:1498 res/xrc/Actions.xrc:1599 res/xrc/Actions.xrc:1930 #: res/xrc/BatchBuild.xrc:57 res/xrc/BatchBuild.xrc:119 res/xrc/EditUV.xrc:39 #: res/xrc/EditUV.xrc:258 res/xrc/EditUV.xrc:333 res/xrc/EditUV.xrc:454 #: res/xrc/ImportDialog.xrc:181 res/xrc/Project.xrc:570 res/xrc/Project.xrc:780 #: res/xrc/Project.xrc:957 res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:466 #: res/xrc/Setup.xrc:302 res/xrc/ShapeProperties.xrc:838 #: res/xrc/Skeleton.xrc:43 res/xrc/Skeleton.xrc:266 res/xrc/Slider.xrc:71 #: res/xrc/Slider.xrc:246 res/xrc/SliderDataImport.xrc:97 msgid "&Cancel" msgstr "&Abbrechen" #: res/xrc/Actions.xrc:110 msgid "Move Shape" msgstr "Modell verschieben" #: res/xrc/Actions.xrc:254 msgid "Mirror Axis" msgstr "Spiegelachse" #: res/xrc/Actions.xrc:320 msgid "Scale Shape" msgstr "Modell skalieren" #: res/xrc/Actions.xrc:329 msgid "" "Scaling will adjust the size of a mesh. This permanently affects vertices." msgstr "" "Skalierung verändert die Größe eines Modells. Dies beeinflusst Vertices " "permanent." #: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667 #: res/xrc/ShapeProperties.xrc:711 res/xrc/Skeleton.xrc:133 msgid "Origin" msgstr "Ausgangspunkt" #: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678 msgid "Zero (0, 0, 0)" msgstr "Nullpunkt (0, 0, 0)" #: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679 msgid "Center of selected shapes(s)" msgstr "Mitte der ausgewählten Modelle" #: res/xrc/Actions.xrc:484 res/xrc/Actions.xrc:847 msgid "Uniform (XYZ)" msgstr "Proportionen beibehalten (XYZ)" #: res/xrc/Actions.xrc:517 msgid "Rotate Shape" msgstr "Modell rotieren" #: res/xrc/Actions.xrc:712 msgid "Inflate Shape" msgstr "Modell aufblasen" #: res/xrc/Actions.xrc:721 msgid "" "Inflate/deflate a mesh along its normals. This permanently affects vertices." msgstr "" "Aufblasen vergrößert ein Modell entlang dessen Normals. Dies beeinflusst " "Vertices permanent." #: res/xrc/Actions.xrc:880 msgid "Mirror Shape" msgstr "Modell spiegeln" #: res/xrc/Actions.xrc:924 msgid "Swap bones on X axis (L/R)" msgstr "Bones auf X-Achse tauschen (L/R)" #: res/xrc/Actions.xrc:956 msgid "Smooth Seams" msgstr "Normals an Rändern glätten" #: res/xrc/Actions.xrc:1032 msgid "Set Shape Textures" msgstr "Modelltexturen setzen" #: res/xrc/Actions.xrc:1079 res/xrc/ConvertBodyReference.xrc:183 #: res/xrc/OutfitStudio.xrc:1953 res/xrc/OutfitStudio.xrc:2413 msgid "Copy Bone Weights" msgstr "Bone Weighting kopieren" #: res/xrc/Actions.xrc:1088 msgid "" "Each vertex of the reference will copy its weights to the nearest collection " "of vertices within the given radius. Bear in mind that some geometry will " "always require manual tweaking to become weighted and work well. Often, the " "default values are sufficient." msgstr "" "Jeder Vertex der Referenz wird sein Weighting auf die nächste Sammlung an " "Vertices innerhalb des gegebenen Radius kopieren. Allerdings müssen manche " "Modelle trotzdem noch manuell bearbeitet werden, um Weighting abzubekommen " "oder gut damit zu funktionieren. Meist genügen die Standardwerte." #: res/xrc/Actions.xrc:1108 res/xrc/Actions.xrc:1258 msgid "Search Radius" msgstr "Suchradius" #: res/xrc/Actions.xrc:1137 res/xrc/Actions.xrc:1287 msgid "Max Vertex Targets" msgstr "Max Vertex Ziele" #: res/xrc/Actions.xrc:1168 res/xrc/Actions.xrc:1316 msgid "No Target Limit" msgstr "Keine Ziellimitierung" #: res/xrc/Actions.xrc:1177 msgid "" "The skin coordinate system doesn't match the reference shape's. Do you want " "to copy the transforms?" msgstr "" #: res/xrc/Actions.xrc:1187 msgid "Copy skin transform from reference" msgstr "Skin-Transformation der Referenz kopieren" #: res/xrc/Actions.xrc:1197 res/xrc/ShapeProperties.xrc:806 msgid "Recalculate geometry's coordinates so it doesn't move" msgstr "" #: res/xrc/Actions.xrc:1198 res/xrc/ShapeProperties.xrc:807 msgid "" "Transform geometry so its position in global coordinates does not change." msgstr "" #: res/xrc/Actions.xrc:1229 msgid "Conforming..." msgstr "Übertrage..." #: res/xrc/Actions.xrc:1238 msgid "" "Each vertex of the reference will copy its slider data to the nearest " "collection of vertices within the given radius. Bear in mind that some " "geometry will always require manual tweaking to become conformed and work " "well. Often, the default values are sufficient." msgstr "" "Jeder Vertex der Referenz wird seine Sliderdaten auf die nächste Sammlung an " "Vertices innerhalb des gegebenen Radius kopieren. Allerdings müssen manche " "Modelle trotzdem noch manuell bearbeitet werden, um die Sliderdaten " "abzubekommen oder gut damit zu funktionieren. Meist genügen die " "Standardwerte." #: res/xrc/Actions.xrc:1339 msgid "No Squeeze" msgstr "Nicht quetschen" #: res/xrc/Actions.xrc:1362 msgid "Solid Mode" msgstr "Festmodus" #: res/xrc/Actions.xrc:1385 msgid "Axis" msgstr "Achse" #: res/xrc/Actions.xrc:1435 res/xrc/BodySlide.xrc:97 #: res/xrc/NormalsGenDlg.xrc:191 msgid "Preset" msgstr "Preset" #: res/xrc/Actions.xrc:1451 src/program/OutfitStudio.cpp:8177 msgid "Default" msgstr "Standard" #: res/xrc/Actions.xrc:1460 msgid "Even Movement" msgstr "Glatte Bewegung" #: res/xrc/Actions.xrc:1469 msgid "Solid Object" msgstr "Festes Objekt" #: res/xrc/Actions.xrc:1508 msgid "Merge Geometry" msgstr "Geometrie zusammenführen" #: res/xrc/Actions.xrc:1517 msgid "" "This function copies vertices and triangles from one shape to another. " "Partitions/segments of source and target shapes must match. It is the " "user's responsibility to check that all other shape and shader properties " "are compatible, or merging will likely have side effects." msgstr "" #: res/xrc/Actions.xrc:1532 msgid "Source" msgstr "Quelle" #: res/xrc/Actions.xrc:1550 msgid "Target" msgstr "Ziel" #: res/xrc/Actions.xrc:1579 msgid "Delete source shape" msgstr "Quellmodell löschen" #: res/xrc/Actions.xrc:1609 msgid "Mask symmetric vertices" msgstr "Symmetrische Vertices maskieren" #: res/xrc/Actions.xrc:1618 msgid "Masks all vertices that do not have any of the selected asymmetries." msgstr "" "Maskiert alle Vertices, welche keine der ausgewählten Asymmetrien vorweisen." #: res/xrc/Actions.xrc:1644 msgid "Vertices currently unmasked:" msgstr "Vertices ohne Maskierung:" #: res/xrc/Actions.xrc:1672 msgid "Unmatched Vertices:" msgstr "Nicht zutreffende Vertices:" #: res/xrc/Actions.xrc:1694 msgid "Vertex Data Asymmetries" msgstr "Asymmetrien der Vertexdaten" #: res/xrc/Actions.xrc:1727 res/xrc/OutfitStudio.xrc:793 #: res/xrc/OutfitStudio.xrc:1057 res/xrc/ShapeProperties.xrc:84 #: res/xrc/ShapeProperties.xrc:620 msgid "Type" msgstr "Typ" #: res/xrc/Actions.xrc:1736 msgid "Average" msgstr "Durchschnitt" #: res/xrc/Actions.xrc:1745 msgid "Count" msgstr "Anzahl" #: res/xrc/Actions.xrc:1763 msgid "Position" msgstr "Position" #: res/xrc/Actions.xrc:1831 res/xrc/Project.xrc:751 msgid "Sliders" msgstr "Slider" #: res/xrc/Actions.xrc:1878 res/xrc/OutfitStudio.xrc:387 #: res/xrc/OutfitStudio.xrc:2461 res/xrc/OutfitStudio.xrc:2505 msgid "Bones" msgstr "Bones" #: res/xrc/Actions.xrc:1897 msgid "Vertices that will still be unmasked:" msgstr "Vertices die weiterhin unmaskiert sein werden:" #: res/xrc/Actions.xrc:1923 msgid "&Mask" msgstr "&Maskieren" #: res/xrc/BatchBuild.xrc:6 msgid "Batch Build" msgstr "Batch-Erstellung" #: res/xrc/BatchBuild.xrc:21 msgid "" "Select the slider sets for the batch build process. Use the group and outfit " "filters to show the outfits you want!" msgstr "" "Wählen Sie die Sets für den Batch-Erstellungsprozess. Mithilfe der Gruppen- " "und Outfitfilter können Sie die Auswahl eingrenzen!" #: res/xrc/BatchBuild.xrc:50 msgid "&Build" msgstr "&Erstellen" #: res/xrc/BatchBuild.xrc:67 src/program/BodySlideApp.cpp:2448 msgid "Choose output set" msgstr "Ausgabe-Set auswählen" #: res/xrc/BatchBuild.xrc:78 msgid "" "The following sets will override the same files.\n" "Please decide which one to use and select it in the list below." msgstr "" "Die folgenden Sets würde die selben Dateien überschreiben.\n" "Bitte entscheiden Sie, welche davon verwendet werden sollen." #: res/xrc/BatchBuild.xrc:88 msgid "Type and hit enter to choose output..." msgstr "Hier tippen und Enter betätigen, um die Ausgabe zu wählen..." #: res/xrc/BodySlide.xrc:7 msgid "BodySlide" msgstr "BodySlide" #: res/xrc/BodySlide.xrc:28 msgid "Outfit/Body" msgstr "Outfit/Körper" #: res/xrc/BodySlide.xrc:44 msgid "Select an outfit to modify" msgstr "Wählen Sie das zu bearbeitende Outfit" #: res/xrc/BodySlide.xrc:58 msgid "Deletes a project from its project file" msgstr "Löscht ein Projekt aus der Projektdatei" #: res/xrc/BodySlide.xrc:74 msgid "Opens the current project in Outfit Studio" msgstr "Öffnet das aktuelle Projekt in Outfit Studio" #: res/xrc/BodySlide.xrc:113 msgid "Choose from a list of slider settings presets" msgstr "Wählen Sie aus einer Liste von Presets" #: res/xrc/BodySlide.xrc:127 msgid "Deletes a preset from its preset file" msgstr "Löscht ein Preset aus der Presetdatei" #: res/xrc/BodySlide.xrc:142 msgid "Saves the new slider values to the currently selected preset" msgstr "Speichert die neuen Sliderwerte in das derzeit gewählte Preset" #: res/xrc/BodySlide.xrc:143 res/xrc/GroupManager.xrc:44 #: res/xrc/OutfitStudio.xrc:1257 res/xrc/OutfitStudio.xrc:1318 msgid "Save" msgstr "Speichern" #: res/xrc/BodySlide.xrc:153 msgid "Save the current slider settings as a new preset" msgstr "Speichert die aktuellen Sliderwerte als ein neues Preset" #: res/xrc/BodySlide.xrc:154 res/xrc/GroupManager.xrc:53 #: res/xrc/OutfitStudio.xrc:1266 res/xrc/OutfitStudio.xrc:1327 msgid "Save As..." msgstr "Speichern unter..." #: res/xrc/BodySlide.xrc:165 msgid "" "Opens the group manager where you can edit existing or create new groups" msgstr "Öffnet den Gruppenmanager zum Bearbeiten oder Erstellen von Gruppen" #: res/xrc/BodySlide.xrc:166 res/xrc/GroupManager.xrc:7 #: res/xrc/Project.xrc:1079 msgid "Group Manager" msgstr "Gruppenmanager" #: res/xrc/BodySlide.xrc:218 msgid "Single Weight" msgstr "Einzelnes Gewicht" #: res/xrc/BodySlide.xrc:245 msgid "Low Weight" msgstr "Unteres Gewicht" #: res/xrc/BodySlide.xrc:262 msgid "High Weight" msgstr "Oberes Gewicht" #: res/xrc/BodySlide.xrc:303 msgid "Copy the low weight slider values to the high weight section." msgstr "Kopiert die unteren Sliderwerte in den oberen Bereich." #: res/xrc/BodySlide.xrc:320 msgid "Default outfit choice in Batch Build" msgstr "Standardmäßige Wahl in Batch-Erstellung" #: res/xrc/BodySlide.xrc:331 msgid "Output Path (which the game would use for this outfit)" msgstr "Ausgabepfad (den das Spiel für dieses Outfit verwendet)" #: res/xrc/BodySlide.xrc:343 msgid "(right-click to view alternatives)" msgstr "(Rechtsklick zur Anzeige von Alternativen)" #: res/xrc/BodySlide.xrc:363 msgid "" "Build multiple outfits using the currently active slider values.\n" "\n" "Hold CTRL = Build to custom directory\n" "Hold ALT = Delete from output directory" msgstr "" "Erstellt mehrere Outfits unter Verwendung der derzeit aktiven Sliderwerte.\n" "\n" "STRG gedrückt halten = Benutzerdefiniertes Verzeichnis auswählen\n" "ALT gedrückt halten = Aus dem Ausgabeverzeichnis löschen" #: res/xrc/BodySlide.xrc:364 msgid "Batch Build..." msgstr "Batch-Erstellung..." #: res/xrc/BodySlide.xrc:379 msgid "Build Morphs" msgstr "Morphs erstellen" #: res/xrc/BodySlide.xrc:380 msgid "" "Builds a morphs (.tri) file alongside the meshes for accessing the sliders " "in-game. Requires other mods to make use of the morph data." msgstr "" "Erstellt eine Morphdatei (.tri) neben den Meshes zum Verwenden der Slider " "innerhalb des Spiels. Benötigt weitere Mods zur Verwendung der Morphs." #: res/xrc/BodySlide.xrc:390 msgid "Force Body Normals" msgstr "Körper Normals erzwingen" #: res/xrc/BodySlide.xrc:391 msgid "" "Adds normal and tangent data to the body meshes (including bodies within " "outfits) for Skyrim. Use this only if you have a tangent space body mod." msgstr "" #: res/xrc/BodySlide.xrc:407 msgid "Show a preview window for this outfit." msgstr "Zeigt eine Vorschau für dieses Outfit." #: res/xrc/BodySlide.xrc:408 res/xrc/NormalsGenDlg.xrc:166 #: src/program/PreviewWindow.cpp:27 msgid "Preview" msgstr "Vorschau" #: res/xrc/BodySlide.xrc:426 msgid "" "Creates the currently selected outfit/body.\n" "\n" "Hold CTRL = Build to working directory\n" "Hold ALT = Delete from output directory" msgstr "" "Erstellt das derzeit ausgewählte Outfit/den Körper.\n" "\n" "STRG gedrückt halten = Im Arbeitsverzeichnis erstellen\n" "ALT gedrückt halten = Vom Ausgabeverzeichnis entfernen" #: res/xrc/BodySlide.xrc:427 msgid "Build" msgstr "Erstellen" #: res/xrc/BodySlide.xrc:439 msgid "Copy the high weight slider values to the low weight section." msgstr "Kopiert die oberen Sliderwerte in den unteren Bereich." #: res/xrc/BodySlide.xrc:466 res/xrc/OutfitStudio.xrc:1755 msgid "Open settings dialog." msgstr "Öffnet die Einstellungen." #: res/xrc/BodySlide.xrc:467 res/xrc/OutfitStudio.xrc:1754 #: res/xrc/Settings.xrc:5 msgid "Settings" msgstr "Einstellungen" #: res/xrc/BodySlide.xrc:476 msgid "" "Open Outfit Studio, a full-featured tool for creating and converting outfits." msgstr "" "Öffnet Outfit Studio, ein mit vielen Funktionen ausgestattetes Werkzeug zum " "Erstellen und Konvertieren von Outfits." #: res/xrc/BodySlide.xrc:477 res/xrc/OutfitStudio.xrc:7 msgid "Outfit Studio" msgstr "Outfit Studio" #: res/xrc/BodySlide.xrc:487 res/xrc/BodySlide.xrc:499 msgid "Filter Options" msgstr "Filter Optionen" #: res/xrc/BodySlide.xrc:489 msgid "Choose groups..." msgstr "Gruppen auswählen..." #: res/xrc/BodySlide.xrc:490 msgid "Choose groups to display in the Outfit menu" msgstr "Gruppen an Outfits zum Anzeigen in der Liste auswählen" #: res/xrc/BodySlide.xrc:494 msgid "Refresh Groups" msgstr "Gruppen aktualisieren" #: res/xrc/BodySlide.xrc:495 msgid "Refresh group information" msgstr "Gruppeninformationen werden neu geladen" #: res/xrc/BodySlide.xrc:501 msgid "Refresh Outfits" msgstr "Outfits aktualisieren" #: res/xrc/BodySlide.xrc:502 msgid "Reloads outfit list" msgstr "Outfit-Liste wird neu geladen" #: res/xrc/BodySlide.xrc:506 msgid "Regular Expressions" msgstr "Reguläre Ausdrücke" #: res/xrc/BodySlide.xrc:507 msgid "Allow the use of regular expressions (regex) for filtering." msgstr "Erlaubt die Verwendung von regulären Ausdrücken (Regex) zur Filterung." #: res/xrc/BodySlide.xrc:511 msgid "Has Zap Options" msgstr "Hat Zap-Möglichkeiten" #: res/xrc/BodySlide.xrc:512 msgid "Show only outfits that have zap options." msgstr "Nur Outfits mit Zap-Möglichkeiten anzeigen." #: res/xrc/BodySlide.xrc:517 msgid "Browse outfit folder..." msgstr "Outfit-Ordner durchsuchen..." #: res/xrc/BodySlide.xrc:518 msgid "" "Browses to the shape data folder of the current outfit in the file explorer." msgstr "ShapeData-Verzeichnis des aktuellen Outfits im Datei-Explorer öffnen." #: res/xrc/BodySlide.xrc:521 msgid "Save Outfit list as group..." msgstr "Outfit-Liste als Gruppe speichern..." #: res/xrc/BodySlide.xrc:522 msgid "Save the current filtered outfit list as a group" msgstr "Speichert die derzeit gefilterten Outfits als neue Gruppe" #: res/xrc/BodySlide.xrc:527 res/xrc/Project.xrc:1096 #: res/xrc/SliderDataImport.xrc:106 msgid "Select None" msgstr "Nichts auswählen" #: res/xrc/BodySlide.xrc:530 res/xrc/EditUV.xrc:111 res/xrc/Project.xrc:1099 #: res/xrc/SliderDataImport.xrc:109 msgid "Select All" msgstr "Alle auswählen" #: res/xrc/BodySlide.xrc:533 res/xrc/EditUV.xrc:115 res/xrc/Project.xrc:1102 #: res/xrc/SliderDataImport.xrc:112 msgid "Invert Selection" msgstr "Auswahl umkehren" #: res/xrc/ConvertBodyReference.xrc:6 msgid "Convert / Replace Body Reference" msgstr "Körperreferenz konvertieren/ersetzen" #: res/xrc/ConvertBodyReference.xrc:16 res/xrc/ConvertBodyReference.xrc:219 msgid "This wizard aids in the conversion to another body/reference.." msgstr "" "Dieser Assistent hilft bei der Konvertierung zu einem anderen Körper/" "Referenz." #: res/xrc/ConvertBodyReference.xrc:25 msgid "Reference Bodies" msgstr "Referenzkörper" #: res/xrc/ConvertBodyReference.xrc:36 msgid "Select a conversion reference (or 'None' to skip converting):" msgstr "" "Wählen Sie eine Konvertierungsreferenz (oder 'None' um die Konvertierung zu " "überspringen):" #: res/xrc/ConvertBodyReference.xrc:58 msgid "Conversion Body Reference" msgstr "Konvertierungsreferenz" #: res/xrc/ConvertBodyReference.xrc:78 msgid "Select a body reference to convert to:" msgstr "Wählen Sie eine Körperreferenz zu der konvertiert wird:" #: res/xrc/ConvertBodyReference.xrc:100 msgid "New Body Reference" msgstr "Neue Körperreferenz" #: res/xrc/ConvertBodyReference.xrc:130 res/xrc/NormalsGenDlg.xrc:108 #: res/xrc/Slider.xrc:161 msgid "Options" msgstr "Optionen" #: res/xrc/ConvertBodyReference.xrc:136 res/xrc/SliderDataImport.xrc:77 msgid "Merge Sliders" msgstr "Slider zusammenführen" #: res/xrc/ConvertBodyReference.xrc:145 msgid "Merge Zaps" msgstr "Zaps zusammenführen" #: res/xrc/ConvertBodyReference.xrc:165 msgid "Conform Sliders" msgstr "Slider übertragen" #: res/xrc/ConvertBodyReference.xrc:174 msgid "Skip conform popup (use default settings)" msgstr "Conform-Popup überspringen (Standardwerte verwenden)" #: res/xrc/ConvertBodyReference.xrc:192 msgid "Skip bone weights popup (use default settings)" msgstr "Bone Weights-Popup überspringen (Standardwerte verwenden)" #: res/xrc/ConvertBodyReference.xrc:203 msgid "Delete reference after completion" msgstr "Referenz nach Abschluss entfernen" #: res/xrc/ConvertBodyReference.xrc:228 msgid "Rename Project (optional)" msgstr "Projekt umbenennen (optional)" #: res/xrc/ConvertBodyReference.xrc:239 msgid "Specify text to be removed from the project name (comma-delimited):" msgstr "" "Geben Sie einen Text an, der vom Projektnamen entfernt werden soll " "(kommagetrennt):" #: res/xrc/ConvertBodyReference.xrc:260 msgid "Remove from project name" msgstr "Vom Projektnamen entfernen" #: res/xrc/ConvertBodyReference.xrc:277 msgid "Specify any text to be prepended to project name:" msgstr "" "Geben Sie einen Text an, der dem Projektnamen vorangestellt werden soll:" #: res/xrc/ConvertBodyReference.xrc:298 msgid "Prepend to project name" msgstr "Vor den Projektnamen anfügen" #: res/xrc/ConvertBodyReference.xrc:315 msgid "NOTE: Game file output path is unaffected by this" msgstr "HINWEIS: Ausgabepfad für Spiel wird hiervon nicht beeinflusst" #: res/xrc/ConvertBodyReference.xrc:326 msgid "Extras (optional)" msgstr "Extras (optional)" #: res/xrc/ConvertBodyReference.xrc:337 msgid "Remove the following shapes before conversion (comma-delimited):" msgstr "Folgende Modelle vor der Konvertierung entfernen (kommagetrennt):" #: res/xrc/ConvertBodyReference.xrc:359 msgid "Shapes to delete" msgstr "Modelle entfernen" #: res/xrc/ConvertBodyReference.xrc:375 msgid "Add the following bones after conversion (comma-delimited):" msgstr "Folgende Bones nach der Konvertierung hinzufügen (kommagetrennt):" #: res/xrc/ConvertBodyReference.xrc:396 msgid "Bones to add" msgstr "Bones hinzufügen" #: res/xrc/EditUV.xrc:5 msgid "Edit UV" msgstr "Texturkoordinaten bearbeiten" #: res/xrc/EditUV.xrc:52 msgid "Box Selection" msgstr "Auswahlrechteck" #: res/xrc/EditUV.xrc:53 msgid "" "Box Selection\n" "Shortcut: 1" msgstr "" "Auswahlrechteck\n" "Tastenkürzel: 1" #: res/xrc/EditUV.xrc:60 msgid "Vertex Selection" msgstr "Vertex-Auswahl" #: res/xrc/EditUV.xrc:61 msgid "" "Vertex Selection\n" "Shortcut: 2" msgstr "" "Vertex-Auswahl\n" "Tastenkürzel: 2" #: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:78 #: res/xrc/OutfitStudio.xrc:2156 msgid "Move" msgstr "Bewegen" #: res/xrc/EditUV.xrc:68 msgid "" "Move\n" "Shortcut: 3" msgstr "" "Bewegen\n" "Tastenkürzel: 3" #: res/xrc/EditUV.xrc:74 res/xrc/EditUV.xrc:343 res/xrc/ImportDialog.xrc:71 #: res/xrc/OutfitStudio.xrc:1559 res/xrc/ShapeProperties.xrc:672 #: src/program/NormalsGenDialog.cpp:300 msgid "Scale" msgstr "Skalierung" #: res/xrc/EditUV.xrc:75 msgid "" "Scale\n" "Shortcut: 4" msgstr "" "Skalierung\n" "Tastenkürzel: 4" #: res/xrc/EditUV.xrc:81 res/xrc/EditUV.xrc:268 msgid "Rotate" msgstr "Rotieren" #: res/xrc/EditUV.xrc:82 msgid "" "Rotate\n" "Shortcut: 5" msgstr "" "Rotieren\n" "Tastenkürzel: 5" #: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89 msgid "Show Seam Edges" msgstr "Nahtkanten anzeigen" #: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1640 msgid "Menu" msgstr "Menü" #: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1763 msgid "Edit" msgstr "Bearbeiten" #: res/xrc/EditUV.xrc:101 res/xrc/OutfitStudio.xrc:1765 msgid "Undo\tCtrl+Z" msgstr "Rückgängig\tCtrl+Z" #: res/xrc/EditUV.xrc:102 res/xrc/OutfitStudio.xrc:1766 msgid "Undo the previous action." msgstr "Macht die letzte Aktion rückgängig." #: res/xrc/EditUV.xrc:105 res/xrc/OutfitStudio.xrc:1769 msgid "Redo\tCtrl+Y" msgstr "Wiederherstellen\tCtrl+Y" #: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:42 #: res/xrc/OutfitStudio.xrc:1770 msgid "Redo the next undone action." msgstr "Stellt die letzte Aktion wieder her." #: res/xrc/EditUV.xrc:110 msgid "Select All\tCtrl+A" msgstr "Alle auswählen\tCtrl+A" #: res/xrc/EditUV.xrc:114 msgid "Invert Selection\tCtrl+I" msgstr "Auswahl umkehren\tCtrl+I" #: res/xrc/EditUV.xrc:118 msgid "Select Less\tA" msgstr "Weniger auswählen\tD" #: res/xrc/EditUV.xrc:119 msgid "Select less adjacent points in the selected islands." msgstr "Weniger angrenzende Punkte in den ausgewählten Islands markieren." #: res/xrc/EditUV.xrc:122 msgid "Select More\tD" msgstr "Mehr auswählen\tD" #: res/xrc/EditUV.xrc:123 msgid "Select more adjacent points in the selected islands." msgstr "Mehr angrenzende Punkte in den ausgewählten Islands markieren." #: res/xrc/EditUV.xrc:127 msgid "Mask Selection" msgstr "Auswahl maskieren" #: res/xrc/EditUV.xrc:128 msgid "" "Create a mask from the current UV selection for the mesh in the main " "viewport." msgstr "Maskiert die aktuelle UV-Selektion des Meshes im Haupt-Viewport." #: res/xrc/EditUV.xrc:132 msgid "Translate...\tT" msgstr "Bewegen...\tT" #: res/xrc/EditUV.xrc:133 msgid "Show a dialog to translate the current selection." msgstr "Öffnet einen Dialog zum Bewegen der aktuellen Auswahl." #: res/xrc/EditUV.xrc:136 msgid "Rotate...\tR" msgstr "Rotieren...\tR" #: res/xrc/EditUV.xrc:137 msgid "Show a dialog to rotate the current selection." msgstr "Öffnet einen Dialog zum Rotieren der aktuellen Auswahl." #: res/xrc/EditUV.xrc:140 msgid "Scale...\tS" msgstr "Skalieren...\tS" #: res/xrc/EditUV.xrc:141 msgid "Show a dialog to scale the current selection." msgstr "Öffnet einen Dialog zum Skalieren der aktuellen Auswahl." #: res/xrc/EditUV.xrc:148 msgid "Translate" msgstr "Bewegen" #: res/xrc/EditUV.xrc:289 msgid "Angle" msgstr "Winkel" #: res/xrc/EditUV.xrc:432 msgid "Uniform (UV)" msgstr "Proportionen beibehalten (UV)" #: res/xrc/GroupManager.xrc:17 msgid "" "Choose a group and add or remove members by selecting them in the lists." msgstr "" "Wählen Sie eine Gruppe zum Hinzufügen oder Entfernen von Mitgliedern aus." #: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:1011 msgid "Select a group XML file" msgstr "Wählen Sie eine Gruppen-Datei" #: res/xrc/GroupManager.xrc:71 msgid "Groups" msgstr "Gruppen" #: res/xrc/GroupManager.xrc:101 msgid "Add Group" msgstr "Gruppe hinzufügen" #: res/xrc/GroupManager.xrc:110 msgid "Remove Group" msgstr "Gruppe entfernen" #: res/xrc/GroupManager.xrc:122 msgid "Members" msgstr "Mitglieder" #: res/xrc/GroupManager.xrc:137 msgid "Remove >>" msgstr "Entfernen >>" #: res/xrc/GroupManager.xrc:151 msgid "Outfits" msgstr "Outfits" #: res/xrc/GroupManager.xrc:172 msgid "<< Add" msgstr "<< Hinzufügen" #: res/xrc/ImportDialog.xrc:5 msgid "Import Options..." msgstr "Import Optionen..." #: res/xrc/ImportDialog.xrc:53 msgid "Invert U" msgstr "U invertieren" #: res/xrc/ImportDialog.xrc:62 msgid "Invert V" msgstr "V invertieren" #: res/xrc/ImportDialog.xrc:89 msgid "Rotate (X)" msgstr "Rotieren (X)" #: res/xrc/ImportDialog.xrc:98 msgid "Choose X rotation." msgstr "X-Rotation wählen." #: res/xrc/ImportDialog.xrc:113 msgid "Rotate (Y)" msgstr "Rotieren (Y)" #: res/xrc/ImportDialog.xrc:122 msgid "Choose Y rotation." msgstr "Y-Rotation wählen." #: res/xrc/ImportDialog.xrc:137 msgid "Rotate (Z)" msgstr "Rotieren (Z)" #: res/xrc/ImportDialog.xrc:146 msgid "Choose Z rotation." msgstr "Z-Rotation wählen." #: res/xrc/NormalsGenDlg.xrc:6 msgid "Normal Map Generator" msgstr "Normal Map Generator" #: res/xrc/NormalsGenDlg.xrc:21 msgid "Layers" msgstr "Schichten" #: res/xrc/NormalsGenDlg.xrc:37 msgid "Load or save preset layer settings." msgstr "Schichteneinstellungen laden oder speichern." #: res/xrc/NormalsGenDlg.xrc:61 msgid "Add a new layer after the current one in the layer list." msgstr "" "Fügt eine neue Schicht nach der aktuell in der Liste ausgewählten hinzu." #: res/xrc/NormalsGenDlg.xrc:62 msgid "Add Layer" msgstr "Schicht hinzufügen" #: res/xrc/NormalsGenDlg.xrc:71 msgid "Move selected layer up one position." msgstr "Bewegt die ausgewählte Schicht um eins nach oben." #: res/xrc/NormalsGenDlg.xrc:72 msgid "Move Up" msgstr "Nach oben" #: res/xrc/NormalsGenDlg.xrc:87 msgid "Delete the selected layer." msgstr "Die ausgewählte Schicht löschen." #: res/xrc/NormalsGenDlg.xrc:88 msgid "Delete Layer" msgstr "Schicht löschen" #: res/xrc/NormalsGenDlg.xrc:114 msgid "" "Save a copy of an existing normal map if one already exists. File is saved " "in the original directory." msgstr "" "Speichert eine Kopie einer existierenden Normal Map, wenn bereits eine " "existiert. Die Datei wird im selben Verzeichnis gespeichert." #: res/xrc/NormalsGenDlg.xrc:115 msgid "Backup destination file" msgstr "Zieldatei sichern" #: res/xrc/NormalsGenDlg.xrc:124 msgid "" "Compress output file using BC7 compression. This can make saving the file " "take a VERY long time!" msgstr "" "Ausgabedatei mit BC7 kompromieren. Dies kann die Speicherzeit um einiges " "erhöhen!" #: res/xrc/NormalsGenDlg.xrc:125 msgid "Compress output " msgstr "Ausgabe komprimieren " #: res/xrc/NormalsGenDlg.xrc:134 msgid "" "Use the file name specified in the background layer to save the normal map." msgstr "" "Verwende zum Speichern der Normal Map den Dateinamen, der in der " "Hintergrundschicht angegeben wurde." #: res/xrc/NormalsGenDlg.xrc:135 msgid "Save to background layer file" msgstr "Zur Hintergrund-Datei speichern" #: res/xrc/NormalsGenDlg.xrc:145 msgid "Choose an output file..." msgstr "Ausgabedatei auswählen..." #: res/xrc/NormalsGenDlg.xrc:149 msgid "Location to save normal map to." msgstr "Pfad zum Speichern der Normal Map." #: res/xrc/NormalsGenDlg.xrc:165 msgid "Display current settings on mesh in preview window." msgstr "Zeige die aktuellen Einstellungen auf dem Modell in der Vorschau." #: res/xrc/NormalsGenDlg.xrc:181 msgid "Generate and save the normal map file." msgstr "Normal Map-Datei generieren und abspeichern." #: res/xrc/NormalsGenDlg.xrc:182 msgid "Generate" msgstr "Generieren" #: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2017 msgid "Load Preset..." msgstr "Preset laden..." #: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2021 msgid "Save Preset..." msgstr "Preset speichern..." #: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5 msgid "New Project" msgstr "Neues Projekte" #: res/xrc/OutfitStudio.xrc:23 msgid "" "Create a new project by selecting a reference body slider set, and outfit " "model files." msgstr "" "Erstellt ein neues Projekt durch auswählen einer Referenz und eines Outfit " "Modells." #: res/xrc/OutfitStudio.xrc:28 msgid "Load Project" msgstr "Projekt laden" #: res/xrc/OutfitStudio.xrc:29 msgid "Load a previously created slider set for editing." msgstr "Läd ein zuvor erstelltes Set zur Bearbeitung." #: res/xrc/OutfitStudio.xrc:34 msgid "Undo" msgstr "Rückgängig" #: res/xrc/OutfitStudio.xrc:35 msgid "Undo a previous action." msgstr "Macht die letzte Aktion rückgängig." #: res/xrc/OutfitStudio.xrc:41 msgid "Redo" msgstr "Wiederherstellen" #: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2135 msgid "Select" msgstr "Auswählen" #: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2136 msgid "Navigate and select meshes (or vertices in vertex mode)." msgstr "" "Navigiert durch Modelle und wählt sie aus (oder Vertices im Vertexmodus)." #: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2140 #: src/program/NormalsGenDialog.cpp:291 msgid "Mask" msgstr "Maskieren" #: res/xrc/OutfitStudio.xrc:58 res/xrc/OutfitStudio.xrc:2141 msgid "" "Mask vertices to prevent them from being transformed.\n" "Hold down the ALT key to remove masking." msgstr "" "Maskiert Vertices, um zu verhindern, dass sie transformiert werden.\n" "ALT gedrückt halten, um Maskierungen zu entfernen." #: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2145 msgid "Inflate" msgstr "Vergrößern" #: res/xrc/OutfitStudio.xrc:65 res/xrc/OutfitStudio.xrc:2146 msgid "Increase mesh volume in an area." msgstr "Vergrößert das Meshvolumen im Bereich." #: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2151 msgid "Deflate" msgstr "Reduzieren" #: res/xrc/OutfitStudio.xrc:72 res/xrc/OutfitStudio.xrc:2152 msgid "Decrease mesh volume in an area." msgstr "Reduziert das Meshvolumen im Bereich." #: res/xrc/OutfitStudio.xrc:79 res/xrc/OutfitStudio.xrc:2157 msgid "Move vertices over a plane parallel to the view." msgstr "Bewegt Vertices auf einer Ebene parallel zur Blickrichtung." #: res/xrc/OutfitStudio.xrc:85 res/xrc/OutfitStudio.xrc:2161 msgid "Smooth" msgstr "Glätten" #: res/xrc/OutfitStudio.xrc:86 res/xrc/OutfitStudio.xrc:2162 msgid "Smooth an area of a mesh." msgstr "Glättet einen Bereich eines Meshes." #: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2166 msgid "Undiff" msgstr "Undiff" #: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2167 msgid "Undiff an area of a slider." msgstr "Entfernt Slider-Daten eines Bereichs." #: res/xrc/OutfitStudio.xrc:99 res/xrc/OutfitStudio.xrc:2171 msgid "Weight Paint" msgstr "Weight Pinsel" #: res/xrc/OutfitStudio.xrc:100 msgid "" "Apply animation weight values for currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "Wendet Animations-Weighting für den derzeit gewählten Bone an.\n" "ALT gedrückt halten, um das Weighting abzuschwächen." #: res/xrc/OutfitStudio.xrc:107 res/xrc/OutfitStudio.xrc:2177 msgid "Color Paint" msgstr "Farbe" #: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2178 msgid "" "Apply vertex colors.\n" "Hold down the ALT key to remove colors." msgstr "Vertexfarben anwenden. ALT gedrückt halten zum Entfernen." #: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2183 msgid "Alpha Paint" msgstr "Alpha" #: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2184 msgid "" "Apply vertex alpha.\n" "Hold down the ALT key to remove alpha." msgstr "Vertex Alpha anwenden. ALT gedrückt halten zum Entfernen." #: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2189 msgid "Collapse Vertex" msgstr "Collapse Vertex" #: res/xrc/OutfitStudio.xrc:124 res/xrc/OutfitStudio.xrc:2190 msgid "" "Deletes vertices with no more than three connections, without creating a " "hole." msgstr "" "Entfernt Vertices mit nicht mehr als drei Verbindungen ohne ein Loch dabei " "zu erzeugen." #: res/xrc/OutfitStudio.xrc:130 res/xrc/OutfitStudio.xrc:2194 msgid "Flip Edge" msgstr "Kante umkehren" #: res/xrc/OutfitStudio.xrc:131 res/xrc/OutfitStudio.xrc:2195 msgid "Flips mesh edges so that the opposite pair of vertices is connected." msgstr "" "Kehrt Kanten um, sodass das gegenüberliegende Paar an Vertices verbunden " "wird." #: res/xrc/OutfitStudio.xrc:137 res/xrc/OutfitStudio.xrc:2199 msgid "Split Edge" msgstr "Kante aufteilen" #: res/xrc/OutfitStudio.xrc:138 res/xrc/OutfitStudio.xrc:2200 msgid "Splits a mesh edge in two with a new vertex." msgstr "Teilt eine Kante mit einem neuen Vertex in zwei." #: res/xrc/OutfitStudio.xrc:144 res/xrc/OutfitStudio.xrc:2204 msgid "Move Vertex" msgstr "Vertex bewegen" #: res/xrc/OutfitStudio.xrc:145 res/xrc/OutfitStudio.xrc:2205 msgid "Moves a vertex." msgstr "Bewegt ein Vertex." #: res/xrc/OutfitStudio.xrc:155 msgid "Field of View" msgstr "Sichtfeld" #: res/xrc/OutfitStudio.xrc:159 msgid "Field of View: 65" msgstr "Sichtfeld: 65" #: res/xrc/OutfitStudio.xrc:164 msgid "Brush Settings" msgstr "Pinseleinstellungen" #: res/xrc/OutfitStudio.xrc:169 msgid "Open Discord invite link." msgstr "Discord Einladungslink öffnen." #: res/xrc/OutfitStudio.xrc:174 msgid "Open GitHub link." msgstr "GitHub-Link öffnen." #: res/xrc/OutfitStudio.xrc:179 msgid "Open PayPal link." msgstr "PayPal-Link öffnen." #: res/xrc/OutfitStudio.xrc:200 msgid "Transform" msgstr "Transformieren" #: res/xrc/OutfitStudio.xrc:201 res/xrc/OutfitStudio.xrc:2211 msgid "Shows a transform tool to manipulate shapes and vertices with." msgstr "" "Zeigt ein Transformierwerkzeug an, mit welchem Modelle und Vertices " "manipuliert werden können." #: res/xrc/OutfitStudio.xrc:207 msgid "Pivot" msgstr "Pivot" #: res/xrc/OutfitStudio.xrc:208 res/xrc/OutfitStudio.xrc:2216 msgid "" "Shows a pivot that can be moved and makes it the center of mesh operations " "like rotation and scale." msgstr "" "Zeigt einen verschiebbaren Pivot an und macht diesen das Zentrum von " "Modelloperationen wie das Rotieren oder Skalieren." #: res/xrc/OutfitStudio.xrc:214 msgid "Vertex Edit" msgstr "Vertex Bearbeitung" #: res/xrc/OutfitStudio.xrc:215 msgid "" "Lets you select vertices to add to or remove from the mask.\n" "Click on a vertex to select/unmask it.\n" "Hold down CTRL to unselect/mask it." msgstr "" "Hier können Sie Vertices auswählen, die der Maske hinzugefügt oder daraus " "entfernt werden sollen.\n" "Klicken Sie auf einen Vertex, um ihn auszuwählen/zu demaskieren.\n" "Halten Sie die STRG gedrückt zum maskieren." #: res/xrc/OutfitStudio.xrc:222 msgid "View Front" msgstr "Vorderansicht" #: res/xrc/OutfitStudio.xrc:223 msgid "Change camera view to the front." msgstr "Ändert die Kameraansicht nach vorne." #: res/xrc/OutfitStudio.xrc:227 msgid "View Back" msgstr "Hinteransicht" #: res/xrc/OutfitStudio.xrc:228 msgid "Change camera view to the back." msgstr "Ändert die Kameraansicht nach hinten." #: res/xrc/OutfitStudio.xrc:232 msgid "View Left" msgstr "Linksansicht" #: res/xrc/OutfitStudio.xrc:233 msgid "Change camera view to the left." msgstr "Ändert die Kameraansicht nach links." #: res/xrc/OutfitStudio.xrc:237 msgid "View Right" msgstr "Rechtsansicht" #: res/xrc/OutfitStudio.xrc:238 msgid "Change camera view to the right." msgstr "Ändert die Kameraansicht nach rechts." #: res/xrc/OutfitStudio.xrc:242 res/xrc/Settings.xrc:294 msgid "Perspective View" msgstr "Perspektivische Ansicht" #: res/xrc/OutfitStudio.xrc:243 msgid "Toggle perspective view." msgstr "Perspektivische Ansicht umschalten." #: res/xrc/OutfitStudio.xrc:249 msgid "Show Nodes" msgstr "Knoten anzeigen" #: res/xrc/OutfitStudio.xrc:250 msgid "Toggle rendering of nodes." msgstr "Knotenansicht umschalten." #: res/xrc/OutfitStudio.xrc:255 msgid "Show Bones" msgstr "Bones anzeigen" #: res/xrc/OutfitStudio.xrc:256 msgid "Toggle rendering of bones." msgstr "Bones-Ansicht umschalten." #: res/xrc/OutfitStudio.xrc:261 msgid "Show Floor" msgstr "Boden anzeigen" #: res/xrc/OutfitStudio.xrc:262 msgid "Toggle rendering of the floor grid." msgstr "Bodengitter umschalten." #: res/xrc/OutfitStudio.xrc:268 msgid "X Mirror" msgstr "X-Spiegelung" #: res/xrc/OutfitStudio.xrc:269 res/xrc/OutfitStudio.xrc:1775 msgid "Mirror edits across the X axis." msgstr "Spiegelt die Änderungen auf der X-Achse." #: res/xrc/OutfitStudio.xrc:276 res/xrc/OutfitStudio.xrc:1781 msgid "Edit Connected Only\tC" msgstr "Nur Verbundenes bearbeiten\tC" #: res/xrc/OutfitStudio.xrc:277 msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius." msgstr "" "Bearbeitet nur Vertices, die mit denen verbunden sind, die der Pinselradius " "erreicht." #: res/xrc/OutfitStudio.xrc:283 res/xrc/OutfitStudio.xrc:1788 msgid "Merge Vertex" msgstr "Vertex verschmelzen" #: res/xrc/OutfitStudio.xrc:284 res/xrc/OutfitStudio.xrc:1789 msgid "Merges two vertices and fills any gaps." msgstr "Verschmilzt zwei Vertices und füllt jegliche Lücken." #: res/xrc/OutfitStudio.xrc:290 res/xrc/OutfitStudio.xrc:1795 msgid "Weld Vertex" msgstr "Vertex angleichen" #: res/xrc/OutfitStudio.xrc:291 res/xrc/OutfitStudio.xrc:1796 msgid "Welds two vertices while keeping the texture coordinates (UV) distinct." msgstr "" "Gleicht zwei Vertices an, aber behält getrennte Texturkoordinaten (UV)." #: res/xrc/OutfitStudio.xrc:297 res/xrc/OutfitStudio.xrc:1802 msgid "Restrict To Surface" msgstr "Auf Oberfläche beschränken" #: res/xrc/OutfitStudio.xrc:298 res/xrc/OutfitStudio.xrc:1803 msgid "Restricts motion to a mesh surface." msgstr "Beschränkt Bewegung auf eine Modelloberfläche." #: res/xrc/OutfitStudio.xrc:304 res/xrc/OutfitStudio.xrc:1809 msgid "Restrict To Plane" msgstr "Auf Ebene beschränken" #: res/xrc/OutfitStudio.xrc:305 res/xrc/OutfitStudio.xrc:1810 msgid "Restricts motion to parallel to the surface." msgstr "Beschränkt Bewegung auf parallel zur Oberfläche." #: res/xrc/OutfitStudio.xrc:311 res/xrc/OutfitStudio.xrc:1816 msgid "Restrict To Normal" msgstr "Auf Normal beschränken" #: res/xrc/OutfitStudio.xrc:312 res/xrc/OutfitStudio.xrc:1817 msgid "Restricts motion to perpendicular to the surface." msgstr "Beschränkt Bewegung auf aufrecht zur Oberfläche." #: res/xrc/OutfitStudio.xrc:375 msgid "Meshes" msgstr "Modelle" #: res/xrc/OutfitStudio.xrc:399 res/xrc/OutfitStudio.xrc:2519 #: res/xrc/OutfitStudio.xrc:2545 msgid "Segments" msgstr "Segmente" #: res/xrc/OutfitStudio.xrc:411 res/xrc/OutfitStudio.xrc:2552 #: res/xrc/OutfitStudio.xrc:2563 msgid "Partitions" msgstr "Partitionen" #: res/xrc/OutfitStudio.xrc:423 msgid "Colors" msgstr "Farben" #: res/xrc/OutfitStudio.xrc:435 msgid "Lights" msgstr "Beleuchtung" #: res/xrc/OutfitStudio.xrc:475 msgid "Total Bones: 0" msgstr "Bones insgesamt: 0" #: res/xrc/OutfitStudio.xrc:485 msgid "Shape Selection Bones: 0" msgstr "Bones Modellauswahl: 0" #: res/xrc/OutfitStudio.xrc:515 msgid "Brush Color" msgstr "Pinselfarbe" #: res/xrc/OutfitStudio.xrc:524 msgid "Color of the brush." msgstr "Farbe des Pinsels." #: res/xrc/OutfitStudio.xrc:546 msgid "Clamp Max Value" msgstr "Maximalwert" #: res/xrc/OutfitStudio.xrc:589 src/program/OutfitStudio.cpp:3173 #: src/program/OutfitStudio.cpp:6817 msgid "Edit Alpha" msgstr "Alpha bearbeiten" #: res/xrc/OutfitStudio.xrc:635 res/xrc/OutfitStudio.xrc:1039 #: res/xrc/OutfitStudio.xrc:1140 src/program/OutfitStudio.cpp:6531 #: src/program/OutfitStudio.cpp:11359 src/ui/wxBrushSettingsPopup.cpp:186 msgid "Reset" msgstr "Zurücksetzen" #: res/xrc/OutfitStudio.xrc:648 msgid "Ambient" msgstr "Umgebung" #: res/xrc/OutfitStudio.xrc:673 msgid "Frontal" msgstr "Frontal" #: res/xrc/OutfitStudio.xrc:698 msgid "Directional 1" msgstr "Richtung 1" #: res/xrc/OutfitStudio.xrc:723 msgid "Directional 2" msgstr "Richtung 2" #: res/xrc/OutfitStudio.xrc:748 msgid "Directional 3" msgstr "Richtung 3" #: res/xrc/OutfitStudio.xrc:916 msgid "Slot" msgstr "Slot" #: res/xrc/OutfitStudio.xrc:991 src/program/OutfitStudio.cpp:5601 msgid "SSF File" msgstr "SSF-Datei" #: res/xrc/OutfitStudio.xrc:1011 msgid "Set" msgstr "Setzen" #: res/xrc/OutfitStudio.xrc:1029 res/xrc/OutfitStudio.xrc:1130 #: src/program/OutfitStudio.cpp:6531 msgid "Apply" msgstr "Anwenden" #: res/xrc/OutfitStudio.xrc:1158 msgid "De-/Select Sliders" msgstr "Slider ab-/anwählen" #: res/xrc/OutfitStudio.xrc:1177 msgid "Fixed Weight Brush" msgstr "Fixierte Pinselstärke" #: res/xrc/OutfitStudio.xrc:1188 msgid "Normalize Weights" msgstr "Weights normalisieren" #: res/xrc/OutfitStudio.xrc:1205 msgid "X-Mirror Bone" msgstr "Bone spiegeln" #: res/xrc/OutfitStudio.xrc:1230 msgid "Masks" msgstr "Masken" #: res/xrc/OutfitStudio.xrc:1275 res/xrc/OutfitStudio.xrc:1336 #: res/xrc/OutfitStudio.xrc:2485 msgid "Delete" msgstr "Entfernen" #: res/xrc/OutfitStudio.xrc:1291 msgid "Posing" msgstr "Posen" #: res/xrc/OutfitStudio.xrc:1352 msgid "Show Pose" msgstr "Pose anzeigen" #: res/xrc/OutfitStudio.xrc:1370 msgid "Reset Bone" msgstr "Bone zurücksetzen" #: res/xrc/OutfitStudio.xrc:1390 msgid "Rotation X" msgstr "Rotation X" #: res/xrc/OutfitStudio.xrc:1418 msgid "Rotation Y" msgstr "Rotation Y" #: res/xrc/OutfitStudio.xrc:1446 msgid "Rotation Z" msgstr "Rotation Z" #: res/xrc/OutfitStudio.xrc:1474 msgid "Offset X" msgstr "X-Verschiebung" #: res/xrc/OutfitStudio.xrc:1502 msgid "Offset Y" msgstr "Y-Verschiebung" #: res/xrc/OutfitStudio.xrc:1530 msgid "Offset Z" msgstr "Z-Verschiebung" #: res/xrc/OutfitStudio.xrc:1592 msgid "Reset All" msgstr "Alle zurücksetzen" #: res/xrc/OutfitStudio.xrc:1600 msgid "Apply to Mesh" msgstr "Auf Modell anwenden" #: res/xrc/OutfitStudio.xrc:1642 res/xrc/Settings.xrc:392 #: src/program/NormalsGenDialog.cpp:284 msgid "File" msgstr "Datei" #: res/xrc/OutfitStudio.xrc:1644 msgid "New Project...\tCtrl+N" msgstr "Neues Projekt...\tCtrl+N" #: res/xrc/OutfitStudio.xrc:1645 msgid "Create a new outfit project." msgstr "Erstellt ein neues Outfit Projekt." #: res/xrc/OutfitStudio.xrc:1648 msgid "Load Project..\tCtrl+O" msgstr "Projekt laden..\tCtrl+O" #: res/xrc/OutfitStudio.xrc:1649 msgid "Load a project." msgstr "Läd ein existierendes Projekt." #: res/xrc/OutfitStudio.xrc:1652 msgid "Add Project..\tCtrl+Shift+O" msgstr "Projekt hinzufügen..\tCtrl+Shift+O" #: res/xrc/OutfitStudio.xrc:1653 msgid "Add a project without replacing the current one." msgstr "Fügt ein Projekt hinzu, ohne das aktuelle zu ersetzen." #: res/xrc/OutfitStudio.xrc:1656 msgid "Unload Project...\tCtrl+W" msgstr "Projekt entladen...\tCtrl+W" #: res/xrc/OutfitStudio.xrc:1657 msgid "Unloads the project and creates an empty new one." msgstr "Entläd das Projekt und erstellt ein leeres neues." #: res/xrc/OutfitStudio.xrc:1660 msgid "Recent Projects..." msgstr "Zuletzt verwendete Projekte..." #: res/xrc/OutfitStudio.xrc:1665 msgid "Load Reference..." msgstr "Referenz laden..." #: res/xrc/OutfitStudio.xrc:1666 msgid "" "Load a new reference slider set, replacing any current reference objects." msgstr "Läd ein neues Referenzset. Ersetzt alle aktuellen Referenzobjekte." #: res/xrc/OutfitStudio.xrc:1669 msgid "Load Outfit..." msgstr "Outfit laden..." #: res/xrc/OutfitStudio.xrc:1670 msgid "" "Load a NIF file as the working outfit, replacing any current outfit objects." msgstr "" "Läd eine NIF-Datei als Arbeitsoutfit. Ersetzt alle aktuellen Outfit Objekte." #: res/xrc/OutfitStudio.xrc:1674 msgid "Convert / Replace Reference...\tCtrl+Shift+R" msgstr "Referenz konvertieren / ersetzen...\tCtrl+Shift+R" #: res/xrc/OutfitStudio.xrc:1675 msgid "Convert to or replace an outfit's body/reference" msgstr "Referenz/Körper konvertieren oder ersetzen" #: res/xrc/OutfitStudio.xrc:1679 msgid "Save Project\tCtrl+S" msgstr "Projekt speichern\tCtrl+S" #: res/xrc/OutfitStudio.xrc:1680 msgid "Save the project." msgstr "Speichert das Projekt." #: res/xrc/OutfitStudio.xrc:1684 msgid "Save Project As...\tCtrl+Shift+S" msgstr "Projekt speichern unter...\tCtrl+Shift+S" #: res/xrc/OutfitStudio.xrc:1685 msgid "Save the project under a new name." msgstr "Speichert das Projekt unter einem neuen Namen." #: res/xrc/OutfitStudio.xrc:1689 src/program/OutfitStudio.cpp:7392 #: src/program/OutfitStudio.cpp:7502 src/program/OutfitStudio.cpp:7628 msgid "Import" msgstr "Import" #: res/xrc/OutfitStudio.xrc:1691 msgid "From NIF..." msgstr "Aus NIF..." #: res/xrc/OutfitStudio.xrc:1692 msgid "Choose a NIF file to import into the project." msgstr "Wählen Sie eine NIF-Datei, die dem Projekt hinzugefügt werden soll." #: res/xrc/OutfitStudio.xrc:1695 msgid "From OBJ..." msgstr "Aus OBJ..." #: res/xrc/OutfitStudio.xrc:1696 msgid "Import an OBJ file as a new shape in the outfit." msgstr "Importiert eine OBJ-Datei als neues Modell." #: res/xrc/OutfitStudio.xrc:1699 msgid "From FBX..." msgstr "Aus FBX..." #: res/xrc/OutfitStudio.xrc:1700 msgid "Import an FBX file as a new shape in the outfit." msgstr "Importiert eine FBX-Datei als neues Modell." #: res/xrc/OutfitStudio.xrc:1703 msgid "From TRI (Head)..." msgstr "Aus TRI (Kopf)..." #: res/xrc/OutfitStudio.xrc:1704 msgid "Import shape and morphs from a head TRI file." msgstr "Importiert Modell und Morphs aus einer (Kopf) TRI-Datei." #: res/xrc/OutfitStudio.xrc:1707 msgid "Import Data" msgstr "Daten importieren" #: res/xrc/OutfitStudio.xrc:1709 msgid "Import BSClothExtraData From HKX" msgstr "BSClothExtraData aus HKX importieren" #: res/xrc/OutfitStudio.xrc:1710 msgid "" "Choose an HKX file to import as a BSClothExtraData block into the project." msgstr "Wählen Sie eine HKX-Datei zum Importieren als BSClothExtraData-Block." #: res/xrc/OutfitStudio.xrc:1715 res/xrc/OutfitStudio.xrc:1849 #: res/xrc/OutfitStudio.xrc:2329 msgid "Export" msgstr "Export" #: res/xrc/OutfitStudio.xrc:1717 msgid "To NIF...\tCtrl+E" msgstr "Als NIF...\tCtrl+E" #: res/xrc/OutfitStudio.xrc:1718 msgid "Save the current project as a NIF file (without reference)" msgstr "Speichert das aktuelle Projekt als NIF-Datei (ohne Referenz)" #: res/xrc/OutfitStudio.xrc:1721 msgid "To NIF With Reference...\tCtrl+Alt+E" msgstr "Als NIF mit Referenz...\tCtrl+Alt+E" #: res/xrc/OutfitStudio.xrc:1722 msgid "Save the current project as a NIF file (including reference)" msgstr "Speichert das aktuelle Projekt als NIF-Datei (inklusive Referenz)" #: res/xrc/OutfitStudio.xrc:1725 res/xrc/OutfitStudio.xrc:1855 #: res/xrc/OutfitStudio.xrc:2335 msgid "To OBJ..." msgstr "Als OBJ..." #: res/xrc/OutfitStudio.xrc:1726 msgid "Export the current project as an OBJ file." msgstr "Exportiert das aktuelle Projekt als OBJ-Datei." #: res/xrc/OutfitStudio.xrc:1729 res/xrc/OutfitStudio.xrc:1859 #: res/xrc/OutfitStudio.xrc:2339 msgid "To FBX..." msgstr "Als FBX..." #: res/xrc/OutfitStudio.xrc:1730 msgid "Export the current project as an FBX file." msgstr "Exportiert das aktuelle Projekt als FBX-Datei." #: res/xrc/OutfitStudio.xrc:1733 res/xrc/OutfitStudio.xrc:1863 #: res/xrc/OutfitStudio.xrc:2343 msgid "To TRI (Head)..." msgstr "Als TRI (Kopf)..." #: res/xrc/OutfitStudio.xrc:1734 res/xrc/OutfitStudio.xrc:1864 #: res/xrc/OutfitStudio.xrc:2344 msgid "Export head morphs to a TRI file." msgstr "Exportiert Kopf-Morphs als TRI-Datei." #: res/xrc/OutfitStudio.xrc:1737 msgid "Export Data" msgstr "Daten exportieren" #: res/xrc/OutfitStudio.xrc:1739 msgid "Export BSClothExtraData As HKX" msgstr "BSClothExtraData als HKX exportieren" #: res/xrc/OutfitStudio.xrc:1740 msgid "" "Save one of the currently loaded BSClothExtraData blocks to an HKX file." msgstr "" "Speichert einen der aktuell geladenen BSClothExtraData-Blocks als HKX-Datei." #: res/xrc/OutfitStudio.xrc:1745 msgid "Make Conversion Reference" msgstr "Konvertierungsreferenz erstellen" #: res/xrc/OutfitStudio.xrc:1746 msgid "" "Using the current slider settings for the reference shape, create a new " "reference that will morph from the current shape back to the base shape." msgstr "" "Mithilfe der aktuellen Sliderwerte wird eine neue Referenz erstellt, die " "sich von der aktuellen Form zurück zur Basisform bewegt." #: res/xrc/OutfitStudio.xrc:1750 res/xrc/Project.xrc:967 msgid "Pack Projects..." msgstr "Projekte packen..." #: res/xrc/OutfitStudio.xrc:1751 msgid "Pack one or more projects into a folder or archive for sharing." msgstr "Projekte in einen Ordner oder ein Archiv packen." #: res/xrc/OutfitStudio.xrc:1758 msgid "Exit\tAlt+F4" msgstr "Beenden\tAlt+F4" #: res/xrc/OutfitStudio.xrc:1759 msgid "Exit Outfit Studio." msgstr "Outfit Studio beenden." #: res/xrc/OutfitStudio.xrc:1774 msgid "X Mirror\tX" msgstr "X-Spiegelung\tX" #: res/xrc/OutfitStudio.xrc:1782 msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius" msgstr "" "Bearbeitet nur Vertices, die mit denen verbunden sind, die der Pinselradius " "erreicht" #: res/xrc/OutfitStudio.xrc:1824 msgid "Recalculate Normals" msgstr "Normals neu berechnen" #: res/xrc/OutfitStudio.xrc:1825 msgid "Recalculate normals on active mesh" msgstr "Berechnet die Normals des aktiven Meshes neu" #: res/xrc/OutfitStudio.xrc:1828 msgid "Disable Normals Calculation" msgstr "Normals-Aktualisierung deaktivieren" #: res/xrc/OutfitStudio.xrc:1829 msgid "" "Turn off all automatic recalculation of normals on all meshes. Only applies " "to Outfit Studio." msgstr "" #: res/xrc/OutfitStudio.xrc:1834 msgid "Reset Transforms" msgstr "Transforms zurücksetzen" #: res/xrc/OutfitStudio.xrc:1835 msgid "Resets the shape and skin transforms." msgstr "Setzt Modell- und Skinning-Transforms zurück." #: res/xrc/OutfitStudio.xrc:1838 src/program/OutfitStudio.cpp:10876 msgid "Delete Unreferenced Nodes" msgstr "Unreferenzierte Nodes entfernen" #: res/xrc/OutfitStudio.xrc:1839 msgid "Deletes all nodes from the project that aren't used in any other block." msgstr "" "Entfernt alle Nodes des Projekts, die nicht in keinem anderen Block " "verwendet werden." #: res/xrc/OutfitStudio.xrc:1842 msgid "Remove Skinning" msgstr "Skinning entfernen" #: res/xrc/OutfitStudio.xrc:1843 msgid "Removes skinning of all shapes and all unused nodes." msgstr "Skinning aller Modelle und unverwendete Nodes entfernen." #: res/xrc/OutfitStudio.xrc:1847 res/xrc/OutfitStudio.xrc:2327 msgid "Shape" msgstr "Modell" #: res/xrc/OutfitStudio.xrc:1851 res/xrc/OutfitStudio.xrc:2331 msgid "To NIF..." msgstr "Als NIF..." #: res/xrc/OutfitStudio.xrc:1852 res/xrc/OutfitStudio.xrc:2332 msgid "Export only the selected shapes to a NIF file." msgstr "Exportiert nur die ausgewählten Modelle als NIF-Datei." #: res/xrc/OutfitStudio.xrc:1856 res/xrc/OutfitStudio.xrc:2336 msgid "Export only the selected shapes to an OBJ file." msgstr "Exportiert nur die ausgewählten Modelle als OBJ-Datei." #: res/xrc/OutfitStudio.xrc:1860 res/xrc/OutfitStudio.xrc:2340 msgid "Export only the selected shapes to an FBX file." msgstr "Exportiert nur die ausgewählten Modelle als FBX-Datei." #: res/xrc/OutfitStudio.xrc:1868 res/xrc/OutfitStudio.xrc:2348 #: res/xrc/Slider.xrc:200 msgid "UV" msgstr "UV" #: res/xrc/OutfitStudio.xrc:1870 res/xrc/OutfitStudio.xrc:2350 msgid "Edit..." msgstr "Bearbeiten..." #: res/xrc/OutfitStudio.xrc:1871 res/xrc/OutfitStudio.xrc:2351 msgid "Edit the texture coordinates." msgstr "Bearbeitung der Texturkoordinaten." #: res/xrc/OutfitStudio.xrc:1874 res/xrc/OutfitStudio.xrc:2354 msgid "Invert X" msgstr "X umkehren" #: res/xrc/OutfitStudio.xrc:1875 res/xrc/OutfitStudio.xrc:2355 msgid "Inverts the X-axis of the texture coordinates." msgstr "Kehrt die X-Achse der Texturkoordinaten um." #: res/xrc/OutfitStudio.xrc:1878 res/xrc/OutfitStudio.xrc:2358 msgid "Invert Y" msgstr "Y umkehren" #: res/xrc/OutfitStudio.xrc:1879 res/xrc/OutfitStudio.xrc:2359 msgid "Inverts the Y-axis of the texture coordinates." msgstr "Kehrt die Y-Achse der Texturkoordinaten um." #: res/xrc/OutfitStudio.xrc:1883 res/xrc/OutfitStudio.xrc:2363 msgid "Delete Vertices...\tShift+Del" msgstr "Vertices löschen...\tShift+Del" #: res/xrc/OutfitStudio.xrc:1884 res/xrc/OutfitStudio.xrc:2364 msgid "Deletes all unmasked vertices of the currently selected shapes." msgstr "" "Löscht alle nicht maskierten Vertices des aktuell ausgewählten Modells." #: res/xrc/OutfitStudio.xrc:1887 res/xrc/OutfitStudio.xrc:2367 msgid "Separate Vertices...\tShift+S" msgstr "Vertices aufteilen...\tShift+S" #: res/xrc/OutfitStudio.xrc:1888 res/xrc/OutfitStudio.xrc:2368 msgid "Separate the current shape into two by using the mask." msgstr "Teilt das ausgewählte Modell mithilfe der Maske in zwei auf." #: res/xrc/OutfitStudio.xrc:1891 res/xrc/OutfitStudio.xrc:2371 msgid "Mirror Shape..." msgstr "Modell spiegeln..." #: res/xrc/OutfitStudio.xrc:1892 res/xrc/OutfitStudio.xrc:2372 msgid "Mirror the selected shapes on any axis." msgstr "Spiegelt die ausgewählten Modelle auf einer Achse." #: res/xrc/OutfitStudio.xrc:1895 res/xrc/OutfitStudio.xrc:2375 msgid "Merge Geometry..." msgstr "Geometrie zusammenführen..." #: res/xrc/OutfitStudio.xrc:1896 res/xrc/OutfitStudio.xrc:2376 msgid "Copies vertices and triangles from one shape to another." msgstr "Vertices und Triangles von einem Modell zum anderen kopieren." #: res/xrc/OutfitStudio.xrc:1899 res/xrc/OutfitStudio.xrc:2379 msgid "Duplicate..." msgstr "Duplizieren..." #: res/xrc/OutfitStudio.xrc:1900 res/xrc/OutfitStudio.xrc:2380 msgid "Duplicate the current shape." msgstr "Dupliziert das aktuelle Modell." #: res/xrc/OutfitStudio.xrc:1903 res/xrc/OutfitStudio.xrc:2383 msgid "Refine Mesh" msgstr "Modell verfeinern" #: res/xrc/OutfitStudio.xrc:1904 res/xrc/OutfitStudio.xrc:2384 msgid "Splits all edges between unmasked vertices" msgstr "Teilt alle Kanten zwischen den unmaskierten Vertices" #: res/xrc/OutfitStudio.xrc:1907 res/xrc/OutfitStudio.xrc:2387 msgid "Rename...\tF2" msgstr "Umbenennen...\tF2" #: res/xrc/OutfitStudio.xrc:1908 res/xrc/OutfitStudio.xrc:2388 msgid "Change the name of the current shape." msgstr "Ändert den Namen des aktuellen Modells." #: res/xrc/OutfitStudio.xrc:1911 res/xrc/OutfitStudio.xrc:2391 msgid "Set Reference" msgstr "Referenz setzen" #: res/xrc/OutfitStudio.xrc:1912 res/xrc/OutfitStudio.xrc:2392 msgid "Turn the shape into the reference shape of the project." msgstr "Wandelt das Modell in ein Referenzmodell des Projekts um." #: res/xrc/OutfitStudio.xrc:1916 res/xrc/OutfitStudio.xrc:2396 msgid "Move..." msgstr "Verschieben..." #: res/xrc/OutfitStudio.xrc:1917 res/xrc/OutfitStudio.xrc:2397 msgid "" "Apply an offset adjustment to the mesh vertices. This permanently moves " "vertices." msgstr "Verschiebt die Vertices des Modells permanent." #: res/xrc/OutfitStudio.xrc:1920 res/xrc/OutfitStudio.xrc:2400 msgid "Scale..." msgstr "Skalieren..." #: res/xrc/OutfitStudio.xrc:1921 res/xrc/OutfitStudio.xrc:2401 msgid "Apply a scale adjustment to the shape. This permanently moves vertices." msgstr "Skaliert die Vertices des Modells permanent." #: res/xrc/OutfitStudio.xrc:1924 res/xrc/OutfitStudio.xrc:2404 msgid "Rotate..." msgstr "Rotieren..." #: res/xrc/OutfitStudio.xrc:1925 res/xrc/OutfitStudio.xrc:2405 msgid "Apply a rotation to the mesh vertices. This permanently moves vertices." msgstr "Rotiert die Vertices des Modells permanent." #: res/xrc/OutfitStudio.xrc:1928 res/xrc/OutfitStudio.xrc:2408 msgid "Inflate..." msgstr "Aufblasen..." #: res/xrc/OutfitStudio.xrc:1929 res/xrc/OutfitStudio.xrc:2409 msgid "" "Inflates/deflates a shape along its normals. This permanently moves vertices." msgstr "" "Aufblasen vergrößert ein Modell entlang dessen Normals. Dies beeinflusst " "Vertices permanent." #: res/xrc/OutfitStudio.xrc:1933 msgid "Normals" msgstr "Normals" #: res/xrc/OutfitStudio.xrc:1935 msgid "Smooth Seam Normals" msgstr "Rand-Normals glätten" #: res/xrc/OutfitStudio.xrc:1936 msgid "" "Smooths edges of seams (usually found at texture borders), disable if this " "causes odd normals on the shape." msgstr "" "Glättet Kanten von Rändern (normalerweise bei Texturgrenzen). Deaktivieren " "bei seltsamen Normals." #: res/xrc/OutfitStudio.xrc:1941 msgid "Edit Smoothing Angle..." msgstr "Winkel für Glättung bearbeiten..." #: res/xrc/OutfitStudio.xrc:1942 msgid "" "Angle, in degrees, that controls the threshold at which normal seams are " "smoothed." msgstr "" #: res/xrc/OutfitStudio.xrc:1945 msgid "Lock Normals" msgstr "Normals sperren" #: res/xrc/OutfitStudio.xrc:1946 msgid "" "Locks the mesh normals. Enable if you want to keep custom normals intact." msgstr "" "Sperrt die Normals des Modells. Aktivieren, wenn manuell angepasste Normals " "intakt bleiben sollen." #: res/xrc/OutfitStudio.xrc:1954 res/xrc/OutfitStudio.xrc:2414 msgid "Copies all bone weights from the reference shape to the current shape." msgstr "" "Kopiert das Bone Weighting des Referenzmodells auf das aktuelle Modell." #: res/xrc/OutfitStudio.xrc:1957 res/xrc/OutfitStudio.xrc:2417 msgid "Copy Selected Weights" msgstr "Ausgewähltes Weighting kopieren" #: res/xrc/OutfitStudio.xrc:1958 res/xrc/OutfitStudio.xrc:2418 msgid "" "Copies selected bone weights from the reference shape to the current shape." msgstr "" "Kopiert das ausgewählte Weighting vom Referenzmodell auf das aktuelle Modell." #: res/xrc/OutfitStudio.xrc:1961 res/xrc/OutfitStudio.xrc:2421 msgid "Transfer Selected Weights" msgstr "Ausgewähltes Weighting transferieren" #: res/xrc/OutfitStudio.xrc:1962 res/xrc/OutfitStudio.xrc:2422 msgid "" "Transfers selected weights from the reference shape to the current shape. " "Requires same vertex count and order." msgstr "" "Transferiert das ausgewählte Weighting vom Referenzmodell auf das aktuelle " "Modell. Benötigt die selbe Anzahl und Reihenfolge an Vertices." #: res/xrc/OutfitStudio.xrc:1965 res/xrc/OutfitStudio.xrc:2425 #: res/xrc/OutfitStudio.xrc:2500 msgid "Mask Weighted Vertices" msgstr "Gewichtete Vertices maskieren" #: res/xrc/OutfitStudio.xrc:1966 res/xrc/OutfitStudio.xrc:2426 msgid "" "Masks vertices with bone weights, so you can manually assign weights to " "unweighted vertices." msgstr "Maskiert Vertices mit Bone Weighting." #: res/xrc/OutfitStudio.xrc:1969 msgid "Check For Bad Bones..." msgstr "Auf mangelhafte Bones prüfen..." #: res/xrc/OutfitStudio.xrc:1970 res/xrc/OutfitStudio.xrc:2430 msgid "" "Looks for bones with inconsistencies in their transforms. If any are found, " "a dialog is opened to give options for fixing them." msgstr "" #: res/xrc/OutfitStudio.xrc:1974 res/xrc/OutfitStudio.xrc:2434 msgid "Copy Partitions/Segments..." msgstr "Partitionen/Segmente kopieren..." #: res/xrc/OutfitStudio.xrc:1975 res/xrc/OutfitStudio.xrc:2435 msgid "" "Copies partitions/segments and all triangle assignments from the reference " "shape to the current shape." msgstr "" "Kopiert Partitionen/Segmente und deren Triangle-Zuweisungen vom " "Referenzmodell zum ausgewählten Modell." #: res/xrc/OutfitStudio.xrc:1979 res/xrc/OutfitStudio.xrc:2439 msgid "Mask Symmetric Vertices..." msgstr "Symmetrische Vertices maskieren..." #: res/xrc/OutfitStudio.xrc:1980 res/xrc/OutfitStudio.xrc:2440 msgid "" "Masks unmasked vertices that have a mirrored vertex with identical data." msgstr "" #: res/xrc/OutfitStudio.xrc:1983 res/xrc/OutfitStudio.xrc:2443 msgid "Symmetrize Vertices..." msgstr "Vertices symmetrisieren..." #: res/xrc/OutfitStudio.xrc:1984 res/xrc/OutfitStudio.xrc:2444 msgid "Changes vertex data to be identical to mirrored vertices." msgstr "" #: res/xrc/OutfitStudio.xrc:1987 res/xrc/OutfitStudio.xrc:2447 msgid "Mask Symmetric Triangles" msgstr "Symmetrische Triangles maskieren" #: res/xrc/OutfitStudio.xrc:1988 res/xrc/OutfitStudio.xrc:2448 msgid "Masks triangles that can be matched to a mirrored triangle." msgstr "" #: res/xrc/OutfitStudio.xrc:1992 res/xrc/OutfitStudio.xrc:2452 msgid "Delete\tDel" msgstr "Entfernen\tDel" #: res/xrc/OutfitStudio.xrc:1993 res/xrc/OutfitStudio.xrc:2453 msgid "Removes the currently selected shape from the outfit." msgstr "Entfernt das derzeit ausgewählte Modell aus dem Outfit." #: res/xrc/OutfitStudio.xrc:1996 res/xrc/OutfitStudio.xrc:2456 msgid "Properties..." msgstr "Eigenschaften..." #: res/xrc/OutfitStudio.xrc:1997 res/xrc/OutfitStudio.xrc:2457 msgid "" "Opens the properties dialog for shader, texture and more settings of the " "selected shape." msgstr "" "Öffnet das Eigenschaftenfenster für Shader, Texturen und mehr des aktuellen " "Modells." #: res/xrc/OutfitStudio.xrc:2001 msgid "Slider" msgstr "Slider" #: res/xrc/OutfitStudio.xrc:2003 msgid "Conform Selected\tCtrl+C" msgstr "Ausgewählte übertragen\tCtrl+C" #: res/xrc/OutfitStudio.xrc:2004 msgid "Conform selected outfit shape to all checked sliders." msgstr "Überträgt alle angehakten Slider auf die ausgewählten Modelle." #: res/xrc/OutfitStudio.xrc:2007 msgid "Conform All\tCtrl+Shift+C" msgstr "Alle übertragen\tCtrl+Shift+C" #: res/xrc/OutfitStudio.xrc:2008 msgid "Conform all outfit shapes to all checked sliders." msgstr "Überträgt alle angehakten Slider auf alle Modelle." #: res/xrc/OutfitStudio.xrc:2012 msgid "Set Base Shape" msgstr "Grundform setzen" #: res/xrc/OutfitStudio.xrc:2013 msgid "Set the current outfit shape as the base shape and clear slider data." msgstr "" "Setzt die aktuelle Form der Outfitmodelle als Grundform und löscht " "Sliderdaten." #: res/xrc/OutfitStudio.xrc:2018 msgid "" "Load and preview a slider preset. Inverted sliders will have inverted values." msgstr "" "Läd ein Preset zur Vorschau. Umgekehrte Slider bekommen umgekehrte Werte." #: res/xrc/OutfitStudio.xrc:2022 msgid "" "Save a slider preset with the current values. Inverted sliders will have " "inverted values." msgstr "" "Speichert ein Preset mit den aktuellen Werten. Umgekehrte Slider bekommen " "umgekehrte Werte." #: res/xrc/OutfitStudio.xrc:2026 msgid "New Slider" msgstr "Neuer Slider" #: res/xrc/OutfitStudio.xrc:2027 msgid "Create a new shape transformation slider." msgstr "Erstellt einen neuen Slider zum Transformieren von Modellen." #: res/xrc/OutfitStudio.xrc:2030 msgid "Coalesce sliders" msgstr "Slider zusammenfügen" #: res/xrc/OutfitStudio.xrc:2031 msgid "" "Create a new shape transformation slider based on the current slider values" msgstr "" "Erstellt einen neuen Slider, der auf den aktuellen Sliderwerten basiert" #: res/xrc/OutfitStudio.xrc:2034 msgid "New Zap Slider" msgstr "Neuer Zap Slider" #: res/xrc/OutfitStudio.xrc:2035 msgid "Create a new Zap slider based on unmasked vertices" msgstr "" "Erstellt einen neuen Zap Slider, der auf allen nicht maskierten Vertices " "basiert" #: res/xrc/OutfitStudio.xrc:2039 msgid "Import OSD..." msgstr "OSD importieren..." #: res/xrc/OutfitStudio.xrc:2040 msgid "Imports OSD file and creates sliders for shapes with a matching name." msgstr "" "Importiert eine OSD-Datei und erstellt daraus Slider für Modelle mit " "passendem Namen." #: res/xrc/OutfitStudio.xrc:2043 msgid "Export OSD..." msgstr "OSD exportieren..." #: res/xrc/OutfitStudio.xrc:2044 msgid "Exports all currently loaded slider data to an OSD file." msgstr "Exportiert alle derzeit geladenen Sliderdaten in eine OSD-Datei." #: res/xrc/OutfitStudio.xrc:2047 msgid "Import TRI Morphs..." msgstr "TRI-Morphs importieren..." #: res/xrc/OutfitStudio.xrc:2048 msgid "" "Imports TRI morphs from a TRI file and creates sliders for shapes with a " "matching name." msgstr "" "Importiert TRI-Morphs aus einer TRI-Datei und erstellt daraus Slider für " "Modelle mit passendem Namen." #: res/xrc/OutfitStudio.xrc:2051 msgid "Export TRI Morphs..." msgstr "TRI-Morphs exportieren..." #: res/xrc/OutfitStudio.xrc:2052 msgid "Exports TRI morphs to a TRI file." msgstr "Exportiert TRI-Morphs in eine TRI-Datei." #: res/xrc/OutfitStudio.xrc:2055 msgid "Import Starfield morphs..." msgstr "Starfield-Morphs importieren..." #: res/xrc/OutfitStudio.xrc:2056 msgid "" "Imports Starfield morph.dat file and creates sliders for shapes with a " "matching name." msgstr "" "Importiert eine Starfield morph.dat-Datei und erstellt daraus Slider für " "Modelle mit passendem Namen." #: res/xrc/OutfitStudio.xrc:2059 msgid "Export to OBJs..." msgstr "OBJs exportieren..." #: res/xrc/OutfitStudio.xrc:2060 msgid "Export all sliders to an OBJ file per slider." msgstr "Exportiert alle Slider als eine OBJ-Datei je Slider." #: res/xrc/OutfitStudio.xrc:2064 msgid "Import Slider Data" msgstr "Sliderdaten importieren" #: res/xrc/OutfitStudio.xrc:2066 msgid "Import NIF..." msgstr "NIF importieren..." #: res/xrc/OutfitStudio.xrc:2067 msgid "Import a NIF file and overwrites the current shape's slider data." msgstr "" "Importiert eine BodySlide NIF-Datei und überschreibt die Sliderdaten des " "aktuellen Modells." #: res/xrc/OutfitStudio.xrc:2070 msgid "Import BSD..." msgstr "BSD importieren..." #: res/xrc/OutfitStudio.xrc:2071 msgid "" "Import a BodySlide BSD file and overwrites the current shape's slider data." msgstr "" "Importiert eine BodySlide BSD-Datei und überschreibt die Sliderdaten des " "aktuellen Modells." #: res/xrc/OutfitStudio.xrc:2074 msgid "Import OBJ..." msgstr "OBJ importieren..." #: res/xrc/OutfitStudio.xrc:2075 msgid "" "Import an OBJ file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "" "Importiert eine OBJ-Datei, die mit der Vertex Anzahl des aktuellen Modells " "übereinstimmt, und berechnet Sliderdaten aus der Differenz." #: res/xrc/OutfitStudio.xrc:2078 msgid "Import FBX..." msgstr "FBX importieren..." #: res/xrc/OutfitStudio.xrc:2079 msgid "" "Import an FBX file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "" "Importiert eine FBX-Datei, die mit der Vertex Anzahl des aktuellen Modells " "übereinstimmt, und berechnet Sliderdaten aus der Differenz." #: res/xrc/OutfitStudio.xrc:2084 msgid "Export Slider Data" msgstr "Sliderdaten exportieren" #: res/xrc/OutfitStudio.xrc:2086 msgid "Export NIF..." msgstr "NIF exportieren..." #: res/xrc/OutfitStudio.xrc:2087 msgid "Exports the current slider's data as a NIF file." msgstr "Exportiert die Daten des aktuellen Sliders als BodySlide NIF-Datei." #: res/xrc/OutfitStudio.xrc:2090 msgid "Export BSD..." msgstr "BSD exportieren..." #: res/xrc/OutfitStudio.xrc:2091 msgid "Exports the current slider's data as a BodySlide BSD file." msgstr "Exportiert die Daten des aktuellen Sliders als BodySlide BSD-Datei." #: res/xrc/OutfitStudio.xrc:2094 msgid "Export OBJ..." msgstr "OBJ exportieren..." #: res/xrc/OutfitStudio.xrc:2095 msgid "Exports the current slider's data as an OBJ file." msgstr "Exportiert die Daten des aktuellen Sliders als BodySlide OBJ-Datei." #: res/xrc/OutfitStudio.xrc:2101 src/program/OutfitStudio.cpp:8013 msgid "Clone Slider" msgstr "Slider duplizieren" #: res/xrc/OutfitStudio.xrc:2102 msgid "Clones the current slider." msgstr "Dupliziert den aktuellen Slider." #: res/xrc/OutfitStudio.xrc:2106 msgid "Negate Slider" msgstr "Slider negieren" #: res/xrc/OutfitStudio.xrc:2107 msgid "Negates the current slider, reversing it's effect" msgstr "Negiert den aktuellen Slider zum Umkehren seines Effektes" #: res/xrc/OutfitStudio.xrc:2111 msgid "Mask Affected Vertices" msgstr "Beeinflusste Vertices maskieren" #: res/xrc/OutfitStudio.xrc:2112 msgid "Masks the vertices the slider is affecting for all selected shapes." msgstr "" "Maskiert die Vertices aller ausgewählten Modelle, welche der Slider " "beeinflusst." #: res/xrc/OutfitStudio.xrc:2116 msgid "Clear Slider Data" msgstr "Sliderdaten löschen" #: res/xrc/OutfitStudio.xrc:2117 msgid "" "Erases the slider data without removing the slider itself. (Cannot be undone)" msgstr "" "Löscht die Sliderdaten, ohne den Slider selbst zu entfernen. (Kann nicht " "rückgängig gemacht werden)" #: res/xrc/OutfitStudio.xrc:2120 msgid "Delete Slider\tCtrl+Del" msgstr "Slider entfernen\tCtrl+Del" #: res/xrc/OutfitStudio.xrc:2121 msgid "Delete the active slider from the project. (Cannot be undone)" msgstr "" "Entfernt den aktiven Slider aus dem Projekt. (Kann nicht rückgängig gemacht " "werden)" #: res/xrc/OutfitStudio.xrc:2125 msgid "Properties...\tTab" msgstr "Eigenschaften...\tTab" #: res/xrc/OutfitStudio.xrc:2126 src/ui/wxSliderPanel.cpp:69 msgid "Display and edit the active slider's properties." msgstr "Zeigt die Eigenschaften des aktiven Sliders zur Bearbeitung an." #: res/xrc/OutfitStudio.xrc:2131 msgid "Tool" msgstr "Werkzeug" #: res/xrc/OutfitStudio.xrc:2133 msgid "Current Tool" msgstr "Aktuelles Werkzeug" #: res/xrc/OutfitStudio.xrc:2172 msgid "" "Apply animation weight values for the currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "Wendet Animations-Weighting für den derzeit gewählten Bone an.\n" "ALT gedrückt halten, um das Weighting abzuschwächen." #: res/xrc/OutfitStudio.xrc:2210 msgid "Transform\tF" msgstr "Transformieren\tF" #: res/xrc/OutfitStudio.xrc:2215 msgid "Pivot\tP" msgstr "Pivot\tP" #: res/xrc/OutfitStudio.xrc:2220 msgid "Vertex Edit\tQ" msgstr "Vertex Bearbeitung\tQ" #: res/xrc/OutfitStudio.xrc:2221 msgid "" "Shows vertex points and lets you mask/unmask them.\n" "Without any brush active, click on a vertex to unmask it.\n" "Hold down CTRL to mask it." msgstr "" "Zeigt Vertexpunkte und ermöglicht es, diese zur Maske hinzuzufügen oder zu " "entfernen.\n" "Ohne einen aktiven Pinsel auf einen Vertex klicken, um ihn zu demaskieren.\n" "STRG gedrückt halten, um ihn zu maskieren." #: res/xrc/OutfitStudio.xrc:2226 msgid "Increase Brush Size\tShift++" msgstr "Pinselgröße erhöhen\tShift++" #: res/xrc/OutfitStudio.xrc:2227 msgid "Increase brush diameter" msgstr "Erhöht den Durchmesser des Pinsels" #: res/xrc/OutfitStudio.xrc:2230 msgid "Decrease Brush Size\tShift+-" msgstr "Pinselgröße verringern\tShift+-" #: res/xrc/OutfitStudio.xrc:2231 msgid "Decrease brush diameter" msgstr "Verringert den Durchmesser des Pinsels" #: res/xrc/OutfitStudio.xrc:2234 msgid "Increase Brush Strength\tCtrl++" msgstr "Pinselstärke erhöhen\tCtrl++" #: res/xrc/OutfitStudio.xrc:2235 msgid "Increase brush strength" msgstr "Erhöht die Stärke des Pinsels" #: res/xrc/OutfitStudio.xrc:2238 msgid "Decrease Brush Strength\tCtrl+-" msgstr "Pinselstärke verringern\tCtrl+-" #: res/xrc/OutfitStudio.xrc:2239 msgid "Decrease brush strength" msgstr "Verringert die Stärke des Pinsels" #: res/xrc/OutfitStudio.xrc:2243 msgid "Mask Less\tA" msgstr "Weniger maskieren\tA" #: res/xrc/OutfitStudio.xrc:2244 msgid "Mask Less" msgstr "Weniger maskieren" #: res/xrc/OutfitStudio.xrc:2247 msgid "Mask More\tD" msgstr "Mehr maskieren\tD" #: res/xrc/OutfitStudio.xrc:2248 msgid "Mask More" msgstr "Mehr maskieren" #: res/xrc/OutfitStudio.xrc:2252 msgid "Invert Mask\tCtrl+I" msgstr "Maske umkehren\tCtrl+I" #: res/xrc/OutfitStudio.xrc:2253 msgid "Invert Mask" msgstr "Maske umkehren" #: res/xrc/OutfitStudio.xrc:2256 msgid "Clear Mask\tCtrl+A" msgstr "Maske löschen\tCtrl+A" #: res/xrc/OutfitStudio.xrc:2257 msgid "Clear Mask" msgstr "Maske entfernen" #: res/xrc/OutfitStudio.xrc:2261 msgid "View" msgstr "Ansicht" #: res/xrc/OutfitStudio.xrc:2263 msgid "Front\tShift+1" msgstr "Vorne\tShift+1" #: res/xrc/OutfitStudio.xrc:2266 msgid "Back\tShift+2" msgstr "Hinten\tShift+2" #: res/xrc/OutfitStudio.xrc:2269 msgid "Left\tShift+3" msgstr "Links\tShift+3" #: res/xrc/OutfitStudio.xrc:2272 msgid "Right\tShift+4" msgstr "Rechts\tShift+4" #: res/xrc/OutfitStudio.xrc:2275 msgid "Perspective\tShift+5" msgstr "Perspektive\tShift+5" #: res/xrc/OutfitStudio.xrc:2280 msgid "Toggle Rotation Center\tShift+R" msgstr "Rotationszentrum umschalten\tShift+R" #: res/xrc/OutfitStudio.xrc:2281 msgid "Switch between the different rotation center modes." msgstr "Schaltet zwischen den verschiedenen Rotationszentrum-Modi um." #: res/xrc/OutfitStudio.xrc:2284 msgid "Show Nodes\tShift+N" msgstr "Knoten anzeigen\tShift+N" #: res/xrc/OutfitStudio.xrc:2288 msgid "Show Bones\tShift+B" msgstr "Bones anzeigen\tShift+B" #: res/xrc/OutfitStudio.xrc:2292 msgid "Show Floor\tG" msgstr "Boden anzeigen\tG" #: res/xrc/OutfitStudio.xrc:2297 msgid "Toggle Visibility\tE" msgstr "Sichtbarkeit umschalten\tE" #: res/xrc/OutfitStudio.xrc:2298 msgid "Switch between the different visibility modes for the selected shapes." msgstr "" "Schaltet für die ausgewählten Modelle zwischen den verschiedenen " "Sichtbarkeitsmodi um." #: res/xrc/OutfitStudio.xrc:2301 msgid "Show Wireframe\tW" msgstr "Gitternetz anzeigen\tW" #: res/xrc/OutfitStudio.xrc:2302 msgid "Show wireframe on all models." msgstr "Gitternetz auf allen Modellen anzeigen." #: res/xrc/OutfitStudio.xrc:2306 msgid "Enable Lighting\tL" msgstr "Beleuchtung aktivieren\tL" #: res/xrc/OutfitStudio.xrc:2307 msgid "Turn on or off lighting." msgstr "Schaltet die Beleuchtung an oder aus." #: res/xrc/OutfitStudio.xrc:2312 msgid "Enable Textures\tT" msgstr "Texturen aktivieren\tT" #: res/xrc/OutfitStudio.xrc:2313 msgid "Display texture maps on models." msgstr "Zeigt Texturen der Modelle an." #: res/xrc/OutfitStudio.xrc:2318 msgid "Enable Vertex Colors" msgstr "Vertex-Farben aktivieren" #: res/xrc/OutfitStudio.xrc:2319 msgid "Display vertex colors on models." msgstr "Zeigt Vertex-Farben der Modelle an." #: res/xrc/OutfitStudio.xrc:2429 msgid "Check For Bad Bones" msgstr "Auf mangelhafte Bones prüfen" #: res/xrc/OutfitStudio.xrc:2463 msgid "Bad Bone" msgstr "Mangelhafter Bone" #: res/xrc/OutfitStudio.xrc:2465 msgid "Set Skin Transform From Node" msgstr "Skin-Transformation aus Node setzen" #: res/xrc/OutfitStudio.xrc:2466 msgid "Fixes the bad bone by calculating a new skin-to-bone transform." msgstr "" "Korrigiert den mangelhaften Bone durch Berechnen einer neuen Skin-to-Bone " "Transformation." #: res/xrc/OutfitStudio.xrc:2469 msgid "Set Node Transform From Skin" msgstr "Node-Transformation aus Skin setzen" #: res/xrc/OutfitStudio.xrc:2470 msgid "" "Fixes the bad custom bone by calculating a new bone-to-global transform." msgstr "" #: res/xrc/OutfitStudio.xrc:2474 res/xrc/OutfitStudio.xrc:2507 #: res/xrc/ShapeProperties.xrc:280 res/xrc/ShapeProperties.xrc:438 #: res/xrc/ShapeProperties.xrc:611 msgid "Add" msgstr "Hinzufügen" #: res/xrc/OutfitStudio.xrc:2476 res/xrc/OutfitStudio.xrc:2509 msgid "From Skeleton..." msgstr "Aus Skelett..." #: res/xrc/OutfitStudio.xrc:2477 res/xrc/OutfitStudio.xrc:2510 msgid "Choose a bone from the reference skeleton to add to the project." msgstr "" "Wählen Sie einen Bone aus dem Referenzskelett, um ihn dem Projekt " "hinzuzufügen." #: res/xrc/OutfitStudio.xrc:2480 res/xrc/OutfitStudio.xrc:2513 msgid "Custom Bone..." msgstr "Benutzerdefinierter Bone..." #: res/xrc/OutfitStudio.xrc:2481 res/xrc/OutfitStudio.xrc:2514 msgid "Add a custom bone to the project." msgstr "Fügt einen benutzerdefinierten Bone dem Projekt hinzu." #: res/xrc/OutfitStudio.xrc:2487 msgid "From Project" msgstr "Aus Projekt" #: res/xrc/OutfitStudio.xrc:2488 msgid "Delete bone(s) from all shapes of the project." msgstr "Bone(s) von allen Modellen des Projektes entfernen." #: res/xrc/OutfitStudio.xrc:2491 msgid "From Selected Shapes" msgstr "Von ausgewählten Modellen" #: res/xrc/OutfitStudio.xrc:2492 msgid "Delete bone(s) from only the selected shapes." msgstr "Bone(s) nur von ausgewählten Modellen entfernen." #: res/xrc/OutfitStudio.xrc:2496 msgid "Edit Bone..." msgstr "Bone bearbeiten..." #: res/xrc/OutfitStudio.xrc:2497 msgid "Edit a custom bone or view a standard bone." msgstr "Bone bearbeiten oder Standard-Bone anzeigen." #: res/xrc/OutfitStudio.xrc:2501 msgid "Masks vertices with weights for the selected bones." msgstr "Maskiert die Vertices mit Weights für die ausgewählten Bones." #: res/xrc/OutfitStudio.xrc:2521 res/xrc/OutfitStudio.xrc:2547 msgid "Add Segment..." msgstr "Segment hinzufügen..." #: res/xrc/OutfitStudio.xrc:2522 res/xrc/OutfitStudio.xrc:2548 msgid "Choose a segment to add to the shape." msgstr "Segment zum Hinzufügen wählen." #: res/xrc/OutfitStudio.xrc:2525 res/xrc/OutfitStudio.xrc:2536 msgid "Add Sub Segment..." msgstr "Untersegment hinzufügen..." #: res/xrc/OutfitStudio.xrc:2526 res/xrc/OutfitStudio.xrc:2537 msgid "Add a new sub segment to the currently selected segment." msgstr "Neues Untersegment am aktuell ausgewählten Segment hinzufügen." #: res/xrc/OutfitStudio.xrc:2529 msgid "Delete Segment..." msgstr "Segment löschen..." #: res/xrc/OutfitStudio.xrc:2530 msgid "Delete segment and all of its sub segments from the shape." msgstr "Entfernt das Segment und all seine Untersegmente vom Modell." #: res/xrc/OutfitStudio.xrc:2534 msgid "Sub Segments" msgstr "Untersegmente" #: res/xrc/OutfitStudio.xrc:2540 msgid "Delete Sub Segment..." msgstr "Untersegment löschen..." #: res/xrc/OutfitStudio.xrc:2541 msgid "Delete the selected sub segment." msgstr "Ausgewähltes Untersegment löschen." #: res/xrc/OutfitStudio.xrc:2554 res/xrc/OutfitStudio.xrc:2565 msgid "Add Partition..." msgstr "Partition hinzufügen..." #: res/xrc/OutfitStudio.xrc:2555 res/xrc/OutfitStudio.xrc:2566 msgid "Adds a new partition to the shape." msgstr "Fügt dem Modell eine neue Partition hinzu." #: res/xrc/OutfitStudio.xrc:2558 msgid "Delete Partition..." msgstr "Partition entfernen..." #: res/xrc/OutfitStudio.xrc:2559 msgid "Deletes the partition from the shape." msgstr "Entfernt die Partition vom Modell." #: res/xrc/Project.xrc:16 msgid "" "Welcome to the New Project wizard!\n" "\n" "First, please choose a reference. Typically, this is a body (such as CBBE) " "or a conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "Willkommen zum Assistenten für ein neues Projekt!\n" "\n" "Zuerst, wählen Sie bitte eine Referenz. Normalerweise ist dies ein Körper " "(wie z.B. CBBE) oder ein Konvertierungsset (wie z.B. Vanilla zu CBBE) und " "kommt mit seinen eigenen Slidern." #: res/xrc/Project.xrc:32 res/xrc/Project.xrc:598 msgid "Reference" msgstr "Referenz" #: res/xrc/Project.xrc:50 res/xrc/Project.xrc:616 msgid "From Template" msgstr "Aus Vorlage" #: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272 #: res/xrc/Project.xrc:635 res/xrc/Project.xrc:846 res/xrc/Project.xrc:918 msgid "From File" msgstr "Aus Datei" #: res/xrc/Project.xrc:79 res/xrc/Project.xrc:645 msgid "Select a project or NIF file" msgstr "Wählen Sie eine Projekt- oder NIF-Datei" #: res/xrc/Project.xrc:106 res/xrc/Project.xrc:672 msgid "Slider Set:" msgstr "Slider Set:" #: res/xrc/Project.xrc:124 res/xrc/Project.xrc:690 msgid "Shape:" msgstr "Modell:" #: res/xrc/Project.xrc:146 res/xrc/Project.xrc:712 msgid "Clear Reference" msgstr "Referenz entfernen" #: res/xrc/Project.xrc:162 msgid "Next, select an outfit/mesh to work on and enter a display name for it." msgstr "" "Als nächstes, wählen Sie ein Outfit/Modell zum Bearbeiten und geben Sie " "einen Anzeigenamen dafür ein." #: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:813 msgid "Display Name" msgstr "Anzeigename" #: res/xrc/Project.xrc:197 res/xrc/Project.xrc:833 msgid "Outfit/Mesh" msgstr "Outfit/Modell" #: res/xrc/Project.xrc:220 res/xrc/Project.xrc:856 msgid "Select a file to load as an outfit/mesh" msgstr "Wählen Sie eine Datei zum Laden als Outfit/Modell" #: res/xrc/Project.xrc:232 res/xrc/Project.xrc:868 msgid "Clear Outfit" msgstr "Outfit entfernen" #: res/xrc/Project.xrc:250 res/xrc/Project.xrc:896 msgid "Textures" msgstr "Texturen" #: res/xrc/Project.xrc:257 res/xrc/Project.xrc:903 msgid "Automatically search for textures" msgstr "Automatisch nach Texturen suchen" #: res/xrc/Project.xrc:282 res/xrc/Project.xrc:928 msgid "Select a texture file" msgstr "Wählen Sie eine Textur-Datei" #: res/xrc/Project.xrc:297 msgid "Save Project As..." msgstr "Projekte speichern unter..." #: res/xrc/Project.xrc:328 msgid "The name of the outfit and slider set, as it will appear in BodySlide." msgstr "" "Der Name des Outfits und Slidersets, wie er in BodySlide erscheinen wird." #: res/xrc/Project.xrc:337 msgid "Copies the current display name to the project text fields below." msgstr "" "Kopiert den aktuellen Anzeigenamen in alle Projekt Textfelder unterhalb." #: res/xrc/Project.xrc:338 msgid "To Project" msgstr "Zu Projekt" #: res/xrc/Project.xrc:354 msgid "Output File Name" msgstr "Ausgabe Dateiname" #: res/xrc/Project.xrc:363 msgid "" "The name of the outfit file that will end up in the game data path when " "BodySlide builds it. Should not include _1 or _0 in the name, e.g: " "lovelydress" msgstr "" "Der Name der Outfit-Datei, die im Data Ordner des Spiels von BodySlide " "erstellt wird. Sollte nicht _1 oder _0 enthalten, z.B. lovelydress" #: res/xrc/Project.xrc:389 msgid "Output Data Path" msgstr "Ausgabe Dateipfad" #: res/xrc/Project.xrc:398 msgid "" "The location in the game's data path where BodySlide-built outfit files will " "be placed, e.g: meshes\\clothes\\lovelydress" msgstr "" "Der Ordner innerhalb der Spieldaten, in welchem BodySlide die Outfit-Dateien " "erstellen wird, z.B. meshes\\clothes\\lovelydress" #: res/xrc/Project.xrc:410 msgid "" "If this is enabled, BodySlide creates a low and high weight model when it " "generates the final outfit." msgstr "" "Wenn dies aktiviert ist, wird BodySlide Dateien für ein unteres und oberes " "Gewicht erstellen." #: res/xrc/Project.xrc:411 msgid "Low/High Weight Output" msgstr "Unteres/Oberes Gewicht" #: res/xrc/Project.xrc:419 msgid "" "If this is enabled, only one output file will be created (useful for single-" "weighted things like hair)." msgstr "Wenn dies aktiviert ist, wird nur eine einzelne Datei ausgegeben." #: res/xrc/Project.xrc:420 msgid "Single Weight Output" msgstr "Einzelnes Gewicht" #: res/xrc/Project.xrc:431 msgid "Project" msgstr "Projekt" #: res/xrc/Project.xrc:443 msgid "Slider Set File" msgstr "Slider Set Datei" #: res/xrc/Project.xrc:453 msgid "The .osp slider set project file" msgstr "Die .osp Sliderset Projekt-Datei" #: res/xrc/Project.xrc:454 msgid "Select slider set .osp file name" msgstr "Wählen Sie einen Slider Set .osp Dateinamen" #: res/xrc/Project.xrc:472 msgid "Shape Data Folder" msgstr "Shape Data Ordner" #: res/xrc/Project.xrc:482 msgid "" "The folder where all the slider data will go, as well as the base outfit NIF " "file." msgstr "" "Der Ordner, indem alle Sliderdaten und NIF-Dateien des Basisoutfits " "gespeichert werden." #: res/xrc/Project.xrc:483 msgid "Select slider data folder" msgstr "Wählen Sie den Sliderdaten Ordner" #: res/xrc/Project.xrc:500 msgid "Shape Data File" msgstr "Shape Data Datei" #: res/xrc/Project.xrc:510 msgid "The name of the output's base NIF file." msgstr "Der Name der Ausgabe NIF-Datei." #: res/xrc/Project.xrc:511 msgid "Select output NIF file name" msgstr "Wählen Sie einen Ausgabe NIF-Dateinamen" #: res/xrc/Project.xrc:523 msgid "" "Outfits require the reference body to be a part of the output file. Disable " "this if you've already copied the reference over or you don't want it " "included." msgstr "" "Outfits benötigen den Referenzkörper innerhalb der Ausgabedatei. Deaktiviere " "dies, wenn du die Referenz bereits kopiert hast oder sie nicht in der " "Ausgabe benötigst." #: res/xrc/Project.xrc:524 msgid "Copy reference shape into output" msgstr "Referenzmodell in die Ausgabe kopieren" #: res/xrc/Project.xrc:533 msgid "" "Prevents the building of morph .tri files in BodySlide for this project." msgstr "" #: res/xrc/Project.xrc:534 msgid "Prevent morph file building in BodySlide" msgstr "" #: res/xrc/Project.xrc:543 msgid "" "Prevents the removal of fully zapped shapes when building in BodySlide. " "Useful when the shape order and count matters, like for retextures using " "texture sets." msgstr "" #: res/xrc/Project.xrc:544 msgid "Prevent removal of fully zapped shapes in BodySlide" msgstr "" #: res/xrc/Project.xrc:563 res/xrc/SavePreset.xrc:78 msgid "&Save" msgstr "&Speichern" #: res/xrc/Project.xrc:579 msgid "Load Reference" msgstr "Referenz laden" #: res/xrc/Project.xrc:588 msgid "" "Please choose a reference. Typically, this is a body (such as CBBE) or a " "conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "Wählen Sie bitte eine Referenz. Normalerweise ist dies ein Körper (wie z.B. " "CBBE) oder ein Konvertierungsset (wie z.B. Vanilla zu CBBE) und kommt mit " "seinen eigenen Slidern." #: res/xrc/Project.xrc:724 msgid "Merge" msgstr "Zusammenführen" #: res/xrc/Project.xrc:741 msgid "Zaps" msgstr "Zaps" #: res/xrc/Project.xrc:742 msgid "Merge existing zaps with new sliders" msgstr "Existierende Slider mit neuen zusammenführen" #: res/xrc/Project.xrc:752 msgid "Merge new sliders with existing sliders" msgstr "Neue Slider mit existierenden verschmelzen" #: res/xrc/Project.xrc:789 msgid "Load Outfit" msgstr "Outfit laden" #: res/xrc/Project.xrc:798 msgid "" "Please select an outfit/mesh to work on and enter a display name for it." msgstr "" "Wählen Sie ein Outfit/Modell zum Bearbeiten und geben Sie einen Anzeigenamen " "dafür ein." #: res/xrc/Project.xrc:877 msgid "Keep other shapes" msgstr "Andere Modelle behalten" #: res/xrc/Project.xrc:1001 msgid "Group file (optional):" msgstr "Gruppendatei (optional):" #: res/xrc/Project.xrc:1010 msgid "Group file to pack (optional)." msgstr "Gruppendatei zum Packen (optional)." #: res/xrc/Project.xrc:1027 msgid "Merged file name:" msgstr "Zusammengefügte Datei:" #: res/xrc/Project.xrc:1035 msgid "File name to use for the merged project file." msgstr "Dateiname für die zusammengefügte Projektdatei." #: res/xrc/Project.xrc:1061 msgid "Pack Folder..." msgstr "Ordner packen..." #: res/xrc/Project.xrc:1070 msgid "Pack Archive..." msgstr "Archiv packen..." #: res/xrc/Project.xrc:1087 src/program/OutfitStudio.cpp:3846 #: src/program/OutfitStudio.cpp:6531 src/program/OutfitStudio.cpp:7392 #: src/program/OutfitStudio.cpp:7502 src/program/OutfitStudio.cpp:7628 #: src/program/OutfitStudio.cpp:11359 src/program/ShapeProperties.cpp:135 msgid "Cancel" msgstr "Abbrechen" #: res/xrc/SavePreset.xrc:6 msgid "Enter preset name..." msgstr "Preset-Name eingeben..." #: res/xrc/SavePreset.xrc:15 msgid "Please enter a name for the new preset:" msgstr "Bitte geben Sie einen Namen für das neue Preset ein:" #: res/xrc/SavePreset.xrc:38 msgid "Select groups to assign to the new preset:" msgstr "Wählen Sie die erwünschten Gruppen aus:" #: res/xrc/Settings.xrc:15 msgid "Game" msgstr "Spiel" #: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:5226 msgid "Target Game" msgstr "Verwendetes Spiel" #: res/xrc/Settings.xrc:37 msgid "Choose the target game you want to use the program for here." msgstr "" "Wählen Sie das Spiel, für welches Sie dieses Programm verwenden möchten." #: res/xrc/Settings.xrc:67 msgid "Game Data Path" msgstr "Data Ordner" #: res/xrc/Settings.xrc:77 msgid "Select the data path of the game..." msgstr "Wählen Sie den Data Ordner des Spiels aus..." #: res/xrc/Settings.xrc:79 msgid "Data path to load textures from." msgstr "Verzeichnis, aus dem Texturen geladen werden sollen." #: res/xrc/Settings.xrc:91 msgid "Advanced" msgstr "Erweitert" #: res/xrc/Settings.xrc:108 msgid "Output Path" msgstr "Ausgabe Ordner" #: res/xrc/Settings.xrc:118 msgid "Select the output path..." msgstr "Wählen Sie den Ausgabeordner aus..." #: res/xrc/Settings.xrc:120 msgid "" "Data path to build files to. If empty, Game Data Path will be used instead." msgstr "" "Verzeichnis, in dem Ausgabedateien erstellt werden sollen. Falls leer, wird " "stattdessen der Data-Ordner verwendet." #: res/xrc/Settings.xrc:137 msgid "Project Path" msgstr "Projekt-Pfad" #: res/xrc/Settings.xrc:147 msgid "Select the project path..." msgstr "Wählen Sie den Projektordner aus..." #: res/xrc/Settings.xrc:149 msgid "" "Project path where files related to BodySlide are loaded from. If empty, " "executable directory will be used instead." msgstr "" "Projektverzeichnis, aus dem BodySlide-Dateien geladen werden sollen. Falls " "leer, wird stattdessen das Programmverzeichnis verwendet." #: res/xrc/Settings.xrc:165 msgid "" "With this turned on, BodySlide receives a new checkbox \"Force Body " "Normals\". Using it when building adds normal and tangent data to the body " "meshes (including bodies within outfits) for Skyrim. Use this only if you " "have a tangent space body mod." msgstr "" #: res/xrc/Settings.xrc:166 msgid "Show 'Force Body Normals'" msgstr "'Körper Normals erzwingen' anzeigen" #: res/xrc/Settings.xrc:184 msgid "General" msgstr "Allgemein" #: res/xrc/Settings.xrc:196 msgid "" "Enables/disables the dialog for choosing which set to build during a batch " "build if overrides happen." msgstr "" "Aktiviert/Deaktiviert den Auswahldialog der erscheint, wenn es zu " "Überschreibungen in der Batch-Erstellung kommt." #: res/xrc/Settings.xrc:197 msgid "Override Warning" msgstr "Überschreibungswarnung" #: res/xrc/Settings.xrc:206 msgid "" "Enables/disables scanning BSAs in the game data folder for textures to load." msgstr "" "Aktiviert/Deaktiviert das Scannen von BSAs im Data Ordner zum Laden von " "Texturen." #: res/xrc/Settings.xrc:207 msgid "BSA Textures" msgstr "BSA Texturen" #: res/xrc/Settings.xrc:224 msgid "" "Enables/disables panning the camera with the left mouse button in Outfit " "Studio." msgstr "" "Aktiviert/Deaktiviert das Verschieben der Kamera in Outfit Studio mit einem " "Linksklick." #: res/xrc/Settings.xrc:225 msgid "Left Mouse Pan" msgstr "Linksklick zum Verschieben" #: res/xrc/Settings.xrc:234 msgid "" "Enables/disables opening the brush settings near the mouse cursor when " "hitting the 'space' key." msgstr "" "Aktiviert/deaktiviert das Öffnen der Pinseleinstellungen in der Nähe des " "Mauszeigers bei Betätigung der Leertaste." #: res/xrc/Settings.xrc:235 msgid "Brush Settings Near Cursor" msgstr "Pinseleinstellungen bei Mauszeiger" #: res/xrc/Settings.xrc:244 msgid "" "Enables/disables the undo history for the mask brush and vertex selection." msgstr "" #: res/xrc/Settings.xrc:245 msgid "Mask History" msgstr "Maskenverlauf" #: res/xrc/Settings.xrc:263 msgid "Language" msgstr "Sprache" #: res/xrc/Settings.xrc:272 msgid "Use the selected language for the program." msgstr "Verwende die ausgewählte Sprache für das Programm." #: res/xrc/Settings.xrc:287 msgid "Rendering" msgstr "Rendering" #: res/xrc/Settings.xrc:293 msgid "Enables/disables the perspective view in the rendering window." msgstr "" #: res/xrc/Settings.xrc:310 msgid "Background Color" msgstr "Hintergrundfarbe" #: res/xrc/Settings.xrc:319 msgid "Background color of the renderer." msgstr "Hintergrundfarbe des Renderers." #: res/xrc/Settings.xrc:337 msgid "Wireframe Color" msgstr "Wireframe-Farbe" #: res/xrc/Settings.xrc:346 msgid "Wireframe color of the renderer." msgstr "Wireframe-Farbe des Renderers." #: res/xrc/Settings.xrc:361 msgid "Data Files" msgstr "Datendateien" #: res/xrc/Settings.xrc:379 msgid "Reference Skeleton" msgstr "Referenzskelett" #: res/xrc/Settings.xrc:402 msgid "Select a reference skeleton .nif file..." msgstr "Wählen Sie eine .nif-Datei als Referenzskelett aus..." #: res/xrc/Settings.xrc:405 msgid "The reference skeleton file for Outfit Studio." msgstr "Die Referenzskelett-Datei für Outfit Studio." #: res/xrc/Settings.xrc:422 msgid "Root Node" msgstr "Root Knoten" #: res/xrc/Settings.xrc:431 msgid "" "The root node name of the reference skeleton. Can differ from game to game." msgstr "" "Der Name des Root Knotens des Referenzskeletts. Kann von Spiel zu Spiel " "abweichen." #: res/xrc/Setup.xrc:5 msgid "Setup" msgstr "Setup" #: res/xrc/Setup.xrc:15 msgid "" "Please select the data folder and your target game.\n" "You can only choose one game at a time, but it is possible to change the " "selection in the settings." msgstr "" "Bitte wählen Sie den Data-Ordner und Ihr Spiel.\n" "Es kann nur ein Spiel gleichzeitig aktiv sein, aber es ist in den " "Einstellungen möglich die Auswahl abzuändern." #: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102 #: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189 #: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247 res/xrc/Setup.xrc:276 msgid "Game not found! Select the data folder manually..." msgstr "Spiel nicht gefunden! Wählen Sie den Data-Ordner manuell..." #: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103 #: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190 #: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248 res/xrc/Setup.xrc:277 msgid "Select a folder" msgstr "Verzeichnis wählen" #: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113 #: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200 #: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258 res/xrc/Setup.xrc:287 msgid "Choose Game" msgstr "Spiel wählen" #: res/xrc/ShapeProperties.xrc:5 msgid "Shape Properties" msgstr "Modelleigenschaften" #: res/xrc/ShapeProperties.xrc:16 msgid "Shader" msgstr "Shader" #: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:629 #: res/xrc/Skeleton.xrc:94 msgid "Name" msgstr "Name" #: res/xrc/ShapeProperties.xrc:102 msgid "Specular Color" msgstr "Specular Farbe" #: res/xrc/ShapeProperties.xrc:120 msgid "Specular Strength" msgstr "Specular Stärke" #: res/xrc/ShapeProperties.xrc:139 msgid "Specular Power" msgstr "Specular Kraft" #: res/xrc/ShapeProperties.xrc:179 msgid "Emissive Color" msgstr "Emissive Farbe" #: res/xrc/ShapeProperties.xrc:197 msgid "Emissive Multiple" msgstr "Emissive Multiplikator" #: res/xrc/ShapeProperties.xrc:216 msgid "Alpha" msgstr "Alpha" #: res/xrc/ShapeProperties.xrc:235 msgid "Vertex Colors" msgstr "Vertex Farben" #: res/xrc/ShapeProperties.xrc:252 msgid "Double Sided" msgstr "Zweiseitig" #: res/xrc/ShapeProperties.xrc:289 res/xrc/ShapeProperties.xrc:447 msgid "Remove" msgstr "Entfernen" #: res/xrc/ShapeProperties.xrc:298 msgid "Textures..." msgstr "Texturen..." #: res/xrc/ShapeProperties.xrc:310 msgid "Transparency" msgstr "Transparenz" #: res/xrc/ShapeProperties.xrc:333 msgid "Threshold" msgstr "Grenzwert" #: res/xrc/ShapeProperties.xrc:373 msgid "Vertex Alpha" msgstr "Vertex Alpha" #: res/xrc/ShapeProperties.xrc:391 msgid "Alpha Test" msgstr "Alpha Test" #: res/xrc/ShapeProperties.xrc:409 msgid "Alpha Blend" msgstr "Alpha Blend" #: res/xrc/ShapeProperties.xrc:460 msgid "Copy from shape..." msgstr "Kopieren von Modell..." #: res/xrc/ShapeProperties.xrc:468 msgid "Geometry" msgstr "Geometrie" #: res/xrc/ShapeProperties.xrc:488 msgid "Full Precision" msgstr "Volle Präzision" #: res/xrc/ShapeProperties.xrc:507 msgid "Sub Index" msgstr "Sub Index" #: res/xrc/ShapeProperties.xrc:526 msgid "Skinned" msgstr "Skinned" #: res/xrc/ShapeProperties.xrc:544 msgid "Dynamic" msgstr "Dynamisch" #: res/xrc/ShapeProperties.xrc:590 msgid "Extra Data" msgstr "Extra Daten" #: res/xrc/ShapeProperties.xrc:638 msgid "Value" msgstr "Wert" #: res/xrc/ShapeProperties.xrc:648 msgid "Coordinates" msgstr "Koordinaten" #: res/xrc/ShapeProperties.xrc:657 msgid "Transform from shape to global coordinates:" msgstr "Von Modell- nach globale Koordinaten transformieren:" #: res/xrc/ShapeProperties.xrc:720 res/xrc/Skeleton.xrc:142 msgid "Rotation" msgstr "Rotation" #: res/xrc/Skeleton.xrc:6 msgid "Select a bone to add" msgstr "Wählen Sie einen hinzuzufügenden Bone" #: res/xrc/Skeleton.xrc:15 msgid "Bones in the current reference skeleton:" msgstr "Bones im aktuellen Referenzskelett:" #: res/xrc/Skeleton.xrc:53 msgid "Add Custom Bone" msgstr "Benutzerdefinierten Bone hinzufügen" #: res/xrc/Skeleton.xrc:68 msgid "Parent" msgstr "Parent" #: res/xrc/Skeleton.xrc:234 msgid "Add Count #" msgstr "Anzahl Neu #" #: res/xrc/Slider.xrc:6 msgid "Select a slider preset" msgstr "Wählen Sie ein Slider Preset" #: res/xrc/Slider.xrc:15 msgid "Choose a preset:" msgstr "Wählen Sie ein Preset:" #: res/xrc/Slider.xrc:40 msgid "Low weight" msgstr "Unteres Gewicht" #: res/xrc/Slider.xrc:49 msgid "High weight" msgstr "Oberes Gewicht" #: res/xrc/Slider.xrc:81 msgid "Slider Properties" msgstr "Slidereigenschaften" #: res/xrc/Slider.xrc:91 msgid "Slider Name" msgstr "Slidername" #: res/xrc/Slider.xrc:108 msgid "Default Values" msgstr "Standardwerte" #: res/xrc/Slider.xrc:114 msgid "Low" msgstr "Niedrig" #: res/xrc/Slider.xrc:131 msgid "High" msgstr "Hoch" #: res/xrc/Slider.xrc:148 msgid "Zapped" msgstr "Zapped" #: res/xrc/Slider.xrc:173 msgid "Invert" msgstr "Invertieren" #: res/xrc/Slider.xrc:182 msgid "Hidden" msgstr "Versteckt" #: res/xrc/Slider.xrc:191 msgid "Zap" msgstr "Zap" #: res/xrc/Slider.xrc:211 msgid "Toggle Zaps:" msgstr "Zap-Umschaltung:" #: res/xrc/SliderDataImport.xrc:6 msgid "Slider Data Import Options..." msgstr "Sliderdaten Import-Optionen..." #: res/xrc/SliderDataImport.xrc:21 msgid "Select the shapes that slider data will be imported for:" msgstr "Wählen Sie die Modelle für die Sliderdaten importiert werden:" #: res/xrc/SliderDataImport.xrc:52 msgid "Select the sliders to be imported" msgstr "Wählen Sie die zu importierenden Slider" #: src/components/Anim.cpp:570 msgid "" "Bone information incomplete. Exported data will not contain correct bone " "entries! Be sure to load a reference NIF prior to export." msgstr "" "Bone-Informationen sind unvollständig. Exportierte Daten werden keine " "korrekten Bone-Einträge besitzen! Stelle sicher, dass du eine Referenz vor " "dem Export geladen hast." #: src/components/Anim.cpp:571 msgid "Export Warning" msgstr "Export Warnung" #: src/components/Anim.cpp:764 #, c-format msgid "Failed to load skeleton '%s'!" msgstr "Konnte Skelett '%s' nicht laden!" #: src/components/Anim.cpp:772 #, c-format msgid "Root '%s' not found in skeleton '%s'!" msgstr "Root '%s' konnte nicht im Skelett '%s' gefunden werden!" #: src/program/BodySlideApp.cpp:189 src/program/OutfitStudio.cpp:423 msgid "" "No read/write permission for game data path!\n" "\n" "Please launch the program with admin elevation and make sure the game data " "path in the settings is correct." msgstr "" "Kein Schreib-/Lesezugriff auf den Spieldaten-Ordner!\n" "\n" "Bitte starten Sie das Programm mit Admin-Rechten und stellen Sie sicher, " "dass der Spieldaten-Pfad in den Einstellungen korrekt ist." #: src/program/BodySlideApp.cpp:190 src/program/BodySlideApp.cpp:200 #: src/program/BodySlideApp.cpp:1535 src/program/OutfitStudio.cpp:424 #: src/program/OutfitStudio.cpp:434 src/program/OutfitStudio.cpp:660 #: src/program/OutfitStudio.cpp:667 msgid "Warning" msgstr "Warnung" #: src/program/BodySlideApp.cpp:199 src/program/OutfitStudio.cpp:433 msgid "" "No read/write permission for project path!\n" "\n" "Please launch the program with admin elevation and make sure the project " "path in the settings is correct." msgstr "" "Kein Schreib-/Lesezugriff auf den Projekte-Ordner!\n" "\n" "Bitte starten Sie das Programm mit Admin-Rechten und stellen Sie sicher, " "dass der Projekte-Pfad in den Einstellungen korrekt ist." #: src/program/BodySlideApp.cpp:272 src/program/OutfitStudio.cpp:521 #, c-format msgid "Unexpected exception has occurred: %s, the program will terminate." msgstr "" "Unerwartete Ausnahme trat auf: %s, das Programm wird sich jetzt beenden." #: src/program/BodySlideApp.cpp:272 src/program/OutfitStudio.cpp:521 msgid "Unexpected exception" msgstr "Unerwartete Ausnahme" #: src/program/BodySlideApp.cpp:295 src/program/OutfitStudio.cpp:541 #, c-format msgid "Unhandled exception has occurred: %s, the program will terminate." msgstr "" "Unbehandelte Ausnahme trat auf: %s, das Programm wird sich jetzt beenden." #: src/program/BodySlideApp.cpp:295 src/program/OutfitStudio.cpp:541 msgid "Unhandled exception" msgstr "Unbehandelte Ausnahme" #: src/program/BodySlideApp.cpp:306 src/program/OutfitStudio.cpp:549 msgid "Fatal exception has occurred, the program will terminate." msgstr "Ein fataler Fehler trat auf, das Programm wird sich jetzt beenden." #: src/program/BodySlideApp.cpp:306 src/program/OutfitStudio.cpp:549 msgid "Fatal exception" msgstr "Fataler Fehler" #: src/program/BodySlideApp.cpp:1012 msgid "Failed to launch Outfit Studio executable!" msgstr "Fehler beim Starten von Outfit Studio!" #: src/program/BodySlideApp.cpp:1012 src/program/BodySlideApp.cpp:1556 #: src/program/BodySlideApp.cpp:1868 src/program/BodySlideApp.cpp:3037 #: src/program/BodySlideApp.cpp:3044 src/program/BodySlideApp.cpp:3849 #: src/program/OutfitStudio.cpp:1001 src/program/OutfitStudio.cpp:1007 #: src/program/OutfitStudio.cpp:1560 src/program/OutfitStudio.cpp:1571 #: src/program/OutfitStudio.cpp:1607 src/program/OutfitStudio.cpp:1618 #: src/program/OutfitStudio.cpp:1628 src/program/OutfitStudio.cpp:1637 #: src/program/OutfitStudio.cpp:1648 src/program/OutfitStudio.cpp:1659 #: src/program/OutfitStudio.cpp:1671 src/program/OutfitStudio.cpp:1710 #: src/program/OutfitStudio.cpp:1718 src/program/OutfitStudio.cpp:1725 #: src/program/OutfitStudio.cpp:1761 src/program/OutfitStudio.cpp:1769 #: src/program/OutfitStudio.cpp:1776 src/program/OutfitStudio.cpp:1786 #: src/program/OutfitStudio.cpp:1795 src/program/OutfitStudio.cpp:1803 #: src/program/OutfitStudio.cpp:1810 src/program/OutfitStudio.cpp:1821 #: src/program/OutfitStudio.cpp:1830 src/program/OutfitStudio.cpp:1837 #: src/program/OutfitStudio.cpp:2112 src/program/OutfitStudio.cpp:2146 #: src/program/OutfitStudio.cpp:2161 src/program/OutfitStudio.cpp:2247 #: src/program/OutfitStudio.cpp:2256 src/program/OutfitStudio.cpp:2264 #: src/program/OutfitStudio.cpp:2278 src/program/OutfitStudio.cpp:2287 #: src/program/OutfitStudio.cpp:2293 src/program/OutfitStudio.cpp:2327 #: src/program/OutfitStudio.cpp:3745 src/program/OutfitStudio.cpp:3752 #: src/program/OutfitStudio.cpp:4404 src/program/OutfitStudio.cpp:4423 #: src/program/OutfitStudio.cpp:4489 src/program/OutfitStudio.cpp:4525 #: src/program/OutfitStudio.cpp:4544 src/program/OutfitStudio.cpp:4614 #: src/program/OutfitStudio.cpp:4650 src/program/OutfitStudio.cpp:4669 #: src/program/OutfitStudio.cpp:4694 src/program/OutfitStudio.cpp:4744 #: src/program/OutfitStudio.cpp:4749 src/program/OutfitStudio.cpp:4763 #: src/program/OutfitStudio.cpp:4770 src/program/OutfitStudio.cpp:4775 #: src/program/OutfitStudio.cpp:4786 src/program/OutfitStudio.cpp:7203 #: src/program/OutfitStudio.cpp:7261 src/program/OutfitStudio.cpp:7267 #: src/program/OutfitStudio.cpp:7271 src/program/OutfitStudio.cpp:7282 #: src/program/OutfitStudio.cpp:7292 src/program/OutfitStudio.cpp:7296 #: src/program/OutfitStudio.cpp:7313 src/program/OutfitStudio.cpp:7317 #: src/program/OutfitStudio.cpp:7328 src/program/OutfitStudio.cpp:7338 #: src/program/OutfitStudio.cpp:7351 src/program/OutfitStudio.cpp:7465 #: src/program/OutfitStudio.cpp:7478 src/program/OutfitStudio.cpp:7580 #: src/program/OutfitStudio.cpp:7585 src/program/OutfitStudio.cpp:7598 #: src/program/OutfitStudio.cpp:7692 src/program/OutfitStudio.cpp:7696 #: src/program/OutfitStudio.cpp:7707 src/program/OutfitStudio.cpp:7717 #: src/program/OutfitStudio.cpp:7721 src/program/OutfitStudio.cpp:7744 #: src/program/OutfitStudio.cpp:7753 src/program/OutfitStudio.cpp:7757 #: src/program/OutfitStudio.cpp:7786 src/program/OutfitStudio.cpp:7790 #: src/program/OutfitStudio.cpp:7813 src/program/OutfitStudio.cpp:7822 #: src/program/OutfitStudio.cpp:7833 src/program/OutfitStudio.cpp:7840 #: src/program/OutfitStudio.cpp:7851 src/program/OutfitStudio.cpp:7858 #: src/program/OutfitStudio.cpp:7885 src/program/OutfitStudio.cpp:7936 #: src/program/OutfitStudio.cpp:7997 src/program/OutfitStudio.cpp:8029 #: src/program/OutfitStudio.cpp:8033 src/program/OutfitStudio.cpp:8046 #: src/program/OutfitStudio.cpp:8050 src/program/OutfitStudio.cpp:8261 #: src/program/OutfitStudio.cpp:8428 src/program/OutfitStudio.cpp:8447 #: src/program/OutfitStudio.cpp:8531 src/program/OutfitStudio.cpp:8555 #: src/program/OutfitStudio.cpp:8593 src/program/OutfitStudio.cpp:8745 #: src/program/OutfitStudio.cpp:8934 src/program/OutfitStudio.cpp:9086 #: src/program/OutfitStudio.cpp:9262 src/program/OutfitStudio.cpp:9317 #: src/program/OutfitStudio.cpp:9531 src/program/OutfitStudio.cpp:9541 #: src/program/OutfitStudio.cpp:9582 src/program/OutfitStudio.cpp:9587 #: src/program/OutfitStudio.cpp:9596 src/program/OutfitStudio.cpp:9612 #: src/program/OutfitStudio.cpp:9617 src/program/OutfitStudio.cpp:9785 #: src/program/OutfitStudio.cpp:9793 src/program/OutfitStudio.cpp:9834 #: src/program/OutfitStudio.cpp:10156 src/program/OutfitStudio.cpp:10161 #: src/program/OutfitStudio.cpp:10247 src/program/OutfitStudio.cpp:10252 #: src/program/OutfitStudio.cpp:10340 src/program/OutfitStudio.cpp:10346 #: src/program/OutfitStudio.cpp:10351 src/program/OutfitStudio.cpp:10358 #: src/program/OutfitStudio.cpp:10385 src/program/OutfitStudio.cpp:10430 #: src/program/OutfitStudio.cpp:10481 src/program/OutfitStudio.cpp:10486 #: src/program/OutfitStudio.cpp:10520 src/program/OutfitStudio.cpp:10732 #: src/program/OutfitStudio.cpp:10782 src/program/OutfitStudio.cpp:10889 #: src/program/OutfitStudio.cpp:11031 src/program/OutfitStudio.cpp:11115 #: src/program/OutfitStudio.cpp:12499 src/program/OutfitStudio.cpp:12819 #: src/program/OutfitStudio.cpp:12856 src/program/OutfitStudio.cpp:12861 #: src/program/OutfitStudio.cpp:12873 src/program/OutfitStudio.cpp:14209 msgid "Error" msgstr "Fehler" #: src/program/BodySlideApp.cpp:1535 src/program/OutfitStudio.cpp:667 msgid "" "Failed to find game install path registry key or GameDataPath in the config." msgstr "" "Konnte den Registry-Key des Spielpfades oder den GameDataPath in der " "Konfiguration nicht finden." #: src/program/BodySlideApp.cpp:1781 src/program/OutfitStudio.cpp:913 #, c-format msgid "System language '%d' is wrong." msgstr "Systemsprache '%d' ist ungültig." #: src/program/BodySlideApp.cpp:1790 src/program/OutfitStudio.cpp:922 #, c-format msgid "" "The system language '%d' is not supported by your system. Try installing " "support for this language." msgstr "" "Die Systemsprache '%d' wird nicht von Ihrem System unterstützt. Sie können " "versuchen, die Unterstützung der Sprache zu installieren." #: src/program/BodySlideApp.cpp:1868 msgid "Failed to create group file." msgstr "Konnte Gruppen-Datei nicht erstellen." #: src/program/BodySlideApp.cpp:1882 msgid "" "That group already exists in the specified file, do you wish to overwrite " "the group?" msgstr "" "Diese Gruppe existiert bereits in der angegebenen Datei, willst du sie " "überschreiben?" #: src/program/BodySlideApp.cpp:1882 msgid "Group already exists" msgstr "Gruppe existiert bereits" #: src/program/BodySlideApp.cpp:2062 msgid "" "WARNING: Game data path not configured. Would you like to show BodySlide " "where it is?" msgstr "" "WARNUNG: Spieldaten-Pfad nicht konfiguriert. Möchtest du BodySlide zeigen, " "wo dieser ist?" #: src/program/BodySlideApp.cpp:2063 src/program/BodySlideApp.cpp:2386 #: src/program/BodySlideApp.cpp:2391 msgid "Game not found" msgstr "Spiel nicht gefunden" #: src/program/BodySlideApp.cpp:2071 msgid "Please choose a directory to set as your Data path" msgstr "Bitte wählen Sie ein Verzeichnis für den Spieldaten-Pfad" #: src/program/BodySlideApp.cpp:2089 msgid "" "WARNING: This will delete the output files from the output folder, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "WARNUNG: Dies wird die Ausgabedateien vom Ausgabeordner löschen, was " "potenziell zu Problem führen kann.\n" "\n" "Willst du fortsetzen?" #: src/program/BodySlideApp.cpp:2090 msgid "Clean Build" msgstr "Säuberungs-Erstellung" #: src/program/BodySlideApp.cpp:2098 msgid "Removed the following files:\n" msgstr "Folgende Dateien wurden entfernt:\n" #: src/program/BodySlideApp.cpp:2110 src/program/BodySlideApp.cpp:2123 msgid " (no action)\n" msgstr " (keine Aktion)\n" #: src/program/BodySlideApp.cpp:2114 src/program/BodySlideApp.cpp:2126 #: src/program/BodySlideApp.cpp:2357 msgid "Process Successful" msgstr "Prozess erfolgreich" #: src/program/BodySlideApp.cpp:2244 #, c-format msgid "" "Failed to write TRI file to the following location\n" "\n" "%s" msgstr "" "Konnte TRI-Datei nicht an die folgende Stelle schreiben\n" "\n" "%s" #: src/program/BodySlideApp.cpp:2244 src/program/BodySlideApp.cpp:2300 #: src/program/BodySlideApp.cpp:2335 msgid "Unable to process" msgstr "Konnte nicht verarbeitet werden" #: src/program/BodySlideApp.cpp:2300 src/program/BodySlideApp.cpp:2335 #, c-format msgid "" "Failed to build set to the following location\n" "\n" "%s" msgstr "" "Konnte das Set nicht an der folgenden Stelle erstellen\n" "\n" "%s" #: src/program/BodySlideApp.cpp:2302 src/program/BodySlideApp.cpp:2337 msgid "Choose alternate file name" msgstr "Wählen Sie einen alternativen Dateinamen" #: src/program/BodySlideApp.cpp:2349 msgid "Successfully processed the following files:\n" msgstr "Erfolgreich die folgenden Dateien verarbeitet:\n" #: src/program/BodySlideApp.cpp:2371 msgid "" "WARNING: This will delete the output files from the output folders, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "WARNUNG: Dies wird die Ausgabedateien aus den Ausgabeordnern löschen, was " "potenziell zu Problem führen kann.\n" "\n" "Willst du fortsetzen?" #: src/program/BodySlideApp.cpp:2372 msgid "Clean Batch Build" msgstr "Säuberungs-Batch-Erstellung" #: src/program/BodySlideApp.cpp:2386 msgid "" "WARNING: Game data path not configured. Files can't be removed that way." msgstr "" "WARNUNG: Spieldaten-Pfad ist nicht konfiguriert. Dateien können so nicht " "entfernt werden." #: src/program/BodySlideApp.cpp:2390 msgid "" "WARNING: Game data path not configured. Continue saving files to the working " "directory?" msgstr "" "WARNUNG: Spieldaten-Pfad nicht konfiguriert. Dateien stattdessen in das " "Arbeitsverzeichnis speichern?" #: src/program/BodySlideApp.cpp:2519 msgid "Processing Outfits" msgstr "Verarbeite Outfits" #: src/program/BodySlideApp.cpp:2519 src/program/OutfitStudio.h:1075 msgid "Starting..." msgstr "Starten..." #: src/program/BodySlideApp.cpp:2531 #, c-format msgid "Processing '%s' (%d of %d)..." msgstr "Verarbeite '%s' (%d von %d)..." #: src/program/BodySlideApp.cpp:2539 msgid "No recorded outfit name source" msgstr "Keine aufgenommene Outfitnamen-Quelle" #: src/program/BodySlideApp.cpp:2550 msgid "Unable to get slider set from file: " msgstr "Konnte Slider Set nicht aus Datei bekommen: " #: src/program/BodySlideApp.cpp:2555 msgid "Unable to open slider set file: " msgstr "Konnte Slider Set Datei nicht öffnen: " #: src/program/BodySlideApp.cpp:2590 msgid "Unable to load input nif: " msgstr "Konnte Eingabe NIF nicht lesen: " #: src/program/BodySlideApp.cpp:2795 msgid "Unable to create destination directory: " msgstr "Konnte Ziel-Verzeichnis nicht erstellen: " #: src/program/BodySlideApp.cpp:2872 src/program/BodySlideApp.cpp:2880 #: src/program/BodySlideApp.cpp:2891 msgid "Unable to save nif file: " msgstr "Konnte NIF-Datei nicht speichern: " #: src/program/BodySlideApp.cpp:2965 src/program/BodySlideApp.cpp:4088 msgid "The following sets failed" msgstr "Die folgenden Sets sind fehlgeschlagen" #: src/program/BodySlideApp.cpp:2965 src/program/BodySlideApp.cpp:4088 msgid "Failed" msgstr "Fehlgeschlagen" #: src/program/BodySlideApp.cpp:3037 msgid "Failed to load BodySlide.xrc file!" msgstr "Konnte die BodySlide.xrc Datei nicht laden!" #: src/program/BodySlideApp.cpp:3044 msgid "Failed to load BodySlide frame!" msgstr "Konnte das BodySlide-Fenster nicht laden!" #: src/program/BodySlideApp.cpp:3077 msgid "Filter groups..." msgstr "Gruppen filtern..." #: src/program/BodySlideApp.cpp:3083 msgid "Filter outfits..." msgstr "Outfits filtern..." #: src/program/BodySlideApp.cpp:3089 msgid "Filter sliders..." msgstr "Slider filtern..." #: src/program/BodySlideApp.cpp:3727 msgid "Choose groups to filter outfit list" msgstr "Wählen Sie Gruppen zum Filtern der Outfitliste" #: src/program/BodySlideApp.cpp:3727 msgid "Choose Groups" msgstr "Gruppen auswählen" #: src/program/BodySlideApp.cpp:3759 msgid "Choose or create group file" msgstr "Wählen Sie oder erstelle eine Gruppen-Datei" #: src/program/BodySlideApp.cpp:3772 msgid "What would you like the new group to be called?" msgstr "Wie möchten Sie die neue Gruppe nennen?" #: src/program/BodySlideApp.cpp:3772 msgid "New Group Name" msgstr "Neuer Gruppenname" #: src/program/BodySlideApp.cpp:3818 msgid "Do you really wish to delete the selected project?" msgstr "" "Sind Sie sich sicher, dass Sie das ausgewählte Projekt löschen möchten?" #: src/program/BodySlideApp.cpp:3818 msgid "Delete Project" msgstr "Projekt löschen" #: src/program/BodySlideApp.cpp:3827 msgid "Do you really wish to delete the selected preset?" msgstr "Sind Sie sich sicher, dass Sie das ausgwählte Preset löschen möchten?" #: src/program/BodySlideApp.cpp:3827 msgid "Delete Preset" msgstr "Preset löschen" #: src/program/BodySlideApp.cpp:3849 src/program/OutfitStudio.cpp:7261 #, c-format msgid "Failed to save preset (%d)!" msgstr "Konnte Preset nicht speichern (%d)!" #: src/program/BodySlideApp.cpp:3877 #, c-format msgid "Failed to save preset as '%s' (%d)!" msgstr "Konnte Preset nicht als '%s' speichern (%d)!" #: src/program/BodySlideApp.cpp:4063 msgid "Choose a folder to contain the saved files" msgstr "Wählen Sie einen Ordner, der die gespeicherten Dateien beinhalten soll" #: src/program/BodySlideApp.cpp:4078 msgid "All sets processed successfully!" msgstr "Alle Sets erfolgreich vearbeitet!" #: src/program/BodySlideApp.cpp:4078 msgid "Complete" msgstr "Abgeschlossen" #: src/program/ConvertBodyReferenceDialog.cpp:121 msgid "Starting conversion..." msgstr "Starte Konvertierung..." #: src/program/ConvertBodyReferenceDialog.cpp:139 msgid "Updating Project Output Settings" msgstr "Aktualisiere Projektausgabe-Einstellungen" #: src/program/ConvertBodyReferenceDialog.cpp:178 msgid "Deleting Shapes..." msgstr "Lösche Modelle..." #: src/program/ConvertBodyReferenceDialog.cpp:199 msgid "Loading conversion reference..." msgstr "Lade Konvertierungsreferenz..." #: src/program/ConvertBodyReferenceDialog.cpp:209 #: src/program/ConvertBodyReferenceDialog.cpp:253 msgid "Conforming outfit parts..." msgstr "Übertrage Slider..." #: src/program/ConvertBodyReferenceDialog.cpp:216 msgid "Updating conversion Slider..." msgstr "Aktualisiere Konvertierungs-Slider..." #: src/program/ConvertBodyReferenceDialog.cpp:220 msgid "Setting the base shape and removing the conversion reference" msgstr "Basismodell setzen und Konvertierungsreferenz entfernen" #: src/program/ConvertBodyReferenceDialog.cpp:227 msgid "Skipping conversion reference..." msgstr "Überspringe Konvertierungsreferenz..." #: src/program/ConvertBodyReferenceDialog.cpp:232 msgid "Loading new reference..." msgstr "Lade neue Referenz..." #: src/program/ConvertBodyReferenceDialog.cpp:246 msgid "Copying bones..." msgstr "Kopiere Bones..." #: src/program/ConvertBodyReferenceDialog.cpp:260 msgid "Adding Bones..." msgstr "Füge Bones hinzu..." #: src/program/ConvertBodyReferenceDialog.cpp:289 msgid "Conversion finished." msgstr "Konvertierung abgeschlossen." #: src/program/EditUV.cpp:519 src/program/OutfitStudio.cpp:11603 msgid "Outfit Studio: OpenGL context is not OK." msgstr "Outfit Studio: OpenGL-Kontext ist nicht OK." #: src/program/EditUV.cpp:519 src/program/OutfitStudio.cpp:11603 #: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:33 #: src/render/GLSurface.cpp:2116 src/render/GLSurface.cpp:2133 msgid "OpenGL Error" msgstr "OpenGL Fehler" #: src/program/FBXImportDialog.cpp:161 src/program/ObjImportDialog.cpp:168 #: src/program/OutfitStudio.cpp:9582 src/program/OutfitStudio.cpp:12856 msgid "The shape has reached the vertex count limit." msgstr "Das Modell hat das Vertex-Limit erreicht." #: src/program/FBXImportDialog.cpp:165 src/program/ObjImportDialog.cpp:172 #: src/program/OutfitStudio.cpp:9587 src/program/OutfitStudio.cpp:12861 msgid "The shape has reached the triangle count limit." msgstr "Das Modell hat das Triangle-Limit erreicht." #: src/program/GroupManager.cpp:143 msgid "Please enter a new unique name for the group." msgstr "Bitte geben Sie einen neuen, einzigartigen Namen für die Gruppe ein." #: src/program/GroupManager.cpp:143 msgid "Rename Group" msgstr "Gruppe umbenennen" #: src/program/GroupManager.cpp:323 msgid "Save changes to group file?" msgstr "Änderungen in Gruppen-Datei speichern?" #: src/program/GroupManager.cpp:323 msgid "Save Changes" msgstr "Änderungen speichern" #: src/program/NormalsGenDialog.cpp:90 msgid "Enter a name for the new layer." msgstr "Geben Sie einen Namen für die neue Ebene ein." #: src/program/NormalsGenDialog.cpp:90 msgid "Name new layer" msgstr "Neue Ebene benennen" #: src/program/NormalsGenDialog.cpp:205 msgid "Choose a normals generator preset file..." msgstr "Normal-Generator Voreinstellungsdatei auswählen..." #: src/program/NormalsGenDialog.cpp:222 msgid "Save normals generator preset to..." msgstr "Normal-Generator Voreinstellung speichern nach..." #: src/program/NormalsGenDialog.cpp:240 msgid "Layer" msgstr "Ebene" #: src/program/NormalsGenDialog.cpp:263 msgid "Background File" msgstr "Hintergrunddatei" #: src/program/NormalsGenDialog.cpp:264 msgid "File source for this layer." msgstr "Dateiquelle für diese Ebene." #: src/program/NormalsGenDialog.cpp:265 msgid "Color" msgstr "Farbe" #: src/program/NormalsGenDialog.cpp:266 msgid "Solid background color (if file is not set)." msgstr "Einheitliche Hintergrundfarbe (wenn Datei nicht gesetzt)." #: src/program/NormalsGenDialog.cpp:267 msgid "Resolution" msgstr "Auflösung" #: src/program/NormalsGenDialog.cpp:269 msgid "" "Output texture dimensions. By default all images will be scaled to fit this " "size." msgstr "" "Dimensionen der Ausgabetextur. Standardmäßig werden alle Texturen auf diese " "Größe angepasst." #: src/program/NormalsGenDialog.cpp:286 msgid "" "File containing normals data to combine. Note this file should fit the mesh " "UVs." msgstr "" "Datei mit den zu kombinierenden Normals-Daten. Diese Datei sollte an die UVs " "des Modells angepasst sein." #: src/program/NormalsGenDialog.cpp:288 msgid "Is Tangent Space?" msgstr "Ist Tangent Space?" #: src/program/NormalsGenDialog.cpp:289 msgid "" "True if the normals data in the layer file is in tangent space, false if " "they are in model space (msn)." msgstr "" "Ja, wenn die Normals-Daten in der Schichtdatei im Tangent Space ist. Nein, " "wenn sie im Model Space (msn) ist." #: src/program/NormalsGenDialog.cpp:292 msgid "A greyscale image used to mask updates to destination image." msgstr "Graustufenbild um Änderungen an der Ausgabetextur zur maskieren." #: src/program/NormalsGenDialog.cpp:294 msgid "X Offset" msgstr "X-Verschiebung" #: src/program/NormalsGenDialog.cpp:295 src/program/NormalsGenDialog.cpp:298 msgid "Offset to apply to image position." msgstr "Verschiebung der Bildposition." #: src/program/NormalsGenDialog.cpp:297 msgid "Y Offset" msgstr "Y-Verschiebung" #: src/program/NormalsGenDialog.cpp:301 msgid "If true, scale image to match background resolution." msgstr "Wenn ja, wird das Bild an die Hintergrundauflösung angepasst." #: src/program/OutfitProject.cpp:53 msgid "Checking destination..." msgstr "Überprüfe Ziel..." #: src/program/OutfitProject.cpp:113 msgid "Adding reference shapes..." msgstr "Füge Referenzmodelle hinzu..." #: src/program/OutfitProject.cpp:134 src/program/OutfitProject.cpp:2245 msgid "Adding outfit shapes..." msgstr "Füge Outfit-Modelle hinzu..." #: src/program/OutfitProject.cpp:193 msgid "Calculating slider data..." msgstr "Berechne Sliderdaten..." #: src/program/OutfitProject.cpp:201 msgid "Creating slider set file..." msgstr "Erstelle Slider Set Datei..." #: src/program/OutfitProject.cpp:208 msgid "Failed to open or create slider set file: " msgstr "Konnte Slider Set Datei nicht öffnen oder erstellen: " #: src/program/OutfitProject.cpp:215 msgid "Saving slider set file..." msgstr "Speichere Slider Set Datei..." #: src/program/OutfitProject.cpp:218 msgid "Failed to write to slider set file: " msgstr "Konnte Slider Set Datei nicht schreiben: " #: src/program/OutfitProject.cpp:222 msgid "Saving NIF file..." msgstr "Speichere NIF-Datei..." #: src/program/OutfitProject.cpp:252 msgid "Failed to write base .nif file: " msgstr "Konnte Basis NIF-Datei nicht schreiben: " #: src/program/OutfitProject.cpp:258 src/program/OutfitProject.cpp:1700 #: src/program/OutfitProject.cpp:1730 src/program/OutfitStudio.cpp:3608 msgid "Finished" msgstr "Abgeschlossen" #: src/program/OutfitProject.cpp:1594 src/program/OutfitProject.cpp:1686 msgid "Gathering bones..." msgstr "Sammle Bones..." #: src/program/OutfitProject.cpp:1622 msgid "Initializing proximity data..." msgstr "Initialisiere Umgebungsdaten..." #: src/program/OutfitProject.cpp:1668 src/program/OutfitStudio.cpp:10180 msgid "Copying bone weights..." msgstr "Kopiere Bone Weighting..." #: src/program/OutfitProject.cpp:1706 src/program/OutfitStudio.cpp:10371 msgid "Transferring bone weights..." msgstr "Transferiere Bone Weighting..." #: src/program/OutfitProject.cpp:1951 msgid "Template source entries are invalid." msgstr "Vorlagen Quelleinträge sind ungültig." #: src/program/OutfitProject.cpp:1951 src/program/OutfitProject.cpp:1981 #: src/program/OutfitProject.cpp:1986 src/program/OutfitProject.cpp:2031 #: src/program/OutfitProject.cpp:2053 src/program/OutfitProject.cpp:2060 #: src/program/OutfitProject.cpp:2070 src/program/OutfitProject.cpp:2082 msgid "Reference Error" msgstr "Referenz Fehler" #: src/program/OutfitProject.cpp:1978 src/program/OutfitProject.cpp:2050 #: src/program/OutfitProject.cpp:4637 #, c-format msgid "" "NIF version not supported!\n" "\n" "File: %s\n" "%s" msgstr "" "NIF-Version wird nicht unterstützt!\n" "\n" "Datei: %s\n" "%s" #: src/program/OutfitProject.cpp:1986 src/program/OutfitProject.cpp:2060 #, c-format msgid "Could not load reference NIF file '%s'!" msgstr "Konnte Referenz NIF-Datei '%s' nicht laden!" #: src/program/OutfitProject.cpp:2031 #, c-format msgid "Could not load slider set file '%s'!" msgstr "Konnte Slider Set Datei '%s' nicht laden!" #: src/program/OutfitProject.cpp:2070 #, c-format msgid "Reference NIF file '%s' does not contain any shapes." msgstr "Referenz NIF-Datei '%s' beinhaltet keine Modelle." #: src/program/OutfitProject.cpp:2082 #, c-format msgid "Shape '%s' not found in reference NIF file '%s'!" msgstr "" "Modell '%s' konnte nicht in der Referenz NIF-Datei '%s' gefunden werden!" #: src/program/OutfitProject.cpp:2142 msgid "Loading slider set..." msgstr "Lade Slider Set..." #: src/program/OutfitProject.cpp:2149 src/program/OutfitProject.cpp:2235 msgid "Retrieving sliders..." msgstr "Rufe Slider ab..." #: src/program/OutfitProject.cpp:2159 msgid "Loading outfit shapes..." msgstr "Lade Outfit-Modelle..." #: src/program/OutfitProject.cpp:2202 src/program/OutfitProject.cpp:2301 msgid "Updating slider data..." msgstr "Aktualisiere Sliderdaten..." #: src/program/OutfitProject.cpp:2227 msgid "Adding slider set..." msgstr "Füge Slider Set hinzu..." #: src/program/OutfitProject.cpp:2294 msgid "" "The following shapes were renamed and won't have slider data attached. " "Rename the duplicates yourself beforehand." msgstr "" "Die folgenden Modelle wurden umbenannt und werden keine Sliderdaten haben. " "Die Duplikate müssen vorher umbenannt werden." #: src/program/OutfitProject.cpp:2296 msgid "Renamed Shapes" msgstr "Umbenannte Modelle" #: src/program/OutfitProject.cpp:4640 src/program/OutfitProject.cpp:4645 msgid "NIF Error" msgstr "NIF Fehler" #: src/program/OutfitProject.cpp:4645 #, c-format msgid "Could not load NIF file '%s'!" msgstr "Konnte NIF-Datei '%s' nicht laden!" #: src/program/OutfitProject.cpp:4777 msgid "" "There was cloth physics data loaded at some point (BSClothExtraData). Please " "choose all the origins to use in the output." msgstr "" "Es wurden zu einem bestimmten Punkt Physikdaten geladen (BSClothExtraData). " "Bitte wählen Sie alle, die in der Ausgabe verwendet werden sollen." #: src/program/OutfitProject.cpp:4778 msgid "Choose cloth data" msgstr "Physikdaten auswählen" #: src/program/OutfitProject.cpp:4848 msgid "" "No reference has been loaded. For correct bone transforms, you might need " "to load a reference before importing OBJ files." msgstr "" #: src/program/OutfitProject.cpp:4856 #, c-format msgid "Could not load OBJ file '%s'!" msgstr "Konnte OBJ-Datei '%s' nicht laden!" #: src/program/OutfitProject.cpp:4856 src/program/OutfitProject.cpp:4880 #: src/program/OutfitProject.cpp:4942 src/program/OutfitProject.cpp:5108 msgid "OBJ Error" msgstr "OBJ Fehler" #: src/program/OutfitProject.cpp:4862 src/program/OutfitProject.cpp:5027 msgid "" "The reference shape has a skin coordinate system that is different from the " "global coordinate system. Would you like to copy the reference's global-to-" "skin transform to the imported shapes?" msgstr "" #: src/program/OutfitProject.cpp:4864 src/program/OutfitProject.cpp:5029 msgid "Copy skin coordinates" msgstr "Skin-Koordinaten kopieren" #: src/program/OutfitProject.cpp:4880 #, c-format msgid "Could not copy data from OBJ file '%s'!" msgstr "Konnte Daten nicht von OBJ-Datei '%s' kopieren!" #: src/program/OutfitProject.cpp:4897 msgid "" "The vertex count of the selected .obj file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "Die Anzahl an Vertices der ausgewählten OBJ-Datei stimmt nicht mit der des " "derzeit ausgewählten Outfit-Modells überein. Möchten Sie das aktuelle Modell " "aktualisieren? ('Nein' zum Erstellen eines neuen Modells)" #: src/program/OutfitProject.cpp:4899 src/program/OutfitProject.cpp:5055 msgid "Merge or New" msgstr "Verschmelzen oder neu" #: src/program/OutfitProject.cpp:4903 src/program/OutfitProject.cpp:5059 msgid "Update Vertex Positions?" msgstr "Vertex-Positionen aktualisieren?" #: src/program/OutfitProject.cpp:4903 src/program/OutfitProject.cpp:5059 msgid "Vertex Position Update" msgstr "Vertex-Positionen Aktualisierung" #: src/program/OutfitProject.cpp:4908 src/program/OutfitProject.cpp:5064 msgid "Update Texture Coordinates?" msgstr "Texturkoordinaten aktualisieren?" #: src/program/OutfitProject.cpp:4908 src/program/OutfitProject.cpp:5064 msgid "UV Update" msgstr "UV Aktualisierung" #: src/program/OutfitProject.cpp:4914 src/program/OutfitProject.cpp:5070 msgid "Update Normals?" msgstr "Normals aktualisieren?" #: src/program/OutfitProject.cpp:4914 src/program/OutfitProject.cpp:5070 msgid "Normals Update" msgstr "Normals Aktualisierung" #: src/program/OutfitProject.cpp:4924 src/program/OutfitProject.cpp:5086 msgid "Please specify a name for the new shape" msgstr "Bitte geben Sie einen Namen für das neue Modell an" #: src/program/OutfitProject.cpp:4924 src/program/OutfitProject.cpp:5086 msgid "New Shape Name" msgstr "Neuer Modellname" #: src/program/OutfitProject.cpp:4935 src/program/OutfitProject.cpp:5101 #, c-format msgid "" "The vertex or triangle limit for '%s' was exceeded.\n" "Remaining data was dropped.\n" "\n" "Vertices (current/max): %zu/%zu\n" "Triangles (current/max): %zu/%zu" msgstr "" "Das Vertex- oder Triangle Limit für '%s' wurde überschritten.\n" "Die übrigen Daten wurden entfernt.\n" "\n" "Vertices (current/max): %zu/%zu\n" "Triangles (current/max): %zu/%zu" #: src/program/OutfitProject.cpp:5015 msgid "" "No reference has been loaded. For correct bone transforms, you might need " "to load a reference before importing FBX files." msgstr "" #: src/program/OutfitProject.cpp:5053 msgid "" "The vertex count of the selected .fbx file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "Die Anzahl an Vertices der ausgewählten FBX-Datei stimmt nicht mit der des " "derzeit ausgewählten Outfit-Modells überein. Möchten Sie das aktuelle Modell " "aktualisieren? ('Nein' zum Erstellen eines neuen Modells)" #: src/program/OutfitProject.cpp:5077 msgid "Update Animation Weighting?" msgstr "Animationen-Weighting aktualisieren?" #: src/program/OutfitProject.cpp:5077 msgid "Animation Weight Update" msgstr "Animationen-Weighting Aktualisierung" #: src/program/OutfitProject.cpp:5226 msgid "Would you like Skyrim NIFs to be optimized for SSE during this session?" msgstr "Sollen Skyrim NIFs während dieser Session für SSE optimiert werden?" #: src/program/OutfitProject.cpp:5243 msgid "" "File format doesn't match the current game. Use FBX export, then start a new " "project and import the FBX file there." msgstr "" "Dateiformat stimmt nicht mit dem aktuellen Spiel überein. Bitte FBX-Export " "verwenden, dann ein neues Projekt öffnen und die FBX-Datei dort importieren." #: src/program/OutfitProject.cpp:5244 msgid "Version" msgstr "Version" #: src/program/OutfitProject.cpp:5257 #, c-format msgid "Unable to locate external mesh data for shape. Expected path: %s" msgstr "Konnte externe Mesh-Daten für Modell nicht laden. Erwarteter Pfad: %s" #: src/program/OutfitProject.cpp:5258 msgid "External Mesh Data Load Failure" msgstr "Ladefehler externer Mesh-Daten" #: src/program/OutfitProject.cpp:5368 msgid "No Bad Bones Found." msgstr "Keine mangelhaften Bones gefunden." #: src/program/OutfitProject.cpp:5368 msgid "No Bad Bones" msgstr "Keine mangelhaften Bones" #: src/program/OutfitProject.cpp:5483 msgid "Bad Bones" msgstr "Mangelhafte Bones" #: src/program/OutfitProject.cpp:5504 msgid "Error in rotation" msgstr "Fehler in Rotation" #: src/program/OutfitProject.cpp:5505 msgid "Error in translation" msgstr "Fehler in Position" #: src/program/OutfitProject.cpp:5506 msgid "Error in scale" msgstr "Fehler in Skalierung" #: src/program/OutfitProject.cpp:5533 #, c-format msgid "Bad standard bones for shape \"%s\"" msgstr "Mangelhafte Standard-Bones für Modell \"%s\"" #: src/program/OutfitProject.cpp:5536 #, c-format msgid "" "%zu bones in shape \"%s\" had inconsistencies between their NIF skin " "transforms and the standard skeleton:\n" msgstr "" "%zu Bones in Modell \"%s\" hatten Inkonsistenzen zwischen ihren NIF Skin-" "Transformationen und dem Standard-Skelett:\n" #: src/program/OutfitProject.cpp:5551 msgid "Update skin (recommended)" msgstr "Skinning aktualisieren (empfohlen)" #: src/program/OutfitProject.cpp:5559 src/program/OutfitProject.cpp:5623 #: src/program/OutfitProject.cpp:5646 msgid "Details" msgstr "Details" #: src/program/OutfitProject.cpp:5559 msgid "Bone" msgstr "Bone" #: src/program/OutfitProject.cpp:5564 src/program/OutfitProject.cpp:5660 msgid "Do nothing" msgstr "Nichts tun" #: src/program/OutfitProject.cpp:5576 #, c-format msgid "Bad Custom Bone \"%s\"" msgstr "Mangelhafter benutzerdefinierter Bone \"%s\"" #: src/program/OutfitProject.cpp:5579 #, c-format msgid "" "Custom bone \"%s\" had inconsistent NIF node and skin transforms for the " "following shapes:\n" "\"" msgstr "" "Benutzerdefinierter Bone \"%s\" hatte inkonsistente NIF Node- und Skin-" "Transformationen für folgende Modelle:\n" "\"" #: src/program/OutfitProject.cpp:5599 msgid "Trust node and skins \"" msgstr "Nodes und Skinnings vertrauen \"" #: src/program/OutfitProject.cpp:5601 msgid "Trust node and skin \"" msgstr "Node und Skinning vertrauen \"" #: src/program/OutfitProject.cpp:5609 msgid "\", and update other skins (recommended)" msgstr "\", und andere Skinnings aktualisieren (empfohlen)" #: src/program/OutfitProject.cpp:5612 msgid "Trust node, and update skins" msgstr "Node vertrauen und Skinnings aktualisieren" #: src/program/OutfitProject.cpp:5614 msgid "Trust node, and update skin" msgstr "Node vertrauen und Skinning aktualisieren" #: src/program/OutfitProject.cpp:5623 msgid "Skin" msgstr "Skin" #: src/program/OutfitProject.cpp:5632 msgid "Trust skin \"" msgstr "Skinning vertrauen \"" #: src/program/OutfitProject.cpp:5634 msgid "\", and update node" msgstr "\", und Node aktualisieren" #: src/program/OutfitProject.cpp:5636 msgid "\", and update node and other skins" msgstr "\", und Node und andere Skinnings aktualisieren" #: src/program/OutfitProject.cpp:5646 msgid "With" msgstr "Mit" #: src/program/OutfitProject.cpp:5647 msgid "Node" msgstr "Node" #: src/program/OutfitProject.cpp:5673 msgid "Fix nothing" msgstr "Nichts beheben" #: src/program/OutfitStudio.cpp:449 src/program/OutfitStudio.cpp:450 #: src/program/OutfitStudio.cpp:14152 src/program/OutfitStudio.cpp:14153 msgid "Adding NIF file..." msgstr "Füge NIF-Datei hinzu..." #: src/program/OutfitStudio.cpp:454 src/program/OutfitStudio.cpp:465 #: src/program/OutfitStudio.cpp:476 src/program/OutfitStudio.cpp:4331 #: src/program/OutfitStudio.cpp:14157 src/program/OutfitStudio.cpp:14168 #: src/program/OutfitStudio.cpp:14179 msgid "Refreshing GUI..." msgstr "Aktualisiere GUI..." #: src/program/OutfitStudio.cpp:461 src/program/OutfitStudio.cpp:14164 msgid "Adding OBJ file..." msgstr "Füge OBJ-Datei hinzu..." #: src/program/OutfitStudio.cpp:471 src/program/OutfitStudio.cpp:472 #: src/program/OutfitStudio.cpp:14174 src/program/OutfitStudio.cpp:14175 msgid "Adding FBX file..." msgstr "Füge FBX-Datei hinzu..." #: src/program/OutfitStudio.cpp:660 msgid "" "Failed to find game install path registry value or GameDataPath in the " "config." msgstr "" "Konnte den Registry-Wert des Spielpfades oder den GameDataPath in der " "Konfiguration nicht finden." #: src/program/OutfitStudio.cpp:1001 msgid "Failed to load OutfitStudio.xrc file!" msgstr "Konnte OutfitStudio.xrc Datei nicht laden!" #: src/program/OutfitStudio.cpp:1007 msgid "Failed to load Outfit Studio frame!" msgstr "Konnte Outfit Studio Fenster nicht laden!" #: src/program/OutfitStudio.cpp:1025 src/program/OutfitStudio.cpp:3872 #: src/program/OutfitStudio.h:1105 msgid "Ready!" msgstr "Bereit!" #: src/program/OutfitStudio.cpp:1534 src/program/OutfitStudio.cpp:1539 msgid "Packing projects to folder..." msgstr "Projekte in einen Ordner packen..." #: src/program/OutfitStudio.cpp:1560 src/program/OutfitStudio.cpp:1607 #: src/program/OutfitStudio.cpp:1710 #, c-format msgid "Failed to open input file '%s'!" msgstr "Konnte Eingabedatei '%s' nicht öffnen!" #: src/program/OutfitStudio.cpp:1571 #, c-format msgid "Failed to copy input file '%s'!" msgstr "Konnte Eingabedatei '%s' nicht kopieren!" #: src/program/OutfitStudio.cpp:1618 #, c-format msgid "Failed to copy data file '%s'!" msgstr "Konnte Datendatei '%s' nicht kopieren!" #: src/program/OutfitStudio.cpp:1628 src/program/OutfitStudio.cpp:1786 #, c-format msgid "Failed to save merged project file '%s'!" msgstr "Konnte zusammengefügte Projektdatei '%s' nicht speichern!" #: src/program/OutfitStudio.cpp:1637 src/program/OutfitStudio.cpp:1795 #, c-format msgid "Failed to open project file '%s'!" msgstr "Konnte Projektdatei '%s' nicht öffnen!" #: src/program/OutfitStudio.cpp:1648 #, c-format msgid "Failed to copy merged project file '%s'!" msgstr "Konnte zusammengefügte Projektdatei '%s' nicht kopieren!" #: src/program/OutfitStudio.cpp:1659 src/program/OutfitStudio.cpp:1821 #, c-format msgid "Failed to open group file '%s'!" msgstr "Konnte Gruppendatei '%s' nicht öffnen!" #: src/program/OutfitStudio.cpp:1671 #, c-format msgid "Failed to copy group file '%s'!" msgstr "Konnte Gruppendatei '%s' nicht kopieren!" #: src/program/OutfitStudio.cpp:1677 src/program/OutfitStudio.cpp:1843 msgid "Packing finished." msgstr "Packen abgeschlossen." #: src/program/OutfitStudio.cpp:1681 src/program/OutfitStudio.cpp:1686 msgid "Packing projects to archive..." msgstr "Projekte in ein Archiv packen..." #: src/program/OutfitStudio.cpp:1718 src/program/OutfitStudio.cpp:1769 #: src/program/OutfitStudio.cpp:1803 src/program/OutfitStudio.cpp:1830 msgid "Failed to put new entry into archive!" msgstr "Konnte keinen neuen Eintrag im Archiv erstellen!" #: src/program/OutfitStudio.cpp:1725 src/program/OutfitStudio.cpp:1776 #: src/program/OutfitStudio.cpp:1810 src/program/OutfitStudio.cpp:1837 msgid "Failed to copy file contents to archive!" msgstr "Konnte Dateiinhalt nicht in Archiv kopieren!" #: src/program/OutfitStudio.cpp:1761 #, c-format msgid "Failed to open data file '%s'!" msgstr "Konnte Datendatei '%s' nicht öffnen!" #: src/program/OutfitStudio.cpp:2112 src/program/OutfitStudio.cpp:2161 #: src/program/OutfitStudio.cpp:3745 src/program/OutfitStudio.cpp:3752 #: src/program/OutfitStudio.cpp:4744 src/program/OutfitStudio.cpp:4770 #: src/program/OutfitStudio.cpp:7338 src/program/OutfitStudio.cpp:7465 #: src/program/OutfitStudio.cpp:7580 src/program/OutfitStudio.cpp:7822 #: src/program/OutfitStudio.cpp:7840 src/program/OutfitStudio.cpp:7858 msgid "There are no valid shapes loaded!" msgstr "Es sind keine gültigen Modelle geladen!" #: src/program/OutfitStudio.cpp:2120 src/program/OutfitStudio.cpp:2303 #, c-format msgid "Saving project '%s'..." msgstr "Speichere Projekt '%s'..." #: src/program/OutfitStudio.cpp:2147 src/program/OutfitStudio.cpp:2328 msgid "Saving failed." msgstr "Speichern fehlgeschlagen." #: src/program/OutfitStudio.cpp:2152 src/program/OutfitStudio.cpp:2323 msgid "Saved." msgstr "Gespeichert." #: src/program/OutfitStudio.cpp:2247 msgid "Invalid or no slider set file specified! Please try again." msgstr "" "Ungültige oder keine Slider Set Datei angegeben! Bitte versuche es erneut." #: src/program/OutfitStudio.cpp:2256 msgid "No outfit name specified! Please try again." msgstr "Kein Outfitname angegeben! Bitte versuche es erneut." #: src/program/OutfitStudio.cpp:2264 msgid "No data folder specified! Please try again." msgstr "Kein Daten-Ordner angegeben! Bitte versuche es erneut." #: src/program/OutfitStudio.cpp:2278 msgid "" "An invalid or no base outfit .nif file name specified! Please try again." msgstr "" "Ungültige oder keine Basis Outfit NIF-Datei angegeben! Bitte versuche es " "erneut." #: src/program/OutfitStudio.cpp:2287 msgid "No game file path specified! Please try again." msgstr "Kein Spiel Dateipfad angegeben! Bitte versuche es erneut." #: src/program/OutfitStudio.cpp:2293 msgid "No game file name specified! Please try again." msgstr "Kein Spiel Dateinamen angegeben! Bitte versuche es erneut." #: src/program/OutfitStudio.cpp:2340 #, c-format msgid "Failed to open '%s' as a slider set file!" msgstr "Konnte '%s' nicht als Slider Set Datei öffnen!" #: src/program/OutfitStudio.cpp:2340 src/program/OutfitStudio.cpp:2404 msgid "Slider Set Error" msgstr "Slider Set Fehler" #: src/program/OutfitStudio.cpp:2359 msgid "Please choose an outfit to load" msgstr "Wählen Sie bitte ein Outfit zum Laden" #: src/program/OutfitStudio.cpp:2359 msgid "Load a slider set" msgstr "Lade ein Slider Set" #: src/program/OutfitStudio.cpp:2370 msgid "Loading project..." msgstr "Lade Projekt..." #: src/program/OutfitStudio.cpp:2390 msgid "Loading outfit data..." msgstr "Lade Outfit-Daten..." #: src/program/OutfitStudio.cpp:2404 #, c-format msgid "Failed to create project '%s' from file '%s' (%d)!" msgstr "Konnte Projekt '%s' nicht aus Datei '%s' erstellen (%d)!" #: src/program/OutfitStudio.cpp:2418 #, c-format msgid "Loading reference shape '%s'..." msgstr "Lade Referenzmodell '%s'..." #: src/program/OutfitStudio.cpp:2432 msgid "Loading textures..." msgstr "Lade Texturen..." #: src/program/OutfitStudio.cpp:2437 src/program/OutfitStudio.cpp:3590 #: src/program/OutfitStudio.cpp:3835 msgid "Creating outfit..." msgstr "Erstelle Outfit..." #: src/program/OutfitStudio.cpp:2441 src/program/OutfitStudio.cpp:3600 #: src/program/OutfitStudio.cpp:3735 #, c-format msgid "Creating %zu slider(s)..." msgstr "Erstelle %zu Slider..." #: src/program/OutfitStudio.cpp:2460 msgid "Creating sliders..." msgstr "Erstelle Slider..." #: src/program/OutfitStudio.cpp:2463 msgid "Clearing old sliders..." msgstr "Lösche alte Slider..." #: src/program/OutfitStudio.cpp:2474 msgid "Loading slider: " msgstr "Lade Slider: " #: src/program/OutfitStudio.cpp:2534 src/program/OutfitStudio.cpp:7981 msgid "Enter a name for the new slider:" msgstr "Geben Sie einen Namen für den neuen Slider ein:" #: src/program/OutfitStudio.cpp:2534 src/program/OutfitStudio.cpp:7981 msgid "Create New Slider" msgstr "Neuen Slider erstellen" #: src/program/OutfitStudio.cpp:2668 #, c-format msgid "Total Bones: %zu" msgstr "Bones insgesamt: %zu" #: src/program/OutfitStudio.cpp:2683 #, c-format msgid "Shape Selection Bones: %zu" msgstr "Bones Modellauswahl: %zu" #: src/program/OutfitStudio.cpp:3183 msgid "Edit Color" msgstr "Farbe bearbeiten" #: src/program/OutfitStudio.cpp:3349 msgid "" "You are trying to edit a slider's morph with that slider set to zero. Do " "you wish to set the slider to one now?" msgstr "" "Sie versuchen einen Slider auf 0% zu bearbeiten. Soll dieser auf 100% " "gesetzt werden?" #: src/program/OutfitStudio.cpp:3366 msgid "" "You can only use the undiff brush while editing a slider. Note, use the " "pencil button next to a slider to enable editing of that slider's morph." msgstr "" "Sie können den Undiff Pinsel nur verwenden, während ein Slider bearbeitet " "wird. Der Pinsel-Knopf neben jedem Slider kann den Bearbeitungsmodus dieses " "aktivieren." #: src/program/OutfitStudio.cpp:3377 msgid "" "You can only edit the base shape when all sliders are zero. Do you wish to " "set all sliders to zero now? Note, use the pencil button next to a slider " "to enable editing of that slider's morph." msgstr "" "Sie können das Basismodell nur bearbeiten, wenn alle Slider auf Null sind. " "Möchtest du jetzt alle Slider auf Null setzen? Der Pinsel-Knopf neben jedem " "Slider kann den Bearbeitungsmodus dieses aktivieren." #: src/program/OutfitStudio.cpp:3456 #, c-format msgid "You have unsaved changes to '%s'. Would you like to save them now?" msgstr "" "Es gibt ungespeicherte Änderungen an '%s'. Möchten Sie diese speichern?" #: src/program/OutfitStudio.cpp:3457 msgid "Unsaved Changes" msgstr "Ungespeicherte Änderungen" #: src/program/OutfitStudio.cpp:3512 #, c-format msgid "Creating project '%s'..." msgstr "Erstelle Projekt '%s'..." #: src/program/OutfitStudio.cpp:3529 src/program/OutfitStudio.cpp:3673 msgid "Loading reference..." msgstr "Lade Referenz..." #: src/program/OutfitStudio.cpp:3569 src/program/OutfitStudio.cpp:3793 #: src/program/OutfitStudio.cpp:3802 msgid "Loading outfit..." msgstr "Lade Outfit..." #: src/program/OutfitStudio.cpp:3615 msgid "Select a slider set to load" msgstr "Wählen Sie ein Slider Set zum Laden" #: src/program/OutfitStudio.cpp:3632 msgid "Select a slider set to add" msgstr "Wählen Sie ein Slider Set zum Hinzufügen" #: src/program/OutfitStudio.cpp:3649 src/program/OutfitStudio.cpp:3757 #: src/program/OutfitStudio.cpp:9267 src/program/OutfitStudio.cpp:9322 #: src/program/OutfitStudio.cpp:9413 src/program/OutfitStudio.cpp:9536 msgid "" "You're currently editing slider data, please exit the slider's edit mode " "(pencil button) and try again." msgstr "" "Sie bearbeiten im Moment Sliderdaten. Bitte verlassen Sie den " "Bearbeitungsmodus des Sliders (Pinsel-Knopf) und versuchen es erneut." #: src/program/OutfitStudio.cpp:3679 msgid "Loading reference set..." msgstr "Lade Referenz-Set..." #: src/program/OutfitStudio.cpp:3731 msgid "Creating reference..." msgstr "Erstelle Referenz..." #: src/program/OutfitStudio.cpp:3845 msgid "Unload the project? All unsaved changes will be lost" msgstr "" "Wollen Sie das Projekt wirklich entladen? Alle nicht gespeicherten " "Änderungen gehen verloren" #: src/program/OutfitStudio.cpp:3845 msgid "Unload Project" msgstr "Projekt entladen" #: src/program/OutfitStudio.cpp:3846 msgid "Unload" msgstr "Entladen" #: src/program/OutfitStudio.cpp:4318 msgid "Import NIF file" msgstr "NIF-Datei importieren" #: src/program/OutfitStudio.cpp:4325 src/program/OutfitStudio.cpp:4326 msgid "Importing NIF file..." msgstr "Importiere NIF-Datei..." #: src/program/OutfitStudio.cpp:4348 msgid "Export outfit NIF" msgstr "Outfit NIF exportieren" #: src/program/OutfitStudio.cpp:4366 #, c-format msgid "Failed to save NIF file '%s'!" msgstr "Konnte NIF-Datei '%s' nicht speichern!" #: src/program/OutfitStudio.cpp:4366 src/program/OutfitStudio.cpp:4398 #: src/program/OutfitStudio.cpp:4483 src/program/OutfitStudio.cpp:4608 #: src/program/OutfitStudio.cpp:4832 msgid "Export Error" msgstr "Export Fehler" #: src/program/OutfitStudio.cpp:4382 msgid "Export project NIF" msgstr "Projekt NIF exportieren" #: src/program/OutfitStudio.cpp:4398 #, c-format msgid "Failed to save NIF file '%s' with reference!" msgstr "Konnte NIF-Datei '%s' mit Referenz nicht speichern!" #: src/program/OutfitStudio.cpp:4404 src/program/OutfitStudio.cpp:4489 #: src/program/OutfitStudio.cpp:4614 src/program/OutfitStudio.cpp:4749 #: src/program/OutfitStudio.cpp:4775 src/program/OutfitStudio.cpp:7267 #: src/program/OutfitStudio.cpp:7292 src/program/OutfitStudio.cpp:7313 #: src/program/OutfitStudio.cpp:7585 src/program/OutfitStudio.cpp:7692 #: src/program/OutfitStudio.cpp:7717 src/program/OutfitStudio.cpp:7753 #: src/program/OutfitStudio.cpp:7786 src/program/OutfitStudio.cpp:7885 #: src/program/OutfitStudio.cpp:7936 src/program/OutfitStudio.cpp:8029 #: src/program/OutfitStudio.cpp:8046 src/program/OutfitStudio.cpp:8428 #: src/program/OutfitStudio.cpp:8447 src/program/OutfitStudio.cpp:8531 #: src/program/OutfitStudio.cpp:8555 src/program/OutfitStudio.cpp:8593 #: src/program/OutfitStudio.cpp:8745 src/program/OutfitStudio.cpp:8934 #: src/program/OutfitStudio.cpp:9086 src/program/OutfitStudio.cpp:9262 #: src/program/OutfitStudio.cpp:9317 src/program/OutfitStudio.cpp:9531 #: src/program/OutfitStudio.cpp:9617 src/program/OutfitStudio.cpp:10156 #: src/program/OutfitStudio.cpp:10247 src/program/OutfitStudio.cpp:10340 #: src/program/OutfitStudio.cpp:10385 src/program/OutfitStudio.cpp:10430 #: src/program/OutfitStudio.cpp:10481 src/program/OutfitStudio.cpp:10732 #: src/program/OutfitStudio.cpp:10782 src/program/OutfitStudio.cpp:10889 #: src/program/OutfitStudio.cpp:11031 src/program/OutfitStudio.cpp:11115 #: src/program/OutfitStudio.cpp:14209 msgid "There is no shape selected!" msgstr "Es ist kein Modell ausgewählt!" #: src/program/OutfitStudio.cpp:4411 msgid "Export selected shapes to NIF" msgstr "Ausgewählten Modelle als NIF-Datei exportieren" #: src/program/OutfitStudio.cpp:4423 msgid "Failed to export selected shapes to NIF file!" msgstr "Konnte ausgewählte Modelle nicht als NIF-Datei exportieren!" #: src/program/OutfitStudio.cpp:4428 msgid "Import .obj file for new shape" msgstr "OBJ-Datei mit neuem Modell importieren" #: src/program/OutfitStudio.cpp:4466 msgid "" "Some of the shapes have coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the OBJ? (This is not recommended.)" msgstr "" #: src/program/OutfitStudio.cpp:4468 src/program/OutfitStudio.cpp:4503 #: src/program/OutfitStudio.cpp:4593 src/program/OutfitStudio.cpp:4628 msgid "Transform to global" msgstr "Nach Globalkoordinaten transformieren" #: src/program/OutfitStudio.cpp:4475 msgid "Export project as an .obj file" msgstr "Projekt als OBJ-Datei exportieren" #: src/program/OutfitStudio.cpp:4483 src/program/OutfitStudio.cpp:4525 #: src/program/OutfitStudio.cpp:4544 src/program/OutfitStudio.cpp:7813 msgid "Failed to export OBJ file!" msgstr "Konnte OBJ-Datei nicht exportieren!" #: src/program/OutfitStudio.cpp:4501 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the OBJ?" msgstr "" #: src/program/OutfitStudio.cpp:4512 msgid "Export selected shapes as an .obj file" msgstr "Ausgewählte Modelle als OBJ-Datei exportieren" #: src/program/OutfitStudio.cpp:4529 msgid "Export shape as an .obj file" msgstr "Modell als OBJ-Datei exportieren" #: src/program/OutfitStudio.cpp:4550 msgid "Import .fbx file for new shape" msgstr "FBX-Datei mit neuem Modell importieren" #: src/program/OutfitStudio.cpp:4591 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the FBX? (This is not recommended.)" msgstr "" #: src/program/OutfitStudio.cpp:4600 msgid "Export project as an .fbx file" msgstr "Projekt als FBX-Datei exportieren" #: src/program/OutfitStudio.cpp:4608 src/program/OutfitStudio.cpp:4650 #: src/program/OutfitStudio.cpp:4669 msgid "Failed to export FBX file!" msgstr "Konnte FBX-Datei nicht exportieren!" #: src/program/OutfitStudio.cpp:4626 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the FBX?" msgstr "" #: src/program/OutfitStudio.cpp:4637 msgid "Export selected shapes as an .fbx file" msgstr "Ausgewählte Modelle als FBX-Datei exportieren" #: src/program/OutfitStudio.cpp:4654 msgid "Export shape as an .fbx file" msgstr "Modell als FBX-Datei exportieren" #: src/program/OutfitStudio.cpp:4675 src/program/OutfitStudio.cpp:7469 msgid "Import .tri morphs" msgstr "TRI-Morphs importieren" #: src/program/OutfitStudio.cpp:4694 src/program/OutfitStudio.cpp:7478 msgid "Failed to load TRI file!" msgstr "Konnte TRI-Datei nicht importieren!" #: src/program/OutfitStudio.cpp:4700 src/program/OutfitStudio.cpp:8537 msgid "Please enter a new unique name for the shape." msgstr "Bitte geben Sie einen neuen, einzigartigen Namen für das Modell ein." #: src/program/OutfitStudio.cpp:4700 src/program/OutfitStudio.cpp:8537 msgid "Rename Shape" msgstr "Modell umbenennen" #: src/program/OutfitStudio.cpp:4753 src/program/OutfitStudio.cpp:4779 #: src/program/OutfitStudio.cpp:7844 msgid "Export .tri morphs" msgstr "TRI-Morphs exportieren" #: src/program/OutfitStudio.cpp:4763 src/program/OutfitStudio.cpp:4786 #: src/program/OutfitStudio.cpp:7851 msgid "Failed to export TRI file!" msgstr "Konnte TRI-Datei nicht exportieren!" #: src/program/OutfitStudio.cpp:4791 msgid "Import physics data to project" msgstr "Physikdaten in Projekt importieren" #: src/program/OutfitStudio.cpp:4798 #, c-format msgid "Failed to import physics data file '%s'!" msgstr "Konnte Physikdaten-Datei '%s' nicht importieren!" #: src/program/OutfitStudio.cpp:4798 msgid "Import Error" msgstr "Import Fehler" #: src/program/OutfitStudio.cpp:4810 msgid "There is no physics data loaded!" msgstr "Es sind keine Physikdaten geladen!" #: src/program/OutfitStudio.cpp:4810 src/program/OutfitStudio.cpp:6553 #: src/program/OutfitStudio.cpp:7254 msgid "Info" msgstr "Info" #: src/program/OutfitStudio.cpp:4818 msgid "Please choose the physics data source you want to export." msgstr "Wählen Sie die Physikdaten-Quelle, die Sie exportieren möchten." #: src/program/OutfitStudio.cpp:4818 msgid "Choose physics data" msgstr "Physikdaten wählen" #: src/program/OutfitStudio.cpp:4826 msgid "Export physics data" msgstr "Physikdaten exportieren" #: src/program/OutfitStudio.cpp:4832 #, c-format msgid "Failed to save physics data file '%s'!" msgstr "Konnte Physikdaten-Datei '%s' nicht speichern!" #: src/program/OutfitStudio.cpp:4839 msgid "This function requires at least one slider position to be non-zero." msgstr "" "Diese Funktion benötigt mindestens einen Slider, der nicht auf Null steht." #: src/program/OutfitStudio.cpp:4851 msgid "" "Create a conversion slider for the current slider settings with the " "following name: " msgstr "" "Einen Konvertierungs-Slider für die aktuellen Sliderwerte mit folgendem " "Namen erstellen: " #: src/program/OutfitStudio.cpp:4851 msgid "Create New Conversion Slider" msgstr "Neuen Konvertierungs-Slider erstellen" #: src/program/OutfitStudio.cpp:5601 msgid "Please enter an SSF file path." msgstr "Bitte geben Sie einen SSF-Dateipfad an." #: src/program/OutfitStudio.cpp:6398 #, c-format msgid "Field of View: %d" msgstr "Sichtfeld: %d" #: src/program/OutfitStudio.cpp:6528 msgid "Your changes were not applied yet. Do you want to apply or reset them?" msgstr "" "Ihre Änderungen wurden noch nicht angewandt. Wollen Sie diese anwenden oder " "zurücksetzen?" #: src/program/OutfitStudio.cpp:6529 msgid "Pending Changes" msgstr "Ungespeicherte Änderungen" #: src/program/OutfitStudio.cpp:6553 msgid "" "You must have exactly one mesh selected in order to edit partitions or " "segments." msgstr "" #: src/program/OutfitStudio.cpp:7203 msgid "There are no sliders loaded!" msgstr "Es sind keine Slider geladen!" #: src/program/OutfitStudio.cpp:7254 msgid "No changes were made to the sliders, so no preset was saved!" msgstr "" "Es wurden keine Veränderungen an Slidern vorgenommen, daher wurde auch kein " "Preset gespeichert!" #: src/program/OutfitStudio.cpp:7271 src/program/OutfitStudio.cpp:7296 #: src/program/OutfitStudio.cpp:7317 src/program/OutfitStudio.cpp:7696 msgid "There is no slider in edit mode to import data to!" msgstr "" "Es ist kein Slider im Bearbeitungsmodus, für den man Daten importieren " "könnte!" #: src/program/OutfitStudio.cpp:7275 msgid "Import .nif file for slider calculation" msgstr "NIF-Datei zur Sliderberechnung importieren" #: src/program/OutfitStudio.cpp:7282 msgid "No mesh found in the .nif file that matches currently selected shape!" msgstr "" "Anzahl an Vertices des Modells in der NIF-Datei stimmt nicht mit dem derzeit " "ausgewählten Modell überein!" #: src/program/OutfitStudio.cpp:7300 msgid "Import .bsd slider data" msgstr "BSD Sliderdaten importieren" #: src/program/OutfitStudio.cpp:7321 msgid "Import .obj file for slider calculation" msgstr "OBJ-Datei zur Sliderberechnung importieren" #: src/program/OutfitStudio.cpp:7328 src/program/OutfitStudio.cpp:7707 msgid "Vertex count of .obj file mesh does not match currently selected shape!" msgstr "" "Anzahl an Vertices des Modells in der OBJ-Datei stimmt nicht mit dem derzeit " "ausgewählten Modell überein!" #: src/program/OutfitStudio.cpp:7342 msgid "Import .osd file" msgstr "OSD-Datei importieren" #: src/program/OutfitStudio.cpp:7351 msgid "Failed to import OSD file!" msgstr "Konnte OSD-Datei nicht importieren!" #: src/program/OutfitStudio.cpp:7391 src/program/OutfitStudio.cpp:7501 #: src/program/OutfitStudio.cpp:7627 msgid "This will delete all loaded sliders. Are you sure?" msgstr "Dies löscht alle geladenen Slider. Sind Sie sich sicher?" #: src/program/OutfitStudio.cpp:7391 src/program/OutfitStudio.cpp:7460 msgid "OSD Import" msgstr "OSD Import" #: src/program/OutfitStudio.cpp:7460 src/program/OutfitStudio.cpp:7575 #: src/program/OutfitStudio.cpp:7687 #, c-format msgid "" "Added morphs for the following shapes:\n" "\n" "%s" msgstr "" "Für die folgenden Modelle wurden Morphs hinzugefügt:\n" "\n" "%s" #: src/program/OutfitStudio.cpp:7501 src/program/OutfitStudio.cpp:7575 msgid "TRI Import" msgstr "TRI Import" #: src/program/OutfitStudio.cpp:7589 msgid "Import Starfield morph.dat file" msgstr "Starfield morph.dat-Datei importieren" #: src/program/OutfitStudio.cpp:7598 msgid "Failed to import Starfield morph file!" msgstr "Konnte Starfield morph.dat-Datei nicht importieren!" #: src/program/OutfitStudio.cpp:7627 src/program/OutfitStudio.cpp:7687 msgid "Starfield Morph Import" msgstr "Starfield Morph-Import" #: src/program/OutfitStudio.cpp:7700 msgid "Import .fbx file for slider calculation" msgstr "FBX-Datei zur Sliderberechnung importieren" #: src/program/OutfitStudio.cpp:7721 src/program/OutfitStudio.cpp:7757 #: src/program/OutfitStudio.cpp:7790 msgid "There is no slider in edit mode to export data from!" msgstr "" "Es ist kein Slider im Bearbeitungsmodus, von dem man Daten exportieren " "könnte!" #: src/program/OutfitStudio.cpp:7726 msgid "Export .nif slider data to directory" msgstr "NIF Sliderdaten in Verzeichnis exportieren" #: src/program/OutfitStudio.cpp:7737 msgid "Export .nif slider data" msgstr "NIF Sliderdaten exportieren" #: src/program/OutfitStudio.cpp:7744 msgid "Failed to export NIF file!" msgstr "Konnte NIF-Datei nicht exportieren!" #: src/program/OutfitStudio.cpp:7762 msgid "Export .bsd slider data to directory" msgstr "BSD Sliderdaten in Verzeichnis exportieren" #: src/program/OutfitStudio.cpp:7773 msgid "Export .bsd slider data" msgstr "BSD Sliderdaten exportieren" #: src/program/OutfitStudio.cpp:7795 src/program/OutfitStudio.cpp:7862 msgid "Export .obj slider data to directory" msgstr "OBJ Sliderdaten in Verzeichnis exportieren" #: src/program/OutfitStudio.cpp:7806 msgid "Export .obj slider data" msgstr "OBJ Sliderdaten exportieren" #: src/program/OutfitStudio.cpp:7826 msgid "Export .osd file" msgstr "OSD-Datei exportieren" #: src/program/OutfitStudio.cpp:7833 msgid "Failed to export OSD file!" msgstr "Konnte OSD-Datei nicht exportieren!" #: src/program/OutfitStudio.cpp:7891 msgid "" "Are you sure you wish to clear the unmasked slider data for the selected " "shapes? This action cannot be undone." msgstr "" "Sind Sie sich sicher, dass Sie die unmaskierten Slider-Daten löschen " "wollen? Dies kann nicht rückgängig gemacht werden." #: src/program/OutfitStudio.cpp:7892 src/program/OutfitStudio.cpp:7897 msgid "Confirm data erase" msgstr "Datenlöschung bestätigen" #: src/program/OutfitStudio.cpp:7895 #, c-format msgid "" "Are you sure you wish to clear the unmasked slider data for the shape '%s'? " "This action cannot be undone." msgstr "" "Sind Sie sich sicher, dass Sie die unmaskierten Slider-Daten für das Modell " "'%s' löschen wollen? Dies kann nicht rückgängig gemacht werden." #: src/program/OutfitStudio.cpp:7950 msgid "Enter a name for the new zap:" msgstr "Gib einen Namen für den neuen Zap ein:" #: src/program/OutfitStudio.cpp:7950 msgid "Create New Zap" msgstr "Neuen Zap erstellen" #: src/program/OutfitStudio.cpp:7997 msgid "There is no slider in edit mode to clone!" msgstr "" "Es befindet sich kein Slider im Bearbeitungsmodus, der dupliziert werden " "könnte!" #: src/program/OutfitStudio.cpp:8013 msgid "Enter a name for the cloned slider:" msgstr "Geben Sie einen Namen für den duplizierten Slider ein:" #: src/program/OutfitStudio.cpp:8033 msgid "There is no slider in edit mode to negate!" msgstr "" "Es befindet sich kein Slider im Bearbeitungsmodus, den man negieren könnte!" #: src/program/OutfitStudio.cpp:8050 msgid "There is no slider in edit mode to create a mask from!" msgstr "" "Es befindet sich kein Slider im Bearbeitungsmodus, aus dem man eine Maske " "erstellen könnte!" #: src/program/OutfitStudio.cpp:8060 msgid "Are you sure you wish to delete the selected slider(s)?" msgstr "Sind Sie sich sicher, dass Sie die ausgewählten Slider löschen wollen?" #: src/program/OutfitStudio.cpp:8061 msgid "Confirm slider delete" msgstr "Sliderlöschung bestätigen" #: src/program/OutfitStudio.cpp:8261 msgid "There is no slider in edit mode to show properties for!" msgstr "" "Es befindet sich kein Slider im Bearbeitungsmodus, für den man Eigenschaften " "anzeigen könnte!" #: src/program/OutfitStudio.cpp:8274 src/program/OutfitStudio.cpp:8318 msgid "Conforming: " msgstr "Übertrage: " #: src/program/OutfitStudio.cpp:8305 msgid "Conforming shapes..." msgstr "Übertrage auf Modelle..." #: src/program/OutfitStudio.cpp:8329 msgid "All shapes conformed." msgstr "Auf alle Modelle übertragen." #: src/program/OutfitStudio.cpp:9291 msgid "Are you sure you wish to delete parts of the selected shapes?" msgstr "" "Sind Sie sich sicher, dass Sie Teile des ausgewählten Modells löschen wollen?" #: src/program/OutfitStudio.cpp:9291 src/program/OutfitStudio.cpp:9621 msgid "Confirm Delete" msgstr "Löschen bestätigen" #: src/program/OutfitStudio.cpp:9333 msgid "Please enter a unique name for the new separated shape." msgstr "" "Bitte geben Sie einen einzigartigen Namen für das neu aufgeteilte Modell ein." #: src/program/OutfitStudio.cpp:9333 msgid "Separate Vertices..." msgstr "Vertices aufteilen..." #: src/program/OutfitStudio.cpp:9383 msgid "No errors found!" msgstr "Keine Fehler gefunden!" #: src/program/OutfitStudio.cpp:9389 msgid "Errors:" msgstr "Fehler:" #: src/program/OutfitStudio.cpp:9391 msgid "Target must be different from source." msgstr "Ziel muss sich von der Quelle unterscheiden." #: src/program/OutfitStudio.cpp:9393 msgid "" "Partitions do not match. Make sure the amount of partitions and their slots " "match up." msgstr "" "Partitionen stimmen nicht überein. Bitte stellen Sie sicher, dass die Anzahl " "und Slots der Partitionen übereinstimmen." #: src/program/OutfitStudio.cpp:9395 msgid "" "Segments do not match. Make sure the amount of segments, sub segments and " "their info as well as the segmentation file match." msgstr "" "Segmente stimmen nicht überein. Bitte stellen Sie sicher, dass die Anzahl " "und Informationen der Segmente und Untersegmente übereinstimmen." #: src/program/OutfitStudio.cpp:9397 msgid "Resulting shape would have too many vertices." msgstr "Entstehendes Modell hätte zu viele Vertices." #: src/program/OutfitStudio.cpp:9399 msgid "Resulting shape would have too many triangles." msgstr "Entstehendes Modell hätte zu viele Triangles." #: src/program/OutfitStudio.cpp:9401 msgid "" "Shaders do not match. Make sure both shapes either have or don't have a " "shader and their shader type matches." msgstr "" "Shader stimmen nicht überein. Bitte stellen Sie sicher, dass beide Modelle " "entweder einen Shader haben oder nicht haben und deren Shadertyp " "übereinstimmt." #: src/program/OutfitStudio.cpp:9403 msgid "" "Base texture doesn't match. Make sure both shapes have the same base/diffuse " "texture path." msgstr "" "Basistextur stimmt nicht überein. Bitte stellen Sie sicher, dass beide " "Modelle den selben Basis-/Diffuse-Texturpfad besitzen." #: src/program/OutfitStudio.cpp:9405 msgid "" "Alpha property mismatch. Make sure both shapes either have or don't have an " "alpha property and their flags + threshold match." msgstr "" "Alpha-Property stimmt nicht überein. Bitte stellen Sie sicher, dass beide " "Modelle entweder eine Alpha-Property haben oder nicht haben und deren Flags " "+ Threshold übereinstimmt." #: src/program/OutfitStudio.cpp:9492 msgid "" "You can only copy shapes into an outfit, and there is no outfit in the " "current project. Load one first!" msgstr "" "Sie können nur Modelle in ein Outfit kopieren, und im Moment ist keines im " "Projekte. Laden Sie zuerst eines!" #: src/program/OutfitStudio.cpp:9499 msgid "Please enter a unique name for the duplicated shape." msgstr "" "Bitte geben Sie einen einzigartigen Namen für das duplizierte Modell ein." #: src/program/OutfitStudio.cpp:9499 msgid "Duplicate Shape" msgstr "Modell duplizieren" #: src/program/OutfitStudio.cpp:9541 msgid "There is more than one shape selected." msgstr "Es ist mehr als ein Modell ausgewählt." #: src/program/OutfitStudio.cpp:9596 msgid "" "An edge has multiple triangles of the same orientation. Correct the " "orientations before splitting." msgstr "" "Eine Kante ist mit mehrere Triangles derselben Ausrichtung verbunden. " "Korrigieren Sie die Ausrichtung vor dem Aufteilen." #: src/program/OutfitStudio.cpp:9612 msgid "" "Can't delete shape while in slider edit mode. Use CTRL+Delete to delete " "sliders instead." msgstr "" #: src/program/OutfitStudio.cpp:9621 msgid "" "Are you sure you wish to delete the selected shapes? This action cannot be " "undone." msgstr "" "Sind Sie sich sicher, dass Sie die ausgewählten Modelle löschen wollen? " "Dies kann nicht rückgängig gemacht werden." #: src/program/OutfitStudio.cpp:9785 msgid "No bone name was entered!" msgstr "Es wurde kein Bone-Name eingegeben!" #: src/program/OutfitStudio.cpp:9793 src/program/OutfitStudio.cpp:9834 #, c-format msgid "Bone '%s' already exists in the project!" msgstr "Bone '%s' existiert bereits im Projekt!" #: src/program/OutfitStudio.cpp:9892 msgid "View Standard Bone" msgstr "Standard-Bone anzeigen" #: src/program/OutfitStudio.cpp:9903 msgid "Edit Custom Bone" msgstr "Benutzerdefinierten Bone bearbeiten" #: src/program/OutfitStudio.cpp:9986 msgid "" "The following shapes have unweighted vertices, which can cause issues. The " "affected vertices have been put under a mask. Do you want to save anyway?" msgstr "" "Die folgenden Modelle haben Vertices ohne Weighting, was Probleme " "verursachen kann. Die betroffenen Vertices wurden unter eine Maske versetzt. " "Trotzdem speichern?" #: src/program/OutfitStudio.cpp:9989 msgid "Unweighted Vertices" msgstr "Vertices ohne Weighting" #: src/program/OutfitStudio.cpp:10161 src/program/OutfitStudio.cpp:10252 #: src/program/OutfitStudio.cpp:10346 src/program/OutfitStudio.cpp:10486 msgid "There is no reference shape!" msgstr "Es ist kein Referenz-Modell vorhanden!" #: src/program/OutfitStudio.cpp:10170 src/program/OutfitStudio.cpp:10320 msgid "" "Sorry, you can't copy weights from the reference shape to itself. Skipping " "this shape." msgstr "" "Sie können leider kein Weighting vom Referenzmodell auf es selbst kopieren. " "Überspringe dieses Modell." #: src/program/OutfitStudio.cpp:10170 src/program/OutfitStudio.cpp:10320 msgid "Can't copy weights" msgstr "Weighting kann nicht kopiert werden" #: src/program/OutfitStudio.cpp:10290 msgid "Copying selected bone weights..." msgstr "Kopieren ausgewähltes Bone-Weighting..." #: src/program/OutfitStudio.cpp:10351 msgid "Sorry, you can't copy weights from the reference shape to itself." msgstr "" "Sie können leider kein Weighting vom Referenzmodell auf es selbst kopieren." #: src/program/OutfitStudio.cpp:10358 msgid "The vertex count of the reference and chosen shape is not the same!" msgstr "" "Die Anzahl an Vertices in der Referenz und dem gewählten Modell stimmt nicht " "überein!" #: src/program/OutfitStudio.cpp:10495 msgid "" "Sorry, you can't copy partitions/segments from the reference shape to " "itself. Skipping this shape." msgstr "" "Sie können leider keine Partitionen/Segmente vom Referenzmodell auf es " "selbst kopieren. Überspringe dieses Modell." #: src/program/OutfitStudio.cpp:10495 msgid "Can't copy segments/partitions" msgstr "Kann Segmente/Partitionen nicht kopieren" #: src/program/OutfitStudio.cpp:10500 msgid "" "Triangles will be assigned to the partition/segment of the nearest triangle " "in the reference. Existing partitions/segments are cleared. This action " "can't be undone." msgstr "" #: src/program/OutfitStudio.cpp:10500 msgid "Copy Partitions/Segments" msgstr "Partitionen/Segmente kopieren" #: src/program/OutfitStudio.cpp:10509 msgid "Copying segments/partitions..." msgstr "Kopiere Segments/Partitionen..." #: src/program/OutfitStudio.cpp:10520 #, c-format msgid "" "The partitions/segments could not be copied for '%s' because %d triangles " "could not be matched." msgstr "" #: src/program/OutfitStudio.cpp:10571 msgid " sliders" msgstr " Slider" #: src/program/OutfitStudio.cpp:10573 msgid " bones" msgstr " Bones" #: src/program/OutfitStudio.cpp:10709 msgid "Symmetrize Vertices" msgstr "Vertices symmetrisieren" #: src/program/OutfitStudio.cpp:10711 msgid "" "Eliminates the selected asymmetries from unmasked vertices by adjusting " "vertex data to be consistent with mirror vertices." msgstr "" #: src/program/OutfitStudio.cpp:10713 msgid "" " (Hint: To choose which non-selected bones are adjusted during weight " "normalization, unlock them in the bones list in the Bones tab.)" msgstr "" #: src/program/OutfitStudio.cpp:10717 msgid "Vertices that will be symmetrized:" msgstr "Vertices, die symmetrisiert werden:" #: src/program/OutfitStudio.cpp:10718 msgid "&Symmetrize" msgstr "&Symmetrisieren" #: src/program/OutfitStudio.cpp:10875 #, c-format msgid "%d unreferenced nodes were deleted." msgstr "%d unreferenzierte Nodes wurden entfernt." #: src/program/OutfitStudio.cpp:11173 msgid "Please enter a new unique name for the mask." msgstr "Bitte geben Sie einen neuen, einzigartigen Namen für die Maske ein." #: src/program/OutfitStudio.cpp:11173 msgid "New Mask" msgstr "Neue Maske" #: src/program/OutfitStudio.cpp:11358 msgid "Reset all bone poses?" msgstr "Pose aller Bones zurücksetzen?" #: src/program/OutfitStudio.cpp:11358 msgid "Reset Pose" msgstr "Pose zurücksetzen" #: src/program/OutfitStudio.cpp:11509 msgid "Please enter a new unique name for the pose." msgstr "Bitte geben Sie einen neuen, einzigartigen Namen für die Pose ein." #: src/program/OutfitStudio.cpp:11509 msgid "New Pose" msgstr "Neue Pose" #: src/program/OutfitStudio.cpp:11560 #, c-format msgid "Are you sure you wish to delete the pose '%s'?" msgstr "Sind Sie sich sicher, dass Sie die Pose '%s' löschen wollen?" #: src/program/OutfitStudio.cpp:11561 msgid "Confirm pose delete" msgstr "Posenlöschung bestätigen" #: src/program/OutfitStudio.cpp:12499 msgid "The vertex picked has more than three connections." msgstr "Das gewählte Vertex hat mehr als drei Verbindungen." #: src/program/OutfitStudio.cpp:12734 msgid "" "Neither the selected nor target vertices are on the mesh boundary. It is " "recommended that you only weld or merge boundary vertices. Continue?" msgstr "" #: src/program/OutfitStudio.cpp:12735 msgid "" "The selected vertex is not on the mesh boundary. It is recommended that you " "only weld or merge boundary vertices. Continue?" msgstr "" #: src/program/OutfitStudio.cpp:12736 msgid "" "The target vertex is not on the mesh boundary. It is recommended that you " "only weld or merge boundary vertices. Continue?" msgstr "" #: src/program/OutfitStudio.cpp:12737 msgid "Weld/Merge Non-Boundary Vertices" msgstr "" #: src/program/OutfitStudio.cpp:12819 msgid "The edge picked is on the surface boundary. Pick an interior edge." msgstr "" "Die ausgewählte Kante ist am Oberflächenrand. Wählen Sie eine innere Kante." #: src/program/OutfitStudio.cpp:12873 msgid "" "The edge picked has multiple triangles of the same orientation. Correct the " "orientations before splitting." msgstr "" "Die ausgewählte Kante hat mehrere Triangles mit der selben Ausrichtung. " "Bitte korrigieren Sie die Ausrichtung vor der Aufteilung." #: src/program/OutfitStudio.cpp:14220 src/program/OutfitStudio.cpp:14221 msgid "Loading slider file..." msgstr "Lade Slider-Datei..." #: src/program/PreviewWindow.cpp:39 msgid "Show the Normal Map Generator dialog." msgstr "Zeige den Normal Map Generator-Dialog." #: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:33 msgid "Preview failed: OpenGL context is not OK." msgstr "Vorschau fehlgeschlagen: OpenGL-Kontext ist nicht OK." #: src/program/ShapeProperties.cpp:104 msgid "Material" msgstr "Material" #: src/program/ShapeProperties.cpp:117 #, c-format msgid "%zu shapes selected" msgstr "%zu Modelle ausgewählt" #: src/program/ShapeProperties.cpp:132 #, c-format msgid "This action will affect all %zu selected shapes. Are you sure?" msgstr "" "Diese Aktion betrifft alle %zu ausgewählten Modelle. Sind Sie sich sicher?" #: src/program/ShapeProperties.cpp:133 msgid "Confirmation" msgstr "Bestätigung" #: src/program/ShapeProperties.cpp:135 msgid "Yes" msgstr "Ja" #: src/program/ShapeProperties.cpp:135 msgid "No" msgstr "Nein" #: src/program/ShapeProperties.cpp:352 msgid "Choose material file" msgstr "Material-Datei auswählen" #: src/program/ShapeProperties.cpp:662 msgid "Please choose a shape to copy from" msgstr "Bitte wählen Sie ein Modell für die Kopie aus" #: src/program/ShapeProperties.cpp:662 msgid "Choose shape" msgstr "Modell auswählen" #: src/ui/wxBrushSettingsPopup.cpp:133 msgid "Size" msgstr "Größe" #: src/ui/wxBrushSettingsPopup.cpp:137 msgid "Shortcut: 'S' + mouse wheel" msgstr "Tastaturkürzel: 'S' + Mausrad" #: src/ui/wxBrushSettingsPopup.cpp:146 msgid "Strength" msgstr "Stärke" #: src/ui/wxBrushSettingsPopup.cpp:158 msgid "Focus" msgstr "Fokus" #: src/ui/wxBrushSettingsPopup.cpp:170 msgid "Spacing" msgstr "Abstand" #: src/ui/wxSliderPanel.cpp:63 msgid "Turn on edit mode for this slider." msgstr "Schalte den Bearbeitungsmodus dieses Sliders an." #: src/ui/wxSliderPanel.cpp:75 msgid "Weaken slider data by 1%." msgstr "Sliderdaten um 1% abschwächen." #: src/ui/wxSliderPanel.cpp:82 msgid "Strengthen slider data by 1%." msgstr "Sliderdaten um 1% verstärken." #~ msgid "Mirror" #~ msgstr "Spiegeln" #~ msgid "Mirror the selected shapes on the Y-axis." #~ msgstr "Spiegelt die ausgewählten Modelle auf der Y-Achse." #~ msgid "Mirror the selected shapes on the Z-axis." #~ msgstr "Spiegelt die ausgewählten Modelle auf der Z-Achse." #~ msgid "Group Filter" #~ msgstr "Gruppenfilter" #~ msgid "Outfit Filter" #~ msgstr "Outfitfilter" ================================================ FILE: lang/el/BodySlide.mo ================================================ ================================================ FILE: lang/el/BodySlide.po ================================================ ================================================ FILE: lang/es/BodySlide.mo ================================================ ================================================ FILE: lang/es/BodySlide.po ================================================ ================================================ FILE: lang/eu/BodySlide.mo ================================================ ================================================ FILE: lang/eu/BodySlide.po ================================================ ================================================ FILE: lang/fi/BodySlide.mo ================================================ ================================================ FILE: lang/fi/BodySlide.po ================================================ ================================================ FILE: lang/fr/BodySlide.po ================================================ msgid "" msgstr "" "Project-Id-Version: BodySlide\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" "Language: fr_FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.0\n" "X-Poedit-KeywordsList: _\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:410 msgid "About" msgstr "À propos" #: res/xrc/About.xrc:145 res/xrc/GroupManager.xrc:189 msgid "Close" msgstr "Fermer" #: res/xrc/Actions.xrc:6 msgid "Apply a vertex position" msgstr "Appliquez une position de vertex" #: res/xrc/Actions.xrc:15 msgid "This permanently moves a single vertex straight to the given location." msgstr "" "Cela déplace en permanence un seul vertex directement vers l'emplacement " "donné." #: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499 #: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:741 res/xrc/Actions.xrc:891 #: res/xrc/Actions.xrc:1170 res/xrc/Actions.xrc:1271 res/xrc/BatchBuild.xrc:103 #: res/xrc/EditUV.xrc:32 res/xrc/FBXImport.xrc:45 res/xrc/Project.xrc:712 #: res/xrc/Project.xrc:891 res/xrc/Settings.xrc:410 #: res/xrc/ShapeProperties.xrc:755 res/xrc/Skeleton.xrc:36 #: res/xrc/Skeleton.xrc:232 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238 msgid "&OK" msgstr "&D'accord" #: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506 #: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:748 res/xrc/Actions.xrc:898 #: res/xrc/Actions.xrc:1177 res/xrc/Actions.xrc:1278 res/xrc/BatchBuild.xrc:57 #: res/xrc/BatchBuild.xrc:110 res/xrc/EditUV.xrc:39 res/xrc/FBXImport.xrc:52 #: res/xrc/Project.xrc:546 res/xrc/Project.xrc:719 res/xrc/Project.xrc:898 #: res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:417 res/xrc/Setup.xrc:273 #: res/xrc/ShapeProperties.xrc:762 res/xrc/Skeleton.xrc:43 #: res/xrc/Skeleton.xrc:239 res/xrc/Slider.xrc:71 res/xrc/Slider.xrc:246 msgid "&Cancel" msgstr "&Annuler" #: res/xrc/Actions.xrc:110 msgid "Move Shape" msgstr "Bougez la Forme" #: res/xrc/Actions.xrc:254 msgid "Mirror Axis" msgstr "Axe Miroir" #: res/xrc/Actions.xrc:320 msgid "Scale Shape" msgstr "Échelle la Forme" #: res/xrc/Actions.xrc:329 msgid "" "Scaling will adjust the size of a mesh. This permanently affects vertices." msgstr "" "La mise à l'échelle ajustera la taille d'un maillage. Cela affecte en " "permanence les vertices." #: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667 #: res/xrc/ShapeProperties.xrc:635 res/xrc/Skeleton.xrc:133 msgid "Origin" msgstr "Origine" #: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678 msgid "Zero (0, 0, 0)" msgstr "Zéro (0, 0, 0)" #: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679 msgid "Center of selected shapes(s)" msgstr "Centre de formes sélectionnées(s)" #: res/xrc/Actions.xrc:484 msgid "Uniform (XYZ)" msgstr "Uniforme (XYZ)" #: res/xrc/Actions.xrc:517 msgid "Rotate Shape" msgstr "Tournez la Forme" #: res/xrc/Actions.xrc:711 msgid "Set Shape Textures" msgstr "Définir les Textures des Formes" #: res/xrc/Actions.xrc:758 res/xrc/OutfitStudio.xrc:2031 #: res/xrc/OutfitStudio.xrc:2394 msgid "Copy Bone Weights" msgstr "Copier les poids des os" #: res/xrc/Actions.xrc:767 msgid "" "Each vertex of the reference will copy its weights to the nearest collection " "of vertices within the given radius. Bear in mind that some geometry will " "always require manual tweaking to become weighted and work well. Often, the " "default values are sufficient." msgstr "" "Chaque vertex de la référence copiera ses poids dans la collection de " "vertices la plus proche dans le rayon donné. Gardez à l'esprit que certaines " "géométries nécessiteront toujours des ajustements manuels pour devenir " "pondérées et fonctionner correctement. Souvent, les valeurs par défaut sont " "suffisantes." #: res/xrc/Actions.xrc:787 res/xrc/Actions.xrc:937 msgid "Search Radius" msgstr "Rayon de Recherche" #: res/xrc/Actions.xrc:816 res/xrc/Actions.xrc:966 msgid "Max Vertex Targets" msgstr "Max Vertex Cibles" #: res/xrc/Actions.xrc:847 res/xrc/Actions.xrc:995 msgid "No Target Limit" msgstr "Aucune Limite Cible" #: res/xrc/Actions.xrc:856 msgid "" "The skin coordinate system doesn't match the reference shape's. Do you want " "to copy the transforms?" msgstr "" "Le système de coordonnées cutanées ne correspond pas à la forme de " "référence. Voulez-vous copier les transformations?" #: res/xrc/Actions.xrc:866 msgid "Copy skin transform from reference" msgstr "Copie de la transformation de la peau à partir de la référence" #: res/xrc/Actions.xrc:876 res/xrc/ShapeProperties.xrc:730 msgid "Recalculate geometry's coordinates so it doesn't move" msgstr "Recalculer les coordonnées de la géométrie pour qu’elle ne bouge pas" #: res/xrc/Actions.xrc:877 res/xrc/ShapeProperties.xrc:731 msgid "" "Transform geometry so its position in global coordinates does not change." msgstr "" "Transformez la géométrie de sorte que sa position dans les coordonnées " "globales ne change pas." #: res/xrc/Actions.xrc:908 msgid "Conforming..." msgstr "Conforme..." #: res/xrc/Actions.xrc:917 msgid "" "Each vertex of the reference will copy its slider data to the nearest " "collection of vertices within the given radius. Bear in mind that some " "geometry will always require manual tweaking to become conformed and work " "well. Often, the default values are sufficient." msgstr "" "Chaque vertex de la référence copiera ses données de slider dans la " "collection de vertices la plus proche dans le rayon donné. Gardez à l'esprit " "que certaines géométries nécessiteront toujours des ajustements manuels pour " "devenir pondérées et fonctionner correctement. Souvent, les valeurs par " "défaut sont suffisantes." #: res/xrc/Actions.xrc:1018 msgid "No Squeeze" msgstr "Aucune Pression" #: res/xrc/Actions.xrc:1041 msgid "Solid Mode" msgstr "Mode Solide" #: res/xrc/Actions.xrc:1064 msgid "Axis" msgstr "L'Axe" #: res/xrc/Actions.xrc:1114 res/xrc/BodySlide.xrc:97 #: res/xrc/NormalsGenDlg.xrc:191 msgid "Preset" msgstr "Préréglage" #: res/xrc/Actions.xrc:1130 msgid "Default" msgstr "Valeurs par Défaut" #: res/xrc/Actions.xrc:1139 msgid "Even Movement" msgstr "Même Mouvement" #: res/xrc/Actions.xrc:1148 msgid "Solid Object" msgstr "Objet Solide" #: res/xrc/Actions.xrc:1187 msgid "Copy Geometry" msgstr "Copier la Géométrie" #: res/xrc/Actions.xrc:1196 msgid "" "This function copies vertices and triangles from one shape to another. " "Partitions/segments of source and target shapes must match. It is the " "user's responsibility to check that all other shape and shader properties " "are compatible, or merging will likely have side effects." msgstr "" "Cette fonction copie les vertices et les triangles d'une forme à une autre. " "Les partitions/segments des formes source et cible doivent correspondre. Il " "est de la responsabilité de l'utilisateur de vérifier que toutes les autres " "propriétés de forme et de shader sont compatibles, ou la fusion aura " "probablement des effets secondaires." #: res/xrc/Actions.xrc:1211 msgid "Source" msgstr "Source" #: res/xrc/Actions.xrc:1229 msgid "Target" msgstr "Cible" #: res/xrc/Actions.xrc:1258 msgid "Delete source shape" msgstr "Effacer la forme source" #: res/xrc/BatchBuild.xrc:6 msgid "Batch Build" msgstr "Construction Par Lots" #: res/xrc/BatchBuild.xrc:21 msgid "" "Select the slider sets for the batch build process. Use the group and outfit " "filters to show the outfits you want!" msgstr "" "Sélectionnez les ensembles de glissières pour le processus de construction " "par lots. Utilisez les filtres de groupe et de tenue pour afficher les " "tenues que vous souhaitez !" #: res/xrc/BatchBuild.xrc:50 msgid "&Build" msgstr "&Construire" #: res/xrc/BatchBuild.xrc:67 src/program/BodySlideApp.cpp:2065 msgid "Choose output set" msgstr "Choisir l'ensemble de sortie" #: res/xrc/BatchBuild.xrc:78 msgid "" "The following sets will override the same files.\n" "Please decide which one to use and select it in the list below." msgstr "" "Les ensembles suivants remplaceront les mêmes fichiers.\n" "Veuillez décider lequel utiliser et sélectionnez-le dans la liste ci-dessous." #: res/xrc/BodySlide.xrc:7 msgid "BodySlide" msgstr "Bodyslide" #: res/xrc/BodySlide.xrc:28 msgid "Outfit/Body" msgstr "Vêtement/Corps" #: res/xrc/BodySlide.xrc:44 msgid "Select an outfit to modify" msgstr "Sélectionnez une tenue à modifier" #: res/xrc/BodySlide.xrc:58 msgid "Deletes a project from its project file" msgstr "Supprime un projet de son fichier de projet" #: res/xrc/BodySlide.xrc:74 msgid "Opens the current project in Outfit Studio" msgstr "Ouvre le projet en cours dans Outfit Studio" #: res/xrc/BodySlide.xrc:113 msgid "Choose from a list of slider settings presets" msgstr "Choisissez parmi une liste de paramètres prédéfinis de slider" #: res/xrc/BodySlide.xrc:127 msgid "Deletes a preset from its preset file" msgstr "Supprime un préréglage de son fichier de préréglage" #: res/xrc/BodySlide.xrc:142 msgid "Saves the new slider values to the currently selected preset" msgstr "" "Enregistre les nouvelles valeurs du slider dans le préréglage actuellement " "sélectionné" #: res/xrc/BodySlide.xrc:143 res/xrc/GroupManager.xrc:44 #: res/xrc/OutfitStudio.xrc:1310 msgid "Save" msgstr "Sauvegarder" #: res/xrc/BodySlide.xrc:152 msgid "Save the current slider settings as a new preset" msgstr "" "Sauvegarder les paramètres actuels du slider comme un nouveau préréglage" #: res/xrc/BodySlide.xrc:153 res/xrc/GroupManager.xrc:53 #: res/xrc/OutfitStudio.xrc:1319 msgid "Save As..." msgstr "Sauvegarder sous..." #: res/xrc/BodySlide.xrc:164 msgid "" "Opens the group manager where you can edit existing or create new groups" msgstr "" "Ouvre le gestionnaire de groupe dans lequel vous pouvez modifier des groupes " "existants ou créer de nouveaux groupes" #: res/xrc/BodySlide.xrc:165 res/xrc/GroupManager.xrc:7 #: res/xrc/Project.xrc:1020 msgid "Group Manager" msgstr "Gerante de Groupe" #: res/xrc/BodySlide.xrc:189 msgid "Single Weight" msgstr "Poids Seul" #: res/xrc/BodySlide.xrc:216 msgid "Low Weight" msgstr "Poids Faible" #: res/xrc/BodySlide.xrc:233 msgid "High Weight" msgstr "Poids Haut" #: res/xrc/BodySlide.xrc:276 msgid "Copy the low weight slider values to the high weight section." msgstr "" "Copiez les valeurs du slider de poids faible dans la section de poids haut." #: res/xrc/BodySlide.xrc:298 msgid "" "Build multiple outfits using the currently active slider values.\n" "\n" "Hold CTRL = Build to custom directory\n" "Hold ALT = Delete from output directory" msgstr "" "Créez plusieurs tenues en utilisant les valeurs du slider actif.\n" "\n" "Maintenir CTRL = Construire dans le répertoire personnalisé\n" "Maintenir ALT = Supprimer du répertoire de sortie" #: res/xrc/BodySlide.xrc:299 msgid "Batch Build..." msgstr "Construction par lots..." #: res/xrc/BodySlide.xrc:314 msgid "Build Morphs" msgstr "Construire des morphes" #: res/xrc/BodySlide.xrc:315 msgid "" "Builds a morphs (.tri) file alongside the meshes for accessing the sliders " "in-game. Requires other mods to make use of the morph data." msgstr "" "Construit un fichier morphs (.tri) à côté des maillages pour accéder aux " "sliders dans le jeu. Nécessite d'autres mods pour utiliser les données de " "morphing." #: res/xrc/BodySlide.xrc:325 msgid "Force Body Normals" msgstr "Obliger Normales du Corps" #: res/xrc/BodySlide.xrc:326 msgid "" "Adds normal and tangent data to the body meshes (including bodies within " "outfits) for Skyrim. Use this only if you have a tangent space body mod." msgstr "" "Ajoute des données normales et tangentes aux maillages corporels (y compris " "les corps dans les tenues) pour Skyrim. Utilisez ceci uniquement si vous " "avez un mod de corps d'espace tangent." #: res/xrc/BodySlide.xrc:349 msgid "Show a preview window for this outfit." msgstr "Afficher une fenêtre d'aperçu pour cette tenue." #: res/xrc/BodySlide.xrc:350 res/xrc/NormalsGenDlg.xrc:166 #: src/program/PreviewWindow.cpp:28 msgid "Preview" msgstr "Aperçu" #: res/xrc/BodySlide.xrc:367 msgid "" "Creates the currently selected outfit/body.\n" "\n" "Hold CTRL = Build to working directory\n" "Hold ALT = Delete from output directory" msgstr "" "Crée la tenue/corps actuellement sélectionnée.\n" "\n" "Maintenir CTRL = Construire dans le répertoire de travail\n" "Maintenir ALT = Supprimer du répertoire de sortie" #: res/xrc/BodySlide.xrc:368 msgid "Build" msgstr "Construire" #: res/xrc/BodySlide.xrc:387 msgid "Copy the high weight slider values to the low weight section." msgstr "" "Copiez les valeurs du slider de poids haut dans la section de poids faible." #: res/xrc/BodySlide.xrc:419 res/xrc/OutfitStudio.xrc:1820 msgid "Open settings dialog." msgstr "Ouvrez la boîte de dialogue des paramètres." #: res/xrc/BodySlide.xrc:420 res/xrc/OutfitStudio.xrc:1819 #: res/xrc/Settings.xrc:5 msgid "Settings" msgstr "Paramètres" #: res/xrc/BodySlide.xrc:429 msgid "" "Open Outfit Studio, a full-featured tool for creating and converting outfits." msgstr "" "Ouvrez Outfit Studio, un outil complet pour créer et convertir des tenues." #: res/xrc/BodySlide.xrc:430 res/xrc/OutfitStudio.xrc:7 msgid "Outfit Studio" msgstr "Outfit Studio" #: res/xrc/BodySlide.xrc:442 res/xrc/BodySlide.xrc:453 msgid "Filter Options" msgstr "Options de filtre" #: res/xrc/BodySlide.xrc:444 msgid "Choose groups..." msgstr "Choisissez des groupes..." #: res/xrc/BodySlide.xrc:445 msgid "Choose groups to display in the Outfit menu" msgstr "Choisissez les groupes à afficher dans le menu Outfit" #: res/xrc/BodySlide.xrc:448 msgid "Refresh Groups" msgstr "Rafraîchir les groupes" #: res/xrc/BodySlide.xrc:449 msgid "Refresh group information" msgstr "Rafraîchir les informations du groupe" #: res/xrc/BodySlide.xrc:455 msgid "Save Outfit list as group..." msgstr "Sauvegarder la liste des tenues comme groupe..." #: res/xrc/BodySlide.xrc:456 msgid "Save the current filtered outfit list as a group" msgstr "Sauvegarder la liste de tenues filtrée actuelle en tant que groupe" #: res/xrc/BodySlide.xrc:459 msgid "Refresh Outfits" msgstr "Rafraîchir les tenues" #: res/xrc/BodySlide.xrc:460 msgid "Reloads outfit list" msgstr "Recharge la liste des tenues" #: res/xrc/BodySlide.xrc:465 res/xrc/Project.xrc:1037 msgid "Select None" msgstr "Ne sélectionnez aucun" #: res/xrc/BodySlide.xrc:468 res/xrc/EditUV.xrc:110 res/xrc/Project.xrc:1040 msgid "Select All" msgstr "Sélectionnez tout" #: res/xrc/BodySlide.xrc:471 res/xrc/EditUV.xrc:114 res/xrc/Project.xrc:1043 msgid "Invert Selection" msgstr "Sélection d'inversion" #: res/xrc/EditUV.xrc:5 msgid "Edit UV" msgstr "Modifiez UV" #: res/xrc/EditUV.xrc:52 msgid "Box Selection" msgstr "Sélection de Boîtes" #: res/xrc/EditUV.xrc:53 msgid "" "Box Selection\n" "Shortcut: 1" msgstr "" "Sélection de Boîtes\n" "Raccourci: 1" #: res/xrc/EditUV.xrc:60 msgid "Vertex Selection" msgstr "Sélection de Vertex" #: res/xrc/EditUV.xrc:61 msgid "" "Vertex Selection\n" "Shortcut: 2" msgstr "" "Sélection de Vertex\n" "Raccourci: 2" #: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:63 #: res/xrc/OutfitStudio.xrc:2203 msgid "Move" msgstr "Bougez" #: res/xrc/EditUV.xrc:68 msgid "" "Move\n" "Shortcut: 3" msgstr "" "Bougez\n" "Raccourci: 3" #: res/xrc/EditUV.xrc:74 res/xrc/ShapeProperties.xrc:596 #: src/program/NormalsGenDialog.cpp:320 msgid "Scale" msgstr "Échelle" #: res/xrc/EditUV.xrc:75 msgid "" "Scale\n" "Shortcut: 4" msgstr "" "Échelle\n" "Raccourci: 4" #: res/xrc/EditUV.xrc:81 msgid "Rotate" msgstr "Rotation" #: res/xrc/EditUV.xrc:82 msgid "" "Rotate\n" "Shortcut: 5" msgstr "" "Rotation\n" "Raccourci: 5" #: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89 msgid "Show Seam Edges" msgstr "Afficher les Bords de Couture" #: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1714 msgid "Menu" msgstr "Menu" #: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1828 msgid "Edit" msgstr "Modifiez" #: res/xrc/EditUV.xrc:101 res/xrc/OutfitStudio.xrc:1830 msgid "Undo\tCtrl+Z" msgstr "Annulez\tCtrl+Z" #: res/xrc/EditUV.xrc:102 res/xrc/OutfitStudio.xrc:1831 msgid "Undo the previous action." msgstr "Annulez l'action précédente." #: res/xrc/EditUV.xrc:105 res/xrc/OutfitStudio.xrc:1834 msgid "Redo\tCtrl+Y" msgstr "Refaire\tCtrl+Y" #: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:1835 msgid "Redo the next undone action." msgstr "Refaire l'action suivante non effectuée." #: res/xrc/EditUV.xrc:109 msgid "Select All\tCtrl+A" msgstr "Sélectionnez tout\tCtrl+A" #: res/xrc/EditUV.xrc:113 msgid "Invert Selection\tCtrl+I" msgstr "Sélection d'inversion\tCtrl+I" #: res/xrc/EditUV.xrc:117 msgid "Select Less\tA" msgstr "Sélectionnez moins\tA" #: res/xrc/EditUV.xrc:118 msgid "Select less adjacent points in the selected islands." msgstr "Sélectionnez moins de points adjacents dans les îles sélectionnées." #: res/xrc/EditUV.xrc:121 msgid "Select More\tD" msgstr "Sélectionnez plus\tD" #: res/xrc/EditUV.xrc:122 msgid "Select more adjacent points in the selected islands." msgstr "Sélectionnez plus de points adjacents dans les îles sélectionnées." #: res/xrc/FBXImport.xrc:6 msgid "FBX Import Options..." msgstr "Options d'importation FBX..." #: res/xrc/FBXImport.xrc:21 msgid "Invert U" msgstr "Inversez U" #: res/xrc/FBXImport.xrc:30 msgid "Invert V" msgstr "Inversez V" #: res/xrc/GroupManager.xrc:17 msgid "" "Choose a group and add or remove members by selecting them in the lists." msgstr "" "Choisissez un groupe et ajoutez ou supprimez des membres en les " "sélectionnant dans les listes." #: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:952 msgid "Select a group XML file" msgstr "Sélectionnez un fichier XML de groupe" #: res/xrc/GroupManager.xrc:71 msgid "Groups" msgstr "Groupes" #: res/xrc/GroupManager.xrc:101 msgid "Add Group" msgstr "Ajouter le groupe" #: res/xrc/GroupManager.xrc:110 msgid "Remove Group" msgstr "Supprimer le groupe" #: res/xrc/GroupManager.xrc:122 msgid "Members" msgstr "Membres" #: res/xrc/GroupManager.xrc:137 msgid "Remove >>" msgstr "Supprimer>>" #: res/xrc/GroupManager.xrc:151 msgid "Outfits" msgstr "Tenues" #: res/xrc/GroupManager.xrc:172 msgid "<< Add" msgstr "<< Ajouter" #: res/xrc/NormalsGenDlg.xrc:6 msgid "Normal Map Generator" msgstr "Normal Map Generator" #: res/xrc/NormalsGenDlg.xrc:21 msgid "Layers" msgstr "Couches" #: res/xrc/NormalsGenDlg.xrc:37 msgid "Load or save preset layer settings." msgstr "Chargez ou enregistrez les paramètres de couche prédéfinis." #: res/xrc/NormalsGenDlg.xrc:61 msgid "Add a new layer after the current one in the layer list." msgstr "" "Ajoutez un nouveau calque après le calque actuel dans la liste des calques." #: res/xrc/NormalsGenDlg.xrc:62 msgid "Add Layer" msgstr "Ajouter une Couche" #: res/xrc/NormalsGenDlg.xrc:71 msgid "Move selected layer up one position." msgstr "Déplacer le calque sélectionné d'une position vers le haut." #: res/xrc/NormalsGenDlg.xrc:72 msgid "Move Up" msgstr "Déplacer vers le haut" #: res/xrc/NormalsGenDlg.xrc:87 msgid "Delete the selected layer." msgstr "Effacez la couche sélectionnée." #: res/xrc/NormalsGenDlg.xrc:88 msgid "Delete Layer" msgstr "Effacez une Couche" #: res/xrc/NormalsGenDlg.xrc:108 res/xrc/Slider.xrc:161 msgid "Options" msgstr "Options" #: res/xrc/NormalsGenDlg.xrc:114 msgid "" "Save a copy of an existing normal map if one already exists. File is saved " "in the original directory." msgstr "" "Enregistrez une copie d'une carte normale existante s'il en existe déjà une. " "Le fichier est enregistré dans le répertoire d'origine." #: res/xrc/NormalsGenDlg.xrc:115 msgid "Backup destination file" msgstr "Fichier de destination de la sauvegarde" #: res/xrc/NormalsGenDlg.xrc:124 msgid "" "Compress output file using BC7 compression. This can make saving the file " "take a VERY long time!" msgstr "" "Compressez le fichier de sortie à l'aide de la compression BC7. Cela peut " "rendre l'enregistrement du fichier TRÈS long!" #: res/xrc/NormalsGenDlg.xrc:125 msgid "Compress output " msgstr "Compressez la sortie " #: res/xrc/NormalsGenDlg.xrc:134 msgid "" "Use the file name specified in the background layer to save the normal map." msgstr "" "Utilisez le nom de fichier spécifié dans la couche de fond pour enregistrer " "la carte normale." #: res/xrc/NormalsGenDlg.xrc:135 msgid "Save to background layer file" msgstr "Enregistrer dans le fichier de la couche de fond" #: res/xrc/NormalsGenDlg.xrc:145 msgid "Choose an output file..." msgstr "Choisissez le fichier de sortie..." #: res/xrc/NormalsGenDlg.xrc:149 msgid "Location to save normal map to." msgstr "Emplacement où enregistrer la carte normale." #: res/xrc/NormalsGenDlg.xrc:165 msgid "Display current settings on mesh in preview window." msgstr "" "Affiche les paramètres actuels sur le maillage dans la fenêtre d'aperçu." #: res/xrc/NormalsGenDlg.xrc:181 msgid "Generate and save the normal map file." msgstr "Générez et enregistrez le fichier de carte normale." #: res/xrc/NormalsGenDlg.xrc:182 msgid "Generate" msgstr "Générez" #: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2073 msgid "Load Preset..." msgstr "Chargez le préréglage..." #: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2077 msgid "Save Preset..." msgstr "Sauvegarder le préréglage..." #: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5 msgid "New Project" msgstr "Nouveau Projet" #: res/xrc/OutfitStudio.xrc:23 msgid "" "Create a new project by selecting a reference body slider set, and outfit " "model files." msgstr "" "Créez un nouveau projet en sélectionnant un jeu de slider de corps de " "référence et des fichiers de modèles d'équipement." #: res/xrc/OutfitStudio.xrc:28 msgid "Load Project" msgstr "Chargez Projet" #: res/xrc/OutfitStudio.xrc:29 msgid "Load a previously created slider set for editing." msgstr "Chargez un jeu de slider précédemment créé pour l'éditer." #: res/xrc/OutfitStudio.xrc:34 res/xrc/OutfitStudio.xrc:2182 msgid "Select" msgstr "Sélectionnez" #: res/xrc/OutfitStudio.xrc:35 res/xrc/OutfitStudio.xrc:2183 msgid "Navigate and select meshes (or vertices in vertex mode)." msgstr "Naviguez et sélectionnez des mailles (ou des vertices en mode vertex)." #: res/xrc/OutfitStudio.xrc:42 res/xrc/OutfitStudio.xrc:2187 #: src/program/NormalsGenDialog.cpp:311 msgid "Mask" msgstr "Masque" #: res/xrc/OutfitStudio.xrc:43 res/xrc/OutfitStudio.xrc:2188 msgid "" "Mask vertices to prevent them from being transformed.\n" "Hold down the ALT key to remove masking." msgstr "" "Masque les vertices pour éviter qu'ils ne soient transformés.\n" "Maintenez la touche ALT enfoncée pour supprimer le masquage." #: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2192 msgid "Inflate" msgstr "Augmentez" #: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2193 msgid "Increase mesh volume in an area." msgstr "Augmentez le volume de la maille dans une zone." #: res/xrc/OutfitStudio.xrc:56 res/xrc/OutfitStudio.xrc:2198 msgid "Deflate" msgstr "Diminuez" #: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2199 msgid "Decrease mesh volume in an area." msgstr "Diminuer le volume de la maille dans une zone." #: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2204 msgid "Move vertices over a plane parallel to the view." msgstr "Déplace les vertices sur un plan parallèle à la vue." #: res/xrc/OutfitStudio.xrc:70 res/xrc/OutfitStudio.xrc:2208 msgid "Smooth" msgstr "Lissez" #: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2209 msgid "Smooth an area of a mesh." msgstr "Lisser une zone d'une maille." #: res/xrc/OutfitStudio.xrc:77 res/xrc/OutfitStudio.xrc:2213 msgid "Undiff" msgstr "Undiff" #: res/xrc/OutfitStudio.xrc:78 res/xrc/OutfitStudio.xrc:2214 msgid "Undiff an area of a slider." msgstr "Undiff une zone d'un curseur." #: res/xrc/OutfitStudio.xrc:84 res/xrc/OutfitStudio.xrc:2218 msgid "Weight Paint" msgstr "Peinture de Poids" #: res/xrc/OutfitStudio.xrc:85 msgid "" "Apply animation weight values for currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "Appliquez des valeurs de poids d'animation pour l'os actuellement " "sélectionné.\n" "Maintenez la touche ALT enfoncée pour affaiblir la pondération." #: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2224 msgid "Color Paint" msgstr "Peinture de Couleur" #: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2225 msgid "" "Apply vertex colors.\n" "Hold down the ALT key to remove colors." msgstr "" "Appliquer les couleurs des vertex.\n" "Maintenez la touche ALT enfoncée pour supprimer les couleurs." #: res/xrc/OutfitStudio.xrc:100 res/xrc/OutfitStudio.xrc:2230 msgid "Alpha Paint" msgstr "Peinture de l'Alpha" #: res/xrc/OutfitStudio.xrc:101 res/xrc/OutfitStudio.xrc:2231 msgid "" "Apply vertex alpha.\n" "Hold down the ALT key to remove alpha." msgstr "" "Appliquer l'alpha de vertex.\n" "Maintenez la touche ALT enfoncée pour supprimer l'alpha." #: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2236 msgid "Collapse Vertex" msgstr "Collapse Vertex" #: res/xrc/OutfitStudio.xrc:109 res/xrc/OutfitStudio.xrc:2237 msgid "" "Deletes vertices with no more than three connections, without creating a " "hole." msgstr "" "Supprime les vertices n'ayant pas plus de trois connexions, sans créer de " "trou." #: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2241 msgid "Flip Edge" msgstr "Retourner le Bord" #: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2242 msgid "Flips mesh edges so that the opposite pair of vertices is connected." msgstr "" "Retourne bords de la maille de manière à ce que la paire de vertices opposée " "soit connectée." #: res/xrc/OutfitStudio.xrc:122 res/xrc/OutfitStudio.xrc:2246 msgid "Split Edge" msgstr "Séparer le Bord" #: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2247 msgid "Splits a mesh edge in two with a new vertex." msgstr "Séparer un bord du maillage en deux avec un nouveau vertex." #: res/xrc/OutfitStudio.xrc:134 msgid "Field of View" msgstr "Champ de Vision" #: res/xrc/OutfitStudio.xrc:138 msgid "Field of View: 65" msgstr "Champ de Vision: 65" #: res/xrc/OutfitStudio.xrc:143 msgid "Open Discord invite link." msgstr "Ouvrir le lien d'invitation Discord." #: res/xrc/OutfitStudio.xrc:148 msgid "Open GitHub link." msgstr "Ouvrir le lien GitHub." #: res/xrc/OutfitStudio.xrc:153 msgid "Open PayPal link." msgstr "Ouvrir le lien PayPal." #: res/xrc/OutfitStudio.xrc:174 msgid "Transform" msgstr "Transformez" #: res/xrc/OutfitStudio.xrc:175 res/xrc/OutfitStudio.xrc:2253 msgid "Shows a transform tool to manipulate shapes and vertices with." msgstr "" "Affiche un outil de transformation pour manipuler les formes et les vertices " "avec." #: res/xrc/OutfitStudio.xrc:181 msgid "Pivot" msgstr "Pivot" #: res/xrc/OutfitStudio.xrc:182 res/xrc/OutfitStudio.xrc:2258 msgid "" "Shows a pivot that can be moved and makes it the center of mesh operations " "like rotation and scale." msgstr "" "Affiche un pivot qui peut être déplacé et en fait le centre des opérations " "de maillage comme la rotation et l'échelle." #: res/xrc/OutfitStudio.xrc:188 msgid "Vertex Edit" msgstr "Modifiez Vertex" #: res/xrc/OutfitStudio.xrc:189 msgid "" "Lets you select vertices to add to or remove from the mask.\n" "Click on a vertex to select/unmask it.\n" "Hold down CTRL to unselect/mask it." msgstr "" "Vous permet de sélectionner les vertices à ajouter ou à retirer du masque.\n" "Cliquez sur un vertex pour le sélectionner/démasquer.\n" "Maintenez la touche CTRL enfoncée pour le désélectionner/masquer." #: res/xrc/OutfitStudio.xrc:196 msgid "X Mirror" msgstr "Miroir X" #: res/xrc/OutfitStudio.xrc:197 res/xrc/OutfitStudio.xrc:1840 msgid "Mirror edits across the X axis." msgstr "Miroir des modifications sur l'axe X." #: res/xrc/OutfitStudio.xrc:205 res/xrc/OutfitStudio.xrc:1846 msgid "Edit Connected Only\tC" msgstr "Modifiez connecté uniquement\tC" #: res/xrc/OutfitStudio.xrc:206 msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius." msgstr "" "Modifiez uniquement les vertices connectés à ceux situés sous le pinceau " "dans le rayon de la brosse." #: res/xrc/OutfitStudio.xrc:212 res/xrc/OutfitStudio.xrc:1852 msgid "Global Brush Collision\tB" msgstr "Collision globale de brosses\tB" #: res/xrc/OutfitStudio.xrc:213 msgid "" "Allows for the brushes to collide with all currently selected meshes at the " "same time." msgstr "" "Permet aux brosses d'entrer en collision avec toutes les mailles " "sélectionnées en même temps." #: res/xrc/OutfitStudio.xrc:220 msgid "View Front" msgstr "Voir l'avant" #: res/xrc/OutfitStudio.xrc:221 msgid "Change camera view to the front." msgstr "Changez la vue de la caméra vers l'avant." #: res/xrc/OutfitStudio.xrc:225 msgid "View Back" msgstr "Voir le dos" #: res/xrc/OutfitStudio.xrc:226 msgid "Change camera view to the back." msgstr "Changez la vue de la caméra vers le dos." #: res/xrc/OutfitStudio.xrc:230 msgid "View Left" msgstr "Voir à gauche" #: res/xrc/OutfitStudio.xrc:231 msgid "Change camera view to the left." msgstr "Changez la vue de la caméra vers la gauche." #: res/xrc/OutfitStudio.xrc:235 msgid "View Right" msgstr "Voir à droit" #: res/xrc/OutfitStudio.xrc:236 msgid "Change camera view to the right." msgstr "Changez la vue de la caméra vers la droit." #: res/xrc/OutfitStudio.xrc:240 msgid "Perspective View" msgstr "Voir Perspective" #: res/xrc/OutfitStudio.xrc:241 msgid "Toggle perspective view." msgstr "Basculez la vue en perspective." #: res/xrc/OutfitStudio.xrc:247 msgid "Show Nodes" msgstr "Affichez les Nœuds" #: res/xrc/OutfitStudio.xrc:248 msgid "Toggle rendering of nodes." msgstr "Basculer le rendu des noeuds." #: res/xrc/OutfitStudio.xrc:253 msgid "Show Bones" msgstr "Affichez les Os" #: res/xrc/OutfitStudio.xrc:254 msgid "Toggle rendering of bones." msgstr "Basculer le rendu des os." #: res/xrc/OutfitStudio.xrc:259 msgid "Show Floor" msgstr "Afficher l'Étage" #: res/xrc/OutfitStudio.xrc:260 msgid "Toggle rendering of the floor grid." msgstr "Basculer le rendu de grille l'étage." #: res/xrc/OutfitStudio.xrc:287 msgid "Brush Settings" msgstr "Paramètres des brosses" #: res/xrc/OutfitStudio.xrc:302 msgid "Size" msgstr "Taille" #: res/xrc/OutfitStudio.xrc:332 msgid "Strength" msgstr "Force" #: res/xrc/OutfitStudio.xrc:362 msgid "Focus" msgstr "Concentrer" #: res/xrc/OutfitStudio.xrc:392 msgid "Spacing" msgstr "Espacement" #: res/xrc/OutfitStudio.xrc:469 msgid "Meshes" msgstr "Mailles" #: res/xrc/OutfitStudio.xrc:481 res/xrc/OutfitStudio.xrc:2420 #: res/xrc/OutfitStudio.xrc:2453 msgid "Bones" msgstr "Os" #: res/xrc/OutfitStudio.xrc:493 res/xrc/OutfitStudio.xrc:2467 #: res/xrc/OutfitStudio.xrc:2493 msgid "Segments" msgstr "Segments" #: res/xrc/OutfitStudio.xrc:505 res/xrc/OutfitStudio.xrc:2500 #: res/xrc/OutfitStudio.xrc:2511 msgid "Partitions" msgstr "Partitions" #: res/xrc/OutfitStudio.xrc:517 msgid "Colors" msgstr "Les Couleurs" #: res/xrc/OutfitStudio.xrc:529 msgid "Lights" msgstr "Lumières" #: res/xrc/OutfitStudio.xrc:569 msgid "Total Bones: 0" msgstr "Total des Os: 0" #: res/xrc/OutfitStudio.xrc:579 msgid "Shape Selection Bones: 0" msgstr "Sélection des Formes Os: 0" #: res/xrc/OutfitStudio.xrc:607 msgid "Brush Color" msgstr "Couleur de Brosse" #: res/xrc/OutfitStudio.xrc:616 msgid "Color of the brush." msgstr "La couleur de la brosse." #: res/xrc/OutfitStudio.xrc:628 src/program/OutfitStudio.cpp:2952 #: src/program/OutfitStudio.cpp:6292 msgid "Edit Alpha" msgstr "Modifiez l'Alpha" #: res/xrc/OutfitStudio.xrc:674 res/xrc/OutfitStudio.xrc:1066 #: res/xrc/OutfitStudio.xrc:1167 src/program/OutfitStudio.cpp:5967 #: src/program/OutfitStudio.cpp:9666 msgid "Reset" msgstr "Réinitialiser" #: res/xrc/OutfitStudio.xrc:687 msgid "Ambient" msgstr "Ambiante" #: res/xrc/OutfitStudio.xrc:712 msgid "Frontal" msgstr "Frontale" #: res/xrc/OutfitStudio.xrc:737 msgid "Directional 1" msgstr "Directionnel 1" #: res/xrc/OutfitStudio.xrc:762 msgid "Directional 2" msgstr "Directionnel 2" #: res/xrc/OutfitStudio.xrc:787 msgid "Directional 3" msgstr "Directionnel 3" #: res/xrc/OutfitStudio.xrc:832 res/xrc/OutfitStudio.xrc:1084 #: res/xrc/ShapeProperties.xrc:84 res/xrc/ShapeProperties.xrc:544 msgid "Type" msgstr "Catégorie" #: res/xrc/OutfitStudio.xrc:955 msgid "Slot" msgstr "Fente" #: res/xrc/OutfitStudio.xrc:1018 src/program/OutfitStudio.cpp:5122 msgid "SSF File" msgstr "Fichier SSF" #: res/xrc/OutfitStudio.xrc:1038 msgid "Set" msgstr "Définir" #: res/xrc/OutfitStudio.xrc:1056 res/xrc/OutfitStudio.xrc:1157 #: src/program/OutfitStudio.cpp:5967 src/program/OutfitStudio.cpp:9693 msgid "Apply" msgstr "Appliquez" #: res/xrc/OutfitStudio.xrc:1185 msgid "De-/Select Sliders" msgstr "Dé-/Sélectionnez les sliders" #: res/xrc/OutfitStudio.xrc:1204 msgid "Fixed Weight Brush" msgstr "Brosse de poids fixe" #: res/xrc/OutfitStudio.xrc:1215 msgid "Normalize Weights" msgstr "Normaliser les Poids" #: res/xrc/OutfitStudio.xrc:1232 msgid "X-Mirror Bone" msgstr "Os du Miroir X" #: res/xrc/OutfitStudio.xrc:1257 msgid "Preview Scaling" msgstr "Mise à l'échelle de l'aperçu" #: res/xrc/OutfitStudio.xrc:1284 msgid "Masks" msgstr "Masques" #: res/xrc/OutfitStudio.xrc:1328 res/xrc/OutfitStudio.xrc:2433 msgid "Delete" msgstr "Effacer" #: res/xrc/OutfitStudio.xrc:1344 msgid "Posing" msgstr "Posant" #: res/xrc/OutfitStudio.xrc:1361 msgid "Show Pose" msgstr "Afficher la Pose" #: res/xrc/OutfitStudio.xrc:1379 msgid "Reset Bone" msgstr "Réinitialiser l'Os" #: res/xrc/OutfitStudio.xrc:1399 msgid "Rotation X" msgstr "Rotation X" #: res/xrc/OutfitStudio.xrc:1427 msgid "Rotation Y" msgstr "Rotation Y" #: res/xrc/OutfitStudio.xrc:1455 msgid "Rotation Z" msgstr "Rotation Z" #: res/xrc/OutfitStudio.xrc:1483 msgid "Offset X" msgstr "Décalage X" #: res/xrc/OutfitStudio.xrc:1511 msgid "Offset Y" msgstr "Décalage Y" #: res/xrc/OutfitStudio.xrc:1540 msgid "Offset Z" msgstr "Décalage Z" #: res/xrc/OutfitStudio.xrc:1573 msgid "Reset All" msgstr "Réinitialiser Toute" #: res/xrc/OutfitStudio.xrc:1581 msgid "Apply to Mesh" msgstr "Appliquer à la Maille" #: res/xrc/OutfitStudio.xrc:1716 res/xrc/Settings.xrc:343 #: src/program/NormalsGenDialog.cpp:304 msgid "File" msgstr "Fichier" #: res/xrc/OutfitStudio.xrc:1718 msgid "New Project...\tCtrl+N" msgstr "Nouveau Projet...\tCtrl+N" #: res/xrc/OutfitStudio.xrc:1719 msgid "Create a new outfit project." msgstr "Créez un nouveau projet de tenue." #: res/xrc/OutfitStudio.xrc:1722 msgid "Load Project..\tCtrl+O" msgstr "Chargez le Projet..\tCtrl+O" #: res/xrc/OutfitStudio.xrc:1723 msgid "Load a project." msgstr "Chargez un projet." #: res/xrc/OutfitStudio.xrc:1726 msgid "Add Project..\tCtrl+Shift+O" msgstr "Ajoutez un Projet...\tCtrl+Shift+O" #: res/xrc/OutfitStudio.xrc:1727 msgid "Add a project without replacing the current one." msgstr "Ajouter un projet sans remplacer le projet actuel." #: res/xrc/OutfitStudio.xrc:1730 msgid "Unload Project...\tCtrl+W" msgstr "Déchargez le Projet...\tCtrl+W" #: res/xrc/OutfitStudio.xrc:1731 msgid "Unloads the project and creates an empty new one." msgstr "Décharge le projet et crée un nouveau projet vide." #: res/xrc/OutfitStudio.xrc:1735 msgid "Load Reference..." msgstr "Chargez un référence..." #: res/xrc/OutfitStudio.xrc:1736 msgid "" "Load a new reference slider set, replacing any current reference objects." msgstr "" "Chargez un nouveau slider set de référence, remplaçant tous les objets de " "référence actuels." #: res/xrc/OutfitStudio.xrc:1739 msgid "Load Outfit..." msgstr "Chargez la tenue..." #: res/xrc/OutfitStudio.xrc:1740 msgid "" "Load a NIF file as the working outfit, replacing any current outfit objects." msgstr "" "Chargez un fichier NIF comme tenue de travail, en remplaçant tous les objets " "de la tenue actuelle." #: res/xrc/OutfitStudio.xrc:1744 msgid "Save Project\tCtrl+S" msgstr "Sauvegarder le Projet\tCtrl+S" #: res/xrc/OutfitStudio.xrc:1745 msgid "Save the project." msgstr "Sauvegarder le projet." #: res/xrc/OutfitStudio.xrc:1749 msgid "Save Project As...\tCtrl+Shift+S" msgstr "Sauvegarder le Projet Sous...\tCtrl+Shift+S" #: res/xrc/OutfitStudio.xrc:1750 msgid "Save the project under a new name." msgstr "Sauvegarder le projet sous un nouveau nom." #: res/xrc/OutfitStudio.xrc:1754 src/program/OutfitStudio.cpp:6823 #: src/program/OutfitStudio.cpp:6913 msgid "Import" msgstr "Importez" #: res/xrc/OutfitStudio.xrc:1756 msgid "From NIF..." msgstr "De NIF..." #: res/xrc/OutfitStudio.xrc:1757 msgid "Choose a NIF file to import into the project." msgstr "Choisissez un fichier NIF à importer dans le projet." #: res/xrc/OutfitStudio.xrc:1760 msgid "From OBJ..." msgstr "De OBJ..." #: res/xrc/OutfitStudio.xrc:1761 msgid "Import an OBJ file as a new shape in the outfit." msgstr "Importez un fichier OBJ comme une nouvelle forme dans l'équipement." #: res/xrc/OutfitStudio.xrc:1764 msgid "From FBX..." msgstr "De FBX..." #: res/xrc/OutfitStudio.xrc:1765 msgid "Import an FBX file as a new shape in the outfit." msgstr "Importez un fichier FBX comme une nouvelle forme dans l'équipement." #: res/xrc/OutfitStudio.xrc:1768 msgid "From TRI (Head)..." msgstr "De TRI (Tête)..." #: res/xrc/OutfitStudio.xrc:1769 msgid "Import shape and morphs from a head TRI file." msgstr "Importez des formes et des morphes à partir d'un fichier TRI de tête." #: res/xrc/OutfitStudio.xrc:1772 msgid "Import Data" msgstr "Importez des données" #: res/xrc/OutfitStudio.xrc:1774 msgid "Import BSClothExtraData From HKX" msgstr "Importez BSClothExtraData de HKX" #: res/xrc/OutfitStudio.xrc:1775 msgid "" "Choose an HKX file to import as a BSClothExtraData block into the project." msgstr "" "Choisissez un fichier HKX à importer comme bloc BSClothExtraData dans le " "projet." #: res/xrc/OutfitStudio.xrc:1780 res/xrc/OutfitStudio.xrc:1932 #: res/xrc/OutfitStudio.xrc:2307 msgid "Export" msgstr "Exporter" #: res/xrc/OutfitStudio.xrc:1782 msgid "To NIF...\tCtrl+E" msgstr "Vers NIF...\tCtrl+E" #: res/xrc/OutfitStudio.xrc:1783 msgid "Save the current project as a NIF file (without reference)" msgstr "Sauvegarder le projet en cours comme un fichier NIF (sans référence)" #: res/xrc/OutfitStudio.xrc:1786 msgid "To NIF With Reference...\tCtrl+Alt+E" msgstr "Vers NIF avec Référence...\tCtrl+Alt+E" #: res/xrc/OutfitStudio.xrc:1787 msgid "Save the current project as a NIF file (including reference)" msgstr "" "Sauvegarder le projet en cours comme un fichier NIF (y compris la référence)" #: res/xrc/OutfitStudio.xrc:1790 res/xrc/OutfitStudio.xrc:1938 #: res/xrc/OutfitStudio.xrc:2313 msgid "To OBJ..." msgstr "Vers OBJ..." #: res/xrc/OutfitStudio.xrc:1791 msgid "Export the current project as an OBJ file." msgstr "Exportez le projet en cours sous forme de fichier OBJ." #: res/xrc/OutfitStudio.xrc:1794 res/xrc/OutfitStudio.xrc:1942 #: res/xrc/OutfitStudio.xrc:2317 msgid "To FBX..." msgstr "Vers FBX..." #: res/xrc/OutfitStudio.xrc:1795 msgid "Export the current project as an FBX file." msgstr "Exportez le projet en cours sous forme de fichier FBX." #: res/xrc/OutfitStudio.xrc:1798 res/xrc/OutfitStudio.xrc:1946 #: res/xrc/OutfitStudio.xrc:2321 msgid "To TRI (Head)..." msgstr "Vers TRI (Tête)..." #: res/xrc/OutfitStudio.xrc:1799 res/xrc/OutfitStudio.xrc:1947 #: res/xrc/OutfitStudio.xrc:2322 msgid "Export head morphs to a TRI file." msgstr "Exportez les morphes de tête dans un fichier TRI." #: res/xrc/OutfitStudio.xrc:1802 msgid "Export Data" msgstr "Exporter des données" #: res/xrc/OutfitStudio.xrc:1804 msgid "Export BSClothExtraData As HKX" msgstr "Exporter BSClothExtraData comme HKX" #: res/xrc/OutfitStudio.xrc:1805 msgid "" "Save one of the currently loaded BSClothExtraData blocks to an HKX file." msgstr "" "Sauvegarder l'un des blocs BSClothExtraData actuellement chargés dans un " "fichier HKX." #: res/xrc/OutfitStudio.xrc:1810 msgid "Make Conversion Reference" msgstr "Créer une référence de conversion" #: res/xrc/OutfitStudio.xrc:1811 msgid "" "Using the current slider settings for the reference shape, create a new " "reference that will morph from the current shape back to the base shape." msgstr "" "À l'aide des paramètres de slider actuels pour la forme de référence, créez " "une nouvelle référence qui passera de la forme actuelle à la forme de base." #: res/xrc/OutfitStudio.xrc:1815 res/xrc/Project.xrc:908 msgid "Pack Projects..." msgstr "Emballez des Projets..." #: res/xrc/OutfitStudio.xrc:1816 msgid "Pack one or more projects into a folder or archive for sharing." msgstr "" "Emballez un ou plusieurs projets dans un dossier ou une archive pour les " "partager." #: res/xrc/OutfitStudio.xrc:1823 msgid "Exit\tAlt+F4" msgstr "Sortir\tAlt+F4" #: res/xrc/OutfitStudio.xrc:1824 msgid "Exit Outfit Studio." msgstr "Sortie de l'Outfit Studio." #: res/xrc/OutfitStudio.xrc:1839 msgid "X Mirror\tX" msgstr "Miroir X\tX" #: res/xrc/OutfitStudio.xrc:1847 msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius" msgstr "" "Modifiez uniquement les vertices connectés à ceux situés sous le pinceau " "dans le rayon du pinceau" #: res/xrc/OutfitStudio.xrc:1853 msgid "" "Allows for the brushes to collide with all currently selected meshes at the " "same time" msgstr "" "Permet aux brosses d'entrer en collision avec toutes les mailles " "sélectionnées en même temps" #: res/xrc/OutfitStudio.xrc:1859 msgid "Recalculate Normals\tR" msgstr "Recalculer les normales\tR" #: res/xrc/OutfitStudio.xrc:1860 msgid "Recalculate normals on active mesh" msgstr "Recalculer les normales sur le maillage actif" #: res/xrc/OutfitStudio.xrc:1863 msgid "Reset Transforms" msgstr "Réinitialisation des transformations" #: res/xrc/OutfitStudio.xrc:1864 msgid "Resets the shape and skin transforms." msgstr "Réinitialise la forme et la peau se transforme." #: res/xrc/OutfitStudio.xrc:1867 src/program/OutfitStudio.cpp:9255 msgid "Delete Unreferenced Nodes" msgstr "Effacer les Nœuds Non Référencés" #: res/xrc/OutfitStudio.xrc:1868 msgid "Deletes all nodes from the project that aren't used in any other block." msgstr "" "Effacer tous les nœuds du projet qui ne sont pas utilisés dans un autre bloc." #: res/xrc/OutfitStudio.xrc:1871 msgid "Remove Skinning" msgstr "Supprimer l'Habillage" #: res/xrc/OutfitStudio.xrc:1872 msgid "Removes skinning of all shapes and all unused nodes." msgstr "" "Supprime l'habillage de toutes les formes et de tous les nœuds inutilisés." #: res/xrc/OutfitStudio.xrc:1876 msgid "View" msgstr "Voir" #: res/xrc/OutfitStudio.xrc:1878 msgid "Front\tShift+1" msgstr "Avant\tShift+1" #: res/xrc/OutfitStudio.xrc:1881 msgid "Back\tShift+2" msgstr "Dos\tShift+2" #: res/xrc/OutfitStudio.xrc:1884 msgid "Left\tShift+3" msgstr "Gauche\tShift+3" #: res/xrc/OutfitStudio.xrc:1887 msgid "Right\tShift+4" msgstr "Droit\tShift+4" #: res/xrc/OutfitStudio.xrc:1890 msgid "Perspective\tShift+5" msgstr "Perspective\tShift+5" #: res/xrc/OutfitStudio.xrc:1895 msgid "Show Nodes\tShift+N" msgstr "Affichez les Nœuds\tShift+N" #: res/xrc/OutfitStudio.xrc:1899 msgid "Show Bones\tShift+B" msgstr "Affichez les Os\tShift+B" #: res/xrc/OutfitStudio.xrc:1903 msgid "Show Floor\tG" msgstr "Afficher l'Étage\tG" #: res/xrc/OutfitStudio.xrc:1908 msgid "Toggle Visibility\tE" msgstr "Basculez la visibilité\tE" #: res/xrc/OutfitStudio.xrc:1909 msgid "Switch between the different visibility modes for the selected shapes." msgstr "" "Basculez entre les différents modes de visibilité des formes sélectionnées." #: res/xrc/OutfitStudio.xrc:1912 msgid "Show Wireframe\tW" msgstr "Affichez le filaire\tW" #: res/xrc/OutfitStudio.xrc:1913 msgid "Show wireframe on all models." msgstr "Affichez le filaire sur tous les modèles." #: res/xrc/OutfitStudio.xrc:1917 msgid "Enable Lighting\tL" msgstr "Activer l'éclairage\tL" #: res/xrc/OutfitStudio.xrc:1918 msgid "Turn on or off lighting." msgstr "Allumez ou éteignez l'éclairage." #: res/xrc/OutfitStudio.xrc:1923 msgid "Enable Textures\tT" msgstr "Activer Textures\tT" #: res/xrc/OutfitStudio.xrc:1924 msgid "Display texture maps on models." msgstr "Affichez les cartes de texture sur les modèles." #: res/xrc/OutfitStudio.xrc:1930 res/xrc/OutfitStudio.xrc:2305 msgid "Shape" msgstr "Forme" #: res/xrc/OutfitStudio.xrc:1934 res/xrc/OutfitStudio.xrc:2309 msgid "To NIF..." msgstr "Vers NIF..." #: res/xrc/OutfitStudio.xrc:1935 res/xrc/OutfitStudio.xrc:2310 msgid "Export only the selected shapes to a NIF file." msgstr "Exportez uniquement les formes sélectionnées vers un fichier NIF." #: res/xrc/OutfitStudio.xrc:1939 res/xrc/OutfitStudio.xrc:2314 msgid "Export only the selected shapes to an OBJ file." msgstr "Exporter uniquement les formes sélectionnées vers un fichier OBJ." #: res/xrc/OutfitStudio.xrc:1943 res/xrc/OutfitStudio.xrc:2318 msgid "Export only the selected shapes to an FBX file." msgstr "Exportez uniquement les formes sélectionnées vers un fichier FBX." #: res/xrc/OutfitStudio.xrc:1951 res/xrc/OutfitStudio.xrc:2326 #: res/xrc/Slider.xrc:200 msgid "UV" msgstr "UV" #: res/xrc/OutfitStudio.xrc:1953 res/xrc/OutfitStudio.xrc:2328 msgid "Edit..." msgstr "Modifiez..." #: res/xrc/OutfitStudio.xrc:1954 res/xrc/OutfitStudio.xrc:2329 msgid "Edit the texture coordinates." msgstr "Modifiez les coordonnées de la texture." #: res/xrc/OutfitStudio.xrc:1957 res/xrc/OutfitStudio.xrc:2332 msgid "Invert X" msgstr "Inversez X" #: res/xrc/OutfitStudio.xrc:1958 res/xrc/OutfitStudio.xrc:2333 msgid "Inverts the X-axis of the texture coordinates." msgstr "Inverse l'axe X des coordonnées de la texture." #: res/xrc/OutfitStudio.xrc:1961 res/xrc/OutfitStudio.xrc:2336 msgid "Invert Y" msgstr "Inversez Y" #: res/xrc/OutfitStudio.xrc:1962 res/xrc/OutfitStudio.xrc:2337 msgid "Inverts the Y-axis of the texture coordinates." msgstr "Inverse l'axe Y des coordonnées de la texture." #: res/xrc/OutfitStudio.xrc:1966 res/xrc/OutfitStudio.xrc:2341 msgid "Mirror" msgstr "Miroir" #: res/xrc/OutfitStudio.xrc:1969 res/xrc/OutfitStudio.xrc:2344 msgid "Mirror the selected shapes on the X-axis." msgstr "Miroir les formes sélectionnées sur l'axe X." #: res/xrc/OutfitStudio.xrc:1973 res/xrc/OutfitStudio.xrc:2348 msgid "Mirror the selected shapes on the Y-axis." msgstr "Miroir les formes sélectionnées sur l'axe Y." #: res/xrc/OutfitStudio.xrc:1977 res/xrc/OutfitStudio.xrc:2352 msgid "Mirror the selected shapes on the Z-axis." msgstr "Miroir les formes sélectionnées sur l'axe Z." #: res/xrc/OutfitStudio.xrc:1981 res/xrc/OutfitStudio.xrc:2356 msgid "Delete Vertices...\tShift+Del" msgstr "Effacer Vertices...\tShift+Del" #: res/xrc/OutfitStudio.xrc:1982 res/xrc/OutfitStudio.xrc:2357 msgid "Deletes all unmasked vertices of the currently selected shapes." msgstr "" "Supprime tous les vertices non masqués des formes actuellement sélectionnées." #: res/xrc/OutfitStudio.xrc:1985 res/xrc/OutfitStudio.xrc:2360 #: src/program/OutfitStudio.cpp:8329 msgid "Separate Vertices...\tShift+S" msgstr "Vertices séparés...\tShift+S" #: res/xrc/OutfitStudio.xrc:1986 res/xrc/OutfitStudio.xrc:2361 msgid "Separate the current shape into two by using the mask." msgstr "Séparez la forme actuelle en deux à l'aide du masque." #: res/xrc/OutfitStudio.xrc:1989 res/xrc/OutfitStudio.xrc:2364 msgid "Copy Geometry..." msgstr "Copier la Géométrie..." #: res/xrc/OutfitStudio.xrc:1990 res/xrc/OutfitStudio.xrc:2365 msgid "Copies vertices and triangles from one shape to another." msgstr "Copie les vertices et les triangles d'une forme à une autre." #: res/xrc/OutfitStudio.xrc:1993 res/xrc/OutfitStudio.xrc:2368 msgid "Duplicate..." msgstr "Dupliquez..." #: res/xrc/OutfitStudio.xrc:1994 res/xrc/OutfitStudio.xrc:2369 msgid "Duplicate the current shape." msgstr "Dupliquez la forme actuelle." #: res/xrc/OutfitStudio.xrc:1997 res/xrc/OutfitStudio.xrc:2372 msgid "Rename...\tF2" msgstr "Renommez...\tF2" #: res/xrc/OutfitStudio.xrc:1998 res/xrc/OutfitStudio.xrc:2373 msgid "Change the name of the current shape." msgstr "Change le nom de la forme actuelle." #: res/xrc/OutfitStudio.xrc:2001 res/xrc/OutfitStudio.xrc:2376 msgid "Set Reference" msgstr "Définir la référence" #: res/xrc/OutfitStudio.xrc:2002 res/xrc/OutfitStudio.xrc:2377 msgid "Turn the shape into the reference shape of the project." msgstr "Transformez la forme en forme de référence du projet." #: res/xrc/OutfitStudio.xrc:2006 res/xrc/OutfitStudio.xrc:2381 msgid "Move..." msgstr "Bougez..." #: res/xrc/OutfitStudio.xrc:2007 res/xrc/OutfitStudio.xrc:2382 msgid "" "Apply an offset adjustment to the mesh vertices. This permanently moves " "vertices." msgstr "" "Appliquez un ajustement de décalage aux vertices du maillage. Cela déplace " "définitivement les vertices." #: res/xrc/OutfitStudio.xrc:2010 res/xrc/OutfitStudio.xrc:2385 msgid "Scale..." msgstr "Échelle..." #: res/xrc/OutfitStudio.xrc:2011 res/xrc/OutfitStudio.xrc:2386 msgid "Apply a scale adjustment to the shape. This permanently moves vertices." msgstr "" "Appliquez un ajustement d'échelle à la forme. Cela déplace définitivement " "les vertices." #: res/xrc/OutfitStudio.xrc:2014 res/xrc/OutfitStudio.xrc:2389 msgid "Rotate..." msgstr "Rotation..." #: res/xrc/OutfitStudio.xrc:2015 res/xrc/OutfitStudio.xrc:2390 msgid "Apply a rotation to the mesh vertices. This permanently moves vertices." msgstr "" "Appliquez une rotation aux vertices du maillage. Cela déplace définitivement " "les vertices." #: res/xrc/OutfitStudio.xrc:2018 msgid "Smooth Seam Normals" msgstr "Couture lisse normales" #: res/xrc/OutfitStudio.xrc:2019 msgid "" "Smooths edges of seams (usually found at texture borders), disable if this " "causes odd normals on the shape." msgstr "" "Lisse les bords des coutures (généralement présentes aux bordures de " "texture), désactivez si cela provoque des normales impaires sur la forme." #: res/xrc/OutfitStudio.xrc:2024 msgid "Lock Normals" msgstr "Verrouiller les normales" #: res/xrc/OutfitStudio.xrc:2025 msgid "" "Locks the mesh normals. Enable if you want to keep custom normals intact." msgstr "" "Verrouille les normales du maillage. Activez si vous voulez garder les " "normales personnalisées intactes." #: res/xrc/OutfitStudio.xrc:2032 res/xrc/OutfitStudio.xrc:2395 msgid "Copies all bone weights from the reference shape to the current shape." msgstr "" "Copie tous les poids des os de la forme de référence vers la forme actuelle." #: res/xrc/OutfitStudio.xrc:2035 res/xrc/OutfitStudio.xrc:2398 msgid "Copy Selected Weights" msgstr "Copier les poids sélectionnés" #: res/xrc/OutfitStudio.xrc:2036 res/xrc/OutfitStudio.xrc:2399 msgid "" "Copies selected bone weights from the reference shape to the current shape." msgstr "" "Copie les poids des os sélectionnés de la forme de référence vers la forme " "actuelle." #: res/xrc/OutfitStudio.xrc:2039 res/xrc/OutfitStudio.xrc:2402 msgid "Transfer Selected Weights" msgstr "Transférer les poids sélectionnés" #: res/xrc/OutfitStudio.xrc:2040 res/xrc/OutfitStudio.xrc:2403 msgid "" "Transfers selected weights from the reference shape to the current shape. " "Requires same vertex count and order." msgstr "" "Transfère les poids sélectionnés de la forme de référence à la forme " "actuelle. Nécessite le même nombre de vertex et le même ordre." #: res/xrc/OutfitStudio.xrc:2043 res/xrc/OutfitStudio.xrc:2406 #: res/xrc/OutfitStudio.xrc:2448 msgid "Mask Weighted Vertices" msgstr "Masquer les Vertices Pondérés" #: res/xrc/OutfitStudio.xrc:2044 res/xrc/OutfitStudio.xrc:2407 msgid "" "Masks vertices with bone weights, so you can manually assign weights to " "unweighted vertices." msgstr "" "Masque les vertices avec des poids d'os, afin que vous puissiez attribuer " "manuellement des poids aux vertices non pondérés." #: res/xrc/OutfitStudio.xrc:2048 res/xrc/OutfitStudio.xrc:2411 msgid "Delete\tDel" msgstr "Effacer\tDel" #: res/xrc/OutfitStudio.xrc:2049 res/xrc/OutfitStudio.xrc:2412 msgid "Removes the currently selected shape from the outfit." msgstr "Supprime la forme actuellement sélectionnée de la tenue." #: res/xrc/OutfitStudio.xrc:2052 res/xrc/OutfitStudio.xrc:2415 msgid "Properties..." msgstr "Propriétés..." #: res/xrc/OutfitStudio.xrc:2053 res/xrc/OutfitStudio.xrc:2416 msgid "" "Opens the properties dialog for shader, texture and more settings of the " "selected shape." msgstr "" "Ouvre la boîte de dialogue des propriétés pour les paramètres d'ombrage, de " "texture et autres de la forme sélectionnée." #: res/xrc/OutfitStudio.xrc:2057 msgid "Slider" msgstr "Curseur" #: res/xrc/OutfitStudio.xrc:2059 msgid "Conform Selected\tCtrl+C" msgstr "Conforme sélectionné\tCtrl+C" #: res/xrc/OutfitStudio.xrc:2060 msgid "Conform selected outfit shape to all checked sliders." msgstr "Conforme la forme de la tenue sélectionnée à tous les sliders cochés." #: res/xrc/OutfitStudio.xrc:2063 msgid "Conform All\tCtrl+Shift+C" msgstr "Conforme tout\tCtrl+Shift+C" #: res/xrc/OutfitStudio.xrc:2064 msgid "Conform all outfit shapes to all checked sliders." msgstr "Conforme toutes les formes de tenue à tous les sliders cochés." #: res/xrc/OutfitStudio.xrc:2068 msgid "Set Base Shape" msgstr "Définir la forme de la base" #: res/xrc/OutfitStudio.xrc:2069 msgid "Set the current outfit shape as the base shape and clear slider data." msgstr "" "Définir la forme de la tenue actuelle comme forme de base et effacer les " "données du slider." #: res/xrc/OutfitStudio.xrc:2074 msgid "" "Load and preview a slider preset. Inverted sliders will have inverted values." msgstr "" "Chargez et prévisualisez un préréglage de slider. Les sliders inversés " "auront des valeurs inversées." #: res/xrc/OutfitStudio.xrc:2078 msgid "" "Save a slider preset with the current values. Inverted sliders will have " "inverted values." msgstr "" "Sauvegarder un préréglage de slider avec les valeurs actuelles. Les valeurs " "des sliders inversés seront inversées." #: res/xrc/OutfitStudio.xrc:2082 msgid "New Slider" msgstr "Nouveau slider" #: res/xrc/OutfitStudio.xrc:2083 msgid "Create a new shape transformation slider." msgstr "Créez un nouveau slider de transformation de forme." #: res/xrc/OutfitStudio.xrc:2086 msgid "Coalesce sliders" msgstr "Coalescez les sliders" #: res/xrc/OutfitStudio.xrc:2087 msgid "" "Create a new shape transformation slider based on the current slider values" msgstr "" "Créer un nouveau slider de transformation de forme basé sur les valeurs " "actuelles du slider" #: res/xrc/OutfitStudio.xrc:2090 msgid "New Zap Slider" msgstr "Nouveau slider Zap" #: res/xrc/OutfitStudio.xrc:2091 msgid "Create a new Zap slider based on unmasked vertices" msgstr "Créer un nouveau slider Zap basé sur les vertices non masqués" #: res/xrc/OutfitStudio.xrc:2095 msgid "Import OSD..." msgstr "Importez OSD..." #: res/xrc/OutfitStudio.xrc:2096 msgid "Imports OSD file and creates sliders for shapes with a matching name." msgstr "" "Importe le fichier OSD et crée des sliders pour les formes dont le nom " "correspond." #: res/xrc/OutfitStudio.xrc:2099 msgid "Export OSD..." msgstr "Exportez OSD..." #: res/xrc/OutfitStudio.xrc:2100 msgid "Exports all currently loaded slider data to an OSD file." msgstr "" "Exporte toutes les données des sliders actuellement chargés vers un fichier " "OSD." #: res/xrc/OutfitStudio.xrc:2103 msgid "Import TRI Morphs..." msgstr "Importez TRI Morphs..." #: res/xrc/OutfitStudio.xrc:2104 msgid "" "Imports TRI morphs from a TRI file and creates sliders for shapes with a " "matching name." msgstr "" "Importe des TRI Morphs à partir d'un fichier TRI et crée des sliders pour " "les formes avec un nom correspondant." #: res/xrc/OutfitStudio.xrc:2107 msgid "Export TRI Morphs..." msgstr "Exportez TRI Morphs..." #: res/xrc/OutfitStudio.xrc:2108 msgid "Exports TRI morphs to a TRI file." msgstr "Exporte des TRI Morphs dans un fichier TRI." #: res/xrc/OutfitStudio.xrc:2111 msgid "Export to OBJs..." msgstr "Exportez vers OBJs..." #: res/xrc/OutfitStudio.xrc:2112 msgid "Export all sliders to an OBJ file per slider." msgstr "Exportez tous les sliders dans un fichier OBJ par slider." #: res/xrc/OutfitStudio.xrc:2116 msgid "Import Slider Data" msgstr "Importez les données du slider" #: res/xrc/OutfitStudio.xrc:2118 msgid "Import NIF..." msgstr "Importez NIF..." #: res/xrc/OutfitStudio.xrc:2119 msgid "Import a NIF file and overwrites the current shape's slider data." msgstr "" "Importez un fichier NIF et écrase les données du slider de la forme actuelle." #: res/xrc/OutfitStudio.xrc:2122 msgid "Import BSD..." msgstr "Importez BSD..." #: res/xrc/OutfitStudio.xrc:2123 msgid "" "Import a BodySlide BSD file and overwrites the current shape's slider data." msgstr "" "Importez un fichier BSD BodySlide et écrase les données du slider de la " "forme actuelle." #: res/xrc/OutfitStudio.xrc:2126 msgid "Import OBJ..." msgstr "Importez OBJ..." #: res/xrc/OutfitStudio.xrc:2127 msgid "" "Import an OBJ file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "" "Importez un fichier OBJ correspondant au nombre de vertex de la forme " "actuelle et calculez les données du slider à partir de la différence." #: res/xrc/OutfitStudio.xrc:2130 msgid "Import FBX..." msgstr "Importez FBX..." #: res/xrc/OutfitStudio.xrc:2131 msgid "" "Import an FBX file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "" "Importez un fichier FBX correspondant au nombre de vertex de la forme " "actuelle et calculez les données du slider à partir de la différence." #: res/xrc/OutfitStudio.xrc:2136 msgid "Export Slider Data" msgstr "Exportez les données du slider" #: res/xrc/OutfitStudio.xrc:2138 msgid "Export NIF..." msgstr "Exportez NIF..." #: res/xrc/OutfitStudio.xrc:2139 msgid "Exports the current slider's data as a NIF file." msgstr "Exporte les données du slider actuel sous forme de fichier NIF." #: res/xrc/OutfitStudio.xrc:2142 msgid "Export BSD..." msgstr "Exportez BSD..." #: res/xrc/OutfitStudio.xrc:2143 msgid "Exports the current slider's data as a BodySlide BSD file." msgstr "" "Exporte les données du slider actuel sous forme de fichier BSD BodySlide." #: res/xrc/OutfitStudio.xrc:2146 msgid "Export OBJ..." msgstr "Export OBJ..." #: res/xrc/OutfitStudio.xrc:2147 msgid "Exports the current slider's data as an OBJ file." msgstr "Exporte les données du slider actuel sous forme de fichier OBJ." #: res/xrc/OutfitStudio.xrc:2153 msgid "Negate Slider" msgstr "Annuler le slider" #: res/xrc/OutfitStudio.xrc:2154 msgid "Negates the current slider, reversing it's effect" msgstr "Annule le slider actuel, inversant son effet" #: res/xrc/OutfitStudio.xrc:2158 msgid "Mask Affected Vertices" msgstr "Masquer les vertices affectés" #: res/xrc/OutfitStudio.xrc:2159 msgid "Masks the vertices the slider is affecting for all selected shapes." msgstr "" "Masque les vertices que le slider affecte pour toutes les formes " "sélectionnées." #: res/xrc/OutfitStudio.xrc:2163 msgid "Clear Slider Data" msgstr "Effacer les données du slider" #: res/xrc/OutfitStudio.xrc:2164 msgid "" "Erases the slider data without removing the slider itself. (Cannot be undone)" msgstr "" "Efface les données du slider sans supprimer le slider lui-même. (Ne peut pas " "être défait)" #: res/xrc/OutfitStudio.xrc:2167 msgid "Delete Slider" msgstr "Effacer slider" #: res/xrc/OutfitStudio.xrc:2168 msgid "Delete the active slider from the project. (Cannot be undone)" msgstr "Supprime le slider actif du projet. (Ne peut être annulé)" #: res/xrc/OutfitStudio.xrc:2172 msgid "Properties...\tTab" msgstr "Propriétés...\tTab" #: res/xrc/OutfitStudio.xrc:2173 msgid "Display and edit the active slider's properties." msgstr "Affichez et modifiez les propriétés du slider actif." #: res/xrc/OutfitStudio.xrc:2178 msgid "Tool" msgstr "Outil" #: res/xrc/OutfitStudio.xrc:2180 msgid "Current Tool" msgstr "Outil Actuel" #: res/xrc/OutfitStudio.xrc:2219 msgid "" "Apply animation weight values for the currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "Appliquez des valeurs de poids d'animation pour l'os actuellement " "sélectionné.\n" "Maintenez la touche ALT enfoncée pour affaiblir la pondération." #: res/xrc/OutfitStudio.xrc:2252 msgid "Transform\tF" msgstr "Transformez\tF" #: res/xrc/OutfitStudio.xrc:2257 msgid "Pivot\tP" msgstr "Pivot\tP" #: res/xrc/OutfitStudio.xrc:2262 msgid "Vertex Edit\tQ" msgstr "Modifiez Vertex\tQ" #: res/xrc/OutfitStudio.xrc:2263 msgid "" "Shows vertex points and lets you mask/unmask them.\n" "Without any brush active, click on a vertex to unmask it.\n" "Hold down CTRL to mask it." msgstr "" "Affiche les points de vertex et vous permet de les masquer/démasquer.\n" "Sans brosses actif, cliquez sur un vertex pour le démasquer.\n" "Maintenez la touche CTRL enfoncée pour le masquer." #: res/xrc/OutfitStudio.xrc:2268 msgid "Increase Brush Size\tShift++" msgstr "Augmentez la taille de la brosse\tShift++" #: res/xrc/OutfitStudio.xrc:2269 msgid "Increase brush diameter" msgstr "Augmentez le diamètre de la brosse" #: res/xrc/OutfitStudio.xrc:2272 msgid "Decrease Brush Size\tShift+-" msgstr "Diminuez la taille de la brosse\tShift+-" #: res/xrc/OutfitStudio.xrc:2273 msgid "Decrease brush diameter" msgstr "Diminuez le diamètre de la brosse" #: res/xrc/OutfitStudio.xrc:2276 msgid "Increase Brush Strength\tCtrl++" msgstr "Augmenter la force de la brosse\tCtrl++" #: res/xrc/OutfitStudio.xrc:2277 msgid "Increase brush strength" msgstr "Augmenter la force de la brosse" #: res/xrc/OutfitStudio.xrc:2280 msgid "Decrease Brush Strength\tCtrl+-" msgstr "Diminuez la force de la brosse\tCtrl+-" #: res/xrc/OutfitStudio.xrc:2281 msgid "Decrease brush strength" msgstr "Diminuez la force de la brosse" #: res/xrc/OutfitStudio.xrc:2285 msgid "Mask Less\tA" msgstr "Masque Moins\tA" #: res/xrc/OutfitStudio.xrc:2286 msgid "Mask Less" msgstr "Masque moins" #: res/xrc/OutfitStudio.xrc:2289 msgid "Mask More\tD" msgstr "Masque Plus\tD" #: res/xrc/OutfitStudio.xrc:2290 msgid "Mask More" msgstr "Masque plus" #: res/xrc/OutfitStudio.xrc:2294 msgid "Invert Mask\tCtrl+I" msgstr "Inversez le Masque\tCtrl+I" #: res/xrc/OutfitStudio.xrc:2295 msgid "Invert Mask" msgstr "Inversez le Masque" #: res/xrc/OutfitStudio.xrc:2298 msgid "Clear Mask\tCtrl+A" msgstr "Effacez le Masque\tCtrl+A" #: res/xrc/OutfitStudio.xrc:2299 msgid "Clear Mask" msgstr "Effacez le Masque" #: res/xrc/OutfitStudio.xrc:2422 res/xrc/OutfitStudio.xrc:2455 #: res/xrc/ShapeProperties.xrc:244 res/xrc/ShapeProperties.xrc:366 #: res/xrc/ShapeProperties.xrc:535 msgid "Add" msgstr "Ajouter" #: res/xrc/OutfitStudio.xrc:2424 res/xrc/OutfitStudio.xrc:2457 msgid "From Skeleton..." msgstr "Du Squelette..." #: res/xrc/OutfitStudio.xrc:2425 res/xrc/OutfitStudio.xrc:2458 msgid "Choose a bone from the reference skeleton to add to the project." msgstr "Choisissez un os dans le squelette de référence à ajouter au projet." #: res/xrc/OutfitStudio.xrc:2428 res/xrc/OutfitStudio.xrc:2461 msgid "Custom Bone..." msgstr "Os personnalisé..." #: res/xrc/OutfitStudio.xrc:2429 res/xrc/OutfitStudio.xrc:2462 msgid "Add a custom bone to the project." msgstr "Ajoutez un os personnalisé au projet." #: res/xrc/OutfitStudio.xrc:2435 msgid "From Project" msgstr "De Projet" #: res/xrc/OutfitStudio.xrc:2436 msgid "Delete bone(s) from all shapes of the project." msgstr "Supprimer le ou / les os de toutes les formes du projet." #: res/xrc/OutfitStudio.xrc:2439 msgid "From Selected Shapes" msgstr "À partir de Formes Sélectionnées" #: res/xrc/OutfitStudio.xrc:2440 msgid "Delete bone(s) from only the selected shapes." msgstr "Supprimer le ou / les os à partir des formes sélectionnées uniquement." #: res/xrc/OutfitStudio.xrc:2444 msgid "Edit Bone..." msgstr "Modifiez l'Os..." #: res/xrc/OutfitStudio.xrc:2445 msgid "Edit a custom bone or view a standard bone." msgstr "Modifiez un os personnalisé ou visualiser un os standard." #: res/xrc/OutfitStudio.xrc:2449 msgid "Masks vertices with weights for the selected bones." msgstr "Masque les vertices avec des poids pour les os sélectionnés." #: res/xrc/OutfitStudio.xrc:2469 res/xrc/OutfitStudio.xrc:2495 msgid "Add Segment..." msgstr "Ajouter Segment..." #: res/xrc/OutfitStudio.xrc:2470 res/xrc/OutfitStudio.xrc:2496 msgid "Choose a segment to add to the shape." msgstr "Choisissez un segment à ajouter à la forme." #: res/xrc/OutfitStudio.xrc:2473 res/xrc/OutfitStudio.xrc:2484 msgid "Add Sub Segment..." msgstr "Ajouter un Sous-Segment..." #: res/xrc/OutfitStudio.xrc:2474 res/xrc/OutfitStudio.xrc:2485 msgid "Add a new sub segment to the currently selected segment." msgstr "Ajouter un nouveau sous-segment au segment actuellement sélectionné." #: res/xrc/OutfitStudio.xrc:2477 msgid "Delete Segment..." msgstr "Effacer Segment..." #: res/xrc/OutfitStudio.xrc:2478 msgid "Delete segment and all of its sub segments from the shape." msgstr "Effacer le segment et tous ses sous-segments de la forme." #: res/xrc/OutfitStudio.xrc:2482 msgid "Sub Segments" msgstr "Sous-Segments" #: res/xrc/OutfitStudio.xrc:2488 msgid "Delete Sub Segment..." msgstr "Effacer Sous-Segment..." #: res/xrc/OutfitStudio.xrc:2489 msgid "Delete the selected sub segment." msgstr "Effacez la sous-segment sélectionnée." #: res/xrc/OutfitStudio.xrc:2502 res/xrc/OutfitStudio.xrc:2513 msgid "Add Partition..." msgstr "Ajouter une partition..." #: res/xrc/OutfitStudio.xrc:2503 res/xrc/OutfitStudio.xrc:2514 msgid "Adds a new partition to the shape." msgstr "Créez un nouveau partition de forme." #: res/xrc/OutfitStudio.xrc:2506 msgid "Delete Partition..." msgstr "Effacer une partition..." #: res/xrc/OutfitStudio.xrc:2507 msgid "Deletes the partition from the shape." msgstr "Effacer le partition de la forme." #: res/xrc/Project.xrc:16 msgid "" "Welcome to the New Project wizard!\n" "\n" "First, please choose a reference. Typically, this is a body (such as CBBE) " "or a conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "Bienvenue dans l'assistant Nouveau Projet!\n" "\n" "Tout d'abord, veuillez choisir une référence. En règle générale, il s'agit " "d'un corps (tel que CBBE) ou d'un jeu de conversion (tel que Vanilla To " "CBBE) et est livré avec ses sliders." #: res/xrc/Project.xrc:32 res/xrc/Project.xrc:574 msgid "Reference" msgstr "Référence" #: res/xrc/Project.xrc:50 res/xrc/Project.xrc:592 msgid "From Template" msgstr "Du Modèle" #: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272 #: res/xrc/Project.xrc:611 res/xrc/Project.xrc:785 res/xrc/Project.xrc:857 msgid "From File" msgstr "De Fichier" #: res/xrc/Project.xrc:79 res/xrc/Project.xrc:621 msgid "Select a project or NIF file" msgstr "Sélectionnez un projet ou un fichier NIF" #: res/xrc/Project.xrc:106 res/xrc/Project.xrc:648 msgid "Slider Set:" msgstr "Ensemble de Slider:" #: res/xrc/Project.xrc:124 res/xrc/Project.xrc:666 msgid "Shape:" msgstr "Forme:" #: res/xrc/Project.xrc:146 res/xrc/Project.xrc:688 msgid "Clear Reference" msgstr "Effacez la Référence" #: res/xrc/Project.xrc:162 msgid "Next, select an outfit/mesh to work on and enter a display name for it." msgstr "" "Ensuite, sélectionnez une tenue / un maillage sur lequel travailler et " "entrez un nom d'affichage pour celui-ci." #: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:752 msgid "Display Name" msgstr "Nom d'affichage" #: res/xrc/Project.xrc:197 res/xrc/Project.xrc:772 msgid "Outfit/Mesh" msgstr "Tenue/Maillage" #: res/xrc/Project.xrc:220 res/xrc/Project.xrc:795 msgid "Select a file to load as an outfit/mesh" msgstr "Sélectionnez un fichier à chargez comme tenue/maillage" #: res/xrc/Project.xrc:232 res/xrc/Project.xrc:807 msgid "Clear Outfit" msgstr "Effacez la Tenue" #: res/xrc/Project.xrc:250 res/xrc/Project.xrc:835 msgid "Textures" msgstr "Textures" #: res/xrc/Project.xrc:257 res/xrc/Project.xrc:842 msgid "Automatically search for textures" msgstr "Recherchez automatique de textures" #: res/xrc/Project.xrc:282 res/xrc/Project.xrc:867 msgid "Select a texture file" msgstr "Sélectionnez un fichier de la texture" #: res/xrc/Project.xrc:297 msgid "Save Project As..." msgstr "Sauvegarder le Projet Sous..." #: res/xrc/Project.xrc:328 msgid "The name of the outfit and slider set, as it will appear in BodySlide." msgstr "" "Le nom de la tenue et slider ensemble, comme il apparaîtra dans BodySlide." #: res/xrc/Project.xrc:337 msgid "Copies the current display name to the project text fields below." msgstr "" "Copie le nom d’affichage actuel aux champs de texte du projet ci-dessous." #: res/xrc/Project.xrc:338 msgid "To Project" msgstr "A la Projet" #: res/xrc/Project.xrc:354 msgid "Output File Name" msgstr "Nom du fichier de sortie" #: res/xrc/Project.xrc:363 msgid "" "The name of the outfit file that will end up in the game data path when " "BodySlide builds it. Should not include _1 or _0 in the name, e.g: " "lovelydress" msgstr "" "Le nom du fichier de tenue qui se retrouvera dans le chemin de données de " "jeu lorsque BodySlide le construit. Ne doit pas inclure _1 ou _0 dans le " "nom, par exemple: lovelydress" #: res/xrc/Project.xrc:389 msgid "Output Data Path" msgstr "Chemin de données de sortie" #: res/xrc/Project.xrc:398 msgid "" "The location in the game's data path where BodySlide-built outfit files will " "be placed, e.g: meshes\\clothes\\lovelydress" msgstr "" "L’emplacement dans le chemin de données du jeu où bodyslide construit " "fichiers de tenue seront placés, par exemple: mailles \\clothes\\lovelydress" #: res/xrc/Project.xrc:410 msgid "" "If this is enabled, BodySlide creates a low and high weight model when it " "generates the final outfit." msgstr "" "Si cela est activé, BodySlide crée un modèle de faible et de haut poids " "quand il génère la tenue finale." #: res/xrc/Project.xrc:411 msgid "Low/High Weight Output" msgstr "Poids Faible/Haut de Sortie" #: res/xrc/Project.xrc:419 msgid "" "If this is enabled, only one output file will be created (useful for single-" "weighted things like hair)." msgstr "" "Si cela est activé, un seul fichier de sortie sera créé (utile pour les " "choses mono pondérées comme les cheveux)." #: res/xrc/Project.xrc:420 msgid "Single Weight Output" msgstr "Sortie Poids Unique" #: res/xrc/Project.xrc:431 msgid "Project" msgstr "Projet" #: res/xrc/Project.xrc:443 msgid "Slider Set File" msgstr "Fichier Slider Set" #: res/xrc/Project.xrc:453 msgid "The .osp slider set project file" msgstr "Le fichier de projet slider set .osp" #: res/xrc/Project.xrc:454 msgid "Select slider set .osp file name" msgstr "Sélectionnez le nom du fichier slider set .osp" #: res/xrc/Project.xrc:472 msgid "Shape Data Folder" msgstr "Dossier de données de forme" #: res/xrc/Project.xrc:482 msgid "" "The folder where all the slider data will go, as well as the base outfit NIF " "file." msgstr "" "Le dossier où toutes les données du slider ira, ainsi que la tenue de base " "fichier NIF." #: res/xrc/Project.xrc:483 msgid "Select slider data folder" msgstr "Sélectionnez le dossier de données du slider" #: res/xrc/Project.xrc:500 msgid "Shape Data File" msgstr "Fichier de données de forme" #: res/xrc/Project.xrc:510 msgid "The name of the output's base NIF file." msgstr "Le nom du fichier NIF de base de la sortie." #: res/xrc/Project.xrc:511 msgid "Select output NIF file name" msgstr "Sélectionnez le nom du fichier NIF de sortie" #: res/xrc/Project.xrc:523 msgid "" "Outfits require the reference body to be a part of the output file. Disable " "this if you've already copied the reference over or you don't want it " "included." msgstr "" "Les tenues exigent que le corps de référence fait partie du fichier de " "sortie. Désactivez cela si vous avez déjà copié la référence ou si vous ne " "voulez pas qu’elle soit incluse." #: res/xrc/Project.xrc:524 msgid "Copy reference shape into output" msgstr "Copier la forme de référence en sortie" #: res/xrc/Project.xrc:539 res/xrc/SavePreset.xrc:78 msgid "&Save" msgstr "&Sauvegarder" #: res/xrc/Project.xrc:555 msgid "Load Reference" msgstr "Chargez un Référence" #: res/xrc/Project.xrc:564 msgid "" "Please choose a reference. Typically, this is a body (such as CBBE) or a " "conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "Choisir une référence. En règle générale, il s'agit d'un corps (tel que " "CBBE) ou d'un jeu de conversion (tel que Vanilla To CBBE) et est livré avec " "ses sliders." #: res/xrc/Project.xrc:697 msgid "Merge new sliders with existing sliders" msgstr "Fusionner les nouveaux sliders avec les sliders existants" #: res/xrc/Project.xrc:728 msgid "Load Outfit" msgstr "Chargez la Tenue" #: res/xrc/Project.xrc:737 msgid "" "Please select an outfit/mesh to work on and enter a display name for it." msgstr "" "Sélectionnez une tenue / un maillage sur lequel travailler et entrez un nom " "d'affichage pour celui-ci." #: res/xrc/Project.xrc:816 msgid "Keep other shapes" msgstr "Gardez d'autres formes" #: res/xrc/Project.xrc:942 msgid "Group file (optional):" msgstr "Fichier de groupe (facultatif):" #: res/xrc/Project.xrc:951 msgid "Group file to pack (optional)." msgstr "Fichier de groupe à emballer (facultatif)." #: res/xrc/Project.xrc:968 msgid "Merged file name:" msgstr "Nom de fichier fusionné:" #: res/xrc/Project.xrc:976 msgid "File name to use for the merged project file." msgstr "Nom de fichier à utiliser pour le fichier de projet fusionné." #: res/xrc/Project.xrc:1002 msgid "Pack Folder..." msgstr "Emballez le Dossier..." #: res/xrc/Project.xrc:1011 msgid "Pack Archive..." msgstr "Emballez Archive..." #: res/xrc/Project.xrc:1028 src/program/OutfitStudio.cpp:3429 #: src/program/OutfitStudio.cpp:5967 src/program/OutfitStudio.cpp:6823 #: src/program/OutfitStudio.cpp:6913 src/program/OutfitStudio.cpp:9666 #: src/program/OutfitStudio.cpp:9693 msgid "Cancel" msgstr "Annuler" #: res/xrc/SavePreset.xrc:6 msgid "Enter preset name..." msgstr "Entrez le nom du préréglage ..." #: res/xrc/SavePreset.xrc:15 msgid "Please enter a name for the new preset:" msgstr "Veuillez saisir un nom pour le nouveau préréglage:" #: res/xrc/SavePreset.xrc:38 msgid "Select groups to assign to the new preset:" msgstr "Sélectionnez les groupes à affecter au nouveau préréglage:" #: res/xrc/Settings.xrc:15 msgid "Game" msgstr "Jeu" #: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:3902 msgid "Target Game" msgstr "Jeu de cible" #: res/xrc/Settings.xrc:37 msgid "Choose the target game you want to use the program for here." msgstr "" "Choisissez ici le jeu cible pour lequel vous souhaitez utiliser le programme." #: res/xrc/Settings.xrc:66 msgid "Game Data Path" msgstr "Chemin des données du jeu" #: res/xrc/Settings.xrc:76 msgid "Select the data path of the game..." msgstr "Sélectionnez le chemin des données du jeu ..." #: res/xrc/Settings.xrc:78 msgid "Data path to load textures from." msgstr "Chemin de données à partir duquel charger les textures." #: res/xrc/Settings.xrc:90 msgid "Advanced" msgstr "Avancée" #: res/xrc/Settings.xrc:107 msgid "Output Path" msgstr "Chemin de sortie" #: res/xrc/Settings.xrc:117 msgid "Select the output path..." msgstr "Sélectionnez le chemin de sortie..." #: res/xrc/Settings.xrc:119 msgid "" "Data path to build files to. If empty, Game Data Path will be used instead." msgstr "" "Chemin des données pour construire les fichiers. S'il est vide, le chemin de " "données du jeu sera utilisé à la place." #: res/xrc/Settings.xrc:136 msgid "Project Path" msgstr "Chemin du Projet" #: res/xrc/Settings.xrc:146 msgid "Select the project path..." msgstr "Sélectionnez le chemin du projet..." #: res/xrc/Settings.xrc:148 msgid "" "Project path where files related to BodySlide are loaded from. If empty, " "executable directory will be used instead." msgstr "" "Chemin du projet à partir duquel les fichiers liés à BodySlide sont chargés. " "S'il est vide, le répertoire exécutable sera utilisé à la place." #: res/xrc/Settings.xrc:165 msgid "General" msgstr "Général" #: res/xrc/Settings.xrc:177 msgid "" "Enables/disables the dialog for choosing which set to build during a batch " "build if overrides happen." msgstr "" "Active/désactive la boîte de dialogue pour choisir le jeu à construire lors " "d'une génération par lots si des remplacements se produisent." #: res/xrc/Settings.xrc:178 msgid "Override Warning" msgstr "Avertissement de remplacement" #: res/xrc/Settings.xrc:187 msgid "" "Enables/disables scanning BSAs in the game data folder for textures to load." msgstr "" "Active/désactive l'analyse des BSA dans le dossier de données du jeu pour le " "chargement des textures." #: res/xrc/Settings.xrc:188 msgid "BSA Textures" msgstr "BSA Textures" #: res/xrc/Settings.xrc:205 msgid "" "Enables/disables panning the camera with the left mouse button in Outfit " "Studio." msgstr "" "Active/désactive le panoramique de la caméra avec le bouton gauche de la " "souris dans Outfit Studio." #: res/xrc/Settings.xrc:206 msgid "Left Mouse Pan" msgstr "Panoramique gauche de la souris" #: res/xrc/Settings.xrc:224 msgid "Language" msgstr "Langue" #: res/xrc/Settings.xrc:233 msgid "Use the selected language for the program." msgstr "Utilisez la langue sélectionnée pour le programme." #: res/xrc/Settings.xrc:248 msgid "Rendering" msgstr "Rendu" #: res/xrc/Settings.xrc:261 msgid "Background Color" msgstr "Couleur de Fond" #: res/xrc/Settings.xrc:270 msgid "Background color of the renderer." msgstr "Couleur de fond du moteur de rendu." #: res/xrc/Settings.xrc:288 msgid "Wireframe Color" msgstr "Couleur de l'Image Filaire" #: res/xrc/Settings.xrc:297 msgid "Wireframe color of the renderer." msgstr "Couleur de l'image filaire du moteur de rendu." #: res/xrc/Settings.xrc:312 msgid "Data Files" msgstr "Fichier de données" #: res/xrc/Settings.xrc:330 msgid "Reference Skeleton" msgstr "Squelette de référence" #: res/xrc/Settings.xrc:353 msgid "Select a reference skeleton .nif file..." msgstr "Sélectionnez un fichier .nif de squelette de référence..." #: res/xrc/Settings.xrc:356 msgid "The reference skeleton file for Outfit Studio." msgstr "Le fichier squelette de référence pour Outfit Studio." #: res/xrc/Settings.xrc:373 msgid "Root Node" msgstr "Nœud racine" #: res/xrc/Settings.xrc:382 msgid "" "The root node name of the reference skeleton. Can differ from game to game." msgstr "" "Le nom du nœud racine du squelette de référence. Peut différer d'un jeu à " "l'autre." #: res/xrc/Setup.xrc:5 msgid "Setup" msgstr "Configuration" #: res/xrc/Setup.xrc:15 msgid "" "Please select the data folder and your target game.\n" "You can only choose one game at a time, but it is possible to change the " "selection in the settings." msgstr "" "Veuillez sélectionner le dossier de données et votre jeu cible.\n" "Vous ne pouvez choisir qu'un seul jeu à la fois, mais il est possible de " "modifier la sélection dans les paramètres." #: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102 #: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189 #: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247 msgid "Game not found! Select the data folder manually..." msgstr "Jeu non trouvé! Sélectionnez manuellement le dossier de données..." #: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103 #: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190 #: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248 msgid "Select a folder" msgstr "Sélectionnez une dossier" #: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113 #: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200 #: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258 msgid "Choose Game" msgstr "Choisissez le Jeu" #: res/xrc/ShapeProperties.xrc:5 msgid "Shape Properties" msgstr "Propriétés de la forme" #: res/xrc/ShapeProperties.xrc:16 msgid "Shader" msgstr "Ombrage" #: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:553 #: res/xrc/Skeleton.xrc:68 msgid "Name" msgstr "Nom" #: res/xrc/ShapeProperties.xrc:102 msgid "Specular Color" msgstr "Couleur Spéculaire" #: res/xrc/ShapeProperties.xrc:120 msgid "Specular Strength" msgstr "Force Spéculaire" #: res/xrc/ShapeProperties.xrc:139 msgid "Specular Power" msgstr "Puissance Spéculaire" #: res/xrc/ShapeProperties.xrc:179 msgid "Emissive Color" msgstr "Couleur Émissive" #: res/xrc/ShapeProperties.xrc:197 msgid "Emissive Multiple" msgstr "Multiples Émissive" #: res/xrc/ShapeProperties.xrc:216 msgid "Vertex Colors" msgstr "Couleurs des Vertex" #: res/xrc/ShapeProperties.xrc:253 res/xrc/ShapeProperties.xrc:375 msgid "Remove" msgstr "Supprimer" #: res/xrc/ShapeProperties.xrc:262 msgid "Textures..." msgstr "Textures..." #: res/xrc/ShapeProperties.xrc:274 msgid "Transparency" msgstr "Transparence" #: res/xrc/ShapeProperties.xrc:297 msgid "Threshold" msgstr "Seuil" #: res/xrc/ShapeProperties.xrc:337 msgid "Vertex Alpha" msgstr "Alpha des Vertex" #: res/xrc/ShapeProperties.xrc:388 msgid "Copy from shape..." msgstr "Copie de la forme..." #: res/xrc/ShapeProperties.xrc:396 msgid "Geometry" msgstr "Géométrie" #: res/xrc/ShapeProperties.xrc:416 msgid "Full Precision" msgstr "Précision Totale" #: res/xrc/ShapeProperties.xrc:434 msgid "Sub Index" msgstr "Sous-index" #: res/xrc/ShapeProperties.xrc:452 msgid "Skinned" msgstr "Écorché" #: res/xrc/ShapeProperties.xrc:469 msgid "Dynamic" msgstr "Dynamique" #: res/xrc/ShapeProperties.xrc:514 msgid "Extra Data" msgstr "Données Supplémentaires" #: res/xrc/ShapeProperties.xrc:562 msgid "Value" msgstr "Valeur" #: res/xrc/ShapeProperties.xrc:572 msgid "Coordinates" msgstr "Coordonnées" #: res/xrc/ShapeProperties.xrc:581 msgid "Transform from global to skin coordinates:" msgstr "Transformez les coordonnées globales en coordonnées de la peau:" #: res/xrc/ShapeProperties.xrc:644 res/xrc/Skeleton.xrc:142 msgid "Rotation" msgstr "Rotation" #: res/xrc/Skeleton.xrc:6 msgid "Select a bone to add" msgstr "Sélectionnez un os à ajouter" #: res/xrc/Skeleton.xrc:15 msgid "Bones in the current reference skeleton:" msgstr "Os dans le squelette de référence actuel :" #: res/xrc/Skeleton.xrc:53 msgid "Add Custom Bone" msgstr "Ajouter l’os personnalisé" #: res/xrc/Skeleton.xrc:93 msgid "Parent" msgstr "Parent" #: res/xrc/Slider.xrc:6 msgid "Select a slider preset" msgstr "Sélectionnez un préréglage du slider" #: res/xrc/Slider.xrc:15 msgid "Choose a preset:" msgstr "Choisissez un préréglage:" #: res/xrc/Slider.xrc:40 msgid "Low weight" msgstr "Poids Faible" #: res/xrc/Slider.xrc:49 msgid "High weight" msgstr "Poids Haut" #: res/xrc/Slider.xrc:81 msgid "Slider Properties" msgstr "Propriétés slider" #: res/xrc/Slider.xrc:91 msgid "Slider Name" msgstr "Nom du Slider" #: res/xrc/Slider.xrc:108 msgid "Default Values" msgstr "Valeurs par Défaut" #: res/xrc/Slider.xrc:114 msgid "Low" msgstr "Faible" #: res/xrc/Slider.xrc:131 msgid "High" msgstr "Élevé" #: res/xrc/Slider.xrc:148 msgid "Zapped" msgstr "Zappé" #: res/xrc/Slider.xrc:173 msgid "Invert" msgstr "Inverser" #: res/xrc/Slider.xrc:182 msgid "Hidden" msgstr "Caché" #: res/xrc/Slider.xrc:191 msgid "Zap" msgstr "Zap" #: res/xrc/Slider.xrc:211 msgid "Toggle Zaps:" msgstr "Basculez Zaps:" #: src/components/Anim.cpp:509 msgid "" "Bone information incomplete. Exported data will not contain correct bone " "entries! Be sure to load a reference NIF prior to export." msgstr "" "Information osseuse incomplète. Les données exportées ne contiendront pas " "les entrées d'os correctes! Assurez-vous de charger un NIF de référence " "avant l'exportation." #: src/components/Anim.cpp:509 msgid "Export Warning" msgstr "Avertissement de Exporter" #: src/components/Anim.cpp:575 #, c-format msgid "Failed to load skeleton '%s'!" msgstr "Échec du chargement du squelette '%s'!" #: src/components/Anim.cpp:583 #, c-format msgid "Root '%s' not found in skeleton '%s'!" msgstr "Racine '%s' non trouvée dans le squelette '%s'!" #: src/program/BodySlideApp.cpp:181 src/program/OutfitStudio.cpp:394 msgid "" "No read/write permission for game data path!\n" "\n" "Please launch the program with admin elevation and make sure the game data " "path in the settings is correct." msgstr "" "Aucune permission de lecture/écriture pour le chemin des données du jeu!\n" "\n" "Veuillez lancer le programme avec l'autorisation de l'administrateur et " "vérifiez que le chemin des données du jeu dans les paramètres est correct." #: src/program/BodySlideApp.cpp:181 src/program/BodySlideApp.cpp:188 #: src/program/BodySlideApp.cpp:1246 src/program/BodySlideApp.cpp:1253 #: src/program/OutfitStudio.cpp:394 src/program/OutfitStudio.cpp:401 #: src/program/OutfitStudio.cpp:627 src/program/OutfitStudio.cpp:634 msgid "Warning" msgstr "Avertissement" #: src/program/BodySlideApp.cpp:188 src/program/OutfitStudio.cpp:401 msgid "" "No read/write permission for project path!\n" "\n" "Please launch the program with admin elevation and make sure the project " "path in the settings is correct." msgstr "" "Aucune permission de lecture/écriture pour le chemin du projet!\n" "\n" "Veuillez lancer le programme avec l'autorisation de l'administrateur et " "vérifiez que le chemin du projet dans les paramètres est correct." #: src/program/BodySlideApp.cpp:259 src/program/OutfitStudio.cpp:489 #, c-format msgid "Unexpected exception has occurred: %s, the program will terminate." msgstr "Une exception inattendue s'est produite: %s, le programme s'arrête." #: src/program/BodySlideApp.cpp:259 src/program/OutfitStudio.cpp:489 msgid "Unexpected exception" msgstr "Exception inattendue" #: src/program/BodySlideApp.cpp:282 src/program/OutfitStudio.cpp:509 #, c-format msgid "Unhandled exception has occurred: %s, the program will terminate." msgstr "Une exception non gérée s'est produite: %s, le programme s'arrête." #: src/program/BodySlideApp.cpp:282 src/program/OutfitStudio.cpp:509 msgid "Unhandled exception" msgstr "Exception non gérée" #: src/program/BodySlideApp.cpp:293 src/program/OutfitStudio.cpp:517 msgid "Fatal exception has occurred, the program will terminate." msgstr "Une exception fatale s'est produite, le programme se terminera." #: src/program/BodySlideApp.cpp:293 src/program/OutfitStudio.cpp:517 msgid "Fatal exception" msgstr "Exception fatale" #: src/program/BodySlideApp.cpp:743 msgid "Failed to launch Outfit Studio executable!" msgstr "Impossible de lancer l'exécutable d'Outfit Studio !" #: src/program/BodySlideApp.cpp:743 src/program/BodySlideApp.cpp:1274 #: src/program/BodySlideApp.cpp:1566 src/program/BodySlideApp.cpp:2562 #: src/program/BodySlideApp.cpp:2569 src/program/BodySlideApp.cpp:3252 #: src/program/OutfitStudio.cpp:918 src/program/OutfitStudio.cpp:924 #: src/program/OutfitStudio.cpp:1361 src/program/OutfitStudio.cpp:1372 #: src/program/OutfitStudio.cpp:1409 src/program/OutfitStudio.cpp:1420 #: src/program/OutfitStudio.cpp:1430 src/program/OutfitStudio.cpp:1439 #: src/program/OutfitStudio.cpp:1450 src/program/OutfitStudio.cpp:1461 #: src/program/OutfitStudio.cpp:1473 src/program/OutfitStudio.cpp:1512 #: src/program/OutfitStudio.cpp:1520 src/program/OutfitStudio.cpp:1527 #: src/program/OutfitStudio.cpp:1564 src/program/OutfitStudio.cpp:1572 #: src/program/OutfitStudio.cpp:1579 src/program/OutfitStudio.cpp:1589 #: src/program/OutfitStudio.cpp:1598 src/program/OutfitStudio.cpp:1606 #: src/program/OutfitStudio.cpp:1613 src/program/OutfitStudio.cpp:1624 #: src/program/OutfitStudio.cpp:1633 src/program/OutfitStudio.cpp:1640 #: src/program/OutfitStudio.cpp:1888 src/program/OutfitStudio.cpp:1911 #: src/program/OutfitStudio.cpp:1925 src/program/OutfitStudio.cpp:2009 #: src/program/OutfitStudio.cpp:2018 src/program/OutfitStudio.cpp:2026 #: src/program/OutfitStudio.cpp:2040 src/program/OutfitStudio.cpp:2049 #: src/program/OutfitStudio.cpp:2055 src/program/OutfitStudio.cpp:2083 #: src/program/OutfitStudio.cpp:3953 src/program/OutfitStudio.cpp:3973 #: src/program/OutfitStudio.cpp:4037 src/program/OutfitStudio.cpp:4070 #: src/program/OutfitStudio.cpp:4084 src/program/OutfitStudio.cpp:4152 #: src/program/OutfitStudio.cpp:4185 src/program/OutfitStudio.cpp:4199 #: src/program/OutfitStudio.cpp:4224 src/program/OutfitStudio.cpp:4275 #: src/program/OutfitStudio.cpp:4280 src/program/OutfitStudio.cpp:4294 #: src/program/OutfitStudio.cpp:4301 src/program/OutfitStudio.cpp:4306 #: src/program/OutfitStudio.cpp:4317 src/program/OutfitStudio.cpp:6681 #: src/program/OutfitStudio.cpp:6737 src/program/OutfitStudio.cpp:6743 #: src/program/OutfitStudio.cpp:6747 src/program/OutfitStudio.cpp:6758 #: src/program/OutfitStudio.cpp:6768 src/program/OutfitStudio.cpp:6772 #: src/program/OutfitStudio.cpp:6789 src/program/OutfitStudio.cpp:6793 #: src/program/OutfitStudio.cpp:6804 src/program/OutfitStudio.cpp:6814 #: src/program/OutfitStudio.cpp:6832 src/program/OutfitStudio.cpp:6904 #: src/program/OutfitStudio.cpp:6922 src/program/OutfitStudio.cpp:6996 #: src/program/OutfitStudio.cpp:7000 src/program/OutfitStudio.cpp:7011 #: src/program/OutfitStudio.cpp:7021 src/program/OutfitStudio.cpp:7025 #: src/program/OutfitStudio.cpp:7048 src/program/OutfitStudio.cpp:7057 #: src/program/OutfitStudio.cpp:7061 src/program/OutfitStudio.cpp:7090 #: src/program/OutfitStudio.cpp:7094 src/program/OutfitStudio.cpp:7117 #: src/program/OutfitStudio.cpp:7126 src/program/OutfitStudio.cpp:7137 #: src/program/OutfitStudio.cpp:7144 src/program/OutfitStudio.cpp:7155 #: src/program/OutfitStudio.cpp:7162 src/program/OutfitStudio.cpp:7186 #: src/program/OutfitStudio.cpp:7236 src/program/OutfitStudio.cpp:7296 #: src/program/OutfitStudio.cpp:7300 src/program/OutfitStudio.cpp:7313 #: src/program/OutfitStudio.cpp:7317 src/program/OutfitStudio.cpp:7379 #: src/program/OutfitStudio.cpp:7688 src/program/OutfitStudio.cpp:7705 #: src/program/OutfitStudio.cpp:7723 src/program/OutfitStudio.cpp:7747 #: src/program/OutfitStudio.cpp:7782 src/program/OutfitStudio.cpp:7928 #: src/program/OutfitStudio.cpp:8112 src/program/OutfitStudio.cpp:8259 #: src/program/OutfitStudio.cpp:8313 src/program/OutfitStudio.cpp:8529 #: src/program/OutfitStudio.cpp:8669 src/program/OutfitStudio.cpp:8677 #: src/program/OutfitStudio.cpp:8972 src/program/OutfitStudio.cpp:8977 #: src/program/OutfitStudio.cpp:9046 src/program/OutfitStudio.cpp:9051 #: src/program/OutfitStudio.cpp:9137 src/program/OutfitStudio.cpp:9143 #: src/program/OutfitStudio.cpp:9148 src/program/OutfitStudio.cpp:9155 #: src/program/OutfitStudio.cpp:9184 src/program/OutfitStudio.cpp:9214 #: src/program/OutfitStudio.cpp:9266 src/program/OutfitStudio.cpp:9440 #: src/program/OutfitStudio.cpp:10646 src/program/OutfitStudio.cpp:10700 #: src/program/OutfitStudio.cpp:10734 src/program/OutfitStudio.cpp:10739 #: src/program/OutfitStudio.cpp:10761 src/program/OutfitStudio.cpp:11891 msgid "Error" msgstr "Erreur" #: src/program/BodySlideApp.cpp:1246 src/program/OutfitStudio.cpp:627 msgid "" "Failed to find game install path registry value or GameDataPath in the " "config." msgstr "" "Impossible de trouver la valeur de registre du chemin d'installation du jeu " "ou GameDataPath dans la configuration." #: src/program/BodySlideApp.cpp:1253 src/program/OutfitStudio.cpp:634 msgid "" "Failed to find game install path registry key or GameDataPath in the config." msgstr "" "Impossible de trouver la clé de registre du chemin d'installation du jeu ou " "GameDataPath dans la configuration." #: src/program/BodySlideApp.cpp:1479 src/program/OutfitStudio.cpp:860 #, c-format msgid "System language '%d' is wrong." msgstr "La langue du système '%d' est incorrecte." #: src/program/BodySlideApp.cpp:1488 src/program/OutfitStudio.cpp:869 #, c-format msgid "" "The system language '%d' is not supported by your system. Try installing " "support for this language." msgstr "" "La langue système '%d' n'est pas prise en charge par votre système. Essayez " "d'installer le support pour cette langue." #: src/program/BodySlideApp.cpp:1566 msgid "Failed to create group file." msgstr "Échec de la création du fichier de groupe." #: src/program/BodySlideApp.cpp:1580 msgid "" "That group already exists in the specified file, do you wish to overwrite " "the group?" msgstr "" "Ce groupe existe déjà dans le fichier spécifié, souhaitez-vous écraser le " "groupe?" #: src/program/BodySlideApp.cpp:1580 msgid "Group already exists" msgstr "Le groupe existe déjà" #: src/program/BodySlideApp.cpp:1714 msgid "" "WARNING: Game data path not configured. Would you like to show BodySlide " "where it is?" msgstr "" "AVERTISSEMENT: Le chemin des données du jeu n'est pas configuré. Voulez-vous " "montrer BodySlide où il se trouve?" #: src/program/BodySlideApp.cpp:1714 src/program/BodySlideApp.cpp:2001 #: src/program/BodySlideApp.cpp:2005 msgid "Game not found" msgstr "Jeu non trouvé" #: src/program/BodySlideApp.cpp:1721 msgid "Please choose a directory to set as your Data path" msgstr "Veuillez choisir un répertoire à définir comme chemin de données" #: src/program/BodySlideApp.cpp:1739 msgid "" "WARNING: This will delete the output files from the output folder, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "AVERTISSEMENT: Cela supprimera les fichiers de sortie du dossier de sortie, " "ce qui pourrait provoquer des pannes.\n" "\n" "Voulez-vous continuer?" #: src/program/BodySlideApp.cpp:1739 msgid "Clean Build" msgstr "Construire Proprement" #: src/program/BodySlideApp.cpp:1746 msgid "Removed the following files:\n" msgstr "Suppression des fichiers suivants:\n" #: src/program/BodySlideApp.cpp:1758 src/program/BodySlideApp.cpp:1771 msgid " (no action)\n" msgstr " (aucune action)\n" #: src/program/BodySlideApp.cpp:1762 src/program/BodySlideApp.cpp:1774 #: src/program/BodySlideApp.cpp:1977 msgid "Process Successful" msgstr "Succès du Processus" #: src/program/BodySlideApp.cpp:1864 #, c-format msgid "" "Failed to write TRI file to the following location\n" "\n" "%s" msgstr "" "Échec de l'écriture du fichier TRI à l'emplacement suivant\n" "\n" "%s" #: src/program/BodySlideApp.cpp:1864 src/program/BodySlideApp.cpp:1920 #: src/program/BodySlideApp.cpp:1955 msgid "Unable to process" msgstr "Impossible à traiter" #: src/program/BodySlideApp.cpp:1920 src/program/BodySlideApp.cpp:1955 #, c-format msgid "" "Failed to build set to the following location\n" "\n" "%s" msgstr "" "Échec de la création de l'ensemble à l'emplacement suivant\n" "\n" "%s" #: src/program/BodySlideApp.cpp:1922 src/program/BodySlideApp.cpp:1957 msgid "Choose alternate file name" msgstr "Choisissez un autre nom de fichier" #: src/program/BodySlideApp.cpp:1969 msgid "Successfully processed the following files:\n" msgstr "Traitement réussi des fichiers suivants:\n" #: src/program/BodySlideApp.cpp:1988 msgid "" "WARNING: This will delete the output files from the output folders, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "AVERTISSEMENT: Cela supprimera les fichiers de sortie des dossier de sortie, " "ce qui pourrait provoquer des pannes.\n" "\n" "Voulez-vous continuer?" #: src/program/BodySlideApp.cpp:1988 msgid "Clean Batch Build" msgstr "Proprement Construction par lots" #: src/program/BodySlideApp.cpp:2001 msgid "" "WARNING: Game data path not configured. Files can't be removed that way." msgstr "" "AVERTISSEMENT: le chemin des données du jeu n'est pas configuré. Les " "fichiers ne peuvent pas être supprimés de cette façon." #: src/program/BodySlideApp.cpp:2005 msgid "" "WARNING: Game data path not configured. Continue saving files to the working " "directory?" msgstr "" "AVERTISSEMENT: le chemin des données du jeu n'est pas configuré. Continuer à " "enregistrer les fichiers dans le répertoire de travail?" #: src/program/BodySlideApp.cpp:2114 msgid "Processing Outfits" msgstr "Tenues de traitement" #: src/program/BodySlideApp.cpp:2114 src/program/OutfitStudio.h:1089 msgid "Starting..." msgstr "Commencer..." #: src/program/BodySlideApp.cpp:2131 #, c-format msgid "Processing '%s' (%d of %d)..." msgstr "Traitement'%s' (%d of %d)..." #: src/program/BodySlideApp.cpp:2139 msgid "No recorded outfit name source" msgstr "Aucune source de nom de tenue enregistrée" #: src/program/BodySlideApp.cpp:2150 msgid "Unable to get slider set from file: " msgstr "Impossible d'obtenir le slider set du fichier: " #: src/program/BodySlideApp.cpp:2155 msgid "Unable to open slider set file: " msgstr "Impossible d'ouvrir le fichier de slider set: " #: src/program/BodySlideApp.cpp:2190 msgid "Unable to load input nif: " msgstr "Impossible de charger l'entrée nif: " #: src/program/BodySlideApp.cpp:2337 msgid "Unable to create destination directory: " msgstr "Impossible de créer le répertoire de destination: " #: src/program/BodySlideApp.cpp:2401 src/program/BodySlideApp.cpp:2409 #: src/program/BodySlideApp.cpp:2420 msgid "Unable to save nif file: " msgstr "Impossible d'enregistrer le fichier nif: " #: src/program/BodySlideApp.cpp:2490 src/program/BodySlideApp.cpp:3427 msgid "The following sets failed" msgstr "Les ensembles suivants ont échoué" #: src/program/BodySlideApp.cpp:2490 src/program/BodySlideApp.cpp:3427 msgid "Failed" msgstr "Échec" #: src/program/BodySlideApp.cpp:2562 msgid "Failed to load BodySlide.xrc file!" msgstr "Échec du chargement du fichier Bodyslide.xrc!" #: src/program/BodySlideApp.cpp:2569 msgid "Failed to load BodySlide frame!" msgstr "Échec du chargement du cadre BodySlide!" #: src/program/BodySlideApp.cpp:2589 msgid "Group Filter" msgstr "Filtre de Groupe" #: src/program/BodySlideApp.cpp:2590 msgid "Filter by group" msgstr "Filtrer par groupe" #: src/program/BodySlideApp.cpp:2596 msgid "Outfit Filter" msgstr "Filtre de Tenue" #: src/program/BodySlideApp.cpp:2597 msgid "Filter by outfit" msgstr "Filtre par tenue" #: src/program/BodySlideApp.cpp:3161 msgid "Choose groups to filter outfit list" msgstr "Choisissez des groupes pour filtrer la liste des tenues" #: src/program/BodySlideApp.cpp:3161 msgid "Choose Groups" msgstr "Choisissez des Groupes" #: src/program/BodySlideApp.cpp:3178 msgid "Choose or create group file" msgstr "Choisissez ou créez un fichier de groupe" #: src/program/BodySlideApp.cpp:3187 msgid "What would you like the new group to be called?" msgstr "Comment aimeriez-vous que le nouveau groupe soit appelé?" #: src/program/BodySlideApp.cpp:3187 msgid "New Group Name" msgstr "Nouveau Nom de Groupes" #: src/program/BodySlideApp.cpp:3224 msgid "Do you really wish to delete the selected project?" msgstr "Voulez-vous vraiment supprimer le projet sélectionné ?" #: src/program/BodySlideApp.cpp:3224 msgid "Delete Project" msgstr "Supprimer le Projet" #: src/program/BodySlideApp.cpp:3233 msgid "Do you really wish to delete the selected preset?" msgstr "Voulez-vous vraiment supprimer le préréglage sélectionné?" #: src/program/BodySlideApp.cpp:3233 msgid "Delete Preset" msgstr "Supprimer le préréglage" #: src/program/BodySlideApp.cpp:3252 src/program/OutfitStudio.cpp:6737 #, c-format msgid "Failed to save preset (%d)!" msgstr "Échec de l'enregistrement du préréglage (%d)!" #: src/program/BodySlideApp.cpp:3279 #, c-format msgid "Failed to save preset as '%s' (%d)!" msgstr "Échec de l'enregistrement du préréglage sous '%s' (%d)!" #: src/program/BodySlideApp.cpp:3402 msgid "Choose a folder to contain the saved files" msgstr "Choisissez un dossier pour contenir les fichiers enregistrés" #: src/program/BodySlideApp.cpp:3417 msgid "All sets processed successfully!" msgstr "Tous les jeux ont été traités avec succès!" #: src/program/BodySlideApp.cpp:3417 msgid "Complete" msgstr "Finir" #: src/program/EditUV.cpp:329 src/program/OutfitStudio.cpp:9768 msgid "Outfit Studio: OpenGL context is not OK." msgstr "Outfit Studio: OpenGL le contexte n'est pas OK." #: src/program/EditUV.cpp:329 src/program/OutfitStudio.cpp:9768 #: src/program/PreviewWindow.cpp:66 src/render/GLSurface.cpp:1880 #: src/render/GLSurface.cpp:1897 msgid "OpenGL Error" msgstr "OpenGL Erreur" #: src/program/GroupManager.cpp:139 msgid "Please enter a new unique name for the group." msgstr "Veuillez saisir un nouveau nom unique pour la groupe." #: src/program/GroupManager.cpp:139 msgid "Rename Group" msgstr "Renommez la Groupe" #: src/program/GroupManager.cpp:321 msgid "Save changes to group file?" msgstr "Sauvegarder les modifications dans le fichier de groupe?" #: src/program/GroupManager.cpp:321 msgid "Save Changes" msgstr "Sauvegarder les modifications" #: src/program/NormalsGenDialog.cpp:97 msgid "Enter a name for the new layer." msgstr "Entrez un nom pour la nouvelle couche." #: src/program/NormalsGenDialog.cpp:97 msgid "Name new layer" msgstr "Nommez la nouvelle couche" #: src/program/NormalsGenDialog.cpp:220 msgid "Choose a normals generator preset file..." msgstr "Choisissez un fichier de préréglage du générateur de normales..." #: src/program/NormalsGenDialog.cpp:238 msgid "Save normals generator preset to..." msgstr "Enregistrer le préréglage du générateur de normales dans..." #: src/program/NormalsGenDialog.cpp:257 msgid "Layer" msgstr "Couche" #: src/program/NormalsGenDialog.cpp:282 msgid "Background File" msgstr "Fichier de Fond" #: src/program/NormalsGenDialog.cpp:283 msgid "File source for this layer." msgstr "Source du fichier pour cette couche." #: src/program/NormalsGenDialog.cpp:284 msgid "Color" msgstr "Couleur" #: src/program/NormalsGenDialog.cpp:285 msgid "Solid background color (if file is not set)." msgstr "Couleur de fond solide (si le fichier n'est pas défini)." #: src/program/NormalsGenDialog.cpp:286 msgid "Resolution" msgstr "Résolution" #: src/program/NormalsGenDialog.cpp:288 msgid "" "Output texture dimensions. By default all images will be scaled to fit this " "size." msgstr "" "Dimensions de la texture de sortie. Par défaut, toutes les images seront " "mises à l'échelle pour correspondre à cette taille." #: src/program/NormalsGenDialog.cpp:306 msgid "" "File containing normals data to combine. Note this file should fit the mesh " "UVs." msgstr "" "Fichier contenant des données normales à combiner. Notez que ce fichier doit " "s'adapter aux UV du maillage." #: src/program/NormalsGenDialog.cpp:308 msgid "Is Tangent Space?" msgstr "C'est l'espace Tangent?" #: src/program/NormalsGenDialog.cpp:309 msgid "" "True if the normals data in the layer file is in tangent space, false if " "they are in model space (msn)." msgstr "" "Vrai si les données normales dans le fichier de couche sont dans l'espace " "tangent, faux si elles sont dans l'espace modèle (msn)." #: src/program/NormalsGenDialog.cpp:312 msgid "A greyscale image used to mask updates to destination image." msgstr "" "Une image en niveaux de gris utilisée pour masquer les mises à jour de " "l'image de destination." #: src/program/NormalsGenDialog.cpp:314 msgid "X Offset" msgstr "X Décalage" #: src/program/NormalsGenDialog.cpp:315 src/program/NormalsGenDialog.cpp:318 msgid "Offset to apply to image position." msgstr "Décalage à appliquer à la position de l'image." #: src/program/NormalsGenDialog.cpp:317 msgid "Y Offset" msgstr "Y Décalage" #: src/program/NormalsGenDialog.cpp:321 msgid "If true, scale image to match background resolution." msgstr "" "Si vrai, mettre l'image à l'échelle pour qu'elle corresponde à la résolution " "du fond." #: src/program/OutfitProject.cpp:51 msgid "Checking destination..." msgstr "Vérification de la destination..." #: src/program/OutfitProject.cpp:101 msgid "Adding reference shapes..." msgstr "Ajout de formes de référence..." #: src/program/OutfitProject.cpp:119 src/program/OutfitProject.cpp:2163 msgid "Adding outfit shapes..." msgstr "Ajouter des formes de tenues..." #: src/program/OutfitProject.cpp:176 msgid "Calculating slider data..." msgstr "Calculer les données du slider..." #: src/program/OutfitProject.cpp:184 msgid "Creating slider set file..." msgstr "Création d'un fichier de slider set..." #: src/program/OutfitProject.cpp:194 msgid "Failed to open or create slider set file: " msgstr "Impossible d'ouvrir ou de créer le fichier du slider set: " #: src/program/OutfitProject.cpp:211 msgid "Saving slider set file..." msgstr "Sauvegarde du fichier de slider set..." #: src/program/OutfitProject.cpp:214 msgid "Failed to write to slider set file: " msgstr "Échec de l'écriture dans le fichier de slider set: " #: src/program/OutfitProject.cpp:218 msgid "Saving NIF file..." msgstr "Sauvegarde du fichier NIF..." #: src/program/OutfitProject.cpp:248 msgid "Failed to write base .nif file: " msgstr "Échec de l'écriture du fichier .nif de base: " #: src/program/OutfitProject.cpp:254 src/program/OutfitProject.cpp:1626 #: src/program/OutfitProject.cpp:1656 src/program/OutfitProject.cpp:2139 #: src/program/OutfitProject.cpp:2217 src/program/OutfitStudio.cpp:423 #: src/program/OutfitStudio.cpp:435 src/program/OutfitStudio.cpp:447 #: src/program/OutfitStudio.cpp:2206 src/program/OutfitStudio.cpp:3228 #: src/program/OutfitStudio.cpp:3351 src/program/OutfitStudio.cpp:3423 #: src/program/OutfitStudio.cpp:7558 src/program/OutfitStudio.cpp:7597 #: src/program/OutfitStudio.cpp:9036 src/program/OutfitStudio.cpp:9127 #: src/program/OutfitStudio.cpp:9176 src/program/OutfitStudio.cpp:11841 #: src/program/OutfitStudio.cpp:11853 src/program/OutfitStudio.cpp:11865 #: src/program/OutfitStudio.cpp:11915 msgid "Finished" msgstr "Fini" #: src/program/OutfitProject.cpp:1522 src/program/OutfitProject.cpp:1612 msgid "Gathering bones..." msgstr "Rassembler les os..." #: src/program/OutfitProject.cpp:1550 msgid "Initializing proximity data..." msgstr "Initialisation des données de proximité..." #: src/program/OutfitProject.cpp:1594 src/program/OutfitStudio.cpp:8986 msgid "Copying bone weights..." msgstr "Copie des poids osseux..." #: src/program/OutfitProject.cpp:1632 src/program/OutfitStudio.cpp:9168 msgid "Transferring bone weights..." msgstr "Transfert de poids osseux..." #: src/program/OutfitProject.cpp:1880 msgid "Template source entries are invalid." msgstr "Les entrées de source du modèle ne sont pas valides." #: src/program/OutfitProject.cpp:1880 src/program/OutfitProject.cpp:1909 #: src/program/OutfitProject.cpp:1914 src/program/OutfitProject.cpp:1957 #: src/program/OutfitProject.cpp:1980 src/program/OutfitProject.cpp:1987 #: src/program/OutfitProject.cpp:1997 src/program/OutfitProject.cpp:2009 msgid "Reference Error" msgstr "Erreur de Référence" #: src/program/OutfitProject.cpp:1905 src/program/OutfitProject.cpp:1976 #: src/program/OutfitProject.cpp:3410 #, c-format msgid "" "NIF version not supported!\n" "\n" "File: %s\n" "%s" msgstr "" "Version NIF non prise en charge!\n" "\n" "File: %s\n" "%s" #: src/program/OutfitProject.cpp:1914 src/program/OutfitProject.cpp:1987 #, c-format msgid "Could not load reference NIF file '%s'!" msgstr "Impossible de charger le fichier NIF de référence '%s'!" #: src/program/OutfitProject.cpp:1957 #, c-format msgid "Could not load slider set file '%s'!" msgstr "Impossible de charger le fichier de slider set '%s'!" #: src/program/OutfitProject.cpp:1997 #, c-format msgid "Reference NIF file '%s' does not contain any shapes." msgstr "Le fichier NIF de référence '%s' ne contient aucune forme." #: src/program/OutfitProject.cpp:2009 #, c-format msgid "Shape '%s' not found in reference NIF file '%s'!" msgstr "Forme '%s' non trouvée dans le fichier NIF de référence '%s'!" #: src/program/OutfitProject.cpp:2061 msgid "Loading slider set..." msgstr "Chargement du slider set..." #: src/program/OutfitProject.cpp:2068 src/program/OutfitProject.cpp:2153 msgid "Retrieving sliders..." msgstr "Récupérer les sliders..." #: src/program/OutfitProject.cpp:2078 msgid "Loading outfit shapes..." msgstr "Chargement des formes de tenues..." #: src/program/OutfitProject.cpp:2121 src/program/OutfitProject.cpp:2214 msgid "Updating slider data..." msgstr "Mise à jour des données du slider..." #: src/program/OutfitProject.cpp:2145 msgid "Adding slider set..." msgstr "Ajout d'un slider set..." #: src/program/OutfitProject.cpp:2211 msgid "" "The following shapes were renamed and won't have slider data attached. " "Rename the duplicates yourself beforehand." msgstr "" "Les formes suivantes ont été renommées et n'auront pas de données de slider " "attachées. Renommez les doublons vous-même au préalable." #: src/program/OutfitProject.cpp:2211 msgid "Renamed Shapes" msgstr "Formes Renommées" #: src/program/OutfitProject.cpp:3414 src/program/OutfitProject.cpp:3419 msgid "NIF Error" msgstr "Erreur NIF" #: src/program/OutfitProject.cpp:3419 #, c-format msgid "Could not load NIF file '%s'!" msgstr "Impossible de charger le fichier NIF '%s'!" #: src/program/OutfitProject.cpp:3550 msgid "" "There was cloth physics data loaded at some point (BSClothExtraData). Please " "choose all the origins to use in the output." msgstr "" "Des données de physique du tissu ont été chargées à un moment donné " "(BSClothExtraData). Veuillez choisir toutes les origines à utiliser dans la " "sortie." #: src/program/OutfitProject.cpp:3550 msgid "Choose cloth data" msgstr "Choisir les données du tissu" #: src/program/OutfitProject.cpp:3601 msgid "" "No reference has been loaded. For correct bone transforms, you might need " "to load a reference before importing OBJ files. Import anyway?" msgstr "" "Aucune référence n'a été chargée. Pour des transformations osseuses " "correctes, il peut être nécessaire de charger une référence avant d'importer " "des fichiers OBJ. Importer quand même?" #: src/program/OutfitProject.cpp:3601 src/program/OutfitProject.cpp:3743 msgid "Import without reference" msgstr "Importez sans Référence" #: src/program/OutfitProject.cpp:3608 src/program/OutfitProject.cpp:3750 msgid "" "The reference shape has a skin coordinate system that is different from the " "global coordinate system. Would you like to copy the reference's global-to-" "skin transform to the imported shapes?" msgstr "" "La forme de référence a un système de coordonnées de peau qui est différent " "du système de coordonnées global. Voulez-vous copier la transformation " "globale-peau de la référence sur les formes importées?" #: src/program/OutfitProject.cpp:3608 src/program/OutfitProject.cpp:3750 msgid "Copy skin coordinates" msgstr "Transformez les coordonnées de la peau" #: src/program/OutfitProject.cpp:3625 #, c-format msgid "Could not load OBJ file '%s'!" msgstr "Impossible de charger le fichier OBJ '%s'!" #: src/program/OutfitProject.cpp:3625 src/program/OutfitProject.cpp:3637 #: src/program/OutfitProject.cpp:3682 src/program/OutfitProject.cpp:3822 msgid "OBJ Error" msgstr "Erreur OBJ" #: src/program/OutfitProject.cpp:3637 #, c-format msgid "Could not copy data from OBJ file '%s'!" msgstr "Impossible de copier les données du fichier OBJ '%s'!" #: src/program/OutfitProject.cpp:3654 msgid "" "The vertex count of the selected .obj file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "Le nombre de vertex du fichier .obj sélectionné correspond à la forme de la " "tenue actuellement sélectionnée. Souhaitez-vous mettre à jour la forme " "actuelle? (cliquez sur Non pour créer une nouvelle forme)" #: src/program/OutfitProject.cpp:3654 src/program/OutfitProject.cpp:3784 msgid "Merge or New" msgstr "Fusionner ou Nouveaux" #: src/program/OutfitProject.cpp:3656 src/program/OutfitProject.cpp:3786 msgid "Update Vertex Positions?" msgstr "Mettre à jour les positions des vertex?" #: src/program/OutfitProject.cpp:3656 src/program/OutfitProject.cpp:3786 msgid "Vertex Position Update" msgstr "Mise à jour de la position des vertex" #: src/program/OutfitProject.cpp:3660 src/program/OutfitProject.cpp:3790 msgid "Update Texture Coordinates?" msgstr "Mettre à jour les coordonnées de texture?" #: src/program/OutfitProject.cpp:3660 src/program/OutfitProject.cpp:3790 msgid "UV Update" msgstr "Mise à jour UV" #: src/program/OutfitProject.cpp:3667 src/program/OutfitProject.cpp:3803 msgid "Please specify a name for the new shape" msgstr "Veuillez saisir un nom pour le nouveau forme" #: src/program/OutfitProject.cpp:3667 src/program/OutfitProject.cpp:3803 msgid "New Shape Name" msgstr "Nouveau Nom de Forme" #: src/program/OutfitProject.cpp:3681 src/program/OutfitProject.cpp:3821 #, c-format msgid "" "The vertex or triangle limit for '%s' was exceeded.\n" "Remaining data was dropped.\n" "\n" "Vertices (current/max): %zu/%zu\n" "Triangles (current/max): %zu/%zu" msgstr "" "La limite de vertex ou de triangles pour '%s' a été dépassée.\n" "Les données restantes ont été abandonnées.\n" "\n" "Vertices (actuels/maximaux): %zu/%zu\n" "Triangles (actuels/maximaux): %zu/%zu" #: src/program/OutfitProject.cpp:3743 msgid "" "No reference has been loaded. For correct bone transforms, you might need " "to load a reference before importing FBX files. Import anyway?" msgstr "" "Aucune référence n'a été chargée. Pour des transformations osseuses " "correctes, il peut être nécessaire de charger une référence avant d'importer " "des fichiers FBX. Importer quand même?" #: src/program/OutfitProject.cpp:3784 msgid "" "The vertex count of the selected .fbx file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "Le nombre de vertex du fichier .fbx sélectionné correspond à la forme de la " "tenue actuellement sélectionnée. Souhaitez-vous mettre à jour la forme " "actuelle? (cliquez sur Non pour créer une nouvelle forme)" #: src/program/OutfitProject.cpp:3794 msgid "Update Animation Weighting?" msgstr "Mise à jour de la Pondération des Animations?" #: src/program/OutfitProject.cpp:3794 msgid "Animation Weight Update" msgstr "Mise à jour des Poids d'Animation" #: src/program/OutfitProject.cpp:3902 msgid "Would you like Skyrim NIFs to be optimized for SSE during this session?" msgstr "" "Souhaitez-vous que les NIFs de Skyrim soient optimisés pour SSE pendant " "cette session?" #: src/program/OutfitProject.cpp:3919 msgid "" "Version of NIF file doesn't match current target game. To use the meshes for " "the target game, export to OBJ/FBX and reload them again." msgstr "" "La version du fichier NIF ne correspond pas au jeu cible actuel. Pour " "utiliser les maillages pour le jeu cible, exportez-les vers OBJ/FBX et " "rechargez-les à nouveau." #: src/program/OutfitProject.cpp:3919 msgid "Version" msgstr "Version" #: src/program/OutfitStudio.cpp:415 src/program/OutfitStudio.cpp:416 #: src/program/OutfitStudio.cpp:11833 src/program/OutfitStudio.cpp:11834 msgid "Adding NIF file..." msgstr "Ajout d'un fichier NIF..." #: src/program/OutfitStudio.cpp:420 src/program/OutfitStudio.cpp:432 #: src/program/OutfitStudio.cpp:444 src/program/OutfitStudio.cpp:3885 #: src/program/OutfitStudio.cpp:11838 src/program/OutfitStudio.cpp:11850 #: src/program/OutfitStudio.cpp:11862 msgid "Refreshing GUI..." msgstr "Rafraîchissante GUI..." #: src/program/OutfitStudio.cpp:428 src/program/OutfitStudio.cpp:11846 msgid "Adding OBJ file..." msgstr "Ajout d'un fichier OBJ..." #: src/program/OutfitStudio.cpp:439 src/program/OutfitStudio.cpp:440 #: src/program/OutfitStudio.cpp:11857 src/program/OutfitStudio.cpp:11858 msgid "Adding FBX file..." msgstr "Ajout d'un fichier FBX..." #: src/program/OutfitStudio.cpp:918 msgid "Failed to load OutfitStudio.xrc file!" msgstr "Échec du chargement du fichier OutfitStudio.xrc!" #: src/program/OutfitStudio.cpp:924 msgid "Failed to load Outfit Studio frame!" msgstr "Échec du chargement du cadre Outfit Studio!" #: src/program/OutfitStudio.cpp:942 src/program/OutfitStudio.h:1113 msgid "Ready!" msgstr "Prêt!" #: src/program/OutfitStudio.cpp:1335 src/program/OutfitStudio.cpp:1340 msgid "Packing projects to folder..." msgstr "Emballage des projets dans les dossiers..." #: src/program/OutfitStudio.cpp:1361 src/program/OutfitStudio.cpp:1409 #: src/program/OutfitStudio.cpp:1512 #, c-format msgid "Failed to open input file '%s'!" msgstr "Échec de l'ouverture le fichier d'entrée '%s'!" #: src/program/OutfitStudio.cpp:1372 #, c-format msgid "Failed to copy input file '%s'!" msgstr "Échec de copier le fichier d'entrée '%s'!" #: src/program/OutfitStudio.cpp:1420 #, c-format msgid "Failed to copy data file '%s'!" msgstr "Échec de copier le fichier de données '%s'!" #: src/program/OutfitStudio.cpp:1430 src/program/OutfitStudio.cpp:1589 #, c-format msgid "Failed to save merged project file '%s'!" msgstr "Échec de l'enregistrement du fichier de projet fusionné '%s'!" #: src/program/OutfitStudio.cpp:1439 src/program/OutfitStudio.cpp:1598 #, c-format msgid "Failed to open project file '%s'!" msgstr "Échec de l'ouverture du fichier de projet '%s'!" #: src/program/OutfitStudio.cpp:1450 #, c-format msgid "Failed to copy merged project file '%s'!" msgstr "Échec de la copie du fichier de projet fusionné '%s'!" #: src/program/OutfitStudio.cpp:1461 src/program/OutfitStudio.cpp:1624 #, c-format msgid "Failed to open group file '%s'!" msgstr "Échec de l'ouverture le fichier de groupe '%s'!" #: src/program/OutfitStudio.cpp:1473 #, c-format msgid "Failed to copy group file '%s'!" msgstr "Échec de copier le fichier de groupe '%s'!" #: src/program/OutfitStudio.cpp:1483 src/program/OutfitStudio.cpp:1488 msgid "Packing projects to archive..." msgstr "Emballage des projets dans l'archive..." #: src/program/OutfitStudio.cpp:1520 src/program/OutfitStudio.cpp:1572 #: src/program/OutfitStudio.cpp:1606 src/program/OutfitStudio.cpp:1633 msgid "Failed to put new entry into archive!" msgstr "Échec de la mise la nouvelle entrée dans l'archive!" #: src/program/OutfitStudio.cpp:1527 src/program/OutfitStudio.cpp:1579 #: src/program/OutfitStudio.cpp:1613 src/program/OutfitStudio.cpp:1640 msgid "Failed to copy file contents to archive!" msgstr "Échec de la copie du contenu du fichier dans l'archive!" #: src/program/OutfitStudio.cpp:1564 #, c-format msgid "Failed to open data file '%s'!" msgstr "Échec de l'ouverture le fichier de données '%s'!" #: src/program/OutfitStudio.cpp:1888 src/program/OutfitStudio.cpp:1925 #: src/program/OutfitStudio.cpp:4275 src/program/OutfitStudio.cpp:4301 #: src/program/OutfitStudio.cpp:6814 src/program/OutfitStudio.cpp:6904 #: src/program/OutfitStudio.cpp:7126 src/program/OutfitStudio.cpp:7144 #: src/program/OutfitStudio.cpp:7162 msgid "There are no valid shapes loaded!" msgstr "Il n'y a pas de formes valides chargées!" #: src/program/OutfitStudio.cpp:1896 src/program/OutfitStudio.cpp:2063 #, c-format msgid "Saving project '%s'..." msgstr "Sauvegarde du projet '%s'..." #: src/program/OutfitStudio.cpp:2009 msgid "Invalid or no slider set file specified! Please try again." msgstr "Fichier de slider set non valide ou non spécifié! Veuillez réessayer." #: src/program/OutfitStudio.cpp:2018 msgid "No outfit name specified! Please try again." msgstr "Aucun nom de tenue n'a été spécifié! Veuillez réessayer." #: src/program/OutfitStudio.cpp:2026 msgid "No data folder specified! Please try again." msgstr "Aucun dossier de données n'a été spécifié! Veuillez réessayer." #: src/program/OutfitStudio.cpp:2040 msgid "" "An invalid or no base outfit .nif file name specified! Please try again." msgstr "" "Un nom de fichier .nif invalide ou sans tenue de base a été spécifié! " "Veuillez réessayer." #: src/program/OutfitStudio.cpp:2049 msgid "No game file path specified! Please try again." msgstr "Aucun chemin de fichier de jeu n'a été spécifié! Veuillez réessayer." #: src/program/OutfitStudio.cpp:2055 msgid "No game file name specified! Please try again." msgstr "Aucun nom de fichier de jeu n'a été spécifié! Veuillez réessayer." #: src/program/OutfitStudio.cpp:2096 #, c-format msgid "Failed to open '%s' as a slider set file!" msgstr "Impossible d'ouvrir '%s' comme fichier de slider set!" #: src/program/OutfitStudio.cpp:2096 src/program/OutfitStudio.cpp:2160 msgid "Slider Set Error" msgstr "Slider Set Erreur" #: src/program/OutfitStudio.cpp:2115 msgid "Please choose an outfit to load" msgstr "Choisissez une tenue à charger" #: src/program/OutfitStudio.cpp:2115 msgid "Load a slider set" msgstr "Chargez un slider set" #: src/program/OutfitStudio.cpp:2126 msgid "Loading project..." msgstr "Chargement projet..." #: src/program/OutfitStudio.cpp:2146 msgid "Loading outfit data..." msgstr "Chargement des données de tenues..." #: src/program/OutfitStudio.cpp:2160 #, c-format msgid "Failed to create project '%s' from file '%s' (%d)!" msgstr "Impossible de créer le projet '%s' à partir du fichier '%s' (%d)!" #: src/program/OutfitStudio.cpp:2174 #, c-format msgid "Loading reference shape '%s'..." msgstr "Chargement la forme référence '%s'..." #: src/program/OutfitStudio.cpp:2188 msgid "Loading textures..." msgstr "Chargement textures..." #: src/program/OutfitStudio.cpp:2193 src/program/OutfitStudio.cpp:3208 #: src/program/OutfitStudio.cpp:3417 msgid "Creating outfit..." msgstr "Créer des tenues..." #: src/program/OutfitStudio.cpp:2197 src/program/OutfitStudio.cpp:3218 #: src/program/OutfitStudio.cpp:3344 #, c-format msgid "Creating %zu slider(s)..." msgstr "Créer %zu slider(s)..." #: src/program/OutfitStudio.cpp:2220 msgid "Creating sliders..." msgstr "Créer des sliders..." #: src/program/OutfitStudio.cpp:2223 msgid "Clearing old sliders..." msgstr "Nettoyage des anciens sliders..." #: src/program/OutfitStudio.cpp:2237 msgid "Loading slider: " msgstr "Chargement du slider: " #: src/program/OutfitStudio.cpp:2268 msgid "Turn on edit mode for this slider." msgstr "Activez le mode d'édition pour ce slider." #: src/program/OutfitStudio.cpp:2272 msgid "Weaken slider data by 1%." msgstr "Affaiblir les données du slider de 1%." #: src/program/OutfitStudio.cpp:2278 msgid "Strengthen slider data by 1%." msgstr "Renforcer les données du slider de 1%." #: src/program/OutfitStudio.cpp:2335 src/program/OutfitStudio.cpp:7281 msgid "Enter a name for the new slider:" msgstr "Entrez un nom pour le nouveau slider:" #: src/program/OutfitStudio.cpp:2335 src/program/OutfitStudio.cpp:7281 msgid "Create New Slider" msgstr "Créez Slider Nouveau" #: src/program/OutfitStudio.cpp:2462 #, c-format msgid "Total Bones: %zu" msgstr "Total des Os: %zu" #: src/program/OutfitStudio.cpp:2477 #, c-format msgid "Shape Selection Bones: %zu" msgstr "Sélection des Formes Os: %zu" #: src/program/OutfitStudio.cpp:2959 msgid "Edit Color" msgstr "Modifiez Couleur" #: src/program/OutfitStudio.cpp:3014 msgid "" "You are trying to edit a slider's morph with that slider set to zero. Do " "you wish to set the slider to one now?" msgstr "" "Vous essayez de modifier la morphologie d'un slider alors que celui-ci est " "réglé sur zéro. Voulez-vous mettre le slider à un maintenant ?" #: src/program/OutfitStudio.cpp:3029 msgid "" "You can only use the undiff brush while editing a slider. Note, use the " "pencil button next to a slider to enable editing of that slider's morph." msgstr "" "Vous ne pouvez utiliser le pinceau d'undiff que lorsque vous modifiez un " "slider. Remarque, utilisez le bouton crayon à côté d'un slider pour activer " "l'édition de la morphologie de ce slider." #: src/program/OutfitStudio.cpp:3037 msgid "" "You can only edit the base shape when all sliders are zero. Do you wish to " "set all sliders to zero now? Note, use the pencil button next to a slider " "to enable editing of that slider's morph." msgstr "" "Vous ne pouvez modifier la forme de base que lorsque tous les sliders sont à " "zéro. Voulez-vous mettre tous les sliders à zéro maintenant ? Remarque, " "utilisez le bouton crayon à côté d'un slider pour activer l'édition de la " "morphologie de ce slider." #: src/program/OutfitStudio.cpp:3067 #, c-format msgid "You have unsaved changes to '%s'. Would you like to save them now?" msgstr "" "Vous avez des modifications non sauvegardées sur '%s'. Voulez-vous les " "sauvegarder maintenant?" #: src/program/OutfitStudio.cpp:3067 msgid "Unsaved Changes" msgstr "Modifications Non Sauvegarder" #: src/program/OutfitStudio.cpp:3126 #, c-format msgid "Creating project '%s'..." msgstr "Créer le projet '%s'..." #: src/program/OutfitStudio.cpp:3143 src/program/OutfitStudio.cpp:3284 msgid "Loading reference..." msgstr "Chargement référence..." #: src/program/OutfitStudio.cpp:3187 src/program/OutfitStudio.cpp:3375 #: src/program/OutfitStudio.cpp:3384 msgid "Loading outfit..." msgstr "Chargement de tenues..." #: src/program/OutfitStudio.cpp:3234 msgid "Select a slider set to load" msgstr "Sélectionnez un slider set à charger" #: src/program/OutfitStudio.cpp:3246 msgid "Select a slider set to add" msgstr "Sélectionnez un slider set à ajouter" #: src/program/OutfitStudio.cpp:3259 src/program/OutfitStudio.cpp:8264 #: src/program/OutfitStudio.cpp:8318 src/program/OutfitStudio.cpp:8407 msgid "" "You're currently editing slider data, please exit the slider's edit mode " "(pencil button) and try again." msgstr "" "Vous êtes en train de modifier les données du slider, veuillez quitter le " "mode d'édition du slider (bouton crayon) et réessayer." #: src/program/OutfitStudio.cpp:3290 msgid "Loading reference set..." msgstr "Chargement du jeu de références..." #: src/program/OutfitStudio.cpp:3340 msgid "Creating reference..." msgstr "Créer une référence..." #: src/program/OutfitStudio.cpp:3428 msgid "Unload the project? All unsaved changes will be lost" msgstr "" "Décharger le projet? Toutes les modifications non sauvegardées seront perdues" #: src/program/OutfitStudio.cpp:3428 msgid "Unload Project" msgstr "Déchargez le Projet" #: src/program/OutfitStudio.cpp:3429 msgid "Unload" msgstr "Déchargez" #: src/program/OutfitStudio.cpp:3872 msgid "Import NIF file" msgstr "Importer un fichier NIF" #: src/program/OutfitStudio.cpp:3879 src/program/OutfitStudio.cpp:3880 msgid "Importing NIF file..." msgstr "Importation d'un fichier NIF..." #: src/program/OutfitStudio.cpp:3891 msgid "Finished." msgstr "Fini." #: src/program/OutfitStudio.cpp:3902 msgid "Export outfit NIF" msgstr "Exporter la tenue NIF" #: src/program/OutfitStudio.cpp:3917 #, c-format msgid "Failed to save NIF file '%s'!" msgstr "Échec de l'enregistrement du fichier NIF '%s'!" #: src/program/OutfitStudio.cpp:3917 src/program/OutfitStudio.cpp:3947 #: src/program/OutfitStudio.cpp:4031 src/program/OutfitStudio.cpp:4146 #: src/program/OutfitStudio.cpp:4363 msgid "Export Error" msgstr "Erreur d'Exportation" #: src/program/OutfitStudio.cpp:3933 msgid "Export project NIF" msgstr "Exporter la projet NIF" #: src/program/OutfitStudio.cpp:3947 #, c-format msgid "Failed to save NIF file '%s' with reference!" msgstr "Échec de l'enregistrement du fichier NIF '%s' avec référence!" #: src/program/OutfitStudio.cpp:3953 src/program/OutfitStudio.cpp:4037 #: src/program/OutfitStudio.cpp:4152 src/program/OutfitStudio.cpp:4280 #: src/program/OutfitStudio.cpp:4306 src/program/OutfitStudio.cpp:6743 #: src/program/OutfitStudio.cpp:6768 src/program/OutfitStudio.cpp:6789 #: src/program/OutfitStudio.cpp:6996 src/program/OutfitStudio.cpp:7021 #: src/program/OutfitStudio.cpp:7057 src/program/OutfitStudio.cpp:7090 #: src/program/OutfitStudio.cpp:7186 src/program/OutfitStudio.cpp:7236 #: src/program/OutfitStudio.cpp:7296 src/program/OutfitStudio.cpp:7313 #: src/program/OutfitStudio.cpp:7688 src/program/OutfitStudio.cpp:7705 #: src/program/OutfitStudio.cpp:7723 src/program/OutfitStudio.cpp:7747 #: src/program/OutfitStudio.cpp:7782 src/program/OutfitStudio.cpp:7928 #: src/program/OutfitStudio.cpp:8112 src/program/OutfitStudio.cpp:8259 #: src/program/OutfitStudio.cpp:8313 src/program/OutfitStudio.cpp:8529 #: src/program/OutfitStudio.cpp:8972 src/program/OutfitStudio.cpp:9046 #: src/program/OutfitStudio.cpp:9137 src/program/OutfitStudio.cpp:9184 #: src/program/OutfitStudio.cpp:9214 src/program/OutfitStudio.cpp:9266 #: src/program/OutfitStudio.cpp:9440 src/program/OutfitStudio.cpp:11891 msgid "There is no shape selected!" msgstr "Il n'y a pas de forme sélectionnée!" #: src/program/OutfitStudio.cpp:3960 msgid "Export selected shapes to NIF" msgstr "Exportez les formes sélectionnées vers NIF" #: src/program/OutfitStudio.cpp:3973 msgid "Failed to export selected shapes to NIF file!" msgstr "Impossible d'exporter les formes sélectionnées vers le fichier NIF!" #: src/program/OutfitStudio.cpp:3978 msgid "Import .obj file for new shape" msgstr "Importez un fichier .obj pour une nouvelle forme" #: src/program/OutfitStudio.cpp:4016 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the OBJ? (This is not recommended.)" msgstr "" "Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont " "pas les mêmes que le système de coordonnées global. La géométrie doit-elle " "être transformée en coordonnées globales dans l'OBJ? (Ceci n'est pas " "recommandé)." #: src/program/OutfitStudio.cpp:4016 src/program/OutfitStudio.cpp:4049 #: src/program/OutfitStudio.cpp:4131 src/program/OutfitStudio.cpp:4164 msgid "Transform to global" msgstr "Transformez a la globales" #: src/program/OutfitStudio.cpp:4022 msgid "Export project as an .obj file" msgstr "Exporter la projet sous forme de fichier .obj" #: src/program/OutfitStudio.cpp:4031 src/program/OutfitStudio.cpp:4070 #: src/program/OutfitStudio.cpp:4084 src/program/OutfitStudio.cpp:7117 msgid "Failed to export OBJ file!" msgstr "Échec de l'exportation du fichier OBJ!" #: src/program/OutfitStudio.cpp:4049 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the OBJ?" msgstr "" "Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont " "pas les mêmes que le système de coordonnées global. La géométrie doit-elle " "être transformée en coordonnées globales dans l'OBJ?" #: src/program/OutfitStudio.cpp:4056 msgid "Export selected shapes as an .obj file" msgstr "Exporter les formes sélectionnées sous forme de fichier .obj" #: src/program/OutfitStudio.cpp:4074 msgid "Export shape as an .obj file" msgstr "Exporter la forme sous forme de fichier .obj" #: src/program/OutfitStudio.cpp:4090 msgid "Import .fbx file for new shape" msgstr "Importez un fichier .fbx pour une nouvelle forme" #: src/program/OutfitStudio.cpp:4131 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the FBX? (This is not recommended.)" msgstr "" "Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont " "pas les mêmes que le système de coordonnées global. La géométrie doit-elle " "être transformée en coordonnées globales dans le FBX? (Ceci n'est pas " "recommandé)." #: src/program/OutfitStudio.cpp:4137 msgid "Export project as an .fbx file" msgstr "Exporter la projet sous forme de fichier .fbx" #: src/program/OutfitStudio.cpp:4146 src/program/OutfitStudio.cpp:4185 #: src/program/OutfitStudio.cpp:4199 msgid "Failed to export FBX file!" msgstr "Échec de l'exportation du fichier FBX!" #: src/program/OutfitStudio.cpp:4164 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the FBX?" msgstr "" "Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont " "pas les mêmes que le système de coordonnées global. La géométrie doit-elle " "être transformée en coordonnées globales dans le FBX?" #: src/program/OutfitStudio.cpp:4171 msgid "Export selected shapes as an .fbx file" msgstr "Exporter les formes sélectionnées sous forme de fichier .fbx" #: src/program/OutfitStudio.cpp:4189 msgid "Export shape as an .fbx file" msgstr "Exporter la forme sous forme de fichier .fbx" #: src/program/OutfitStudio.cpp:4205 src/program/OutfitStudio.cpp:6908 msgid "Import .tri morphs" msgstr "Importez .tri morphs" #: src/program/OutfitStudio.cpp:4224 src/program/OutfitStudio.cpp:6922 msgid "Failed to load TRI file!" msgstr "Échec du chargement du fichier TRI!" #: src/program/OutfitStudio.cpp:4230 src/program/OutfitStudio.cpp:7729 msgid "Please enter a new unique name for the shape." msgstr "Veuillez saisir un nouveau nom unique pour la forme." #: src/program/OutfitStudio.cpp:4230 src/program/OutfitStudio.cpp:7729 msgid "Rename Shape" msgstr "Renommez la Forme" #: src/program/OutfitStudio.cpp:4284 src/program/OutfitStudio.cpp:4310 #: src/program/OutfitStudio.cpp:7148 msgid "Export .tri morphs" msgstr "Exportez .tri morphs" #: src/program/OutfitStudio.cpp:4294 src/program/OutfitStudio.cpp:4317 #: src/program/OutfitStudio.cpp:7155 msgid "Failed to export TRI file!" msgstr "Échec de l'exportation du fichier TRI!" #: src/program/OutfitStudio.cpp:4322 msgid "Import physics data to project" msgstr "Importer des données physiques dans le projet" #: src/program/OutfitStudio.cpp:4329 #, c-format msgid "Failed to import physics data file '%s'!" msgstr "Échec de l'importation du fichier de données physiques '%s'!" #: src/program/OutfitStudio.cpp:4329 msgid "Import Error" msgstr "Erreur d'Importation" #: src/program/OutfitStudio.cpp:4341 msgid "There is no physics data loaded!" msgstr "Il n'y a pas de données physiques chargées!" #: src/program/OutfitStudio.cpp:4341 src/program/OutfitStudio.cpp:6730 msgid "Info" msgstr "Info" #: src/program/OutfitStudio.cpp:4349 msgid "Please choose the physics data source you want to export." msgstr "" "Veuillez choisir la source de données physiques que vous souhaitez exporter." #: src/program/OutfitStudio.cpp:4349 msgid "Choose physics data" msgstr "Choisir de données physiques" #: src/program/OutfitStudio.cpp:4357 msgid "Export physics data" msgstr "Exportez de données physiques" #: src/program/OutfitStudio.cpp:4363 #, c-format msgid "Failed to save physics data file '%s'!" msgstr "Échec de l'enregistrement du fichier de données physiques '%s'!" #: src/program/OutfitStudio.cpp:4370 msgid "This function requires at least one slider position to be non-zero." msgstr "" "Cette fonction nécessite qu'au moins une position de slider soit différente " "de zéro." #: src/program/OutfitStudio.cpp:4381 msgid "" "Create a conversion slider for the current slider settings with the " "following name: " msgstr "" "Créez un slider de conversion pour les paramètres de slider actuels avec le " "nom suivant: " #: src/program/OutfitStudio.cpp:4381 msgid "Create New Conversion Slider" msgstr "Créez Slider Conversion Nouveau" #: src/program/OutfitStudio.cpp:5122 msgid "Please enter an SSF file path." msgstr "Veuillez saisir un chemin d'accès au fichier SSF." #: src/program/OutfitStudio.cpp:5844 #, c-format msgid "Field of View: %d" msgstr "Champ de Vision: %d" #: src/program/OutfitStudio.cpp:5966 msgid "Your changes were not applied yet. Do you want to apply or reset them?" msgstr "" "Vos modifications n'ont pas encore été appliquées. Voulez-vous les appliquer " "ou les réinitialiser?" #: src/program/OutfitStudio.cpp:5966 msgid "Pending Changes" msgstr "Modifications en Attente" #: src/program/OutfitStudio.cpp:6681 msgid "There are no sliders loaded!" msgstr "Il n'y a pas de sliders chargés!" #: src/program/OutfitStudio.cpp:6730 msgid "No changes were made to the sliders, so no preset was saved!" msgstr "" "Aucune modification n'a été apportée aux sliders, donc aucun préréglage n'a " "été enregistré!" #: src/program/OutfitStudio.cpp:6747 src/program/OutfitStudio.cpp:6772 #: src/program/OutfitStudio.cpp:6793 src/program/OutfitStudio.cpp:7000 msgid "There is no slider in edit mode to import data to!" msgstr "Il n'y a pas de slider en mode édition pour importer des données!" #: src/program/OutfitStudio.cpp:6751 msgid "Import .nif file for slider calculation" msgstr "Importez un fichier .nif pour le calcul du slider" #: src/program/OutfitStudio.cpp:6758 msgid "No mesh found in the .nif file that matches currently selected shape!" msgstr "" "Aucun maillage trouvé dans le fichier .nif qui correspond à la forme " "actuellement sélectionnée!" #: src/program/OutfitStudio.cpp:6776 msgid "Import .bsd slider data" msgstr "Importez les données du slider .bsd" #: src/program/OutfitStudio.cpp:6797 msgid "Import .obj file for slider calculation" msgstr "Importez un fichier .obj pour le calcul du slider" #: src/program/OutfitStudio.cpp:6804 src/program/OutfitStudio.cpp:7011 msgid "Vertex count of .obj file mesh does not match currently selected shape!" msgstr "" "Le nombre de vertex du maillage du fichier .obj ne correspond pas à la forme " "actuellement sélectionnée!" #: src/program/OutfitStudio.cpp:6818 msgid "Import .osd file" msgstr "Importez un fichier .osd" #: src/program/OutfitStudio.cpp:6822 src/program/OutfitStudio.cpp:6912 msgid "This will delete all loaded sliders. Are you sure?" msgstr "Cela supprimera tous les sliders chargés. Êtes-vous sûr?" #: src/program/OutfitStudio.cpp:6822 src/program/OutfitStudio.cpp:6899 msgid "OSD Import" msgstr "Importez OSD" #: src/program/OutfitStudio.cpp:6832 msgid "Failed to import OSD file!" msgstr "Échec de l'importation du fichier OSD!" #: src/program/OutfitStudio.cpp:6899 src/program/OutfitStudio.cpp:6991 #, c-format msgid "" "Added morphs for the following shapes:\n" "\n" "%s" msgstr "" "Ajout de morphes pour les formes suivantes:\n" "\n" "%s" #: src/program/OutfitStudio.cpp:6912 src/program/OutfitStudio.cpp:6991 msgid "TRI Import" msgstr "TRI Importer" #: src/program/OutfitStudio.cpp:7004 msgid "Import .fbx file for slider calculation" msgstr "Importez un fichier .fbx pour le calcul du slider" #: src/program/OutfitStudio.cpp:7025 src/program/OutfitStudio.cpp:7061 #: src/program/OutfitStudio.cpp:7094 msgid "There is no slider in edit mode to export data from!" msgstr "" "Il n'y a pas de slider en mode d'édition à partir duquel exporter des " "données!" #: src/program/OutfitStudio.cpp:7030 msgid "Export .nif slider data to directory" msgstr "Exporter les données du slider .nif vers le répertoire" #: src/program/OutfitStudio.cpp:7041 msgid "Export .nif slider data" msgstr "Exporter les données du slider .nif" #: src/program/OutfitStudio.cpp:7048 msgid "Failed to export NIF file!" msgstr "Échec de l'exportation du fichier NIF!" #: src/program/OutfitStudio.cpp:7066 msgid "Export .bsd slider data to directory" msgstr "Exporter les données du slider .bsd vers le répertoire" #: src/program/OutfitStudio.cpp:7077 msgid "Export .bsd slider data" msgstr "Exporter les données du slider .bsd" #: src/program/OutfitStudio.cpp:7099 src/program/OutfitStudio.cpp:7166 msgid "Export .obj slider data to directory" msgstr "Exporter les données du slider .obj vers le répertoire" #: src/program/OutfitStudio.cpp:7110 msgid "Export .obj slider data" msgstr "Exporter les données du slider .obj" #: src/program/OutfitStudio.cpp:7130 msgid "Export .osd file" msgstr "Exporter un fichier .osd" #: src/program/OutfitStudio.cpp:7137 msgid "Failed to export OSD file!" msgstr "Échec de l'exportation du fichier OSD!" #: src/program/OutfitStudio.cpp:7192 msgid "" "Are you sure you wish to clear the unmasked slider data for the selected " "shapes? This action cannot be undone." msgstr "" "Voulez-vous vraiment effacer les vertices non masqués des formes " "sélectionnées? Cette action ne peut pas être annulée." #: src/program/OutfitStudio.cpp:7193 src/program/OutfitStudio.cpp:7197 msgid "Confirm data erase" msgstr "Confirmer l'effacement des données" #: src/program/OutfitStudio.cpp:7196 #, c-format msgid "" "Are you sure you wish to clear the unmasked slider data for the shape '%s'? " "This action cannot be undone." msgstr "" "Voulez-vous vraiment effacer les vertices non masqués des formes '%s'? Cette " "action ne peut pas être annulée." #: src/program/OutfitStudio.cpp:7250 msgid "Enter a name for the new zap:" msgstr "Entrez un nom pour le nouveau zap:" #: src/program/OutfitStudio.cpp:7250 msgid "Create New Zap" msgstr "Créer Nouveau Zap" #: src/program/OutfitStudio.cpp:7300 msgid "There is no slider in edit mode to negate!" msgstr "Il n'y a pas de slider en mode édition pour annuler!" #: src/program/OutfitStudio.cpp:7317 msgid "There is no slider in edit mode to create a mask from!" msgstr "Il n'y a pas de slider en mode édition pour créer un masque!" #: src/program/OutfitStudio.cpp:7327 msgid "Are you sure you wish to delete the selected slider(s)?" msgstr "Voulez-vous vraiment supprimer le(s) slider(s) sélectionné(s)?" #: src/program/OutfitStudio.cpp:7328 msgid "Confirm slider delete" msgstr "Confirmer la suppression du slider" #: src/program/OutfitStudio.cpp:7379 msgid "There is no slider in edit mode to show properties for!" msgstr "Il n'y a pas de slider en mode édition pour afficher les propriétés!" #: src/program/OutfitStudio.cpp:7526 src/program/OutfitStudio.cpp:7581 msgid "Conforming: " msgstr "Conforme: " #: src/program/OutfitStudio.cpp:7543 msgid "Initializing data..." msgstr "Initialisation des données..." #: src/program/OutfitStudio.cpp:7553 msgid "Shape(s) conformed." msgstr "Le(s) formes se sont conformées." #: src/program/OutfitStudio.cpp:7574 msgid "Conforming all shapes..." msgstr "Conforme à toutes les formes..." #: src/program/OutfitStudio.cpp:7592 msgid "All shapes conformed." msgstr "Toutes les formes se sont conformées." #: src/program/OutfitStudio.cpp:8288 msgid "Are you sure you wish to delete parts of the selected shapes?" msgstr "Voulez-vous vraiment effacer des parties des formes sélectionnées?" #: src/program/OutfitStudio.cpp:8288 src/program/OutfitStudio.cpp:8533 msgid "Confirm Delete" msgstr "Confirmation de la suppression" #: src/program/OutfitStudio.cpp:8329 msgid "Please enter a unique name for the new separated shape." msgstr "Veuillez saisir un nom unique pour la nouvelle forme séparée." #: src/program/OutfitStudio.cpp:8377 msgid "No errors found!" msgstr "Aucune erreur trouvée!" #: src/program/OutfitStudio.cpp:8383 msgid "Errors:" msgstr "Erreur:" #: src/program/OutfitStudio.cpp:8385 msgid "Target must be different from source." msgstr "La cible doit être différente de la source." #: src/program/OutfitStudio.cpp:8387 msgid "" "Partitions do not match. Make sure the amount of partitions and their slots " "match up." msgstr "" "Les partitions ne correspondent pas. Assurez-vous que le nombre de " "partitions et leurs emplacements correspondent." #: src/program/OutfitStudio.cpp:8389 msgid "" "Segments do not match. Make sure the amount of segments, sub segments and " "their info as well as the segmentation file match." msgstr "" "Les segments ne correspondent pas. Assurez-vous que la quantité de segments, " "de sous-segments et leurs informations ainsi que le fichier de segmentation " "correspondent." #: src/program/OutfitStudio.cpp:8391 msgid "Resulting shape would have too many vertices." msgstr "La forme résultante aurait trop de vertices." #: src/program/OutfitStudio.cpp:8393 msgid "Resulting shape would have too many triangles." msgstr "La forme résultante aurait trop de triangles." #: src/program/OutfitStudio.cpp:8395 msgid "" "Shaders do not match. Make sure both shapes either have or don't have a " "shader and their shader type matches." msgstr "" "Les shaders ne correspondent pas. Assurez-vous que les deux formes ont ou " "n'ont pas de shader et que leur type de shader correspond." #: src/program/OutfitStudio.cpp:8397 msgid "" "Base texture doesn't match. Make sure both shapes have the same base/diffuse " "texture path." msgstr "" "La texture de base ne correspond pas. Assurez-vous que les deux formes ont " "le même chemin de texture de base/diffuse." #: src/program/OutfitStudio.cpp:8399 msgid "" "Alpha property mismatch. Make sure both shapes either have or don't have an " "alpha property and their flags + threshold match." msgstr "" "Mauvaise correspondance des propriétés alpha. Assurez-vous que les deux " "formes ont ou n'ont pas une propriété alpha et que leurs drapeaux + seuil " "correspondent." #: src/program/OutfitStudio.cpp:8485 msgid "" "You can only copy shapes into an outfit, and there is no outfit in the " "current project. Load one first!" msgstr "" "Vous ne pouvez copier que des formes dans une tenue et il n'y a aucune tenue " "dans le projet en cours. Chargez-en un en premier!" #: src/program/OutfitStudio.cpp:8490 msgid "Please enter a unique name for the duplicated shape." msgstr "Veuillez saisir un nom unique pour la forme dupliquée." #: src/program/OutfitStudio.cpp:8490 msgid "Duplicate Shape" msgstr "Forme Dupliquée" #: src/program/OutfitStudio.cpp:8533 msgid "" "Are you sure you wish to delete the selected shapes? This action cannot be " "undone." msgstr "" "Voulez-vous vraiment supprimer des formes sélectionnées? Cette action ne " "peut pas être annulée." #: src/program/OutfitStudio.cpp:8669 msgid "No bone name was entered!" msgstr "Aucun nom d'os n'a été entré!" #: src/program/OutfitStudio.cpp:8677 #, c-format msgid "Bone '%s' already exists in the project!" msgstr "L'os '%s' existe déjà dans le projet!" #: src/program/OutfitStudio.cpp:8804 msgid "" "The following shapes have unweighted vertices, which can cause issues. The " "affected vertices have been put under a mask. Do you want to save anyway?" msgstr "" "Les formes suivantes ont des vertices non pondérés, ce qui peut causer des " "problèmes. Les vertices concernés ont été placés sous un masque. Voulez-vous " "quand même enregistrer?" #: src/program/OutfitStudio.cpp:8804 msgid "Unweighted Vertices" msgstr "Vertices non Pondérés" #: src/program/OutfitStudio.cpp:8977 src/program/OutfitStudio.cpp:9051 #: src/program/OutfitStudio.cpp:9143 msgid "There is no reference shape!" msgstr "Il n'y a pas de forme de référence!" #: src/program/OutfitStudio.cpp:9027 src/program/OutfitStudio.cpp:9118 msgid "" "Sorry, you can't copy weights from the reference shape to itself. Skipping " "this shape." msgstr "" "Désolé, vous ne pouvez pas copier les poids de la forme de référence sur " "elle-même. Sauter cette forme." #: src/program/OutfitStudio.cpp:9027 src/program/OutfitStudio.cpp:9118 msgid "Can't copy weights" msgstr "Ne pouvez pas copier les poids" #: src/program/OutfitStudio.cpp:9089 msgid "Copying selected bone weights..." msgstr "Copie des poids des os sélectionnés..." #: src/program/OutfitStudio.cpp:9148 msgid "Sorry, you can't copy weights from the reference shape to itself." msgstr "" "Désolé, vous ne pouvez pas copier les poids de la forme de référence sur " "elle-même." #: src/program/OutfitStudio.cpp:9155 msgid "The vertex count of the reference and chosen shape is not the same!" msgstr "" "Le nombre de vertex de la forme de référence et de la forme choisie n'est " "pas le même!" #: src/program/OutfitStudio.cpp:9254 #, c-format msgid "%d unreferenced nodes were deleted." msgstr "%d nœuds non référencés ont été supprimés." #: src/program/OutfitStudio.cpp:9497 msgid "Please enter a new unique name for the mask." msgstr "Veuillez saisir un nouveau nom unique pour la masque." #: src/program/OutfitStudio.cpp:9497 msgid "New Mask" msgstr "Nouveaux Masque" #: src/program/OutfitStudio.cpp:9665 msgid "Reset all bone poses?" msgstr "Réinitialiser toutes les poses d'os?" #: src/program/OutfitStudio.cpp:9665 msgid "Reset Pose" msgstr "Réinitialiser la Pose" #: src/program/OutfitStudio.cpp:9692 msgid "Permanently apply the pose to the mesh?" msgstr "Appliquer définitivement la pose au maillage?" #: src/program/OutfitStudio.cpp:9692 msgid "Apply Pose to Mesh" msgstr "Appliquer la Pose au Maillage" #: src/program/OutfitStudio.cpp:10646 msgid "The vertex picked has more than three connections." msgstr "Le vertex choisi a plus de trois connexions." #: src/program/OutfitStudio.cpp:10700 msgid "The edge picked is on the surface boundary. Pick an interior edge." msgstr "" "Le bord sélectionné se trouve sur la limite de la surface. Choisissez un " "bord intérieur." #: src/program/OutfitStudio.cpp:10734 msgid "The shape has reached the vertex count limit." msgstr "La forme a atteint la limite du nombre de vertex." #: src/program/OutfitStudio.cpp:10739 msgid "The shape has reached the triangle count limit." msgstr "La forme a atteint la limite du nombre de triangles." #: src/program/OutfitStudio.cpp:10761 msgid "" "The edge picked has multiple triangles of the same orientation. Correct the " "orientations before splitting." msgstr "" "Le bord sélectionné a plusieurs triangles de la même orientation. Corrigez " "les orientations avant de fractionner." #: src/program/OutfitStudio.cpp:11902 src/program/OutfitStudio.cpp:11903 msgid "Loading slider file..." msgstr "Chargement du fichier de slider..." #: src/program/PreviewWindow.cpp:39 msgid "Show the Normal Map Generator dialog." msgstr "Affichez la boîte de dialogue Normal Map Generator." #: src/program/PreviewWindow.cpp:66 msgid "Preview failed: OpenGL context is not OK." msgstr "L'aperçu a échoué: OpenGL le contexte n'est pas OK." #: src/program/ShapeProperties.cpp:100 msgid "Material" msgstr "Matériel" #: src/program/ShapeProperties.cpp:260 msgid "Choose material file" msgstr "Choisissez le fichier matériel" #: src/program/ShapeProperties.cpp:497 msgid "Please choose a shape to copy from" msgstr "Veuillez choisir une forme à copier" #: src/program/ShapeProperties.cpp:497 msgid "Choose shape" msgstr "Choisissez du forme" ================================================ FILE: lang/hi/BodySlide.mo ================================================ ================================================ FILE: lang/hi/BodySlide.po ================================================ ================================================ FILE: lang/hu/BodySlide.mo ================================================ ================================================ FILE: lang/hu/BodySlide.po ================================================ ================================================ FILE: lang/id/BodySlide.mo ================================================ ================================================ FILE: lang/id/BodySlide.po ================================================ ================================================ FILE: lang/it/BodySlide.mo ================================================ ================================================ FILE: lang/it/BodySlide.po ================================================ ================================================ FILE: lang/ja/BodySlide.mo ================================================ ================================================ FILE: lang/ja/BodySlide.po ================================================ ================================================ FILE: lang/ko/BodySlide.mo ================================================ ================================================ FILE: lang/ko/BodySlide.po ================================================ ================================================ FILE: lang/lt/BodySlide.mo ================================================ ================================================ FILE: lang/lt/BodySlide.po ================================================ ================================================ FILE: lang/lv/BodySlide.mo ================================================ ================================================ FILE: lang/lv/BodySlide.po ================================================ ================================================ FILE: lang/ms/BodySlide.mo ================================================ ================================================ FILE: lang/ms/BodySlide.po ================================================ ================================================ FILE: lang/nb/BodySlide.mo ================================================ ================================================ FILE: lang/nb/BodySlide.po ================================================ ================================================ FILE: lang/ne/BodySlide.mo ================================================ ================================================ FILE: lang/ne/BodySlide.po ================================================ ================================================ FILE: lang/nl/BodySlide.mo ================================================ ================================================ FILE: lang/nl/BodySlide.po ================================================ ================================================ FILE: lang/pl/BodySlide.mo ================================================ ================================================ FILE: lang/pl/BodySlide.po ================================================ ================================================ FILE: lang/pt/BodySlide.mo ================================================ ================================================ FILE: lang/pt/BodySlide.po ================================================ ================================================ FILE: lang/ro/BodySlide.mo ================================================ ================================================ FILE: lang/ro/BodySlide.po ================================================ ================================================ FILE: lang/ru/BodySlide.mo ================================================ ================================================ FILE: lang/ru/BodySlide.po ================================================ ================================================ FILE: lang/sk/BodySlide.mo ================================================ ================================================ FILE: lang/sk/BodySlide.po ================================================ ================================================ FILE: lang/sl/BodySlide.mo ================================================ ================================================ FILE: lang/sl/BodySlide.po ================================================ ================================================ FILE: lang/sq/BodySlide.mo ================================================ ================================================ FILE: lang/sq/BodySlide.po ================================================ ================================================ FILE: lang/sv/BodySlide.mo ================================================ ================================================ FILE: lang/sv/BodySlide.po ================================================ ================================================ FILE: lang/ta/BodySlide.mo ================================================ ================================================ FILE: lang/ta/BodySlide.po ================================================ ================================================ FILE: lang/tr/BodySlide.po ================================================ msgid "" msgstr "" "Project-Id-Version: BodySlide\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.2\n" "X-Poedit-KeywordsList: _\n" "X-Poedit-Basepath: ..\n" "X-Poedit-SearchPath-0: src\n" "X-Poedit-SearchPath-1: lang/xrctext.cpp\n" #: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:429 msgid "About" msgstr "Hakkında" #: res/xrc/About.xrc:145 res/xrc/GroupManager.xrc:189 msgid "Close" msgstr "Kapat" #: res/xrc/Actions.xrc:6 msgid "Apply a vertex position" msgstr "Tepe Noktası Uygula" #: res/xrc/Actions.xrc:15 msgid "This permanently moves a single vertex straight to the given location." msgstr "" "Bu ayar, tek bir tepe noktasını kalıcı olarak doğrudan verilen konuma taşır." #: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499 #: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:741 res/xrc/Actions.xrc:891 #: res/xrc/Actions.xrc:1170 res/xrc/Actions.xrc:1271 res/xrc/BatchBuild.xrc:112 #: res/xrc/EditUV.xrc:32 res/xrc/EditUV.xrc:244 res/xrc/EditUV.xrc:319 #: res/xrc/EditUV.xrc:440 res/xrc/ImportDialog.xrc:174 res/xrc/Project.xrc:753 #: res/xrc/Project.xrc:930 res/xrc/Settings.xrc:438 #: res/xrc/ShapeProperties.xrc:810 res/xrc/Skeleton.xrc:36 #: res/xrc/Skeleton.xrc:232 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238 #: res/xrc/SliderDataImport.xrc:90 msgid "&OK" msgstr "&TAMAM" #: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506 #: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:748 res/xrc/Actions.xrc:898 #: res/xrc/Actions.xrc:1177 res/xrc/Actions.xrc:1278 res/xrc/Actions.xrc:1609 #: res/xrc/BatchBuild.xrc:57 res/xrc/BatchBuild.xrc:119 res/xrc/EditUV.xrc:39 #: res/xrc/EditUV.xrc:251 res/xrc/EditUV.xrc:326 res/xrc/EditUV.xrc:447 #: res/xrc/ImportDialog.xrc:181 res/xrc/Project.xrc:550 res/xrc/Project.xrc:760 #: res/xrc/Project.xrc:937 res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:445 #: res/xrc/Setup.xrc:273 res/xrc/ShapeProperties.xrc:817 #: res/xrc/Skeleton.xrc:43 res/xrc/Skeleton.xrc:239 res/xrc/Slider.xrc:71 #: res/xrc/Slider.xrc:246 res/xrc/SliderDataImport.xrc:97 msgid "&Cancel" msgstr "&İptal" #: res/xrc/Actions.xrc:110 msgid "Move Shape" msgstr "Kalıbı Taşı" #: res/xrc/Actions.xrc:254 msgid "Mirror Axis" msgstr "Yansıtıcı Ekseni" #: res/xrc/Actions.xrc:320 msgid "Scale Shape" msgstr "Kalıp Ölçeği" #: res/xrc/Actions.xrc:329 msgid "" "Scaling will adjust the size of a mesh. This permanently affects vertices." msgstr "" "Ölçekleme bir kafesin boyutunu ayarlayacaktır. Bu, sürekli olarak köşe " "noktalarını etkiler." #: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667 #: res/xrc/ShapeProperties.xrc:690 res/xrc/Skeleton.xrc:133 msgid "Origin" msgstr "Baslangıç" #: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678 msgid "Zero (0, 0, 0)" msgstr "Sıfır" #: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679 msgid "Center of selected shapes(s)" msgstr "Seçili Kalıp(ların) Merkezi" #: res/xrc/Actions.xrc:484 msgid "Uniform (XYZ)" msgstr "Giydirme (XYZ)" #: res/xrc/Actions.xrc:517 msgid "Rotate Shape" msgstr "Kalıbı Döndür" #: res/xrc/Actions.xrc:711 msgid "Set Shape Textures" msgstr "Kalıp Dokusunu Ayarla" #: res/xrc/Actions.xrc:758 res/xrc/ConvertBodyReference.xrc:183 #: res/xrc/OutfitStudio.xrc:1946 res/xrc/OutfitStudio.xrc:2404 msgid "Copy Bone Weights" msgstr "Beden Ağırlıklarını Kopyala" #: res/xrc/Actions.xrc:767 msgid "" "Each vertex of the reference will copy its weights to the nearest collection " "of vertices within the given radius. Bear in mind that some geometry will " "always require manual tweaking to become weighted and work well. Often, the " "default values are sufficient." msgstr "" "Örneğin her köşesi, ağırlıkları verilen yarıçaptaki en yakın tepe noktası " "koleksiyonuna kopyalanır. Bazı geometrilerin, baskın hale gelmesi ve daha " "iyi çalışması için her zaman el ile ayarlamayı gerektireceğini unutma. Çoğu " "zaman, varsayılan değerler yeterlidir." #: res/xrc/Actions.xrc:787 res/xrc/Actions.xrc:937 msgid "Search Radius" msgstr "Yarıçap Taraması" #: res/xrc/Actions.xrc:816 res/xrc/Actions.xrc:966 msgid "Max Vertex Targets" msgstr "Max Köşe Hedeflemesi" #: res/xrc/Actions.xrc:847 res/xrc/Actions.xrc:995 msgid "No Target Limit" msgstr "Hedef Limiti Yok" #: res/xrc/Actions.xrc:856 msgid "" "The skin coordinate system doesn't match the reference shape's. Do you want " "to copy the transforms?" msgstr "" "Dış görünüm koordinatı, referans şekliyle eşleşmiyor. Dönüşümleri kopyalamak " "istiyor musun?" #: res/xrc/Actions.xrc:866 msgid "Copy skin transform from reference" msgstr "Cilt dönüşümünü referanstan kopyala" #: res/xrc/Actions.xrc:876 res/xrc/ShapeProperties.xrc:785 msgid "Recalculate geometry's coordinates so it doesn't move" msgstr "Hareket etmemesi için geometrinin koordinatlarını yeniden hesapla" #: res/xrc/Actions.xrc:877 res/xrc/ShapeProperties.xrc:786 msgid "" "Transform geometry so its position in global coordinates does not change." msgstr "" "Geometriyi, küresel koordinat konumunu değiştirmeyecek şekilde dönüştür." #: res/xrc/Actions.xrc:908 msgid "Conforming..." msgstr "Uyum sağlanıyor..." #: res/xrc/Actions.xrc:917 msgid "" "Each vertex of the reference will copy its slider data to the nearest " "collection of vertices within the given radius. Bear in mind that some " "geometry will always require manual tweaking to become conformed and work " "well. Often, the default values are sufficient." msgstr "" "Örneğin her köşesi, ağırlıkları verilen yarıçap içindeki en yakın köşe " "noktasına kopyalanır. Bazı geometrilerin, baskın hale gelmesi ve daha iyi " "çalışması için her zaman el ile ayarlamayı gerektireceğini unutma. Çoğu " "zaman, varsayılan değerler yeterlidir." #: res/xrc/Actions.xrc:1018 msgid "No Squeeze" msgstr "Sıkıstırma Yok" #: res/xrc/Actions.xrc:1041 msgid "Solid Mode" msgstr "Koyu Mod" #: res/xrc/Actions.xrc:1064 msgid "Axis" msgstr "Eksen" #: res/xrc/Actions.xrc:1114 res/xrc/BodySlide.xrc:97 #: res/xrc/NormalsGenDlg.xrc:191 msgid "Preset" msgstr "Hazır Ayar" #: res/xrc/Actions.xrc:1130 msgid "Default" msgstr "Varsayılan" #: res/xrc/Actions.xrc:1139 msgid "Even Movement" msgstr "Düz Hareket" #: res/xrc/Actions.xrc:1148 msgid "Solid Object" msgstr "Katı Nesne" #: res/xrc/Actions.xrc:1187 msgid "Merge Geometry" msgstr "Geometriyi Birleştir" #: res/xrc/Actions.xrc:1196 msgid "" "This function copies vertices and triangles from one shape to another. " "Partitions/segments of source and target shapes must match. It is the " "user's responsibility to check that all other shape and shader properties " "are compatible, or merging will likely have side effects." msgstr "" "Bu ayar, köşeleri ve üçgenleri bir şekilden diğerine kopyalar. Kaynak ve " "hedef şekillerin bölümleri/segmentleri eşleşmelidir. Diğer tüm şekil ve " "gölgelendirici özelliklerinin uyumlu olup olmadığını kontrol etmek " "kullanıcının sorumluluğundadır, aksi takdirde birleştirmenin yan etkileri " "olabilir." #: res/xrc/Actions.xrc:1211 msgid "Source" msgstr "Kaynak" #: res/xrc/Actions.xrc:1229 msgid "Target" msgstr "Hedef" #: res/xrc/Actions.xrc:1258 msgid "Delete source shape" msgstr "Kaynak Kalıbını Sil" #: res/xrc/Actions.xrc:1288 msgid "Mask symmetric vertices" msgstr "Simetrik köşeleri maskele" #: res/xrc/Actions.xrc:1297 msgid "Masks all vertices that do not have any of the selected asymmetries." msgstr "" "Seçilen asimetrilerden herhangi birine sahip olmayan tüm köşeleri maskeler." #: res/xrc/Actions.xrc:1323 msgid "Vertices currently unmasked:" msgstr "Şu anda maskelenmemiş tepe noktaları:" #: res/xrc/Actions.xrc:1351 msgid "Unmatched Vertices:" msgstr "Benzersiz Tepe Noktaları:" #: res/xrc/Actions.xrc:1373 msgid "Vertex Data Asymmetries" msgstr "Tepe Noktası Veri Asimetrisi" #: res/xrc/Actions.xrc:1406 res/xrc/OutfitStudio.xrc:793 #: res/xrc/OutfitStudio.xrc:1057 res/xrc/ShapeProperties.xrc:84 #: res/xrc/ShapeProperties.xrc:599 msgid "Type" msgstr "Tip" #: res/xrc/Actions.xrc:1415 msgid "Average" msgstr "Ortalama" #: res/xrc/Actions.xrc:1424 msgid "Count" msgstr "Hesaplama" #: res/xrc/Actions.xrc:1442 msgid "Position" msgstr "Konum" #: res/xrc/Actions.xrc:1510 res/xrc/Project.xrc:731 msgid "Sliders" msgstr "Kaydırıcılar" #: res/xrc/Actions.xrc:1557 res/xrc/OutfitStudio.xrc:387 #: res/xrc/OutfitStudio.xrc:2452 res/xrc/OutfitStudio.xrc:2496 msgid "Bones" msgstr "İskeletler" #: res/xrc/Actions.xrc:1576 msgid "Vertices that will still be unmasked:" msgstr "Hâlâ maskelenmemiş köşeler:" #: res/xrc/Actions.xrc:1602 msgid "&Mask" msgstr "&Maske" #: res/xrc/BatchBuild.xrc:6 msgid "Batch Build" msgstr "Toplu Yapılandırma" #: res/xrc/BatchBuild.xrc:21 msgid "" "Select the slider sets for the batch build process. Use the group and outfit " "filters to show the outfits you want!" msgstr "" "Toplu yapılandırma işlemi için kaydırıcı kümelerini seç. İstediğin " "kıyafetleri göstermek için grup ve kıyafet filtrelerini kullan!" #: res/xrc/BatchBuild.xrc:50 msgid "&Build" msgstr "&Beden" #: res/xrc/BatchBuild.xrc:67 src/program/BodySlideApp.cpp:2292 msgid "Choose output set" msgstr "Çıkış setini seç" #: res/xrc/BatchBuild.xrc:78 msgid "" "The following sets will override the same files.\n" "Please decide which one to use and select it in the list below." msgstr "" "Aşağıdaki bazı ayarlar aynı dosyaları geçersiz kılabilir.\n" "Lütfen hangisini kullanacağına karar ver ve listeden seçimini yap." #: res/xrc/BatchBuild.xrc:88 msgid "Type and hit enter to choose output..." msgstr "Çıkış setini seç ve Enter'a bas..." #: res/xrc/BodySlide.xrc:7 msgid "BodySlide" msgstr "Beden Yapılandırması" #: res/xrc/BodySlide.xrc:28 msgid "Outfit/Body" msgstr "Kıyafet/Beden" #: res/xrc/BodySlide.xrc:44 msgid "Select an outfit to modify" msgstr "Ayarlanacak bir kıyafeti seç" #: res/xrc/BodySlide.xrc:58 msgid "Deletes a project from its project file" msgstr "Proje dosyasından bir projeyi siler" #: res/xrc/BodySlide.xrc:74 msgid "Opens the current project in Outfit Studio" msgstr "Mevcut projeyi Outfit Studio programında açar" #: res/xrc/BodySlide.xrc:113 msgid "Choose from a list of slider settings presets" msgstr "Listeden önceden hazırlanmış bir dosyayı seç" #: res/xrc/BodySlide.xrc:127 msgid "Deletes a preset from its preset file" msgstr "Hazır ayarlı bir dosyadan bir hazır ayarı siler" #: res/xrc/BodySlide.xrc:142 msgid "Saves the new slider values to the currently selected preset" msgstr "Yeni dosya değerlerini seçili olan hazır ayar dosyasına kaydeder" #: res/xrc/BodySlide.xrc:143 res/xrc/GroupManager.xrc:44 #: res/xrc/OutfitStudio.xrc:1257 res/xrc/OutfitStudio.xrc:1318 msgid "Save" msgstr "Kaydet" #: res/xrc/BodySlide.xrc:153 msgid "Save the current slider settings as a new preset" msgstr "Mevcut ayarlarını yeni bir hazır ayar olarak kaydet" #: res/xrc/BodySlide.xrc:154 res/xrc/GroupManager.xrc:53 #: res/xrc/OutfitStudio.xrc:1266 res/xrc/OutfitStudio.xrc:1327 msgid "Save As..." msgstr "Farklı Kaydet..." #: res/xrc/BodySlide.xrc:165 msgid "" "Opens the group manager where you can edit existing or create new groups" msgstr "" "Mevcut hazır ayarlarını veya yeni gruplar oluşturabileceğin grup " "yöneticisini açar" #: res/xrc/BodySlide.xrc:166 res/xrc/GroupManager.xrc:7 #: res/xrc/Project.xrc:1059 msgid "Group Manager" msgstr "Gurup Yöneticisi" #: res/xrc/BodySlide.xrc:190 msgid "Single Weight" msgstr "Tekil Ağırlık" #: res/xrc/BodySlide.xrc:217 msgid "Low Weight" msgstr "Düsük Ağırlık" #: res/xrc/BodySlide.xrc:234 msgid "High Weight" msgstr "Yüksek Ağırlık" #: res/xrc/BodySlide.xrc:275 msgid "Copy the low weight slider values to the high weight section." msgstr "Düşük ağırlık değerlerini yüksek ağırlık bölümüne kopyalar." #: res/xrc/BodySlide.xrc:292 msgid "Default outfit choice in Batch Build" msgstr "Toplu Oluşturma'da Varsayılan Kıyafet Seçimi" #: res/xrc/BodySlide.xrc:303 msgid "Output Path (which the game would use for this outfit)" msgstr "Çıkış Veri Yolu (oyunda bu kıyafet kullanılacak)" #: res/xrc/BodySlide.xrc:315 msgid "(right-click to view alternatives)" msgstr "(alternatifleri görmek için sağ tuşa tıkla)" #: res/xrc/BodySlide.xrc:335 msgid "" "Build multiple outfits using the currently active slider values.\n" "\n" "Hold CTRL = Build to custom directory\n" "Hold ALT = Delete from output directory" msgstr "" "Mevcut değerleri kullanarak birden fazla kıyafeti oluştur.\n" "\n" "CTRL Basılı Tut = Özel dizin olarak kaydeder\n" "ALT Basılı Tut = Kıyafet dizinini siler" #: res/xrc/BodySlide.xrc:336 msgid "Batch Build..." msgstr "Toplu Yapılandırma..." #: res/xrc/BodySlide.xrc:351 msgid "Build Morphs" msgstr "Beden Oluştur" #: res/xrc/BodySlide.xrc:352 msgid "" "Builds a morphs (.tri) file alongside the meshes for accessing the sliders " "in-game. Requires other mods to make use of the morph data." msgstr "" "Oyundaki beden yapılarına erişmek için oyun-içi dosyalarının yanında bir " "morphs yani (.tri) dosyası oluşturur. Morph verisini kullanmak için başka " "modlarda gereklidir." #: res/xrc/BodySlide.xrc:362 msgid "Force Body Normals" msgstr "Normal Bedensel Değerler" #: res/xrc/BodySlide.xrc:363 msgid "" "Adds normal and tangent data to the body meshes (including bodies within " "outfits) for Skyrim. Use this only if you have a tangent space body mod." msgstr "" "Skyrim için gövde ağlarına (kıyafetli bedenler dahil) normal ve sonradan " "eklenen verileri ekler. Bunu yalnızca beden değiştirme modunuz varsa " "kullanın." #: res/xrc/BodySlide.xrc:379 msgid "Show a preview window for this outfit." msgstr "Bu kıyafet için bir önizleme penceresi açılır." #: res/xrc/BodySlide.xrc:380 res/xrc/NormalsGenDlg.xrc:166 #: src/program/PreviewWindow.cpp:27 msgid "Preview" msgstr "Ön İzleme" #: res/xrc/BodySlide.xrc:398 msgid "" "Creates the currently selected outfit/body.\n" "\n" "Hold CTRL = Build to working directory\n" "Hold ALT = Delete from output directory" msgstr "" "Şuanda seçili olan kıyafet/beden.\n" "\n" "CTRL Basılı Tut = Özel dizin olarak kaydeder\n" "ALT Basılı Tut = Bedeni ve Kıyafeti siler" #: res/xrc/BodySlide.xrc:399 msgid "Build" msgstr "Olustur" #: res/xrc/BodySlide.xrc:411 msgid "Copy the high weight slider values to the low weight section." msgstr "Yüksek ağırlık değerlerini düşük ağırlık bölümüne kopyalar." #: res/xrc/BodySlide.xrc:438 res/xrc/OutfitStudio.xrc:1755 msgid "Open settings dialog." msgstr "Ayarlar menüsünü aç." #: res/xrc/BodySlide.xrc:439 res/xrc/OutfitStudio.xrc:1754 #: res/xrc/Settings.xrc:5 msgid "Settings" msgstr "Ayarlar" #: res/xrc/BodySlide.xrc:448 msgid "" "Open Outfit Studio, a full-featured tool for creating and converting outfits." msgstr "" "Başlatılan Outfit Studio (Kıyafet Stüdyosu), kıyafetler oluşturmak ve " "dönüştürmek için tam özellikli bir araçtır." #: res/xrc/BodySlide.xrc:449 res/xrc/OutfitStudio.xrc:7 msgid "Outfit Studio" msgstr "Kıyafet Dünyası" #: res/xrc/BodySlide.xrc:459 res/xrc/BodySlide.xrc:470 msgid "Filter Options" msgstr "Filtre Ayarları" #: res/xrc/BodySlide.xrc:461 msgid "Choose groups..." msgstr "Gurup seç..." #: res/xrc/BodySlide.xrc:462 msgid "Choose groups to display in the Outfit menu" msgstr "Kıyafet menüsünde görüntülenecek gurupları seçebilirsin" #: res/xrc/BodySlide.xrc:465 msgid "Refresh Groups" msgstr "Grupları Yenile" #: res/xrc/BodySlide.xrc:466 msgid "Refresh group information" msgstr "Gurup bilgilerini yenile" #: res/xrc/BodySlide.xrc:472 msgid "Save Outfit list as group..." msgstr "Kıyafet Listesini gurup olarak kaydet..." #: res/xrc/BodySlide.xrc:473 msgid "Save the current filtered outfit list as a group" msgstr "Filtrelenen mevcut kıyafet listesini bir grup olarak kaydet" #: res/xrc/BodySlide.xrc:476 msgid "Refresh Outfits" msgstr "Kıyafetleri Yenile" #: res/xrc/BodySlide.xrc:477 msgid "Reloads outfit list" msgstr "Yeniden yüklenen kıyafet listesi" #: res/xrc/BodySlide.xrc:480 msgid "Regular Expressions" msgstr "Düzenli İfadeler" #: res/xrc/BodySlide.xrc:481 msgid "Allow the use of regular expressions (regex) for filtering." msgstr "Filtreleme için ifadelerin (Normal) kullanımına izin ver." #: res/xrc/BodySlide.xrc:487 res/xrc/Project.xrc:1076 #: res/xrc/SliderDataImport.xrc:106 msgid "Select None" msgstr "Hiçbirini Seçme" #: res/xrc/BodySlide.xrc:490 res/xrc/EditUV.xrc:110 res/xrc/Project.xrc:1079 #: res/xrc/SliderDataImport.xrc:109 msgid "Select All" msgstr "Tümünü Seç" #: res/xrc/BodySlide.xrc:493 res/xrc/EditUV.xrc:114 res/xrc/Project.xrc:1082 #: res/xrc/SliderDataImport.xrc:112 msgid "Invert Selection" msgstr "Tersine Seçim Yap" #: res/xrc/ConvertBodyReference.xrc:6 msgid "Convert / Replace Body Reference" msgstr "Örnek Bedeni Değiştir / Dönüştür" #: res/xrc/ConvertBodyReference.xrc:16 res/xrc/ConvertBodyReference.xrc:219 msgid "This wizard aids in the conversion to another body/reference.." msgstr "" "Bu sihirbaz, başka bir gövdeye/örnek bedene dönüştürmeye yardımcı olur.." #: res/xrc/ConvertBodyReference.xrc:25 msgid "Reference Bodies" msgstr "Örnek Beden" #: res/xrc/ConvertBodyReference.xrc:36 msgid "Select a conversion reference (or 'None' to skip converting):" msgstr "Bir örnek beden seçin (ya da 'Yok' seçeneğiyle dönüşümü atlayın):" #: res/xrc/ConvertBodyReference.xrc:58 msgid "Conversion Body Reference" msgstr "Örnek Beden Dönüşümü" #: res/xrc/ConvertBodyReference.xrc:78 msgid "Select a body reference to convert to:" msgstr "Dönüştürmek için Örnek Gövde'yi seç:" #: res/xrc/ConvertBodyReference.xrc:100 msgid "New Body Reference" msgstr "Yeni Örnek Beden" #: res/xrc/ConvertBodyReference.xrc:130 res/xrc/NormalsGenDlg.xrc:108 #: res/xrc/Slider.xrc:161 msgid "Options" msgstr "Ayarlar" #: res/xrc/ConvertBodyReference.xrc:136 res/xrc/SliderDataImport.xrc:77 msgid "Merge Sliders" msgstr "Kaydırıcıları Birleştir" #: res/xrc/ConvertBodyReference.xrc:145 msgid "Merge Zaps" msgstr "Zap'ları Birleştir" #: res/xrc/ConvertBodyReference.xrc:165 msgid "Conform Sliders" msgstr "Uyumlu Kaydırıcılar" #: res/xrc/ConvertBodyReference.xrc:174 msgid "Skip conform popup (use default settings)" msgstr "Açılan Uyumlu penceresini atla (varsayılan ayarları kullan)" #: res/xrc/ConvertBodyReference.xrc:192 msgid "Skip bone weights popup (use default settings)" msgstr "Kemik ağırlıkları penceresini atla (varsayılan ayarları kullan)" #: res/xrc/ConvertBodyReference.xrc:203 msgid "Delete reference after completion" msgstr "Tamamlandıktan sonra örnek referansı sil" #: res/xrc/ConvertBodyReference.xrc:228 msgid "Rename Project (optional)" msgstr "Projeyi Yeniden Adlandır (isteğe bağlı)" #: res/xrc/ConvertBodyReference.xrc:239 msgid "Specify text to be removed from the project name (comma-delimited):" msgstr "Proje adından kaldırılacak metni belirt (virgülle ayrılan):" #: res/xrc/ConvertBodyReference.xrc:260 msgid "Remove from project name" msgstr "Proje adını sil" #: res/xrc/ConvertBodyReference.xrc:277 msgid "Specify any text to be prepended to project name:" msgstr "Proje adının başına eklenecek metni belirt:" #: res/xrc/ConvertBodyReference.xrc:298 msgid "Prepend to project name" msgstr "Proje adının önüne ekle" #: res/xrc/ConvertBodyReference.xrc:315 msgid "NOTE: Game file output path is unaffected by this" msgstr "NOT: Oyun dosyasının çıkış yolu bundan etkilenmez" #: res/xrc/ConvertBodyReference.xrc:326 msgid "Extras (optional)" msgstr "Ekstra Ayarlar (isteğe bağlı)" #: res/xrc/ConvertBodyReference.xrc:337 msgid "Remove the following shapes before conversion (comma-delimited):" msgstr "Dönüştürmeden önce belirtilen şekilleri kaldır (virgülle ayrılan):" #: res/xrc/ConvertBodyReference.xrc:359 msgid "Shapes to delete" msgstr "Kalıpları Sil" #: res/xrc/ConvertBodyReference.xrc:375 msgid "Add the following bones after conversion (comma-delimited):" msgstr "Dönüştürmeden sonra belirtilen iskeletleri ekle (virgülle ayrılan):" #: res/xrc/ConvertBodyReference.xrc:396 msgid "Bones to add" msgstr "Yüklenen İskeletler" #: res/xrc/EditUV.xrc:5 msgid "Edit UV" msgstr "UV Düzenleme" #: res/xrc/EditUV.xrc:52 msgid "Box Selection" msgstr "Kutu Seçimi" #: res/xrc/EditUV.xrc:53 msgid "" "Box Selection\n" "Shortcut: 1" msgstr "" "Seçilen Kutu\n" "Kısayol: 1" #: res/xrc/EditUV.xrc:60 msgid "Vertex Selection" msgstr "Tepe Noktası Seçimi" #: res/xrc/EditUV.xrc:61 msgid "" "Vertex Selection\n" "Shortcut: 2" msgstr "" "Seçilen Tepe Noktası\n" "Kısayol: 2" #: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:78 #: res/xrc/OutfitStudio.xrc:2140 msgid "Move" msgstr "Hareket" #: res/xrc/EditUV.xrc:68 msgid "" "Move\n" "Shortcut: 3" msgstr "" "Hareket\n" "Kısayol: 3" #: res/xrc/EditUV.xrc:74 res/xrc/EditUV.xrc:336 res/xrc/ImportDialog.xrc:71 #: res/xrc/OutfitStudio.xrc:1559 res/xrc/ShapeProperties.xrc:651 #: src/program/NormalsGenDialog.cpp:300 msgid "Scale" msgstr "Derece" #: res/xrc/EditUV.xrc:75 msgid "" "Scale\n" "Shortcut: 4" msgstr "" "Derece\n" "Kısayol: 4" #: res/xrc/EditUV.xrc:81 res/xrc/EditUV.xrc:261 msgid "Rotate" msgstr "Dönüş" #: res/xrc/EditUV.xrc:82 msgid "" "Rotate\n" "Shortcut: 5" msgstr "" "Dönüş\n" "Kısayol: 5" #: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89 msgid "Show Seam Edges" msgstr "Dikiş Kenarları" #: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1640 msgid "Menu" msgstr "Menü" #: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1763 msgid "Edit" msgstr "Düzenle" #: res/xrc/EditUV.xrc:101 res/xrc/OutfitStudio.xrc:1765 msgid "Undo\tCtrl+Z" msgstr "Geri Al\tCtrl+Z" #: res/xrc/EditUV.xrc:102 res/xrc/OutfitStudio.xrc:1766 msgid "Undo the previous action." msgstr "Önceki eylemi geri al." #: res/xrc/EditUV.xrc:105 res/xrc/OutfitStudio.xrc:1769 msgid "Redo\tCtrl+Y" msgstr "Yinele\tCtrl+Y" #: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:42 #: res/xrc/OutfitStudio.xrc:1770 msgid "Redo the next undone action." msgstr "Son yaptığın işlemi tekrarla." #: res/xrc/EditUV.xrc:109 msgid "Select All\tCtrl+A" msgstr "Tümünü Seç\tCtrl+A" #: res/xrc/EditUV.xrc:113 msgid "Invert Selection\tCtrl+I" msgstr "Tersine Seçim\tCtrl+I" #: res/xrc/EditUV.xrc:117 msgid "Select Less\tA" msgstr "Daha Az Seçim\tA" #: res/xrc/EditUV.xrc:118 msgid "Select less adjacent points in the selected islands." msgstr "Seçili adalardan daha az bitişik noktayı seç." #: res/xrc/EditUV.xrc:121 msgid "Select More\tD" msgstr "Daha Fazla Seçim\tD" #: res/xrc/EditUV.xrc:122 msgid "Select more adjacent points in the selected islands." msgstr "Seçili adalardan daha çok bitişik noktayı seç." #: res/xrc/EditUV.xrc:125 msgid "Translate...\tT" msgstr "Dönüşüm...\tT" #: res/xrc/EditUV.xrc:126 msgid "Show a dialog to translate the current selection." msgstr "Geçerli seçimi tersine çevirmek için bir iletişim kutusu göster." #: res/xrc/EditUV.xrc:129 msgid "Rotate...\tR" msgstr "Dönüş...\tR" #: res/xrc/EditUV.xrc:130 msgid "Show a dialog to rotate the current selection." msgstr "Geçerli seçimi döndürmek için bir iletişim kutusu göster." #: res/xrc/EditUV.xrc:133 msgid "Scale...\tS" msgstr "Derece...\tS" #: res/xrc/EditUV.xrc:134 msgid "Show a dialog to scale the current selection." msgstr "Geçerli seçimi ölçeklendirmek için bir iletişim kutusu göster." #: res/xrc/EditUV.xrc:141 msgid "Translate" msgstr "Dönüşüm" #: res/xrc/EditUV.xrc:282 msgid "Angle" msgstr "Açı / Köşe" #: res/xrc/EditUV.xrc:425 msgid "Uniform (UV)" msgstr "(UV) Kaplama" #: res/xrc/GroupManager.xrc:17 msgid "" "Choose a group and add or remove members by selecting them in the lists." msgstr "" "Bir gruptan tercihini yap ve listelerinden seçerek üyelerini ekle veya " "kaldır." #: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:991 msgid "Select a group XML file" msgstr "XML dosya gurubundan seçimini yap" #: res/xrc/GroupManager.xrc:71 msgid "Groups" msgstr "Guruplar" #: res/xrc/GroupManager.xrc:101 msgid "Add Group" msgstr "Gurup Yükle" #: res/xrc/GroupManager.xrc:110 msgid "Remove Group" msgstr "Gurup Sil" #: res/xrc/GroupManager.xrc:122 msgid "Members" msgstr "Üyeler" #: res/xrc/GroupManager.xrc:137 msgid "Remove >>" msgstr "Sil >>" #: res/xrc/GroupManager.xrc:151 msgid "Outfits" msgstr "Kıyafetler" #: res/xrc/GroupManager.xrc:172 msgid "<< Add" msgstr "<< Yükle" #: res/xrc/ImportDialog.xrc:5 msgid "Import Options..." msgstr "Çıkartma Seçenekleri..." #: res/xrc/ImportDialog.xrc:53 msgid "Invert U" msgstr "U Çıkartma" #: res/xrc/ImportDialog.xrc:62 msgid "Invert V" msgstr "V Çıkartma" #: res/xrc/ImportDialog.xrc:89 msgid "Rotate (X)" msgstr "Döndür (X)" #: res/xrc/ImportDialog.xrc:98 msgid "Choose X rotation." msgstr "X Konumuna Döndür." #: res/xrc/ImportDialog.xrc:113 msgid "Rotate (Y)" msgstr "Döndür (Y)" #: res/xrc/ImportDialog.xrc:122 msgid "Choose Y rotation." msgstr "Y Konumuna Döndür." #: res/xrc/ImportDialog.xrc:137 msgid "Rotate (Z)" msgstr "Döndür (Z)" #: res/xrc/ImportDialog.xrc:146 msgid "Choose Z rotation." msgstr "Z Konumuna Döndür." #: res/xrc/NormalsGenDlg.xrc:6 msgid "Normal Map Generator" msgstr "Normal Harita Üreticisi" #: res/xrc/NormalsGenDlg.xrc:21 msgid "Layers" msgstr "Katmanlar" #: res/xrc/NormalsGenDlg.xrc:37 msgid "Load or save preset layer settings." msgstr "Önceden hazır olarak ayarlanmış katman değerlerini yükle veya kaydet." #: res/xrc/NormalsGenDlg.xrc:61 msgid "Add a new layer after the current one in the layer list." msgstr "Katman listesindeki mevcut satırdan sonra yeni bir katmanı ekler." #: res/xrc/NormalsGenDlg.xrc:62 msgid "Add Layer" msgstr "Katman Ekle" #: res/xrc/NormalsGenDlg.xrc:71 msgid "Move selected layer up one position." msgstr "Seçilen katmanı bir konum yukarı taşır." #: res/xrc/NormalsGenDlg.xrc:72 msgid "Move Up" msgstr "Yukarı Taşı" #: res/xrc/NormalsGenDlg.xrc:87 msgid "Delete the selected layer." msgstr "Seçilen katmanı sil." #: res/xrc/NormalsGenDlg.xrc:88 msgid "Delete Layer" msgstr "Katmanı Sil" #: res/xrc/NormalsGenDlg.xrc:114 msgid "" "Save a copy of an existing normal map if one already exists. File is saved " "in the original directory." msgstr "" "Kopyala ve kaydet, normal bir haritanın bir kopyasını kaydedin. Dosya " "orijinal dizinde kaydedilir." #: res/xrc/NormalsGenDlg.xrc:115 msgid "Backup destination file" msgstr "Hedef dosyayı Yedekle" #: res/xrc/NormalsGenDlg.xrc:124 msgid "" "Compress output file using BC7 compression. This can make saving the file " "take a VERY long time!" msgstr "" "BC7 sıkıştırma biçemini kullanarak çıktı dosyasını sıkıştırır. Bu, dosyanın " "çok uzun süre korunmasını sağlayabilir!" #: res/xrc/NormalsGenDlg.xrc:125 msgid "Compress output " msgstr "Çıktı sıkıştırması " #: res/xrc/NormalsGenDlg.xrc:134 msgid "" "Use the file name specified in the background layer to save the normal map." msgstr "" "Normal haritayı kaydetmek için arka plan katmanında belirtilen dosya adını " "kullanın." #: res/xrc/NormalsGenDlg.xrc:135 msgid "Save to background layer file" msgstr "Arka plan katman dosyasına kaydet" #: res/xrc/NormalsGenDlg.xrc:145 msgid "Choose an output file..." msgstr "Bir çıktı dosyasını seç..." #: res/xrc/NormalsGenDlg.xrc:149 msgid "Location to save normal map to." msgstr "Normal haritayı kaydetme konumu." #: res/xrc/NormalsGenDlg.xrc:165 msgid "Display current settings on mesh in preview window." msgstr "Ön izleme penceresindeki geçerli ayarlarını kafes olarak görüntüle." #: res/xrc/NormalsGenDlg.xrc:181 msgid "Generate and save the normal map file." msgstr "Normal harita dosyasını oluştur ve kaydet." #: res/xrc/NormalsGenDlg.xrc:182 msgid "Generate" msgstr "Oluştur" #: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2010 msgid "Load Preset..." msgstr "Hazır Ayarı Yükle..." #: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2014 msgid "Save Preset..." msgstr "Hazır Ayarı Kaydet..." #: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5 msgid "New Project" msgstr "Yeni Proje" #: res/xrc/OutfitStudio.xrc:23 msgid "" "Create a new project by selecting a reference body slider set, and outfit " "model files." msgstr "" "Örnek bir vücut kaydırıcısı setini ve kıyafet modeli dosyasını seçerek yeni " "bir proje oluştur." #: res/xrc/OutfitStudio.xrc:28 msgid "Load Project" msgstr "Projeyi Yükle" #: res/xrc/OutfitStudio.xrc:29 msgid "Load a previously created slider set for editing." msgstr "Düzenlemek için önceden oluşturulmuş bir kaydırıcı yükle." #: res/xrc/OutfitStudio.xrc:34 msgid "Undo" msgstr "Geri Al" #: res/xrc/OutfitStudio.xrc:35 msgid "Undo a previous action." msgstr "Önceki eylemi geri al." #: res/xrc/OutfitStudio.xrc:41 msgid "Redo" msgstr "Yinele" #: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2119 msgid "Select" msgstr "Seç" #: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2120 msgid "Navigate and select meshes (or vertices in vertex mode)." msgstr "Kafesler arasında gezin ve seç (veya uç tepe noktalarında)." #: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2124 #: src/program/NormalsGenDialog.cpp:291 msgid "Mask" msgstr "Maske" #: res/xrc/OutfitStudio.xrc:58 res/xrc/OutfitStudio.xrc:2125 msgid "" "Mask vertices to prevent them from being transformed.\n" "Hold down the ALT key to remove masking." msgstr "" "Değiştirilmelerini önlemek için Uç tepe noktası maskeleri.\n" "Maskelemeyi kaldırmak için ALT tuşuna basılı tut." #: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2129 msgid "Inflate" msgstr "Büyült" #: res/xrc/OutfitStudio.xrc:65 res/xrc/OutfitStudio.xrc:2130 msgid "Increase mesh volume in an area." msgstr "Bir alandaki kafes yoğunluğunu artırır." #: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2135 msgid "Deflate" msgstr "İncelt" #: res/xrc/OutfitStudio.xrc:72 res/xrc/OutfitStudio.xrc:2136 msgid "Decrease mesh volume in an area." msgstr "Bir alandaki kafes yoğunluğunu artırır." #: res/xrc/OutfitStudio.xrc:79 res/xrc/OutfitStudio.xrc:2141 msgid "Move vertices over a plane parallel to the view." msgstr "Tepe noktalarını, görünüme paralel bir düzlemin üzerine getirir." #: res/xrc/OutfitStudio.xrc:85 res/xrc/OutfitStudio.xrc:2145 msgid "Smooth" msgstr "Düzgünleştir" #: res/xrc/OutfitStudio.xrc:86 res/xrc/OutfitStudio.xrc:2146 msgid "Smooth an area of a mesh." msgstr "Düzgünleştir." #: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2150 msgid "Undiff" msgstr "Farkı Sil" #: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2151 msgid "Undiff an area of a slider." msgstr "Kaydırıcının bir alanındaki farkını kaldır." #: res/xrc/OutfitStudio.xrc:99 res/xrc/OutfitStudio.xrc:2155 msgid "Weight Paint" msgstr "Ağırlık Boyaması" #: res/xrc/OutfitStudio.xrc:100 msgid "" "Apply animation weight values for currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "Seçili olan kemik için animasyon ağırlık değerleri uygula.\n" "Ağırlığı azaltmak için ALT tuşuna basılı tut." #: res/xrc/OutfitStudio.xrc:107 res/xrc/OutfitStudio.xrc:2161 msgid "Color Paint" msgstr "Boyama Rengi" #: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2162 msgid "" "Apply vertex colors.\n" "Hold down the ALT key to remove colors." msgstr "" "Uç Renkleri kabul et.\n" "Rengi kaldırmak için ALT tuşuna basılı tut." #: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2167 msgid "Alpha Paint" msgstr "Alfa Boyama" #: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2168 msgid "" "Apply vertex alpha.\n" "Hold down the ALT key to remove alpha." msgstr "" "Uç Alfayı kabul et.\n" "Alfayı kaldırmak için ALT tuşunu basılı tut." #: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2173 msgid "Collapse Vertex" msgstr "Uç Noktaları Daralt" #: res/xrc/OutfitStudio.xrc:124 res/xrc/OutfitStudio.xrc:2174 msgid "" "Deletes vertices with no more than three connections, without creating a " "hole." msgstr "" "Bir delik oluşturmadan, en fazla üç bağlantıya sahip olan köşe noktalarını " "siler." #: res/xrc/OutfitStudio.xrc:130 res/xrc/OutfitStudio.xrc:2178 msgid "Flip Edge" msgstr "Kenarı Çevir" #: res/xrc/OutfitStudio.xrc:131 res/xrc/OutfitStudio.xrc:2179 msgid "Flips mesh edges so that the opposite pair of vertices is connected." msgstr "Kafes kenarlarını ters köşelere bağlanacak şekilde çevirir." #: res/xrc/OutfitStudio.xrc:137 res/xrc/OutfitStudio.xrc:2183 msgid "Split Edge" msgstr "Bölünmüş Kenar" #: res/xrc/OutfitStudio.xrc:138 res/xrc/OutfitStudio.xrc:2184 msgid "Splits a mesh edge in two with a new vertex." msgstr "Mesh dosyasının kenarını yeni bir tepe noktası ile ikiye böler." #: res/xrc/OutfitStudio.xrc:144 res/xrc/OutfitStudio.xrc:2188 msgid "Move Vertex" msgstr "Tepe Noktasını Taşı" #: res/xrc/OutfitStudio.xrc:145 res/xrc/OutfitStudio.xrc:2189 msgid "Moves a vertex." msgstr "Bir köşeyi hareket ettirir." #: res/xrc/OutfitStudio.xrc:155 msgid "Field of View" msgstr "Görüş Alanı" #: res/xrc/OutfitStudio.xrc:159 msgid "Field of View: 65" msgstr "Görüş Alanı: 65" #: res/xrc/OutfitStudio.xrc:164 msgid "Brush Settings" msgstr "Fırçalama Ayarları" #: res/xrc/OutfitStudio.xrc:169 msgid "Open Discord invite link." msgstr "Discord Site bağlantısını aç." #: res/xrc/OutfitStudio.xrc:174 msgid "Open GitHub link." msgstr "GitHub Site bağlantısını aç." #: res/xrc/OutfitStudio.xrc:179 msgid "Open PayPal link." msgstr "PayPal Site bağlantısını aç." #: res/xrc/OutfitStudio.xrc:200 msgid "Transform" msgstr "Dönüştür" #: res/xrc/OutfitStudio.xrc:201 res/xrc/OutfitStudio.xrc:2195 msgid "Shows a transform tool to manipulate shapes and vertices with." msgstr "" "Kalıpları ve uç tepe noktalarını işlemek için bir dönüştürme aracı gösterir." #: res/xrc/OutfitStudio.xrc:207 msgid "Pivot" msgstr "Eksen" #: res/xrc/OutfitStudio.xrc:208 res/xrc/OutfitStudio.xrc:2200 msgid "" "Shows a pivot that can be moved and makes it the center of mesh operations " "like rotation and scale." msgstr "" "Hareket ettirilebilen bir dönüşü gösterir ve döndürme ve ölçekleme gibi " "işlemlerin merkezi eksenini sağlar." #: res/xrc/OutfitStudio.xrc:214 msgid "Vertex Edit" msgstr "Tepe Noktasını Düzenle" #: res/xrc/OutfitStudio.xrc:215 msgid "" "Lets you select vertices to add to or remove from the mask.\n" "Click on a vertex to select/unmask it.\n" "Hold down CTRL to unselect/mask it." msgstr "" "Maskeye eklemek veya çıkarmak için tepe noktalarını seçmeni sağlar.\n" "Tepe noktalarını kaldırmak/maskelemek için basılı tut.\n" "Seçimi kaldırmak/maskelemek için CTRL tuşuna bas." #: res/xrc/OutfitStudio.xrc:222 msgid "View Front" msgstr "Ön Görünüm" #: res/xrc/OutfitStudio.xrc:223 msgid "Change camera view to the front." msgstr "Kamera görünümünü önden görecek şekilde değiştirir." #: res/xrc/OutfitStudio.xrc:227 msgid "View Back" msgstr "Arka Görünüm" #: res/xrc/OutfitStudio.xrc:228 msgid "Change camera view to the back." msgstr "Kamera görünümünü arkadan görecek şekilde değiştirir." #: res/xrc/OutfitStudio.xrc:232 msgid "View Left" msgstr "Soldan Görünüm" #: res/xrc/OutfitStudio.xrc:233 msgid "Change camera view to the left." msgstr "Kamera görünümünü soldan görecek şekilde değiştirir." #: res/xrc/OutfitStudio.xrc:237 msgid "View Right" msgstr "Sağdan Görünüm" #: res/xrc/OutfitStudio.xrc:238 msgid "Change camera view to the right." msgstr "Kamera görünümünü sağdan görecek şekilde değiştirir." #: res/xrc/OutfitStudio.xrc:242 msgid "Perspective View" msgstr "Derin Görünüm" #: res/xrc/OutfitStudio.xrc:243 msgid "Toggle perspective view." msgstr "Kamera görünümünü derinlemesine görecek şekilde değiştirir." #: res/xrc/OutfitStudio.xrc:249 msgid "Show Nodes" msgstr "Düğümleri Göster" #: res/xrc/OutfitStudio.xrc:250 msgid "Toggle rendering of nodes." msgstr "Düğümleri, Bezeleri görüntüler." #: res/xrc/OutfitStudio.xrc:255 msgid "Show Bones" msgstr "İskeleti Göster" #: res/xrc/OutfitStudio.xrc:256 msgid "Toggle rendering of bones." msgstr "Kemik İskelet yapısını görüntüler." #: res/xrc/OutfitStudio.xrc:261 msgid "Show Floor" msgstr "Zemini Göster" #: res/xrc/OutfitStudio.xrc:262 msgid "Toggle rendering of the floor grid." msgstr "Zemin ızgarasını görüntüler." #: res/xrc/OutfitStudio.xrc:268 msgid "X Mirror" msgstr "Yansıtma X" #: res/xrc/OutfitStudio.xrc:269 res/xrc/OutfitStudio.xrc:1775 msgid "Mirror edits across the X axis." msgstr "X ekseni boyunca yansıtma düzenlemeleri." #: res/xrc/OutfitStudio.xrc:276 res/xrc/OutfitStudio.xrc:1781 msgid "Edit Connected Only\tC" msgstr "Sadece Bağlantıyı Düzenle\tC" #: res/xrc/OutfitStudio.xrc:277 msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius." msgstr "" "Fırça yarıçapı içindeki boyamanın altındakilere bağlı olan yalnızca köşe " "noktalarını düzenle." #: res/xrc/OutfitStudio.xrc:283 res/xrc/OutfitStudio.xrc:1788 msgid "Merge Vertex" msgstr "Tepe Noktasını Düzenle" #: res/xrc/OutfitStudio.xrc:284 res/xrc/OutfitStudio.xrc:1789 msgid "Merges two vertices and fills any gaps." msgstr "İki köşeyi birleştirir ve boşlukları doldurur." #: res/xrc/OutfitStudio.xrc:290 res/xrc/OutfitStudio.xrc:1795 msgid "Weld Vertex" msgstr "Köşe Kaynaşımı" #: res/xrc/OutfitStudio.xrc:291 res/xrc/OutfitStudio.xrc:1796 msgid "Welds two vertices while keeping the texture coordinates (UV) distinct." msgstr "" "Doku koordinatlarını (UV) farklı tutarken iki köşeyi birbirine kaynaştırır." #: res/xrc/OutfitStudio.xrc:297 res/xrc/OutfitStudio.xrc:1802 msgid "Restrict To Surface" msgstr "Yüzey Alanıyla Kısıtla" #: res/xrc/OutfitStudio.xrc:298 res/xrc/OutfitStudio.xrc:1803 msgid "Restricts motion to a mesh surface." msgstr "Hareketi tek bir ağ yüzeyiyle sınırlar." #: res/xrc/OutfitStudio.xrc:304 res/xrc/OutfitStudio.xrc:1809 msgid "Restrict To Plane" msgstr "Düzlem Alanıyla Sınırla" #: res/xrc/OutfitStudio.xrc:305 res/xrc/OutfitStudio.xrc:1810 msgid "Restricts motion to parallel to the surface." msgstr "Hareketi yüzeye paralel olarak kısıtlar." #: res/xrc/OutfitStudio.xrc:311 res/xrc/OutfitStudio.xrc:1816 msgid "Restrict To Normal" msgstr "Normal Alanı Kısıtla" #: res/xrc/OutfitStudio.xrc:312 res/xrc/OutfitStudio.xrc:1817 msgid "Restricts motion to perpendicular to the surface." msgstr "Hareketi yüzeye dik olarak sınırlar." #: res/xrc/OutfitStudio.xrc:375 msgid "Meshes" msgstr "Kafesler" #: res/xrc/OutfitStudio.xrc:399 res/xrc/OutfitStudio.xrc:2510 #: res/xrc/OutfitStudio.xrc:2536 msgid "Segments" msgstr "Parçalar" #: res/xrc/OutfitStudio.xrc:411 res/xrc/OutfitStudio.xrc:2543 #: res/xrc/OutfitStudio.xrc:2554 msgid "Partitions" msgstr "Bölümler" #: res/xrc/OutfitStudio.xrc:423 msgid "Colors" msgstr "Renkler" #: res/xrc/OutfitStudio.xrc:435 msgid "Lights" msgstr "Işıklar" #: res/xrc/OutfitStudio.xrc:475 msgid "Total Bones: 0" msgstr "Toplam İskelet: 0" #: res/xrc/OutfitStudio.xrc:485 msgid "Shape Selection Bones: 0" msgstr "İskelet Modeli Seçimi: 0" #: res/xrc/OutfitStudio.xrc:515 msgid "Brush Color" msgstr "Fırça Rengi" #: res/xrc/OutfitStudio.xrc:524 msgid "Color of the brush." msgstr "Fırçanın rengi." #: res/xrc/OutfitStudio.xrc:546 msgid "Clamp Max Value" msgstr "Max Küme Değeri" #: res/xrc/OutfitStudio.xrc:589 src/program/OutfitStudio.cpp:3062 #: src/program/OutfitStudio.cpp:6647 msgid "Edit Alpha" msgstr "Alfa Düzenleme" #: res/xrc/OutfitStudio.xrc:635 res/xrc/OutfitStudio.xrc:1039 #: res/xrc/OutfitStudio.xrc:1140 src/program/OutfitStudio.cpp:6362 #: src/program/OutfitStudio.cpp:10632 msgid "Reset" msgstr "Sıfırla" #: res/xrc/OutfitStudio.xrc:648 msgid "Ambient" msgstr "Çevre" #: res/xrc/OutfitStudio.xrc:673 msgid "Frontal" msgstr "Önden" #: res/xrc/OutfitStudio.xrc:698 msgid "Directional 1" msgstr "Yön 1" #: res/xrc/OutfitStudio.xrc:723 msgid "Directional 2" msgstr "Yön 2" #: res/xrc/OutfitStudio.xrc:748 msgid "Directional 3" msgstr "Yön 3" #: res/xrc/OutfitStudio.xrc:916 msgid "Slot" msgstr "Yuva" #: res/xrc/OutfitStudio.xrc:991 src/program/OutfitStudio.cpp:5472 msgid "SSF File" msgstr "SSF Dosyası" #: res/xrc/OutfitStudio.xrc:1011 msgid "Set" msgstr "Ayarla" #: res/xrc/OutfitStudio.xrc:1029 res/xrc/OutfitStudio.xrc:1130 #: src/program/OutfitStudio.cpp:6362 msgid "Apply" msgstr "Uygula" #: res/xrc/OutfitStudio.xrc:1158 msgid "De-/Select Sliders" msgstr "De-/Kaydırıcıları Seç" #: res/xrc/OutfitStudio.xrc:1177 msgid "Fixed Weight Brush" msgstr "Ağırlık Fırçalaması Düzeltme" #: res/xrc/OutfitStudio.xrc:1188 msgid "Normalize Weights" msgstr "Ağırlıkları Normalleştir" #: res/xrc/OutfitStudio.xrc:1205 msgid "X-Mirror Bone" msgstr "X-Yansıtma İskelet" #: res/xrc/OutfitStudio.xrc:1230 msgid "Masks" msgstr "Maskeler" #: res/xrc/OutfitStudio.xrc:1275 res/xrc/OutfitStudio.xrc:1336 #: res/xrc/OutfitStudio.xrc:2476 msgid "Delete" msgstr "Sil" #: res/xrc/OutfitStudio.xrc:1291 msgid "Posing" msgstr "Hareket" #: res/xrc/OutfitStudio.xrc:1352 msgid "Show Pose" msgstr "Hareketi Göster" #: res/xrc/OutfitStudio.xrc:1370 msgid "Reset Bone" msgstr "İskeleti Sıfırla" #: res/xrc/OutfitStudio.xrc:1390 msgid "Rotation X" msgstr "Döndür X Konumu" #: res/xrc/OutfitStudio.xrc:1418 msgid "Rotation Y" msgstr "Döndür Y Konumu" #: res/xrc/OutfitStudio.xrc:1446 msgid "Rotation Z" msgstr "Döndür Z Konumu" #: res/xrc/OutfitStudio.xrc:1474 msgid "Offset X" msgstr "Dengele X Konumu" #: res/xrc/OutfitStudio.xrc:1502 msgid "Offset Y" msgstr "Dengele Y Konumu" #: res/xrc/OutfitStudio.xrc:1530 msgid "Offset Z" msgstr "Dengele Z Konumu" #: res/xrc/OutfitStudio.xrc:1592 msgid "Reset All" msgstr "Tümünü Sıfırla" #: res/xrc/OutfitStudio.xrc:1600 msgid "Apply to Mesh" msgstr "Mesh Dosyasına Uygula" #: res/xrc/OutfitStudio.xrc:1642 res/xrc/Settings.xrc:371 #: src/program/NormalsGenDialog.cpp:284 msgid "File" msgstr "Dosya" #: res/xrc/OutfitStudio.xrc:1644 msgid "New Project...\tCtrl+N" msgstr "Yeni Proje...\tCtrl+N" #: res/xrc/OutfitStudio.xrc:1645 msgid "Create a new outfit project." msgstr "Yeni bir kıyafet projesi oluştur." #: res/xrc/OutfitStudio.xrc:1648 msgid "Load Project..\tCtrl+O" msgstr "Hazır Proje Yükle..\tCtrl+O" #: res/xrc/OutfitStudio.xrc:1649 msgid "Load a project." msgstr "Önceki Projeyi yükle." #: res/xrc/OutfitStudio.xrc:1652 msgid "Add Project..\tCtrl+Shift+O" msgstr "Proje Ekle..\tCtrl+Shift+O" #: res/xrc/OutfitStudio.xrc:1653 msgid "Add a project without replacing the current one." msgstr "Geçerli olanı değiştirmeden yeni bir proje ekle." #: res/xrc/OutfitStudio.xrc:1656 msgid "Unload Project...\tCtrl+W" msgstr "Projeyi Kaldır...\tCtrl+W" #: res/xrc/OutfitStudio.xrc:1657 msgid "Unloads the project and creates an empty new one." msgstr "Projeyi kaldırır ve yeni bir boş proje oluşturur." #: res/xrc/OutfitStudio.xrc:1660 msgid "Recent Projects..." msgstr "Son Projeler..." #: res/xrc/OutfitStudio.xrc:1665 msgid "Load Reference..." msgstr "Örnekten Yükle..." #: res/xrc/OutfitStudio.xrc:1666 msgid "" "Load a new reference slider set, replacing any current reference objects." msgstr "" "Mevcut referans nesnelerini değiştirerek yeni bir örnekleme kaydırıcı setini " "yükle." #: res/xrc/OutfitStudio.xrc:1669 msgid "Load Outfit..." msgstr "Kıyafeti Yükle..." #: res/xrc/OutfitStudio.xrc:1670 msgid "" "Load a NIF file as the working outfit, replacing any current outfit objects." msgstr "" "Herhangi bir mevcut kıyafet nesnesini değiştirerek, çalışma kıyafeti " "şeklinde NIF dosyası olarak yükle." #: res/xrc/OutfitStudio.xrc:1674 msgid "Convert / Replace Reference...\tCtrl+Shift+R" msgstr "Örnek Kalıbı Değiştir/Dönüştür...\tCtrl+Shift+R" #: res/xrc/OutfitStudio.xrc:1675 msgid "Convert to or replace an outfit's body/reference" msgstr "Bir kıyafeti bedenine göre beden/örnek olarak dönüştür veya değiştir" #: res/xrc/OutfitStudio.xrc:1679 msgid "Save Project\tCtrl+S" msgstr "Projeyi Kaydet\tCtrl+S" #: res/xrc/OutfitStudio.xrc:1680 msgid "Save the project." msgstr "Çalışmanı Kaydet." #: res/xrc/OutfitStudio.xrc:1684 msgid "Save Project As...\tCtrl+Shift+S" msgstr "Projeyi Farklı Kaydet...\tCtrl+Shift+S" #: res/xrc/OutfitStudio.xrc:1685 msgid "Save the project under a new name." msgstr "Projeyi yeni bir isim vererek kaydet." #: res/xrc/OutfitStudio.xrc:1689 src/program/OutfitStudio.cpp:7222 #: src/program/OutfitStudio.cpp:7333 msgid "Import" msgstr "Yerleştir" #: res/xrc/OutfitStudio.xrc:1691 msgid "From NIF..." msgstr "NIF olarak..." #: res/xrc/OutfitStudio.xrc:1692 msgid "Choose a NIF file to import into the project." msgstr "Projeye yerleştirmek için bir NIF dosyasını seç." #: res/xrc/OutfitStudio.xrc:1695 msgid "From OBJ..." msgstr "OBJ olarak..." #: res/xrc/OutfitStudio.xrc:1696 msgid "Import an OBJ file as a new shape in the outfit." msgstr "Bir OBJ dosyasını kıyafette yeni bir kalıp olarak içe aktar." #: res/xrc/OutfitStudio.xrc:1699 msgid "From FBX..." msgstr "FBX olarak..." #: res/xrc/OutfitStudio.xrc:1700 msgid "Import an FBX file as a new shape in the outfit." msgstr "Bir FBX dosyasını kıyafette yeni bir kalıp olarak içe aktar." #: res/xrc/OutfitStudio.xrc:1703 msgid "From TRI (Head)..." msgstr "TRI Dosyası Olarak (Kafa)..." #: res/xrc/OutfitStudio.xrc:1704 msgid "Import shape and morphs from a head TRI file." msgstr "TRI morphs dosyası verilerini TRI dosyası olarak çıkarır." #: res/xrc/OutfitStudio.xrc:1707 msgid "Import Data" msgstr "Data Yerleştir" #: res/xrc/OutfitStudio.xrc:1709 msgid "Import BSClothExtraData From HKX" msgstr "BSClothExtraData Dosyasına HKX Dosyasından Yerleştir" #: res/xrc/OutfitStudio.xrc:1710 msgid "" "Choose an HKX file to import as a BSClothExtraData block into the project." msgstr "" "Projeye BSClothExtraData bloğu olarak almak için bir HKX dosyasını seç." #: res/xrc/OutfitStudio.xrc:1715 res/xrc/OutfitStudio.xrc:1843 #: res/xrc/OutfitStudio.xrc:2313 msgid "Export" msgstr "Çıkart" #: res/xrc/OutfitStudio.xrc:1717 msgid "To NIF...\tCtrl+E" msgstr "NIF olarak...\tCtrl+E" #: res/xrc/OutfitStudio.xrc:1718 msgid "Save the current project as a NIF file (without reference)" msgstr "Mevcut projeyi bir NIF dosyası olarak kaydet (referans olmadan)" #: res/xrc/OutfitStudio.xrc:1721 msgid "To NIF With Reference...\tCtrl+Alt+E" msgstr "Referans ile NIF'e aktar...\tCtrl+Alt+E" #: res/xrc/OutfitStudio.xrc:1722 msgid "Save the current project as a NIF file (including reference)" msgstr "Mevcut projeyi bir NIF dosyası olarak kaydet (referans dahil olarak)" #: res/xrc/OutfitStudio.xrc:1725 res/xrc/OutfitStudio.xrc:1849 #: res/xrc/OutfitStudio.xrc:2319 msgid "To OBJ..." msgstr "OBJ olarak..." #: res/xrc/OutfitStudio.xrc:1726 msgid "Export the current project as an OBJ file." msgstr "Seçilen modeli bir OBJ kalıbı olarak dışa aktar." #: res/xrc/OutfitStudio.xrc:1729 res/xrc/OutfitStudio.xrc:1853 #: res/xrc/OutfitStudio.xrc:2323 msgid "To FBX..." msgstr "FBX olarak..." #: res/xrc/OutfitStudio.xrc:1730 msgid "Export the current project as an FBX file." msgstr "Mevcut projeyi bir FBX dosyası olarak dışa aktar." #: res/xrc/OutfitStudio.xrc:1733 res/xrc/OutfitStudio.xrc:1857 #: res/xrc/OutfitStudio.xrc:2327 msgid "To TRI (Head)..." msgstr "TRI olarak (Kafa)..." #: res/xrc/OutfitStudio.xrc:1734 res/xrc/OutfitStudio.xrc:1858 #: res/xrc/OutfitStudio.xrc:2328 msgid "Export head morphs to a TRI file." msgstr "TRI morphs dosyası verilerini TRI dosyası olarak çıkarır." #: res/xrc/OutfitStudio.xrc:1737 msgid "Export Data" msgstr "Verileri Dışa Aktar" #: res/xrc/OutfitStudio.xrc:1739 msgid "Export BSClothExtraData As HKX" msgstr "BSClothExtraData dosyasını HKX olarak çıkart" #: res/xrc/OutfitStudio.xrc:1740 msgid "" "Save one of the currently loaded BSClothExtraData blocks to an HKX file." msgstr "" "Şu anda yüklü olan BSClothExtraData bloklarından birini HKX dosyasına kaydet." #: res/xrc/OutfitStudio.xrc:1745 msgid "Make Conversion Reference" msgstr "Dönüşüm Referansı Oluştur" #: res/xrc/OutfitStudio.xrc:1746 msgid "" "Using the current slider settings for the reference shape, create a new " "reference that will morph from the current shape back to the base shape." msgstr "" "Referans şekli için mevcut kaydırıcı ayarlarını kullanarak, mevcut şekilden " "taban şekline dönüşecek yeni bir referans oluştur." #: res/xrc/OutfitStudio.xrc:1750 res/xrc/Project.xrc:947 msgid "Pack Projects..." msgstr "Paket Projeler..." #: res/xrc/OutfitStudio.xrc:1751 msgid "Pack one or more projects into a folder or archive for sharing." msgstr "" "Bir veya daha fazla projeyi paylaşmak üzere bir klasöre veya arşive paketle." #: res/xrc/OutfitStudio.xrc:1758 msgid "Exit\tAlt+F4" msgstr "Kapat\tAlt+F4" #: res/xrc/OutfitStudio.xrc:1759 msgid "Exit Outfit Studio." msgstr "Kapat Outfit Studio." #: res/xrc/OutfitStudio.xrc:1774 msgid "X Mirror\tX" msgstr "Yansıtma X\tX" #: res/xrc/OutfitStudio.xrc:1782 msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius" msgstr "" "Fırça yarıçapı içindeki boyamanın altındakilere bağlı olan yalnızca köşe " "noktalarını düzenle" #: res/xrc/OutfitStudio.xrc:1824 msgid "Recalculate Normals\tR" msgstr "Yeniden Hesaplama Normali\tR" #: res/xrc/OutfitStudio.xrc:1825 msgid "Recalculate normals on active mesh" msgstr "Aktif kafeste normal değerleri yeniden hesapla" #: res/xrc/OutfitStudio.xrc:1828 msgid "Reset Transforms" msgstr "Dönüşümü Sıfırla" #: res/xrc/OutfitStudio.xrc:1829 msgid "Resets the shape and skin transforms." msgstr "Kalıpları ve cilt dönüşümlerini sıfırlar." #: res/xrc/OutfitStudio.xrc:1832 src/program/OutfitStudio.cpp:10232 msgid "Delete Unreferenced Nodes" msgstr "Örneklenmeyen Düğümleri Sil" #: res/xrc/OutfitStudio.xrc:1833 msgid "Deletes all nodes from the project that aren't used in any other block." msgstr "Başka bir blokta kullanılmayan tüm düğümleri projeden siler." #: res/xrc/OutfitStudio.xrc:1836 msgid "Remove Skinning" msgstr "Kaplamayı Kaldır" #: res/xrc/OutfitStudio.xrc:1837 msgid "Removes skinning of all shapes and all unused nodes." msgstr "Tüm kalıpların ve kullanılmayan tüm düğümlerin kaplamasını kaldırır." #: res/xrc/OutfitStudio.xrc:1841 res/xrc/OutfitStudio.xrc:2311 msgid "Shape" msgstr "Model" #: res/xrc/OutfitStudio.xrc:1845 res/xrc/OutfitStudio.xrc:2315 msgid "To NIF..." msgstr "NIF olarak..." #: res/xrc/OutfitStudio.xrc:1846 res/xrc/OutfitStudio.xrc:2316 msgid "Export only the selected shapes to a NIF file." msgstr "Bir NIF dosyasını kıyafette yeni bir kalıp olarak içe aktar." #: res/xrc/OutfitStudio.xrc:1850 res/xrc/OutfitStudio.xrc:2320 msgid "Export only the selected shapes to an OBJ file." msgstr "" "Geçerli kaydırıcının verilerini BodySlide OBJ dosyası olarak kaydederek dışa " "aktarır." #: res/xrc/OutfitStudio.xrc:1854 res/xrc/OutfitStudio.xrc:2324 msgid "Export only the selected shapes to an FBX file." msgstr "Seçilen modeli bir FBX kalıbı olarak dışa aktar." #: res/xrc/OutfitStudio.xrc:1862 res/xrc/OutfitStudio.xrc:2332 #: res/xrc/Slider.xrc:200 msgid "UV" msgstr "UV" #: res/xrc/OutfitStudio.xrc:1864 res/xrc/OutfitStudio.xrc:2334 msgid "Edit..." msgstr "Düzenle..." #: res/xrc/OutfitStudio.xrc:1865 res/xrc/OutfitStudio.xrc:2335 msgid "Edit the texture coordinates." msgstr "Doku (texture) koordinatlarını düzenle." #: res/xrc/OutfitStudio.xrc:1868 res/xrc/OutfitStudio.xrc:2338 msgid "Invert X" msgstr "X Yöne Çevir" #: res/xrc/OutfitStudio.xrc:1869 res/xrc/OutfitStudio.xrc:2339 msgid "Inverts the X-axis of the texture coordinates." msgstr "Textures doku dosyalarını X-ekseni tarafına doğru çevir." #: res/xrc/OutfitStudio.xrc:1872 res/xrc/OutfitStudio.xrc:2342 msgid "Invert Y" msgstr "Y Yöne Çevir" #: res/xrc/OutfitStudio.xrc:1873 res/xrc/OutfitStudio.xrc:2343 msgid "Inverts the Y-axis of the texture coordinates." msgstr "Textures doku dosyalarını Y-ekseni tarafına doğru çevir." #: res/xrc/OutfitStudio.xrc:1877 res/xrc/OutfitStudio.xrc:2347 msgid "Mirror" msgstr "Yansıt" #: res/xrc/OutfitStudio.xrc:1880 res/xrc/OutfitStudio.xrc:2350 msgid "Mirror the selected shapes on the X-axis." msgstr "Seçilen modelleri X-eksenine doğru yansıt." #: res/xrc/OutfitStudio.xrc:1884 res/xrc/OutfitStudio.xrc:2354 msgid "Mirror the selected shapes on the Y-axis." msgstr "Seçilen modelleri Y-eksenine doğru yansıt." #: res/xrc/OutfitStudio.xrc:1888 res/xrc/OutfitStudio.xrc:2358 msgid "Mirror the selected shapes on the Z-axis." msgstr "Seçilen modelleri Z-eksenine doğru yansıt." #: res/xrc/OutfitStudio.xrc:1892 res/xrc/OutfitStudio.xrc:2362 msgid "Delete Vertices...\tShift+Del" msgstr "Köşeleri Sil...\tShift+Del" #: res/xrc/OutfitStudio.xrc:1893 res/xrc/OutfitStudio.xrc:2363 msgid "Deletes all unmasked vertices of the currently selected shapes." msgstr "Seçili modellerin tüm maskelenmemiş köşelerini siler." #: res/xrc/OutfitStudio.xrc:1896 res/xrc/OutfitStudio.xrc:2366 msgid "Separate Vertices...\tShift+S" msgstr "Ayrışmış Köşeler...\tShift+S" #: res/xrc/OutfitStudio.xrc:1897 res/xrc/OutfitStudio.xrc:2367 msgid "Separate the current shape into two by using the mask." msgstr "Maskeyi kullanarak mevcut modeli ikiye ayır." #: res/xrc/OutfitStudio.xrc:1900 res/xrc/OutfitStudio.xrc:2370 msgid "Merge Geometry..." msgstr "Geometriyi Birleştir..." #: res/xrc/OutfitStudio.xrc:1901 res/xrc/OutfitStudio.xrc:2371 msgid "Copies vertices and triangles from one shape to another." msgstr "Köşeleri ve üçgenleri bir şekilden diğerine kopyalar." #: res/xrc/OutfitStudio.xrc:1904 res/xrc/OutfitStudio.xrc:2374 msgid "Duplicate..." msgstr "Tekrarla..." #: res/xrc/OutfitStudio.xrc:1905 res/xrc/OutfitStudio.xrc:2375 msgid "Duplicate the current shape." msgstr "Geçerli modeli tekrarla." #: res/xrc/OutfitStudio.xrc:1908 res/xrc/OutfitStudio.xrc:2378 msgid "Refine Mesh" msgstr "Ağ Düzeltme" #: res/xrc/OutfitStudio.xrc:1909 res/xrc/OutfitStudio.xrc:2379 msgid "Splits all edges between unmasked vertices" msgstr "Maskelenmemiş köşeler arasında tüm kenarları böler" #: res/xrc/OutfitStudio.xrc:1912 res/xrc/OutfitStudio.xrc:2382 msgid "Rename...\tF2" msgstr "Ad Değiştir...\tF2" #: res/xrc/OutfitStudio.xrc:1913 res/xrc/OutfitStudio.xrc:2383 msgid "Change the name of the current shape." msgstr "Geçerli modelin adını değiştir." #: res/xrc/OutfitStudio.xrc:1916 res/xrc/OutfitStudio.xrc:2386 msgid "Set Reference" msgstr "Örnek Kurulumu" #: res/xrc/OutfitStudio.xrc:1917 res/xrc/OutfitStudio.xrc:2387 msgid "Turn the shape into the reference shape of the project." msgstr "Dönüştürülen projeyi örnek model olarak kaydet." #: res/xrc/OutfitStudio.xrc:1921 res/xrc/OutfitStudio.xrc:2391 msgid "Move..." msgstr "Hareket..." #: res/xrc/OutfitStudio.xrc:1922 res/xrc/OutfitStudio.xrc:2392 msgid "" "Apply an offset adjustment to the mesh vertices. This permanently moves " "vertices." msgstr "" "Kafes köşelerine bir dengeleme ayarı uygula. Bu kalıcı olarak köşe " "noktalarını düzenleyecek." #: res/xrc/OutfitStudio.xrc:1925 res/xrc/OutfitStudio.xrc:2395 msgid "Scale..." msgstr "Derece..." #: res/xrc/OutfitStudio.xrc:1926 res/xrc/OutfitStudio.xrc:2396 msgid "Apply a scale adjustment to the shape. This permanently moves vertices." msgstr "" "Modele bir ölçek derecesi ayarını uygula. Bu kalıcı olarak köşe noktalarını " "düzenleyecek." #: res/xrc/OutfitStudio.xrc:1929 res/xrc/OutfitStudio.xrc:2399 msgid "Rotate..." msgstr "Dönüş..." #: res/xrc/OutfitStudio.xrc:1930 res/xrc/OutfitStudio.xrc:2400 msgid "Apply a rotation to the mesh vertices. This permanently moves vertices." msgstr "" "Modele bir dönüş derecesi ayarını uygula. Bu kalıcı olarak köşe noktalarını " "düzenleyecek." #: res/xrc/OutfitStudio.xrc:1933 msgid "Smooth Seam Normals" msgstr "Pürüzsüz Dikiş Standartı" #: res/xrc/OutfitStudio.xrc:1934 msgid "" "Smooths edges of seams (usually found at texture borders), disable if this " "causes odd normals on the shape." msgstr "" "Dikişlerin kenarlarını pürüzsüzleştirir (genellikle doku sınırlarında " "bulunur), bu durum model üzerindeki tuhaf şekillere neden oluyorsa devre " "dışı bırakabilirsin." #: res/xrc/OutfitStudio.xrc:1939 msgid "Lock Normals" msgstr "Standart Kilidi" #: res/xrc/OutfitStudio.xrc:1940 msgid "" "Locks the mesh normals. Enable if you want to keep custom normals intact." msgstr "" "Kafes kenarlarını kilitler. Özel yapılandırmayı bozmak istemiyorsan bunu " "etkinleştir." #: res/xrc/OutfitStudio.xrc:1947 res/xrc/OutfitStudio.xrc:2405 msgid "Copies all bone weights from the reference shape to the current shape." msgstr "" "Tüm beden ağırlıklarını referans aldığı modelden mevcut modele kopyalar." #: res/xrc/OutfitStudio.xrc:1950 res/xrc/OutfitStudio.xrc:2408 msgid "Copy Selected Weights" msgstr "Seçilen Ağırlıkları Kopyala" #: res/xrc/OutfitStudio.xrc:1951 res/xrc/OutfitStudio.xrc:2409 msgid "" "Copies selected bone weights from the reference shape to the current shape." msgstr "" "Tercihe göre seçilen beden ağırlıklarını referans aldığı modelden mevcut " "modele kopyalar." #: res/xrc/OutfitStudio.xrc:1954 res/xrc/OutfitStudio.xrc:2412 msgid "Transfer Selected Weights" msgstr "Seçilen Ağırlıkları Aktar" #: res/xrc/OutfitStudio.xrc:1955 res/xrc/OutfitStudio.xrc:2413 msgid "" "Transfers selected weights from the reference shape to the current shape. " "Requires same vertex count and order." msgstr "" "Referans modelinden seçilen şekil ağırlıklarını aktarır. Aynı köşegen " "açıları sayısını ve kodlamasını gerektirir." #: res/xrc/OutfitStudio.xrc:1958 res/xrc/OutfitStudio.xrc:2416 #: res/xrc/OutfitStudio.xrc:2491 msgid "Mask Weighted Vertices" msgstr "Kafes Ağırlıklarını Maskele" #: res/xrc/OutfitStudio.xrc:1959 res/xrc/OutfitStudio.xrc:2417 msgid "" "Masks vertices with bone weights, so you can manually assign weights to " "unweighted vertices." msgstr "" "Kemik ağırlıklarına sahip köşeleri maskeleyerek ağırlık atamasını sıfırlar, " "böylece istediğin değerleri ağırlıksız köşelere elle atayabilirsin." #: res/xrc/OutfitStudio.xrc:1962 msgid "Check For Bad Bones..." msgstr "Hatalı İskelet Kontrolü..." #: res/xrc/OutfitStudio.xrc:1963 res/xrc/OutfitStudio.xrc:2421 msgid "" "Looks for bones with inconsistencies in their transforms. If any are found, " "a dialog is opened to give options for fixing them." msgstr "" "Dönüşümlerinde tutarsızlık yapan iskelet yapılarını arar. Hatalı iskelet " "bulunursa, bunu düzeltmek için seçenekler sunan bir iletişim kutusu açılır." #: res/xrc/OutfitStudio.xrc:1967 res/xrc/OutfitStudio.xrc:2425 msgid "Copy Partitions/Segments..." msgstr "Kopyala Bölümler/Parçalar..." #: res/xrc/OutfitStudio.xrc:1968 res/xrc/OutfitStudio.xrc:2426 msgid "" "Copies partitions/segments and all triangle assignments from the reference " "shape to the current shape." msgstr "" "Bölümleri/parçaları ve tüm üçgen atamalarını referans alınan örnek kalıptan " "geçerli kalıba kopyalar." #: res/xrc/OutfitStudio.xrc:1972 res/xrc/OutfitStudio.xrc:2430 msgid "Mask Symmetric Vertices..." msgstr "Simetrik Köşeleri Maskele..." #: res/xrc/OutfitStudio.xrc:1973 res/xrc/OutfitStudio.xrc:2431 msgid "" "Masks unmasked vertices that have a mirrored vertex with identical data." msgstr "" "Aynı verilere sahip tepe noktalarını maskelenmemiş olan tepe noktalarına " "maskeler." #: res/xrc/OutfitStudio.xrc:1976 res/xrc/OutfitStudio.xrc:2434 msgid "Symmetrize Vertices..." msgstr "Tepe Noktalarını Simetrileştir..." #: res/xrc/OutfitStudio.xrc:1977 res/xrc/OutfitStudio.xrc:2435 msgid "Changes vertex data to be identical to mirrored vertices." msgstr "" "Tepe noktası verilerini yansıtılmış köşelerle aynı olacak şekilde değiştirir." #: res/xrc/OutfitStudio.xrc:1980 res/xrc/OutfitStudio.xrc:2438 msgid "Mask Symmetric Triangles" msgstr "Üçgenleri Simetrik Maskele" #: res/xrc/OutfitStudio.xrc:1981 res/xrc/OutfitStudio.xrc:2439 msgid "Masks triangles that can be matched to a mirrored triangle." msgstr "Yansıtılmış bir üçgenle eşleşen tüm üçgenleri maskeler." #: res/xrc/OutfitStudio.xrc:1985 res/xrc/OutfitStudio.xrc:2443 msgid "Delete\tDel" msgstr "Sil\tDel" #: res/xrc/OutfitStudio.xrc:1986 res/xrc/OutfitStudio.xrc:2444 msgid "Removes the currently selected shape from the outfit." msgstr "Mevcut kıyafetlerden seçili kalıbı kaldırır." #: res/xrc/OutfitStudio.xrc:1989 res/xrc/OutfitStudio.xrc:2447 msgid "Properties..." msgstr "Özellikler..." #: res/xrc/OutfitStudio.xrc:1990 res/xrc/OutfitStudio.xrc:2448 msgid "" "Opens the properties dialog for shader, texture and more settings of the " "selected shape." msgstr "" "Gölgelendirici, doku ve seçilen kalıbın daha fazla ayarları için özellikler " "iletişim kutusunu açar." #: res/xrc/OutfitStudio.xrc:1994 msgid "Slider" msgstr "Kaydırıcı" #: res/xrc/OutfitStudio.xrc:1996 msgid "Conform Selected\tCtrl+C" msgstr "Seçimi Uydur\tCtrl+C" #: res/xrc/OutfitStudio.xrc:1997 msgid "Conform selected outfit shape to all checked sliders." msgstr "" "Seçilen kaydırıcılara tercih edilen kıyafet kalıbını uygun hale getirir." #: res/xrc/OutfitStudio.xrc:2000 msgid "Conform All\tCtrl+Shift+C" msgstr "Tümünü Uydur\tCtrl+Shift+C" #: res/xrc/OutfitStudio.xrc:2001 msgid "Conform all outfit shapes to all checked sliders." msgstr "Tüm kaydırıcılara seçilen kıyafet kalıbını uygun hale getirir." #: res/xrc/OutfitStudio.xrc:2005 msgid "Set Base Shape" msgstr "Temel Kalıbı Ayarla" #: res/xrc/OutfitStudio.xrc:2006 msgid "Set the current outfit shape as the base shape and clear slider data." msgstr "" "Mevcut kıyafet kalıbını ana şablon olarak ayarla ve kaydırıcı verilerini " "temizle." #: res/xrc/OutfitStudio.xrc:2011 msgid "" "Load and preview a slider preset. Inverted sliders will have inverted values." msgstr "" "Hazır kaydırıcı ayarını yükle ve ön izlemeye al. Ters kaydırıcılar, ters " "değerlere sahip olacaktır." #: res/xrc/OutfitStudio.xrc:2015 msgid "" "Save a slider preset with the current values. Inverted sliders will have " "inverted values." msgstr "" "Hazır kaydırıcı ayarını mevcut değerleri ile kaydet. Ters kaydırıcılar, ters " "değerlere sahip olacaktır." #: res/xrc/OutfitStudio.xrc:2019 msgid "New Slider" msgstr "Yeni Kaydırıcı Gurup" #: res/xrc/OutfitStudio.xrc:2020 msgid "Create a new shape transformation slider." msgstr "Yeni bir kalıp dönüştürme kaydırıcısı oluştur." #: res/xrc/OutfitStudio.xrc:2023 msgid "Coalesce sliders" msgstr "Birleşik Kaydırıcılar" #: res/xrc/OutfitStudio.xrc:2024 msgid "" "Create a new shape transformation slider based on the current slider values" msgstr "Mevcut kaydırıcı değerlerini uygulayarak yeni bir kalıp oluştur" #: res/xrc/OutfitStudio.xrc:2027 msgid "New Zap Slider" msgstr "Yeni Zap Kaydırıcısı" #: res/xrc/OutfitStudio.xrc:2028 msgid "Create a new Zap slider based on unmasked vertices" msgstr "Değer atanmayan köşelere yeni bir Zap kaydırıcısı oluştur" #: res/xrc/OutfitStudio.xrc:2032 msgid "Import OSD..." msgstr "OSD Dosyası Yerleştir..." #: res/xrc/OutfitStudio.xrc:2033 msgid "Imports OSD file and creates sliders for shapes with a matching name." msgstr "" "OSD dosyasını içe aktarır ve eşleşen ada sahip kalıplar için bir kaydırıcı " "oluşturur." #: res/xrc/OutfitStudio.xrc:2036 msgid "Export OSD..." msgstr "OSD olarak Çıkar..." #: res/xrc/OutfitStudio.xrc:2037 msgid "Exports all currently loaded slider data to an OSD file." msgstr "Yüklü olan tüm kaydırıcı verilerini bir OSD dosyası olarak aktarır." #: res/xrc/OutfitStudio.xrc:2040 msgid "Import TRI Morphs..." msgstr "TRI Morphs Dosyası olarak yerleştir..." #: res/xrc/OutfitStudio.xrc:2041 msgid "" "Imports TRI morphs from a TRI file and creates sliders for shapes with a " "matching name." msgstr "" "Bir TRI morphs dosyasından verileri TRI dosyası olarak içe aktarır ve " "eşleşen ada sahip kalıplar için kaydırıcı oluşturur." #: res/xrc/OutfitStudio.xrc:2044 msgid "Export TRI Morphs..." msgstr "TRI Morphs Dosyası olarak Çıkar..." #: res/xrc/OutfitStudio.xrc:2045 msgid "Exports TRI morphs to a TRI file." msgstr "TRI morphs dosyası verilerini TRI dosyası olarak çıkarır." #: res/xrc/OutfitStudio.xrc:2048 msgid "Export to OBJs..." msgstr "OBJ Dosyası olarak Çıkar..." #: res/xrc/OutfitStudio.xrc:2049 msgid "Export all sliders to an OBJ file per slider." msgstr "Tüm kaydırıcıları farklı bir OBJ dosyası olarak kaydeder." #: res/xrc/OutfitStudio.xrc:2053 msgid "Import Slider Data" msgstr "Kaydırıcı Verisini Al" #: res/xrc/OutfitStudio.xrc:2055 msgid "Import NIF..." msgstr "NIF Dosyası Yerleştir..." #: res/xrc/OutfitStudio.xrc:2056 msgid "Import a NIF file and overwrites the current shape's slider data." msgstr "" "Bir NIF dosyasını içe aktarır ve geçerli kalıbın kaydırıcı verilerinin " "üzerine yazar." #: res/xrc/OutfitStudio.xrc:2059 msgid "Import BSD..." msgstr "BSD Dosyası Yerleştir..." #: res/xrc/OutfitStudio.xrc:2060 msgid "" "Import a BodySlide BSD file and overwrites the current shape's slider data." msgstr "" "BodySlide BSD dosyasını içe aktarır ve geçerli kalıbın kaydırıcı verilerini " "üzerine yazar." #: res/xrc/OutfitStudio.xrc:2063 msgid "Import OBJ..." msgstr "OBJ Dosyası Yerleştir..." #: res/xrc/OutfitStudio.xrc:2064 msgid "" "Import an OBJ file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "" "Geçerli kalıbın tepe noktalarıyla eşleşen bir OBJ dosyasını içe aktarır ve " "kaydırıcı verileri farkını hesaplar." #: res/xrc/OutfitStudio.xrc:2067 msgid "Import FBX..." msgstr "FBX Dosyası Yerleştir..." #: res/xrc/OutfitStudio.xrc:2068 msgid "" "Import an FBX file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "" "Geçerli kalıbın tepe noktalarıyla eşleşen bir FBX dosyasını içe aktarır ve " "kaydırıcı verileri farkını hesaplar." #: res/xrc/OutfitStudio.xrc:2073 msgid "Export Slider Data" msgstr "Kaydırıcı Verisini Çıkart" #: res/xrc/OutfitStudio.xrc:2075 msgid "Export NIF..." msgstr "NIF olarak çıkart..." #: res/xrc/OutfitStudio.xrc:2076 msgid "Exports the current slider's data as a NIF file." msgstr "" "Geçerli kaydırıcının tüm verilerini bir NIF dosyası olarak dışa aktarır." #: res/xrc/OutfitStudio.xrc:2079 msgid "Export BSD..." msgstr "BSD olarak Çıkart..." #: res/xrc/OutfitStudio.xrc:2080 msgid "Exports the current slider's data as a BodySlide BSD file." msgstr "" "Geçerli kaydırıcının verilerini BodySlide BSD dosyası olarak kaydederek dışa " "aktarır." #: res/xrc/OutfitStudio.xrc:2083 msgid "Export OBJ..." msgstr "OBJ olarak Çıkart..." #: res/xrc/OutfitStudio.xrc:2084 msgid "Exports the current slider's data as an OBJ file." msgstr "" "Geçerli kaydırıcının verilerini BodySlide OBJ dosyası olarak kaydederek dışa " "aktarır." #: res/xrc/OutfitStudio.xrc:2090 msgid "Negate Slider" msgstr "Kaydırıcıyı İptal Et" #: res/xrc/OutfitStudio.xrc:2091 msgid "Negates the current slider, reversing it's effect" msgstr "Geçerli kaydırıcıyı iptal eder, etkilerini geri alır" #: res/xrc/OutfitStudio.xrc:2095 msgid "Mask Affected Vertices" msgstr "Uç Etki Maskesi" #: res/xrc/OutfitStudio.xrc:2096 msgid "Masks the vertices the slider is affecting for all selected shapes." msgstr "" "Kaydırma çubuğu ile seçilen tüm kalıpların etkilendiği tepe noktalarını " "maskeler." #: res/xrc/OutfitStudio.xrc:2100 msgid "Clear Slider Data" msgstr "Kaydırıcı Verilerini Temizle" #: res/xrc/OutfitStudio.xrc:2101 msgid "" "Erases the slider data without removing the slider itself. (Cannot be undone)" msgstr "" "Kaydırıcının kendiliğinden kaldırmadığı kaydırıcı verilerini siler. (Geri " "alınamaz)" #: res/xrc/OutfitStudio.xrc:2104 msgid "Delete Slider" msgstr "Kaydırıcıyı Sil" #: res/xrc/OutfitStudio.xrc:2105 msgid "Delete the active slider from the project. (Cannot be undone)" msgstr "Etkin kaydırıcıyı projeden siler. (Geri Alınamaz)" #: res/xrc/OutfitStudio.xrc:2109 msgid "Properties...\tTab" msgstr "Özellikler...\tTab" #: res/xrc/OutfitStudio.xrc:2110 src/ui/wxSliderPanel.cpp:69 msgid "Display and edit the active slider's properties." msgstr "Aktif kaydırıcının özelliklerini görüntüler ve düzenler." #: res/xrc/OutfitStudio.xrc:2115 msgid "Tool" msgstr "Araçlar" #: res/xrc/OutfitStudio.xrc:2117 msgid "Current Tool" msgstr "Mevcut Araçlar" #: res/xrc/OutfitStudio.xrc:2156 msgid "" "Apply animation weight values for the currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "Seçili olan iskelet için animasyon ağırlık değerlerini uygular.\n" "Ağırlığı düşürmek için ALT tuşuna basılı tut." #: res/xrc/OutfitStudio.xrc:2194 msgid "Transform\tF" msgstr "Dönüştür\tF" #: res/xrc/OutfitStudio.xrc:2199 msgid "Pivot\tP" msgstr "Eksen\tP" #: res/xrc/OutfitStudio.xrc:2204 msgid "Vertex Edit\tQ" msgstr "Tepe Noktasını Düzenle\tQ" #: res/xrc/OutfitStudio.xrc:2205 msgid "" "Shows vertex points and lets you mask/unmask them.\n" "Without any brush active, click on a vertex to unmask it.\n" "Hold down CTRL to mask it." msgstr "" "Köşe noktalarını gösterir ve bunları maskelemeni/maskeyi kaldırmanı sağlar.\n" "Herhangi bir fırça etkin değilken, maskesini kaldırmak için bir tepe " "noktasına tıklayın.\n" "Gizlemek için CTRL tuşunu basılı tutun." #: res/xrc/OutfitStudio.xrc:2210 msgid "Increase Brush Size\tShift++" msgstr "Fırça Çapını Büyült\tShift++" #: res/xrc/OutfitStudio.xrc:2211 msgid "Increase brush diameter" msgstr "Fırça çapını büyült" #: res/xrc/OutfitStudio.xrc:2214 msgid "Decrease Brush Size\tShift+-" msgstr "Fırça Çapını Küçült\tShift+-" #: res/xrc/OutfitStudio.xrc:2215 msgid "Decrease brush diameter" msgstr "Fırça çapını küçült" #: res/xrc/OutfitStudio.xrc:2218 msgid "Increase Brush Strength\tCtrl++" msgstr "Fırça Kuvvetini Arttır\tCtrl++" #: res/xrc/OutfitStudio.xrc:2219 msgid "Increase brush strength" msgstr "Fırça kuvvetini arttır" #: res/xrc/OutfitStudio.xrc:2222 msgid "Decrease Brush Strength\tCtrl+-" msgstr "Fırça Kuvvetini Azalt\tCtrl+-" #: res/xrc/OutfitStudio.xrc:2223 msgid "Decrease brush strength" msgstr "Fırça kuvvetini azalt" #: res/xrc/OutfitStudio.xrc:2227 msgid "Mask Less\tA" msgstr "Maskeyi Küçült\tA" #: res/xrc/OutfitStudio.xrc:2228 msgid "Mask Less" msgstr "Maskeyi Küçült" #: res/xrc/OutfitStudio.xrc:2231 msgid "Mask More\tD" msgstr "Maske Daha Fazla\tD" #: res/xrc/OutfitStudio.xrc:2232 msgid "Mask More" msgstr "Maske Daha Fazlası" #: res/xrc/OutfitStudio.xrc:2236 msgid "Invert Mask\tCtrl+I" msgstr "Maskeyi Ters Çevir\tCtrl+I" #: res/xrc/OutfitStudio.xrc:2237 msgid "Invert Mask" msgstr "Maskeyi Ters Çevir" #: res/xrc/OutfitStudio.xrc:2240 msgid "Clear Mask\tCtrl+A" msgstr "Maskeyi Temizle\tCtrl+A" #: res/xrc/OutfitStudio.xrc:2241 msgid "Clear Mask" msgstr "Maskeyi Temizle" #: res/xrc/OutfitStudio.xrc:2245 msgid "View" msgstr "Gösterim" #: res/xrc/OutfitStudio.xrc:2247 msgid "Front\tShift+1" msgstr "Önden Görünüm\tShift+1" #: res/xrc/OutfitStudio.xrc:2250 msgid "Back\tShift+2" msgstr "Arkadan Görünüm\tShift+2" #: res/xrc/OutfitStudio.xrc:2253 msgid "Left\tShift+3" msgstr "Soldan Görünüm\tShift+3" #: res/xrc/OutfitStudio.xrc:2256 msgid "Right\tShift+4" msgstr "Sağdan Görünüm\tShift+4" #: res/xrc/OutfitStudio.xrc:2259 msgid "Perspective\tShift+5" msgstr "Derin Görünüm\tShift+5" #: res/xrc/OutfitStudio.xrc:2264 msgid "Toggle Rotation Center\tShift+R" msgstr "Döndürme Komutu\tShift+R" #: res/xrc/OutfitStudio.xrc:2265 msgid "Switch between the different rotation center modes." msgstr "Farklı dönüş merkezleri arasında geçiş yap." #: res/xrc/OutfitStudio.xrc:2268 msgid "Show Nodes\tShift+N" msgstr "Düğümleri Göster\tShift+N" #: res/xrc/OutfitStudio.xrc:2272 msgid "Show Bones\tShift+B" msgstr "İskeletleri Göster\tShift+B" #: res/xrc/OutfitStudio.xrc:2276 msgid "Show Floor\tG" msgstr "Zemini Göster\tG" #: res/xrc/OutfitStudio.xrc:2281 msgid "Toggle Visibility\tE" msgstr "Hayalet Modunda\tE" #: res/xrc/OutfitStudio.xrc:2282 msgid "Switch between the different visibility modes for the selected shapes." msgstr "Kalıplar için farklı görünürlülük seçenekleri arasında geçiş yap." #: res/xrc/OutfitStudio.xrc:2285 msgid "Show Wireframe\tW" msgstr "Tel Çerçeveyi Göster\tW" #: res/xrc/OutfitStudio.xrc:2286 msgid "Show wireframe on all models." msgstr "Tüm modelleri tel bir kafes içerisinde gösterir." #: res/xrc/OutfitStudio.xrc:2290 msgid "Enable Lighting\tL" msgstr "Aydınlatma Açık\tL" #: res/xrc/OutfitStudio.xrc:2291 msgid "Turn on or off lighting." msgstr "Aydınlatmayı açar ve kapatır." #: res/xrc/OutfitStudio.xrc:2296 msgid "Enable Textures\tT" msgstr "Dokuları Etkinleştir\tT" #: res/xrc/OutfitStudio.xrc:2297 msgid "Display texture maps on models." msgstr "Tüm modellerin doku (texture) haritalarını gösterir." #: res/xrc/OutfitStudio.xrc:2302 msgid "Enable Vertex Colors" msgstr "Köşe Renklerini Etkinleştir" #: res/xrc/OutfitStudio.xrc:2303 msgid "Display vertex colors on models." msgstr "Modellemelerde köşe renklerini görüntüle." #: res/xrc/OutfitStudio.xrc:2420 msgid "Check For Bad Bones" msgstr "Hatalı İskeletleri Tara" #: res/xrc/OutfitStudio.xrc:2454 msgid "Bad Bone" msgstr "Hatalı İskelet" #: res/xrc/OutfitStudio.xrc:2456 msgid "Set Skin Transform From Node" msgstr "Düğümden Dış Görünümü Ayarla" #: res/xrc/OutfitStudio.xrc:2457 msgid "Fixes the bad bone by calculating a new skin-to-bone transform." msgstr "" "Yeni bir deri kaplaması ile iskelet dönüşümünü hesaplayarak bozuk iskeleti " "düzeltir." #: res/xrc/OutfitStudio.xrc:2460 msgid "Set Node Transform From Skin" msgstr "Düğüm Dönüşümü İçin Deri Kaplama" #: res/xrc/OutfitStudio.xrc:2461 msgid "" "Fixes the bad custom bone by calculating a new bone-to-global transform." msgstr "" "Yeni bir iskeletten küresel dönüşümü hesaplayarak hatalı iskeleti düzeltir." #: res/xrc/OutfitStudio.xrc:2465 res/xrc/OutfitStudio.xrc:2498 #: res/xrc/ShapeProperties.xrc:263 res/xrc/ShapeProperties.xrc:421 #: res/xrc/ShapeProperties.xrc:590 msgid "Add" msgstr "Yükle" #: res/xrc/OutfitStudio.xrc:2467 res/xrc/OutfitStudio.xrc:2500 msgid "From Skeleton..." msgstr "İskelet Yapısı Hakkında..." #: res/xrc/OutfitStudio.xrc:2468 res/xrc/OutfitStudio.xrc:2501 msgid "Choose a bone from the reference skeleton to add to the project." msgstr "Projeye eklemek için örnek iskeletten bir kemik yapısını seç." #: res/xrc/OutfitStudio.xrc:2471 res/xrc/OutfitStudio.xrc:2504 msgid "Custom Bone..." msgstr "Kemik Yapısı Hakkında..." #: res/xrc/OutfitStudio.xrc:2472 res/xrc/OutfitStudio.xrc:2505 msgid "Add a custom bone to the project." msgstr "Projene bir kemik yapısı ekle." #: res/xrc/OutfitStudio.xrc:2478 msgid "From Project" msgstr "Proje Hakkında" #: res/xrc/OutfitStudio.xrc:2479 msgid "Delete bone(s) from all shapes of the project." msgstr "Kemik (iskelet yapısını) ve projenin tüm kalıplarını Sil." #: res/xrc/OutfitStudio.xrc:2482 msgid "From Selected Shapes" msgstr "Seçilen Kalıplar Hakkında" #: res/xrc/OutfitStudio.xrc:2483 msgid "Delete bone(s) from only the selected shapes." msgstr "Kemik (iskelet yapısını) ve projede uyguladığın bu kalıbı Sil." #: res/xrc/OutfitStudio.xrc:2487 msgid "Edit Bone..." msgstr "İskeleti Düzenle..." #: res/xrc/OutfitStudio.xrc:2488 msgid "Edit a custom bone or view a standard bone." msgstr "" "Özel bir kemik yapısını düzenleyin veya standart bir kemik yapısını " "görüntüleyin." #: res/xrc/OutfitStudio.xrc:2492 msgid "Masks vertices with weights for the selected bones." msgstr "Köşeleri seçilen kemikler için ağırlık değerlerini maskeler." #: res/xrc/OutfitStudio.xrc:2512 res/xrc/OutfitStudio.xrc:2538 msgid "Add Segment..." msgstr "Bölümsel Ekleme..." #: res/xrc/OutfitStudio.xrc:2513 res/xrc/OutfitStudio.xrc:2539 msgid "Choose a segment to add to the shape." msgstr "Kalıba eklemek için iskeletin bir bölümünü seç." #: res/xrc/OutfitStudio.xrc:2516 res/xrc/OutfitStudio.xrc:2527 msgid "Add Sub Segment..." msgstr "Alt Bölüm Eklemesi..." #: res/xrc/OutfitStudio.xrc:2517 res/xrc/OutfitStudio.xrc:2528 msgid "Add a new sub segment to the currently selected segment." msgstr "Kalıba eklemek için iskeletin alt katmanını seç." #: res/xrc/OutfitStudio.xrc:2520 msgid "Delete Segment..." msgstr "Ana Bölümü Sil..." #: res/xrc/OutfitStudio.xrc:2521 msgid "Delete segment and all of its sub segments from the shape." msgstr "Bölümleri ve tüm alt segmentlerini kalıptan sil." #: res/xrc/OutfitStudio.xrc:2525 msgid "Sub Segments" msgstr "Alt Bölümler" #: res/xrc/OutfitStudio.xrc:2531 msgid "Delete Sub Segment..." msgstr "Alt Bölümleri Sil..." #: res/xrc/OutfitStudio.xrc:2532 msgid "Delete the selected sub segment." msgstr "Seçili tüm alt bölümleri sil." #: res/xrc/OutfitStudio.xrc:2545 res/xrc/OutfitStudio.xrc:2556 msgid "Add Partition..." msgstr "Bölüm Ekle..." #: res/xrc/OutfitStudio.xrc:2546 res/xrc/OutfitStudio.xrc:2557 msgid "Adds a new partition to the shape." msgstr "Kalıba yeni bir bölüm ekler." #: res/xrc/OutfitStudio.xrc:2549 msgid "Delete Partition..." msgstr "Bölümü Sil..." #: res/xrc/OutfitStudio.xrc:2550 msgid "Deletes the partition from the shape." msgstr "Kalıba eklenen yeni bölümü siler." #: res/xrc/Project.xrc:16 msgid "" "Welcome to the New Project wizard!\n" "\n" "First, please choose a reference. Typically, this is a body (such as CBBE) " "or a conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "Yeni Proje Sihirbazına hoş geldin!\n" "\n" "Öncelikle, bir örnekten seçimini yapmalısın. Tipik olarak, bu bir beden " "olabilir (CBBE gibi) veya bir dönüştürme seti olabilir (Vanilla'dan " "CBBE'ye) gibi, ve onlar kalıpları ile birlikte açılır." #: res/xrc/Project.xrc:32 res/xrc/Project.xrc:578 msgid "Reference" msgstr "Örnekler" #: res/xrc/Project.xrc:50 res/xrc/Project.xrc:596 msgid "From Template" msgstr "Şablondan" #: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272 #: res/xrc/Project.xrc:615 res/xrc/Project.xrc:826 res/xrc/Project.xrc:898 msgid "From File" msgstr "Dosyadan" #: res/xrc/Project.xrc:79 res/xrc/Project.xrc:625 msgid "Select a project or NIF file" msgstr "Çalışmak için Bir NIF dosyası seç" #: res/xrc/Project.xrc:106 res/xrc/Project.xrc:652 msgid "Slider Set:" msgstr "Kaydırıcı Seti:" #: res/xrc/Project.xrc:124 res/xrc/Project.xrc:670 msgid "Shape:" msgstr "Kalıp:" #: res/xrc/Project.xrc:146 res/xrc/Project.xrc:692 msgid "Clear Reference" msgstr "Örneği Temizle" #: res/xrc/Project.xrc:162 msgid "Next, select an outfit/mesh to work on and enter a display name for it." msgstr "" "Sonrasında, çalışmak için bir kıyafeti/kafesi seç ve bunun için yeni bir " "isim gir." #: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:793 msgid "Display Name" msgstr "İsmi Görüntüle" #: res/xrc/Project.xrc:197 res/xrc/Project.xrc:813 msgid "Outfit/Mesh" msgstr "Kıyafet/Kafes" #: res/xrc/Project.xrc:220 res/xrc/Project.xrc:836 msgid "Select a file to load as an outfit/mesh" msgstr "Bir kıyafeti/kafesi (meshes dosyaları) yüklemek için bir dosyadan seç" #: res/xrc/Project.xrc:232 res/xrc/Project.xrc:848 msgid "Clear Outfit" msgstr "Kıyafeti Temizle" #: res/xrc/Project.xrc:250 res/xrc/Project.xrc:876 msgid "Textures" msgstr "Dokular" #: res/xrc/Project.xrc:257 res/xrc/Project.xrc:883 msgid "Automatically search for textures" msgstr "Otomatik olarak Doku ara" #: res/xrc/Project.xrc:282 res/xrc/Project.xrc:908 msgid "Select a texture file" msgstr "Doku dosyasını seç" #: res/xrc/Project.xrc:297 msgid "Save Project As..." msgstr "Projeyi Farklı Kaydet..." #: res/xrc/Project.xrc:328 msgid "The name of the outfit and slider set, as it will appear in BodySlide." msgstr "BodySlide menülerinde görünecek şekilde kıyafet ve beden adını gir." #: res/xrc/Project.xrc:337 msgid "Copies the current display name to the project text fields below." msgstr "Geçerli olan adı aşağıdaki proje metin alanlarına kopyalar." #: res/xrc/Project.xrc:338 msgid "To Project" msgstr "Proje İçin" #: res/xrc/Project.xrc:354 msgid "Output File Name" msgstr "Dosya Çıkış Adı" #: res/xrc/Project.xrc:363 msgid "" "The name of the outfit file that will end up in the game data path when " "BodySlide builds it. Should not include _1 or _0 in the name, e.g: " "lovelydress" msgstr "" "BodySlide onu oluşturduğunda oyun veri yolunda kopyalanacak olan kıyafet " "dosyasının adı. Adında _1 veya _0 bulunmamalıdır, örn. sevgigeceliği" #: res/xrc/Project.xrc:389 msgid "Output Data Path" msgstr "Çıkış Veri Yolu" #: res/xrc/Project.xrc:398 msgid "" "The location in the game's data path where BodySlide-built outfit files will " "be placed, e.g: meshes\\clothes\\lovelydress" msgstr "" "BodySlide tarafından oluşturulan kıyafet dosyalarının yerleştirileceği " "oyunun veri klasörü konumu, örn .: meshes\\clothes\\sevgigeceliği" #: res/xrc/Project.xrc:410 msgid "" "If this is enabled, BodySlide creates a low and high weight model when it " "generates the final outfit." msgstr "" "Bu etkinleştirilirse, BodySlide son kıyafeti oluşturduğunda düşük ve yüksek " "ağırlıkta oluşuna göre bir örnek modeli oluşturur." #: res/xrc/Project.xrc:411 msgid "Low/High Weight Output" msgstr "Düşük/Yüksek Ağırlık Çıkışı" #: res/xrc/Project.xrc:419 msgid "" "If this is enabled, only one output file will be created (useful for single-" "weighted things like hair)." msgstr "" "Bu etkinleştirilirse, yalnızca bir çıktı dosyası oluşturulur (saç ve kaş " "gibi tekil ağırlıklı şeyler için yararlıdır)." #: res/xrc/Project.xrc:420 msgid "Single Weight Output" msgstr "Tekil Ağırlık Çıkışı" #: res/xrc/Project.xrc:431 msgid "Project" msgstr "Proje" #: res/xrc/Project.xrc:443 msgid "Slider Set File" msgstr "Kaydırıcı Ayar Dosyası" #: res/xrc/Project.xrc:453 msgid "The .osp slider set project file" msgstr ".osp slider (kaydırıcı) ayarlanmış proje dosyası" #: res/xrc/Project.xrc:454 msgid "Select slider set .osp file name" msgstr "Kaydırıcı .osp dosyası adını Seç" #: res/xrc/Project.xrc:472 msgid "Shape Data Folder" msgstr "Kalıp Veri Klasörü" #: res/xrc/Project.xrc:482 msgid "" "The folder where all the slider data will go, as well as the base outfit NIF " "file." msgstr "" "Tüm kaydırıcı verilerinin yanı sıra temel donanım olan NIF dosyasının da yer " "alacağı klasör." #: res/xrc/Project.xrc:483 msgid "Select slider data folder" msgstr "Kaydırıcı veri klasörünü seç" #: res/xrc/Project.xrc:500 msgid "Shape Data File" msgstr "Kalıp Veri Dosyası" #: res/xrc/Project.xrc:510 msgid "The name of the output's base NIF file." msgstr "Oluşturulan temel NIF dosyasının adı." #: res/xrc/Project.xrc:511 msgid "Select output NIF file name" msgstr "Oluşturulan NIF dosyası adını Seç" #: res/xrc/Project.xrc:523 msgid "" "Outfits require the reference body to be a part of the output file. Disable " "this if you've already copied the reference over or you don't want it " "included." msgstr "" "Kıyafetler örnek gövdenin çıktı dosyasının bir parçası olmasını gerektirir. " "Örneği daha önce kopyaladıysan veya verilerini içermesini istemiyorsan bunu " "devre dışı bırak." #: res/xrc/Project.xrc:524 msgid "Copy reference shape into output" msgstr "Örnek kalıbı çıktıya kopyala" #: res/xrc/Project.xrc:543 res/xrc/SavePreset.xrc:78 msgid "&Save" msgstr "&Kaydet" #: res/xrc/Project.xrc:559 msgid "Load Reference" msgstr "Örnekten Yükle" #: res/xrc/Project.xrc:568 msgid "" "Please choose a reference. Typically, this is a body (such as CBBE) or a " "conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "Lütfen öncelikle, bir örnekten seçimini yap. Genellikle, bu bir beden " "olabilir (CBBE gibi) veya bir dönüştürme seti olabilir (Vanilla'dan " "CBBE'ye) gibi, ve onlar kalıpları ile birlikte açılırlar." #: res/xrc/Project.xrc:704 msgid "Merge" msgstr "Birleşik" #: res/xrc/Project.xrc:721 msgid "Zaps" msgstr "Zap'lar" #: res/xrc/Project.xrc:722 msgid "Merge existing zaps with new sliders" msgstr "Mevcut zapları yeni kaydırıcılarla birleştir" #: res/xrc/Project.xrc:732 msgid "Merge new sliders with existing sliders" msgstr "Yeni kaydırıcıları mevcut kalıplarla birleştir" #: res/xrc/Project.xrc:769 msgid "Load Outfit" msgstr "Kıyafeti Yükle" #: res/xrc/Project.xrc:778 msgid "" "Please select an outfit/mesh to work on and enter a display name for it." msgstr "" "Lütfen üzerinde çalışmak için bir kıyafet/kafes örgüsünü seç ve yeni bir " "isim ataması yap." #: res/xrc/Project.xrc:857 msgid "Keep other shapes" msgstr "Diğer Kalıpları Koru" #: res/xrc/Project.xrc:981 msgid "Group file (optional):" msgstr "Grup dosyası (isteğe bağlı):" #: res/xrc/Project.xrc:990 msgid "Group file to pack (optional)." msgstr "Grup paket dosyası (isteğe bağlı)." #: res/xrc/Project.xrc:1007 msgid "Merged file name:" msgstr "Birleştirilmiş dosya adı:" #: res/xrc/Project.xrc:1015 msgid "File name to use for the merged project file." msgstr "Birleştirilmiş proje dosyası için kullanılacak dosya ismidir." #: res/xrc/Project.xrc:1041 msgid "Pack Folder..." msgstr "Dosyaları Paketle..." #: res/xrc/Project.xrc:1050 msgid "Pack Archive..." msgstr "Arşivleri Paketle..." #: res/xrc/Project.xrc:1067 src/program/OutfitStudio.cpp:3728 #: src/program/OutfitStudio.cpp:6362 src/program/OutfitStudio.cpp:7222 #: src/program/OutfitStudio.cpp:7333 src/program/OutfitStudio.cpp:10632 msgid "Cancel" msgstr "İptal" #: res/xrc/SavePreset.xrc:6 msgid "Enter preset name..." msgstr "Hazır Ayarlardan seç..." #: res/xrc/SavePreset.xrc:15 msgid "Please enter a name for the new preset:" msgstr "Lütfen yeni hazır ayar için bir isim yaz:" #: res/xrc/SavePreset.xrc:38 msgid "Select groups to assign to the new preset:" msgstr "Yeni hazır ayarı atayacağın grupları seç:" #: res/xrc/Settings.xrc:15 msgid "Game" msgstr "Oyun" #: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:5128 msgid "Target Game" msgstr "Hedef Oyun" #: res/xrc/Settings.xrc:37 msgid "Choose the target game you want to use the program for here." msgstr "Programı kullanmak istediğin hedef oyununu seç." #: res/xrc/Settings.xrc:66 msgid "Game Data Path" msgstr "Oyun Veri Yolu" #: res/xrc/Settings.xrc:76 msgid "Select the data path of the game..." msgstr "Oyunun yüklü olduğu klasör konumunu seç..." #: res/xrc/Settings.xrc:78 msgid "Data path to load textures from." msgstr "Doku (textures) dosyalarından yüklemek ve oluşturmak için veri yolu." #: res/xrc/Settings.xrc:90 msgid "Advanced" msgstr "Gelişmiş Seçenekler" #: res/xrc/Settings.xrc:107 msgid "Output Path" msgstr "Çıkış Veri Yolu" #: res/xrc/Settings.xrc:117 msgid "Select the output path..." msgstr "Oyunun çıktı klasörü konumunu seç..." #: res/xrc/Settings.xrc:119 msgid "" "Data path to build files to. If empty, Game Data Path will be used instead." msgstr "" "Dosyaların oluşturulacağı veri klasörü. Eğer seçenek boş olarak " "işaretlenirse, bunun yerine orijinal Oyun Veri Yolu kullanılacak." #: res/xrc/Settings.xrc:136 msgid "Project Path" msgstr "Proje Klasörü" #: res/xrc/Settings.xrc:146 msgid "Select the project path..." msgstr "Projeler için klasör yolunu seç..." #: res/xrc/Settings.xrc:148 msgid "" "Project path where files related to BodySlide are loaded from. If empty, " "executable directory will be used instead." msgstr "" "BodySlide ile ilgili dosyaların yüklendiği proje klasörüdür. Boşsa, bunun " "yerine yürütülebilir dizin kullanılacaktır." #: res/xrc/Settings.xrc:164 msgid "" "With this turned on, BodySlide receives a new checkbox \"Force Body Normals" "\". Using it when building adds normal and tangent data to the body meshes " "(including bodies within outfits) for Skyrim. Use this only if you have a " "tangent space body mod." msgstr "" "Bu etkinleştirildiğinde, BodySlide yeni bir \"Force Body Normals\" Normal " "Beden Yapısı için onay kutusu alır. İnşa ederken kullanmak, Skyrim için " "gövde ağlarına (kıyafetlerdeki gövdeler dahil) normal ve yan verileri ekler. " "Bunu yalnızca ikincil bir beden modunuz varsa kullanın." #: res/xrc/Settings.xrc:165 msgid "Show 'Force Body Normals'" msgstr "Göster 'Normal Beden Yapısı'" #: res/xrc/Settings.xrc:183 msgid "General" msgstr "Genel" #: res/xrc/Settings.xrc:195 msgid "" "Enables/disables the dialog for choosing which set to build during a batch " "build if overrides happen." msgstr "" "Geçersiz kılma gerçekleştiğinde hangi setin oluşturulacağını seçmek için " "iletişim kutusunu etkinleştirir/devre dışı bırakır." #: res/xrc/Settings.xrc:196 msgid "Override Warning" msgstr "Uyarıları Geçersiz Kıl" #: res/xrc/Settings.xrc:205 msgid "" "Enables/disables scanning BSAs in the game data folder for textures to load." msgstr "" "Yüklenecek dokular için oyun veri klasöründeki BSA dosyalarını taramayı " "etkinleştirir/devre dışı bırakır." #: res/xrc/Settings.xrc:206 msgid "BSA Textures" msgstr "BSA Doku Dosyaları" #: res/xrc/Settings.xrc:223 msgid "" "Enables/disables panning the camera with the left mouse button in Outfit " "Studio." msgstr "" "Outfit Studio'da kamerayı farenin sol tuşuyla çevirmeyi etkinleştirir/devre " "dışı bırakır." #: res/xrc/Settings.xrc:224 msgid "Left Mouse Pan" msgstr "Sol Fare Tuşu" #: res/xrc/Settings.xrc:233 msgid "" "Enables/disables opening the brush settings near the mouse cursor when " "hitting the 'space' key." msgstr "" "'Boşluk-Space' tuşuna basıldığında fare imlecinin yanında fırça ayarlarının " "açılmasını etkinleştirir/devre dışı bırakır." #: res/xrc/Settings.xrc:234 msgid "Brush Settings Near Cursor" msgstr "İmleç Yakınında Fırça Ayarları" #: res/xrc/Settings.xrc:252 msgid "Language" msgstr "Dil Seçimi" #: res/xrc/Settings.xrc:261 msgid "Use the selected language for the program." msgstr "" "Programı Türkçe olarak kullanabilmek için dil ayarlarından Türkçe'yi seç.." #: res/xrc/Settings.xrc:276 msgid "Rendering" msgstr "Kaplamalar" #: res/xrc/Settings.xrc:289 msgid "Background Color" msgstr "Arkaplan Rengi" #: res/xrc/Settings.xrc:298 msgid "Background color of the renderer." msgstr "Arkaplan rengini düzenler." #: res/xrc/Settings.xrc:316 msgid "Wireframe Color" msgstr "Tel Kafesi Rengi" #: res/xrc/Settings.xrc:325 msgid "Wireframe color of the renderer." msgstr "Oluşturulan yeni tel kafesi için renk belirle." #: res/xrc/Settings.xrc:340 msgid "Data Files" msgstr "Veri Dosyaları" #: res/xrc/Settings.xrc:358 msgid "Reference Skeleton" msgstr "Örnek İskelet" #: res/xrc/Settings.xrc:381 msgid "Select a reference skeleton .nif file..." msgstr "Referans-Örnek iskeleti için .nif dosyasını seç..." #: res/xrc/Settings.xrc:384 msgid "The reference skeleton file for Outfit Studio." msgstr "Outfit Studio için referans iskelet dosyası." #: res/xrc/Settings.xrc:401 msgid "Root Node" msgstr "Temel Kodlama" #: res/xrc/Settings.xrc:410 msgid "" "The root node name of the reference skeleton. Can differ from game to game." msgstr "" "Referans iskeletin temel kod adı. Oyundan oyuna farklılık gösterebilir." #: res/xrc/Setup.xrc:5 msgid "Setup" msgstr "Kurulum" #: res/xrc/Setup.xrc:15 msgid "" "Please select the data folder and your target game.\n" "You can only choose one game at a time, but it is possible to change the " "selection in the settings." msgstr "" "Lütfen data-veri klasörünü ve hedef oyununu seç.\n" "Tek seferde yalnızca bir oyun seçebilirsin, ancak oyun seçimini ayar " "menüsünden değiştirmek mümkündür." #: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102 #: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189 #: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247 msgid "Game not found! Select the data folder manually..." msgstr "" "Oyun bulunamadı! Oyunun Data-Veri klasör dizinini kendin belirtmelisin..." #: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103 #: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190 #: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248 msgid "Select a folder" msgstr "Klasör Konumunu Seç" #: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113 #: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200 #: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258 msgid "Choose Game" msgstr "Oyun Seç" #: res/xrc/ShapeProperties.xrc:5 msgid "Shape Properties" msgstr "Kalıp Özellikleri" #: res/xrc/ShapeProperties.xrc:16 msgid "Shader" msgstr "Ön Bellek" #: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:608 #: res/xrc/Skeleton.xrc:68 msgid "Name" msgstr "İsim" #: res/xrc/ShapeProperties.xrc:102 msgid "Specular Color" msgstr "Yansıtıcı Renk" #: res/xrc/ShapeProperties.xrc:120 msgid "Specular Strength" msgstr "Yansıtıcı Kuvvet" #: res/xrc/ShapeProperties.xrc:139 msgid "Specular Power" msgstr "Yansıtıcı Güç" #: res/xrc/ShapeProperties.xrc:179 msgid "Emissive Color" msgstr "Yayıcı Renk" #: res/xrc/ShapeProperties.xrc:197 msgid "Emissive Multiple" msgstr "Yayıcı Katman" #: res/xrc/ShapeProperties.xrc:216 msgid "Alpha" msgstr "Alfa" #: res/xrc/ShapeProperties.xrc:235 msgid "Vertex Colors" msgstr "Uç Renkler" #: res/xrc/ShapeProperties.xrc:272 res/xrc/ShapeProperties.xrc:430 msgid "Remove" msgstr "Sil" #: res/xrc/ShapeProperties.xrc:281 msgid "Textures..." msgstr "Dokular..." #: res/xrc/ShapeProperties.xrc:293 msgid "Transparency" msgstr "Şeffaflık" #: res/xrc/ShapeProperties.xrc:316 msgid "Threshold" msgstr "Eşik Değeri" #: res/xrc/ShapeProperties.xrc:356 msgid "Vertex Alpha" msgstr "Uç Alfa" #: res/xrc/ShapeProperties.xrc:374 msgid "Alpha Test" msgstr "Alfa Testi" #: res/xrc/ShapeProperties.xrc:392 msgid "Alpha Blend" msgstr "Alfa Karışımı" #: res/xrc/ShapeProperties.xrc:443 msgid "Copy from shape..." msgstr "Kalıptan kopyala..." #: res/xrc/ShapeProperties.xrc:451 msgid "Geometry" msgstr "Geometri" #: res/xrc/ShapeProperties.xrc:471 msgid "Full Precision" msgstr "Tam Hassasiyet" #: res/xrc/ShapeProperties.xrc:489 msgid "Sub Index" msgstr "Alt Endeks" #: res/xrc/ShapeProperties.xrc:507 msgid "Skinned" msgstr "Deri-Cilt" #: res/xrc/ShapeProperties.xrc:524 msgid "Dynamic" msgstr "Dinamik" #: res/xrc/ShapeProperties.xrc:569 msgid "Extra Data" msgstr "Ekstra Veri" #: res/xrc/ShapeProperties.xrc:617 msgid "Value" msgstr "Değer" #: res/xrc/ShapeProperties.xrc:627 msgid "Coordinates" msgstr "Koordinat" #: res/xrc/ShapeProperties.xrc:636 msgid "Transform from shape to global coordinates:" msgstr "Kalıptan küresel koordinatlara dönüştür:" #: res/xrc/ShapeProperties.xrc:699 res/xrc/Skeleton.xrc:142 msgid "Rotation" msgstr "Dönüş Hareketleri" #: res/xrc/Skeleton.xrc:6 msgid "Select a bone to add" msgstr "Eklenecek kemik yapısını seç" #: res/xrc/Skeleton.xrc:15 msgid "Bones in the current reference skeleton:" msgstr "Örnek iskeletteki kemik yapısı:" #: res/xrc/Skeleton.xrc:53 msgid "Add Custom Bone" msgstr "Özel Kemik Yapısı Ekle" #: res/xrc/Skeleton.xrc:93 msgid "Parent" msgstr "Temel" #: res/xrc/Slider.xrc:6 msgid "Select a slider preset" msgstr "Bir kaydırıcı hazır ayar seç" #: res/xrc/Slider.xrc:15 msgid "Choose a preset:" msgstr "Hazır ayarı seç:" #: res/xrc/Slider.xrc:40 msgid "Low weight" msgstr "Düsük ağırlık" #: res/xrc/Slider.xrc:49 msgid "High weight" msgstr "Yüksek ağırlık" #: res/xrc/Slider.xrc:81 msgid "Slider Properties" msgstr "Kaydırıcı Özellikleri" #: res/xrc/Slider.xrc:91 msgid "Slider Name" msgstr "Kaydırıcı Adı" #: res/xrc/Slider.xrc:108 msgid "Default Values" msgstr "Varsayılan Değerler" #: res/xrc/Slider.xrc:114 msgid "Low" msgstr "Düsük" #: res/xrc/Slider.xrc:131 msgid "High" msgstr "Yüksek" #: res/xrc/Slider.xrc:148 msgid "Zapped" msgstr "Komuta Et" #: res/xrc/Slider.xrc:173 msgid "Invert" msgstr "Ters Çevir" #: res/xrc/Slider.xrc:182 msgid "Hidden" msgstr "Gizli" #: res/xrc/Slider.xrc:191 msgid "Zap" msgstr "Zap" #: res/xrc/Slider.xrc:211 msgid "Toggle Zaps:" msgstr "Aç/Kapa Zap:" #: res/xrc/SliderDataImport.xrc:6 msgid "Slider Data Import Options..." msgstr "Kaydırıcı Veri İçe Aktarma Seçenekleri..." #: res/xrc/SliderDataImport.xrc:21 msgid "Select the shapes that slider data will be imported for:" msgstr "Kaydırıcı verilerin içe aktarılacağı kalıpları seç:" #: res/xrc/SliderDataImport.xrc:52 msgid "Select the sliders to be imported" msgstr "İçe aktarılacak kaydırıcıları seç" #: src/components/Anim.cpp:570 msgid "" "Bone information incomplete. Exported data will not contain correct bone " "entries! Be sure to load a reference NIF prior to export." msgstr "" "Kemik yapısı bilgisi eksik. Dışa aktarılan veriler doğru kemik girişlerini " "içermeyecektir! Kaydetmeden önce örnek bir NIF dosyasını yüklediğinden emin " "olmalısın." #: src/components/Anim.cpp:571 msgid "Export Warning" msgstr "Dışa Aktarma Tehlikesi" #: src/components/Anim.cpp:689 #, c-format msgid "Failed to load skeleton '%s'!" msgstr "İskelet yüklemesi başarısız '%s'!" #: src/components/Anim.cpp:697 #, c-format msgid "Root '%s' not found in skeleton '%s'!" msgstr "Temel '%s' iskelet bulunamadı '%s'!" #: src/program/BodySlideApp.cpp:184 src/program/OutfitStudio.cpp:417 msgid "" "No read/write permission for game data path!\n" "\n" "Please launch the program with admin elevation and make sure the game data " "path in the settings is correct." msgstr "" "Oyun veri yolu için okuma/yazma izni yok!\n" "\n" "Lütfen programı yönetici modunda yeniden başlatın ve ayarlardaki oyun veri " "yolunun doğru olduğundan emin olun." #: src/program/BodySlideApp.cpp:185 src/program/BodySlideApp.cpp:195 #: src/program/BodySlideApp.cpp:1436 src/program/OutfitStudio.cpp:418 #: src/program/OutfitStudio.cpp:428 src/program/OutfitStudio.cpp:652 #: src/program/OutfitStudio.cpp:659 msgid "Warning" msgstr "Uyarı" #: src/program/BodySlideApp.cpp:194 src/program/OutfitStudio.cpp:427 msgid "" "No read/write permission for project path!\n" "\n" "Please launch the program with admin elevation and make sure the project " "path in the settings is correct." msgstr "" "Oyun veri yolu için okuma/yazma izni yok!\n" "\n" "Lütfen programı yönetici modunda yeniden başlatın ve ayarlardaki oyun veri " "yolunun doğru olduğundan emin olun." #: src/program/BodySlideApp.cpp:267 src/program/OutfitStudio.cpp:514 #, c-format msgid "Unexpected exception has occurred: %s, the program will terminate." msgstr "Beklenmeyen bir hata oluştu: %s, program kapatılacak." #: src/program/BodySlideApp.cpp:267 src/program/OutfitStudio.cpp:514 msgid "Unexpected exception" msgstr "Beklenmeyen Hata" #: src/program/BodySlideApp.cpp:290 src/program/OutfitStudio.cpp:534 #, c-format msgid "Unhandled exception has occurred: %s, the program will terminate." msgstr "İşlenmeyen özel durum oluştu: %s, program kapatılacak." #: src/program/BodySlideApp.cpp:290 src/program/OutfitStudio.cpp:534 msgid "Unhandled exception" msgstr "İşlenme Hatası" #: src/program/BodySlideApp.cpp:301 src/program/OutfitStudio.cpp:542 msgid "Fatal exception has occurred, the program will terminate." msgstr "Tehlikeli bir hata oluştu, program kapatılacak." #: src/program/BodySlideApp.cpp:301 src/program/OutfitStudio.cpp:542 msgid "Fatal exception" msgstr "Tehlikeli Hata" #: src/program/BodySlideApp.cpp:923 msgid "Failed to launch Outfit Studio executable!" msgstr "Outfit Studio yürütülebilir sürümü başlatılamadı!" #: src/program/BodySlideApp.cpp:923 src/program/BodySlideApp.cpp:1457 #: src/program/BodySlideApp.cpp:1751 src/program/BodySlideApp.cpp:2813 #: src/program/BodySlideApp.cpp:2820 src/program/BodySlideApp.cpp:3554 #: src/program/OutfitStudio.cpp:975 src/program/OutfitStudio.cpp:981 #: src/program/OutfitStudio.cpp:1473 src/program/OutfitStudio.cpp:1484 #: src/program/OutfitStudio.cpp:1520 src/program/OutfitStudio.cpp:1531 #: src/program/OutfitStudio.cpp:1541 src/program/OutfitStudio.cpp:1550 #: src/program/OutfitStudio.cpp:1561 src/program/OutfitStudio.cpp:1572 #: src/program/OutfitStudio.cpp:1584 src/program/OutfitStudio.cpp:1623 #: src/program/OutfitStudio.cpp:1631 src/program/OutfitStudio.cpp:1638 #: src/program/OutfitStudio.cpp:1674 src/program/OutfitStudio.cpp:1682 #: src/program/OutfitStudio.cpp:1689 src/program/OutfitStudio.cpp:1699 #: src/program/OutfitStudio.cpp:1708 src/program/OutfitStudio.cpp:1716 #: src/program/OutfitStudio.cpp:1723 src/program/OutfitStudio.cpp:1734 #: src/program/OutfitStudio.cpp:1743 src/program/OutfitStudio.cpp:1750 #: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2044 #: src/program/OutfitStudio.cpp:2059 src/program/OutfitStudio.cpp:2144 #: src/program/OutfitStudio.cpp:2153 src/program/OutfitStudio.cpp:2161 #: src/program/OutfitStudio.cpp:2175 src/program/OutfitStudio.cpp:2184 #: src/program/OutfitStudio.cpp:2190 src/program/OutfitStudio.cpp:2222 #: src/program/OutfitStudio.cpp:3627 src/program/OutfitStudio.cpp:3634 #: src/program/OutfitStudio.cpp:4281 src/program/OutfitStudio.cpp:4300 #: src/program/OutfitStudio.cpp:4366 src/program/OutfitStudio.cpp:4402 #: src/program/OutfitStudio.cpp:4421 src/program/OutfitStudio.cpp:4491 #: src/program/OutfitStudio.cpp:4527 src/program/OutfitStudio.cpp:4546 #: src/program/OutfitStudio.cpp:4571 src/program/OutfitStudio.cpp:4622 #: src/program/OutfitStudio.cpp:4627 src/program/OutfitStudio.cpp:4641 #: src/program/OutfitStudio.cpp:4648 src/program/OutfitStudio.cpp:4653 #: src/program/OutfitStudio.cpp:4664 src/program/OutfitStudio.cpp:7033 #: src/program/OutfitStudio.cpp:7091 src/program/OutfitStudio.cpp:7097 #: src/program/OutfitStudio.cpp:7101 src/program/OutfitStudio.cpp:7112 #: src/program/OutfitStudio.cpp:7122 src/program/OutfitStudio.cpp:7126 #: src/program/OutfitStudio.cpp:7143 src/program/OutfitStudio.cpp:7147 #: src/program/OutfitStudio.cpp:7158 src/program/OutfitStudio.cpp:7168 #: src/program/OutfitStudio.cpp:7181 src/program/OutfitStudio.cpp:7296 #: src/program/OutfitStudio.cpp:7309 src/program/OutfitStudio.cpp:7412 #: src/program/OutfitStudio.cpp:7416 src/program/OutfitStudio.cpp:7427 #: src/program/OutfitStudio.cpp:7437 src/program/OutfitStudio.cpp:7441 #: src/program/OutfitStudio.cpp:7464 src/program/OutfitStudio.cpp:7473 #: src/program/OutfitStudio.cpp:7477 src/program/OutfitStudio.cpp:7506 #: src/program/OutfitStudio.cpp:7510 src/program/OutfitStudio.cpp:7533 #: src/program/OutfitStudio.cpp:7542 src/program/OutfitStudio.cpp:7553 #: src/program/OutfitStudio.cpp:7560 src/program/OutfitStudio.cpp:7571 #: src/program/OutfitStudio.cpp:7578 src/program/OutfitStudio.cpp:7602 #: src/program/OutfitStudio.cpp:7653 src/program/OutfitStudio.cpp:7715 #: src/program/OutfitStudio.cpp:7719 src/program/OutfitStudio.cpp:7732 #: src/program/OutfitStudio.cpp:7736 src/program/OutfitStudio.cpp:7947 #: src/program/OutfitStudio.cpp:8114 src/program/OutfitStudio.cpp:8131 #: src/program/OutfitStudio.cpp:8151 src/program/OutfitStudio.cpp:8175 #: src/program/OutfitStudio.cpp:8209 src/program/OutfitStudio.cpp:8361 #: src/program/OutfitStudio.cpp:8550 src/program/OutfitStudio.cpp:8700 #: src/program/OutfitStudio.cpp:8755 src/program/OutfitStudio.cpp:8969 #: src/program/OutfitStudio.cpp:8979 src/program/OutfitStudio.cpp:9020 #: src/program/OutfitStudio.cpp:9025 src/program/OutfitStudio.cpp:9034 #: src/program/OutfitStudio.cpp:9056 src/program/OutfitStudio.cpp:9220 #: src/program/OutfitStudio.cpp:9228 src/program/OutfitStudio.cpp:9528 #: src/program/OutfitStudio.cpp:9533 src/program/OutfitStudio.cpp:9619 #: src/program/OutfitStudio.cpp:9624 src/program/OutfitStudio.cpp:9712 #: src/program/OutfitStudio.cpp:9718 src/program/OutfitStudio.cpp:9723 #: src/program/OutfitStudio.cpp:9730 src/program/OutfitStudio.cpp:9757 #: src/program/OutfitStudio.cpp:9798 src/program/OutfitStudio.cpp:9845 #: src/program/OutfitStudio.cpp:9850 src/program/OutfitStudio.cpp:9884 #: src/program/OutfitStudio.cpp:10096 src/program/OutfitStudio.cpp:10142 #: src/program/OutfitStudio.cpp:10245 src/program/OutfitStudio.cpp:10388 #: src/program/OutfitStudio.cpp:11741 src/program/OutfitStudio.cpp:12061 #: src/program/OutfitStudio.cpp:12098 src/program/OutfitStudio.cpp:12103 #: src/program/OutfitStudio.cpp:12115 src/program/OutfitStudio.cpp:13426 msgid "Error" msgstr "Hata" #: src/program/BodySlideApp.cpp:1436 src/program/OutfitStudio.cpp:659 msgid "" "Failed to find game install path registry key or GameDataPath in the config." msgstr "" "Yapılandırmada oyun yükleme yolu kayıt defteri anahtarı veya GameDataPath " "bulunamadı." #: src/program/BodySlideApp.cpp:1664 src/program/OutfitStudio.cpp:887 #, c-format msgid "System language '%d' is wrong." msgstr "Sistem dili '%d' yanlış." #: src/program/BodySlideApp.cpp:1673 src/program/OutfitStudio.cpp:896 #, c-format msgid "" "The system language '%d' is not supported by your system. Try installing " "support for this language." msgstr "" "Sistem dili '%d' sisteminiz tarafından desteklenmiyor. Bu dil için destek " "alarak yüklemeyi deneyin." #: src/program/BodySlideApp.cpp:1751 msgid "Failed to create group file." msgstr "Grup dosyası oluşturulamadı." #: src/program/BodySlideApp.cpp:1765 msgid "" "That group already exists in the specified file, do you wish to overwrite " "the group?" msgstr "" "Bu grup adında bir dosya zaten mevcut, grubun üzerine yazmak ister misin?" #: src/program/BodySlideApp.cpp:1765 msgid "Group already exists" msgstr "Grup zaten mevcut" #: src/program/BodySlideApp.cpp:1922 msgid "" "WARNING: Game data path not configured. Would you like to show BodySlide " "where it is?" msgstr "" "UYARI: Oyun veri yolu yapılandırılmamış. BodySlide yükleme klasörünü elle " "belirlemek ister misin?" #: src/program/BodySlideApp.cpp:1923 src/program/BodySlideApp.cpp:2224 #: src/program/BodySlideApp.cpp:2229 msgid "Game not found" msgstr "Oyun bulunamadı" #: src/program/BodySlideApp.cpp:1931 msgid "Please choose a directory to set as your Data path" msgstr "Lütfen Veri yolu olarak ayarlamak için bir klasör dizini seç" #: src/program/BodySlideApp.cpp:1949 msgid "" "WARNING: This will delete the output files from the output folder, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "UYARI: Bu, çıkış dosyalarını kopyalanan klasöründen siler, potansiyel olarak " "çökmelere neden olabilir.\n" "\n" "Devam etmek istediğine emin misin?" #: src/program/BodySlideApp.cpp:1950 msgid "Clean Build" msgstr "Kurulumu Temizle" #: src/program/BodySlideApp.cpp:1958 msgid "Removed the following files:\n" msgstr "Dosyalar siliniyor:\n" #: src/program/BodySlideApp.cpp:1970 src/program/BodySlideApp.cpp:1983 msgid " (no action)\n" msgstr " (eylem yok)\n" #: src/program/BodySlideApp.cpp:1974 src/program/BodySlideApp.cpp:1986 #: src/program/BodySlideApp.cpp:2195 msgid "Process Successful" msgstr "İşlem Başarıyla Sonuçlandı" #: src/program/BodySlideApp.cpp:2082 #, c-format msgid "" "Failed to write TRI file to the following location\n" "\n" "%s" msgstr "" "TRI dosyası belirtilen konuma yazılamadı\n" "\n" "%s" #: src/program/BodySlideApp.cpp:2082 src/program/BodySlideApp.cpp:2138 #: src/program/BodySlideApp.cpp:2173 msgid "Unable to process" msgstr "İşlenemiyor" #: src/program/BodySlideApp.cpp:2138 src/program/BodySlideApp.cpp:2173 #, c-format msgid "" "Failed to build set to the following location\n" "\n" "%s" msgstr "" "Bu ayar seti belirtilen konuma yazdırılamadı\n" "\n" "%s" #: src/program/BodySlideApp.cpp:2140 src/program/BodySlideApp.cpp:2175 msgid "Choose alternate file name" msgstr "Alternatif dosya adını seç" #: src/program/BodySlideApp.cpp:2187 msgid "Successfully processed the following files:\n" msgstr "Dosyalar başarıyla işlendi:\n" #: src/program/BodySlideApp.cpp:2209 msgid "" "WARNING: This will delete the output files from the output folders, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "UYARI: Bu, işleme dosyalarını çıkış klasörlerinden siler, potansiyele dayalı " "çökmelere neden olabilir.\n" "\n" "Devam etmek istediğine emin misin?" #: src/program/BodySlideApp.cpp:2210 msgid "Clean Batch Build" msgstr "Toplu Yapı Temizliği" #: src/program/BodySlideApp.cpp:2224 msgid "" "WARNING: Game data path not configured. Files can't be removed that way." msgstr "" "UYARI: Oyun veri yolu yapılandırılmamış. Dosyalar bu şekilde silinemez." #: src/program/BodySlideApp.cpp:2228 msgid "" "WARNING: Game data path not configured. Continue saving files to the working " "directory?" msgstr "" "UYARI: Oyun veri yolu yapılandırılmamış. Dosyaları çalışma dizinine kaydetme " "işlemine devam edilsin mi?" #: src/program/BodySlideApp.cpp:2363 msgid "Processing Outfits" msgstr "Kıyafet işlenmesi" #: src/program/BodySlideApp.cpp:2363 src/program/OutfitStudio.h:1052 msgid "Starting..." msgstr "Başlatılıyor..." #: src/program/BodySlideApp.cpp:2375 #, c-format msgid "Processing '%s' (%d of %d)..." msgstr "İşleniyor '%s' (%d of %d)..." #: src/program/BodySlideApp.cpp:2383 msgid "No recorded outfit name source" msgstr "Kayıtlı bir kıyafet adı kaynağı yok" #: src/program/BodySlideApp.cpp:2394 msgid "Unable to get slider set from file: " msgstr "Kaydırıcı dosyadan alınamadı: " #: src/program/BodySlideApp.cpp:2399 msgid "Unable to open slider set file: " msgstr "Kaydırıcı ayar dosyası açılamıyor: " #: src/program/BodySlideApp.cpp:2434 msgid "Unable to load input nif: " msgstr "Nif giriş kodlaması yüklenemedi: " #: src/program/BodySlideApp.cpp:2581 msgid "Unable to create destination directory: " msgstr "Hedef dizin oluşturulamadı: " #: src/program/BodySlideApp.cpp:2648 src/program/BodySlideApp.cpp:2656 #: src/program/BodySlideApp.cpp:2667 msgid "Unable to save nif file: " msgstr "Nif dosyası kaydedilemiyor: " #: src/program/BodySlideApp.cpp:2741 src/program/BodySlideApp.cpp:3790 msgid "The following sets failed" msgstr "Takipçi ayarları başarısız" #: src/program/BodySlideApp.cpp:2741 src/program/BodySlideApp.cpp:3790 msgid "Failed" msgstr "Başarısız" #: src/program/BodySlideApp.cpp:2813 msgid "Failed to load BodySlide.xrc file!" msgstr "Bodyslide.xrc dosyası yüklenemedi!" #: src/program/BodySlideApp.cpp:2820 msgid "Failed to load BodySlide frame!" msgstr "BodySlide ana çerçevesi yüklenemedi!" #: src/program/BodySlideApp.cpp:2853 msgid "Group Filter" msgstr "Gurup Filtresi" #: src/program/BodySlideApp.cpp:2854 msgid "Filter by group" msgstr "Gruplara göre filtrele" #: src/program/BodySlideApp.cpp:2860 msgid "Outfit Filter" msgstr "Kıyafet Filtresi" #: src/program/BodySlideApp.cpp:2861 msgid "Filter by outfit" msgstr "Kıyafetlere göre filtrele" #: src/program/BodySlideApp.cpp:3450 msgid "Choose groups to filter outfit list" msgstr "Kıyafet listesini filtrelemek için grupları seç" #: src/program/BodySlideApp.cpp:3450 msgid "Choose Groups" msgstr "Gurupları Seç" #: src/program/BodySlideApp.cpp:3469 msgid "Choose or create group file" msgstr "Grup dosyası seç veya oluştur" #: src/program/BodySlideApp.cpp:3482 msgid "What would you like the new group to be called?" msgstr "Yeni grubun da aranmasını istiyor musun?" #: src/program/BodySlideApp.cpp:3482 msgid "New Group Name" msgstr "Yeni Gurup İsmi" #: src/program/BodySlideApp.cpp:3523 msgid "Do you really wish to delete the selected project?" msgstr "Seçilen projeyi silmeyi gerçekten istiyor musun?" #: src/program/BodySlideApp.cpp:3523 msgid "Delete Project" msgstr "Projeyi Sil" #: src/program/BodySlideApp.cpp:3532 msgid "Do you really wish to delete the selected preset?" msgstr "Bu hazır ayarı silmeyi gerçekten istiyor musun?" #: src/program/BodySlideApp.cpp:3532 msgid "Delete Preset" msgstr "Hazır Ayarı Sil" #: src/program/BodySlideApp.cpp:3554 src/program/OutfitStudio.cpp:7091 #, c-format msgid "Failed to save preset (%d)!" msgstr "Hazır ayar kaydedilemedi (%d)!" #: src/program/BodySlideApp.cpp:3582 #, c-format msgid "Failed to save preset as '%s' (%d)!" msgstr "Hazır ayar olarak kaydedilemedi '%s' (%d)!" #: src/program/BodySlideApp.cpp:3765 msgid "Choose a folder to contain the saved files" msgstr "Kaydedilen dosyaların için bir klasör seç" #: src/program/BodySlideApp.cpp:3780 msgid "All sets processed successfully!" msgstr "Tüm guruplar başarıyla ayarlandı!" #: src/program/BodySlideApp.cpp:3780 msgid "Complete" msgstr "Tamamlandı" #: src/program/ConvertBodyReferenceDialog.cpp:121 msgid "Starting conversion..." msgstr "Dönüşüm başlatılıyor..." #: src/program/ConvertBodyReferenceDialog.cpp:139 msgid "Updating Project Output Settings" msgstr "Proje Çıktı Ayarları Güncelleniyor" #: src/program/ConvertBodyReferenceDialog.cpp:178 msgid "Deleting Shapes..." msgstr "Kalıplar Siliniyor..." #: src/program/ConvertBodyReferenceDialog.cpp:199 msgid "Loading conversion reference..." msgstr "Dönüşüm referansı yükleniyor..." #: src/program/ConvertBodyReferenceDialog.cpp:209 #: src/program/ConvertBodyReferenceDialog.cpp:253 msgid "Conforming outfit parts..." msgstr "Kıyafet Dönüşümleri güncelleniyor..." #: src/program/ConvertBodyReferenceDialog.cpp:216 msgid "Updating conversion Slider..." msgstr "Kaydırıcı Dönüşümleri güncelleniyor..." #: src/program/ConvertBodyReferenceDialog.cpp:220 msgid "Setting the base shape and removing the conversion reference" msgstr "Temel kalıp ayarlama ve dönüştürme referansını temizleme" #: src/program/ConvertBodyReferenceDialog.cpp:227 msgid "Skipping conversion reference..." msgstr "Dönüşüm örnekleri atlanıyor..." #: src/program/ConvertBodyReferenceDialog.cpp:232 msgid "Loading new reference..." msgstr "Yeni örnek yükleniyor..." #: src/program/ConvertBodyReferenceDialog.cpp:246 msgid "Copying bones..." msgstr "Kemikler kopyalanıyor..." #: src/program/ConvertBodyReferenceDialog.cpp:260 msgid "Adding Bones..." msgstr "Kemikler Yükleniyor..." #: src/program/ConvertBodyReferenceDialog.cpp:289 msgid "Conversion finished." msgstr "Dönüşüm tamamlandı." #: src/program/EditUV.cpp:497 src/program/OutfitStudio.cpp:10876 msgid "Outfit Studio: OpenGL context is not OK." msgstr "Outfit Studio: OpenGL içeriği mevcut değil." #: src/program/EditUV.cpp:497 src/program/OutfitStudio.cpp:10876 #: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:34 #: src/render/GLSurface.cpp:2116 src/render/GLSurface.cpp:2133 msgid "OpenGL Error" msgstr "OpenGL Hatası" #: src/program/FBXImportDialog.cpp:158 src/program/ObjImportDialog.cpp:165 #: src/program/OutfitStudio.cpp:9020 src/program/OutfitStudio.cpp:12098 msgid "The shape has reached the vertex count limit." msgstr "Bu kalıp, uç tepe sayısı sınırına ulaştı." #: src/program/FBXImportDialog.cpp:162 src/program/ObjImportDialog.cpp:169 #: src/program/OutfitStudio.cpp:9025 src/program/OutfitStudio.cpp:12103 msgid "The shape has reached the triangle count limit." msgstr "Bu kalıp, üçgensel sayı sınırına ulaştı." #: src/program/GroupManager.cpp:143 msgid "Please enter a new unique name for the group." msgstr "Lütfen grup için yeni bir isim belirle." #: src/program/GroupManager.cpp:143 msgid "Rename Group" msgstr "Grubu Yeniden Adlandır" #: src/program/GroupManager.cpp:323 msgid "Save changes to group file?" msgstr "oplu değişiklikler bir gurup dosyası adında kaydedilsin mi?" #: src/program/GroupManager.cpp:323 msgid "Save Changes" msgstr "Değişiklikleri Kaydet" #: src/program/NormalsGenDialog.cpp:90 msgid "Enter a name for the new layer." msgstr "Yeni katman için bir isim belirle." #: src/program/NormalsGenDialog.cpp:90 msgid "Name new layer" msgstr "Yeni Katman İsmi" #: src/program/NormalsGenDialog.cpp:205 msgid "Choose a normals generator preset file..." msgstr "Genel standart ayarlamalarını hazır ayar olarak seç.." #: src/program/NormalsGenDialog.cpp:222 msgid "Save normals generator preset to..." msgstr "Genel standart ayarlamalarını hazır ayar olarak kaydet..." #: src/program/NormalsGenDialog.cpp:240 msgid "Layer" msgstr "Katmanlar" #: src/program/NormalsGenDialog.cpp:263 msgid "Background File" msgstr "Arkaplan Dosyası" #: src/program/NormalsGenDialog.cpp:264 msgid "File source for this layer." msgstr "Bu katmanın dosya kaynağı." #: src/program/NormalsGenDialog.cpp:265 msgid "Color" msgstr "Renkler" #: src/program/NormalsGenDialog.cpp:266 msgid "Solid background color (if file is not set)." msgstr "Koyu arka plan rengi (eğer dosya ayarlanmamışsa)." #: src/program/NormalsGenDialog.cpp:267 msgid "Resolution" msgstr "Çözünürlük" #: src/program/NormalsGenDialog.cpp:269 msgid "" "Output texture dimensions. By default all images will be scaled to fit this " "size." msgstr "" "Doku boyutları çıktısıdır. Varsayılan olarak, tüm resimler bu boyuta uyacak " "şekilde ölçeklendirilecektir." #: src/program/NormalsGenDialog.cpp:286 msgid "" "File containing normals data to combine. Note this file should fit the mesh " "UVs." msgstr "" "Birleştirilecek normal veri dosyalarını içeren kalıp. Bu dosyaların örgü " "UV'lerine uyması gerektiğini unutmamalısın." #: src/program/NormalsGenDialog.cpp:288 msgid "Is Tangent Space?" msgstr "Teğet Uzay mı olsun?" #: src/program/NormalsGenDialog.cpp:289 msgid "" "True if the normals data in the layer file is in tangent space, false if " "they are in model space (msn)." msgstr "" "Eğer katman dosyasındaki normal değerler verisi teğet uzayda yer almıyorsa, " "model uzayda (msn) yanlış görüntülenir." #: src/program/NormalsGenDialog.cpp:292 msgid "A greyscale image used to mask updates to destination image." msgstr "" "Hedef resme güncellemeleri maskelemek için kullanılan gri tonlamalı bir " "resim." #: src/program/NormalsGenDialog.cpp:294 msgid "X Offset" msgstr "X Dengesi" #: src/program/NormalsGenDialog.cpp:295 src/program/NormalsGenDialog.cpp:298 msgid "Offset to apply to image position." msgstr "Görüntü pozisyonuna uygulamak için dengeleme." #: src/program/NormalsGenDialog.cpp:297 msgid "Y Offset" msgstr "Y Dengesi" #: src/program/NormalsGenDialog.cpp:301 msgid "If true, scale image to match background resolution." msgstr "" "Eğer bunu kabul ediyorsan, resmi arka plan çözünürlüğüne uyacak şekilde " "yeniden ölçeklendirmelisin." #: src/program/OutfitProject.cpp:51 msgid "Checking destination..." msgstr "Hedef kontrol ediliyor..." #: src/program/OutfitProject.cpp:106 msgid "Adding reference shapes..." msgstr "Örnek kalıplar ekleniyor..." #: src/program/OutfitProject.cpp:124 src/program/OutfitProject.cpp:2176 msgid "Adding outfit shapes..." msgstr "Kıyafet kalıpları ekleniyor..." #: src/program/OutfitProject.cpp:181 msgid "Calculating slider data..." msgstr "Kaydırıcı verileri hesaplanıyor..." #: src/program/OutfitProject.cpp:189 msgid "Creating slider set file..." msgstr "Kaydırıcı gurup dosyası oluşturuluyor..." #: src/program/OutfitProject.cpp:196 msgid "Failed to open or create slider set file: " msgstr "Kaydırıcı grubu dosyası açılamadı veya oluşturulamadı: " #: src/program/OutfitProject.cpp:203 msgid "Saving slider set file..." msgstr "Kaydırıcı gurup dosyası kaydediliyor..." #: src/program/OutfitProject.cpp:206 msgid "Failed to write to slider set file: " msgstr "Kaydırıcı grubu dosyasına yazdırılamadı: " #: src/program/OutfitProject.cpp:210 msgid "Saving NIF file..." msgstr "NIF dosyası olarak Kaydediliyor.." #: src/program/OutfitProject.cpp:240 msgid "Failed to write base .nif file: " msgstr "Temel .nif dosyası olarak yazdırması Başarısız: " #: src/program/OutfitProject.cpp:246 src/program/OutfitProject.cpp:1641 #: src/program/OutfitProject.cpp:1671 src/program/OutfitStudio.cpp:3490 msgid "Finished" msgstr "Tamamlandı" #: src/program/OutfitProject.cpp:1535 src/program/OutfitProject.cpp:1627 msgid "Gathering bones..." msgstr "Kemikler toplanılıyor..." #: src/program/OutfitProject.cpp:1563 msgid "Initializing proximity data..." msgstr "Uyumluluk veri tabanı başlatılıyor..." #: src/program/OutfitProject.cpp:1609 src/program/OutfitStudio.cpp:9552 msgid "Copying bone weights..." msgstr "Kemik ağırlıkları kopyalanıyor..." #: src/program/OutfitProject.cpp:1647 src/program/OutfitStudio.cpp:9743 msgid "Transferring bone weights..." msgstr "Kemik ağırlıkları aktarılıyor..." #: src/program/OutfitProject.cpp:1892 msgid "Template source entries are invalid." msgstr "Şablon kaynak girişleri geçersiz." #: src/program/OutfitProject.cpp:1892 src/program/OutfitProject.cpp:1922 #: src/program/OutfitProject.cpp:1927 src/program/OutfitProject.cpp:1972 #: src/program/OutfitProject.cpp:1994 src/program/OutfitProject.cpp:2001 #: src/program/OutfitProject.cpp:2011 src/program/OutfitProject.cpp:2023 msgid "Reference Error" msgstr "Örnekleme Hatası" #: src/program/OutfitProject.cpp:1919 src/program/OutfitProject.cpp:1991 #: src/program/OutfitProject.cpp:4593 #, c-format msgid "" "NIF version not supported!\n" "\n" "File: %s\n" "%s" msgstr "" "NIF sürümü desteklenmiyor!\n" "\n" "Dosya: %s\n" "%s" #: src/program/OutfitProject.cpp:1927 src/program/OutfitProject.cpp:2001 #, c-format msgid "Could not load reference NIF file '%s'!" msgstr "Örnek NIF dosyası yüklenemedi '%s'!" #: src/program/OutfitProject.cpp:1972 #, c-format msgid "Could not load slider set file '%s'!" msgstr "Kaydırıcı grup dosyası yüklenemedi '%s'!" #: src/program/OutfitProject.cpp:2011 #, c-format msgid "Reference NIF file '%s' does not contain any shapes." msgstr "Örnek NIF dosyası '%s' herhangi bir kalıbı içermiyor." #: src/program/OutfitProject.cpp:2023 #, c-format msgid "Shape '%s' not found in reference NIF file '%s'!" msgstr "Kalıp '%s' örnek olan NIF dosyasında bulunamadı '%s'!" #: src/program/OutfitProject.cpp:2075 msgid "Loading slider set..." msgstr "Kaydırıcı grup yükleniyor..." #: src/program/OutfitProject.cpp:2082 src/program/OutfitProject.cpp:2166 msgid "Retrieving sliders..." msgstr "Kaydırıcılar alınıyor..." #: src/program/OutfitProject.cpp:2092 msgid "Loading outfit shapes..." msgstr "Kıyafet kalıpları yükleniyor..." #: src/program/OutfitProject.cpp:2135 src/program/OutfitProject.cpp:2232 msgid "Updating slider data..." msgstr "Kaydırıcı verileri güncelleniyor..." #: src/program/OutfitProject.cpp:2158 msgid "Adding slider set..." msgstr "Kaydırıcı seti eklendi..." #: src/program/OutfitProject.cpp:2225 msgid "" "The following shapes were renamed and won't have slider data attached. " "Rename the duplicates yourself beforehand." msgstr "" "Aşağıdaki kalıplar yeniden adlandırıldı ama kaydırıcı verileri eklenmedi. " "Kopyasını almadan önce yeniden adlandırmalısın." #: src/program/OutfitProject.cpp:2227 msgid "Renamed Shapes" msgstr "Yeniden Adlandırılan Kalıplar" #: src/program/OutfitProject.cpp:4596 src/program/OutfitProject.cpp:4601 msgid "NIF Error" msgstr "NIF Hatası" #: src/program/OutfitProject.cpp:4601 #, c-format msgid "Could not load NIF file '%s'!" msgstr "NIF dosyası yüklenemedi '%s'!" #: src/program/OutfitProject.cpp:4733 msgid "" "There was cloth physics data loaded at some point (BSClothExtraData). Please " "choose all the origins to use in the output." msgstr "" "Bir noktada (BSClothExtraData) için yüklenen kumaş fizik verileri olmalıydı. " "Lütfen çıktıda kullanılacak tüm kaynakları seçtiğinden emin ol." #: src/program/OutfitProject.cpp:4734 msgid "Choose cloth data" msgstr "Kumaş verilerini seç" #: src/program/OutfitProject.cpp:4802 msgid "" "No reference has been loaded. For correct bone transforms, you might need " "to load a reference before importing OBJ files." msgstr "" "Hiçbir Örnek yüklenmedi. Doğru kemik dönüşümleri için OBJ dosyalarını içe " "aktarmadan önce bir örnek kalıp yüklemeniz gerekebilir." #: src/program/OutfitProject.cpp:4810 #, c-format msgid "Could not load OBJ file '%s'!" msgstr "OBJ dosyası yüklenemedi '%s'!" #: src/program/OutfitProject.cpp:4810 src/program/OutfitProject.cpp:4834 #: src/program/OutfitProject.cpp:4896 src/program/OutfitProject.cpp:5062 msgid "OBJ Error" msgstr "OBJ Hatası" #: src/program/OutfitProject.cpp:4816 src/program/OutfitProject.cpp:4981 msgid "" "The reference shape has a skin coordinate system that is different from the " "global coordinate system. Would you like to copy the reference's global-to-" "skin transform to the imported shapes?" msgstr "" "Örnek kalıp, genel koordinat sisteminden farklı bir dış yüzey koordinat " "sistemine sahiptir. Örneğin global-tene dönüşümünü içe aktarılan kalıplara " "kopyalamak ister misin?" #: src/program/OutfitProject.cpp:4818 src/program/OutfitProject.cpp:4983 msgid "Copy skin coordinates" msgstr "Deri-Ten koordinatlarını kopyala" #: src/program/OutfitProject.cpp:4834 #, c-format msgid "Could not copy data from OBJ file '%s'!" msgstr "OBJ dosyasındaki veri kopyalanamadı '%s'!" #: src/program/OutfitProject.cpp:4851 msgid "" "The vertex count of the selected .obj file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "Seçilen .obj dosyasının tepe noktası sayısı geçerli olarak seçilen kıyafet " "kalıbıyla eşleşiyor. Mevcut kalıbı güncellemek ister misin? (yeni bir Kalıp " "oluşturmak için Hayır'a tıkla)" #: src/program/OutfitProject.cpp:4853 src/program/OutfitProject.cpp:5009 msgid "Merge or New" msgstr "Birleştir ya da Yeniden" #: src/program/OutfitProject.cpp:4857 src/program/OutfitProject.cpp:5013 msgid "Update Vertex Positions?" msgstr "Köşe Konumlarının Güncellemesi?" #: src/program/OutfitProject.cpp:4857 src/program/OutfitProject.cpp:5013 msgid "Vertex Position Update" msgstr "Köşe Konumlarını Güncelleme" #: src/program/OutfitProject.cpp:4862 src/program/OutfitProject.cpp:5018 msgid "Update Texture Coordinates?" msgstr "Texture-Doku Konumlarının Güncellemesi?" #: src/program/OutfitProject.cpp:4862 src/program/OutfitProject.cpp:5018 msgid "UV Update" msgstr "UV Güncelleme" #: src/program/OutfitProject.cpp:4868 src/program/OutfitProject.cpp:5024 msgid "Update Normals?" msgstr "Normal Veriler Güncellensin mi?" #: src/program/OutfitProject.cpp:4868 src/program/OutfitProject.cpp:5024 msgid "Normals Update" msgstr "Normal Verileri Güncelle" #: src/program/OutfitProject.cpp:4878 src/program/OutfitProject.cpp:5040 msgid "Please specify a name for the new shape" msgstr "Lütfen yeni kalıp için yeni bir isim belirle" #: src/program/OutfitProject.cpp:4878 src/program/OutfitProject.cpp:5040 msgid "New Shape Name" msgstr "Yeni Kalıp Adı" #: src/program/OutfitProject.cpp:4889 src/program/OutfitProject.cpp:5055 #, c-format msgid "" "The vertex or triangle limit for '%s' was exceeded.\n" "Remaining data was dropped.\n" "\n" "Vertices (current/max): %zu/%zu\n" "Triangles (current/max): %zu/%zu" msgstr "" "Tepe noktası veya üçgen sınırı aşılan '%s' .\n" "Kalan veriler atıldı.\n" "\n" "Tepe Noktaları (mevcut/max): %zu/%zu\n" "Üçgen Noktalar (mevcut/max): %zu/%zu" #: src/program/OutfitProject.cpp:4969 msgid "" "No reference has been loaded. For correct bone transforms, you might need " "to load a reference before importing FBX files." msgstr "" "Hiçbir örnek yüklenmedi. Doğru kemik dönüşümleri için FBX dosyalarını içe " "aktarmadan önce bir örnek yüklemeniz gerekebilir." #: src/program/OutfitProject.cpp:5007 msgid "" "The vertex count of the selected .fbx file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "Seçili .fbx dosyasının tepe noktası sayısı geçerli olarak seçilen kıyafet " "kalıbıyla eşleşiyor. Mevcut şekli güncellemek ister misin? (yeni bir Kalıp " "oluşturmak istiyorsan Hayır'a tıkla)" #: src/program/OutfitProject.cpp:5031 msgid "Update Animation Weighting?" msgstr "Animasyon Ağırlığını Güncelle?" #: src/program/OutfitProject.cpp:5031 msgid "Animation Weight Update" msgstr "Animasyon Ağırlık Güncellemesi" #: src/program/OutfitProject.cpp:5128 msgid "Would you like Skyrim NIFs to be optimized for SSE during this session?" msgstr "" "Geçerli Skyrim NIF dosyalarının Skyrim SE için optimize edilmesini ister " "misin?" #: src/program/OutfitProject.cpp:5145 msgid "" "File format doesn't match the current game. Use FBX export, then start a new " "project and import the FBX file there." msgstr "" "Dosya formatı mevcut oyunla eşleşmiyor. FBX dışa aktarımını kullan, ardından " "yeni bir proje başlat ve FBX dosyasını oraya aktar." #: src/program/OutfitProject.cpp:5146 msgid "Version" msgstr "Sürüm" #: src/program/OutfitProject.cpp:5252 msgid "No Bad Bones Found." msgstr "Hatalı İskelet Bulunamadı." #: src/program/OutfitProject.cpp:5252 msgid "No Bad Bones" msgstr "Hatalı İskelet Yok" #: src/program/OutfitProject.cpp:5367 msgid "Bad Bones" msgstr "Hatalı İskeletler" #: src/program/OutfitProject.cpp:5388 msgid "Error in rotation" msgstr "Dönüşüm Hatası" #: src/program/OutfitProject.cpp:5389 msgid "Error in translation" msgstr "Çevirim Hatası" #: src/program/OutfitProject.cpp:5390 msgid "Error in scale" msgstr "Ölçekleme Hatası" #: src/program/OutfitProject.cpp:5417 #, c-format msgid "Bad standard bones for shape \"%s\"" msgstr "Kalıp için hatalı iskelet \"%s\"" #: src/program/OutfitProject.cpp:5420 #, c-format msgid "" "%zu bones in shape \"%s\" had inconsistencies between their NIF skin " "transforms and the standard skeleton:\n" msgstr "" "%zu iskeletindeki \"%s\" kalıbında NIF dış görünüm dönüşümleri ile standart " "iskelet arasında tutarsızlıklar vardı:\n" #: src/program/OutfitProject.cpp:5435 msgid "Update skin (recommended)" msgstr "Deri-Ten Güncelle (önerilen ayar)" #: src/program/OutfitProject.cpp:5443 src/program/OutfitProject.cpp:5507 #: src/program/OutfitProject.cpp:5530 msgid "Details" msgstr "Detaylar" #: src/program/OutfitProject.cpp:5443 msgid "Bone" msgstr "İskelet" #: src/program/OutfitProject.cpp:5448 src/program/OutfitProject.cpp:5544 msgid "Do nothing" msgstr "Bunu Uygulama" #: src/program/OutfitProject.cpp:5460 #, c-format msgid "Bad Custom Bone \"%s\"" msgstr "Hatalı Özel İskelet \"%s\"" #: src/program/OutfitProject.cpp:5463 #, c-format msgid "" "Custom bone \"%s\" had inconsistent NIF node and skin transforms for the " "following shapes:\n" "\"" msgstr "" "Özel İskelet \"%s\" geçerli NIF dosyası içerisinde hatalı ve bozuk kemikler " "içeriyordu:\n" "\"" #: src/program/OutfitProject.cpp:5483 msgid "Trust node and skins \"" msgstr "Doğru Düğüm ve Deriler \"" #: src/program/OutfitProject.cpp:5485 msgid "Trust node and skin \"" msgstr "Doğru Düğüm ve Deri \"" #: src/program/OutfitProject.cpp:5493 msgid "\", and update other skins (recommended)" msgstr "\", ve diğer deri-tenler güncellendi (önerilen)" #: src/program/OutfitProject.cpp:5496 msgid "Trust node, and update skins" msgstr "Doğru Düğüm, ve Deri-Ten güncellemesi" #: src/program/OutfitProject.cpp:5498 msgid "Trust node, and update skin" msgstr "Doğru Düğüm, ve Deri-Ten güncellemesi" #: src/program/OutfitProject.cpp:5507 msgid "Skin" msgstr "Deri-Ten" #: src/program/OutfitProject.cpp:5516 msgid "Trust skin \"" msgstr "Doğru Deri-Ten \"" #: src/program/OutfitProject.cpp:5518 msgid "\", and update node" msgstr "\", ve güncellenen Düğüm" #: src/program/OutfitProject.cpp:5520 msgid "\", and update node and other skins" msgstr "\", ve güncellenen Düğün ve Deriler" #: src/program/OutfitProject.cpp:5530 msgid "With" msgstr "Birlikte" #: src/program/OutfitProject.cpp:5531 msgid "Node" msgstr "Düğüm" #: src/program/OutfitProject.cpp:5557 msgid "Fix nothing" msgstr "Düzeltme Yapma" #: src/program/OutfitStudio.cpp:443 src/program/OutfitStudio.cpp:444 #: src/program/OutfitStudio.cpp:13371 src/program/OutfitStudio.cpp:13372 msgid "Adding NIF file..." msgstr "NIF dosyası Ekleniyor..." #: src/program/OutfitStudio.cpp:448 src/program/OutfitStudio.cpp:459 #: src/program/OutfitStudio.cpp:470 src/program/OutfitStudio.cpp:4209 #: src/program/OutfitStudio.cpp:13376 src/program/OutfitStudio.cpp:13387 #: src/program/OutfitStudio.cpp:13398 msgid "Refreshing GUI..." msgstr "GUI canlandırılıyor..." #: src/program/OutfitStudio.cpp:455 src/program/OutfitStudio.cpp:13383 msgid "Adding OBJ file..." msgstr "OBJ dosyası Ekleniyor..." #: src/program/OutfitStudio.cpp:465 src/program/OutfitStudio.cpp:466 #: src/program/OutfitStudio.cpp:13393 src/program/OutfitStudio.cpp:13394 msgid "Adding FBX file..." msgstr "FBX dosyası Ekleniyor..." #: src/program/OutfitStudio.cpp:652 msgid "" "Failed to find game install path registry value or GameDataPath in the " "config." msgstr "" "Yapılandırmada oyun yükleme yolu kayıt defteri değeri veya GameDataPath " "bulunamadı." #: src/program/OutfitStudio.cpp:975 msgid "Failed to load OutfitStudio.xrc file!" msgstr "Başarısız.. OutfitStudio.xrc Dosyası yüklenemedi!" #: src/program/OutfitStudio.cpp:981 msgid "Failed to load Outfit Studio frame!" msgstr "Outfit Studio ana çerçevesi yüklenemedi!" #: src/program/OutfitStudio.cpp:999 src/program/OutfitStudio.cpp:3754 #: src/program/OutfitStudio.h:1082 msgid "Ready!" msgstr "Hazır!" #: src/program/OutfitStudio.cpp:1447 src/program/OutfitStudio.cpp:1452 msgid "Packing projects to folder..." msgstr "Projeler klasöre paketleniyor..." #: src/program/OutfitStudio.cpp:1473 src/program/OutfitStudio.cpp:1520 #: src/program/OutfitStudio.cpp:1623 #, c-format msgid "Failed to open input file '%s'!" msgstr "Başarısız '%s'! Açılamayan girdi dosyası!" #: src/program/OutfitStudio.cpp:1484 #, c-format msgid "Failed to copy input file '%s'!" msgstr "aşarısız '%s'! Kopyalanamayan girdi dosyası!" #: src/program/OutfitStudio.cpp:1531 #, c-format msgid "Failed to copy data file '%s'!" msgstr "Başarısız '%s'! Kopyalanamayan veri dosyası!" #: src/program/OutfitStudio.cpp:1541 src/program/OutfitStudio.cpp:1699 #, c-format msgid "Failed to save merged project file '%s'!" msgstr "Başarısız '%s'! Kaydedilemeyen birleştirilmiş proje dosyası!" #: src/program/OutfitStudio.cpp:1550 src/program/OutfitStudio.cpp:1708 #, c-format msgid "Failed to open project file '%s'!" msgstr "Başarısız '%s'! Açılamayan proje dosyası!" #: src/program/OutfitStudio.cpp:1561 #, c-format msgid "Failed to copy merged project file '%s'!" msgstr "Başarısız '%s'! Kopyalanamayan birleştirilmiş proje dosyası!" #: src/program/OutfitStudio.cpp:1572 src/program/OutfitStudio.cpp:1734 #, c-format msgid "Failed to open group file '%s'!" msgstr "Başarısız '%s'! Açılamayan grup dosyası!" #: src/program/OutfitStudio.cpp:1584 #, c-format msgid "Failed to copy group file '%s'!" msgstr "Başarısız '%s'! Kopyalanamayan grup dosyası!" #: src/program/OutfitStudio.cpp:1590 src/program/OutfitStudio.cpp:1756 msgid "Packing finished." msgstr "Paketleme tamamlandı." #: src/program/OutfitStudio.cpp:1594 src/program/OutfitStudio.cpp:1599 msgid "Packing projects to archive..." msgstr "Arşivler klasöre paketleniyor..." #: src/program/OutfitStudio.cpp:1631 src/program/OutfitStudio.cpp:1682 #: src/program/OutfitStudio.cpp:1716 src/program/OutfitStudio.cpp:1743 msgid "Failed to put new entry into archive!" msgstr "Başarısız.. Yeni girdi arşive eklenemedi!" #: src/program/OutfitStudio.cpp:1638 src/program/OutfitStudio.cpp:1689 #: src/program/OutfitStudio.cpp:1723 src/program/OutfitStudio.cpp:1750 msgid "Failed to copy file contents to archive!" msgstr "Başarısız.. Dosya içeriği arşive kopyalanamadı!" #: src/program/OutfitStudio.cpp:1674 #, c-format msgid "Failed to open data file '%s'!" msgstr "Başarısız '%s'! Açılamayan veri dosyası!" #: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2059 #: src/program/OutfitStudio.cpp:3627 src/program/OutfitStudio.cpp:3634 #: src/program/OutfitStudio.cpp:4622 src/program/OutfitStudio.cpp:4648 #: src/program/OutfitStudio.cpp:7168 src/program/OutfitStudio.cpp:7296 #: src/program/OutfitStudio.cpp:7542 src/program/OutfitStudio.cpp:7560 #: src/program/OutfitStudio.cpp:7578 msgid "There are no valid shapes loaded!" msgstr "Başarısız '%s'! Açılamayan veri dosyası!" #: src/program/OutfitStudio.cpp:2020 src/program/OutfitStudio.cpp:2198 #, c-format msgid "Saving project '%s'..." msgstr "Proje kaydediliyor '%s'..." #: src/program/OutfitStudio.cpp:2045 src/program/OutfitStudio.cpp:2223 msgid "Saving failed." msgstr "Kayıt başarısız oldu." #: src/program/OutfitStudio.cpp:2050 src/program/OutfitStudio.cpp:2218 msgid "Saved." msgstr "Kaydediliyor." #: src/program/OutfitStudio.cpp:2144 msgid "Invalid or no slider set file specified! Please try again." msgstr "" "Geçersiz set veya hiç kaydırıcı ayar dosyası belirtilmemiş! Lütfen tekrar " "dene." #: src/program/OutfitStudio.cpp:2153 msgid "No outfit name specified! Please try again." msgstr "Belirtilen bir kıyafet ismi yok! Lütfen tekrar dene." #: src/program/OutfitStudio.cpp:2161 msgid "No data folder specified! Please try again." msgstr "Belirtilen bir data veri klasörü yok! Lütfen tekrar dene." #: src/program/OutfitStudio.cpp:2175 msgid "" "An invalid or no base outfit .nif file name specified! Please try again." msgstr "" "Geçersiz veya temelsiz bir kıyafet .nif dosya adı belirtildi! Lütfen tekrar " "dene." #: src/program/OutfitStudio.cpp:2184 msgid "No game file path specified! Please try again." msgstr "Oyun dosyası yolu belirtilmemiş! Lütfen tekrar dene." #: src/program/OutfitStudio.cpp:2190 msgid "No game file name specified! Please try again." msgstr "Oyun dosya adı belirtilmemiş! Lütfen tekrar dene." #: src/program/OutfitStudio.cpp:2235 #, c-format msgid "Failed to open '%s' as a slider set file!" msgstr "u dosya '%s' bir kaydırıcı seti olarak açılamadı!" #: src/program/OutfitStudio.cpp:2235 src/program/OutfitStudio.cpp:2299 msgid "Slider Set Error" msgstr "Kaydırıcı Seti Hatası" #: src/program/OutfitStudio.cpp:2254 msgid "Please choose an outfit to load" msgstr "Lütfen yüklemek için bir kıyafet seç" #: src/program/OutfitStudio.cpp:2254 msgid "Load a slider set" msgstr "Bir kaydırıcı seti yükle" #: src/program/OutfitStudio.cpp:2265 msgid "Loading project..." msgstr "Proje yükleniyor..." #: src/program/OutfitStudio.cpp:2285 msgid "Loading outfit data..." msgstr "Kıyafet verileri yükleniyor..." #: src/program/OutfitStudio.cpp:2299 #, c-format msgid "Failed to create project '%s' from file '%s' (%d)!" msgstr "'%s' dosyasından '%s' (%d) Proje oluşturulamadı!" #: src/program/OutfitStudio.cpp:2313 #, c-format msgid "Loading reference shape '%s'..." msgstr "Örnek kalıp yükleniyor '%s'..." #: src/program/OutfitStudio.cpp:2327 msgid "Loading textures..." msgstr "Textures Data Yükleniyor..." #: src/program/OutfitStudio.cpp:2332 src/program/OutfitStudio.cpp:3472 #: src/program/OutfitStudio.cpp:3717 msgid "Creating outfit..." msgstr "Kıyafet oluşturma..." #: src/program/OutfitStudio.cpp:2336 src/program/OutfitStudio.cpp:3482 #: src/program/OutfitStudio.cpp:3617 #, c-format msgid "Creating %zu slider(s)..." msgstr "Kaydırıcı(lar) %zu oluşturuluyor..." #: src/program/OutfitStudio.cpp:2355 msgid "Creating sliders..." msgstr "Kaydırıcılar oluşturuluyor..." #: src/program/OutfitStudio.cpp:2358 msgid "Clearing old sliders..." msgstr "Eski kaydırıcılar temizleniyor..." #: src/program/OutfitStudio.cpp:2369 msgid "Loading slider: " msgstr "Yüklenen kaydırıcı: " #: src/program/OutfitStudio.cpp:2429 src/program/OutfitStudio.cpp:7699 msgid "Enter a name for the new slider:" msgstr "Kaydırıcı için yeni bir isim girin:" #: src/program/OutfitStudio.cpp:2429 src/program/OutfitStudio.cpp:7699 msgid "Create New Slider" msgstr "Yeni Kaydırıcı Oluştur" #: src/program/OutfitStudio.cpp:2555 #, c-format msgid "Total Bones: %zu" msgstr "Toplam İskelet: %zu" #: src/program/OutfitStudio.cpp:2570 #, c-format msgid "Shape Selection Bones: %zu" msgstr "Kalıp İçin Seçilen İskeletler: %zu" #: src/program/OutfitStudio.cpp:3072 msgid "Edit Color" msgstr "Renk Düzenleme" #: src/program/OutfitStudio.cpp:3234 msgid "" "You are trying to edit a slider's morph with that slider set to zero. Do " "you wish to set the slider to one now?" msgstr "" "Bu kaydırıcı sıfıra ayarlıyken bir kaydırıcının (morps) dönüşümünü " "düzenlemeye çalışıyorsunuz. Kaydırıcıyı şimdi bir değerine ayarlamak ister " "misiniz?" #: src/program/OutfitStudio.cpp:3251 msgid "" "You can only use the undiff brush while editing a slider. Note, use the " "pencil button next to a slider to enable editing of that slider's morph." msgstr "" "Bir kaydırıcıyı düzenlerken yalnızca yayma fırçasıyla çalışabilirsin. Bu " "kaydırıcının dönüşümünü düzenlemeyi etkinleştirmek için kaydırıcının " "yanındaki kalem düğmesini kullanabilirsin." #: src/program/OutfitStudio.cpp:3262 msgid "" "You can only edit the base shape when all sliders are zero. Do you wish to " "set all sliders to zero now? Note, use the pencil button next to a slider " "to enable editing of that slider's morph." msgstr "" "Yalnızca tüm kaydırıcılar sıfır olduğunda temel şekli düzenleyebilirsin. " "Şimdi tüm kaydırıcıları sıfırlamak istiyor musun? Not: Bu kaydırıcının morph " "düzenlenmesini sağlamak için kaydırıcının yanındaki kalem düğmesini " "kullanmalısın." #: src/program/OutfitStudio.cpp:3338 #, c-format msgid "You have unsaved changes to '%s'. Would you like to save them now?" msgstr "" "'%s' Üzerinde kaydedilmemiş değişikliklerin var. Onları şimdi kurtarmak " "ister misin?" #: src/program/OutfitStudio.cpp:3339 msgid "Unsaved Changes" msgstr "Kaydedilmemiş Değişiklikler" #: src/program/OutfitStudio.cpp:3394 #, c-format msgid "Creating project '%s'..." msgstr "Proje oluşturuluyor '%s'..." #: src/program/OutfitStudio.cpp:3411 src/program/OutfitStudio.cpp:3555 msgid "Loading reference..." msgstr "Örnek yükleniyor..." #: src/program/OutfitStudio.cpp:3451 src/program/OutfitStudio.cpp:3675 #: src/program/OutfitStudio.cpp:3684 msgid "Loading outfit..." msgstr "Kıyafet yükleniyor..." #: src/program/OutfitStudio.cpp:3497 msgid "Select a slider set to load" msgstr "Yüklemek için bir kaydırıcı seç" #: src/program/OutfitStudio.cpp:3514 msgid "Select a slider set to add" msgstr "Eklenecek kaydırıcıyı seç" #: src/program/OutfitStudio.cpp:3531 src/program/OutfitStudio.cpp:3639 #: src/program/OutfitStudio.cpp:8705 src/program/OutfitStudio.cpp:8760 #: src/program/OutfitStudio.cpp:8851 src/program/OutfitStudio.cpp:8974 msgid "" "You're currently editing slider data, please exit the slider's edit mode " "(pencil button) and try again." msgstr "" "Şu anda kaydırıcı verilerini düzenliyorsun, lütfen kaydırıcının düzenleme " "modundan çık (kalem butonuyla) ve tekrar dene." #: src/program/OutfitStudio.cpp:3561 msgid "Loading reference set..." msgstr "Örnek set yükleniyor..." #: src/program/OutfitStudio.cpp:3613 msgid "Creating reference..." msgstr "Örnek oluşturuluyor..." #: src/program/OutfitStudio.cpp:3727 msgid "Unload the project? All unsaved changes will be lost" msgstr "" "Projeyi gerçekten kaldırmayı istiyor musun? Kaydedilmemiş tüm değişiklikler " "silinecek." #: src/program/OutfitStudio.cpp:3727 msgid "Unload Project" msgstr "Projeyi Kaldır" #: src/program/OutfitStudio.cpp:3728 msgid "Unload" msgstr "Kaldır" #: src/program/OutfitStudio.cpp:4196 msgid "Import NIF file" msgstr "NIF dosyası Yerleştir" #: src/program/OutfitStudio.cpp:4203 src/program/OutfitStudio.cpp:4204 msgid "Importing NIF file..." msgstr "NIF dosyası yerleştiriliyor..." #: src/program/OutfitStudio.cpp:4225 msgid "Export outfit NIF" msgstr "Kıyafet çıktısı NIF olarak" #: src/program/OutfitStudio.cpp:4243 #, c-format msgid "Failed to save NIF file '%s'!" msgstr "NIF dosyası olarak kaydedilemedi '%s'!" #: src/program/OutfitStudio.cpp:4243 src/program/OutfitStudio.cpp:4275 #: src/program/OutfitStudio.cpp:4360 src/program/OutfitStudio.cpp:4485 #: src/program/OutfitStudio.cpp:4710 msgid "Export Error" msgstr "Dışa Aktarma Hatası" #: src/program/OutfitStudio.cpp:4259 msgid "Export project NIF" msgstr "Proje NIF dosyasını dışa aktar" #: src/program/OutfitStudio.cpp:4275 #, c-format msgid "Failed to save NIF file '%s' with reference!" msgstr "NIF dosyası '%s' örnek dosya olarak kaydedilemedi!" #: src/program/OutfitStudio.cpp:4281 src/program/OutfitStudio.cpp:4366 #: src/program/OutfitStudio.cpp:4491 src/program/OutfitStudio.cpp:4627 #: src/program/OutfitStudio.cpp:4653 src/program/OutfitStudio.cpp:7097 #: src/program/OutfitStudio.cpp:7122 src/program/OutfitStudio.cpp:7143 #: src/program/OutfitStudio.cpp:7412 src/program/OutfitStudio.cpp:7437 #: src/program/OutfitStudio.cpp:7473 src/program/OutfitStudio.cpp:7506 #: src/program/OutfitStudio.cpp:7602 src/program/OutfitStudio.cpp:7653 #: src/program/OutfitStudio.cpp:7715 src/program/OutfitStudio.cpp:7732 #: src/program/OutfitStudio.cpp:8114 src/program/OutfitStudio.cpp:8131 #: src/program/OutfitStudio.cpp:8151 src/program/OutfitStudio.cpp:8175 #: src/program/OutfitStudio.cpp:8209 src/program/OutfitStudio.cpp:8361 #: src/program/OutfitStudio.cpp:8550 src/program/OutfitStudio.cpp:8700 #: src/program/OutfitStudio.cpp:8755 src/program/OutfitStudio.cpp:8969 #: src/program/OutfitStudio.cpp:9056 src/program/OutfitStudio.cpp:9528 #: src/program/OutfitStudio.cpp:9619 src/program/OutfitStudio.cpp:9712 #: src/program/OutfitStudio.cpp:9757 src/program/OutfitStudio.cpp:9798 #: src/program/OutfitStudio.cpp:9845 src/program/OutfitStudio.cpp:10096 #: src/program/OutfitStudio.cpp:10142 src/program/OutfitStudio.cpp:10245 #: src/program/OutfitStudio.cpp:10388 src/program/OutfitStudio.cpp:13426 msgid "There is no shape selected!" msgstr "Seçili bir kalıp yok!" #: src/program/OutfitStudio.cpp:4288 msgid "Export selected shapes to NIF" msgstr "Seçilen modeli bir NIF kalıbı olarak dışa aktar" #: src/program/OutfitStudio.cpp:4300 msgid "Failed to export selected shapes to NIF file!" msgstr "Seçilen model bir NIF kalıbı olarak dışa aktarılamadı!" #: src/program/OutfitStudio.cpp:4305 msgid "Import .obj file for new shape" msgstr "eni kalıp içerisine .obj dosyasını yerleştir" #: src/program/OutfitStudio.cpp:4343 msgid "" "Some of the shapes have coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the OBJ? (This is not recommended.)" msgstr "" "Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat " "sistemlerine sahiptir. Geometri, OBJ'de genel koordinatlara dönüştürülsün " "mü? (Bu tavsiye edilmez.)" #: src/program/OutfitStudio.cpp:4345 src/program/OutfitStudio.cpp:4380 #: src/program/OutfitStudio.cpp:4470 src/program/OutfitStudio.cpp:4505 msgid "Transform to global" msgstr "Küresel Dönüşüm" #: src/program/OutfitStudio.cpp:4352 msgid "Export project as an .obj file" msgstr "Projeyi bir .obj dosyası olarak dışa aktar" #: src/program/OutfitStudio.cpp:4360 src/program/OutfitStudio.cpp:4402 #: src/program/OutfitStudio.cpp:4421 src/program/OutfitStudio.cpp:7533 msgid "Failed to export OBJ file!" msgstr "OBJ dosyası çıkartımı başarısız!" #: src/program/OutfitStudio.cpp:4378 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the OBJ?" msgstr "" "Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat " "sistemlerine sahiptir. Geometri, OBJ'de genel koordinatlara dönüştürülsün mü?" #: src/program/OutfitStudio.cpp:4389 msgid "Export selected shapes as an .obj file" msgstr "Seçilen kalıpları bir .obj dosyası olarak dışa aktar" #: src/program/OutfitStudio.cpp:4406 msgid "Export shape as an .obj file" msgstr "Kalıbı bir .obj dosyası olarak dışa aktar" #: src/program/OutfitStudio.cpp:4427 msgid "Import .fbx file for new shape" msgstr "Yeni kalıp içerisine .fbx dosyasını yerleştir" #: src/program/OutfitStudio.cpp:4468 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the FBX? (This is not recommended.)" msgstr "" "Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat " "sistemlerine sahiptir. Geometri, FBX genel koordinatlara dönüştürülsün mü? " "(Bu tavsiye edilmez.)" #: src/program/OutfitStudio.cpp:4477 msgid "Export project as an .fbx file" msgstr "Projeyi bir .fbx dosyası olarak dışa aktar" #: src/program/OutfitStudio.cpp:4485 src/program/OutfitStudio.cpp:4527 #: src/program/OutfitStudio.cpp:4546 msgid "Failed to export FBX file!" msgstr "FBX dosyası çıkartımı başarısız!" #: src/program/OutfitStudio.cpp:4503 msgid "" "Some of the shapes have skin coordinate systems that are not the same as the " "global coordinate system. Should the geometry be transformed to global " "coordinates in the FBX?" msgstr "" "Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat " "sistemlerine sahiptir. Geometri, FBX genel koordinatlara dönüştürülsün mü?" #: src/program/OutfitStudio.cpp:4514 msgid "Export selected shapes as an .fbx file" msgstr "Seçilen kalıpları .fbx dosyası olarak dışa aktar" #: src/program/OutfitStudio.cpp:4531 msgid "Export shape as an .fbx file" msgstr "Kalıbı bir .fbx dosyası olarak dışa aktar" #: src/program/OutfitStudio.cpp:4552 src/program/OutfitStudio.cpp:7300 msgid "Import .tri morphs" msgstr ".tri morphs dosyası yerleştir" #: src/program/OutfitStudio.cpp:4571 src/program/OutfitStudio.cpp:7309 msgid "Failed to load TRI file!" msgstr "TRI dosyası yerleştirilemedi!" #: src/program/OutfitStudio.cpp:4577 src/program/OutfitStudio.cpp:8157 msgid "Please enter a new unique name for the shape." msgstr "Lütfen kalıp için yeni bir isim girin." #: src/program/OutfitStudio.cpp:4577 src/program/OutfitStudio.cpp:8157 msgid "Rename Shape" msgstr "Kalıbı Yeniden Adlandır" #: src/program/OutfitStudio.cpp:4631 src/program/OutfitStudio.cpp:4657 #: src/program/OutfitStudio.cpp:7564 msgid "Export .tri morphs" msgstr ".tri morphs Olarak Çıkart" #: src/program/OutfitStudio.cpp:4641 src/program/OutfitStudio.cpp:4664 #: src/program/OutfitStudio.cpp:7571 msgid "Failed to export TRI file!" msgstr "TRI dosyası olarak dışa çıkartma başarısız!" #: src/program/OutfitStudio.cpp:4669 msgid "Import physics data to project" msgstr "Projeye fizik data dosyasını yerleştir" #: src/program/OutfitStudio.cpp:4676 #, c-format msgid "Failed to import physics data file '%s'!" msgstr "Fizik dosyası yüklemesi başarısız '%s'!" #: src/program/OutfitStudio.cpp:4676 msgid "Import Error" msgstr "Yerleştirme Hatası" #: src/program/OutfitStudio.cpp:4688 msgid "There is no physics data loaded!" msgstr "Yüklenen dosyada herhangi bir fizik bilgisi yok!" #: src/program/OutfitStudio.cpp:4688 src/program/OutfitStudio.cpp:6384 #: src/program/OutfitStudio.cpp:7084 msgid "Info" msgstr "Bilgi" #: src/program/OutfitStudio.cpp:4696 msgid "Please choose the physics data source you want to export." msgstr "Lütfen yerleştirmek istediğin fizik veri kaynağını seç." #: src/program/OutfitStudio.cpp:4696 msgid "Choose physics data" msgstr "Fizik verilerini seç" #: src/program/OutfitStudio.cpp:4704 msgid "Export physics data" msgstr "Fizik verilerini yerleştir" #: src/program/OutfitStudio.cpp:4710 #, c-format msgid "Failed to save physics data file '%s'!" msgstr "Fizik veri dosyaları yerleştirmesi başarısız '%s'!" #: src/program/OutfitStudio.cpp:4717 msgid "This function requires at least one slider position to be non-zero." msgstr "" "Bu işlev değeri sıfır olmayan bir en az bir tane kaydırma konumu gerektirir." #: src/program/OutfitStudio.cpp:4729 msgid "" "Create a conversion slider for the current slider settings with the " "following name: " msgstr "" "Geçerli kaydırıcı ayarları için aşağıda aynı adla bir dönüşüm kaydırıcısını " "oluştur: " #: src/program/OutfitStudio.cpp:4729 msgid "Create New Conversion Slider" msgstr "Yeni Dönüşüm Kaydırıcısı Oluştur" #: src/program/OutfitStudio.cpp:5472 msgid "Please enter an SSF file path." msgstr "Lütfen bir SSF dosya yolu gir." #: src/program/OutfitStudio.cpp:6229 #, c-format msgid "Field of View: %d" msgstr "Görüş Alanı: %d" #: src/program/OutfitStudio.cpp:6359 msgid "Your changes were not applied yet. Do you want to apply or reset them?" msgstr "" "Yaptığınız değişiklikler henüz uygulanmadı. Bunları uygulamak mı yoksa " "sıfırlamak mı istiyorsunuz?" #: src/program/OutfitStudio.cpp:6360 msgid "Pending Changes" msgstr "Bekleyen Değişiklikler" #: src/program/OutfitStudio.cpp:6384 msgid "" "You must have exactly one mesh selected in order to edit partitions or " "segments." msgstr "" "Bölümleri veya segmentleri tam olarak düzenlemek için bir mesh dosyası " "seçmelisin." #: src/program/OutfitStudio.cpp:7033 msgid "There are no sliders loaded!" msgstr "Yüklenen bir kaydırıcı yok!" #: src/program/OutfitStudio.cpp:7084 msgid "No changes were made to the sliders, so no preset was saved!" msgstr "" "Kaydırıcılara herhangi bir değişiklik yapılmadı, bu nedenle hiçbir hazır " "ayar kaydedilmedi!" #: src/program/OutfitStudio.cpp:7101 src/program/OutfitStudio.cpp:7126 #: src/program/OutfitStudio.cpp:7147 src/program/OutfitStudio.cpp:7416 msgid "There is no slider in edit mode to import data to!" msgstr "Verileri içe aktarmak için düzenleme modunda hiç kaydırıcı yok!" #: src/program/OutfitStudio.cpp:7105 msgid "Import .nif file for slider calculation" msgstr "Kaydırıcı hesaplaması için .nif dosyasını içe aktar" #: src/program/OutfitStudio.cpp:7112 msgid "No mesh found in the .nif file that matches currently selected shape!" msgstr ".nif dosyasında şu anda seçili kalıba uyan ağ yapısı bulunamadı!" #: src/program/OutfitStudio.cpp:7130 msgid "Import .bsd slider data" msgstr ".bsd Kaydırıcı Dosyası Yerleştir" #: src/program/OutfitStudio.cpp:7151 msgid "Import .obj file for slider calculation" msgstr ".obj kaydırıcı hesaplama dosyası yerleştir" #: src/program/OutfitStudio.cpp:7158 src/program/OutfitStudio.cpp:7427 msgid "Vertex count of .obj file mesh does not match currently selected shape!" msgstr ".obj dosya kafesinin köşe sayısı şu an seçili olan kalıpla eşleşmiyor!" #: src/program/OutfitStudio.cpp:7172 msgid "Import .osd file" msgstr ".osd Dosyasını Yerleştir" #: src/program/OutfitStudio.cpp:7181 msgid "Failed to import OSD file!" msgstr "OSD Dosyası yerleştirmesi başarısız!" #: src/program/OutfitStudio.cpp:7221 src/program/OutfitStudio.cpp:7332 msgid "This will delete all loaded sliders. Are you sure?" msgstr "Bu işlem, tüm yüklü kaydırıcıları siler. Emin misin?" #: src/program/OutfitStudio.cpp:7221 src/program/OutfitStudio.cpp:7291 msgid "OSD Import" msgstr "OSD Yerleştir" #: src/program/OutfitStudio.cpp:7291 src/program/OutfitStudio.cpp:7407 #, c-format msgid "" "Added morphs for the following shapes:\n" "\n" "%s" msgstr "" "Aşağıdaki kalıplara morphs dosyası eklendi:\n" "\n" "%s" #: src/program/OutfitStudio.cpp:7332 src/program/OutfitStudio.cpp:7407 msgid "TRI Import" msgstr "TRI Yerleştir" #: src/program/OutfitStudio.cpp:7420 msgid "Import .fbx file for slider calculation" msgstr ".fbx kaydırıcı hesaplama dosyası yerleştir" #: src/program/OutfitStudio.cpp:7441 src/program/OutfitStudio.cpp:7477 #: src/program/OutfitStudio.cpp:7510 msgid "There is no slider in edit mode to export data from!" msgstr "Verileri dışa aktarmak için düzenleme modunda hiç kaydırıcı yok!" #: src/program/OutfitStudio.cpp:7446 msgid "Export .nif slider data to directory" msgstr ".nif kaydırıcı verilerini dışa aktar" #: src/program/OutfitStudio.cpp:7457 msgid "Export .nif slider data" msgstr ".nif kaydırıcı verilerini Çıkart" #: src/program/OutfitStudio.cpp:7464 msgid "Failed to export NIF file!" msgstr "NIF dosyası Dışa Aktarılamadı!" #: src/program/OutfitStudio.cpp:7482 msgid "Export .bsd slider data to directory" msgstr ".bsd kaydırıcı verilerini dışa aktar" #: src/program/OutfitStudio.cpp:7493 msgid "Export .bsd slider data" msgstr ".bsd kaydırıcı verilerini Çıkart" #: src/program/OutfitStudio.cpp:7515 src/program/OutfitStudio.cpp:7582 msgid "Export .obj slider data to directory" msgstr ".obj kaydırıcı verilerini dışa aktar" #: src/program/OutfitStudio.cpp:7526 msgid "Export .obj slider data" msgstr ".obj kaydırıcı verilerini Çıkart" #: src/program/OutfitStudio.cpp:7546 msgid "Export .osd file" msgstr ".osd Olarak Çıkart" #: src/program/OutfitStudio.cpp:7553 msgid "Failed to export OSD file!" msgstr "OSD dosyası dışa çıkartma başarısız!" #: src/program/OutfitStudio.cpp:7608 msgid "" "Are you sure you wish to clear the unmasked slider data for the selected " "shapes? This action cannot be undone." msgstr "" "Maskelememiş kaydırıcı verilerini silmek istediğinden emin misin ? Bu işlem " "geri alınamaz." #: src/program/OutfitStudio.cpp:7609 src/program/OutfitStudio.cpp:7614 msgid "Confirm data erase" msgstr "Veri silme işlemini onayla" #: src/program/OutfitStudio.cpp:7612 #, c-format msgid "" "Are you sure you wish to clear the unmasked slider data for the shape '%s'? " "This action cannot be undone." msgstr "" "'%s' kalıbı için maskelenmemiş kaydırıcı verilerini silmek istediğinden emin " "misin? Bu işlem geri alınamaz." #: src/program/OutfitStudio.cpp:7667 msgid "Enter a name for the new zap:" msgstr "Yeni zap için bir isim gir:" #: src/program/OutfitStudio.cpp:7667 msgid "Create New Zap" msgstr "Yeni Zap Olustur" #: src/program/OutfitStudio.cpp:7719 msgid "There is no slider in edit mode to negate!" msgstr "Düzenleme modunda düzenleme yapmak için bir kaydırıcı yok!" #: src/program/OutfitStudio.cpp:7736 msgid "There is no slider in edit mode to create a mask from!" msgstr "Maske oluşturmak için düzenleme modunda bir kaydırıcı yok!" #: src/program/OutfitStudio.cpp:7746 msgid "Are you sure you wish to delete the selected slider(s)?" msgstr "Seçilen kaydırıcı(ları) silmek istediğinden emin misin?" #: src/program/OutfitStudio.cpp:7747 msgid "Confirm slider delete" msgstr "Kaydırıcıyı silmeyi onayla" #: src/program/OutfitStudio.cpp:7947 msgid "There is no slider in edit mode to show properties for!" msgstr "Özellikleri göstermek için düzenleme modunda kaydırıcı yok!" #: src/program/OutfitStudio.cpp:7960 src/program/OutfitStudio.cpp:8004 msgid "Conforming: " msgstr "Uyum sağlanıyor: " #: src/program/OutfitStudio.cpp:7991 msgid "Conforming shapes..." msgstr "Kalıplara uygulanıyor..." #: src/program/OutfitStudio.cpp:8015 msgid "All shapes conformed." msgstr "Tüm kalıplar uyumlu." #: src/program/OutfitStudio.cpp:8729 msgid "Are you sure you wish to delete parts of the selected shapes?" msgstr "Seçili kalıp parçalarını silmek istediğinden emin misin?" #: src/program/OutfitStudio.cpp:8729 src/program/OutfitStudio.cpp:9060 msgid "Confirm Delete" msgstr "Silmeyi Onayla" #: src/program/OutfitStudio.cpp:8771 msgid "Please enter a unique name for the new separated shape." msgstr "Lütfen yeni ayrıştırılmış modelin için yeni bir isim gir." #: src/program/OutfitStudio.cpp:8771 msgid "Separate Vertices..." msgstr "Ayrışmış Köşeler..." #: src/program/OutfitStudio.cpp:8821 msgid "No errors found!" msgstr "Hata bulunmadı!" #: src/program/OutfitStudio.cpp:8827 msgid "Errors:" msgstr "Hatalar:" #: src/program/OutfitStudio.cpp:8829 msgid "Target must be different from source." msgstr "Hedef kaynaktan farklı olmalıdır." #: src/program/OutfitStudio.cpp:8831 msgid "" "Partitions do not match. Make sure the amount of partitions and their slots " "match up." msgstr "" "Bölümler eşleşmiyor. Bölümlerin miktarının ve yuvalarının eşleştiğinden emin " "ol." #: src/program/OutfitStudio.cpp:8833 msgid "" "Segments do not match. Make sure the amount of segments, sub segments and " "their info as well as the segmentation file match." msgstr "" "Segmentler eşleşmiyor. Segmentlerin, alt segmentlerin ve bilgilerinin yanı " "sıra segmentasyon dosyasının eşleştiğinden emin ol." #: src/program/OutfitStudio.cpp:8835 msgid "Resulting shape would have too many vertices." msgstr "Ortaya çıkan kalıbta çok fazla tepe noktası oluşur." #: src/program/OutfitStudio.cpp:8837 msgid "Resulting shape would have too many triangles." msgstr "Ortaya çıkan kalıbta çok fazla üçgen köşe oluşur." #: src/program/OutfitStudio.cpp:8839 msgid "" "Shaders do not match. Make sure both shapes either have or don't have a " "shader and their shader type matches." msgstr "" "Shader eşleşmiyor. Her iki kalıbın da gölgelendiricisi olduğundan ve " "gölgelendirici türünün eşleştiğinden emin ol." #: src/program/OutfitStudio.cpp:8841 msgid "" "Base texture doesn't match. Make sure both shapes have the same base/diffuse " "texture path." msgstr "" "Temel texture-doku eşleşmiyor. Her iki şeklin de aynı temel/gerçek doku " "yoluna sahip olduğundan emin ol." #: src/program/OutfitStudio.cpp:8843 msgid "" "Alpha property mismatch. Make sure both shapes either have or don't have an " "alpha property and their flags + threshold match." msgstr "" "Alfa uyuşmazlığı. Her iki kalıbın da alfa özelliğine sahip olduğundan ve " "ortak bayrak + ortak eşik değerlerine sahip olduğundan emin ol." #: src/program/OutfitStudio.cpp:8930 msgid "" "You can only copy shapes into an outfit, and there is no outfit in the " "current project. Load one first!" msgstr "" "Kalıpları yalnızca bir kıyafete kopyalayabilirsin ve mevcut projende " "kıyafetin yok. Önce bir tane yüklemelisin!" #: src/program/OutfitStudio.cpp:8937 msgid "Please enter a unique name for the duplicated shape." msgstr "Lütfen çoğaltılmış kalıp için yeni bir isim gir." #: src/program/OutfitStudio.cpp:8937 msgid "Duplicate Shape" msgstr "Kalıbı Çoğalt" #: src/program/OutfitStudio.cpp:8979 msgid "There is more than one shape selected." msgstr "Birden fazla kalıp seçili." #: src/program/OutfitStudio.cpp:9034 msgid "" "An edge has multiple triangles of the same orientation. Correct the " "orientations before splitting." msgstr "" "Bir kenar, aynı yönelimde birden çok üçgene sahiptir. Bölmeden önce " "oryantasyonlarını düzeltmelisin." #: src/program/OutfitStudio.cpp:9060 msgid "" "Are you sure you wish to delete the selected shapes? This action cannot be " "undone." msgstr "" "Seçilen kalıpları silmek istediğinden emin misin? Bu işlem geri alınamaz." #: src/program/OutfitStudio.cpp:9220 msgid "No bone name was entered!" msgstr "Kemik adı girilmedi!" #: src/program/OutfitStudio.cpp:9228 #, c-format msgid "Bone '%s' already exists in the project!" msgstr "Bu kemik '%s' projende zaten mevcut!" #: src/program/OutfitStudio.cpp:9358 msgid "" "The following shapes have unweighted vertices, which can cause issues. The " "affected vertices have been put under a mask. Do you want to save anyway?" msgstr "" "Aşağıdaki kalıplar sorunlara neden olabilecek, ağırlıksız köşelere sahip. " "Etkilenen köşeler bir maskenin altına yerleştirildi. Yine de kaydetmek ister " "misin?" #: src/program/OutfitStudio.cpp:9361 msgid "Unweighted Vertices" msgstr "Ağırlıksız Tepe Noktaları" #: src/program/OutfitStudio.cpp:9533 src/program/OutfitStudio.cpp:9624 #: src/program/OutfitStudio.cpp:9718 src/program/OutfitStudio.cpp:9850 msgid "There is no reference shape!" msgstr "Seçili bir örnek kalıbı yok!" #: src/program/OutfitStudio.cpp:9542 src/program/OutfitStudio.cpp:9692 msgid "" "Sorry, you can't copy weights from the reference shape to itself. Skipping " "this shape." msgstr "" "Üzgünüm, referans şekillerindeki ağırlıkları istediğin gibi kopyalayamazsın. " "Bu kalıbı atlamalısın." #: src/program/OutfitStudio.cpp:9542 src/program/OutfitStudio.cpp:9692 msgid "Can't copy weights" msgstr "Ağırlıklar kopyalanamaz" #: src/program/OutfitStudio.cpp:9662 msgid "Copying selected bone weights..." msgstr "Seçilen kemik ağırlıklarını kopyalar..." #: src/program/OutfitStudio.cpp:9723 msgid "Sorry, you can't copy weights from the reference shape to itself." msgstr "" "Üzgünüm, referans şekillerindeki ağırlıkları istediğin gibi kopyalayamazsın." #: src/program/OutfitStudio.cpp:9730 msgid "The vertex count of the reference and chosen shape is not the same!" msgstr "Örneğin ve seçilen modelin köşe sayısı aynı değildir!" #: src/program/OutfitStudio.cpp:9859 msgid "" "Sorry, you can't copy partitions/segments from the reference shape to " "itself. Skipping this shape." msgstr "" "Üzgünüm, referans şekillerindeki bölüm/segmentleri istediğin gibi " "kopyalayamazsın. Bu kalıbı atlamalısın." #: src/program/OutfitStudio.cpp:9859 msgid "Can't copy segments/partitions" msgstr "Segment/Bölümler kopyalanamaz" #: src/program/OutfitStudio.cpp:9864 msgid "" "Triangles will be assigned to the partition/segment of the nearest triangle " "in the reference. Existing partitions/segments are cleared. This action " "can't be undone." msgstr "" "Üçgen noktaları, referanstaki en yakın üçgenin bölümüne/sekmentine " "atanacaktır. Mevcut bölüm/segmentler temizlenir. Bu işlem geri alınamaz." #: src/program/OutfitStudio.cpp:9864 msgid "Copy Partitions/Segments" msgstr "Bölüm/Segmentleri Kopyala" #: src/program/OutfitStudio.cpp:9873 msgid "Copying segments/partitions..." msgstr "Segmentler ve Bölümler kopyalanıyor..." #: src/program/OutfitStudio.cpp:9884 #, c-format msgid "" "The partitions/segments could not be copied for '%s' because %d triangles " "could not be matched." msgstr "" "Bölüm/segmentler '%s' için %d üçgen tepeleri eşleştirilemediğinden " "kopyalanamadı." #: src/program/OutfitStudio.cpp:9935 msgid " sliders" msgstr " kaydırıcılar" #: src/program/OutfitStudio.cpp:9937 msgid " bones" msgstr " kemikler" #: src/program/OutfitStudio.cpp:10073 msgid "Symmetrize Vertices" msgstr "tepe Noktalarını Simetrikleştir" #: src/program/OutfitStudio.cpp:10075 msgid "" "Eliminates the selected asymmetries from unmasked vertices by adjusting " "vertex data to be consistent with mirror vertices." msgstr "" "Tepe noktası verilerini ayna tepe noktalarıyla tutarlı olacak şekilde " "ayarlayarak, maskelenmemiş tepe noktalarından seçilen asimetrileri ortadan " "kaldırır." #: src/program/OutfitStudio.cpp:10077 msgid "" " (Hint: To choose which non-selected bones are adjusted during weight " "normalization, unlock them in the bones list in the Bones tab.)" msgstr "" " (İpucu: Ağırlık normalleştirmesi sırasında hangi kemiklerin ayarlanacağını " "seçmek için İskeletler sekmesindeki kemikler listesinden bunların kilidini " "açmalısın.)" #: src/program/OutfitStudio.cpp:10081 msgid "Vertices that will be symmetrized:" msgstr "Simetri yapılacak tepe noktaları:" #: src/program/OutfitStudio.cpp:10082 msgid "&Symmetrize" msgstr "&Simetri" #: src/program/OutfitStudio.cpp:10231 #, c-format msgid "%d unreferenced nodes were deleted." msgstr "%d kullanılmayan bezecikler silindi." #: src/program/OutfitStudio.cpp:10446 msgid "Please enter a new unique name for the mask." msgstr "Lütfen maske için yeni bir isim belirleyin." #: src/program/OutfitStudio.cpp:10446 msgid "New Mask" msgstr "Yeni Maske" #: src/program/OutfitStudio.cpp:10631 msgid "Reset all bone poses?" msgstr "Tüm iskelet hareketleri sıfırlansın mı?" #: src/program/OutfitStudio.cpp:10631 msgid "Reset Pose" msgstr "Hareketleri Sıfırla" #: src/program/OutfitStudio.cpp:10782 msgid "Please enter a new unique name for the pose." msgstr "Lütfen yeni duruş hareketi için bir isim belirle." #: src/program/OutfitStudio.cpp:10782 msgid "New Pose" msgstr "Yeni Hareket" #: src/program/OutfitStudio.cpp:10833 #, c-format msgid "Are you sure you wish to delete the pose '%s'?" msgstr "'%s' hareketini silmek istediğinden emin misin?" #: src/program/OutfitStudio.cpp:10834 msgid "Confirm pose delete" msgstr "Hareketi silmeyi onayla" #: src/program/OutfitStudio.cpp:11741 msgid "The vertex picked has more than three connections." msgstr "Seçilen uç tepe noktasının üçten fazla bağlantısı var." #: src/program/OutfitStudio.cpp:11976 msgid "" "Neither the selected nor target vertices are on the mesh boundary. It is " "recommended that you only weld or merge boundary vertices. Continue?" msgstr "" "Ne seçim ne de hedef köşeler ağ sınırında değil. Yalnızca sınır köşelerini " "kaynaklaman veya birleştirmen önerilir. Devam edecek misin?" #: src/program/OutfitStudio.cpp:11977 msgid "" "The selected vertex is not on the mesh boundary. It is recommended that you " "only weld or merge boundary vertices. Continue?" msgstr "" "Seçilen tepe noktası ağ sınırında değil. Yalnızca sınır köşelerini " "kaynaklaman veya birleştirmen önerilir. Devam edecek misin?" #: src/program/OutfitStudio.cpp:11978 msgid "" "The target vertex is not on the mesh boundary. It is recommended that you " "only weld or merge boundary vertices. Continue?" msgstr "" "Hedef tepe noktası ağ sınırında değil. Yalnızca sınır köşelerini kaynaklaman " "veya birleştirmen önerilir. Devam edecek misin?" #: src/program/OutfitStudio.cpp:11979 msgid "Weld/Merge Non-Boundary Vertices" msgstr "Sınır Dışı Köşeleri Kaynakla/Birleştir" #: src/program/OutfitStudio.cpp:12061 msgid "The edge picked is on the surface boundary. Pick an interior edge." msgstr "Alınan kenar yüzey sınırında. Bir iç kenar seçmelisin." #: src/program/OutfitStudio.cpp:12115 msgid "" "The edge picked has multiple triangles of the same orientation. Correct the " "orientations before splitting." msgstr "" "Seçilen kenar, aynı yönelimde birden çok üçgene sahip. Bölmeden önce " "yönlerini düzeltmelisin." #: src/program/OutfitStudio.cpp:13437 src/program/OutfitStudio.cpp:13438 msgid "Loading slider file..." msgstr "Kaydırıcı dosyası yükleniyor..." #: src/program/PreviewWindow.cpp:39 msgid "Show the Normal Map Generator dialog." msgstr "Normal Harita Üreticisi konuşmasını göster." #: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:34 msgid "Preview failed: OpenGL context is not OK." msgstr "Ön izleme başarısız: OpenGL içeriği Mevcut değil." #: src/program/ShapeProperties.cpp:96 msgid "Material" msgstr "Malzeme" #: src/program/ShapeProperties.cpp:266 msgid "Choose material file" msgstr "Malzeme dosyasını seç" #: src/program/ShapeProperties.cpp:512 msgid "Please choose a shape to copy from" msgstr "Lütfen kopyalamak için bir kalıp seçimi yap" #: src/program/ShapeProperties.cpp:512 msgid "Choose shape" msgstr "Kalıp seçimi" #: src/ui/wxBrushSettingsPopup.cpp:123 msgid "Size" msgstr "Boyut" #: src/ui/wxBrushSettingsPopup.cpp:127 msgid "Shortcut: 'S' + mouse wheel" msgstr "Kısayol Tuşu: 'S' + Fare Tekerleği" #: src/ui/wxBrushSettingsPopup.cpp:136 msgid "Strength" msgstr "Kuvvet" #: src/ui/wxBrushSettingsPopup.cpp:148 msgid "Focus" msgstr "Odak" #: src/ui/wxBrushSettingsPopup.cpp:160 msgid "Spacing" msgstr "Aralık" #: src/ui/wxSliderPanel.cpp:63 msgid "Turn on edit mode for this slider." msgstr "Bu kaydırıcı için düzenleme modunu aç." #: src/ui/wxSliderPanel.cpp:75 msgid "Weaken slider data by 1%." msgstr "Kaydırıcı verilerini 1% azalt." #: src/ui/wxSliderPanel.cpp:82 msgid "Strengthen slider data by 1%." msgstr "Kaydırıcı verilerini %1 oranında güçlendir." ================================================ FILE: lang/uk/BodySlide.mo ================================================ ================================================ FILE: lang/uk/BodySlide.po ================================================ ================================================ FILE: lang/vi/BodySlide.mo ================================================ ================================================ FILE: lang/vi/BodySlide.po ================================================ ================================================ FILE: lang/xrctext.cpp ================================================ #line 5 "res/xrc/About.xrc" _("About"); #line 145 "res/xrc/About.xrc" _("Close"); #line 6 "res/xrc/Actions.xrc" _("Apply a vertex position"); #line 15 "res/xrc/Actions.xrc" _("This permanently moves a single vertex straight to the given location."); #line 93 "res/xrc/Actions.xrc" _("&OK"); #line 100 "res/xrc/Actions.xrc" _("&Cancel"); #line 110 "res/xrc/Actions.xrc" _("Move Shape"); #line 254 "res/xrc/Actions.xrc" _("Mirror Axis"); #line 302 "res/xrc/Actions.xrc" _("&OK"); #line 309 "res/xrc/Actions.xrc" _("&Cancel"); #line 320 "res/xrc/Actions.xrc" _("Scale Shape"); #line 329 "res/xrc/Actions.xrc" _("Scaling will adjust the size of a mesh. This permanently affects vertices."); #line 461 "res/xrc/Actions.xrc" _("Origin"); #line 472 "res/xrc/Actions.xrc" _("Zero (0, 0, 0)"); #line 473 "res/xrc/Actions.xrc" _("Center of selected shapes(s)"); #line 484 "res/xrc/Actions.xrc" _("Uniform (XYZ)"); #line 499 "res/xrc/Actions.xrc" _("&OK"); #line 506 "res/xrc/Actions.xrc" _("&Cancel"); #line 517 "res/xrc/Actions.xrc" _("Rotate Shape"); #line 667 "res/xrc/Actions.xrc" _("Origin"); #line 678 "res/xrc/Actions.xrc" _("Zero (0, 0, 0)"); #line 679 "res/xrc/Actions.xrc" _("Center of selected shapes(s)"); #line 694 "res/xrc/Actions.xrc" _("&OK"); #line 701 "res/xrc/Actions.xrc" _("&Cancel"); #line 712 "res/xrc/Actions.xrc" _("Inflate Shape"); #line 721 "res/xrc/Actions.xrc" _("Inflate/deflate a mesh along its normals. This permanently affects vertices."); #line 847 "res/xrc/Actions.xrc" _("Uniform (XYZ)"); #line 862 "res/xrc/Actions.xrc" _("&OK"); #line 869 "res/xrc/Actions.xrc" _("&Cancel"); #line 880 "res/xrc/Actions.xrc" _("Mirror Shape"); #line 924 "res/xrc/Actions.xrc" _("Swap bones on X axis (L/R)"); #line 938 "res/xrc/Actions.xrc" _("&OK"); #line 945 "res/xrc/Actions.xrc" _("&Cancel"); #line 956 "res/xrc/Actions.xrc" _("Smooth Seams"); #line 1014 "res/xrc/Actions.xrc" _("&OK"); #line 1021 "res/xrc/Actions.xrc" _("&Cancel"); #line 1032 "res/xrc/Actions.xrc" _("Set Shape Textures"); #line 1062 "res/xrc/Actions.xrc" _("&OK"); #line 1069 "res/xrc/Actions.xrc" _("&Cancel"); #line 1079 "res/xrc/Actions.xrc" _("Conforming..."); #line 1088 "res/xrc/Actions.xrc" _("Each vertex of the reference will copy its slider data to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become conformed and work well. Often, the default values are sufficient."); #line 1108 "res/xrc/Actions.xrc" _("Search Radius"); #line 1137 "res/xrc/Actions.xrc" _("Max Vertex Targets"); #line 1166 "res/xrc/Actions.xrc" _("No Target Limit"); #line 1189 "res/xrc/Actions.xrc" _("No Squeeze"); #line 1212 "res/xrc/Actions.xrc" _("Solid Mode"); #line 1235 "res/xrc/Actions.xrc" _("Axis"); #line 1285 "res/xrc/Actions.xrc" _("Preset"); #line 1301 "res/xrc/Actions.xrc" _("Default"); #line 1310 "res/xrc/Actions.xrc" _("Even Movement"); #line 1319 "res/xrc/Actions.xrc" _("Solid Object"); #line 1341 "res/xrc/Actions.xrc" _("&OK"); #line 1348 "res/xrc/Actions.xrc" _("&Cancel"); #line 1358 "res/xrc/Actions.xrc" _("Merge Geometry"); #line 1367 "res/xrc/Actions.xrc" _("This function copies vertices and triangles from one shape to another. Partitions/segments of source and target shapes must match. It is the user's responsibility to check that all other shape and shader properties are compatible, or merging will likely have side effects."); #line 1382 "res/xrc/Actions.xrc" _("Source"); #line 1400 "res/xrc/Actions.xrc" _("Target"); #line 1429 "res/xrc/Actions.xrc" _("Delete source shape"); #line 1442 "res/xrc/Actions.xrc" _("&OK"); #line 1449 "res/xrc/Actions.xrc" _("&Cancel"); #line 1459 "res/xrc/Actions.xrc" _("Mask symmetric vertices"); #line 1468 "res/xrc/Actions.xrc" _("Masks all vertices that do not have any of the selected asymmetries."); #line 1494 "res/xrc/Actions.xrc" _("Vertices currently unmasked:"); #line 1522 "res/xrc/Actions.xrc" _("Unmatched Vertices:"); #line 1544 "res/xrc/Actions.xrc" _("Vertex Data Asymmetries"); #line 1577 "res/xrc/Actions.xrc" _("Type"); #line 1586 "res/xrc/Actions.xrc" _("Average"); #line 1595 "res/xrc/Actions.xrc" _("Count"); #line 1613 "res/xrc/Actions.xrc" _("Position"); #line 1681 "res/xrc/Actions.xrc" _("Sliders"); #line 1728 "res/xrc/Actions.xrc" _("Bones"); #line 1747 "res/xrc/Actions.xrc" _("Vertices that will still be unmasked:"); #line 1773 "res/xrc/Actions.xrc" _("&Mask"); #line 1780 "res/xrc/Actions.xrc" _("&Cancel"); #line 5 "res/xrc/Automation.xrc" _("Automation Script"); #line 22 "res/xrc/Automation.xrc" _("Automation:"); #line 30 "res/xrc/Automation.xrc" _("Select an automation to load, or type a name for a new one"); #line 31 "res/xrc/Automation.xrc" _("Automation name..."); #line 39 "res/xrc/Automation.xrc" _("Save"); #line 40 "res/xrc/Automation.xrc" _("Save the automation script"); #line 48 "res/xrc/Automation.xrc" _("Delete"); #line 49 "res/xrc/Automation.xrc" _("Delete the current automation script"); #line 57 "res/xrc/Automation.xrc" _("Open Folder"); #line 58 "res/xrc/Automation.xrc" _("Open the Automations folder in file explorer"); #line 99 "res/xrc/Automation.xrc" _("Step Settings"); #line 114 "res/xrc/Automation.xrc" _("Type:"); #line 121 "res/xrc/Automation.xrc" _("Bones: Add Custom Bone"); #line 122 "res/xrc/Automation.xrc" _("Bones: Copy Bone Weights"); #line 123 "res/xrc/Automation.xrc" _("Bones: Delete Bones"); #line 124 "res/xrc/Automation.xrc" _("Bones: Edit Custom Bone"); #line 125 "res/xrc/Automation.xrc" _("Bones: Remove Skinning"); #line 126 "res/xrc/Automation.xrc" _("Export: File"); #line 127 "res/xrc/Automation.xrc" _("Export: Save Project"); #line 128 "res/xrc/Automation.xrc" _("Import: File"); #line 129 "res/xrc/Automation.xrc" _("Import: Slider Data"); #line 130 "res/xrc/Automation.xrc" _("Project: Add Project"); #line 131 "res/xrc/Automation.xrc" _("Project: Clear Project"); #line 132 "res/xrc/Automation.xrc" _("Project: Clear Reference"); #line 133 "res/xrc/Automation.xrc" _("Project: Load Reference"); #line 134 "res/xrc/Automation.xrc" _("Project: Set Base Shape"); #line 135 "res/xrc/Automation.xrc" _("Project: Set Reference Shape"); #line 136 "res/xrc/Automation.xrc" _("Shapes: Apply Pose"); #line 137 "res/xrc/Automation.xrc" _("Shapes: Delete Shape"); #line 138 "res/xrc/Automation.xrc" _("Shapes: Duplicate Shape"); #line 139 "res/xrc/Automation.xrc" _("Shapes: Fix Clipping"); #line 140 "res/xrc/Automation.xrc" _("Shapes: Invert UVs"); #line 141 "res/xrc/Automation.xrc" _("Shapes: Mirror Shape"); #line 142 "res/xrc/Automation.xrc" _("Shapes: Refine Mesh"); #line 143 "res/xrc/Automation.xrc" _("Shapes: Rename Shape"); #line 144 "res/xrc/Automation.xrc" _("Shapes: Reset Transforms"); #line 145 "res/xrc/Automation.xrc" _("Shapes: Transform Shape"); #line 146 "res/xrc/Automation.xrc" _("Sliders: Conform Sliders"); #line 147 "res/xrc/Automation.xrc" _("Sliders: Delete Slider"); #line 148 "res/xrc/Automation.xrc" _("Sliders: Set Slider Values"); #line 149 "res/xrc/Automation.xrc" _("Sliders: Set Slider Properties"); #line 150 "res/xrc/Automation.xrc" _("Masks: Load Mask"); #line 151 "res/xrc/Automation.xrc" _("Nodes: Remove Unused Nodes"); #line 159 "res/xrc/Automation.xrc" _("Active:"); #line 165 "res/xrc/Automation.xrc" _("Execute this step"); #line 173 "res/xrc/Automation.xrc" _("Target Shapes:"); #line 185 "res/xrc/Automation.xrc" _("Comma-separated list of shape names. Leave empty to target all shapes."); #line 186 "res/xrc/Automation.xrc" _("Comma-separated shape list"); #line 192 "res/xrc/Automation.xrc" _("Regex"); #line 193 "res/xrc/Automation.xrc" _("Use regex matching for target shape names"); #line 202 "res/xrc/Automation.xrc" _("Note:"); #line 210 "res/xrc/Automation.xrc" _("A note to describe what this step does and how to configure it."); #line 211 "res/xrc/Automation.xrc" _("Description of this step..."); #line 232 "res/xrc/Automation.xrc" _("Add Custom Bone"); #line 246 "res/xrc/Automation.xrc" _("Bone Name:"); #line 252 "res/xrc/Automation.xrc" _("Bone name"); #line 259 "res/xrc/Automation.xrc" _("Parent Bone:"); #line 265 "res/xrc/Automation.xrc" _("Name of the parent bone (leave empty for no parent)"); #line 266 "res/xrc/Automation.xrc" _("Parent bone name"); #line 273 "res/xrc/Automation.xrc" _("Translation:"); #line 314 "res/xrc/Automation.xrc" _("Rotation:"); #line 362 "res/xrc/Automation.xrc" _("Copy Bone Weights"); #line 376 "res/xrc/Automation.xrc" _("Proximity Radius:"); #line 390 "res/xrc/Automation.xrc" _("Max Results:"); #line 404 "res/xrc/Automation.xrc" _("Bone List:"); #line 410 "res/xrc/Automation.xrc" _("Comma-separated list of bone names. Leave empty to copy all bones."); #line 411 "res/xrc/Automation.xrc" _("Comma-separated bone list"); #line 425 "res/xrc/Automation.xrc" _("Delete Bones"); #line 439 "res/xrc/Automation.xrc" _("Bone Names:"); #line 445 "res/xrc/Automation.xrc" _("Comma-separated list of bone names to delete"); #line 446 "res/xrc/Automation.xrc" _("Comma-separated bone list"); #line 453 "res/xrc/Automation.xrc" _("Mode:"); #line 459 "res/xrc/Automation.xrc" _("Delete bone entirely from project"); #line 461 "res/xrc/Automation.xrc" _("If checked, deletes the bone from all shapes and the NIF. If unchecked, only removes bone weights from target shapes."); #line 475 "res/xrc/Automation.xrc" _("Edit Bone"); #line 489 "res/xrc/Automation.xrc" _("Bone Name:"); #line 495 "res/xrc/Automation.xrc" _("Name of the custom bone to edit"); #line 496 "res/xrc/Automation.xrc" _("Bone name"); #line 503 "res/xrc/Automation.xrc" _("Parent Bone:"); #line 509 "res/xrc/Automation.xrc" _("Name of the parent bone (leave empty for no parent)"); #line 510 "res/xrc/Automation.xrc" _("Parent bone name"); #line 517 "res/xrc/Automation.xrc" _("Translation:"); #line 558 "res/xrc/Automation.xrc" _("Rotation:"); #line 606 "res/xrc/Automation.xrc" _("Remove Skinning"); #line 612 "res/xrc/Automation.xrc" _("Removes skinning from target shapes (or all shapes if Target Meshes is empty).\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tThis deletes all bone weights and skinning data from the shapes."); #line 626 "res/xrc/Automation.xrc" _("Export File"); #line 640 "res/xrc/Automation.xrc" _("Export File Path:"); #line 650 "res/xrc/Automation.xrc" _("Select export file path"); #line 658 "res/xrc/Automation.xrc" _("Select export folder"); #line 668 "res/xrc/Automation.xrc" _("Options:"); #line 677 "res/xrc/Automation.xrc" _("Use original file path from batch operation"); #line 682 "res/xrc/Automation.xrc" _("Export with reference shape (.nif only)"); #line 692 "res/xrc/Automation.xrc" _("Filename Prefix:"); #line 698 "res/xrc/Automation.xrc" _("Prefix to add before the filename. Supports {{PLACEHOLDER}} variables."); #line 699 "res/xrc/Automation.xrc" _("e.g. prefix_"); #line 706 "res/xrc/Automation.xrc" _("Filename Suffix:"); #line 712 "res/xrc/Automation.xrc" _("Suffix to add after the filename before the extension. Supports {{PLACEHOLDER}} variables."); #line 713 "res/xrc/Automation.xrc" _("e.g. &suffix"); #line 727 "res/xrc/Automation.xrc" _("Save Project"); #line 733 "res/xrc/Automation.xrc" _("Use original project from batch"); #line 750 "res/xrc/Automation.xrc" _("Display Name:"); #line 756 "res/xrc/Automation.xrc" _("Name shown in BodySlide (supports {{PLACEHOLDER}} variables)"); #line 757 "res/xrc/Automation.xrc" _("Display name"); #line 764 "res/xrc/Automation.xrc" _("Output File Name:"); #line 770 "res/xrc/Automation.xrc" _("Base filename for the output NIF (supports {{PLACEHOLDER}} variables)"); #line 771 "res/xrc/Automation.xrc" _("Output filename"); #line 778 "res/xrc/Automation.xrc" _("Output Data Path:"); #line 784 "res/xrc/Automation.xrc" _("Game data path for output (supports {{PLACEHOLDER}} variables)"); #line 792 "res/xrc/Automation.xrc" _("Slider Set File:"); #line 798 "res/xrc/Automation.xrc" _("Slider set project file (.osp) (supports {{PLACEHOLDER}} variables)"); #line 806 "res/xrc/Automation.xrc" _("Shape Data Folder:"); #line 812 "res/xrc/Automation.xrc" _("Folder for slider data files (supports {{PLACEHOLDER}} variables)"); #line 820 "res/xrc/Automation.xrc" _("Shape Data File:"); #line 826 "res/xrc/Automation.xrc" _("Base NIF filename (supports {{PLACEHOLDER}} variables)"); #line 834 "res/xrc/Automation.xrc" _("Options:"); #line 843 "res/xrc/Automation.xrc" _("Generate low/high weight outputs"); #line 849 "res/xrc/Automation.xrc" _("Copy reference to output"); #line 873 "res/xrc/Automation.xrc" _("Replace (from):"); #line 879 "res/xrc/Automation.xrc" _("Text to find and replace in original project fields (batch only)"); #line 880 "res/xrc/Automation.xrc" _("Find text"); #line 887 "res/xrc/Automation.xrc" _("Replace (to):"); #line 893 "res/xrc/Automation.xrc" _("Replacement text for matching text in original project fields (batch only)"); #line 894 "res/xrc/Automation.xrc" _("Replace with"); #line 901 "res/xrc/Automation.xrc" _("Suffix:"); #line 907 "res/xrc/Automation.xrc" _("Suffix to append to Display Name, Shape Data Folder, and Shape Data File name (batch only)"); #line 908 "res/xrc/Automation.xrc" _("e.g. &modified"); #line 924 "res/xrc/Automation.xrc" _("Copy reference based on loaded project"); #line 925 "res/xrc/Automation.xrc" _("If the loaded project had a reference shape, include it in the output. Otherwise, exclude it. Overrides the option above. (batch only)"); #line 933 "res/xrc/Automation.xrc" _("Only treat these shape names as the reference (comma-separated). Leave empty to use any reference shape."); #line 934 "res/xrc/Automation.xrc" _("Comma-separated shape list"); #line 948 "res/xrc/Automation.xrc" _("Import File"); #line 962 "res/xrc/Automation.xrc" _("Mode:"); #line 968 "res/xrc/Automation.xrc" _("Import all files from folder"); #line 975 "res/xrc/Automation.xrc" _("File:"); #line 981 "res/xrc/Automation.xrc" _("Select file to import"); #line 990 "res/xrc/Automation.xrc" _("Folder:"); #line 996 "res/xrc/Automation.xrc" _("Select folder to import from"); #line 1011 "res/xrc/Automation.xrc" _("Import Slider Data"); #line 1025 "res/xrc/Automation.xrc" _("Mode:"); #line 1031 "res/xrc/Automation.xrc" _("Import all files from folder (ShapeName#SliderName.ext)"); #line 1038 "res/xrc/Automation.xrc" _("Slider Data File:"); #line 1044 "res/xrc/Automation.xrc" _("Select slider data file"); #line 1053 "res/xrc/Automation.xrc" _("Folder:"); #line 1059 "res/xrc/Automation.xrc" _("Select folder with slider data files"); #line 1067 "res/xrc/Automation.xrc" _("Options:"); #line 1073 "res/xrc/Automation.xrc" _("Merge into existing sliders"); #line 1080 "res/xrc/Automation.xrc" _("Slider Names:"); #line 1086 "res/xrc/Automation.xrc" _("Comma-separated list of slider names. Leave empty to import all sliders."); #line 1087 "res/xrc/Automation.xrc" _("Comma-separated slider list"); #line 1101 "res/xrc/Automation.xrc" _("Add Project"); #line 1115 "res/xrc/Automation.xrc" _("Source File:"); #line 1121 "res/xrc/Automation.xrc" _("Select project file"); #line 1130 "res/xrc/Automation.xrc" _("Slider Set:"); #line 1136 "res/xrc/Automation.xrc" _("Name of the slider set to add"); #line 1143 "res/xrc/Automation.xrc" _("Options:"); #line 1152 "res/xrc/Automation.xrc" _("Append new sliders"); #line 1169 "res/xrc/Automation.xrc" _("Clear Project"); #line 1175 "res/xrc/Automation.xrc" _("Clears the current project (removes all shapes, sliders, and references).\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNo additional parameters needed."); #line 1189 "res/xrc/Automation.xrc" _("Clear Reference"); #line 1195 "res/xrc/Automation.xrc" _("Removes the current reference/base shape from the project. Slider data for the reference is moved to the morpher.\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNo additional parameters needed."); #line 1209 "res/xrc/Automation.xrc" _("Load Reference"); #line 1223 "res/xrc/Automation.xrc" _("Template:"); #line 1229 "res/xrc/Automation.xrc" _("Select a reference template to auto-fill the fields below"); #line 1236 "res/xrc/Automation.xrc" _("Source File:"); #line 1242 "res/xrc/Automation.xrc" _("Select reference file"); #line 1251 "res/xrc/Automation.xrc" _("Slider Set:"); #line 1257 "res/xrc/Automation.xrc" _("Name of the slider set within the source file"); #line 1264 "res/xrc/Automation.xrc" _("Shape:"); #line 1270 "res/xrc/Automation.xrc" _("Name of the reference shape"); #line 1277 "res/xrc/Automation.xrc" _("Options:"); #line 1286 "res/xrc/Automation.xrc" _("Load all shapes"); #line 1292 "res/xrc/Automation.xrc" _("Merge sliders"); #line 1298 "res/xrc/Automation.xrc" _("Merge zaps"); #line 1304 "res/xrc/Automation.xrc" _("Append new sliders"); #line 1321 "res/xrc/Automation.xrc" _("Set Base Shape"); #line 1327 "res/xrc/Automation.xrc" _("Bakes the current slider values into the base geometry of all shapes and zeros all sliders.\n\nEquivalent to \"Slider -> Set Base Shape\" in the menu."); #line 1342 "res/xrc/Automation.xrc" _("Set Reference Shape"); #line 1356 "res/xrc/Automation.xrc" _("Shape Name:"); #line 1362 "res/xrc/Automation.xrc" _("Name of the shape to set as reference (highlighted green)."); #line 1363 "res/xrc/Automation.xrc" _("Shape name"); #line 1373 "res/xrc/Automation.xrc" _("Unset Reference"); #line 1374 "res/xrc/Automation.xrc" _("Unset the reference shape instead of setting one. Morph data will be moved."); #line 1388 "res/xrc/Automation.xrc" _("Apply Pose"); #line 1402 "res/xrc/Automation.xrc" _("Pose Name:"); #line 1408 "res/xrc/Automation.xrc" _("Name of the pose from PoseData to apply to meshes"); #line 1409 "res/xrc/Automation.xrc" _("Pose name"); #line 1423 "res/xrc/Automation.xrc" _("Delete Shape"); #line 1429 "res/xrc/Automation.xrc" _("Deletes the shapes specified in the Target Meshes field above.\n\nIf Target Meshes is empty, all non-reference shapes are deleted. Use Regex mode for pattern matching."); #line 1444 "res/xrc/Automation.xrc" _("Duplicate Shape"); #line 1458 "res/xrc/Automation.xrc" _("New Name:"); #line 1464 "res/xrc/Automation.xrc" _("Name for the duplicated shape. Supports {{PLACEHOLDER}} variables."); #line 1465 "res/xrc/Automation.xrc" _("New shape name"); #line 1479 "res/xrc/Automation.xrc" _("Fix Clipping"); #line 1493 "res/xrc/Automation.xrc" _("Mode:"); #line 1500 "res/xrc/Automation.xrc" _("Shapes"); #line 1501 "res/xrc/Automation.xrc" _("Sliders"); #line 1504 "res/xrc/Automation.xrc" _("Shapes: fix base geometry of target shapes. Sliders: fix clipping for each slider individually."); #line 1511 "res/xrc/Automation.xrc" _("Strength (0 - 100):"); #line 1518 "res/xrc/Automation.xrc" _("Clipping fix strength between 0 and 100."); #line 1526 "res/xrc/Automation.xrc" _("Slider Names:"); #line 1532 "res/xrc/Automation.xrc" _("Comma-separated list of slider names to fix clipping for (Sliders mode only). Leave empty to process all non-zap/non-UV sliders."); #line 1533 "res/xrc/Automation.xrc" _("Comma-separated slider list"); #line 1547 "res/xrc/Automation.xrc" _("Invert UVs"); #line 1556 "res/xrc/Automation.xrc" _("Invert U"); #line 1563 "res/xrc/Automation.xrc" _("Invert V"); #line 1577 "res/xrc/Automation.xrc" _("Mirror Shape"); #line 1586 "res/xrc/Automation.xrc" _("Mirror X"); #line 1594 "res/xrc/Automation.xrc" _("Mirror Y"); #line 1601 "res/xrc/Automation.xrc" _("Mirror Z"); #line 1608 "res/xrc/Automation.xrc" _("Swap bones left/right (X axis)"); #line 1622 "res/xrc/Automation.xrc" _("Refine Mesh"); #line 1628 "res/xrc/Automation.xrc" _("Subdivides/refines meshes by splitting edges.\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAll unmasked vertices are refined. Use the Target Meshes field above to select which shapes to refine."); #line 1642 "res/xrc/Automation.xrc" _("Rename Shape"); #line 1656 "res/xrc/Automation.xrc" _("Old Name:"); #line 1662 "res/xrc/Automation.xrc" _("Current name of the shape (supports {{PLACEHOLDER}} variables)"); #line 1663 "res/xrc/Automation.xrc" _("Current shape name"); #line 1670 "res/xrc/Automation.xrc" _("New Name:"); #line 1676 "res/xrc/Automation.xrc" _("New name for the shape (supports {{PLACEHOLDER}} variables)"); #line 1677 "res/xrc/Automation.xrc" _("New shape name"); #line 1691 "res/xrc/Automation.xrc" _("Reset Transforms"); #line 1697 "res/xrc/Automation.xrc" _("Resets global-to-skin transforms for all skinned meshes. No additional parameters needed."); #line 1710 "res/xrc/Automation.xrc" _("Transform Shape"); #line 1724 "res/xrc/Automation.xrc" _("Move:"); #line 1731 "res/xrc/Automation.xrc" _("Move X"); #line 1739 "res/xrc/Automation.xrc" _("Move Y"); #line 1747 "res/xrc/Automation.xrc" _("Move Z"); #line 1755 "res/xrc/Automation.xrc" _("Rotate (°):"); #line 1762 "res/xrc/Automation.xrc" _("Rotate X (degrees)"); #line 1770 "res/xrc/Automation.xrc" _("Rotate Y (degrees)"); #line 1778 "res/xrc/Automation.xrc" _("Rotate Z (degrees)"); #line 1786 "res/xrc/Automation.xrc" _("Scale:"); #line 1793 "res/xrc/Automation.xrc" _("Scale X"); #line 1801 "res/xrc/Automation.xrc" _("Scale Y"); #line 1809 "res/xrc/Automation.xrc" _("Scale Z"); #line 1817 "res/xrc/Automation.xrc" _("Inflate:"); #line 1824 "res/xrc/Automation.xrc" _("Inflate X (along normals)"); #line 1832 "res/xrc/Automation.xrc" _("Inflate Y (along normals)"); #line 1840 "res/xrc/Automation.xrc" _("Inflate Z (along normals)"); #line 1855 "res/xrc/Automation.xrc" _("Conform Sliders"); #line 1869 "res/xrc/Automation.xrc" _("Proximity Radius:"); #line 1883 "res/xrc/Automation.xrc" _("Max Results:"); #line 1897 "res/xrc/Automation.xrc" _("Options:"); #line 1906 "res/xrc/Automation.xrc" _("No squeeze"); #line 1911 "res/xrc/Automation.xrc" _("Solid mode"); #line 1920 "res/xrc/Automation.xrc" _("Axes:"); #line 1931 "res/xrc/Automation.xrc" _("X"); #line 1939 "res/xrc/Automation.xrc" _("Y"); #line 1945 "res/xrc/Automation.xrc" _("Z"); #line 1955 "res/xrc/Automation.xrc" _("Slider Names:"); #line 1961 "res/xrc/Automation.xrc" _("Comma-separated list of slider names to conform. Leave empty to conform all visible sliders."); #line 1962 "res/xrc/Automation.xrc" _("Comma-separated slider list"); #line 1976 "res/xrc/Automation.xrc" _("Delete Slider"); #line 1990 "res/xrc/Automation.xrc" _("Slider Name:"); #line 1996 "res/xrc/Automation.xrc" _("Name of the slider to delete. If regex is checked, matches slider names by pattern."); #line 1997 "res/xrc/Automation.xrc" _("Slider name or pattern"); #line 2004 "res/xrc/Automation.xrc" _("Regex:"); #line 2010 "res/xrc/Automation.xrc" _("Match slider names by regex pattern"); #line 2024 "res/xrc/Automation.xrc" _("Set Slider Values"); #line 2038 "res/xrc/Automation.xrc" _("Slider Names:"); #line 2044 "res/xrc/Automation.xrc" _("Comma-separated list of slider names. Leave empty to set all visible sliders."); #line 2045 "res/xrc/Automation.xrc" _("Comma-separated slider list"); #line 2052 "res/xrc/Automation.xrc" _("Value (0 - 100):"); #line 2059 "res/xrc/Automation.xrc" _("Slider value between 0 and 100 (percentage)"); #line 2074 "res/xrc/Automation.xrc" _("Set Slider Properties"); #line 2088 "res/xrc/Automation.xrc" _("Slider Names:"); #line 2094 "res/xrc/Automation.xrc" _("Comma-separated list of slider names. Leave empty to apply to all sliders."); #line 2095 "res/xrc/Automation.xrc" _("Comma-separated slider list"); #line 2102 "res/xrc/Automation.xrc" _("Zap:"); #line 2109 "res/xrc/Automation.xrc" _("No change"); #line 2110 "res/xrc/Automation.xrc" _("No"); #line 2111 "res/xrc/Automation.xrc" _("Yes"); #line 2113 "res/xrc/Automation.xrc" _("Set the zap flag on matching sliders."); #line 2120 "res/xrc/Automation.xrc" _("Hidden:"); #line 2127 "res/xrc/Automation.xrc" _("No change"); #line 2128 "res/xrc/Automation.xrc" _("No"); #line 2129 "res/xrc/Automation.xrc" _("Yes"); #line 2131 "res/xrc/Automation.xrc" _("Set the hidden flag on matching sliders."); #line 2138 "res/xrc/Automation.xrc" _("Default Zapped:"); #line 2145 "res/xrc/Automation.xrc" _("No change"); #line 2146 "res/xrc/Automation.xrc" _("Not zapped"); #line 2147 "res/xrc/Automation.xrc" _("Zapped"); #line 2149 "res/xrc/Automation.xrc" _("Whether matching zap sliders are zapped by default."); #line 2155 "res/xrc/Automation.xrc" _("Default (Small):"); #line 2161 "res/xrc/Automation.xrc" _("Default small value (0-100). Leave empty for no change."); #line 2169 "res/xrc/Automation.xrc" _("Default (Big):"); #line 2175 "res/xrc/Automation.xrc" _("Default big value (0-100). Leave empty for no change."); #line 2190 "res/xrc/Automation.xrc" _("Load Mask"); #line 2204 "res/xrc/Automation.xrc" _("Mask File:"); #line 2210 "res/xrc/Automation.xrc" _("Select a mask XML file"); #line 2219 "res/xrc/Automation.xrc" _("Mask Name:"); #line 2225 "res/xrc/Automation.xrc" _("Select a mask entry from the loaded mask file."); #line 2239 "res/xrc/Automation.xrc" _("Remove Unused Nodes"); #line 2245 "res/xrc/Automation.xrc" _("Removes all unreferenced nodes from the NIF."); #line 2265 "res/xrc/Automation.xrc" _("Placeholder Variables"); #line 2274 "res/xrc/Automation.xrc" _("Define {{KEY}} = Value pairs. These are substituted in all text fields before execution."); #line 2291 "res/xrc/Automation.xrc" _("Key:"); #line 2297 "res/xrc/Automation.xrc" _("Value:"); #line 2304 "res/xrc/Automation.xrc" _("KEY"); #line 2310 "res/xrc/Automation.xrc" _("Value"); #line 2323 "res/xrc/Automation.xrc" _("+ Add"); #line 2331 "res/xrc/Automation.xrc" _("- Remove"); #line 2348 "res/xrc/Automation.xrc" _("Batch Operation"); #line 2358 "res/xrc/Automation.xrc" _("Mode"); #line 2361 "res/xrc/Automation.xrc" _("None (run on current project)"); #line 2362 "res/xrc/Automation.xrc" _("Folder scan (repeat on files in folder)"); #line 2363 "res/xrc/Automation.xrc" _("Slider sets (repeat on installed slider sets)"); #line 2377 "res/xrc/Automation.xrc" _("Folder Scan Settings"); #line 2390 "res/xrc/Automation.xrc" _("Folder:"); #line 2396 "res/xrc/Automation.xrc" _("Select folder to scan"); #line 2404 "res/xrc/Automation.xrc" _("Extension:"); #line 2411 "res/xrc/Automation.xrc" _("File extension to scan for (e.g. .nif, .obj)"); #line 2419 "res/xrc/Automation.xrc" _("Options:"); #line 2425 "res/xrc/Automation.xrc" _("Include subdirectories"); #line 2432 "res/xrc/Automation.xrc" _("File Filter:"); #line 2444 "res/xrc/Automation.xrc" _("Filter file/folder names (substring or regex)"); #line 2445 "res/xrc/Automation.xrc" _("Filter pattern..."); #line 2451 "res/xrc/Automation.xrc" _("Regex"); #line 2470 "res/xrc/Automation.xrc" _("Slider Set Settings"); #line 2483 "res/xrc/Automation.xrc" _("Filter:"); #line 2495 "res/xrc/Automation.xrc" _("Filter slider set names (substring or regex). Leave empty for all."); #line 2496 "res/xrc/Automation.xrc" _("Filter pattern..."); #line 2502 "res/xrc/Automation.xrc" _("Regex"); #line 2526 "res/xrc/Automation.xrc" _("Output Log"); #line 2543 "res/xrc/Automation.xrc" _("Execute"); #line 2544 "res/xrc/Automation.xrc" _("Execute all active steps in order"); #line 2554 "res/xrc/Automation.xrc" _("Close"); #line 6 "res/xrc/BatchBuild.xrc" _("Batch Build"); #line 21 "res/xrc/BatchBuild.xrc" _("Select the slider sets for the batch build process. Use the group and outfit filters to show the outfits you want!"); #line 50 "res/xrc/BatchBuild.xrc" _("&Build"); #line 57 "res/xrc/BatchBuild.xrc" _("&Cancel"); #line 67 "res/xrc/BatchBuild.xrc" _("Choose output set"); #line 78 "res/xrc/BatchBuild.xrc" _("The following sets will override the same files.\nPlease decide which one to use and select it in the list below."); #line 88 "res/xrc/BatchBuild.xrc" _("Type and hit enter to choose output..."); #line 114 "res/xrc/BatchBuild.xrc" _("&Preview"); #line 115 "res/xrc/BatchBuild.xrc" _("Open a preview window showing the conflicting outfits for the selected group"); #line 127 "res/xrc/BatchBuild.xrc" _("&OK"); #line 135 "res/xrc/BatchBuild.xrc" _("&Cancel"); #line 7 "res/xrc/BodySlide.xrc" _("BodySlide"); #line 28 "res/xrc/BodySlide.xrc" _("Outfit/Body"); #line 44 "res/xrc/BodySlide.xrc" _("Select an outfit to modify"); #line 58 "res/xrc/BodySlide.xrc" _("Deletes a project from its project file"); #line 74 "res/xrc/BodySlide.xrc" _("Opens the current project in Outfit Studio"); #line 97 "res/xrc/BodySlide.xrc" _("Preset"); #line 113 "res/xrc/BodySlide.xrc" _("Choose from a list of slider settings presets"); #line 127 "res/xrc/BodySlide.xrc" _("Deletes a preset from its preset file"); #line 142 "res/xrc/BodySlide.xrc" _("Saves the new slider values to the currently selected preset"); #line 143 "res/xrc/BodySlide.xrc" _("Save"); #line 153 "res/xrc/BodySlide.xrc" _("Save the current slider settings as a new preset"); #line 154 "res/xrc/BodySlide.xrc" _("Save As..."); #line 165 "res/xrc/BodySlide.xrc" _("Opens the group manager where you can edit existing or create new groups"); #line 166 "res/xrc/BodySlide.xrc" _("Group Manager"); #line 240 "res/xrc/BodySlide.xrc" _("Single Weight"); #line 267 "res/xrc/BodySlide.xrc" _("Low Weight"); #line 284 "res/xrc/BodySlide.xrc" _("High Weight"); #line 325 "res/xrc/BodySlide.xrc" _("Copy the low weight slider values to the high weight section."); #line 342 "res/xrc/BodySlide.xrc" _("Default outfit choice in Batch Build"); #line 353 "res/xrc/BodySlide.xrc" _("Output Path (which the game would use for this outfit)"); #line 365 "res/xrc/BodySlide.xrc" _("(right-click to view alternatives)"); #line 385 "res/xrc/BodySlide.xrc" _("Build multiple outfits using the currently active slider values.\n\nHold CTRL = Build to custom directory\nHold ALT = Delete from output directory"); #line 386 "res/xrc/BodySlide.xrc" _("Batch Build..."); #line 401 "res/xrc/BodySlide.xrc" _("Build Morphs"); #line 402 "res/xrc/BodySlide.xrc" _("Builds a morphs (.tri) file alongside the meshes for accessing the sliders in-game. Requires other mods to make use of the morph data."); #line 412 "res/xrc/BodySlide.xrc" _("Force Body Normals"); #line 413 "res/xrc/BodySlide.xrc" _("Adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod."); #line 432 "res/xrc/BodySlide.xrc" _("Fix Clipping"); #line 442 "res/xrc/BodySlide.xrc" _("Controls how far outfit vertices are pushed away from the body surface."); #line 460 "res/xrc/BodySlide.xrc" _("Show a preview window for this outfit."); #line 461 "res/xrc/BodySlide.xrc" _("Preview"); #line 479 "res/xrc/BodySlide.xrc" _("Creates the currently selected outfit/body.\n\nHold CTRL = Build to working directory\nHold ALT = Delete from output directory"); #line 480 "res/xrc/BodySlide.xrc" _("Build"); #line 492 "res/xrc/BodySlide.xrc" _("Copy the high weight slider values to the low weight section."); #line 510 "res/xrc/BodySlide.xrc" _("About"); #line 519 "res/xrc/BodySlide.xrc" _("Open settings dialog."); #line 520 "res/xrc/BodySlide.xrc" _("Settings"); #line 529 "res/xrc/BodySlide.xrc" _("Open Outfit Studio, a full-featured tool for creating and converting outfits."); #line 530 "res/xrc/BodySlide.xrc" _("Outfit Studio"); #line 540 "res/xrc/BodySlide.xrc" _("Filter Options"); #line 542 "res/xrc/BodySlide.xrc" _("Choose groups..."); #line 543 "res/xrc/BodySlide.xrc" _("Choose groups to display in the Outfit menu"); #line 547 "res/xrc/BodySlide.xrc" _("Refresh Groups"); #line 548 "res/xrc/BodySlide.xrc" _("Refresh group information"); #line 552 "res/xrc/BodySlide.xrc" _("Filter Options"); #line 554 "res/xrc/BodySlide.xrc" _("Refresh Outfits"); #line 555 "res/xrc/BodySlide.xrc" _("Reloads outfit list"); #line 559 "res/xrc/BodySlide.xrc" _("Regular Expressions"); #line 560 "res/xrc/BodySlide.xrc" _("Allow the use of regular expressions (regex) for filtering."); #line 564 "res/xrc/BodySlide.xrc" _("Has Zap Options"); #line 565 "res/xrc/BodySlide.xrc" _("Show only outfits that have zap options."); #line 570 "res/xrc/BodySlide.xrc" _("Browse outfit folder..."); #line 571 "res/xrc/BodySlide.xrc" _("Browses to the shape data folder of the current outfit in the file explorer."); #line 574 "res/xrc/BodySlide.xrc" _("Save Outfit list as group..."); #line 575 "res/xrc/BodySlide.xrc" _("Save the current filtered outfit list as a group"); #line 580 "res/xrc/BodySlide.xrc" _("Select None"); #line 583 "res/xrc/BodySlide.xrc" _("Select All"); #line 586 "res/xrc/BodySlide.xrc" _("Invert Selection"); #line 6 "res/xrc/ConvertBodyReference.xrc" _("Convert / Replace Body Reference"); #line 16 "res/xrc/ConvertBodyReference.xrc" _("This wizard aids in the conversion to another body/reference.."); #line 25 "res/xrc/ConvertBodyReference.xrc" _("Reference Bodies"); #line 36 "res/xrc/ConvertBodyReference.xrc" _("Select a conversion reference (or 'None' to skip converting):"); #line 58 "res/xrc/ConvertBodyReference.xrc" _("Conversion Body Reference"); #line 78 "res/xrc/ConvertBodyReference.xrc" _("Select a body reference to convert to:"); #line 100 "res/xrc/ConvertBodyReference.xrc" _("New Body Reference"); #line 130 "res/xrc/ConvertBodyReference.xrc" _("Options"); #line 136 "res/xrc/ConvertBodyReference.xrc" _("Merge Sliders"); #line 145 "res/xrc/ConvertBodyReference.xrc" _("Merge Zaps"); #line 165 "res/xrc/ConvertBodyReference.xrc" _("Conform Sliders"); #line 174 "res/xrc/ConvertBodyReference.xrc" _("Skip conform popup (use default settings)"); #line 183 "res/xrc/ConvertBodyReference.xrc" _("Copy Bone Weights"); #line 192 "res/xrc/ConvertBodyReference.xrc" _("Skip bone weights popup (use default settings)"); #line 203 "res/xrc/ConvertBodyReference.xrc" _("Delete reference after completion"); #line 219 "res/xrc/ConvertBodyReference.xrc" _("This wizard aids in the conversion to another body/reference.."); #line 228 "res/xrc/ConvertBodyReference.xrc" _("Rename Project (optional)"); #line 239 "res/xrc/ConvertBodyReference.xrc" _("Specify text to be removed from the project name (comma-delimited):"); #line 260 "res/xrc/ConvertBodyReference.xrc" _("Remove from project name"); #line 277 "res/xrc/ConvertBodyReference.xrc" _("Specify any text to be prepended to project name:"); #line 298 "res/xrc/ConvertBodyReference.xrc" _("Prepend to project name"); #line 315 "res/xrc/ConvertBodyReference.xrc" _("NOTE: Game file output path is unaffected by this"); #line 326 "res/xrc/ConvertBodyReference.xrc" _("Extras (optional)"); #line 337 "res/xrc/ConvertBodyReference.xrc" _("Remove the following shapes before conversion (comma-delimited):"); #line 359 "res/xrc/ConvertBodyReference.xrc" _("Shapes to delete"); #line 375 "res/xrc/ConvertBodyReference.xrc" _("Add the following bones after conversion (comma-delimited):"); #line 396 "res/xrc/ConvertBodyReference.xrc" _("Bones to add"); #line 5 "res/xrc/EditUV.xrc" _("Edit UV"); #line 32 "res/xrc/EditUV.xrc" _("&OK"); #line 39 "res/xrc/EditUV.xrc" _("&Cancel"); #line 52 "res/xrc/EditUV.xrc" _("Box Selection"); #line 53 "res/xrc/EditUV.xrc" _("Box Selection\nShortcut: 1"); #line 60 "res/xrc/EditUV.xrc" _("Vertex Selection"); #line 61 "res/xrc/EditUV.xrc" _("Vertex Selection\nShortcut: 2"); #line 67 "res/xrc/EditUV.xrc" _("Move"); #line 68 "res/xrc/EditUV.xrc" _("Move\nShortcut: 3"); #line 74 "res/xrc/EditUV.xrc" _("Scale"); #line 75 "res/xrc/EditUV.xrc" _("Scale\nShortcut: 4"); #line 81 "res/xrc/EditUV.xrc" _("Rotate"); #line 82 "res/xrc/EditUV.xrc" _("Rotate\nShortcut: 5"); #line 88 "res/xrc/EditUV.xrc" _("Show Seam Edges"); #line 89 "res/xrc/EditUV.xrc" _("Show Seam Edges"); #line 97 "res/xrc/EditUV.xrc" _("Menu"); #line 99 "res/xrc/EditUV.xrc" _("File"); #line 101 "res/xrc/EditUV.xrc" _("Export UV Template...\tCtrl+E"); #line 102 "res/xrc/EditUV.xrc" _("Export the UV layout as an image file."); #line 106 "res/xrc/EditUV.xrc" _("Edit"); #line 108 "res/xrc/EditUV.xrc" _("Undo\tCtrl+Z"); #line 109 "res/xrc/EditUV.xrc" _("Undo the previous action."); #line 112 "res/xrc/EditUV.xrc" _("Redo\tCtrl+Y"); #line 113 "res/xrc/EditUV.xrc" _("Redo the next undone action."); #line 117 "res/xrc/EditUV.xrc" _("Select All\tCtrl+A"); #line 118 "res/xrc/EditUV.xrc" _("Select All"); #line 121 "res/xrc/EditUV.xrc" _("Invert Selection\tCtrl+I"); #line 122 "res/xrc/EditUV.xrc" _("Invert Selection"); #line 125 "res/xrc/EditUV.xrc" _("Select Less\tA"); #line 126 "res/xrc/EditUV.xrc" _("Select less adjacent points in the selected islands."); #line 129 "res/xrc/EditUV.xrc" _("Select More\tD"); #line 130 "res/xrc/EditUV.xrc" _("Select more adjacent points in the selected islands."); #line 134 "res/xrc/EditUV.xrc" _("Mask Selection"); #line 135 "res/xrc/EditUV.xrc" _("Create a mask from the current UV selection for the mesh in the main viewport."); #line 139 "res/xrc/EditUV.xrc" _("Translate...\tT"); #line 140 "res/xrc/EditUV.xrc" _("Show a dialog to translate the current selection."); #line 143 "res/xrc/EditUV.xrc" _("Rotate...\tR"); #line 144 "res/xrc/EditUV.xrc" _("Show a dialog to rotate the current selection."); #line 147 "res/xrc/EditUV.xrc" _("Scale...\tS"); #line 148 "res/xrc/EditUV.xrc" _("Show a dialog to scale the current selection."); #line 155 "res/xrc/EditUV.xrc" _("Translate"); #line 258 "res/xrc/EditUV.xrc" _("&OK"); #line 265 "res/xrc/EditUV.xrc" _("&Cancel"); #line 275 "res/xrc/EditUV.xrc" _("Rotate"); #line 296 "res/xrc/EditUV.xrc" _("Angle"); #line 333 "res/xrc/EditUV.xrc" _("&OK"); #line 340 "res/xrc/EditUV.xrc" _("&Cancel"); #line 350 "res/xrc/EditUV.xrc" _("Scale"); #line 439 "res/xrc/EditUV.xrc" _("Uniform (UV)"); #line 454 "res/xrc/EditUV.xrc" _("&OK"); #line 461 "res/xrc/EditUV.xrc" _("&Cancel"); #line 470 "res/xrc/EditUV.xrc" _("Export UV Template"); #line 487 "res/xrc/EditUV.xrc" _("Resolution"); #line 507 "res/xrc/EditUV.xrc" _("Wire Color"); #line 520 "res/xrc/EditUV.xrc" _("Background Color"); #line 535 "res/xrc/EditUV.xrc" _("Transparent Background"); #line 545 "res/xrc/EditUV.xrc" _("Include Texture"); #line 553 "res/xrc/EditUV.xrc" _("Wrap Mode"); #line 561 "res/xrc/EditUV.xrc" _("Wrap"); #line 562 "res/xrc/EditUV.xrc" _("Clamp"); #line 573 "res/xrc/EditUV.xrc" _("Anti-Aliasing"); #line 588 "res/xrc/EditUV.xrc" _("&OK"); #line 595 "res/xrc/EditUV.xrc" _("&Cancel"); #line 7 "res/xrc/GroupManager.xrc" _("Group Manager"); #line 17 "res/xrc/GroupManager.xrc" _("Choose a group and add or remove members by selecting them in the lists."); #line 33 "res/xrc/GroupManager.xrc" _("Select a group XML file"); #line 44 "res/xrc/GroupManager.xrc" _("Save"); #line 53 "res/xrc/GroupManager.xrc" _("Save As..."); #line 71 "res/xrc/GroupManager.xrc" _("Groups"); #line 101 "res/xrc/GroupManager.xrc" _("Add Group"); #line 110 "res/xrc/GroupManager.xrc" _("Remove Group"); #line 122 "res/xrc/GroupManager.xrc" _("Members"); #line 137 "res/xrc/GroupManager.xrc" _("Remove >>"); #line 151 "res/xrc/GroupManager.xrc" _("Outfits"); #line 172 "res/xrc/GroupManager.xrc" _("<< Add"); #line 189 "res/xrc/GroupManager.xrc" _("Close"); #line 5 "res/xrc/ImportDialog.xrc" _("Import Options..."); #line 53 "res/xrc/ImportDialog.xrc" _("Invert U"); #line 62 "res/xrc/ImportDialog.xrc" _("Invert V"); #line 71 "res/xrc/ImportDialog.xrc" _("Scale"); #line 89 "res/xrc/ImportDialog.xrc" _("Rotate (X)"); #line 98 "res/xrc/ImportDialog.xrc" _("Choose X rotation."); #line 113 "res/xrc/ImportDialog.xrc" _("Rotate (Y)"); #line 122 "res/xrc/ImportDialog.xrc" _("Choose Y rotation."); #line 137 "res/xrc/ImportDialog.xrc" _("Rotate (Z)"); #line 146 "res/xrc/ImportDialog.xrc" _("Choose Z rotation."); #line 174 "res/xrc/ImportDialog.xrc" _("&OK"); #line 181 "res/xrc/ImportDialog.xrc" _("&Cancel"); #line 6 "res/xrc/NormalsGenDlg.xrc" _("Normal Map Generator"); #line 21 "res/xrc/NormalsGenDlg.xrc" _("Layers"); #line 37 "res/xrc/NormalsGenDlg.xrc" _("Load or save preset layer settings."); #line 61 "res/xrc/NormalsGenDlg.xrc" _("Add a new layer after the current one in the layer list."); #line 62 "res/xrc/NormalsGenDlg.xrc" _("Add Layer"); #line 71 "res/xrc/NormalsGenDlg.xrc" _("Move selected layer up one position."); #line 72 "res/xrc/NormalsGenDlg.xrc" _("Move Up"); #line 87 "res/xrc/NormalsGenDlg.xrc" _("Delete the selected layer."); #line 88 "res/xrc/NormalsGenDlg.xrc" _("Delete Layer"); #line 108 "res/xrc/NormalsGenDlg.xrc" _("Options"); #line 114 "res/xrc/NormalsGenDlg.xrc" _("Save a copy of an existing normal map if one already exists. File is saved in the original directory."); #line 115 "res/xrc/NormalsGenDlg.xrc" _("Backup destination file"); #line 124 "res/xrc/NormalsGenDlg.xrc" _("Compress output file using BC7 compression. This can make saving the file take a VERY long time!"); #line 125 "res/xrc/NormalsGenDlg.xrc" _("Compress output "); #line 134 "res/xrc/NormalsGenDlg.xrc" _("Use the file name specified in the background layer to save the normal map."); #line 135 "res/xrc/NormalsGenDlg.xrc" _("Save to background layer file"); #line 145 "res/xrc/NormalsGenDlg.xrc" _("Choose an output file..."); #line 149 "res/xrc/NormalsGenDlg.xrc" _("Location to save normal map to."); #line 165 "res/xrc/NormalsGenDlg.xrc" _("Display current settings on mesh in preview window."); #line 166 "res/xrc/NormalsGenDlg.xrc" _("Preview"); #line 181 "res/xrc/NormalsGenDlg.xrc" _("Generate and save the normal map file."); #line 182 "res/xrc/NormalsGenDlg.xrc" _("Generate"); #line 191 "res/xrc/NormalsGenDlg.xrc" _("Preset"); #line 193 "res/xrc/NormalsGenDlg.xrc" _("Load Preset..."); #line 197 "res/xrc/NormalsGenDlg.xrc" _("Save Preset..."); #line 7 "res/xrc/OutfitStudio.xrc" _("Outfit Studio"); #line 22 "res/xrc/OutfitStudio.xrc" _("New Project"); #line 23 "res/xrc/OutfitStudio.xrc" _("Create a new project by selecting a reference body slider set, and outfit model files."); #line 28 "res/xrc/OutfitStudio.xrc" _("Load Project"); #line 29 "res/xrc/OutfitStudio.xrc" _("Load a previously created slider set for editing."); #line 34 "res/xrc/OutfitStudio.xrc" _("Undo"); #line 35 "res/xrc/OutfitStudio.xrc" _("Undo a previous action."); #line 41 "res/xrc/OutfitStudio.xrc" _("Redo"); #line 42 "res/xrc/OutfitStudio.xrc" _("Redo the next undone action."); #line 49 "res/xrc/OutfitStudio.xrc" _("Select"); #line 50 "res/xrc/OutfitStudio.xrc" _("Navigate and select meshes (or vertices in vertex mode)."); #line 57 "res/xrc/OutfitStudio.xrc" _("Mask"); #line 58 "res/xrc/OutfitStudio.xrc" _("Mask vertices to prevent them from being transformed.\nHold down the ALT key to remove masking."); #line 64 "res/xrc/OutfitStudio.xrc" _("Inflate"); #line 65 "res/xrc/OutfitStudio.xrc" _("Increase mesh volume in an area."); #line 71 "res/xrc/OutfitStudio.xrc" _("Deflate"); #line 72 "res/xrc/OutfitStudio.xrc" _("Decrease mesh volume in an area."); #line 78 "res/xrc/OutfitStudio.xrc" _("Move"); #line 79 "res/xrc/OutfitStudio.xrc" _("Move vertices over a plane parallel to the view."); #line 85 "res/xrc/OutfitStudio.xrc" _("Smooth"); #line 86 "res/xrc/OutfitStudio.xrc" _("Smooth an area of a mesh."); #line 92 "res/xrc/OutfitStudio.xrc" _("Undiff"); #line 93 "res/xrc/OutfitStudio.xrc" _("Undiff an area of a slider."); #line 99 "res/xrc/OutfitStudio.xrc" _("Weight Paint"); #line 100 "res/xrc/OutfitStudio.xrc" _("Apply animation weight values for currently selected bone.\nHold down the ALT key to weaken the weighting."); #line 107 "res/xrc/OutfitStudio.xrc" _("Color Paint"); #line 108 "res/xrc/OutfitStudio.xrc" _("Apply vertex colors.\nHold down the ALT key to remove colors."); #line 115 "res/xrc/OutfitStudio.xrc" _("Alpha Paint"); #line 116 "res/xrc/OutfitStudio.xrc" _("Apply vertex alpha.\nHold down the ALT key to remove alpha."); #line 123 "res/xrc/OutfitStudio.xrc" _("Collapse Vertex"); #line 124 "res/xrc/OutfitStudio.xrc" _("Deletes vertices with no more than three connections, without creating a hole."); #line 130 "res/xrc/OutfitStudio.xrc" _("Flip Edge"); #line 131 "res/xrc/OutfitStudio.xrc" _("Flips mesh edges so that the opposite pair of vertices is connected."); #line 137 "res/xrc/OutfitStudio.xrc" _("Split Edge"); #line 138 "res/xrc/OutfitStudio.xrc" _("Splits a mesh edge in two with a new vertex."); #line 144 "res/xrc/OutfitStudio.xrc" _("Move Vertex"); #line 145 "res/xrc/OutfitStudio.xrc" _("Moves a vertex."); #line 152 "res/xrc/OutfitStudio.xrc" _("Depth Clip"); #line 154 "res/xrc/OutfitStudio.xrc" _("Simulates lower depth buffer precision to help with depth-related clipping"); #line 161 "res/xrc/OutfitStudio.xrc" _("Field of View"); #line 165 "res/xrc/OutfitStudio.xrc" _("Field of View: 65"); #line 170 "res/xrc/OutfitStudio.xrc" _("Brush Settings"); #line 175 "res/xrc/OutfitStudio.xrc" _("Open Discord invite link."); #line 180 "res/xrc/OutfitStudio.xrc" _("Open GitHub link."); #line 185 "res/xrc/OutfitStudio.xrc" _("Open PayPal link."); #line 206 "res/xrc/OutfitStudio.xrc" _("Transform"); #line 207 "res/xrc/OutfitStudio.xrc" _("Shows a transform tool to manipulate shapes and vertices with."); #line 213 "res/xrc/OutfitStudio.xrc" _("Pivot"); #line 214 "res/xrc/OutfitStudio.xrc" _("Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale."); #line 220 "res/xrc/OutfitStudio.xrc" _("Vertex Edit"); #line 221 "res/xrc/OutfitStudio.xrc" _("Lets you select vertices to add to or remove from the mask.\nClick on a vertex to select/unmask it.\nHold down CTRL to unselect/mask it."); #line 228 "res/xrc/OutfitStudio.xrc" _("View Front"); #line 229 "res/xrc/OutfitStudio.xrc" _("Change camera view to the front."); #line 233 "res/xrc/OutfitStudio.xrc" _("View Back"); #line 234 "res/xrc/OutfitStudio.xrc" _("Change camera view to the back."); #line 238 "res/xrc/OutfitStudio.xrc" _("View Left"); #line 239 "res/xrc/OutfitStudio.xrc" _("Change camera view to the left."); #line 243 "res/xrc/OutfitStudio.xrc" _("View Right"); #line 244 "res/xrc/OutfitStudio.xrc" _("Change camera view to the right."); #line 248 "res/xrc/OutfitStudio.xrc" _("Perspective View"); #line 249 "res/xrc/OutfitStudio.xrc" _("Toggle perspective view."); #line 255 "res/xrc/OutfitStudio.xrc" _("Show Nodes"); #line 256 "res/xrc/OutfitStudio.xrc" _("Toggle rendering of nodes."); #line 261 "res/xrc/OutfitStudio.xrc" _("Show Bones"); #line 262 "res/xrc/OutfitStudio.xrc" _("Toggle rendering of bones."); #line 267 "res/xrc/OutfitStudio.xrc" _("Show Floor"); #line 268 "res/xrc/OutfitStudio.xrc" _("Toggle rendering of the floor grid."); #line 274 "res/xrc/OutfitStudio.xrc" _("X Mirror"); #line 275 "res/xrc/OutfitStudio.xrc" _("Mirror edits across the X axis."); #line 282 "res/xrc/OutfitStudio.xrc" _("Edit Connected Only\tC"); #line 283 "res/xrc/OutfitStudio.xrc" _("Edit only vertices that are connected to the ones under the brush within the brush radius."); #line 289 "res/xrc/OutfitStudio.xrc" _("Merge Vertex"); #line 290 "res/xrc/OutfitStudio.xrc" _("Merges two vertices and fills any gaps."); #line 296 "res/xrc/OutfitStudio.xrc" _("Weld Vertex"); #line 297 "res/xrc/OutfitStudio.xrc" _("Welds two vertices while keeping the texture coordinates (UV) distinct."); #line 303 "res/xrc/OutfitStudio.xrc" _("Restrict To Surface"); #line 304 "res/xrc/OutfitStudio.xrc" _("Restricts motion to a mesh surface."); #line 310 "res/xrc/OutfitStudio.xrc" _("Restrict To Plane"); #line 311 "res/xrc/OutfitStudio.xrc" _("Restricts motion to parallel to the surface."); #line 317 "res/xrc/OutfitStudio.xrc" _("Restrict To Normal"); #line 318 "res/xrc/OutfitStudio.xrc" _("Restricts motion to perpendicular to the surface."); #line 381 "res/xrc/OutfitStudio.xrc" _("Meshes"); #line 393 "res/xrc/OutfitStudio.xrc" _("Bones"); #line 405 "res/xrc/OutfitStudio.xrc" _("Segments"); #line 417 "res/xrc/OutfitStudio.xrc" _("Partitions"); #line 429 "res/xrc/OutfitStudio.xrc" _("Colors"); #line 441 "res/xrc/OutfitStudio.xrc" _("Lights"); #line 481 "res/xrc/OutfitStudio.xrc" _("Total Bones: 0"); #line 491 "res/xrc/OutfitStudio.xrc" _("Shape Selection Bones: 0"); #line 521 "res/xrc/OutfitStudio.xrc" _("Brush Color"); #line 530 "res/xrc/OutfitStudio.xrc" _("Color of the brush."); #line 552 "res/xrc/OutfitStudio.xrc" _("Clamp Max Value"); #line 595 "res/xrc/OutfitStudio.xrc" _("Edit Alpha"); #line 604 "res/xrc/OutfitStudio.xrc" _("Mask matching color"); #line 650 "res/xrc/OutfitStudio.xrc" _("Reset"); #line 663 "res/xrc/OutfitStudio.xrc" _("Ambient"); #line 688 "res/xrc/OutfitStudio.xrc" _("Frontal"); #line 713 "res/xrc/OutfitStudio.xrc" _("Directional 1"); #line 738 "res/xrc/OutfitStudio.xrc" _("Directional 2"); #line 763 "res/xrc/OutfitStudio.xrc" _("Directional 3"); #line 808 "res/xrc/OutfitStudio.xrc" _("Type"); #line 931 "res/xrc/OutfitStudio.xrc" _("Slot"); #line 1006 "res/xrc/OutfitStudio.xrc" _("SSF File"); #line 1026 "res/xrc/OutfitStudio.xrc" _("Set"); #line 1044 "res/xrc/OutfitStudio.xrc" _("Apply"); #line 1054 "res/xrc/OutfitStudio.xrc" _("Reset"); #line 1072 "res/xrc/OutfitStudio.xrc" _("Type"); #line 1145 "res/xrc/OutfitStudio.xrc" _("Apply"); #line 1155 "res/xrc/OutfitStudio.xrc" _("Reset"); #line 1173 "res/xrc/OutfitStudio.xrc" _("De-/Select Sliders"); #line 1192 "res/xrc/OutfitStudio.xrc" _("Fixed Weight Brush"); #line 1203 "res/xrc/OutfitStudio.xrc" _("Normalize Weights"); #line 1220 "res/xrc/OutfitStudio.xrc" _("X-Mirror Bone"); #line 1245 "res/xrc/OutfitStudio.xrc" _("Masks"); #line 1272 "res/xrc/OutfitStudio.xrc" _("Save"); #line 1281 "res/xrc/OutfitStudio.xrc" _("Delete"); #line 1297 "res/xrc/OutfitStudio.xrc" _("Export..."); #line 1306 "res/xrc/OutfitStudio.xrc" _("Import..."); #line 1322 "res/xrc/OutfitStudio.xrc" _("Posing"); #line 1349 "res/xrc/OutfitStudio.xrc" _("Save"); #line 1358 "res/xrc/OutfitStudio.xrc" _("Save As..."); #line 1367 "res/xrc/OutfitStudio.xrc" _("Delete"); #line 1383 "res/xrc/OutfitStudio.xrc" _("Show Pose"); #line 1401 "res/xrc/OutfitStudio.xrc" _("Reset Bone"); #line 1421 "res/xrc/OutfitStudio.xrc" _("Rotation X"); #line 1449 "res/xrc/OutfitStudio.xrc" _("Rotation Y"); #line 1477 "res/xrc/OutfitStudio.xrc" _("Rotation Z"); #line 1505 "res/xrc/OutfitStudio.xrc" _("Offset X"); #line 1533 "res/xrc/OutfitStudio.xrc" _("Offset Y"); #line 1561 "res/xrc/OutfitStudio.xrc" _("Offset Z"); #line 1590 "res/xrc/OutfitStudio.xrc" _("Scale"); #line 1623 "res/xrc/OutfitStudio.xrc" _("Reset All"); #line 1631 "res/xrc/OutfitStudio.xrc" _("Apply to Mesh"); #line 1659 "res/xrc/OutfitStudio.xrc" _("Notes"); #line 1696 "res/xrc/OutfitStudio.xrc" _("Menu"); #line 1698 "res/xrc/OutfitStudio.xrc" _("File"); #line 1700 "res/xrc/OutfitStudio.xrc" _("New Project...\tCtrl+N"); #line 1701 "res/xrc/OutfitStudio.xrc" _("Create a new outfit project."); #line 1704 "res/xrc/OutfitStudio.xrc" _("Load Project..\tCtrl+O"); #line 1705 "res/xrc/OutfitStudio.xrc" _("Load a project."); #line 1708 "res/xrc/OutfitStudio.xrc" _("Add Project..\tCtrl+Shift+O"); #line 1709 "res/xrc/OutfitStudio.xrc" _("Add a project without replacing the current one."); #line 1712 "res/xrc/OutfitStudio.xrc" _("Unload Project...\tCtrl+W"); #line 1713 "res/xrc/OutfitStudio.xrc" _("Unloads the project and creates an empty new one."); #line 1716 "res/xrc/OutfitStudio.xrc" _("Recent Projects..."); #line 1721 "res/xrc/OutfitStudio.xrc" _("Load Reference..."); #line 1722 "res/xrc/OutfitStudio.xrc" _("Load a new reference slider set, replacing any current reference objects."); #line 1725 "res/xrc/OutfitStudio.xrc" _("Load Outfit..."); #line 1726 "res/xrc/OutfitStudio.xrc" _("Load a NIF file as the working outfit, replacing any current outfit objects."); #line 1730 "res/xrc/OutfitStudio.xrc" _("Convert / Replace Reference...\tCtrl+Shift+R"); #line 1731 "res/xrc/OutfitStudio.xrc" _("Convert to or replace an outfit's body/reference"); #line 1734 "res/xrc/OutfitStudio.xrc" _("Open Automation...\tCtrl+Shift+A"); #line 1735 "res/xrc/OutfitStudio.xrc" _("Open the automation dialog to create, load and execute automation scripts."); #line 1739 "res/xrc/OutfitStudio.xrc" _("Save Project\tCtrl+S"); #line 1740 "res/xrc/OutfitStudio.xrc" _("Save the project."); #line 1744 "res/xrc/OutfitStudio.xrc" _("Save Project As...\tCtrl+Shift+S"); #line 1745 "res/xrc/OutfitStudio.xrc" _("Save the project under a new name."); #line 1749 "res/xrc/OutfitStudio.xrc" _("Import"); #line 1751 "res/xrc/OutfitStudio.xrc" _("From NIF..."); #line 1752 "res/xrc/OutfitStudio.xrc" _("Choose a NIF file to import into the project."); #line 1755 "res/xrc/OutfitStudio.xrc" _("From OBJ..."); #line 1756 "res/xrc/OutfitStudio.xrc" _("Import an OBJ file as a new shape in the outfit."); #line 1759 "res/xrc/OutfitStudio.xrc" _("From FBX..."); #line 1760 "res/xrc/OutfitStudio.xrc" _("Import an FBX file as a new shape in the outfit."); #line 1763 "res/xrc/OutfitStudio.xrc" _("From TRI (Head)..."); #line 1764 "res/xrc/OutfitStudio.xrc" _("Import shape and morphs from a head TRI file."); #line 1767 "res/xrc/OutfitStudio.xrc" _("Import Data"); #line 1769 "res/xrc/OutfitStudio.xrc" _("Import BSClothExtraData From HKX"); #line 1770 "res/xrc/OutfitStudio.xrc" _("Choose an HKX file to import as a BSClothExtraData block into the project."); #line 1775 "res/xrc/OutfitStudio.xrc" _("Export"); #line 1777 "res/xrc/OutfitStudio.xrc" _("To NIF...\tCtrl+E"); #line 1778 "res/xrc/OutfitStudio.xrc" _("Save the current project as a NIF file (without reference)"); #line 1781 "res/xrc/OutfitStudio.xrc" _("To NIF With Reference...\tCtrl+Alt+E"); #line 1782 "res/xrc/OutfitStudio.xrc" _("Save the current project as a NIF file (including reference)"); #line 1785 "res/xrc/OutfitStudio.xrc" _("To OBJ..."); #line 1786 "res/xrc/OutfitStudio.xrc" _("Export the current project as an OBJ file."); #line 1789 "res/xrc/OutfitStudio.xrc" _("To FBX..."); #line 1790 "res/xrc/OutfitStudio.xrc" _("Export the current project as an FBX file."); #line 1793 "res/xrc/OutfitStudio.xrc" _("To TRI (Head)..."); #line 1794 "res/xrc/OutfitStudio.xrc" _("Export head morphs to a TRI file."); #line 1797 "res/xrc/OutfitStudio.xrc" _("Export Data"); #line 1799 "res/xrc/OutfitStudio.xrc" _("Export BSClothExtraData As HKX"); #line 1800 "res/xrc/OutfitStudio.xrc" _("Save one of the currently loaded BSClothExtraData blocks to an HKX file."); #line 1805 "res/xrc/OutfitStudio.xrc" _("Make Conversion Reference"); #line 1806 "res/xrc/OutfitStudio.xrc" _("Using the current slider settings for the reference shape, create a new reference that will morph from the current shape back to the base shape."); #line 1810 "res/xrc/OutfitStudio.xrc" _("Pack Projects..."); #line 1811 "res/xrc/OutfitStudio.xrc" _("Pack one or more projects into a folder or archive for sharing."); #line 1814 "res/xrc/OutfitStudio.xrc" _("Settings"); #line 1815 "res/xrc/OutfitStudio.xrc" _("Open settings dialog."); #line 1818 "res/xrc/OutfitStudio.xrc" _("Exit\tAlt+F4"); #line 1819 "res/xrc/OutfitStudio.xrc" _("Exit Outfit Studio."); #line 1823 "res/xrc/OutfitStudio.xrc" _("Edit"); #line 1825 "res/xrc/OutfitStudio.xrc" _("Undo\tCtrl+Z"); #line 1826 "res/xrc/OutfitStudio.xrc" _("Undo the previous action."); #line 1829 "res/xrc/OutfitStudio.xrc" _("Redo\tCtrl+Y"); #line 1830 "res/xrc/OutfitStudio.xrc" _("Redo the next undone action."); #line 1834 "res/xrc/OutfitStudio.xrc" _("X Mirror\tX"); #line 1835 "res/xrc/OutfitStudio.xrc" _("Mirror edits across the X axis."); #line 1841 "res/xrc/OutfitStudio.xrc" _("Edit Connected Only\tC"); #line 1842 "res/xrc/OutfitStudio.xrc" _("Edit only vertices that are connected to the ones under the brush within the brush radius"); #line 1848 "res/xrc/OutfitStudio.xrc" _("Merge Vertex"); #line 1849 "res/xrc/OutfitStudio.xrc" _("Merges two vertices and fills any gaps."); #line 1855 "res/xrc/OutfitStudio.xrc" _("Weld Vertex"); #line 1856 "res/xrc/OutfitStudio.xrc" _("Welds two vertices while keeping the texture coordinates (UV) distinct."); #line 1862 "res/xrc/OutfitStudio.xrc" _("Restrict To Surface"); #line 1863 "res/xrc/OutfitStudio.xrc" _("Restricts motion to a mesh surface."); #line 1869 "res/xrc/OutfitStudio.xrc" _("Restrict To Plane"); #line 1870 "res/xrc/OutfitStudio.xrc" _("Restricts motion to parallel to the surface."); #line 1876 "res/xrc/OutfitStudio.xrc" _("Restrict To Normal"); #line 1877 "res/xrc/OutfitStudio.xrc" _("Restricts motion to perpendicular to the surface."); #line 1884 "res/xrc/OutfitStudio.xrc" _("Recalculate Normals"); #line 1885 "res/xrc/OutfitStudio.xrc" _("Recalculate normals on active mesh"); #line 1888 "res/xrc/OutfitStudio.xrc" _("Disable Normals Calculation"); #line 1889 "res/xrc/OutfitStudio.xrc" _("Turn off all automatic recalculation of normals on all meshes. Only applies to Outfit Studio."); #line 1894 "res/xrc/OutfitStudio.xrc" _("Reset Transforms"); #line 1895 "res/xrc/OutfitStudio.xrc" _("Resets the shape and skin transforms."); #line 1898 "res/xrc/OutfitStudio.xrc" _("Delete Unreferenced Nodes"); #line 1899 "res/xrc/OutfitStudio.xrc" _("Deletes all nodes from the project that aren't used in any other block."); #line 1902 "res/xrc/OutfitStudio.xrc" _("Remove Skinning"); #line 1903 "res/xrc/OutfitStudio.xrc" _("Removes skinning of all shapes and all unused nodes."); #line 1907 "res/xrc/OutfitStudio.xrc" _("Shape"); #line 1909 "res/xrc/OutfitStudio.xrc" _("Export"); #line 1911 "res/xrc/OutfitStudio.xrc" _("To NIF..."); #line 1912 "res/xrc/OutfitStudio.xrc" _("Export only the selected shapes to a NIF file."); #line 1915 "res/xrc/OutfitStudio.xrc" _("To OBJ..."); #line 1916 "res/xrc/OutfitStudio.xrc" _("Export only the selected shapes to an OBJ file."); #line 1919 "res/xrc/OutfitStudio.xrc" _("To FBX..."); #line 1920 "res/xrc/OutfitStudio.xrc" _("Export only the selected shapes to an FBX file."); #line 1923 "res/xrc/OutfitStudio.xrc" _("To TRI (Head)..."); #line 1924 "res/xrc/OutfitStudio.xrc" _("Export head morphs to a TRI file."); #line 1928 "res/xrc/OutfitStudio.xrc" _("UV"); #line 1930 "res/xrc/OutfitStudio.xrc" _("Edit..."); #line 1931 "res/xrc/OutfitStudio.xrc" _("Edit the texture coordinates."); #line 1934 "res/xrc/OutfitStudio.xrc" _("Invert X (Mirror)"); #line 1935 "res/xrc/OutfitStudio.xrc" _("Inverts the X-axis to mirror the texture coordinates."); #line 1938 "res/xrc/OutfitStudio.xrc" _("Invert Y (Flip)"); #line 1939 "res/xrc/OutfitStudio.xrc" _("Inverts the Y-axis to flip the texture coordinates."); #line 1943 "res/xrc/OutfitStudio.xrc" _("Delete Vertices...\tShift+Del"); #line 1944 "res/xrc/OutfitStudio.xrc" _("Deletes all unmasked vertices of the currently selected shapes."); #line 1947 "res/xrc/OutfitStudio.xrc" _("Separate Vertices...\tShift+S"); #line 1948 "res/xrc/OutfitStudio.xrc" _("Separate the current shape into two by using the mask."); #line 1951 "res/xrc/OutfitStudio.xrc" _("Mirror Shape..."); #line 1952 "res/xrc/OutfitStudio.xrc" _("Mirror the selected shapes on any axis."); #line 1955 "res/xrc/OutfitStudio.xrc" _("Merge Geometry..."); #line 1956 "res/xrc/OutfitStudio.xrc" _("Copies vertices and triangles from one shape to another."); #line 1959 "res/xrc/OutfitStudio.xrc" _("Duplicate..."); #line 1960 "res/xrc/OutfitStudio.xrc" _("Duplicate the current shape."); #line 1963 "res/xrc/OutfitStudio.xrc" _("Refine Mesh"); #line 1964 "res/xrc/OutfitStudio.xrc" _("Splits all edges between unmasked vertices"); #line 1967 "res/xrc/OutfitStudio.xrc" _("Rename...\tF2"); #line 1968 "res/xrc/OutfitStudio.xrc" _("Change the name of the current shape."); #line 1971 "res/xrc/OutfitStudio.xrc" _("Set Reference"); #line 1972 "res/xrc/OutfitStudio.xrc" _("Turn the shape into the reference shape of the project."); #line 1976 "res/xrc/OutfitStudio.xrc" _("Move..."); #line 1977 "res/xrc/OutfitStudio.xrc" _("Apply an offset adjustment to the mesh vertices. This permanently moves vertices."); #line 1980 "res/xrc/OutfitStudio.xrc" _("Scale..."); #line 1981 "res/xrc/OutfitStudio.xrc" _("Apply a scale adjustment to the shape. This permanently moves vertices."); #line 1984 "res/xrc/OutfitStudio.xrc" _("Rotate..."); #line 1985 "res/xrc/OutfitStudio.xrc" _("Apply a rotation to the mesh vertices. This permanently moves vertices."); #line 1988 "res/xrc/OutfitStudio.xrc" _("Inflate..."); #line 1989 "res/xrc/OutfitStudio.xrc" _("Inflates/deflates a shape along its normals. This permanently moves vertices."); #line 1992 "res/xrc/OutfitStudio.xrc" _("Fix Clipping..."); #line 1993 "res/xrc/OutfitStudio.xrc" _("Fixes clipping of outfit vertices that penetrate the reference shape."); #line 1997 "res/xrc/OutfitStudio.xrc" _("Normals"); #line 1999 "res/xrc/OutfitStudio.xrc" _("Smooth Seam Normals"); #line 2000 "res/xrc/OutfitStudio.xrc" _("Smooths edges of seams (usually found at texture borders), disable if this causes odd normals on the shape."); #line 2005 "res/xrc/OutfitStudio.xrc" _("Edit Smoothing Angle..."); #line 2006 "res/xrc/OutfitStudio.xrc" _("Angle, in degrees, that controls the threshold at which normal seams are smoothed."); #line 2009 "res/xrc/OutfitStudio.xrc" _("Lock Normals"); #line 2010 "res/xrc/OutfitStudio.xrc" _("Locks the mesh normals. Enable if you want to keep custom normals intact."); #line 2017 "res/xrc/OutfitStudio.xrc" _("Copy Bone Weights"); #line 2018 "res/xrc/OutfitStudio.xrc" _("Copies all bone weights from the reference shape to the current shape."); #line 2021 "res/xrc/OutfitStudio.xrc" _("Transfer Selected Weights"); #line 2022 "res/xrc/OutfitStudio.xrc" _("Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order."); #line 2025 "res/xrc/OutfitStudio.xrc" _("Mask Weighted Vertices"); #line 2026 "res/xrc/OutfitStudio.xrc" _("Masks vertices with bone weights, so you can manually assign weights to unweighted vertices."); #line 2029 "res/xrc/OutfitStudio.xrc" _("Check For Bad Bones..."); #line 2030 "res/xrc/OutfitStudio.xrc" _("Looks for bones with inconsistencies in their transforms. If any are found, a dialog is opened to give options for fixing them."); #line 2034 "res/xrc/OutfitStudio.xrc" _("Copy Partitions/Segments..."); #line 2035 "res/xrc/OutfitStudio.xrc" _("Copies partitions/segments and all triangle assignments from the reference shape to the current shape."); #line 2039 "res/xrc/OutfitStudio.xrc" _("Mask Symmetric Vertices..."); #line 2040 "res/xrc/OutfitStudio.xrc" _("Masks unmasked vertices that have a mirrored vertex with identical data."); #line 2043 "res/xrc/OutfitStudio.xrc" _("Symmetrize Vertices..."); #line 2044 "res/xrc/OutfitStudio.xrc" _("Changes vertex data to be identical to mirrored vertices."); #line 2047 "res/xrc/OutfitStudio.xrc" _("Mask Symmetric Triangles"); #line 2048 "res/xrc/OutfitStudio.xrc" _("Masks triangles that can be matched to a mirrored triangle."); #line 2052 "res/xrc/OutfitStudio.xrc" _("Delete\tDel"); #line 2053 "res/xrc/OutfitStudio.xrc" _("Removes the currently selected shape from the outfit."); #line 2059 "res/xrc/OutfitStudio.xrc" _("Properties..."); #line 2060 "res/xrc/OutfitStudio.xrc" _("Opens the properties dialog for shader, texture and more settings of the selected shape."); #line 2064 "res/xrc/OutfitStudio.xrc" _("Slider"); #line 2066 "res/xrc/OutfitStudio.xrc" _("Conform Selected\tCtrl+C"); #line 2067 "res/xrc/OutfitStudio.xrc" _("Conform selected outfit shape to all checked sliders."); #line 2070 "res/xrc/OutfitStudio.xrc" _("Conform All\tCtrl+Shift+C"); #line 2071 "res/xrc/OutfitStudio.xrc" _("Conform all outfit shapes to all checked sliders."); #line 2074 "res/xrc/OutfitStudio.xrc" _("Fix Clipping..."); #line 2075 "res/xrc/OutfitStudio.xrc" _("Fixes clipping of outfit vertices that penetrate the reference shape for the active slider."); #line 2079 "res/xrc/OutfitStudio.xrc" _("Set Base Shape"); #line 2080 "res/xrc/OutfitStudio.xrc" _("Set the current outfit shape as the base shape and clear slider data."); #line 2084 "res/xrc/OutfitStudio.xrc" _("Load Preset..."); #line 2085 "res/xrc/OutfitStudio.xrc" _("Load and preview a slider preset. Inverted sliders will have inverted values."); #line 2088 "res/xrc/OutfitStudio.xrc" _("Save Preset..."); #line 2089 "res/xrc/OutfitStudio.xrc" _("Save a slider preset with the current values. Inverted sliders will have inverted values."); #line 2093 "res/xrc/OutfitStudio.xrc" _("New Slider"); #line 2094 "res/xrc/OutfitStudio.xrc" _("Create a new shape transformation slider."); #line 2097 "res/xrc/OutfitStudio.xrc" _("Coalesce sliders"); #line 2098 "res/xrc/OutfitStudio.xrc" _("Create a new shape transformation slider based on the current slider values"); #line 2101 "res/xrc/OutfitStudio.xrc" _("New Zap Slider"); #line 2102 "res/xrc/OutfitStudio.xrc" _("Create a new Zap slider based on unmasked vertices"); #line 2106 "res/xrc/OutfitStudio.xrc" _("Import"); #line 2108 "res/xrc/OutfitStudio.xrc" _("Import OSD..."); #line 2109 "res/xrc/OutfitStudio.xrc" _("Imports OSD file and creates sliders for shapes with a matching name."); #line 2112 "res/xrc/OutfitStudio.xrc" _("Import TRI Morphs..."); #line 2113 "res/xrc/OutfitStudio.xrc" _("Imports TRI morphs from a TRI file and creates sliders for shapes with a matching name."); #line 2116 "res/xrc/OutfitStudio.xrc" _("Import Starfield morphs..."); #line 2117 "res/xrc/OutfitStudio.xrc" _("Imports Starfield morph.dat file and creates sliders for shapes with a matching name."); #line 2121 "res/xrc/OutfitStudio.xrc" _("Import to active slider"); #line 2123 "res/xrc/OutfitStudio.xrc" _("Import NIF..."); #line 2124 "res/xrc/OutfitStudio.xrc" _("Import a NIF file and overwrites the current shape's slider data."); #line 2127 "res/xrc/OutfitStudio.xrc" _("Import BSD..."); #line 2128 "res/xrc/OutfitStudio.xrc" _("Import a BodySlide BSD file and overwrites the current shape's slider data."); #line 2131 "res/xrc/OutfitStudio.xrc" _("Import OBJ..."); #line 2132 "res/xrc/OutfitStudio.xrc" _("Import an OBJ file matching the current shape's vertex count, and calculate slider data from the difference."); #line 2135 "res/xrc/OutfitStudio.xrc" _("Import FBX..."); #line 2136 "res/xrc/OutfitStudio.xrc" _("Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference."); #line 2142 "res/xrc/OutfitStudio.xrc" _("Export"); #line 2144 "res/xrc/OutfitStudio.xrc" _("Export OSD..."); #line 2145 "res/xrc/OutfitStudio.xrc" _("Exports all currently loaded slider data to an OSD file."); #line 2148 "res/xrc/OutfitStudio.xrc" _("Export TRI Morphs..."); #line 2149 "res/xrc/OutfitStudio.xrc" _("Exports TRI morphs to a TRI file."); #line 2152 "res/xrc/OutfitStudio.xrc" _("Export Starfield morphs..."); #line 2153 "res/xrc/OutfitStudio.xrc" _("Exports Starfield morph.dat file."); #line 2156 "res/xrc/OutfitStudio.xrc" _("Export to OBJs..."); #line 2157 "res/xrc/OutfitStudio.xrc" _("Export all sliders to an OBJ file per slider."); #line 2161 "res/xrc/OutfitStudio.xrc" _("Export active slider"); #line 2163 "res/xrc/OutfitStudio.xrc" _("Export NIF..."); #line 2164 "res/xrc/OutfitStudio.xrc" _("Exports the current slider's data as a NIF file."); #line 2167 "res/xrc/OutfitStudio.xrc" _("Export BSD..."); #line 2168 "res/xrc/OutfitStudio.xrc" _("Exports the current slider's data as a BodySlide BSD file."); #line 2171 "res/xrc/OutfitStudio.xrc" _("Export OBJ..."); #line 2172 "res/xrc/OutfitStudio.xrc" _("Exports the current slider's data as an OBJ file."); #line 2179 "res/xrc/OutfitStudio.xrc" _("Clone Slider"); #line 2180 "res/xrc/OutfitStudio.xrc" _("Clones the current slider."); #line 2184 "res/xrc/OutfitStudio.xrc" _("Negate Slider"); #line 2185 "res/xrc/OutfitStudio.xrc" _("Negates the current slider, reversing it's effect"); #line 2189 "res/xrc/OutfitStudio.xrc" _("Mask Affected Vertices"); #line 2190 "res/xrc/OutfitStudio.xrc" _("Masks the vertices the slider is affecting for all selected shapes."); #line 2194 "res/xrc/OutfitStudio.xrc" _("Clear Slider Data"); #line 2195 "res/xrc/OutfitStudio.xrc" _("Erases the slider data without removing the slider itself. (Cannot be undone)"); #line 2198 "res/xrc/OutfitStudio.xrc" _("Delete Slider\tCtrl+Del"); #line 2199 "res/xrc/OutfitStudio.xrc" _("Delete the active slider from the project. (Cannot be undone)"); #line 2203 "res/xrc/OutfitStudio.xrc" _("Properties...\tTab"); #line 2204 "res/xrc/OutfitStudio.xrc" _("Display and edit the active slider's properties."); #line 2209 "res/xrc/OutfitStudio.xrc" _("Tool"); #line 2211 "res/xrc/OutfitStudio.xrc" _("Current Tool"); #line 2213 "res/xrc/OutfitStudio.xrc" _("Select"); #line 2214 "res/xrc/OutfitStudio.xrc" _("Navigate and select meshes (or vertices in vertex mode)."); #line 2218 "res/xrc/OutfitStudio.xrc" _("Mask"); #line 2219 "res/xrc/OutfitStudio.xrc" _("Mask vertices to prevent them from being transformed.\nHold down the ALT key to remove masking."); #line 2223 "res/xrc/OutfitStudio.xrc" _("Inflate"); #line 2224 "res/xrc/OutfitStudio.xrc" _("Increase mesh volume in an area."); #line 2229 "res/xrc/OutfitStudio.xrc" _("Deflate"); #line 2230 "res/xrc/OutfitStudio.xrc" _("Decrease mesh volume in an area."); #line 2234 "res/xrc/OutfitStudio.xrc" _("Move"); #line 2235 "res/xrc/OutfitStudio.xrc" _("Move vertices over a plane parallel to the view."); #line 2239 "res/xrc/OutfitStudio.xrc" _("Smooth"); #line 2240 "res/xrc/OutfitStudio.xrc" _("Smooth an area of a mesh."); #line 2244 "res/xrc/OutfitStudio.xrc" _("Undiff"); #line 2245 "res/xrc/OutfitStudio.xrc" _("Undiff an area of a slider."); #line 2249 "res/xrc/OutfitStudio.xrc" _("Weight Paint"); #line 2250 "res/xrc/OutfitStudio.xrc" _("Apply animation weight values for the currently selected bone.\nHold down the ALT key to weaken the weighting."); #line 2255 "res/xrc/OutfitStudio.xrc" _("Color Paint"); #line 2256 "res/xrc/OutfitStudio.xrc" _("Apply vertex colors.\nHold down the ALT key to remove colors."); #line 2261 "res/xrc/OutfitStudio.xrc" _("Alpha Paint"); #line 2262 "res/xrc/OutfitStudio.xrc" _("Apply vertex alpha.\nHold down the ALT key to remove alpha."); #line 2267 "res/xrc/OutfitStudio.xrc" _("Collapse Vertex"); #line 2268 "res/xrc/OutfitStudio.xrc" _("Deletes vertices with no more than three connections, without creating a hole."); #line 2272 "res/xrc/OutfitStudio.xrc" _("Flip Edge"); #line 2273 "res/xrc/OutfitStudio.xrc" _("Flips mesh edges so that the opposite pair of vertices is connected."); #line 2277 "res/xrc/OutfitStudio.xrc" _("Split Edge"); #line 2278 "res/xrc/OutfitStudio.xrc" _("Splits a mesh edge in two with a new vertex."); #line 2282 "res/xrc/OutfitStudio.xrc" _("Move Vertex"); #line 2283 "res/xrc/OutfitStudio.xrc" _("Moves a vertex."); #line 2288 "res/xrc/OutfitStudio.xrc" _("Transform\tF"); #line 2289 "res/xrc/OutfitStudio.xrc" _("Shows a transform tool to manipulate shapes and vertices with."); #line 2293 "res/xrc/OutfitStudio.xrc" _("Pivot\tP"); #line 2294 "res/xrc/OutfitStudio.xrc" _("Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale."); #line 2298 "res/xrc/OutfitStudio.xrc" _("Vertex Edit\tQ"); #line 2299 "res/xrc/OutfitStudio.xrc" _("Shows vertex points and lets you mask/unmask them.\nWithout any brush active, click on a vertex to unmask it.\nHold down CTRL to mask it."); #line 2304 "res/xrc/OutfitStudio.xrc" _("Increase Brush Size\tShift++"); #line 2305 "res/xrc/OutfitStudio.xrc" _("Increase brush diameter"); #line 2308 "res/xrc/OutfitStudio.xrc" _("Decrease Brush Size\tShift+-"); #line 2309 "res/xrc/OutfitStudio.xrc" _("Decrease brush diameter"); #line 2312 "res/xrc/OutfitStudio.xrc" _("Increase Brush Strength\tCtrl++"); #line 2313 "res/xrc/OutfitStudio.xrc" _("Increase brush strength"); #line 2316 "res/xrc/OutfitStudio.xrc" _("Decrease Brush Strength\tCtrl+-"); #line 2317 "res/xrc/OutfitStudio.xrc" _("Decrease brush strength"); #line 2321 "res/xrc/OutfitStudio.xrc" _("Mask Less\tA"); #line 2322 "res/xrc/OutfitStudio.xrc" _("Mask Less"); #line 2325 "res/xrc/OutfitStudio.xrc" _("Mask More\tD"); #line 2326 "res/xrc/OutfitStudio.xrc" _("Mask More"); #line 2330 "res/xrc/OutfitStudio.xrc" _("Invert Mask\tCtrl+I"); #line 2331 "res/xrc/OutfitStudio.xrc" _("Invert Mask"); #line 2334 "res/xrc/OutfitStudio.xrc" _("Clear Mask\tCtrl+A"); #line 2335 "res/xrc/OutfitStudio.xrc" _("Clear Mask"); #line 2339 "res/xrc/OutfitStudio.xrc" _("View"); #line 2341 "res/xrc/OutfitStudio.xrc" _("Front\tShift+1"); #line 2344 "res/xrc/OutfitStudio.xrc" _("Back\tShift+2"); #line 2347 "res/xrc/OutfitStudio.xrc" _("Left\tShift+3"); #line 2350 "res/xrc/OutfitStudio.xrc" _("Right\tShift+4"); #line 2353 "res/xrc/OutfitStudio.xrc" _("Perspective\tShift+5"); #line 2358 "res/xrc/OutfitStudio.xrc" _("Toggle Rotation Center\tShift+R"); #line 2359 "res/xrc/OutfitStudio.xrc" _("Switch between the different rotation center modes."); #line 2362 "res/xrc/OutfitStudio.xrc" _("Show Nodes\tShift+N"); #line 2366 "res/xrc/OutfitStudio.xrc" _("Show Bones\tShift+B"); #line 2370 "res/xrc/OutfitStudio.xrc" _("Show Floor\tG"); #line 2375 "res/xrc/OutfitStudio.xrc" _("Toggle Visibility\tE"); #line 2376 "res/xrc/OutfitStudio.xrc" _("Switch between the different visibility modes for the selected shapes."); #line 2379 "res/xrc/OutfitStudio.xrc" _("Show Wireframe\tW"); #line 2380 "res/xrc/OutfitStudio.xrc" _("Show wireframe on all models."); #line 2384 "res/xrc/OutfitStudio.xrc" _("Enable Lighting\tL"); #line 2385 "res/xrc/OutfitStudio.xrc" _("Turn on or off lighting."); #line 2390 "res/xrc/OutfitStudio.xrc" _("Enable Textures\tT"); #line 2391 "res/xrc/OutfitStudio.xrc" _("Display texture maps on models."); #line 2396 "res/xrc/OutfitStudio.xrc" _("Enable Vertex Colors"); #line 2397 "res/xrc/OutfitStudio.xrc" _("Display vertex colors on models."); #line 2405 "res/xrc/OutfitStudio.xrc" _("Shape"); #line 2407 "res/xrc/OutfitStudio.xrc" _("Export"); #line 2409 "res/xrc/OutfitStudio.xrc" _("To NIF..."); #line 2410 "res/xrc/OutfitStudio.xrc" _("Export only the selected shapes to a NIF file."); #line 2413 "res/xrc/OutfitStudio.xrc" _("To OBJ..."); #line 2414 "res/xrc/OutfitStudio.xrc" _("Export only the selected shapes to an OBJ file."); #line 2417 "res/xrc/OutfitStudio.xrc" _("To FBX..."); #line 2418 "res/xrc/OutfitStudio.xrc" _("Export only the selected shapes to an FBX file."); #line 2421 "res/xrc/OutfitStudio.xrc" _("To TRI (Head)..."); #line 2422 "res/xrc/OutfitStudio.xrc" _("Export head morphs to a TRI file."); #line 2426 "res/xrc/OutfitStudio.xrc" _("UV"); #line 2428 "res/xrc/OutfitStudio.xrc" _("Edit..."); #line 2429 "res/xrc/OutfitStudio.xrc" _("Edit the texture coordinates."); #line 2432 "res/xrc/OutfitStudio.xrc" _("Invert X"); #line 2433 "res/xrc/OutfitStudio.xrc" _("Inverts the X-axis of the texture coordinates."); #line 2436 "res/xrc/OutfitStudio.xrc" _("Invert Y"); #line 2437 "res/xrc/OutfitStudio.xrc" _("Inverts the Y-axis of the texture coordinates."); #line 2441 "res/xrc/OutfitStudio.xrc" _("Delete Vertices...\tShift+Del"); #line 2442 "res/xrc/OutfitStudio.xrc" _("Deletes all unmasked vertices of the currently selected shapes."); #line 2445 "res/xrc/OutfitStudio.xrc" _("Separate Vertices...\tShift+S"); #line 2446 "res/xrc/OutfitStudio.xrc" _("Separate the current shape into two by using the mask."); #line 2449 "res/xrc/OutfitStudio.xrc" _("Mirror Shape..."); #line 2450 "res/xrc/OutfitStudio.xrc" _("Mirror the selected shapes on any axis."); #line 2453 "res/xrc/OutfitStudio.xrc" _("Merge Geometry..."); #line 2454 "res/xrc/OutfitStudio.xrc" _("Copies vertices and triangles from one shape to another."); #line 2457 "res/xrc/OutfitStudio.xrc" _("Duplicate..."); #line 2458 "res/xrc/OutfitStudio.xrc" _("Duplicate the current shape."); #line 2461 "res/xrc/OutfitStudio.xrc" _("Refine Mesh"); #line 2462 "res/xrc/OutfitStudio.xrc" _("Splits all edges between unmasked vertices"); #line 2465 "res/xrc/OutfitStudio.xrc" _("Rename...\tF2"); #line 2466 "res/xrc/OutfitStudio.xrc" _("Change the name of the current shape."); #line 2469 "res/xrc/OutfitStudio.xrc" _("Set Reference"); #line 2470 "res/xrc/OutfitStudio.xrc" _("Turn the shape into the reference shape of the project."); #line 2474 "res/xrc/OutfitStudio.xrc" _("Move..."); #line 2475 "res/xrc/OutfitStudio.xrc" _("Apply an offset adjustment to the mesh vertices. This permanently moves vertices."); #line 2478 "res/xrc/OutfitStudio.xrc" _("Scale..."); #line 2479 "res/xrc/OutfitStudio.xrc" _("Apply a scale adjustment to the shape. This permanently moves vertices."); #line 2482 "res/xrc/OutfitStudio.xrc" _("Rotate..."); #line 2483 "res/xrc/OutfitStudio.xrc" _("Apply a rotation to the mesh vertices. This permanently moves vertices."); #line 2486 "res/xrc/OutfitStudio.xrc" _("Inflate..."); #line 2487 "res/xrc/OutfitStudio.xrc" _("Inflates/deflates a shape along its normals. This permanently moves vertices."); #line 2490 "res/xrc/OutfitStudio.xrc" _("Fix Clipping..."); #line 2491 "res/xrc/OutfitStudio.xrc" _("Fixes clipping of outfit vertices that penetrate the reference shape."); #line 2495 "res/xrc/OutfitStudio.xrc" _("Copy Bone Weights"); #line 2496 "res/xrc/OutfitStudio.xrc" _("Copies all bone weights from the reference shape to the current shape."); #line 2499 "res/xrc/OutfitStudio.xrc" _("Transfer Selected Weights"); #line 2500 "res/xrc/OutfitStudio.xrc" _("Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order."); #line 2503 "res/xrc/OutfitStudio.xrc" _("Mask Weighted Vertices"); #line 2504 "res/xrc/OutfitStudio.xrc" _("Masks vertices with bone weights, so you can manually assign weights to unweighted vertices."); #line 2507 "res/xrc/OutfitStudio.xrc" _("Check For Bad Bones"); #line 2508 "res/xrc/OutfitStudio.xrc" _("Looks for bones with inconsistencies in their transforms. If any are found, a dialog is opened to give options for fixing them."); #line 2512 "res/xrc/OutfitStudio.xrc" _("Copy Partitions/Segments..."); #line 2513 "res/xrc/OutfitStudio.xrc" _("Copies partitions/segments and all triangle assignments from the reference shape to the current shape."); #line 2517 "res/xrc/OutfitStudio.xrc" _("Mask Symmetric Vertices..."); #line 2518 "res/xrc/OutfitStudio.xrc" _("Masks unmasked vertices that have a mirrored vertex with identical data."); #line 2521 "res/xrc/OutfitStudio.xrc" _("Symmetrize Vertices..."); #line 2522 "res/xrc/OutfitStudio.xrc" _("Changes vertex data to be identical to mirrored vertices."); #line 2525 "res/xrc/OutfitStudio.xrc" _("Mask Symmetric Triangles"); #line 2526 "res/xrc/OutfitStudio.xrc" _("Masks triangles that can be matched to a mirrored triangle."); #line 2530 "res/xrc/OutfitStudio.xrc" _("Delete\tDel"); #line 2531 "res/xrc/OutfitStudio.xrc" _("Removes the currently selected shape from the outfit."); #line 2534 "res/xrc/OutfitStudio.xrc" _("Properties..."); #line 2535 "res/xrc/OutfitStudio.xrc" _("Opens the properties dialog for shader, texture and more settings of the selected shape."); #line 2539 "res/xrc/OutfitStudio.xrc" _("Bones"); #line 2541 "res/xrc/OutfitStudio.xrc" _("Bad Bone"); #line 2543 "res/xrc/OutfitStudio.xrc" _("Set Skin Transform From Node"); #line 2544 "res/xrc/OutfitStudio.xrc" _("Fixes the bad bone by calculating a new skin-to-bone transform."); #line 2547 "res/xrc/OutfitStudio.xrc" _("Set Node Transform From Skin"); #line 2548 "res/xrc/OutfitStudio.xrc" _("Fixes the bad custom bone by calculating a new bone-to-global transform."); #line 2552 "res/xrc/OutfitStudio.xrc" _("Add"); #line 2554 "res/xrc/OutfitStudio.xrc" _("From Skeleton..."); #line 2555 "res/xrc/OutfitStudio.xrc" _("Choose a bone from the reference skeleton to add to the project."); #line 2558 "res/xrc/OutfitStudio.xrc" _("Custom Bone..."); #line 2559 "res/xrc/OutfitStudio.xrc" _("Add a custom bone to the project."); #line 2563 "res/xrc/OutfitStudio.xrc" _("Delete"); #line 2565 "res/xrc/OutfitStudio.xrc" _("From Project"); #line 2566 "res/xrc/OutfitStudio.xrc" _("Delete bone(s) from all shapes of the project."); #line 2569 "res/xrc/OutfitStudio.xrc" _("From Selected Shapes"); #line 2570 "res/xrc/OutfitStudio.xrc" _("Delete bone(s) from only the selected shapes."); #line 2574 "res/xrc/OutfitStudio.xrc" _("Edit Bone..."); #line 2575 "res/xrc/OutfitStudio.xrc" _("Edit a custom bone or view a standard bone."); #line 2578 "res/xrc/OutfitStudio.xrc" _("Mask Weighted Vertices"); #line 2579 "res/xrc/OutfitStudio.xrc" _("Masks vertices with weights for the selected bones."); #line 2583 "res/xrc/OutfitStudio.xrc" _("Bones"); #line 2585 "res/xrc/OutfitStudio.xrc" _("Add"); #line 2587 "res/xrc/OutfitStudio.xrc" _("From Skeleton..."); #line 2588 "res/xrc/OutfitStudio.xrc" _("Choose a bone from the reference skeleton to add to the project."); #line 2591 "res/xrc/OutfitStudio.xrc" _("Custom Bone..."); #line 2592 "res/xrc/OutfitStudio.xrc" _("Add a custom bone to the project."); #line 2597 "res/xrc/OutfitStudio.xrc" _("Segments"); #line 2599 "res/xrc/OutfitStudio.xrc" _("Add Segment..."); #line 2600 "res/xrc/OutfitStudio.xrc" _("Choose a segment to add to the shape."); #line 2603 "res/xrc/OutfitStudio.xrc" _("Add Sub Segment..."); #line 2604 "res/xrc/OutfitStudio.xrc" _("Add a new sub segment to the currently selected segment."); #line 2607 "res/xrc/OutfitStudio.xrc" _("Delete Segment..."); #line 2608 "res/xrc/OutfitStudio.xrc" _("Delete segment and all of its sub segments from the shape."); #line 2612 "res/xrc/OutfitStudio.xrc" _("Sub Segments"); #line 2614 "res/xrc/OutfitStudio.xrc" _("Add Sub Segment..."); #line 2615 "res/xrc/OutfitStudio.xrc" _("Add a new sub segment to the currently selected segment."); #line 2618 "res/xrc/OutfitStudio.xrc" _("Delete Sub Segment..."); #line 2619 "res/xrc/OutfitStudio.xrc" _("Delete the selected sub segment."); #line 2623 "res/xrc/OutfitStudio.xrc" _("Segments"); #line 2625 "res/xrc/OutfitStudio.xrc" _("Add Segment..."); #line 2626 "res/xrc/OutfitStudio.xrc" _("Choose a segment to add to the shape."); #line 2630 "res/xrc/OutfitStudio.xrc" _("Partitions"); #line 2632 "res/xrc/OutfitStudio.xrc" _("Add Partition..."); #line 2633 "res/xrc/OutfitStudio.xrc" _("Adds a new partition to the shape."); #line 2636 "res/xrc/OutfitStudio.xrc" _("Delete Partition..."); #line 2637 "res/xrc/OutfitStudio.xrc" _("Deletes the partition from the shape."); #line 2641 "res/xrc/OutfitStudio.xrc" _("Partitions"); #line 2643 "res/xrc/OutfitStudio.xrc" _("Add Partition..."); #line 2644 "res/xrc/OutfitStudio.xrc" _("Adds a new partition to the shape."); #line 5 "res/xrc/Project.xrc" _("New Project"); #line 16 "res/xrc/Project.xrc" _("Welcome to the New Project wizard!\n\nFirst, please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders."); #line 32 "res/xrc/Project.xrc" _("Reference"); #line 50 "res/xrc/Project.xrc" _("From Template"); #line 69 "res/xrc/Project.xrc" _("From File"); #line 79 "res/xrc/Project.xrc" _("Select a project or NIF file"); #line 106 "res/xrc/Project.xrc" _("Slider Set:"); #line 124 "res/xrc/Project.xrc" _("Shape:"); #line 146 "res/xrc/Project.xrc" _("Clear Reference"); #line 162 "res/xrc/Project.xrc" _("Next, select an outfit/mesh to work on and enter a display name for it."); #line 177 "res/xrc/Project.xrc" _("Display Name"); #line 197 "res/xrc/Project.xrc" _("Outfit/Mesh"); #line 210 "res/xrc/Project.xrc" _("From File"); #line 220 "res/xrc/Project.xrc" _("Select a file to load as an outfit/mesh"); #line 232 "res/xrc/Project.xrc" _("Clear Outfit"); #line 250 "res/xrc/Project.xrc" _("Textures"); #line 257 "res/xrc/Project.xrc" _("Automatically search for textures"); #line 272 "res/xrc/Project.xrc" _("From File"); #line 282 "res/xrc/Project.xrc" _("Select a texture file"); #line 297 "res/xrc/Project.xrc" _("Save Project As..."); #line 319 "res/xrc/Project.xrc" _("Display Name"); #line 328 "res/xrc/Project.xrc" _("The name of the outfit and slider set, as it will appear in BodySlide."); #line 337 "res/xrc/Project.xrc" _("Copies the current display name to the project text fields below."); #line 338 "res/xrc/Project.xrc" _("To Project"); #line 354 "res/xrc/Project.xrc" _("Output File Name"); #line 363 "res/xrc/Project.xrc" _("The name of the outfit file that will end up in the game data path when BodySlide builds it. Should not include _1 or _0 in the name, e.g: lovelydress"); #line 389 "res/xrc/Project.xrc" _("Output Data Path"); #line 398 "res/xrc/Project.xrc" _("The location in the game's data path where BodySlide-built outfit files will be placed, e.g: meshes\\clothes\\lovelydress"); #line 410 "res/xrc/Project.xrc" _("If this is enabled, BodySlide creates a low and high weight model when it generates the final outfit."); #line 411 "res/xrc/Project.xrc" _("Low/High Weight Output"); #line 419 "res/xrc/Project.xrc" _("If this is enabled, only one output file will be created (useful for single-weighted things like hair)."); #line 420 "res/xrc/Project.xrc" _("Single Weight Output"); #line 431 "res/xrc/Project.xrc" _("Project"); #line 443 "res/xrc/Project.xrc" _("Slider Set File"); #line 453 "res/xrc/Project.xrc" _("The .osp slider set project file"); #line 454 "res/xrc/Project.xrc" _("Select slider set .osp file name"); #line 472 "res/xrc/Project.xrc" _("Shape Data Folder"); #line 482 "res/xrc/Project.xrc" _("The folder where all the slider data will go, as well as the base outfit NIF file."); #line 483 "res/xrc/Project.xrc" _("Select slider data folder"); #line 500 "res/xrc/Project.xrc" _("Shape Data File"); #line 510 "res/xrc/Project.xrc" _("The name of the output's base NIF file."); #line 511 "res/xrc/Project.xrc" _("Select output NIF file name"); #line 523 "res/xrc/Project.xrc" _("Outfits require the reference body to be a part of the output file. Disable this if you've already copied the reference over or you don't want it included."); #line 524 "res/xrc/Project.xrc" _("Copy reference shape into output"); #line 533 "res/xrc/Project.xrc" _("Prevents the building of morph .tri files in BodySlide for this project."); #line 534 "res/xrc/Project.xrc" _("Prevent morph file building in BodySlide"); #line 543 "res/xrc/Project.xrc" _("Prevents the removal of fully zapped shapes when building in BodySlide. Useful when the shape order and count matters, like for retextures using texture sets."); #line 544 "res/xrc/Project.xrc" _("Prevent removal of fully zapped shapes in BodySlide"); #line 563 "res/xrc/Project.xrc" _("&Save"); #line 570 "res/xrc/Project.xrc" _("&Cancel"); #line 579 "res/xrc/Project.xrc" _("Load Reference"); #line 588 "res/xrc/Project.xrc" _("Please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders."); #line 598 "res/xrc/Project.xrc" _("Reference"); #line 616 "res/xrc/Project.xrc" _("From Template"); #line 635 "res/xrc/Project.xrc" _("From File"); #line 645 "res/xrc/Project.xrc" _("Select a project or NIF file"); #line 672 "res/xrc/Project.xrc" _("Slider Set:"); #line 690 "res/xrc/Project.xrc" _("Shape:"); #line 712 "res/xrc/Project.xrc" _("Clear Reference"); #line 724 "res/xrc/Project.xrc" _("Merge"); #line 736 "res/xrc/Project.xrc" _("Zaps"); #line 737 "res/xrc/Project.xrc" _("Merge existing zaps with new sliders"); #line 746 "res/xrc/Project.xrc" _("Sliders"); #line 747 "res/xrc/Project.xrc" _("Merge new sliders with existing sliders"); #line 756 "res/xrc/Project.xrc" _("Append new sliders"); #line 757 "res/xrc/Project.xrc" _("Append new sliders that aren't in the project at the end of the list (or don't)"); #line 778 "res/xrc/Project.xrc" _("&OK"); #line 785 "res/xrc/Project.xrc" _("&Cancel"); #line 794 "res/xrc/Project.xrc" _("Load Outfit"); #line 803 "res/xrc/Project.xrc" _("Please select an outfit/mesh to work on and enter a display name for it."); #line 818 "res/xrc/Project.xrc" _("Display Name"); #line 838 "res/xrc/Project.xrc" _("Outfit/Mesh"); #line 851 "res/xrc/Project.xrc" _("From File"); #line 861 "res/xrc/Project.xrc" _("Select a file to load as an outfit/mesh"); #line 873 "res/xrc/Project.xrc" _("Clear Outfit"); #line 882 "res/xrc/Project.xrc" _("Keep other shapes"); #line 901 "res/xrc/Project.xrc" _("Textures"); #line 908 "res/xrc/Project.xrc" _("Automatically search for textures"); #line 923 "res/xrc/Project.xrc" _("From File"); #line 933 "res/xrc/Project.xrc" _("Select a texture file"); #line 955 "res/xrc/Project.xrc" _("&OK"); #line 962 "res/xrc/Project.xrc" _("&Cancel"); #line 972 "res/xrc/Project.xrc" _("Pack Projects..."); #line 1006 "res/xrc/Project.xrc" _("Group file (optional):"); #line 1015 "res/xrc/Project.xrc" _("Group file to pack (optional)."); #line 1016 "res/xrc/Project.xrc" _("Select a group XML file"); #line 1032 "res/xrc/Project.xrc" _("Merged file name:"); #line 1040 "res/xrc/Project.xrc" _("File name to use for the merged project file."); #line 1066 "res/xrc/Project.xrc" _("Pack Folder..."); #line 1075 "res/xrc/Project.xrc" _("Pack Archive..."); #line 1084 "res/xrc/Project.xrc" _("Group Manager"); #line 1092 "res/xrc/Project.xrc" _("Cancel"); #line 1101 "res/xrc/Project.xrc" _("Select None"); #line 1104 "res/xrc/Project.xrc" _("Select All"); #line 1107 "res/xrc/Project.xrc" _("Invert Selection"); #line 6 "res/xrc/SavePreset.xrc" _("Enter preset name..."); #line 15 "res/xrc/SavePreset.xrc" _("Please enter a name for the new preset:"); #line 38 "res/xrc/SavePreset.xrc" _("Select groups to assign to the new preset:"); #line 78 "res/xrc/SavePreset.xrc" _("&Save"); #line 85 "res/xrc/SavePreset.xrc" _("&Cancel"); #line 5 "res/xrc/Settings.xrc" _("Settings"); #line 15 "res/xrc/Settings.xrc" _("Game"); #line 28 "res/xrc/Settings.xrc" _("Target Game"); #line 37 "res/xrc/Settings.xrc" _("Choose the target game you want to use the program for here."); #line 67 "res/xrc/Settings.xrc" _("Game Data Path"); #line 77 "res/xrc/Settings.xrc" _("Select the data path of the game..."); #line 79 "res/xrc/Settings.xrc" _("Data path to load textures from."); #line 91 "res/xrc/Settings.xrc" _("Advanced"); #line 108 "res/xrc/Settings.xrc" _("Output Path"); #line 118 "res/xrc/Settings.xrc" _("Select the output path..."); #line 120 "res/xrc/Settings.xrc" _("Data path to build files to. If empty, Game Data Path will be used instead."); #line 137 "res/xrc/Settings.xrc" _("Project Path"); #line 147 "res/xrc/Settings.xrc" _("Select the project path..."); #line 149 "res/xrc/Settings.xrc" _("Project path where files related to BodySlide are loaded from. If empty, executable directory will be used instead."); #line 165 "res/xrc/Settings.xrc" _("With this turned on, BodySlide receives a new checkbox \"Force Body Normals\". Using it when building adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod."); #line 166 "res/xrc/Settings.xrc" _("Show 'Force Body Normals'"); #line 184 "res/xrc/Settings.xrc" _("General"); #line 196 "res/xrc/Settings.xrc" _("Enables/disables the dialog for choosing which set to build during a batch build if overrides happen."); #line 197 "res/xrc/Settings.xrc" _("Override Warning"); #line 206 "res/xrc/Settings.xrc" _("Enables/disables scanning BSAs in the game data folder for textures to load."); #line 207 "res/xrc/Settings.xrc" _("BSA Textures"); #line 224 "res/xrc/Settings.xrc" _("Enables/disables panning the camera with the left mouse button in Outfit Studio."); #line 225 "res/xrc/Settings.xrc" _("Left Mouse Pan"); #line 234 "res/xrc/Settings.xrc" _("Enables/disables opening the brush settings near the mouse cursor when hitting the 'space' key."); #line 235 "res/xrc/Settings.xrc" _("Brush Settings Near Cursor"); #line 244 "res/xrc/Settings.xrc" _("Enables/disables the undo history for the mask brush and vertex selection."); #line 245 "res/xrc/Settings.xrc" _("Mask History"); #line 263 "res/xrc/Settings.xrc" _("Single Instance"); #line 272 "res/xrc/Settings.xrc" _("Controls behavior when opening files and another instance is already running."); #line 275 "res/xrc/Settings.xrc" _("Ask (Message Box)"); #line 276 "res/xrc/Settings.xrc" _("Open in Existing"); #line 277 "res/xrc/Settings.xrc" _("Open in New"); #line 295 "res/xrc/Settings.xrc" _("Language"); #line 304 "res/xrc/Settings.xrc" _("Use the selected language for the program."); #line 319 "res/xrc/Settings.xrc" _("Rendering"); #line 325 "res/xrc/Settings.xrc" _("Enables/disables the perspective view in the rendering window."); #line 326 "res/xrc/Settings.xrc" _("Perspective View"); #line 341 "res/xrc/Settings.xrc" _("Background Color"); #line 350 "res/xrc/Settings.xrc" _("Background color of the renderer."); #line 367 "res/xrc/Settings.xrc" _("Wireframe Color"); #line 376 "res/xrc/Settings.xrc" _("Wireframe color of the renderer."); #line 393 "res/xrc/Settings.xrc" _("Point Color (normal/masked)"); #line 402 "res/xrc/Settings.xrc" _("Color of points in the renderer."); #line 411 "res/xrc/Settings.xrc" _("Color of masked points in the renderer."); #line 426 "res/xrc/Settings.xrc" _("Data Files"); #line 444 "res/xrc/Settings.xrc" _("Reference Skeleton"); #line 457 "res/xrc/Settings.xrc" _("File"); #line 467 "res/xrc/Settings.xrc" _("Select a reference skeleton .nif file..."); #line 470 "res/xrc/Settings.xrc" _("The reference skeleton file for Outfit Studio."); #line 487 "res/xrc/Settings.xrc" _("Root Node"); #line 496 "res/xrc/Settings.xrc" _("The root node name of the reference skeleton. Can differ from game to game."); #line 524 "res/xrc/Settings.xrc" _("&OK"); #line 531 "res/xrc/Settings.xrc" _("&Cancel"); #line 5 "res/xrc/Setup.xrc" _("Setup"); #line 15 "res/xrc/Setup.xrc" _("Please select the data folder and your target game.\nYou can only choose one game at a time, but it is possible to change the selection in the settings."); #line 44 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 45 "res/xrc/Setup.xrc" _("Select a folder"); #line 55 "res/xrc/Setup.xrc" _("Choose Game"); #line 73 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 74 "res/xrc/Setup.xrc" _("Select a folder"); #line 84 "res/xrc/Setup.xrc" _("Choose Game"); #line 102 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 103 "res/xrc/Setup.xrc" _("Select a folder"); #line 113 "res/xrc/Setup.xrc" _("Choose Game"); #line 131 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 132 "res/xrc/Setup.xrc" _("Select a folder"); #line 142 "res/xrc/Setup.xrc" _("Choose Game"); #line 160 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 161 "res/xrc/Setup.xrc" _("Select a folder"); #line 171 "res/xrc/Setup.xrc" _("Choose Game"); #line 189 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 190 "res/xrc/Setup.xrc" _("Select a folder"); #line 200 "res/xrc/Setup.xrc" _("Choose Game"); #line 218 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 219 "res/xrc/Setup.xrc" _("Select a folder"); #line 229 "res/xrc/Setup.xrc" _("Choose Game"); #line 247 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 248 "res/xrc/Setup.xrc" _("Select a folder"); #line 258 "res/xrc/Setup.xrc" _("Choose Game"); #line 276 "res/xrc/Setup.xrc" _("Game not found! Select the data folder manually..."); #line 277 "res/xrc/Setup.xrc" _("Select a folder"); #line 287 "res/xrc/Setup.xrc" _("Choose Game"); #line 302 "res/xrc/Setup.xrc" _("&Cancel"); #line 5 "res/xrc/ShapeProperties.xrc" _("Shape Properties"); #line 16 "res/xrc/ShapeProperties.xrc" _("Shader"); #line 31 "res/xrc/ShapeProperties.xrc" _("Name"); #line 84 "res/xrc/ShapeProperties.xrc" _("Type"); #line 102 "res/xrc/ShapeProperties.xrc" _("Specular Color"); #line 120 "res/xrc/ShapeProperties.xrc" _("Specular Strength"); #line 139 "res/xrc/ShapeProperties.xrc" _("Specular Power"); #line 179 "res/xrc/ShapeProperties.xrc" _("Emissive Color"); #line 197 "res/xrc/ShapeProperties.xrc" _("Emissive Multiple"); #line 216 "res/xrc/ShapeProperties.xrc" _("Alpha"); #line 235 "res/xrc/ShapeProperties.xrc" _("Vertex Colors"); #line 252 "res/xrc/ShapeProperties.xrc" _("Double Sided"); #line 280 "res/xrc/ShapeProperties.xrc" _("Add"); #line 289 "res/xrc/ShapeProperties.xrc" _("Remove"); #line 298 "res/xrc/ShapeProperties.xrc" _("Textures..."); #line 310 "res/xrc/ShapeProperties.xrc" _("Transparency"); #line 333 "res/xrc/ShapeProperties.xrc" _("Threshold"); #line 373 "res/xrc/ShapeProperties.xrc" _("Vertex Alpha"); #line 391 "res/xrc/ShapeProperties.xrc" _("Alpha Test"); #line 409 "res/xrc/ShapeProperties.xrc" _("Alpha Blend"); #line 438 "res/xrc/ShapeProperties.xrc" _("Add"); #line 447 "res/xrc/ShapeProperties.xrc" _("Remove"); #line 460 "res/xrc/ShapeProperties.xrc" _("Copy from shape..."); #line 468 "res/xrc/ShapeProperties.xrc" _("Geometry"); #line 488 "res/xrc/ShapeProperties.xrc" _("Full Precision"); #line 507 "res/xrc/ShapeProperties.xrc" _("Sub Index"); #line 526 "res/xrc/ShapeProperties.xrc" _("Skinned"); #line 544 "res/xrc/ShapeProperties.xrc" _("Dynamic"); #line 590 "res/xrc/ShapeProperties.xrc" _("Extra Data"); #line 611 "res/xrc/ShapeProperties.xrc" _("Add"); #line 620 "res/xrc/ShapeProperties.xrc" _("Type"); #line 629 "res/xrc/ShapeProperties.xrc" _("Name"); #line 638 "res/xrc/ShapeProperties.xrc" _("Value"); #line 648 "res/xrc/ShapeProperties.xrc" _("Coordinates"); #line 657 "res/xrc/ShapeProperties.xrc" _("Transform from shape to global coordinates:"); #line 672 "res/xrc/ShapeProperties.xrc" _("Scale"); #line 711 "res/xrc/ShapeProperties.xrc" _("Origin"); #line 720 "res/xrc/ShapeProperties.xrc" _("Rotation"); #line 806 "res/xrc/ShapeProperties.xrc" _("Recalculate geometry's coordinates so it doesn't move"); #line 807 "res/xrc/ShapeProperties.xrc" _("Transform geometry so its position in global coordinates does not change."); #line 831 "res/xrc/ShapeProperties.xrc" _("&OK"); #line 838 "res/xrc/ShapeProperties.xrc" _("&Cancel"); #line 6 "res/xrc/Skeleton.xrc" _("Select a bone to add"); #line 15 "res/xrc/Skeleton.xrc" _("Bones in the current reference skeleton:"); #line 36 "res/xrc/Skeleton.xrc" _("&OK"); #line 43 "res/xrc/Skeleton.xrc" _("&Cancel"); #line 53 "res/xrc/Skeleton.xrc" _("Add Custom Bone"); #line 68 "res/xrc/Skeleton.xrc" _("Parent"); #line 94 "res/xrc/Skeleton.xrc" _("Name"); #line 133 "res/xrc/Skeleton.xrc" _("Origin"); #line 142 "res/xrc/Skeleton.xrc" _("Rotation"); #line 234 "res/xrc/Skeleton.xrc" _("Add Count #"); #line 259 "res/xrc/Skeleton.xrc" _("&OK"); #line 266 "res/xrc/Skeleton.xrc" _("&Cancel"); #line 6 "res/xrc/Slider.xrc" _("Select a slider preset"); #line 15 "res/xrc/Slider.xrc" _("Choose a preset:"); #line 40 "res/xrc/Slider.xrc" _("Low weight"); #line 49 "res/xrc/Slider.xrc" _("High weight"); #line 64 "res/xrc/Slider.xrc" _("&OK"); #line 71 "res/xrc/Slider.xrc" _("&Cancel"); #line 81 "res/xrc/Slider.xrc" _("Slider Properties"); #line 91 "res/xrc/Slider.xrc" _("Slider Name"); #line 108 "res/xrc/Slider.xrc" _("Default Values"); #line 114 "res/xrc/Slider.xrc" _("Low"); #line 131 "res/xrc/Slider.xrc" _("High"); #line 148 "res/xrc/Slider.xrc" _("Zapped"); #line 161 "res/xrc/Slider.xrc" _("Options"); #line 173 "res/xrc/Slider.xrc" _("Invert"); #line 182 "res/xrc/Slider.xrc" _("Hidden"); #line 191 "res/xrc/Slider.xrc" _("Zap"); #line 200 "res/xrc/Slider.xrc" _("UV"); #line 211 "res/xrc/Slider.xrc" _("Toggle Zaps:"); #line 238 "res/xrc/Slider.xrc" _("&OK"); #line 246 "res/xrc/Slider.xrc" _("&Cancel"); #line 6 "res/xrc/SliderDataImport.xrc" _("Slider Data Import Options..."); #line 21 "res/xrc/SliderDataImport.xrc" _("Select the shapes that slider data will be imported for:"); #line 52 "res/xrc/SliderDataImport.xrc" _("Select the sliders to be imported"); #line 77 "res/xrc/SliderDataImport.xrc" _("Merge Sliders"); #line 90 "res/xrc/SliderDataImport.xrc" _("&OK"); #line 97 "res/xrc/SliderDataImport.xrc" _("&Cancel"); #line 106 "res/xrc/SliderDataImport.xrc" _("Select None"); #line 109 "res/xrc/SliderDataImport.xrc" _("Select All"); #line 112 "res/xrc/SliderDataImport.xrc" _("Invert Selection"); #line 6 "res/xrc/WeightCopy.xrc" _("Copy Bone Weights"); #line 15 "res/xrc/WeightCopy.xrc" _("Each vertex of the reference will copy its weights to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become weighted and work well. Often, the default values are sufficient."); #line 35 "res/xrc/WeightCopy.xrc" _("Search Radius"); #line 64 "res/xrc/WeightCopy.xrc" _("Max Vertex Targets"); #line 95 "res/xrc/WeightCopy.xrc" _("No Target Limit"); #line 104 "res/xrc/WeightCopy.xrc" _("Bones to copy (click to preview weights):"); #line 127 "res/xrc/WeightCopy.xrc" _("Check All"); #line 135 "res/xrc/WeightCopy.xrc" _("Uncheck All"); #line 151 "res/xrc/WeightCopy.xrc" _("Pose:"); #line 167 "res/xrc/WeightCopy.xrc" _("The skin coordinate system doesn't match the reference shape's. Do you want to copy the transforms?"); #line 177 "res/xrc/WeightCopy.xrc" _("Copy skin transform from reference"); #line 187 "res/xrc/WeightCopy.xrc" _("Recalculate geometry's coordinates so it doesn't move"); #line 188 "res/xrc/WeightCopy.xrc" _("Transform geometry so its position in global coordinates does not change."); #line 204 "res/xrc/WeightCopy.xrc" _("&Preview"); #line 205 "res/xrc/WeightCopy.xrc" _("Run the weight copy and preview the results. Click again to update the preview."); #line 228 "res/xrc/WeightCopy.xrc" _("&OK"); #line 236 "res/xrc/WeightCopy.xrc" _("&Cancel"); ================================================ FILE: lang/zh/BodySlide.po ================================================ msgid "" msgstr "" "Project-Id-Version: BodySlide_zh\n" "POT-Creation-Date: \n" "PO-Revision-Date: 2025-01-27 19:43+0100\n" "Last-Translator: \n" "Language-Team: 小莫\n" "Language: zh\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.5\n" "X-Poedit-Basepath: .\n" "X-Poedit-SearchPath-0: BodySlide.po\n" msgid "Outfit/Body" msgstr "装备/身体" msgid "Select an outfit to modify" msgstr "选择一个装备来修改" msgid "Preset" msgstr "预设" msgid "Choose from a list of slider settings presets" msgstr "从一列滑块集预设中选择" msgid "Saves the new slider values to the currently selected preset" msgstr "保存新滑块值到当前被选预设" msgid "Save" msgstr "保存" msgid "Save the current slider settings as a new preset" msgstr "将当前的滑块集作为新预设保存" msgid "Save As..." msgstr "另存为..." msgid "" "Opens the group manager where you can edit existing or create new groups" msgstr "打开组管理器以编辑现有组或创建新组" msgid "Group Manager" msgstr "组管理器" msgid "Opens the current project in Outfit Studio" msgstr "在Outfit Studio中打开当前项目" msgid "Single Weight" msgstr "单重量" msgid "Low Weight" msgstr "最小重量" msgid "High Weight" msgstr "最大重量" msgid "Copy the low weight slider values to the high weight section." msgstr "复制最小重量的滑块值到最大重量那儿去。" msgid "" "Build multiple outfits using the currently active slider values.\n" "\n" "Hold CTRL = Build to custom directory\n" "Hold ALT = Delete from output directory" msgstr "" "使用当前预设批量建立装备。\n" "按住CTRL = 建立到自定义目录中\n" "按住ALT = 从输出目录中删除" msgid "Batch Build..." msgstr "批量建立..." msgid "Build Morphs" msgstr "建立变形" msgid "" "Builds a morphs (.tri) file alongside the meshes for accessing the sliders " "in-game. Requires other mods to make use of the morph data." msgstr "" "在网格旁建立一个变形(.tri)文件以在游戏中访问滑块。需要其他mod来利用变形数据。" msgid "Show a preview window for this outfit." msgstr "显示这件装备的预览窗口。" msgid "Preview" msgstr "预览" msgid "" "Creates the currently selected outfit/body.\n" "\n" "Hold CTRL = Build to working directory\n" "Hold ALT = Delete from output directory" msgstr "" "创建当前被选装备/身体。\n" "按住CTRL = 建立到工作目录中\n" "按住ALT = 从输出目录中删除" msgid "Build" msgstr "建立" msgid "Copy the high weight slider values to the low weight section." msgstr "复制最大重量滑块值到最小重量那去。" msgid "About" msgstr "关于" msgid "Open settings dialog." msgstr "打开设置对话框。" msgid "Settings" msgstr "设置" msgid "" "Open Outfit Studio, a full-featured tool for creating and converting outfits." msgstr "打开Outfit Studio,一个功能齐全的装备创建和转换工具。" msgid "Failed to launch Outfit Studio executable!" msgstr "无法启动Outfit Studio的可执行文件!" msgid "Filter Options" msgstr "过滤器选项" msgid "Choose groups..." msgstr "选择组..." msgid "Choose groups to display in the Outfit menu" msgstr "选择要在装备菜单中显示的组" msgid "Refresh Groups" msgstr "刷新组" msgid "Refresh group information" msgstr "刷新组信息" msgid "Save Outfit list as group..." msgstr "将装备列表作为组保存..." msgid "Save the current filtered outfit list as a group" msgstr "将当前已过滤的装备列表保存为一个组" msgid "Refresh Outfits" msgstr "刷新装备" msgid "Reloads outfit list" msgstr "重新加载装备列表" msgid "Select None" msgstr "清除选择" msgid "Select All" msgstr "选择所有" msgid "Enter preset name..." msgstr "输入预设名..." msgid "Please enter a name for the new preset:" msgstr "请为新预设输入一个名字:" msgid "Select groups to assign to the new preset:" msgstr "选择要分配新预设的组:" msgid "Deletes a project from its project file" msgstr "从项目文件中删除项目" msgid "Delete Project" msgstr "删除项目" msgid "Do you really wish to delete the selected project?" msgstr "你真的要删除被选的项目吗?" msgid "Deletes a preset from its preset file" msgstr "从预设文件中删除预设" msgid "Delete Preset" msgstr "删除预设" msgid "Do you really wish to delete the selected preset?" msgstr "你真的要删除被选的预设吗?" msgid "&Save" msgstr "&保存" msgid "&OK" msgstr "&确定" msgid "&Cancel" msgstr "&取消" msgid "" "Choose a group and add or remove members by selecting them in the lists." msgstr "选择一个组,并通过在列表中选取来增加或移除成员。" msgid "Select a group XML file" msgstr "选择一个组的 XML 文件" msgid "Save As" msgstr "另存为" msgid "Groups" msgstr "组" msgid "Add Group" msgstr "增加组" msgid "Remove Group" msgstr "移除组" msgid "Members" msgstr "成员" msgid "Remove >>" msgstr "移除 >>" msgid "Outfits" msgstr "装备" msgid "<< Add" msgstr "<< 增加" msgid "Save Changes" msgstr "保存更改" msgid "" "Do you really want to close the group manager? All unsaved changes will be " "lost." msgstr "你确定关闭管理器身形管理器吗?所有未保存的内容都会丢失。" msgid "Batch Build" msgstr "批量建立" msgid "" "Select the slider sets for the batch build process. Use the group and outfit " "filters to show the outfits you want!" msgstr "为批量建立选择滑块集。使用组和装备过滤器来显示你想要的装备!" msgid "&Build" msgstr "&建立" msgid "Game" msgstr "游戏" msgid "Target Game" msgstr "目标游戏" msgid "Choose the target game you want to use the program for here." msgstr "选择你想使用此程序的目标游戏。" msgid "Fallout 3" msgstr "辐射3" msgid "Fallout New Vegas" msgstr "辐射新维加斯" msgid "Skyrim" msgstr "天际" msgid "Fallout 4" msgstr "辐射4" msgid "Advanced" msgstr "高级" msgid "Game Data Path" msgstr "游戏数据路径" msgid "Select the data path of the game..." msgstr "选择此游戏的数据路径..." msgid "Data path to load textures from." msgstr "用来加载材质(和建立文件)的数据路径。" msgid "Output Path" msgstr "输出路径" msgid "Select the output path..." msgstr "选择输出路径......" msgid "" "Data path to build files to. If empty, Game Data Path will be used instead." msgstr "建立文件所用的数据路径。 留空则使用游戏数据路径。" msgid "General" msgstr "常规" msgid "" "Enables/disables the dialog for choosing which set to build during a batch " "build if overrides happen." msgstr "开启/关闭在批量建立发生覆盖时的设置选择对话框。" msgid "Override Warning" msgstr "覆盖警告" msgid "" "Enables/disables scanning BSAs in the game data folder for textures to load." msgstr "开启/关闭扫描游戏数据目录中的BSA以获取要加载的材质。" msgid "BSA Textures" msgstr "BSA材质" msgid "" "Enables/disables panning the camera with the left mouse button in Outfit " "Studio." msgstr "开启/关闭用鼠标左键平移Outfit Studio中的相机。" msgid "Left Mouse Pan" msgstr "鼠标左键平移" msgid "Data Files" msgstr "数据文件" msgid "Reference Skeleton" msgstr "参照骨架" msgid "File" msgstr "文件" msgid "Select a reference skeleton .nif file..." msgstr "选择一个参照骨架.nif文件..." msgid "The reference skeleton file for Outfit Studio." msgstr "Outfit Studio的参照骨架文件。" msgid "Root Node" msgstr "根结点" msgid "" "The root node name of the reference skeleton. Can differ from game to game." msgstr "参照骨架的根节点名称。 不同游戏之间可能不同。" msgid "Close" msgstr "关闭" msgid "Brush Settings" msgstr "笔刷设置" msgid "Size" msgstr "尺寸" msgid "Strength" msgstr "强度" msgid "Focus" msgstr "焦点" msgid "Spacing" msgstr "间距" msgid "Meshes" msgstr "网格" msgid "Bones" msgstr "骨骼" msgid "Lights" msgstr "灯光" msgid "Reset" msgstr "重置" msgid "Ambient" msgstr "环境" msgid "Frontal" msgstr "前端" msgid "Directional 1" msgstr "方向1" msgid "Directional 2" msgstr "方向2" msgid "Directional 3" msgstr "方向3" msgid "De-/Select Sliders" msgstr "取消/选定滑块" msgid "Fixed Weight Brush" msgstr "固定权重(Fixed Weight)笔刷" msgid "Preview Scaling" msgstr "预览缩放" msgid "Menu" msgstr "菜单" msgid "New Project...\tCtrl+N" msgstr "新建项目...\tCtrl+N" msgid "Create a new outfit project." msgstr "创建一个新的装备项目。" msgid "Load Project..\tCtrl+O" msgstr "加载项目..\\tCtrl+O" msgid "Load a project." msgstr "加载一个项目。" msgid "Add Project..\tCtrl+Shift+O" msgstr "添加项目... Ctrl+Shift+O" msgid "Add a project without replacing the current one." msgstr "在不替换当前项目的情况下添加项目。" msgid "Load Reference..." msgstr "加载参照..." msgid "" "Load a new reference slider set, replacing any current reference objects." msgstr "加载一个新的参考滑块集,取代任何当前的参考项目。" msgid "Load Outfit..." msgstr "加载服装..." msgid "" "Load a NIF file as the working outfit, replacing any current outfit objects." msgstr "加载一个NIF文件作为工作装备,替换任何当前的装备对象。" msgid "" "Disable for a different way of loading NIF files to see if that puts it into " "the right (or a better) spot." msgstr "" "禁用以采用不同的方式加载NIF文件,以查看是否能把它放入正确(或更好)的场景。" msgid "Save Project\tCtrl+S" msgstr "保存项目\tCtrl+S" msgid "Save the project." msgstr "保存项目。" msgid "Save Project As...\tCtrl+Shift+S" msgstr "另存项目为\tCtrl+Shift+S" msgid "Save the project under a new name." msgstr "以新的名称保存此项目。" msgid "Import" msgstr "导入" msgid "From NIF..." msgstr "从NIF..." msgid "Choose a NIF file to import into the project." msgstr "选择一个NIF文件来导入到项目中。" msgid "Import Data" msgstr "导入数据" msgid "Import BSClothExtraData From HKX" msgstr "从HKX导入BSClothExtraData" msgid "" "Choose an HKX file to import as a BSClothExtraData block into the project." msgstr "选择一个HKX文件作为BSClothExtraData块导入到项目中。" msgid "Export" msgstr "导出" msgid "Save the current project as a NIF file (without reference)" msgstr "将当前项目保存为NIF文件(不带参照)" msgid "To NIF With Reference..." msgstr "到带参照的NIF..." msgid "Save the current project as a NIF file (including reference)" msgstr "将当前项目保存为NIF文件(包含参照)" msgid "Export Data" msgstr "导出数据" msgid "Export BSClothExtraData As HKX" msgstr "导出BSClothExtraData为HKX" msgid "" "Save one of the currently loaded BSClothExtraData blocks to an HKX file." msgstr "保存一个当前已加载的BSClothExtraData块为HKX文件。" msgid "Make Conversion Reference" msgstr "制作转换参照" msgid "" "Using the current slider settings for the reference shape, create a new " "reference that will morph from the current shape back to the base shape." msgstr "" "在参照模型的基础上使用当前滑块集,创建一个可以从当前模型变回基础模型的新参" "照。" msgid "Exit\tAlt+F4" msgstr "退出\tAlt+F4" msgid "Exit Outfit Studio." msgstr "退出Outfit Studio。" msgid "Edit" msgstr "编辑" msgid "Undo\tCtrl+Z" msgstr "撤销\tCtrl+Z" msgid "Undo the previous action." msgstr "撤消上一个动作。" msgid "Redo\tCtrl+Y" msgstr "重做\tCtrl+Y" msgid "Redo the next undone action." msgstr "重做下一个被撤销的操作。" msgid "X Mirror\tX" msgstr "X镜像\tX" msgid "Mirror edits across the X axis." msgstr "在X轴上镜像编辑。" msgid "Edit Connected Only\tC" msgstr "仅编辑相连的顶点\tC" msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius" msgstr "仅编辑笔刷半径内相连的顶点" msgid "Global Brush Collision\tB" msgstr "全局笔刷处理(Collision)\tB" msgid "" "Allows for the brushes to collide with all currently selected meshes at the " "same time" msgstr "允许画笔在同一时间处理所有当前被选网格" msgid "Recalculate Normals\tR" msgstr "重新计算法线\tR" msgid "Recalculate normals on active mesh" msgstr "在激活的网格上重新计算法线" msgid "View" msgstr "视图" msgid "Front\tShift+1" msgstr "前\tShift+1" msgid "Back\tShift+2" msgstr "后\tShift+2" msgid "Left\tShift+3" msgstr "左\tShift+3" msgid "Right\tShift+4" msgstr "右\tShift+4" msgid "Perspective\tShift+5" msgstr "透视\tShift+5" msgid "Toggle Ghost Mode\tG" msgstr "幽灵模式开关\tG" msgid "Show the active mesh in translucent mode." msgstr "以半透明模式显示被选网格。" msgid "Show Wireframe\tW" msgstr "显示线框\tW" msgid "Show wireframe on all models." msgstr "显示所有模型上的线框。" msgid "Enable Lighting\tL" msgstr "启用照明\tL" msgid "Turn on or off lighting." msgstr "开启或关闭照明。" msgid "Enable Textures\tT" msgstr "启用材质\tT" msgid "Display texture maps on models." msgstr "显示模型上的材质贴图。" msgid "Shape" msgstr "模型" msgid "From OBJ..." msgstr "从OBJ..." msgid "Import an OBJ file as a new shape in the outfit." msgstr "导入一个OBJ文件作为装备上的新模型。" msgid "From FBX..." msgstr "从FBX..." msgid "Import an FBX file as a new shape in the outfit." msgstr "从FBX文件中导入一个新模型插入装备。" msgid "To NIF..." msgstr "到NIF..." msgid "Export only the selected shapes to a NIF file." msgstr "只将被选模型导出到NIF文件。" msgid "Export selected shapes to NIF" msgstr "将被选模型导出到NIF" msgid "Failed to export selected shapes to NIF file!" msgstr "未能将被选模型导出到NIF文件!" msgid "To OBJ..." msgstr "到OBJ..." msgid "Export the current project as an OBJ file." msgstr "将当前项目作为OBJ文件导出。" msgid "To FBX..." msgstr "到FBX..." msgid "Export only the selected shapes to an FBX file." msgstr "仅将被选模型导出到FBX文件。" msgid "UV" msgstr "UV" msgid "Invert X" msgstr "反转X轴" msgid "Inverts the X-axis of the texture coordinates." msgstr "反转材质坐标的X轴。" msgid "Invert Y" msgstr "反转Y轴" msgid "Inverts the Y-axis of the texture coordinates." msgstr "反转材质坐标的Y轴。" msgid "Mirror" msgstr "镜像" msgid "Mirror the selected shapes on the X-axis." msgstr "在X轴上镜像被选形状。" msgid "Mirror the selected shapes on the Y-axis." msgstr "在Y轴上镜像被选形状。" msgid "Mirror the selected shapes on the Z-axis." msgstr "在Z轴上镜像被选形状。" msgid "Duplicate..." msgstr "复制..." msgid "Duplicate the current shape." msgstr "复制当前模型。" msgid "Rename...\tF2" msgstr "重命名... \tF2" msgid "Change the name of the current shape." msgstr "更改当前模型的名称。" msgid "Set Reference" msgstr "设置参照" msgid "Turn the shape into the reference shape of the project." msgstr "将此模型转化为项目的参照模型。" msgid "Move..." msgstr "移动..." msgid "" "Apply an offset adjustment to the mesh vertices. This permanently moves " "vertices." msgstr "对网格顶点调偏(Apply an offset adjustment)。这将永久移动顶点。" msgid "Scale..." msgstr "缩放..." msgid "Apply a scale adjustment to the shape. This permanently moves vertices." msgstr "对模型使用缩放调节。这将永久移动顶点。" msgid "Rotate..." msgstr "旋转..." msgid "Apply a rotation to the mesh vertices. This permanently moves vertices." msgstr "旋转网格顶点。这将永久移动顶点。" msgid "Smooth Seam Normals" msgstr "平滑接缝法线" msgid "" "Smooths edges of seams (usually found at texture borders), disable if this " "causes odd normals on the shape." msgstr "平滑接缝处的边缘(常见于材质边界),若引起模型法线异常请禁用此选项。" msgid "Lock Normals" msgstr "锁定法线" msgid "" "Locks the mesh normals. Enable if you want to keep custom normals intact." msgstr "锁定网格法线。在希望自定义法线原封不动时启用。" msgid "Copy Bone Weights" msgstr "复制骨骼权重" msgid "Copies all bone weights from the reference shape to the current shape." msgstr "将参照模型中的所有骨骼权重复制到到当前模型。" msgid "Copy Selected Weights" msgstr "复制被选权重" msgid "" "Copies selected bone weights from the reference shape to the current shape." msgstr "从参照模型复制被选骨骼权重到当前模型。" msgid "Transfer Selected Weights" msgstr "转移被选权重" msgid "" "Transfers selected weights from the reference shape to the current shape. " "Requires same vertex count and order." msgstr "将被选权重从参照模型转移到当前模型。需要相同的顶点数和顺序。" msgid "Mask Weighted Vertices" msgstr "遮罩权重顶点" msgid "" "Masks vertices with bone weights, so you can manually assign weights to " "unweighted vertices." msgstr "遮罩有骨骼权重的顶点,方便手动处理无权重的顶点。" msgid "Delete\tDel" msgstr "删除\tDel" msgid "Removes the currently selected shape from the outfit." msgstr "从装备中删除当前被选模型。" msgid "Properties..." msgstr "属性..." msgid "" "Opens the properties dialog for shader, texture and more settings of the " "selected shape." msgstr "打开被选模型的着色器、材质等设置的属性对话框。" msgid "Slider" msgstr "滑块" msgid "Conform Selected\tCtrl+C" msgstr "应用被选\tCtrl+C" msgid "Conform selected outfit shape to all checked sliders." msgstr "将被选滑块应用到被选装备模型中。" msgid "Conform All\tCtrl+Shift+C" msgstr "应用所有滑块\tCtrl+Shift+C" msgid "Conform all outfit shapes to all checked sliders." msgstr "将所有被选滑块应用到所有装备模型中。" msgid "Set Base Shape" msgstr "设置基础模型" msgid "Set the current outfit shape as the base shape and clear slider data." msgstr "设置当前装备模型为基础模型,并清除滑块数据。" msgid "Load Preset..." msgstr "加载预设..." msgid "" "Load and preview a slider preset. Inverted sliders will have inverted values." msgstr "加载并预览一个滑块预设。反转滑块的值是相反的。" msgid "Save Preset..." msgstr "保存预设..." msgid "" "Save a slider preset with the current values. Inverted sliders will have " "inverted values." msgstr "保存当前值为滑块预设。反转滑块的值是相反的。" msgid "New Slider" msgstr "新建滑块" msgid "Create a new shape transformation slider." msgstr "创建一个新的模型转换滑块。" msgid "Coalesce sliders" msgstr "合并滑块" msgid "" "Create a new shape transformation slider based on the current slider values" msgstr "创建一个基于当前滑块值的新模型转换滑块" msgid "New Zap Slider" msgstr "新建修正滑块" msgid "Create a new Zap slider based on unmasked vertices" msgstr "创建一个基于未遮罩顶点的新修正滑块" msgid "Import OSD..." msgstr "导入OSD..." msgid "Imports OSD file and creates sliders for shapes with a matching name." msgstr "导入OSD文件并为具有匹配名称的模型创建滑块。" msgid "Export OSD..." msgstr "导出OSD..." msgid "Exports all currently loaded slider data to an OSD file." msgstr "将所有当前已加载的滑块数据导出到OSD文件。" msgid "Import TRI Morphs..." msgstr "导入TRI变形..." msgid "" "Imports TRI morphs from a TRI file and creates sliders for shapes with a " "matching name." msgstr "从TRI文件中导入TRI变形,并为具有匹配名称的模型创建滑块。" msgid "Export TRI Morphs..." msgstr "导出TRI变形..." msgid "Exports TRI morphs to a TRI file." msgstr "导出TRI变形到TRI文件。" msgid "Import Slider Data" msgstr "导入滑块数据" msgid "Import BSD..." msgstr "导入BSD..." msgid "" "Import a BodySlide BSD file and overwrites the current shape's slider data." msgstr "导入一个bodyslide BSD文件,并覆盖当前模型的滑块数据。" msgid "Import OBJ..." msgstr "导入OBJ文件..." msgid "" "Import an OBJ file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "导入一个与当前模型顶点数匹配的OBJ文件,并根据差值计算滑块数据。" msgid "Import FBX..." msgstr "导入FBX文件..." msgid "" "Import an FBX file matching the current shape's vertex count, and calculate " "slider data from the difference." msgstr "导入一个与当前模型顶点数匹配的FBX文件,并根据差值计算滑块数据。" msgid "Export Slider Data" msgstr "导出滑块数据" msgid "Export BSD..." msgstr "导出BSD..." msgid "Exports the current slider's data as a BodySlide BSD file." msgstr "将当前滑块数据作为BSD文件导出。" msgid "Export OBJ..." msgstr "导出OBJ..." msgid "Export only the selected shapes to an OBJ file." msgstr "只将被选模型导出到OBJ文件。" msgid "Negate Slider" msgstr "无效化滑块" msgid "Negates the current slider, reversing it's effect" msgstr "无效化当前滑块,逆转其效果" msgid "Mask Affected Vertices" msgstr "遮罩受影响顶点" msgid "Masks the vertices the slider is affecting for all selected shapes." msgstr "为所有被选模型遮罩受滑块影响的顶点。" msgid "Clear Slider Data" msgstr "清除滑块数据" msgid "" "Erases the slider data without removing the slider itself. (Cannot be undone)" msgstr "清除滑块数据而不删除滑块。(无法撤销)" msgid "Delete Slider" msgstr "删除滑块" msgid "Delete the active slider from the project. (Cannot be undone)" msgstr "从项目中删除被选滑块。(无法撤销)" msgid "Properties...\tTab" msgstr "属性...\tTab" msgid "Display and edit the active slider's properties." msgstr "显示和编辑已激活滑块的属性。" msgid "Tool" msgstr "工具" msgid "Current Tool" msgstr "当前工具" msgid "Select\t0" msgstr "选择\t0" msgid "Navigate and select meshes (or vertices in vertex mode)." msgstr "导航并选择网格(或顶点模式下的顶点)。" msgid "Mask\t1" msgstr "遮罩\t1" msgid "" "Mask vertices to prevent them from being transformed.\n" "Hold down the ALT key to remove masking." msgstr "" "遮罩顶点以防误操作。\n" "按住ALT键移除遮罩。" msgid "Inflate\t2" msgstr "放大\t2" msgid "Increase mesh volume in an area." msgstr "在一个区域放大网格。" msgid "Deflate\t3" msgstr "缩小\t3" msgid "Decrease mesh volume in an area." msgstr "在一个区域缩小网格。" msgid "Move\t4" msgstr "移动\t4" msgid "Move vertices over a plane parallel to the view." msgstr "在平行于视图的平面上移动顶点。" msgid "Smooth\t5" msgstr "平滑\t5" msgid "Smooth an area of a mesh." msgstr "平滑一个区域的网格。" msgid "Weight Paint\t6" msgstr "权重画笔\t6" msgid "" "Apply animation weight values for the currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "对当前被选骨骼应用动画权重值。\n" "按住ALT键减弱权重。" msgid "Transform\tF" msgstr "变换\tF" msgid "Shows a transform tool to manipulate shapes and vertices with." msgstr "显示变换工具来操作模型和顶点。" msgid "Pivot\tF" msgstr "枢轴\tF" msgid "" "Shows a pivot that can be moved and makes it the center of mesh operations " "like rotation and scale." msgstr "显示可以移动的轴,并使其成为网格操作(如旋转和缩放)的中心。" msgid "Vertex Edit\tQ" msgstr "顶点编辑\tQ" msgid "" "Lets you select vertices to add to or remove from the mask.\n" "Click on a vertex to select/unmask it.\n" "Hold down CTRL to unselect/mask it." msgstr "" "允许你添加或删除遮罩中选择顶点。\n" "点击一个顶点来选择/取消遮罩它。\n" "按住CTRL来取消选择/遮罩它。" msgid "Increase Brush Size\tShift++" msgstr "增加笔刷尺寸\tShift++" msgid "Increase brush diameter" msgstr "增加笔刷直径" msgid "Decrease Brush Size\tShift+-" msgstr "减小笔刷尺寸\tShift+-" msgid "Decrease brush diameter" msgstr "减小笔刷直径" msgid "Increase Brush Strength\tCtrl++" msgstr "增加笔刷强度\tCtrl++" msgid "Increase brush strength" msgstr "增加笔刷强度" msgid "Decrease Brush Strength\tCtrl+-" msgstr "减小笔刷强度\tCtrl+-" msgid "Decrease brush strength" msgstr "减小笔刷强度" msgid "Mask Less\tA" msgstr "遮罩减少\tA" msgid "Mask Less" msgstr "遮罩减少" msgid "Mask More\tD" msgstr "遮罩增加\tD" msgid "Mask More" msgstr "遮罩增加" msgid "Invert Mask\tCtrl+I" msgstr "反转遮罩\tCtrl+I" msgid "Invert Mask" msgstr "反转遮罩" msgid "Clear Mask\tCtrl+A" msgstr "清除遮罩\tCtrl+A" msgid "Clear Mask" msgstr "清除遮罩" msgid "Show Mask\tM" msgstr "显示遮罩\tM" msgid "Shade meshes to indicate areas that are currently masked." msgstr "为网格添加阴影来指示当前已被遮罩的区域。" msgid "New Project" msgstr "新建项目" msgid "" "Create a new project by selecting a reference body slider set, and outfit " "model files." msgstr "" "选择一个参照滑块集和装备模型文件以新建一个项目。(Create a new project by " "selecting a reference body slider set, and outfit model files.)" msgid "Load Project" msgstr "加载项目" msgid "Load a previously created slider set for editing." msgstr "打开一个上次创建的滑块集来编辑。" msgid "Select" msgstr "选择" msgid "Mask" msgstr "遮罩" msgid "Inflate" msgstr "放大" msgid "Deflate" msgstr "缩小" msgid "Move" msgstr "移动" msgid "Smooth" msgstr "平滑" msgid "Weight Paint" msgstr "权重画笔" msgid "" "Apply animation weight values for currently selected bone.\n" "Hold down the ALT key to weaken the weighting." msgstr "" "对当前被选骨骼应用动画权重值。\n" "按住ALT键减弱权重。" msgid "Transform" msgstr "变形" msgid "Pivot" msgstr "枢轴" msgid "Vertex Edit" msgstr "顶点编辑" msgid "X Mirror" msgstr "X镜像" msgid "" "Edit only vertices that are connected to the ones under the brush within the " "brush radius." msgstr "仅编辑笔刷半径内相连的顶点。" msgid "Global Brush Collision\tC" msgstr "全局笔刷\tC" msgid "" "Allows for the brushes to collide with all currently selected meshes at the " "same time." msgstr "允许笔刷同时处理所有被选模型。" msgid "View Front" msgstr "前视图" msgid "Change camera view to the front." msgstr "改变相机视图到前方。" msgid "View Back" msgstr "后视图" msgid "Change camera view to the back." msgstr "改变相机视图到后方。" msgid "View Left" msgstr "左视图" msgid "Change camera view to the left." msgstr "改变相机视图到左方。" msgid "View Right" msgstr "右视图" msgid "Change camera view to the right." msgstr "改变相机视图到右方。" msgid "Perspective View" msgstr "透视图" msgid "Toggle perspective view." msgstr "开关透视图。" msgid "Field of View" msgstr "视野" msgid "Field of View: 65" msgstr "视野:65" msgid "Move Shape" msgstr "移动模型" msgid "CBBE to Vanilla (old)" msgstr "CBBE到原版(过时)" msgid "Scale Shape" msgstr "缩放模型" msgid "" "Scaling will adjust the size of a mesh. This permanently affects vertices." msgstr "缩放会调整网格的尺寸。这将永久影响顶点。" msgid "Scale" msgstr "缩放" msgid "Rotate Shape" msgstr "旋转模型" msgid "Apply a vertex position" msgstr "应用顶点位置" msgid "This permanently moves a single vertex straight to the given location." msgstr "这会直接将顶点移动到给定的位置。" msgid "" "Welcome to the New Project wizard!\n" "\n" "First, please choose a reference. Typically, this is a body (such as CBBE) " "or a conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "欢迎使用新项目向导!\n" "\n" "首先,请选择一个参照。一般来说,这是一个身形(比如CBBE)或者一个转换设置(比" "如原版到 CBBE),并且附带其滑块。" msgid "Reference" msgstr "参照" msgid "From Template" msgstr "从模板" msgid "From File" msgstr "从文件" msgid "Select a project or NIF file" msgstr "选择一个项目或NIF文件" msgid "Slider Set:" msgstr "滑块集:" msgid "Shape:" msgstr "模型:" msgid "Clear Reference" msgstr "清除参照" msgid "Next, select an outfit/mesh to work on and enter a display name for it." msgstr "然后,选择一个要处理的装备/网格,并输入它的显示名称。" msgid "Display Name" msgstr "显示名称" msgid "New Outfit" msgstr "新装备" msgid "Outfit/Mesh" msgstr "装备/网格" msgid "Select a file to load as an outfit/mesh" msgstr "选择一个文件作为装备/网格加载 。" msgid "Clear Outfit" msgstr "清除装备" msgid "Textures" msgstr "材质" msgid "Automatically search for textures" msgstr "自动搜索材质" msgid "Select a texture file" msgstr "选择一个材质文件" msgid "Select a slider preset" msgstr "选择一个滑块预设" msgid "Choose a preset:" msgstr "选择一个预设:" msgid "Low weight" msgstr "最小重量" msgid "High weight" msgstr "最大重量" msgid "Set Shape Textures" msgstr "设置模型材质" msgid "Display Texture:" msgstr "显示材质:" msgid "" "Applies the current diffuse texture path to the Outfit Studio display " "texture path." msgstr "将当前漫反射材质的路径应用到Outfit Studio显示材质的路径。" msgid "Apply Diffuse" msgstr "应用漫反射" msgid "Load Reference" msgstr "加载参照" msgid "" "Please choose a reference. Typically, this is a body (such as CBBE) or a " "conversion set (such as Vanilla To CBBE) and comes with its sliders." msgstr "" "请选择一个参照。一般来说,这是一个身形(比如CBBE)或者一个转换设置(比如原版" "到 CBBE),并附带其滑块。" msgid "Merge new sliders with existing sliders" msgstr "将新滑块集与现有滑块集合并" msgid "Load Outfit" msgstr "加载装备" msgid "" "Please select an outfit/mesh to work on and enter a display name for it." msgstr "请选择一个要处理的装备/模型,并输入它的显示名称。" msgid "Keep other shapes" msgstr "保留其他模型" msgid "Add" msgstr "增加" msgid "Delete" msgstr "删除" msgid "From Project" msgstr "从项目" msgid "Delete bone(s) from all shapes of the project." msgstr "删除项目中所有模型的骨骼。" msgid "From Selected Shapes" msgstr "从被选模型" msgid "Delete bone(s) from only the selected shapes." msgstr "删除项目中被选模型的骨骼。" msgid "From Skeleton..." msgstr "从骨架..." msgid "Choose a bone from the reference skeleton to add to the project." msgstr "从参照骨架中选择一个骨骼添加到项目。" msgid "Custom Bone..." msgstr "自定义骨骼..." msgid "Add a custom bone to the project." msgstr "将一个自定义骨骼添加到项目。" msgid "Select a bone to add" msgstr "选择一个骨骼来添加" msgid "Bones in the current reference skeleton:" msgstr "当前参考骨架中的骨骼:" msgid "Add Custom Bone" msgstr "添加自定义骨骼" msgid "Name" msgstr "名字" msgid "Slider Properties" msgstr "滑块属性" msgid "Slider Name" msgstr "滑块名称" msgid "Default Values" msgstr "默认值" msgid "Low" msgstr "最小" msgid "High" msgstr "最大" msgid "Zapped" msgstr "旋转一圈(Zapped)" msgid "Options" msgstr "选项" msgid "Invert" msgstr "反转" msgid "Hidden" msgstr "隐藏" msgid "Zap" msgstr "修正" msgid "Save Project As..." msgstr "将项目保存为..." msgid "The name of the outfit and slider set, as it will appear in BodySlide." msgstr "装备和滑块集的名称,它也会在BodySlide中显示。" msgid "Copies the current display name to the project text fields below." msgstr "将当前显示名称复制到下面的项目文本字段。" msgid "To Project" msgstr "到项目" msgid "Output File Name" msgstr "输出文件名称" msgid "" "The name of the outfit file that will end up in the game data path when " "BodySlide builds it. Should not include _1 or _0 in the name, e.g: " "lovelydress" msgstr "" "Bodyslide建立装备时,装备文件最终会出现在游戏数据路径的名称。不要在名称里包含" "_1或_0,例如:lovelydress" msgid "_0/_1.nif" msgstr "_0/_1.nif" msgid "Output Data Path" msgstr "输出数据路径" msgid "" "The location in the game's data path where BodySlide-built outfit files will " "be placed, e.g: meshes\\clothes\\lovelydress" msgstr "" "BodySlide创建的装备文件将被放置于游戏数据路径中的位置,例如:" "meshes\\clothes\\lovelydress" msgid "" "If this is enabled, BodySlide creates a low and high weight model when it " "generates the final outfit." msgstr "" "若启用此项,当Bodyslide生成最终装备时,将会创建最小重量和最大重量的模型文件。" msgid "Low/High Weight Output" msgstr "最小/最大重量输出" msgid "" "If this is enabled, only one output file will be created (useful for single-" "weighted things like hair)." msgstr "" "若启用此项,只会创建一个输出文件(对于像头发这样的单一权重的东西很有用)。" msgid "Single Weight Output" msgstr "单重量输出" msgid "Project" msgstr "项目" msgid "Slider Set File" msgstr "滑块集文件" msgid "The .osp slider set project file" msgstr ".osp滑块集项目文件" msgid "Select slider set .osp file name" msgstr "选择滑块集.osp文件名称" msgid "Shape Data Folder" msgstr "模型数据文件夹" msgid "" "The folder where all the slider data will go, as well as the base outfit NIF " "file." msgstr "所有滑块数据和基础装备NIF文件存放的位置。" msgid "Select slider data folder" msgstr "选择滑块数据文件夹" msgid "Shape Data File" msgstr "模型数据文件" msgid "The name of the output's base NIF file." msgstr "输出端的NIF基础文件的名称。" msgid "Select output NIF file name" msgstr "选择输出端NIF文件名称" msgid "" "Outfits require the reference body to be a part of the output file. Disable " "this if you've already copied the reference over or you don't want it " "included." msgstr "" "装备需要参照身体作为输出文件的一部分。若你已复制了参照或者你不希望它包含在" "内,请禁用此选项,。" msgid "Copy reference shape into output" msgstr "将参照模型复制到输出端" msgid "Shape Properties" msgstr "模型属性" msgid "Material" msgstr "材料" msgid "Choose material file" msgstr "选择材料文件" msgid "Shader" msgstr "着色器" msgid "Type" msgstr "类型" msgid "Specular Color" msgstr "高光颜色" msgid "Specular Strength" msgstr "高光大小" msgid "Specular Power" msgstr "高光强度" msgid "Emissive Color" msgstr "自发光颜色" msgid "Emissive Multiple" msgstr "自发光倍数" msgid "Remove" msgstr "移除" msgid "Textures..." msgstr "材质..." msgid "Transparency" msgstr "透明度" msgid "Threshold" msgstr "临界值" msgid "Geometry" msgstr "几何结构" msgid "Full Precision" msgstr "全精度" msgid "Sub Index" msgstr "子索引" msgid "Extra Data" msgstr "附加数据" msgid "Value" msgstr "值" msgid "Segments" msgstr "段数" msgid "Apply" msgstr "应用" msgid "SSF File" msgstr "SSF文件" msgid "Partitions" msgstr "分区" msgid "Add Partition..." msgstr "添加分区..." msgid "Adds a new partition to the shape." msgstr "将新分区添加到模型。" msgid "Delete Partition..." msgstr "删除分区..." msgid "Deletes the partition from the shape." msgstr "从模型中删除分区。" msgid "FBX Import Options..." msgstr "FBX导入选项..." msgid "Invert U" msgstr "反转U(轴)" msgid "Invert V" msgstr "反转V(轴)" msgid "Toggle:" msgstr "切换:" msgid "Search Radius" msgstr "搜索半径" msgid "Max Vertex Targets" msgstr "最大顶点目标" msgid "" "Each vertex of the reference will copy its weights to the nearest collection " "of vertices within the given radius. Bear in mind that some geometry will " "always require manual tweaking to become weighted and work well. Often, the " "default values are sufficient." msgstr "" "参照中的每个顶点将会复制它的权重到给定半径内最近的顶点集合。要牢记一些几何结" "构将总是需要手动调整来权重化和更好的工作。默认值通常是足够的。" msgid "" "Bone information incomplete. Exported data will not contain correct bone " "entries! Be sure to load a reference NIF prior to export." msgstr "" "骨骼信息不完整。导出数据将不包含正确的骨骼条目!确保在导出之前加载一个参照" "NIF。" msgid "Export Warning" msgstr "导出警告" msgid "Failed to load skeleton '%s'!" msgstr "未能加载骨架'%s'!" msgid "Root '%s' not found in skeleton '%s'!" msgstr "根'%s'未在骨架'%s'中找到!" msgid "" "No read/write permission for game data path!\n" "\n" "Please launch the program with admin elevation and make sure the game data " "path in the settings is correct." msgstr "" "没有游戏数据路径的读/写权限!\n" "\n" "请使用管理员权限启动程序,并确保游戏数据路径的设置是正确的。" msgid "Warning" msgstr "警告" msgid "Unexpected exception has occurred: %s, the program will terminate." msgstr "发生了意外的异常:%s,程序将终止。" msgid "Unexpected exception" msgstr "意外的异常" msgid "Unhandled exception has occurred: %s, the program will terminate." msgstr "发生了未处理的异常:%s,程序将终止。" msgid "Unhandled exception" msgstr "未处理的异常" msgid "Fatal exception has occurred, the program will terminate." msgstr "发生了致命的异常,程序将终止。" msgid "Fatal exception" msgstr "致命异常" msgid "" "Failed to find game install path registry value or GameDataPath in the " "config." msgstr "未能在配置中找到游戏安装路径的注册表值或GameDataPath。" msgid "" "Failed to find game install path registry key or GameDataPath in the config." msgstr "未能在配置中找到游戏安装路径的注册表项或游戏数据路径。" msgid "System language '%d' is wrong." msgstr "系统语言'%d'是错误的。" msgid "" "The system language '%d' is not supported by your system. Try installing " "support for this language." msgstr "系统语言'%d'不支持你的系统。试着为这种语言安装支持。" msgid "Failed to create group file." msgstr "未能创建组文件。" msgid "" "That group already exists in the specified file, do you wish to overwrite " "the group?" msgstr "该组已经在指定的文件中存在,你想覆盖此组吗?" msgid "Group already exists" msgstr "组已存在" msgid "" "WARNING: Game data path not configured. Would you like to show BodySlide " "where it is?" msgstr "警告:游戏数据路径未配置。你要告诉BodySlide它在哪儿吗?" msgid "Game not found" msgstr "未发现游戏" msgid "Please choose a directory to set as your Data path" msgstr "请选择一个目录来设置为你的数据路径" msgid "" "WARNING: This will delete the output files from the output folder, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "警告:这将从输出文件夹中删除输出文件,可能会导致崩溃。\n" "\n" "你想要继续吗?" msgid "Clean Build" msgstr "清除建立" msgid "Removed the following files:\n" msgstr "移除以下文件:\n" msgid " (no action)\n" msgstr "(无操作)\n" msgid "Process Successful" msgstr "步骤成功" msgid "" "Failed to write TRI file to the following location\n" "\n" "%s" msgstr "" "未能将TRI文件写入以下位置\n" "\n" "%s" msgid "Unable to process" msgstr "无法处理" msgid "" "Failed to build set to the following location\n" "\n" "%s" msgstr "" "未能将设置建立到以下的位置\n" "\n" "%s" msgid "Choose alternate file name" msgstr "选择可选(alternate)文件名" msgid "Successfully processed the following files:\n" msgstr "成功处理以下文件:\n" msgid "" "WARNING: This will delete the output files from the output folders, " "potentially causing crashes.\n" "\n" "Do you want to continue?" msgstr "" "警告:这将从输出文件夹删除(各)输出文件,可能会导致崩溃。\n" "\n" "你想要继续吗?" msgid "Clean Batch Build" msgstr "清除批量建立" msgid "" "WARNING: Game data path not configured. Files can't be removed that way." msgstr "警告:游戏数据路径未配置。这样文件就不能被删除。" msgid "" "WARNING: Game data path not configured. Continue saving files to the working " "directory?" msgstr "警告:游戏数据路径未配置。继续保存文件到工作目录吗?" msgid "" "The following sets will override the same files.\n" "Please decide which one to use and select it in the list below." msgstr "" "以下设置将覆盖相同的文件。\n" "请决定使用哪一个,并在下面的列表中选择它。" msgid "Choose output set" msgstr "选择输出设置" msgid "Processing Outfits" msgstr "处理装备" msgid "Starting..." msgstr "正在开始..." msgid "Processing '%s' (%d of %d)..." msgstr "处理'%s'(%d的%d)中..." msgid "No recorded outfit name source" msgstr "没有记录的装备名称来源" msgid "Unable to get slider set from file: " msgstr "无法从文件得到滑块集:" msgid "Unable to open slider set file: " msgstr "无法打开滑块集文件:" msgid "Unable to load input nif: " msgstr "无法加载输入nif:" msgid "Unable to create destination directory: " msgstr "无法创建目标目录:" msgid "Unable to save nif file: " msgstr "无法保存nif文件:" msgid "All group build sets processed successfully!" msgstr "所有组建立集(group build sets)处理成功!" msgid "Complete" msgstr "完成" msgid "The following sets failed" msgstr "以下集(sets)失败" msgid "Failed" msgstr "失败" msgid "Failed to load BodyslideFrame.xrc file!" msgstr "加载BodyslideFrame.xrc文件失败!" msgid "Error" msgstr "错误" msgid "Failed to load BodySlide frame!" msgstr "加载BodySlide框架失败!" msgid "Group Filter" msgstr "组过滤器" msgid "Filter by group" msgstr "通过组来过滤" msgid "Outfit Filter" msgstr "装备过滤器" msgid "Filter by outfit" msgstr "通过装备来过滤" msgid "Choose groups to filter outfit list" msgstr "选择用于过滤装备列表的组" msgid "Choose Groups" msgstr "选择组" msgid "Choose or create group file" msgstr "选择或创建组文件" msgid "What would you like the new group to be called?" msgstr "你想要给新组取什么名称?" msgid "New Group Name" msgstr "新组名" msgid "Failed to save preset (%d)!" msgstr "未能保存预置(%d)!" msgid "Failed to save preset as '%s' (%d)!" msgstr "未能保存预设为'%s' (%d)!" msgid "Choose a folder to contain the saved files" msgstr "选择一个目录来容纳保存的文件" msgid "All sets processed successfully!" msgstr "所有集(sets)处理成功!" msgid "OpenGL Error" msgstr "OpenGL错误" msgid "Checking destination..." msgstr "检查目标中..." msgid "Adding reference shapes..." msgstr "添加参照模型.中.." msgid "Adding outfit shapes..." msgstr "添加装备模型中..." msgid "Calculating slider data..." msgstr "计算滑块数据中..." msgid "Creating slider set file..." msgstr "创建滑块集文件中..." msgid "Failed to open or create slider set file: " msgstr "未能打开或创建滑块集文件:" msgid "Saving slider set file..." msgstr "保存滑块集文件中..." msgid "Failed to write to slider set file: " msgstr "未能写入滑块集文件:" msgid "Saving NIF file..." msgstr "保存NIF文件中..." msgid "Failed to write base .nif file: " msgstr "未能写入基础.nif文件:" msgid "Finished" msgstr "已完成" msgid "Could not load OBJ file '%s'!" msgstr "无法加载OBJ文件'%s'!" msgid "OBJ Error" msgstr "OBJ错误" msgid "Could not copy data from OBJ file '%s'!" msgstr "无法从OBJ文件'%s'复制数据!" msgid "" "The vertex count of the selected .obj file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "被选.obj文件的顶点数与当前被选装备模型相匹配。您想更新当前模型吗?(点击否以" "创建一个新模型)" msgid "Merge or New" msgstr "合并或新建" msgid "Update Vertex Positions?" msgstr "更新顶点位置?" msgid "Vertex Position Update" msgstr "顶点位置更新" msgid "Update Texture Coordinates?" msgstr "更新材质坐标?" msgid "UV Update" msgstr "UV更新" msgid "Please specify a name for the new shape" msgstr "请为新模型指定一个名字" msgid "New Shape Name" msgstr "新模型名称" msgid "Import Data Error" msgstr "导入数据错误" msgid "Gathering bones..." msgstr "聚集骨骼中..." msgid "Initializing proximity data..." msgstr "初始化邻近数据中..." msgid "Copying bone weights..." msgstr "复制骨骼权重中..." msgid "Transferring bone weights..." msgstr "转移骨骼权重中..." msgid "Template source entries are invalid." msgstr "模板源条目无效。" msgid "Reference Error" msgstr "参照错误" msgid "" "NIF version not supported!\n" "\n" "File: %s\n" "%s\n" "User Version: %i\n" "User Version 2: %i" msgstr "" "NIF版本不支持!\n" "\n" "文件:%s\n" "%s\n" "用户版本:%i\n" "用户版本2:%i" msgid "Could not load reference NIF file '%s'!" msgstr "无法加载参照NIF文件'%s'!" msgid "Could not load slider set file '%s'!" msgstr "无法加载滑块集文件'%s'!" msgid "Reference NIF file '%s' does not contain any shapes." msgstr "参照NIF文件'%s'没有包含任何模型。" msgid "Shape '%s' not found in reference NIF file '%s'!" msgstr "模型 '%s'未能在参照NIF文件 '%s'中找到!" msgid "NIF Error" msgstr "NIF错误" msgid "Could not load NIF file '%s'!" msgstr "无法加载NIF文件'%s'!" msgid "Loading slider set..." msgstr "加载滑块集中..." msgid "Adding slider set..." msgstr "添加滑块集中......" msgid "Retrieving sliders..." msgstr "检索(各)滑块中..." msgid "Loading outfit shapes..." msgstr "加载装备模型中..." msgid "Updating slider data..." msgstr "更新滑块数据中..." msgid "" "There was cloth physics data loaded at some point (BSClothExtraData). Please " "choose all the origins to use in the output." msgstr "" "有布料物理数据被加载在某些点(BSClothExtraData)。请选择所有输出时要用到的" "源。" msgid "Choose cloth data" msgstr "选择布料数据" msgid "" "The vertex count of the selected .fbx file matches the currently selected " "outfit shape. Do you wish to update the current shape? (click No to create " "a new shape)" msgstr "" "被选.fbx文件的顶点数与当前被选装备模型相匹配。您想更新当前模型吗?(点击否以" "创建一个新模型)" msgid "Update Animation Weighting?" msgstr "更新动画权重吗?" msgid "Animation Weight Update" msgstr "动画权重更新" msgid "Failed to load outfitStudio.xrc file!" msgstr "加载outfitStudio.xrc文件失败!" msgid "Failed to load Outfit Studio frame!" msgstr "加载Outfit Studio框架失败!" msgid "Ready!" msgstr "已准备!" msgid "Creating sliders..." msgstr "创建各滑块中..." msgid "Clearing old sliders..." msgstr "清除各旧滑块中..." msgid "Loading slider: " msgstr "正在加载滑块:" msgid "Turn on edit mode for this slider." msgstr "为此滑块打开编辑模式。" msgid "Weaken slider data by 1%." msgstr "减弱滑块数据1%。" msgid "Strengthen slider data by 1%." msgstr "增强滑块数据1%。" msgid "Enter a name for the new slider:" msgstr "为新滑块输入一个名称:" msgid "Create New Slider" msgstr "创建新滑块" msgid "" "You can only edit the base shape when all sliders are zero. Do you wish to " "set all sliders to zero now? Note, use the pencil button next to a slider " "to enable editing of that slider's morph." msgstr "" "当所有滑块为零时你只能编辑基础模型。你现在希望设置所有滑块为零吗?注意,使用" "滑块旁边的铅笔按钮来开启对该滑块变形的编辑。" msgid "Creating project '%s'..." msgstr "创建项目'%s'中..." msgid "Loading reference..." msgstr "加载参照中..." msgid "Loading outfit..." msgstr "加载装备中..." msgid "Creating outfit..." msgstr "创建装备中..." msgid "Creating %zu slider(s)..." msgstr "创建(各)%zu滑块中..." msgid "Select a slider set to load" msgstr "选择要加载的滑块集" msgid "Select a slider set to add" msgstr "选择要添加的滑块" msgid "Failed to open '%s' as a slider set file!" msgstr "未能将'%s'作为滑块集文件打开!" msgid "Slider Set Error" msgstr "滑块集错误" msgid "Please choose an outfit to load" msgstr "请选择一个要加载的装备" msgid "Load a slider set" msgstr "加载一个滑块集" msgid "Loading project..." msgstr "加载项目中..." msgid "Loading outfit data..." msgstr "加载装备数据中..." msgid "Failed to create project '%s' from file '%s' (%d)!" msgstr "未能创建项目'%s'(从文件'%s' 中)(%d)!" msgid "Loading reference shape '%s'..." msgstr "加载参照模型'%s'中..." msgid "Loading textures..." msgstr "加载材质中..." msgid "" "You're currently editing slider data, please exit the slider's edit mode " "(pencil button) and try again." msgstr "你当前正在编辑滑块数据,请退出滑块编辑模式(铅笔按钮)并重试。" msgid "Loading reference set..." msgstr "加载参照集中..." msgid "Creating reference..." msgstr "生成参照中..." msgid "There are no valid shapes loaded!" msgstr "无有效模型被加载!" msgid "" "The following shapes have unweighted vertices, which can cause issues. The " "affected vertices have been put under a mask. Do you want to save anyway?" msgstr "" "以下模型含有未加权重的顶点,可能会导致问题。受影响的顶点已被遮罩。你确定要保" "存吗?" msgid "Unweighted Vertices" msgstr "移除顶点权重" msgid "" "The following shapes were renamed and won't have slider data attached. " "Rename the duplicates yourself beforehand." msgstr "以下模型已重命名,并且不会附加滑块数据。请事先重命名重复项。" msgid "Renamed Shapes" msgstr "重命名模型" msgid "Saving project '%s'..." msgstr "保存项目'%s'中..." msgid "Invalid or no slider set file specified! Please try again." msgstr "无效或没有指定的滑块集文件!请重试。" msgid "No outfit name specified! Please try again." msgstr "没有指定的装备名!请重试。" msgid "No data folder specified! Please try again." msgstr "没有指定的数据目录!请重试。" msgid "" "An invalid or no base outfit .nif file name specified! Please try again." msgstr "一个无效或无基础装备.nif文件的名称被指定!请重试。" msgid "No game file path specified! Please try again." msgstr "没有游戏文件路径被指定!请重试。" msgid "No game file name specified! Please try again." msgstr "没有游戏文件名被指定!请重试。" msgid "Import NIF file" msgstr "导入NIF文件" msgid "Importing NIF file..." msgstr "导入NIF文件中..." msgid "Refreshing GUI..." msgstr "刷新GUI(图形用户界面)中..." msgid "Finished." msgstr "已完成。" msgid "Export outfit NIF" msgstr "导出装备NIF" msgid "Failed to save NIF file '%s'!" msgstr "未能保存NIF文件'%s!" msgid "Export Error" msgstr "导出错误" msgid "Export project NIF" msgstr "导出项目NIF" msgid "Failed to save NIF file '%s' with reference!" msgstr "未能保存带参照的NIF文件'%s'!" msgid "Import physics data to project" msgstr "将物理数据导入到项目" msgid "Failed to import physics data file '%s'!" msgstr "未能导入物理数据文件'%s'!" msgid "Import Error" msgstr "导入错误" msgid "There is no physics data loaded!" msgstr "没有物理数据被加载!" msgid "Info" msgstr "信息" msgid "Please choose the physics data source you want to export." msgstr "请选择你想导出的物理数据源。" msgid "Choose physics data" msgstr "选择物理数据" msgid "Export physics data" msgstr "导出物理数据" msgid "Failed to save physics data file '%s'!" msgstr "未能保存物理数据文件'%s'!" msgid "This function requires at least one slider position to be non-zero." msgstr "此功能需要至少一个滑块不为零。" msgid "" "Create a conversion slider for the current slider settings with the " "following name: " msgstr "使用以下名称为当前滑块设置创建一个转换滑块:" msgid "Create New Conversion Slider" msgstr "创建新的转换滑块" msgid "Field of View: %d" msgstr "视野:%d" msgid "There are no sliders loaded!" msgstr "没有滑块被加载!" msgid "No changes were made to the sliders, so no preset was saved!" msgstr "滑块没有被改变,所以预设没有被保存!" msgid "There is no shape selected!" msgstr "没有被选模型!" msgid "There is no reference shape!" msgstr "没有参考模型!" msgid "There is no slider in edit mode to import data to!" msgstr "编辑模式中没有可导入数据的滑块!" msgid "Import .bsd slider data" msgstr "导入.bsd滑块数据" msgid "Import .obj file for slider calculation" msgstr "为滑块计算导入.obj文件" msgid "Vertex count of .obj file mesh does not match currently selected shape!" msgstr ".obj 网格文件的顶点数量与当前被选模型不匹配!" msgid "Import .tri morphs" msgstr "导入.tri变形" msgid "This will delete all loaded sliders. Are you sure?" msgstr "这会删除所有已加载的滑块。你确定吗?" msgid "TRI Import" msgstr "TRI导入" msgid "Failed to load TRI file!" msgstr "未能加载TRI文件!" msgid "" "Added morphs for the following shapes:\n" "\n" "%s" msgstr "" "为以下模型添加变形数据:\n" "\n" "%s" msgid "Import .fbx file for slider calculation" msgstr "为滑块计算导入.fbx文件" msgid "There is no slider in edit mode to export data from!" msgstr "编辑模式中没有可导出数据的滑块!" msgid "Export .bsd slider data to directory" msgstr "导出.bsd滑块数据到目录" msgid "Export .bsd slider data" msgstr "导出.bsd滑块数据" msgid "Export .obj slider data to directory" msgstr "导出.obj滑块数据到目录" msgid "Export .obj slider data" msgstr "导出.obj滑块数据" msgid "Failed to export OBJ file!" msgstr "未能导出OBJ文件!" msgid "Failed to export FBX file!" msgstr "未能导出FBX文件!" msgid "OSD Import" msgstr "OSD导入" msgid "Import .osd file" msgstr "导入.osd文件" msgid "Failed to import OSD file!" msgstr "未能导入OSD文件!" msgid "Export .osd file" msgstr "导出.osd文件" msgid "Failed to export OSD file!" msgstr "未能导出OSD文件!" msgid "Export .tri morphs" msgstr "导出.tri变形" msgid "Failed to export TRI file!" msgstr "未能导出TRI文件!" msgid "Are you sure you wish to clear the unmasked slider data " msgstr "您确定要清除未被遮罩的滑块数据吗" msgid "for the selected shapes? This cannot be undone." msgstr "对被选模型?这不能被撤消。" msgid "Confirm data erase" msgstr "确认数据擦除" msgid "for the shape \"" msgstr "为模型\"" msgid "Enter a name for the new zap:" msgstr "为新修正命名:" msgid "Create New Zap" msgstr "创建新修正" msgid "There is no slider in edit mode to negate!" msgstr "编辑模式中没有可无效化的滑块!" msgid "There is no slider in edit mode to create a mask from!" msgstr "编辑模式中没有可创建遮罩的滑块!" msgid "Are you sure you wish to delete the selected slider(s)?" msgstr "你确定要删除被选滑块吗(s)" msgid "\"? This cannot be undone." msgstr "\"吗?这无法撤销。" msgid "Confirm slider delete" msgstr "确认滑块删除" msgid "There is no slider in edit mode to show properties for!" msgstr "编辑模式中没有可显示属性的滑块!" msgid "Conforming all shapes..." msgstr "整合所有模型中..." msgid "Conforming: " msgstr "正在整合:" msgid "All shapes conformed." msgstr "所有模型已整合。" msgid "Conforming..." msgstr "整合中..." msgid "Initializing data..." msgstr "初始化数据中..." msgid "Shape(s) conformed." msgstr "模型已整合。" msgid "Import .obj file for new shape" msgstr "为新模型导入.obj文件" msgid "Export selected shapes as an .obj file" msgstr "将被选模型导出为一个.obj文件" msgid "Export shape as an .obj file" msgstr "将模型导出为一个.obj文件" msgid "Export project as an .obj file" msgstr "将项目导出为一个.obj文件" msgid "Export project as an .fbx file" msgstr "将项目导出为一个.fbx文件" msgid "Export shape as an .fbx file" msgstr "将模型导出为一个.fbx文件" msgid "Export selected shapes as an .fbx file" msgstr "将被选模型导出为一个.fbx文件" msgid "Import .fbx file for new shape" msgstr "为新模型导入.fbx文件" msgid "Please enter a new unique name for the shape." msgstr "请为模型输入一个独有的的新名称。" msgid "Rename Shape" msgstr "重命名模型" msgid "" "Rotating slider data is currently not possible using the Rotate Shape dialog." msgstr "目前无法使用旋转模型对话框旋转滑块数据。" msgid "Rotate" msgstr "旋转" msgid "" "You can only copy shapes into an outfit, and there is no outfit in the " "current project. Load one first!" msgstr "你只能将模型复制进装备,且当前项目中没有装备。请先加载一个!" msgid "Please enter a unique name for the duplicated shape." msgstr "请为复制的模型命一个独有的名。" msgid "Duplicate Shape" msgstr "复制模型" msgid "" "Are you sure you wish to delete the unmasked vertices of the selected " "shapes? This action cannot be undone." msgstr "确定删除未遮罩的模型吗?此操作无法撤销。" msgid "" "Are you sure you wish to delete the selected shapes? This action cannot be " "undone." msgstr "确定删除被选模型吗?此操作无法撤销。" msgid "Confirm Delete" msgstr "确认删除" msgid "No bone name was entered!" msgstr "没有骨骼名称被输入!" msgid "Bone '%s' already exists in the project!" msgstr "骨骼'%s'已经存在于项目中!" msgid "" "Sorry, you can't copy weights from the reference shape to itself. Skipping " "this shape." msgstr "抱歉,你无法将参照模型的权重复制到它本身。跳过此模型。" msgid "Can't copy weights" msgstr "无法复制权重" msgid "Copying selected bone weights..." msgstr "复制被选骨骼权重中..." msgid "Sorry, you can't copy weights from the reference shape to itself." msgstr "对不起,你无法复制参照模型的权重到它本身。 。" msgid "The vertex count of the reference and chosen shape is not the same!" msgstr "参照和被选模型的顶点数不同!" msgid "Outfit Studio: OpenGL context is not OK." msgstr "Outfit Studio:OpenGL环境异常。" msgid "Adding NIF file..." msgstr "添加NIF文件中..." msgid "Adding OBJ file..." msgstr "添加OBJ文件中..." msgid "Adding FBX file..." msgstr "添加FBX文件中..." msgid "Loading slider file..." msgstr "加载滑块文件中..." msgid "Preview failed: OpenGL context is not OK." msgstr "Outfit Studio:OpenGL环境异常。" msgid "Version" msgstr "版本" msgid "" "Version of NIF file doesn't match current target game. To use the meshes for " "the target game, export to OBJ/FBX and reload them again." msgstr "" "NIF文件的版本不匹配当前目标游戏。若要为目标游戏使用此网格,请导出到OBJ/FBX并" "重新加载。" msgid "Would you like Skyrim NIFs to be optimized for SSE during this session?" msgstr "你想在本阶段将NIF文件为特别版进行优化吗?" msgid "Language" msgstr "语言" msgid "Use the selected language for the program." msgstr "为程序使用被选语言。" msgid "Rendering" msgstr "渲染中" msgid "Background Color" msgstr "背景颜色" msgid "Background color of the renderer." msgstr "渲染器的背景颜色。" msgid "Unload Project" msgstr "卸载项目" msgid "Unload Project...\tCtrl+W" msgstr "卸载项目..\tCtrl+W" msgid "Unloads the project and creates an empty new one." msgstr "卸载此项目并新建一个空项目。" msgid "" "Do you really want to unload the project? All unsaved changes will be lost." msgstr "你真的要卸载项目吗?所有未保存的修改将丢失。" msgid "Delete Vertices..." msgstr "删除顶点..." msgid "Deletes all unmasked vertices of the currently selected shapes." msgstr "删除当前被选模型所有未被遮罩的顶点。" msgid "Separate Vertices..." msgstr "分离顶点..." msgid "Please enter a unique name for the new separated shape." msgstr "请为新分离的模型命一个独有的名。" msgid "Separate the current shape into two by using the mask." msgstr "用遮罩将当前模型分离为两个。" msgid "Show the Normal Map Generator dialog." msgstr "显示法线贴图生成器对话框。" msgid "Normal Map Generator" msgstr "法线贴图生成器" msgid "Layers" msgstr "图层" msgid "Load or save preset layer settings." msgstr "打开或保存预设图层设置。" msgid "Choose a normals generator preset file..." msgstr "选择一个法线生成器预设文件..." msgid "Save normals generator preset to..." msgstr "将法线生成器预设保存到..." msgid "Background" msgstr "背景" msgid "Background File" msgstr "背景文件" msgid "File source for this layer." msgstr "此图层的文件来源。" msgid "" "File containing normals data to combine. Note this file should fit the mesh " "UVs." msgstr "包含要合并的法线数据的文件。注意这个文件应适应网格uv。" msgid "Color" msgstr "颜色" msgid "Solid background color (if file is not set)." msgstr "纯背景色(若文件没有设置)。" msgid "Resolution" msgstr "分辨率" msgid "" "Output texture dimensions. By default all images will be scaled to fit this " "size." msgstr "输出材质的尺寸(dimensions)。默认所有图像都会被缩放以适应此尺寸。" msgid "Is Tangent Space?" msgstr "是切空间吗?" msgid "" "True if the normals data in the layer file is in tangent space, false if " "they are in model space (msn)." msgstr "" "若图层文件中的法线数据位于切空间中则为真;若位于模型空间(msn)中则为假。" msgid "A greyscale image used to mask updates to destination image." msgstr "一个用于屏蔽目标图像更新的灰度图像。" msgid "X Offset" msgstr "X偏移量" msgid "Y Offset" msgstr "Y偏移量" msgid "Offset to apply to image position." msgstr "应用于图像位置的偏移。" msgid "If true, scale image to match background resolution." msgstr "若为真,缩放图像来匹配背景分辨率。" msgid "Add Layer" msgstr "添加图层" msgid "Add a new layer after the current one in the layer list." msgstr "添加一个新图层于图层列表中的当前图层之后。" msgid "Move Up" msgstr "上移" msgid "Move selected layer up one position." msgstr "将被选图层向上移动一个位置。" msgid "Delete Layer" msgstr "删除图层" msgid "Delete the selected layer." msgstr "删除被选图层。" msgid "Backup destination file" msgstr "备份目标文件" msgid "" "Save a copy of an existing normal map if one already exists. File is saved " "in the original directory." msgstr "若文件已存在,保存现有法线贴图的副本。文件保存在原目录中。" msgid "Compress output" msgstr "压缩输出内容" msgid "" "Compress output file using BC7 compression. This can make saving the file " "take a VERY long time!" msgstr "使用BC7 compression压缩输出文件。这可能会使保存文件花费很长时间!" msgid "Save to background layer file" msgstr "保存到背景图层文件" msgid "" "Use the file name specified in the background layer to save the normal map." msgstr "使用背景图层中指定的文件名来保存法线贴图。" msgid "Location to save normal map to." msgstr "保存法线贴图的位置。" msgid "Choose an output file..." msgstr "选择一个输出文件..." msgid "Display current settings on mesh in preview window." msgstr "在预览窗口中显示网格上的当前设置。" msgid "Generate" msgstr "生成" msgid "Generate and save the normal map file." msgstr "生成并保存法线贴图文件。" msgid "Colors" msgstr "颜色" msgid "Brush Color" msgstr "笔刷颜色" msgid "Color of the brush." msgstr "画笔颜色。" msgid "Edit Color" msgstr "编辑颜色" msgid "Edit Alpha" msgstr "编辑透明度" msgid "Color Paint" msgstr "色漆" msgid "Color Paint\t7" msgstr "色漆\t7" msgid "" "Apply vertex colors.\n" "Hold down the ALT key to remove colors." msgstr "" "应用顶点颜色\n" "按住ALT键以删除颜色。" msgid "Alpha Paint" msgstr "绘制透明度" msgid "Alpha Paint\t8" msgstr "绘制透明度\\8" msgid "" "Apply vertex alpha.\n" "Hold down the ALT key to remove alpha." msgstr "" "应用顶点透明度\n" "按住ALT键以删除透明度。" msgid "Vertex Colors" msgstr "顶点颜色" msgid "Vertex Alpha" msgstr "顶点透明度" msgid "Outfit Studio" msgstr "Outfit Studio" msgid "Browse" msgstr "浏览" msgid "Skyrim Special Edition" msgstr "上古卷轴特别版" msgid "Fallout 4 VR" msgstr "辐射4 VR版" msgid "Skyrim VR" msgstr "天际 VR版" ================================================ FILE: lib/DDS.h ================================================ //-------------------------------------------------------------------------------------- // DDS.h // // This header defines constants and structures that are useful when parsing // DDS files. DDS files were originally designed to use several structures // and constants that are native to DirectDraw and are defined in ddraw.h, // such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar // (compatible) constants and structures so that one can use DDS files // without needing to include ddraw.h. // // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. // // http://go.microsoft.com/fwlink/?LinkId=248926 // http://go.microsoft.com/fwlink/?LinkId=248929 // http://go.microsoft.com/fwlink/?LinkID=615561 //-------------------------------------------------------------------------------------- #pragma once #include namespace DirectX { #pragma pack(push,1) constexpr uint32_t DDS_MAGIC = 0x20534444; // "DDS " struct DDS_PIXELFORMAT { uint32_t size; uint32_t flags; uint32_t fourCC; uint32_t RGBBitCount; uint32_t RBitMask; uint32_t GBitMask; uint32_t BBitMask; uint32_t ABitMask; }; #define DDS_FOURCC 0x00000004 // DDPF_FOURCC #define DDS_RGB 0x00000040 // DDPF_RGB #define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS #define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE #define DDS_LUMINANCEA 0x00020001 // DDPF_LUMINANCE | DDPF_ALPHAPIXELS #define DDS_ALPHAPIXELS 0x00000001 // DDPF_ALPHAPIXELS #define DDS_ALPHA 0x00000002 // DDPF_ALPHA #define DDS_PAL8 0x00000020 // DDPF_PALETTEINDEXED8 #define DDS_PAL8A 0x00000021 // DDPF_PALETTEINDEXED8 | DDPF_ALPHAPIXELS #define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV // DDS_BUMPLUMINANCE 0x00040000 #ifndef MAKEFOURCC #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ (static_cast(static_cast(ch0)) \ | (static_cast(static_cast(ch1)) << 8) \ | (static_cast(static_cast(ch2)) << 16) \ | (static_cast(static_cast(ch3)) << 24)) #endif /* MAKEFOURCC */ #ifndef DDSGLOBALCONST #if defined(__GNUC__) && !defined(__MINGW32__) #define DDSGLOBALCONST extern const __attribute__((weak)) #else #define DDSGLOBALCONST extern const __declspec(selectany) #endif #endif /* DDSGLOBALCONST */ DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT1 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT2 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT3 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT4 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT5 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC4_UNORM = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC4_SNORM = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC5_UNORM = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC5_SNORM = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R8G8_B8G8 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_G8R8_G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_YUY2 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_UYVY = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8R8G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X8R8G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8B8G8R8 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X8B8G8R8 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_G16R16 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R5G6B5 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A1R5G5B5 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X1R5G5B5 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A4R4G4B4 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X4R4G4B4 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R8G8B8 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8R3G3B2 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R3G3B2 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A4L4 = { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x0f, 0, 0, 0xf0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L8 = { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L16 = { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8 = { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0, 0, 0xff00 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8_ALT = { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x00ff, 0, 0, 0xff00 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L8_NVTT1 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xff, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L16_NVTT1 = { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xffff, 0, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8_NVTT1 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00ff, 0, 0, 0xff00 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8 = { sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0, 0, 0, 0xff }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_V8U8 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_Q8W8V8U8 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_V16U16 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0 }; // D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A2R10G10B10 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 }; DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A2B10G10R10 = { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }; // We do not support the following legacy Direct3D 9 formats: // DDSPF_A2W10V10U10 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }; // DDSPF_L6V5U5 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 16, 0x001f, 0x03e0, 0xfc00, 0 }; // DDSPF_X8L8V8U8 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 }; // This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat) DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DX10 = { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }; #define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT #define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT #define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH #define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH #define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE #define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT #define DDS_WIDTH 0x00000004 // DDSD_WIDTH #define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE #define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP #define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX #define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX #define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX #define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY #define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY #define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ #define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ #define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\ DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\ DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ ) #define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP #define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME // Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION enum DDS_RESOURCE_DIMENSION : uint32_t { DDS_DIMENSION_TEXTURE1D = 2, DDS_DIMENSION_TEXTURE2D = 3, DDS_DIMENSION_TEXTURE3D = 4, }; // Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG enum DDS_RESOURCE_MISC_FLAG : uint32_t { DDS_RESOURCE_MISC_TEXTURECUBE = 0x4L, }; enum DDS_MISC_FLAGS2 : uint32_t { DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L, }; #ifndef DDS_ALPHA_MODE_DEFINED #define DDS_ALPHA_MODE_DEFINED enum DDS_ALPHA_MODE : uint32_t { DDS_ALPHA_MODE_UNKNOWN = 0, DDS_ALPHA_MODE_STRAIGHT = 1, DDS_ALPHA_MODE_PREMULTIPLIED = 2, DDS_ALPHA_MODE_OPAQUE = 3, DDS_ALPHA_MODE_CUSTOM = 4, }; #endif struct DDS_HEADER { uint32_t size; uint32_t flags; uint32_t height; uint32_t width; uint32_t pitchOrLinearSize; uint32_t depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags uint32_t mipMapCount; uint32_t reserved1[11]; DDS_PIXELFORMAT ddspf; uint32_t caps; uint32_t caps2; uint32_t caps3; uint32_t caps4; uint32_t reserved2; }; struct DDS_HEADER_DXT10 { DXGI_FORMAT dxgiFormat; uint32_t resourceDimension; uint32_t miscFlag; // see D3D11_RESOURCE_MISC_FLAG uint32_t arraySize; uint32_t miscFlags2; // see DDS_MISC_FLAGS2 }; #pragma pack(pop) static_assert(sizeof(DDS_PIXELFORMAT) == 32, "DDS pixel format size mismatch"); static_assert(sizeof(DDS_HEADER) == 124, "DDS Header size mismatch"); static_assert(sizeof(DDS_HEADER_DXT10) == 20, "DDS DX10 Extended Header size mismatch"); } // namespace ================================================ FILE: lib/FSEngine/FSBSA.cpp ================================================ /***** BEGIN LICENSE BLOCK ***** BSD License Copyright (c) 2005-2012, NIF File Format Library and Tools All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the NIF File Format Library and Tools project may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ #include "FSBSA.h" #ifdef __linux__ #include #else #include #endif #include "../DDS.h" #include #include #include #include #include "../LZ4F/lz4.h" #include "../LZ4F/lz4frame.h" #ifndef MAX_PATH #define MAX_PATH 4096 #endif wxUint32 BSA::BSAFile::size() const { if (sizeFlags > 0) { // Skyrim and earlier return sizeFlags & OB_BSAFILE_SIZEMASK; } return (packedLength == 0) ? unpackedLength : packedLength; } bool BSA::BSAFile::compressed() const { return (sizeFlags & OB_BSAFILE_FLAG_COMPRESS) != 0; } //! Reads a foldername sized string (length + null-terminated string) from the BSA static bool BSAReadSizedString(wxFile &bsa, std::string &s) { wxUint8 len; if (bsa.Read((char *)&len, 1) != 1) return false; if (len <= 0) { s.clear(); return true; } wxMemoryBuffer b(len); if (bsa.Read(b.GetData(), len) == len) { s = b; return true; } return false; } template static void SequenceToLowerCase(TIter begin, TIter end) { for (auto it = begin; it != end; ++it) *it |= 0x20; } wxMemoryBuffer gUncompress(const wxMemoryBuffer &data, wxUint32 unpackedSize = 0, int skip = 0) { if (data.GetDataLen() <= 4) { // Input data is truncated return wxMemoryBuffer(); } wxMemoryInputStream input((char*)data.GetData() + skip, data.GetDataLen() - skip); wxZlibInputStream zlibStream(input); wxMemoryBuffer result; if (!zlibStream.CanRead()) return result; if (unpackedSize > 0) { // Allocate if unpacked size is known result.SetBufSize(unpackedSize); result.SetDataLen(unpackedSize); zlibStream.Read(result.GetData(), unpackedSize); } else { wxMemoryOutputStream output; zlibStream.Read(output); result.SetBufSize(output.GetLength()); result.SetDataLen(output.GetLength()); output.CopyTo(result.GetData(), result.GetDataLen()); } return result; } wxMemoryBuffer lz4fUncompress(const wxMemoryBuffer& data, wxUint32 unpackedSize = 0, int skip = 0) { if (data.GetDataLen() <= skip) { // Input data is truncated return wxMemoryBuffer(); } (void*)&unpackedSize; // unused size_t srcSize = data.GetDataLen() - skip; size_t dstSize = ((unsigned int*)data.GetData())[0]; wxMemoryBuffer result(dstSize); LZ4F_decompressionContext_t dCtx = nullptr; LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION); LZ4F_decompressOptions_t options = { 0 }; LZ4F_decompress(dCtx, result.GetData(), &dstSize, (char*)data.GetData() + skip, &srcSize, &options); LZ4F_freeDecompressionContext(dCtx); result.SetDataLen(dstSize); return result; } wxMemoryBuffer lz4Uncompress(const wxMemoryBuffer& data, wxUint32 unpackedSize = 0) { if (data.GetDataLen() <= 0) { // Input data is truncated return wxMemoryBuffer(); } size_t srcSize = data.GetDataLen(); size_t dstSize = unpackedSize; wxMemoryBuffer result(dstSize); LZ4_decompress_safe_partial((char*)data.GetData(), (char*)result.GetData(), srcSize, dstSize, dstSize); result.SetDataLen(dstSize); return result; }; BSA::BSA(const std::string &filename) : FSArchiveFile(), bsa(filename), bsaInfo(filename), status("initialized") { bsaPath = bsaInfo.GetPathWithSep() + bsaInfo.GetFullName(); bsaBase = bsaInfo.GetPath(); bsaName = bsaInfo.GetFullName(); } BSA::~BSA() { close(); } bool BSA::canOpen(const std::string &fn) { wxFile f(fn); if (f.IsOpened()) { wxUint32 magic, version; if (f.Read((char *)& magic, sizeof(magic)) != 4) return false; if (magic == F4_BSAHEADER_FILEID) { if (f.Read((char *)&version, sizeof(version)) != 4) return false; return version == F4_BSAHEADER_VERSION || F4_BSAHEADER_VERSION2 || F4_BSAHEADER_VERSION3 || version == SF_BSAHEADER_VERSION2 || version == SF_BSAHEADER_VERSION3; } else if (magic == OB_BSAHEADER_FILEID) { if (f.Read((char *)& version, sizeof(version)) != 4) return false; return (version == OB_BSAHEADER_VERSION || version == F3_BSAHEADER_VERSION || version == SSE_BSAHEADER_VERSION); } else return magic == MW_BSAHEADER_FILEID; } return false; } bool BSA::open() { wxMutexLocker lock(bsaMutex); try { bsa.Open(bsaPath); if (!bsa.IsOpened()) throw std::string("file open"); wxUint32 magic, version; bsa.Read((char*)&magic, sizeof(magic)); if (magic == F4_BSAHEADER_FILEID) { bsa.Read((char*)&version, sizeof(version)); if (version != F4_BSAHEADER_VERSION && version != F4_BSAHEADER_VERSION2 && version != F4_BSAHEADER_VERSION3 && version != SF_BSAHEADER_VERSION2 && version != SF_BSAHEADER_VERSION3) throw std::string("file version"); headerVersion = version; ssize_t headerSize = sizeof(ba2Header); if (version == F4_BSAHEADER_VERSION || version == F4_BSAHEADER_VERSION2 || version == F4_BSAHEADER_VERSION3) headerSize = 16; else if (version == SF_BSAHEADER_VERSION2) headerSize = 24; else if (version == SF_BSAHEADER_VERSION3) headerSize = 28; if (bsa.Read((char*)&ba2Header, headerSize) != headerSize) throw std::string("header size"); numFiles = ba2Header.numFiles; namePrefix = false; fileNameSuperBuffer = std::make_unique(numFiles * (MAX_PATH + 2) + 1); char* superBufferPtr = fileNameSuperBuffer.get(); std::vector path_sizes(numFiles * 2); if (bsa.Seek(ba2Header.nameTableOffset)) { bsa.Read(superBufferPtr, numFiles * (MAX_PATH + 2)); wxUint32 cursor = 0; wxUint32 n = 0; for (wxUint32 i = 0; i < ba2Header.numFiles; i++) { wxUint16 len; len = *(wxUint16*)(superBufferPtr + cursor); cursor += 2; path_sizes[n++] = cursor; cursor += len; path_sizes[n++] = cursor; } } std::replace(superBufferPtr, superBufferPtr + numFiles * (MAX_PATH + 2), '\\', '/'); std::string h(ba2Header.type, 4); if (h == "GNRL") { // General BA2 Format if (bsa.Seek(headerSize + 8)) { root.files.reserve(ba2Header.numFiles); BA2GeneralInfo* finfo = new BA2GeneralInfo[ba2Header.numFiles]; bsa.Read(finfo, 36 * numFiles); wxUint32 n = 0; for (wxUint32 i = 0; i < ba2Header.numFiles; i++) { insertFile(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n], finfo[i].packedSize, finfo[i].unpackedSize, finfo[i].offset); /* Folders not required in this tool std::string fullFile = std::string(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n]); std::string file; std::string folder; int folderStrIndex = fullFile.find_last_of('/'); if (folderStrIndex >= 0) { file = fullFile.substr(folderStrIndex + 1, path_sizes[n + 1] - path_sizes[n] - folderStrIndex + 1); folder = fullFile.substr(0, folderStrIndex); } else file = fullFile; insertFile(insertFolder(folder), file, finfo[i].packedSize, finfo[i].unpackedSize, finfo[i].offset); */ n += 2; } delete[] finfo; } } else if (h == "DX10") { // Texture BA2 Format if (bsa.Seek(headerSize + 8)) { root.files.reserve(ba2Header.numFiles); wxUint32 n = 0; for (wxUint32 i = 0; i < ba2Header.numFiles; i++) { BA2Tex tex; bsa.Read((char*)&tex.header, 24); std::vector texChunks(tex.header.numChunks); bsa.Read(texChunks.data(), tex.header.numChunks * 24); tex.chunks = std::move(texChunks); const BA2TexChunk& chunk = tex.chunks[0]; insertFile(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n], chunk.packedSize, chunk.unpackedSize, chunk.offset, &tex); /* Folders not required in this tool std::string fullFile = std::string(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n]); std::string file; std::string folder; int folderStrIndex = fullFile.find_last_of('/'); if (folderStrIndex >= 0) { file = fullFile.substr(folderStrIndex + 1, path_sizes[n + 1] - path_sizes[n] - folderStrIndex + 1); folder = fullFile.substr(0, folderStrIndex); } else file = fullFile; insertFile(insertFolder(folder), file, chunk.packedSize, chunk.unpackedSize, chunk.offset, tex); */ n += 2; } } } } // From NifSkope else if (magic == OB_BSAHEADER_FILEID) { bsa.Read((char*)&version, sizeof(version)); if (version != OB_BSAHEADER_VERSION && version != F3_BSAHEADER_VERSION && version != SSE_BSAHEADER_VERSION) throw std::string("file version"); headerVersion = version; OBBSAHeader header{}; if (bsa.Read((char *)& header, sizeof(header)) != sizeof(header)) throw std::string("header size"); numFiles = header.FileCount; if ((header.ArchiveFlags & OB_BSAARCHIVE_PATHNAMES) == 0 || (header.ArchiveFlags & OB_BSAARCHIVE_FILENAMES) == 0) throw std::string("header flags"); compressToggle = (header.ArchiveFlags & OB_BSAARCHIVE_COMPRESSFILES) != 0; if (version == F3_BSAHEADER_VERSION || version == SSE_BSAHEADER_VERSION) namePrefix = (header.ArchiveFlags & F3_BSAARCHIVE_PREFIXFULLFILENAMES) != 0; else namePrefix = false; wxUint32 folderSize = 0; if (version != SSE_BSAHEADER_VERSION) folderSize = sizeof(OBBSAFolderInfo); else folderSize = sizeof(SSEBSAFolderInfo); if (bsa.Seek(header.FolderRecordOffset + header.FolderNameLength + header.FolderCount * (1 + folderSize) + header.FileCount * sizeof(OBBSAFileInfo)) == wxInvalidOffset) throw std::string("file name seek"); wxMemoryBuffer fileNames(header.FileNameLength); if (bsa.Read(fileNames.GetData(), header.FileNameLength) != (ssize_t)header.FileNameLength) throw std::string("file name read"); wxUint32 fileNameIndex = 0; if (bsa.Seek(header.FolderRecordOffset) == wxInvalidOffset) throw std::string("folder info seek"); BSAFolderInfo initInfo{ 0 }; std::vector folderInfos(header.FolderCount, initInfo); if (version != SSE_BSAHEADER_VERSION) { bool ok = true; for (wxUint32 i = 0; i < header.FolderCount; i++) { ok &= bsa.Read((char *)&folderInfos[i], 8) == 8; // Hash ok &= bsa.Read((char *)&folderInfos[i] + 8, 4) == 4; // File size ok &= bsa.Read((char *)&folderInfos[i] + 16, 4) == 4; // Offset: this is reading a uint32 into a uint64 whose memory must be zeroed if (!ok) throw std::string("folder info read"); } } else { if (bsa.Read((char *)folderInfos.data(), header.FolderCount * folderSize) != (ssize_t)(header.FolderCount * folderSize)) throw std::string("folder info read"); } wxUint32 totalFileCount = 0; for (const BSAFolderInfo& folderInfo : folderInfos) { std::string folderName; if (!BSAReadSizedString(bsa, folderName)) throw std::string("folder name read"); BSAFolder *folder = insertFolder(folderName); wxUint32 fcnt = folderInfo.fileCount; totalFileCount += fcnt; std::vector fileInfos(fcnt); if (bsa.Read((char *)fileInfos.data(), fcnt * sizeof(OBBSAFileInfo)) != (ssize_t)(fcnt * sizeof(OBBSAFileInfo))) throw std::string("file info read"); for (const OBBSAFileInfo fileInfo : fileInfos) { if (fileNameIndex >= header.FileNameLength) throw std::string("file name size"); std::string fileName = static_cast(fileNames.GetData()) + fileNameIndex; fileNameIndex += fileName.length() + 1; insertFile(folder, fileName, fileInfo.sizeFlags, fileInfo.offset); } } if (totalFileCount != header.FileCount) throw std::string("file count"); } else if (magic == MW_BSAHEADER_FILEID) { MWBSAHeader header{}; if (bsa.Read((char *)& header, sizeof(header)) != sizeof(header)) throw std::string("header"); numFiles = header.FileCount; compressToggle = false; namePrefix = false; // header is 12 bytes, hash table is 8 bytes per entry wxUint32 dataOffset = 12 + header.HashOffset + header.FileCount * 8; // file size/offset table std::vector sizeOffset(header.FileCount); if (bsa.Read((char *)sizeOffset.data(), header.FileCount * sizeof(MWBSAFileSizeOffset)) != (ssize_t)(header.FileCount * sizeof(MWBSAFileSizeOffset))) throw std::string("file size/offset"); // filename offset table std::vector nameOffset(header.FileCount); if (bsa.Read((char *)nameOffset.data(), header.FileCount * sizeof(wxUint32)) != (ssize_t)(header.FileCount * sizeof(wxUint32))) throw std::string("file name offset"); // filenames. size is given by ( HashOffset - ( 8 * number of file/size offsets) - ( 4 * number of filenames) ) // i.e. ( HashOffset - ( 12 * number of files ) ) wxMemoryBuffer fileNames; fileNames.SetBufSize(header.HashOffset - 12 * header.FileCount); if (bsa.Read((char *)fileNames.GetData(), header.HashOffset - 12 * header.FileCount) != (ssize_t)(header.HashOffset - 12 * header.FileCount)) throw std::string("file names"); // table of 8 bytes of hash values follow, but we don't need to know what they are // file data follows that, which is fetched by fileContents for (wxUint32 c = 0; c < header.FileCount; c++) { std::string fname = static_cast(fileNames.GetData()) + nameOffset[c]; std::string dname; int x = fname.find_last_of('\\'); if (x > 0) { dname = fname.substr(0, x); fname.erase(0, x + 1); } insertFile(insertFolder(dname), fname, sizeOffset[c].size, dataOffset + sizeOffset[c].offset); } } else throw std::string("file magic"); } catch (std::string e) { status = e; return false; } status = "loaded successful"; return true; } void BSA::close() { wxMutexLocker lock(bsaMutex); bsa.Close(); for (auto &it : root.children) delete it.second; for (auto &it : root.files) delete it.second; root.children.clear(); root.files.clear(); folders.clear(); fileNameSuperBuffer.reset(); } wxInt64 BSA::fileSize(const std::string & fn) const { // note: lazy size count (not accurate for compressed files) if (const BSAFile * file = getFile(fn)) { if (file->sizeFlags > 0) return file->size(); wxUint64 size = file->unpackedLength; if (file->tex.chunks.size()) { for (size_t i = 1; i < file->tex.chunks.size(); i++) { size += file->tex.chunks[i].unpackedSize; } } return size; } return 0; } void BSA::addFilesOfFolders(const std::string &folderName, std::vector &tree) const { if (const BSAFolder *folder = getFolder(folderName)) { tree.push_back(folderName); for (auto &child : folder->children) { addFilesOfFolders(folderName + "/" + child.first, tree); } for (auto &file : folder->files) { tree.push_back(folderName + "/" + file.first); } } } void BSA::fileTree(std::vector &tree) const { tree.push_back(name()); for (auto &folder : root.children) addFilesOfFolders(folder.first, tree); } bool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) { if (const BSAFile *file = getFile(fn)) { wxMutexLocker lock(bsaMutex); if (bsa.Seek(file->offset)) { wxInt64 filesz = file->size(); ssize_t fileok = 1; if (namePrefix) { char len; fileok = bsa.Read(&len, 1); filesz -= len; if (fileok != wxInvalidOffset) fileok = bsa.Seek(file->offset + 1 + len); } if (file->tex.chunks.size() > 0) { // Fill DDS Header for BA2 DirectX::DDS_HEADER ddsHeader = {}; ddsHeader.size = sizeof(ddsHeader); ddsHeader.flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_LINEARSIZE | DDS_HEADER_FLAGS_MIPMAP; ddsHeader.height = file->tex.header.height; ddsHeader.width = file->tex.header.width; ddsHeader.mipMapCount = file->tex.header.numMips; ddsHeader.caps = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_MIPMAP; ddsHeader.pitchOrLinearSize = file->tex.header.width * file->tex.header.height; // 8bpp DirectX::DDS_HEADER_DXT10 ddsHeader10 = {}; ddsHeader10.resourceDimension = DirectX::DDS_DIMENSION_TEXTURE2D; ddsHeader10.arraySize = 1; if (file->tex.header.unk16 == 2049) { ddsHeader.caps2 = DDS_CUBEMAP_ALLFACES; ddsHeader10.miscFlag = DirectX::DDS_RESOURCE_MISC_TEXTURECUBE; ddsHeader10.arraySize *= 6; } bool ok = true; switch (file->tex.header.format) { case DXGI_FORMAT_BC1_TYPELESS: case DXGI_FORMAT_BC1_UNORM: case DXGI_FORMAT_BC1_UNORM_SRGB: ddsHeader.ddspf = DirectX::DDSPF_DXT1; ddsHeader.pitchOrLinearSize /= 2; // 4bpp break; case DXGI_FORMAT_BC2_TYPELESS: case DXGI_FORMAT_BC2_UNORM: case DXGI_FORMAT_BC2_UNORM_SRGB: ddsHeader.ddspf = DirectX::DDSPF_DXT3; break; case DXGI_FORMAT_BC3_TYPELESS: case DXGI_FORMAT_BC3_UNORM: case DXGI_FORMAT_BC3_UNORM_SRGB: ddsHeader.ddspf = DirectX::DDSPF_DXT5; break; case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_UNORM: case DXGI_FORMAT_BC4_SNORM: ddsHeader.ddspf = DirectX::DDSPF_DX10; ddsHeader.pitchOrLinearSize /= 2; // 4bpp ddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format; break; case DXGI_FORMAT_BC5_TYPELESS: case DXGI_FORMAT_BC5_UNORM: case DXGI_FORMAT_BC5_SNORM: ddsHeader.ddspf = DirectX::DDSPF_DX10; ddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format; break; case DXGI_FORMAT_BC6H_TYPELESS: case DXGI_FORMAT_BC6H_UF16: case DXGI_FORMAT_BC6H_SF16: ddsHeader.ddspf = DirectX::DDSPF_DX10; ddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format; break; case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM_SRGB: ddsHeader.ddspf = DirectX::DDSPF_DX10; ddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format; break; case DXGI_FORMAT_B8G8R8A8_TYPELESS: case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: ddsHeader.ddspf = DirectX::DDSPF_A8R8G8B8; ddsHeader.pitchOrLinearSize *= 4; // 32bpp break; case DXGI_FORMAT_R8G8B8A8_TYPELESS: case DXGI_FORMAT_R8G8B8A8_UNORM: case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: case DXGI_FORMAT_R8G8B8A8_UINT: case DXGI_FORMAT_R8G8B8A8_SNORM: case DXGI_FORMAT_R8G8B8A8_SINT: ddsHeader.ddspf = DirectX::DDSPF_A8R8G8B8; ddsHeader.pitchOrLinearSize *= 4; // 32bpp break; case DXGI_FORMAT_R8_TYPELESS: case DXGI_FORMAT_R8_UNORM: case DXGI_FORMAT_R8_UINT: case DXGI_FORMAT_R8_SNORM: case DXGI_FORMAT_R8_SINT: ddsHeader.ddspf = DirectX::DDSPF_L8_NVTT1; break; default: ok = false; break; } if (!ok) return false; // Append DDS Header content.AppendData(&DirectX::DDS_MAGIC, 4); content.AppendData(&ddsHeader, sizeof(ddsHeader)); if (ddsHeader10.dxgiFormat != DXGI_FORMAT_UNKNOWN) content.AppendData(&ddsHeader10, sizeof(ddsHeader10)); } wxMemoryBuffer chunk(filesz); chunk.SetDataLen(filesz); if (fileok != wxInvalidOffset && bsa.Read(chunk.GetData(), filesz) == filesz) { if (file->sizeFlags > 0) { // BSA if (file->compressed() ^ compressToggle) { if (headerVersion == SSE_BSAHEADER_VERSION) chunk = lz4fUncompress(chunk, 0, 4); else chunk = gUncompress(chunk, 0, 4); } content.AppendData(chunk, chunk.GetDataLen()); } else if (file->packedLength > 0 && file->tex.chunks.empty()) { // GNRL BA2 compressed chunk = gUncompress(chunk, file->unpackedLength); content.AppendData(chunk, chunk.GetDataLen()); } else if (file->tex.chunks.empty()) { // GNRL BA2 uncompressed content.AppendData(chunk.GetData(), chunk.GetDataLen()); } if (!file->tex.chunks.empty()) { // Read chunks for DX10 BA2 for (size_t i = 0; i < file->tex.chunks.size(); i++) { const BA2TexChunk& chunkInfo = file->tex.chunks[i]; if (bsa.Seek(chunkInfo.offset)) { wxMemoryBuffer currentChunk; if (chunkInfo.packedSize > 0) { currentChunk.SetBufSize(chunkInfo.packedSize); currentChunk.SetDataLen(chunkInfo.packedSize); if (bsa.Read(currentChunk.GetData(), chunkInfo.packedSize) == (ssize_t)chunkInfo.packedSize) { if (ba2Header.compressionFlag == 3) currentChunk = lz4Uncompress(currentChunk, chunkInfo.unpackedSize); else currentChunk = gUncompress(currentChunk, chunkInfo.unpackedSize); } if (currentChunk.GetDataLen() != chunkInfo.unpackedSize) { // Size does not match at chunkInfo.offset return false; } } else { currentChunk.SetBufSize(chunkInfo.unpackedSize); currentChunk.SetDataLen(chunkInfo.unpackedSize); if (!(bsa.Read(currentChunk.GetData(), chunkInfo.unpackedSize) == (ssize_t)chunkInfo.unpackedSize)) { // Size does not match at chunkInfo.offset return false; } } content.AppendData(currentChunk.GetData(), currentChunk.GetDataLen()); } else { // Seek error return false; } } } return true; } } } return false; } bool BSA::exportFile(const std::string &fn, const std::string &target) { wxMemoryBuffer content; if (!fileContents(fn, content)) return false; if (content.IsEmpty()) return false; wxFile file(target, wxFile::write); if (file.Error()) return false; if (file.Write(content.GetData(), content.GetDataLen()) != content.GetDataLen()) return false; file.Close(); return true; } std::string BSA::absoluteFilePath(const std::string &fn) const { if (hasFile(fn)) { wxFileName fileInfo(fn); return (fileInfo.GetPath(true) + fileInfo.GetName()).ToStdString(); } return std::string(); } BSA::BSAFolder *BSA::insertFolder(std::string name) { if (name.empty()) return &root; std::replace(name.begin(), name.end(), '\\', '/'); SequenceToLowerCase(name.begin(), name.end()); BSAFolder *folder = folders[name]; if (!folder) { folder = new BSAFolder; folders[name] = folder; int p = name.find_last_of('/'); if (p >= 0) { folder->parent = insertFolder(name.substr(0, p)); folder->parent->children[name.substr(p + 1)] = folder; } else { folder->parent = &root; root.children[name] = folder; } } return folder; } BSA::BSAFolder* BSA::insertFolder(char* folder, int szFn) { auto loc = folders.find(std::string(folder, folder + szFn)); if (loc != folders.end()) { return loc->second; } BSAFolder* fldr = new BSAFolder(); folders[std::string(folder, folder + szFn)] = fldr; for (int p = szFn - 1; p >= 0; p--) { if (folder[p] == '/') { fldr->parent = insertFolder(folder, p); fldr->parent->children[std::string(folder + p + 1, szFn - p - 1)] = fldr; return fldr; } } fldr->parent = &root; root.children[std::string(folder, folder + szFn)] = fldr; return fldr; } BSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 sizeFlags, wxUint32 offset) { SequenceToLowerCase(name.begin(), name.end()); BSAFile *file = new BSAFile; file->sizeFlags = sizeFlags; file->offset = offset; folder->files[name] = file; return file; } /* Folders not required in this tool BSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex dds) { SequenceToLowerCase(name.begin(), name.end()); BSAFile *file = new BSAFile; file->tex = dds; file->packedLength = packed; file->unpackedLength = unpacked; file->offset = offset; folder->files[name] = file; return file; } */ BSA::BSAFile* BSA::insertFile(char* filename, int szFn, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex* dds) { SequenceToLowerCase(filename, filename + szFn); /* Folders not required in this tool int p; for (p = szFn - 1; p >= 0; p--) { if (filename[p] == '/') break; } BSAFolder* folder; if (p > -1) folder = insertFolder(filename, p); else folder = &root; */ BSAFile *file = new BSAFile; if (dds) file->tex = *dds; file->packedLength = packed; file->unpackedLength = unpacked; file->offset = offset; //folder->files[filename] = file; root.files.emplace(std::string(filename, szFn), file); return nullptr; } const BSA::BSAFolder *BSA::getFolder(std::string fn) const { SequenceToLowerCase(fn.begin(), fn.end()); if (fn.empty()) { return &root; } else { auto it = folders.find(fn); if (it != folders.end()) { BSA::BSAFolder *folder = it->second; if (folder) return folder; } } return nullptr; } const BSA::BSAFile *BSA::getFile(std::string fn) const { SequenceToLowerCase(fn.begin(), fn.end()); auto earlyfile = root.files.find(fn); if (earlyfile != root.files.end()) { return earlyfile->second; } std::string folderName; int p = fn.find_last_of('/'); if (p >= 0) { folderName = fn.substr(0, p); fn = fn.substr(p + 1); } // TODO: Multiple matches occur and user has no say which version gets loaded // When it comes to the AUTO feature, should give preference to certain BSAs // or take the newest and or highest quality version. if (const BSAFolder *folder = getFolder(folderName)) { auto it = folder->files.find(fn); if (it != folder->files.end()) { BSA::BSAFile *file = it->second; if (file) return file; } } return nullptr; } bool BSA::hasFile(const std::string &fn) const { return getFile(fn) != nullptr; } bool BSA::hasFolder(const std::string &fn) const { return getFolder(fn) != nullptr; } wxDateTime BSA::fileTime(const std::string&) const { wxDateTime created; bsaInfo.GetTimes(nullptr, nullptr, &created); return created; } ================================================ FILE: lib/FSEngine/FSBSA.h ================================================ /***** BEGIN LICENSE BLOCK ***** BSD License Copyright (c) 2005-2012, NIF File Format Library and Tools All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the NIF File Format Library and Tools project may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ #pragma once #include "FSEngine.h" #include #include #include #include #include #include /* Default header data */ #define MW_BSAHEADER_FILEID 0x00000100 //!< Magic for Morrowind BSA #define OB_BSAHEADER_FILEID 0x00415342 //!< Magic for Oblivion BSA, the literal string "BSA\0". #define F4_BSAHEADER_FILEID 0x58445442 //!< Magic for Fallout 4 BA2, the literal string "BTDX". #define OB_BSAHEADER_VERSION 0x67 //!< Version number of an Oblivion BSA #define F3_BSAHEADER_VERSION 0x68 //!< Version number of a Fallout 3 BSA #define SSE_BSAHEADER_VERSION 0x69 //!< Version number of a Skyrim SE BSA #define F4_BSAHEADER_VERSION 0x01 //!< Version number of a Fallout 4 BA2 #define F4_BSAHEADER_VERSION2 0x07 //!< Version number of a Fallout 4 BA2 #define F4_BSAHEADER_VERSION3 0x08 //!< Version number of a Fallout 4 BA2 #define SF_BSAHEADER_VERSION2 0x02 //!< Version number of a Starfield BA2 #define SF_BSAHEADER_VERSION3 0x03 //!< Version number of a Starfield BA2 /* Archive flags */ #define OB_BSAARCHIVE_PATHNAMES 0x0001 //!< Whether the BSA has names for paths #define OB_BSAARCHIVE_FILENAMES 0x0002 //!< Whether the BSA has names for files #define OB_BSAARCHIVE_COMPRESSFILES 0x0004 //!< Whether the files are compressed #define F3_BSAARCHIVE_PREFIXFULLFILENAMES 0x0100 //!< Whether the name is prefixed to the data? /* File flags */ #define OB_BSAFILE_NIF 0x0001 //!< Set when the BSA contains NIF files #define OB_BSAFILE_DDS 0x0002 //!< Set when the BSA contains DDS files #define OB_BSAFILE_XML 0x0004 //!< Set when the BSA contains XML files #define OB_BSAFILE_WAV 0x0008 //!< Set when the BSA contains WAV files #define OB_BSAFILE_MP3 0x0010 //!< Set when the BSA contains MP3 files #define OB_BSAFILE_TXT 0x0020 //!< Set when the BSA contains TXT files #define OB_BSAFILE_HTML 0x0020 //!< Set when the BSA contains HTML files #define OB_BSAFILE_BAT 0x0020 //!< Set when the BSA contains BAT files #define OB_BSAFILE_SCC 0x0020 //!< Set when the BSA contains SCC files #define OB_BSAFILE_SPT 0x0040 //!< Set when the BSA contains SPT files #define OB_BSAFILE_TEX 0x0080 //!< Set when the BSA contains TEX files #define OB_BSAFILE_FNT 0x0080 //!< Set when the BSA contains FNT files #define OB_BSAFILE_CTL 0x0100 //!< Set when the BSA contains CTL files /* Bitmasks for the size field in the header */ #define OB_BSAFILE_SIZEMASK 0x3fffffff //!< Bit mask with OBBSAFileInfo::sizeFlags to get the size of the file /* Record flags */ #define OB_BSAFILE_FLAG_COMPRESS 0xC0000000 //!< Bit mask with OBBSAFileInfo::sizeFlags to get the compression status //! The header of an Oblivion BSA. /*! * Follows OB_BSAHEADER_FILEID and OB_BSAHEADER_VERSION. */ struct OBBSAHeader { wxUint32 FolderRecordOffset; //!< Offset of beginning of folder records wxUint32 ArchiveFlags; //!< Archive flags wxUint32 FolderCount; //!< Total number of folder records ((OB/SSE)BSAFolderInfo) wxUint32 FileCount; //!< Total number of file records (OBBSAFileInfo) wxUint32 FolderNameLength; //!< Total length of folder names wxUint32 FileNameLength; //!< Total length of file names wxUint32 FileFlags; //!< File flags }; //! Info for a file inside an Oblivion BSA struct OBBSAFileInfo { wxUint64 hash; //!< Hash of the filename wxUint32 sizeFlags; //!< Size of the data, possibly with OB_BSAFILE_FLAG_COMPRESS set wxUint32 offset; //!< Offset to raw file data }; //! Info for a folder inside a Skyrim SE BSA struct SSEBSAFolderInfo { wxUint64 hash; //!< Hash of the folder name wxUint32 fileCount; //!< Number of files in folder wxUint32 unknown; //!< Unknown wxUint64 offset; //!< Offset to name of this folder }; //! Info for a folder inside an Oblivion BSA struct OBBSAFolderInfo { wxUint64 hash; //!< Hash of the folder name wxUint32 fileCount; //!< Number of files in folder wxUint32 offset; //!< Offset to name of this folder }; //! Define as general folder info typedef SSEBSAFolderInfo BSAFolderInfo; //! The header of a Morrowind BSA struct MWBSAHeader { wxUint32 HashOffset; //!< Offset of hash table minus header size (12) wxUint32 FileCount; //!< Number of files in the archive }; //! The file size and offset of an entry in a Morrowind BSA struct MWBSAFileSizeOffset { wxUint32 size; //!< The size of the file wxUint32 offset; //!< The offset of the file }; #pragma pack(push, 4) struct BA2Header { char type[4]{}; //!< 08 GNRL=General, DX10=Textures wxUint32 numFiles = 0; //!< 0C wxUint64 nameTableOffset = 0; //!< 10 - relative to start of file wxUint32 unk1 = 0; wxUint32 unk2 = 0; wxUint32 compressionFlag = 0; // LZ4 if 3, ZIP otherwise }; // 24 struct BA2GeneralInfo { wxUint32 unk00; //!< 00 - hash? char ext[4]; //!< 04 - extension wxUint32 unk08; //!< 08 - hash? wxUint32 unk0C; //!< 0C - flags? 00100100 wxUint64 offset; //!< 10 - relative to start of file wxUint32 packedSize; //!< 18 - packed length (zlib) wxUint32 unpackedSize; //!< 1C - unpacked length wxUint32 unk20; //!< 20 - BAADF00D }; #pragma pack(pop) // 18 struct BA2TexInfo { wxUint32 nameHash; //!< 00 char ext[4]; //!< 04 wxUint32 dirHash; //!< 08 wxUint8 unk0C; //!< 0C wxUint8 numChunks; //!< 0D wxUint16 chunkHeaderSize; //!< 0E - size of one chunk header wxUint16 height; //!< 10 wxUint16 width; //!< 12 wxUint8 numMips; //!< 14 wxUint8 format; //!< 15 - DXGI_FORMAT wxUint16 unk16; //!< 16 - 0800 }; // 18 struct BA2TexChunk { wxUint64 offset; //!< 00 wxUint32 packedSize; //!< 08 wxUint32 unpackedSize; //!< 0C wxUint16 startMip; //!< 10 wxUint16 endMip; //!< 12 wxUint32 unk14; //!< 14 - BAADFOOD }; struct BA2Tex { BA2TexInfo header{}; std::vector chunks; }; class BSA final : public FSArchiveFile { public: //! Constructor; creates a %BSA from the given file path. BSA(const std::string &filePath); //! Destructor; closes the file. ~BSA(); //! Opens the %BSA file bool open() override final; //! Closes the %BSA file void close() override final; //! Returns BSA::bsaPath. std::string path() const override final { return bsaPath; } //! Returns BSA::bsaBase. std::string base() const override final { return bsaBase; } //! Returns BSA::bsaName. std::string name() const override final { return bsaName; } //! Whether the specified folder exists or not bool hasFolder(const std::string&) const override final; //! Whether the specified file exists or not bool hasFile(const std::string&) const override final; //! Returns the size of the file per BSAFile::size(). wxInt64 fileSize(const std::string&) const override final; //! Add all files of the folder to the map void addFilesOfFolders(const std::string&, std::vector&) const override final; //! Returns the entire file tree of the BSA void fileTree(std::vector&) const override final; //! Returns the contents of the specified file /*! * \param fn The filename to get the contents for * \param content Reference to the byte array that holds the file contents * \return True if successful */ bool fileContents(const std::string&, wxMemoryBuffer&) override final; //! Writes the contents to the specified file bool exportFile(const std::string&, const std::string&) override final; //! See QFileInfo::created(). wxDateTime fileTime(const std::string&) const override final; //! See QFileInfo::absoluteFilePath(). std::string absoluteFilePath(const std::string&) const override final; //! Whether the given file can be opened as a %BSA or not static bool canOpen(const std::string&); //! Returns BSA::status. std::string statusText() const { return status; } //! Returns BSA::numFiles. wxUint64 fileCount() const { return numFiles; } protected: //! A file inside a BSA struct BSAFile { // Skyrim and earlier wxUint32 sizeFlags = 0; //!< The size of the file in the BSA // Fallout 4 wxUint32 packedLength = 0; wxUint32 unpackedLength = 0; wxUint64 offset = 0; //!< The offset of the file in the BSA //! The size of the file inside the BSA wxUint32 size() const; //! Whether the file is compressed inside the BSA bool compressed() const; BA2Tex tex; }; //! A folder inside a BSA struct BSAFolder { //! Constructor BSAFolder() : parent(0) {} //! Destructor ~BSAFolder() { for (auto &it : children) delete it.second; for (auto &it : files) delete it.second; children.clear(); files.clear(); } BSAFolder *parent; //!< The parent item std::unordered_map children; //!< A map of child folders std::unordered_map files; //!< A map of files inside the folder }; //! Recursive function to generate the tree structure of folders inside a %BSA BSAFolder *insertFolder(std::string name); BSAFolder *insertFolder(char* folder, int szFn); //! Inserts a file into the structure of a %BSA BSAFile* insertFile(BSAFolder* folder, std::string name, wxUint32 sizeFlags, wxUint32 offset); /* Folders not required in this tool BSAFile *insertFile(BSAFolder *folder, std::string name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex dds = BA2Tex()); */ BSAFile *insertFile(char* filename, int szFn, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex* dds = nullptr); //! Gets the specified folder, or the root folder if not found const BSAFolder *getFolder(std::string fn) const; //! Gets the specified file, or null if not found const BSAFile *getFile(std::string fn) const; //! The %BSA file wxFile bsa; //! File info for the %BSA wxFileName bsaInfo; //! Mutual exclusion handler wxMutex bsaMutex; //! The absolute name of the file, e.g. "d:/temp/test.bsa" std::string bsaPath; //! The base path of the file, e.g. "d:/temp" std::string bsaBase; //! The name of the file, e.g. "test.bsa" std::string bsaName; //! Map of folders inside a %BSA std::unordered_map folders; //! The root folder BSAFolder root; //! Error string for exception handling std::string status; //! Version number from the header wxUint32 headerVersion = 0; //! BA2 header BA2Header ba2Header; //! Number of files wxUint64 numFiles = 0; //! Whether the %BSA is compressed bool compressToggle = false; //! Whether Fallout 3 names are prefixed with an extra string bool namePrefix = false; std::unique_ptr fileNameSuperBuffer; }; ================================================ FILE: lib/FSEngine/FSEngine.cpp ================================================ /***** BEGIN LICENSE BLOCK ***** BSD License Copyright (c) 2005-2012, NIF File Format Library and Tools All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the NIF File Format Library and Tools project may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ #include "FSEngine.h" #include "FSBSA.h" //! \file fsengine.cpp File system engine implementations FSArchiveHandler *FSArchiveHandler::openArchive(const std::string &fn) { if (BSA::canOpen(fn)) { BSA *bsa = new BSA(fn); if (bsa->open()) return new FSArchiveHandler(bsa); delete bsa; } return 0; } FSArchiveHandler::FSArchiveHandler(FSArchiveFile *a) { archive = a; wxAtomicInc(archive->ref); } FSArchiveHandler::~FSArchiveHandler() { if (!wxAtomicDec(archive->ref)) delete archive; } ================================================ FILE: lib/FSEngine/FSEngine.h ================================================ /***** BEGIN LICENSE BLOCK ***** BSD License Copyright (c) 2005-2012, NIF File Format Library and Tools All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the NIF File Format Library and Tools project may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ #pragma once #include #include #include //! Provides a way to register an FSArchiveEngine with the application. class FSArchiveHandler { public: //! Opens a BSA for the specified file static FSArchiveHandler *openArchive(const std::string&); public: //! Constructor FSArchiveHandler(class FSArchiveFile *a); //! Destructor ~FSArchiveHandler(); FSArchiveFile *getArchive() { return archive; } protected: class FSArchiveFile *archive; }; //! A file system archive class FSArchiveFile { public: //! Constructor FSArchiveFile() : ref(0) {} virtual ~FSArchiveFile() {} virtual bool open() = 0; virtual void close() = 0; virtual std::string base() const = 0; virtual std::string name() const = 0; virtual std::string path() const = 0; virtual bool hasFolder(const std::string&) const = 0; virtual bool hasFile(const std::string&) const = 0; virtual wxInt64 fileSize(const std::string&) const = 0; virtual void addFilesOfFolders(const std::string&, std::vector&) const = 0; virtual void fileTree(std::vector&) const = 0; virtual bool fileContents(const std::string&, wxMemoryBuffer&) = 0; virtual bool exportFile(const std::string&, const std::string&) = 0; virtual std::string absoluteFilePath(const std::string&) const = 0; virtual wxDateTime fileTime(const std::string&) const = 0; protected: //! A reference counter for an implicitly shared class wxAtomicInt ref; friend class FSArchiveHandler; }; ================================================ FILE: lib/FSEngine/FSManager.cpp ================================================ /***** BEGIN LICENSE BLOCK ***** BSD License Copyright (c) 2005-2012, NIF File Format Library and Tools All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the NIF File Format Library and Tools project may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ #include "FSManager.h" #include "FSEngine.h" #include #include //! Global BSA file manager static FSManager *theFSManager = nullptr; FSManager* FSManager::get() { if (!theFSManager) theFSManager = new FSManager(); return theFSManager; } bool FSManager::exists() { return theFSManager != nullptr; } void FSManager::del() { if (theFSManager) { delete theFSManager; theFSManager = nullptr; } } std::list FSManager::archiveList() { std::list archives; std::transform(get()->archives.begin(), get()->archives.end(), std::back_inserter(archives), [](std::map::value_type& val){ return val.second->getArchive(); }); return archives; } void FSManager::addArchives(const std::vector& archiveList) { for (auto &archive : archiveList) { if (FSArchiveHandler *a = FSArchiveHandler::openArchive(archive)) get()->archives[archive] = a; } } FSManager::FSManager() { } FSManager::~FSManager() { for (auto &it : archives) delete it.second; archives.clear(); } ================================================ FILE: lib/FSEngine/FSManager.h ================================================ /***** BEGIN LICENSE BLOCK ***** BSD License Copyright (c) 2005-2012, NIF File Format Library and Tools All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the NIF File Format Library and Tools project may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***** END LICENCE BLOCK *****/ #pragma once #include #include #include #include class FSArchiveHandler; class FSArchiveFile; //! The file system manager class. class FSManager { public: //! Gets the global file system manager static FSManager *get(); //! Returns if the file manager exists already static bool exists(); //! Deletes the global file system manager static void del(); //! Gets the list of globally registered BSA files static std::list archiveList(); //! Adds archives to the global list static void addArchives(const std::vector&); protected: //! Constructor FSManager(); //! Destructor ~FSManager(); std::map archives; }; ================================================ FILE: lib/LZ4F/lz4.c ================================================ /* LZ4 - Fast LZ compression algorithm Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 homepage : http://www.lz4.org - LZ4 source repository : https://github.com/lz4/lz4 */ /*-************************************ * Tuning parameters **************************************/ /* * LZ4_HEAPMODE : * Select how stateless compression functions like `LZ4_compress_default()` * allocate memory for their hash table, * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()). */ #ifndef LZ4_HEAPMODE # define LZ4_HEAPMODE 0 #endif /* * LZ4_ACCELERATION_DEFAULT : * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 */ #define LZ4_ACCELERATION_DEFAULT 1 /* * LZ4_ACCELERATION_MAX : * Any "acceleration" value higher than this threshold * get treated as LZ4_ACCELERATION_MAX instead (fix #876) */ #define LZ4_ACCELERATION_MAX 65537 /*-************************************ * CPU Feature Detection **************************************/ /* LZ4_FORCE_MEMORY_ACCESS * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. * The below switch allow to select different access method for improved performance. * Method 0 (default) : use `memcpy()`. Safe and portable. * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. * Method 2 : direct access. This method is portable but violate C standard. * It can generate buggy code on targets which assembly generation depends on alignment. * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */ # if defined(__GNUC__) && \ ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \ || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) # define LZ4_FORCE_MEMORY_ACCESS 2 # elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__) # define LZ4_FORCE_MEMORY_ACCESS 1 # endif #endif /* * LZ4_FORCE_SW_BITCOUNT * Define this parameter if your target system or compiler does not support hardware bit count */ #if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for WinCE doesn't support Hardware bit count */ # undef LZ4_FORCE_SW_BITCOUNT /* avoid double def */ # define LZ4_FORCE_SW_BITCOUNT #endif /*-************************************ * Dependency **************************************/ /* * LZ4_SRC_INCLUDED: * Amalgamation flag, whether lz4.c is included */ #ifndef LZ4_SRC_INCLUDED # define LZ4_SRC_INCLUDED 1 #endif #ifndef LZ4_STATIC_LINKING_ONLY #define LZ4_STATIC_LINKING_ONLY #endif #ifndef LZ4_DISABLE_DEPRECATE_WARNINGS #define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */ #endif #define LZ4_STATIC_LINKING_ONLY /* LZ4_DISTANCE_MAX */ #include "lz4.h" /* see also "memory routines" below */ /*-************************************ * Compiler Options **************************************/ #if defined(_MSC_VER) && (_MSC_VER >= 1400) /* Visual Studio 2005+ */ # include /* only present in VS2005+ */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 6237) /* disable: C6237: conditional expression is always 0 */ #endif /* _MSC_VER */ #ifndef LZ4_FORCE_INLINE # ifdef _MSC_VER /* Visual Studio */ # define LZ4_FORCE_INLINE static __forceinline # else # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ # ifdef __GNUC__ # define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) # else # define LZ4_FORCE_INLINE static inline # endif # else # define LZ4_FORCE_INLINE static # endif /* __STDC_VERSION__ */ # endif /* _MSC_VER */ #endif /* LZ4_FORCE_INLINE */ /* LZ4_FORCE_O2 and LZ4_FORCE_INLINE * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8, * together with a simple 8-byte copy loop as a fall-back path. * However, this optimization hurts the decompression speed by >30%, * because the execution does not go to the optimized loop * for typical compressible data, and all of the preamble checks * before going to the fall-back path become useless overhead. * This optimization happens only with the -O3 flag, and -O2 generates * a simple 8-byte copy loop. * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8 * functions are annotated with __attribute__((optimize("O2"))), * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute * of LZ4_wildCopy8 does not affect the compression speed. */ #if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__) # define LZ4_FORCE_O2 __attribute__((optimize("O2"))) # undef LZ4_FORCE_INLINE # define LZ4_FORCE_INLINE static __inline __attribute__((optimize("O2"),always_inline)) #else # define LZ4_FORCE_O2 #endif #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) #else # define expect(expr,value) (expr) #endif #ifndef likely #define likely(expr) expect((expr) != 0, 1) #endif #ifndef unlikely #define unlikely(expr) expect((expr) != 0, 0) #endif /* Should the alignment test prove unreliable, for some reason, * it can be disabled by setting LZ4_ALIGN_TEST to 0 */ #ifndef LZ4_ALIGN_TEST /* can be externally provided */ # define LZ4_ALIGN_TEST 1 #endif /*-************************************ * Memory routines **************************************/ /*! LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION : * Disable relatively high-level LZ4/HC functions that use dynamic memory * allocation functions (malloc(), calloc(), free()). * * Note that this is a compile-time switch. And since it disables * public/stable LZ4 v1 API functions, we don't recommend using this * symbol to generate a library for distribution. * * The following public functions are removed when this symbol is defined. * - lz4 : LZ4_createStream, LZ4_freeStream, * LZ4_createStreamDecode, LZ4_freeStreamDecode, LZ4_create (deprecated) * - lz4hc : LZ4_createStreamHC, LZ4_freeStreamHC, * LZ4_createHC (deprecated), LZ4_freeHC (deprecated) * - lz4frame, lz4file : All LZ4F_* functions */ #if defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) # define ALLOC(s) lz4_error_memory_allocation_is_disabled # define ALLOC_AND_ZERO(s) lz4_error_memory_allocation_is_disabled # define FREEMEM(p) lz4_error_memory_allocation_is_disabled #elif defined(LZ4_USER_MEMORY_FUNCTIONS) /* memory management functions can be customized by user project. * Below functions must exist somewhere in the Project * and be available at link time */ void* LZ4_malloc(size_t s); void* LZ4_calloc(size_t n, size_t s); void LZ4_free(void* p); # define ALLOC(s) LZ4_malloc(s) # define ALLOC_AND_ZERO(s) LZ4_calloc(1,s) # define FREEMEM(p) LZ4_free(p) #else # include /* malloc, calloc, free */ # define ALLOC(s) malloc(s) # define ALLOC_AND_ZERO(s) calloc(1,s) # define FREEMEM(p) free(p) #endif #if ! LZ4_FREESTANDING # include /* memset, memcpy */ #endif #if !defined(LZ4_memset) # define LZ4_memset(p,v,s) memset((p),(v),(s)) #endif #define MEM_INIT(p,v,s) LZ4_memset((p),(v),(s)) /*-************************************ * Common Constants **************************************/ #define MINMATCH 4 #define WILDCOPYLENGTH 8 #define LASTLITERALS 5 /* see ../doc/lz4_Block_format.md#parsing-restrictions */ #define MFLIMIT 12 /* see ../doc/lz4_Block_format.md#parsing-restrictions */ #define MATCH_SAFEGUARD_DISTANCE ((2*WILDCOPYLENGTH) - MINMATCH) /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */ #define FASTLOOP_SAFE_DISTANCE 64 static const int LZ4_minLength = (MFLIMIT+1); #define KB *(1 <<10) #define MB *(1 <<20) #define GB *(1U<<30) #define LZ4_DISTANCE_ABSOLUTE_MAX 65535 #if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX) /* max supported by LZ4 format */ # error "LZ4_DISTANCE_MAX is too big : must be <= 65535" #endif #define ML_BITS 4 #define ML_MASK ((1U<=1) # include #else # ifndef assert # define assert(condition) ((void)0) # endif #endif #define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use after variable declarations */ #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) # include static int g_debuglog_enable = 1; # define DEBUGLOG(l, ...) { \ if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ fprintf(stderr, __FILE__ " %i: ", __LINE__); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, " \n"); \ } } #else # define DEBUGLOG(l, ...) {} /* disabled */ #endif static int LZ4_isAligned(const void* ptr, size_t alignment) { return ((size_t)ptr & (alignment -1)) == 0; } /*-************************************ * Types **************************************/ #include #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # include typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; typedef uintptr_t uptrval; #else # if UINT_MAX != 4294967295UL # error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4" # endif typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; typedef signed int S32; typedef unsigned long long U64; typedef size_t uptrval; /* generally true, except OpenVMS-64 */ #endif #if defined(__x86_64__) typedef U64 reg_t; /* 64-bits in x32 mode */ #else typedef size_t reg_t; /* 32-bits in x32 mode */ #endif typedef enum { notLimited = 0, limitedOutput = 1, fillOutput = 2 } limitedOutput_directive; /*-************************************ * Reading and writing into memory **************************************/ /** * LZ4 relies on memcpy with a constant size being inlined. In freestanding * environments, the compiler can't assume the implementation of memcpy() is * standard compliant, so it can't apply its specialized memcpy() inlining * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze * memcpy() as if it were standard compliant, so it can inline it in freestanding * environments. This is needed when decompressing the Linux Kernel, for example. */ #if !defined(LZ4_memcpy) # if defined(__GNUC__) && (__GNUC__ >= 4) # define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size) # else # define LZ4_memcpy(dst, src, size) memcpy(dst, src, size) # endif #endif #if !defined(LZ4_memmove) # if defined(__GNUC__) && (__GNUC__ >= 4) # define LZ4_memmove __builtin_memmove # else # define LZ4_memmove memmove # endif #endif static unsigned LZ4_isLittleEndian(void) { const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; } #if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) /* lie to the compiler about data alignment; use with caution */ static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; } static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; } static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; } static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } #elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1) /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */ typedef struct { U16 u16; } __attribute__((packed)) LZ4_unalign16; typedef struct { U32 u32; } __attribute__((packed)) LZ4_unalign32; typedef struct { reg_t uArch; } __attribute__((packed)) LZ4_unalignST; static U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign16*)ptr)->u16; } static U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign32*)ptr)->u32; } static reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalignST*)ptr)->uArch; } static void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign16*)memPtr)->u16 = value; } static void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign32*)memPtr)->u32 = value; } #else /* safe and portable access using memcpy() */ static U16 LZ4_read16(const void* memPtr) { U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static U32 LZ4_read32(const void* memPtr) { U32 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static reg_t LZ4_read_ARCH(const void* memPtr) { reg_t val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; } static void LZ4_write16(void* memPtr, U16 value) { LZ4_memcpy(memPtr, &value, sizeof(value)); } static void LZ4_write32(void* memPtr, U32 value) { LZ4_memcpy(memPtr, &value, sizeof(value)); } #endif /* LZ4_FORCE_MEMORY_ACCESS */ static U16 LZ4_readLE16(const void* memPtr) { if (LZ4_isLittleEndian()) { return LZ4_read16(memPtr); } else { const BYTE* p = (const BYTE*)memPtr; return (U16)((U16)p[0] + (p[1]<<8)); } } static void LZ4_writeLE16(void* memPtr, U16 value) { if (LZ4_isLittleEndian()) { LZ4_write16(memPtr, value); } else { BYTE* p = (BYTE*)memPtr; p[0] = (BYTE) value; p[1] = (BYTE)(value>>8); } } /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ LZ4_FORCE_INLINE void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; BYTE* const e = (BYTE*)dstEnd; do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d= 16. */ LZ4_FORCE_INLINE void LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; BYTE* const e = (BYTE*)dstEnd; do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d= dstPtr + MINMATCH * - there is at least 8 bytes available to write after dstEnd */ LZ4_FORCE_INLINE void LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset) { BYTE v[8]; assert(dstEnd >= dstPtr + MINMATCH); switch(offset) { case 1: MEM_INIT(v, *srcPtr, 8); break; case 2: LZ4_memcpy(v, srcPtr, 2); LZ4_memcpy(&v[2], srcPtr, 2); #if defined(_MSC_VER) && (_MSC_VER <= 1936) /* MSVC 2022 ver 17.6 or earlier */ # pragma warning(push) # pragma warning(disable : 6385) /* warning C6385: Reading invalid data from 'v'. */ #endif LZ4_memcpy(&v[4], v, 4); #if defined(_MSC_VER) && (_MSC_VER <= 1936) /* MSVC 2022 ver 17.6 or earlier */ # pragma warning(pop) #endif break; case 4: LZ4_memcpy(v, srcPtr, 4); LZ4_memcpy(&v[4], srcPtr, 4); break; default: LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset); return; } LZ4_memcpy(dstPtr, v, 8); dstPtr += 8; while (dstPtr < dstEnd) { LZ4_memcpy(dstPtr, v, 8); dstPtr += 8; } } #endif /*-************************************ * Common functions **************************************/ static unsigned LZ4_NbCommonBytes (reg_t val) { assert(val != 0); if (LZ4_isLittleEndian()) { if (sizeof(val) == 8) { # if defined(_MSC_VER) && (_MSC_VER >= 1800) && (defined(_M_AMD64) && !defined(_M_ARM64EC)) && !defined(LZ4_FORCE_SW_BITCOUNT) /*-************************************************************************************************* * ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications on ARM64 Windows 11. * The ARM64EC ABI does not support AVX/AVX2/AVX512 instructions, nor their relevant intrinsics * including _tzcnt_u64. Therefore, we need to neuter the _tzcnt_u64 code path for ARM64EC. ****************************************************************************************************/ # if defined(__clang__) && (__clang_major__ < 10) /* Avoid undefined clang-cl intrinsics issue. * See https://github.com/lz4/lz4/pull/1017 for details. */ return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3; # else /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */ return (unsigned)_tzcnt_u64(val) >> 3; # endif # elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanForward64(&r, (U64)val); return (unsigned)r >> 3; # elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_ctzll((U64)val) >> 3; # else const U64 m = 0x0101010101010101ULL; val ^= val - 1; return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56); # endif } else /* 32 bits */ { # if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r; _BitScanForward(&r, (U32)val); return (unsigned)r >> 3; # elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_ctz((U32)val) >> 3; # else const U32 m = 0x01010101; return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24; # endif } } else /* Big Endian CPU */ { if (sizeof(val)==8) { # if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_clzll((U64)val) >> 3; # else #if 1 /* this method is probably faster, * but adds a 128 bytes lookup table */ static const unsigned char ctz7_tab[128] = { 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, }; U64 const mask = 0x0101010101010101ULL; U64 const t = (((val >> 8) - mask) | val) & mask; return ctz7_tab[(t * 0x0080402010080402ULL) >> 57]; #else /* this method doesn't consume memory space like the previous one, * but it contains several branches, * that may end up slowing execution */ static const U32 by32 = sizeof(val)*4; /* 32 on 64 bits (goal), 16 on 32 bits. Just to avoid some static analyzer complaining about shift by 32 on 32-bits target. Note that this code path is never triggered in 32-bits mode. */ unsigned r; if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; } if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } r += (!val); return r; #endif # endif } else /* 32 bits */ { # if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_clz((U32)val) >> 3; # else val >>= 8; val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) | (val + 0x00FF0000)) >> 24; return (unsigned)val ^ 3; # endif } } } #define STEPSIZE sizeof(reg_t) LZ4_FORCE_INLINE unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { const BYTE* const pStart = pIn; if (likely(pIn < pInLimit-(STEPSIZE-1))) { reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; } else { return LZ4_NbCommonBytes(diff); } } while (likely(pIn < pInLimit-(STEPSIZE-1))) { reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; } pIn += LZ4_NbCommonBytes(diff); return (unsigned)(pIn - pStart); } if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; } if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; } if ((pIn compression run slower on incompressible data */ /*-************************************ * Local Structures and types **************************************/ typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; /** * This enum distinguishes several different modes of accessing previous * content in the stream. * * - noDict : There is no preceding content. * - withPrefix64k : Table entries up to ctx->dictSize before the current blob * blob being compressed are valid and refer to the preceding * content (of length ctx->dictSize), which is available * contiguously preceding in memory the content currently * being compressed. * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere * else in memory, starting at ctx->dictionary with length * ctx->dictSize. * - usingDictCtx : Everything concerning the preceding content is * in a separate context, pointed to by ctx->dictCtx. * ctx->dictionary, ctx->dictSize, and table entries * in the current context that refer to positions * preceding the beginning of the current compression are * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx * ->dictSize describe the location and size of the preceding * content, and matches are found by looking in the ctx * ->dictCtx->hashTable. */ typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive; typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; /*-************************************ * Local Utils **************************************/ int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } int LZ4_sizeofState(void) { return sizeof(LZ4_stream_t); } /*-**************************************** * Internal Definitions, used only in Tests *******************************************/ #if defined (__cplusplus) extern "C" { #endif int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize); int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize); int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const void* dictStart, size_t dictSize); #if defined (__cplusplus) } #endif /*-****************************** * Compression functions ********************************/ LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { if (tableType == byU16) return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); else return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; if (LZ4_isLittleEndian()) { const U64 prime5bytes = 889523592379ULL; return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); } else { const U64 prime8bytes = 11400714785074694791ULL; return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } } LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); return LZ4_hash4(LZ4_read32(p), tableType); } LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { default: /* fallthrough */ case clearedTable: { /* illegal! */ assert(0); return; } case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; } case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; } case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; } } } LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { default: /* fallthrough */ case clearedTable: /* fallthrough */ case byPtr: { /* illegal! */ assert(0); return; } case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; } case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; } } } /* LZ4_putPosition*() : only used in byPtr mode */ LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType) { const BYTE** const hashTable = (const BYTE**)tableBase; assert(tableType == byPtr); (void)tableType; hashTable[h] = p; } LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType) { U32 const h = LZ4_hashPosition(p, tableType); LZ4_putPositionOnHash(p, h, tableBase, tableType); } /* LZ4_getIndexOnHash() : * Index of match position registered in hash table. * hash position must be calculated by using base+index, or dictBase+index. * Assumption 1 : only valid if tableType == byU32 or byU16. * Assumption 2 : h is presumed valid (within limits of hash table) */ LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) { LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; assert(h < (1U << (LZ4_MEMORY_USAGE-2))); return hashTable[h]; } if (tableType == byU16) { const U16* const hashTable = (const U16*) tableBase; assert(h < (1U << (LZ4_MEMORY_USAGE-1))); return hashTable[h]; } assert(0); return 0; /* forbidden case */ } static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType) { assert(tableType == byPtr); (void)tableType; { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; } } LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, const void* tableBase, tableType_t tableType) { U32 const h = LZ4_hashPosition(p, tableType); return LZ4_getPositionOnHash(h, tableBase, tableType); } LZ4_FORCE_INLINE void LZ4_prepareTable(LZ4_stream_t_internal* const cctx, const int inputSize, const tableType_t tableType) { /* If the table hasn't been used, it's guaranteed to be zeroed out, and is * therefore safe to use no matter what mode we're in. Otherwise, we figure * out if it's safe to leave as is or whether it needs to be reset. */ if ((tableType_t)cctx->tableType != clearedTable) { assert(inputSize >= 0); if ((tableType_t)cctx->tableType != tableType || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU) || ((tableType == byU32) && cctx->currentOffset > 1 GB) || tableType == byPtr || inputSize >= 4 KB) { DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx); MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE); cctx->currentOffset = 0; cctx->tableType = (U32)clearedTable; } else { DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)"); } } /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, * is faster than compressing without a gap. * However, compressing with currentOffset == 0 is faster still, * so we preserve that case. */ if (cctx->currentOffset != 0 && tableType == byU32) { DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset"); cctx->currentOffset += 64 KB; } /* Finally, clear history */ cctx->dictCtx = NULL; cctx->dictionary = NULL; cctx->dictSize = 0; } /** LZ4_compress_generic() : * inlined, to ensure branches are decided at compilation time. * The following conditions are presumed already validated: * - source != NULL * - inputSize > 0 */ LZ4_FORCE_INLINE int LZ4_compress_generic_validated( LZ4_stream_t_internal* const cctx, const char* const source, char* const dest, const int inputSize, int* inputConsumed, /* only written when outputDirective == fillOutput */ const int maxOutputSize, const limitedOutput_directive outputDirective, const tableType_t tableType, const dict_directive dictDirective, const dictIssue_directive dictIssue, const int acceleration) { int result; const BYTE* ip = (const BYTE*)source; U32 const startIndex = cctx->currentOffset; const BYTE* base = (const BYTE*)source - startIndex; const BYTE* lowLimit; const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx; const BYTE* const dictionary = dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary; const U32 dictSize = dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize; const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with indexes in current context */ int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1; const BYTE* const matchlimit = iend - LASTLITERALS; /* the dictCtx currentOffset is indexed on the start of the dictionary, * while a dictionary in the current context precedes the currentOffset */ const BYTE* dictBase = (dictionary == NULL) ? NULL : (dictDirective == usingDictCtx) ? dictionary + dictSize - dictCtx->currentOffset : dictionary + dictSize - startIndex; BYTE* op = (BYTE*) dest; BYTE* const olimit = op + maxOutputSize; U32 offset = 0; U32 forwardH; DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType); assert(ip != NULL); if (tableType == byU16) assert(inputSize= 1); lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0); /* Update context state */ if (dictDirective == usingDictCtx) { /* Subsequent linked blocks can't use the dictionary. */ /* Instead, they use the block we just compressed. */ cctx->dictCtx = NULL; cctx->dictSize = (U32)inputSize; } else { cctx->dictSize += (U32)inputSize; } cctx->currentOffset += (U32)inputSize; cctx->tableType = (U32)tableType; if (inputSizehashTable, byPtr); } else { LZ4_putIndexOnHash(startIndex, h, cctx->hashTable, tableType); } } ip++; forwardH = LZ4_hashPosition(ip, tableType); /* Main Loop */ for ( ; ; ) { const BYTE* match; BYTE* token; const BYTE* filledIp; /* Find a match */ if (tableType == byPtr) { const BYTE* forwardIp = ip; int step = 1; int searchMatchNb = acceleration << LZ4_skipTrigger; do { U32 const h = forwardH; ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; assert(ip < mflimitPlusOne); match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType); forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType); } while ( (match+LZ4_DISTANCE_MAX < ip) || (LZ4_read32(match) != LZ4_read32(ip)) ); } else { /* byU32, byU16 */ const BYTE* forwardIp = ip; int step = 1; int searchMatchNb = acceleration << LZ4_skipTrigger; do { U32 const h = forwardH; U32 const current = (U32)(forwardIp - base); U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); assert(matchIndex <= current); assert(forwardIp - base < (ptrdiff_t)(2 GB - 1)); ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; assert(ip < mflimitPlusOne); if (dictDirective == usingDictCtx) { if (matchIndex < startIndex) { /* there was no match, try the dictionary */ assert(tableType == byU32); matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); match = dictBase + matchIndex; matchIndex += dictDelta; /* make dictCtx index comparable with current context */ lowLimit = dictionary; } else { match = base + matchIndex; lowLimit = (const BYTE*)source; } } else if (dictDirective == usingExtDict) { if (matchIndex < startIndex) { DEBUGLOG(7, "extDict candidate: matchIndex=%5u < startIndex=%5u", matchIndex, startIndex); assert(startIndex - matchIndex >= MINMATCH); assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; } else { match = base + matchIndex; lowLimit = (const BYTE*)source; } } else { /* single continuous memory segment */ match = base + matchIndex; } forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); DEBUGLOG(7, "candidate at pos=%u (offset=%u \n", matchIndex, current - matchIndex); if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; } /* match outside of valid area */ assert(matchIndex < current); if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX)) && (matchIndex+LZ4_DISTANCE_MAX < current)) { continue; } /* too far */ assert((current - matchIndex) <= LZ4_DISTANCE_MAX); /* match now expected within distance */ if (LZ4_read32(match) == LZ4_read32(ip)) { if (maybe_extMem) offset = current - matchIndex; break; /* match found */ } } while(1); } /* Catch up */ filledIp = ip; while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } /* Encode Literals */ { unsigned const litLength = (unsigned)(ip - anchor); token = op++; if ((outputDirective == limitedOutput) && /* Check output buffer overflow */ (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) ) { return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ } if ((outputDirective == fillOutput) && (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) { op--; goto _last_literals; } if (litLength >= RUN_MASK) { int len = (int)(litLength - RUN_MASK); *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } else *token = (BYTE)(litLength< olimit)) { /* the match was too close to the end, rewind and go to last literals */ op = token; goto _last_literals; } /* Encode Offset */ if (maybe_extMem) { /* static test */ DEBUGLOG(6, " with offset=%u (ext if > %i)", offset, (int)(ip - (const BYTE*)source)); assert(offset <= LZ4_DISTANCE_MAX && offset > 0); LZ4_writeLE16(op, (U16)offset); op+=2; } else { DEBUGLOG(6, " with offset=%u (same segment)", (U32)(ip - match)); assert(ip-match <= LZ4_DISTANCE_MAX); LZ4_writeLE16(op, (U16)(ip - match)); op+=2; } /* Encode MatchLength */ { unsigned matchCode; if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx) && (lowLimit==dictionary) /* match within extDict */ ) { const BYTE* limit = ip + (dictEnd-match); assert(dictEnd > match); if (limit > matchlimit) limit = matchlimit; matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); ip += (size_t)matchCode + MINMATCH; if (ip==limit) { unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit); matchCode += more; ip += more; } DEBUGLOG(6, " with matchLength=%u starting in extDict", matchCode+MINMATCH); } else { matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); ip += (size_t)matchCode + MINMATCH; DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH); } if ((outputDirective) && /* Check output buffer overflow */ (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) { if (outputDirective == fillOutput) { /* Match description too long : reduce it */ U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255; ip -= matchCode - newMatchCode; assert(newMatchCode < matchCode); matchCode = newMatchCode; if (unlikely(ip <= filledIp)) { /* We have already filled up to filledIp so if ip ends up less than filledIp * we have positions in the hash table beyond the current position. This is * a problem if we reuse the hash table. So we have to remove these positions * from the hash table. */ const BYTE* ptr; DEBUGLOG(5, "Clearing %u positions", (U32)(filledIp - ip)); for (ptr = ip; ptr <= filledIp; ++ptr) { U32 const h = LZ4_hashPosition(ptr, tableType); LZ4_clearHash(h, cctx->hashTable, tableType); } } } else { assert(outputDirective == limitedOutput); return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ } } if (matchCode >= ML_MASK) { *token += ML_MASK; matchCode -= ML_MASK; LZ4_write32(op, 0xFFFFFFFF); while (matchCode >= 4*255) { op+=4; LZ4_write32(op, 0xFFFFFFFF); matchCode -= 4*255; } op += matchCode / 255; *op++ = (BYTE)(matchCode % 255); } else *token += (BYTE)(matchCode); } /* Ensure we have enough space for the last literals. */ assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit)); anchor = ip; /* Test end of chunk */ if (ip >= mflimitPlusOne) break; /* Fill table */ { U32 const h = LZ4_hashPosition(ip-2, tableType); if (tableType == byPtr) { LZ4_putPositionOnHash(ip-2, h, cctx->hashTable, byPtr); } else { U32 const idx = (U32)((ip-2) - base); LZ4_putIndexOnHash(idx, h, cctx->hashTable, tableType); } } /* Test next position */ if (tableType == byPtr) { match = LZ4_getPosition(ip, cctx->hashTable, tableType); LZ4_putPosition(ip, cctx->hashTable, tableType); if ( (match+LZ4_DISTANCE_MAX >= ip) && (LZ4_read32(match) == LZ4_read32(ip)) ) { token=op++; *token=0; goto _next_match; } } else { /* byU32, byU16 */ U32 const h = LZ4_hashPosition(ip, tableType); U32 const current = (U32)(ip-base); U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); assert(matchIndex < current); if (dictDirective == usingDictCtx) { if (matchIndex < startIndex) { /* there was no match, try the dictionary */ assert(tableType == byU32); matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); match = dictBase + matchIndex; lowLimit = dictionary; /* required for match length counter */ matchIndex += dictDelta; } else { match = base + matchIndex; lowLimit = (const BYTE*)source; /* required for match length counter */ } } else if (dictDirective==usingExtDict) { if (matchIndex < startIndex) { assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; /* required for match length counter */ } else { match = base + matchIndex; lowLimit = (const BYTE*)source; /* required for match length counter */ } } else { /* single memory segment */ match = base + matchIndex; } LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); assert(matchIndex < current); if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1) && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current)) && (LZ4_read32(match) == LZ4_read32(ip)) ) { token=op++; *token=0; if (maybe_extMem) offset = current - matchIndex; DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i", (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source)); goto _next_match; } } /* Prepare next loop */ forwardH = LZ4_hashPosition(++ip, tableType); } _last_literals: /* Encode Last Literals */ { size_t lastRun = (size_t)(iend - anchor); if ( (outputDirective) && /* Check output buffer overflow */ (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) { if (outputDirective == fillOutput) { /* adapt lastRun to fill 'dst' */ assert(olimit >= op); lastRun = (size_t)(olimit-op) - 1/*token*/; lastRun -= (lastRun + 256 - RUN_MASK) / 256; /*additional length tokens*/ } else { assert(outputDirective == limitedOutput); return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ } } DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun); if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; *op++ = (BYTE) accumulator; } else { *op++ = (BYTE)(lastRun< 0); DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, result); return result; } /** LZ4_compress_generic() : * inlined, to ensure branches are decided at compilation time; * takes care of src == (NULL, 0) * and forward the rest to LZ4_compress_generic_validated */ LZ4_FORCE_INLINE int LZ4_compress_generic( LZ4_stream_t_internal* const cctx, const char* const src, char* const dst, const int srcSize, int *inputConsumed, /* only written when outputDirective == fillOutput */ const int dstCapacity, const limitedOutput_directive outputDirective, const tableType_t tableType, const dict_directive dictDirective, const dictIssue_directive dictIssue, const int acceleration) { DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i", srcSize, dstCapacity); if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; } /* Unsupported srcSize, too large (or negative) */ if (srcSize == 0) { /* src == NULL supported if srcSize == 0 */ if (outputDirective != notLimited && dstCapacity <= 0) return 0; /* no output, can't write anything */ DEBUGLOG(5, "Generating an empty block"); assert(outputDirective == notLimited || dstCapacity >= 1); assert(dst != NULL); dst[0] = 0; if (outputDirective == fillOutput) { assert (inputConsumed != NULL); *inputConsumed = 0; } return 1; } assert(src != NULL); return LZ4_compress_generic_validated(cctx, src, dst, srcSize, inputConsumed, /* only written into if outputDirective == fillOutput */ dstCapacity, outputDirective, tableType, dictDirective, dictIssue, acceleration); } int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse; assert(ctx != NULL); if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; if (maxOutputSize >= LZ4_compressBound(inputSize)) { if (inputSize < LZ4_64Klimit) { return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration); } else { const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32; return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration); } } else { if (inputSize < LZ4_64Klimit) { return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); } else { const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32; return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration); } } } /** * LZ4_compress_fast_extState_fastReset() : * A variant of LZ4_compress_fast_extState(). * * Using this variant avoids an expensive initialization step. It is only safe * to call if the state buffer is known to be correctly initialized already * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of * "correctly initialized"). */ int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration) { LZ4_stream_t_internal* const ctx = &((LZ4_stream_t*)state)->internal_donotuse; if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; assert(ctx != NULL); if (dstCapacity >= LZ4_compressBound(srcSize)) { if (srcSize < LZ4_64Klimit) { const tableType_t tableType = byU16; LZ4_prepareTable(ctx, srcSize, tableType); if (ctx->currentOffset) { return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration); } else { return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration); } } else { const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; LZ4_prepareTable(ctx, srcSize, tableType); return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration); } } else { if (srcSize < LZ4_64Klimit) { const tableType_t tableType = byU16; LZ4_prepareTable(ctx, srcSize, tableType); if (ctx->currentOffset) { return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration); } else { return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); } } else { const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; LZ4_prepareTable(ctx, srcSize, tableType); return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); } } } int LZ4_compress_fast(const char* src, char* dest, int srcSize, int dstCapacity, int acceleration) { int result; #if (LZ4_HEAPMODE) LZ4_stream_t* const ctxPtr = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ if (ctxPtr == NULL) return 0; #else LZ4_stream_t ctx; LZ4_stream_t* const ctxPtr = &ctx; #endif result = LZ4_compress_fast_extState(ctxPtr, src, dest, srcSize, dstCapacity, acceleration); #if (LZ4_HEAPMODE) FREEMEM(ctxPtr); #endif return result; } int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity) { return LZ4_compress_fast(src, dst, srcSize, dstCapacity, 1); } /* Note!: This function leaves the stream in an unclean/broken state! * It is not safe to subsequently use the same state with a _fastReset() or * _continue() call without resetting it. */ static int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize) { void* const s = LZ4_initStream(state, sizeof (*state)); assert(s != NULL); (void)s; if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); } else { if (*srcSizePtr < LZ4_64Klimit) { return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1); } else { tableType_t const addrMode = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, 1); } } } int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { #if (LZ4_HEAPMODE) LZ4_stream_t* const ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ if (ctx == NULL) return 0; #else LZ4_stream_t ctxBody; LZ4_stream_t* const ctx = &ctxBody; #endif int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); #if (LZ4_HEAPMODE) FREEMEM(ctx); #endif return result; } /*-****************************** * Streaming functions ********************************/ #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_stream_t* LZ4_createStream(void) { LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal)); DEBUGLOG(4, "LZ4_createStream %p", lz4s); if (lz4s == NULL) return NULL; LZ4_initStream(lz4s, sizeof(*lz4s)); return lz4s; } #endif static size_t LZ4_stream_t_alignment(void) { #if LZ4_ALIGN_TEST typedef struct { char c; LZ4_stream_t t; } t_a; return sizeof(t_a) - sizeof(LZ4_stream_t); #else return 1; /* effectively disabled */ #endif } LZ4_stream_t* LZ4_initStream (void* buffer, size_t size) { DEBUGLOG(5, "LZ4_initStream"); if (buffer == NULL) { return NULL; } if (size < sizeof(LZ4_stream_t)) { return NULL; } if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL; MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal)); return (LZ4_stream_t*)buffer; } /* resetStream is now deprecated, * prefer initStream() which is more general */ void LZ4_resetStream (LZ4_stream_t* LZ4_stream) { DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream); MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal)); } void LZ4_resetStream_fast(LZ4_stream_t* ctx) { LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32); } #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { if (!LZ4_stream) return 0; /* support free on NULL */ DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream); FREEMEM(LZ4_stream); return (0); } #endif #define HASH_UNIT sizeof(reg_t) int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) { LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; const tableType_t tableType = byU32; const BYTE* p = (const BYTE*)dictionary; const BYTE* const dictEnd = p + dictSize; U32 idx32; DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict); /* It's necessary to reset the context, * and not just continue it with prepareTable() * to avoid any risk of generating overflowing matchIndex * when compressing using this dictionary */ LZ4_resetStream(LZ4_dict); /* We always increment the offset by 64 KB, since, if the dict is longer, * we truncate it to the last 64k, and if it's shorter, we still want to * advance by a whole window length so we can provide the guarantee that * there are only valid offsets in the window, which allows an optimization * in LZ4_compress_fast_continue() where it uses noDictIssue even when the * dictionary isn't a full 64k. */ dict->currentOffset += 64 KB; if (dictSize < (int)HASH_UNIT) { return 0; } if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; dict->dictionary = p; dict->dictSize = (U32)(dictEnd - p); dict->tableType = (U32)tableType; idx32 = dict->currentOffset - dict->dictSize; while (p <= dictEnd-HASH_UNIT) { U32 const h = LZ4_hashPosition(p, tableType); LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType); p+=3; idx32+=3; } return (int)dict->dictSize; } void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) { const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL : &(dictionaryStream->internal_donotuse); DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)", workingStream, dictionaryStream, dictCtx != NULL ? dictCtx->dictSize : 0); if (dictCtx != NULL) { /* If the current offset is zero, we will never look in the * external dictionary context, since there is no value a table * entry can take that indicate a miss. In that case, we need * to bump the offset to something non-zero. */ if (workingStream->internal_donotuse.currentOffset == 0) { workingStream->internal_donotuse.currentOffset = 64 KB; } /* Don't actually attach an empty dictionary. */ if (dictCtx->dictSize == 0) { dictCtx = NULL; } } workingStream->internal_donotuse.dictCtx = dictCtx; } static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize) { assert(nextSize >= 0); if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */ /* rescale hash table */ U32 const delta = LZ4_dict->currentOffset - 64 KB; const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; int i; DEBUGLOG(4, "LZ4_renormDictT"); for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; else LZ4_dict->hashTable[i] -= delta; } LZ4_dict->currentOffset = 64 KB; if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; } } int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { const tableType_t tableType = byU32; LZ4_stream_t_internal* const streamPtr = &LZ4_stream->internal_donotuse; const char* dictEnd = streamPtr->dictSize ? (const char*)streamPtr->dictionary + streamPtr->dictSize : NULL; DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)", inputSize, streamPtr->dictSize); LZ4_renormDictT(streamPtr, inputSize); /* fix index overflow */ if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; /* invalidate tiny dictionaries */ if ( (streamPtr->dictSize < 4) /* tiny dictionary : not enough for a hash */ && (dictEnd != source) /* prefix mode */ && (inputSize > 0) /* tolerance : don't lose history, in case next invocation would use prefix mode */ && (streamPtr->dictCtx == NULL) /* usingDictCtx */ ) { DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary); /* remove dictionary existence from history, to employ faster prefix mode */ streamPtr->dictSize = 0; streamPtr->dictionary = (const BYTE*)source; dictEnd = source; } /* Check overlapping input/dictionary space */ { const char* const sourceEnd = source + inputSize; if ((sourceEnd > (const char*)streamPtr->dictionary) && (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize; } } /* prefix mode : source data follows dictionary */ if (dictEnd == source) { if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration); else return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration); } /* external dictionary mode */ { int result; if (streamPtr->dictCtx) { /* We depend here on the fact that dictCtx'es (produced by * LZ4_loadDict) guarantee that their tables contain no references * to offsets between dictCtx->currentOffset - 64 KB and * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe * to use noDictIssue even when the dict isn't a full 64 KB. */ if (inputSize > 4 KB) { /* For compressing large blobs, it is faster to pay the setup * cost to copy the dictionary's tables into the active context, * so that the compression loop is only looking into one table. */ LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr)); result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); } else { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration); } } else { /* small data <= 4 KB */ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration); } else { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); } } streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)inputSize; return result; } } /* Hidden debug function, to force-test external dictionary mode */ int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize) { LZ4_stream_t_internal* const streamPtr = &LZ4_dict->internal_donotuse; int result; LZ4_renormDictT(streamPtr, srcSize); if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1); } else { result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); } streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)srcSize; return result; } /*! LZ4_saveDict() : * If previously compressed data block is not guaranteed to remain available at its memory location, * save it into a safer place (char* safeBuffer). * Note : no need to call LZ4_loadDict() afterwards, dictionary is immediately usable, * one can therefore call LZ4_compress_fast_continue() right after. * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. */ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, safeBuffer); if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */ if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; } if (safeBuffer == NULL) assert(dictSize == 0); if (dictSize > 0) { const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; assert(dict->dictionary); LZ4_memmove(safeBuffer, previousDictEnd - dictSize, (size_t)dictSize); } dict->dictionary = (const BYTE*)safeBuffer; dict->dictSize = (U32)dictSize; return dictSize; } /*-******************************* * Decompression functions ********************************/ typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive; #undef MIN #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) /* variant for decompress_unsafe() * does not know end of input * presumes input is well formed * note : will consume at least one byte */ static size_t read_long_length_no_check(const BYTE** pp) { size_t b, l = 0; do { b = **pp; (*pp)++; l += b; } while (b==255); DEBUGLOG(6, "read_long_length_no_check: +length=%zu using %zu input bytes", l, l/255 + 1) return l; } /* core decoder variant for LZ4_decompress_fast*() * for legacy support only : these entry points are deprecated. * - Presumes input is correctly formed (no defense vs malformed inputs) * - Does not know input size (presume input buffer is "large enough") * - Decompress a full block (only) * @return : nb of bytes read from input. * Note : this variant is not optimized for speed, just for maintenance. * the goal is to remove support of decompress_fast*() variants by v2.0 **/ LZ4_FORCE_INLINE int LZ4_decompress_unsafe_generic( const BYTE* const istart, BYTE* const ostart, int decompressedSize, size_t prefixSize, const BYTE* const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note: =0 if dictStart==NULL */ ) { const BYTE* ip = istart; BYTE* op = (BYTE*)ostart; BYTE* const oend = ostart + decompressedSize; const BYTE* const prefixStart = ostart - prefixSize; DEBUGLOG(5, "LZ4_decompress_unsafe_generic"); if (dictStart == NULL) assert(dictSize == 0); while (1) { /* start new sequence */ unsigned token = *ip++; /* literals */ { size_t ll = token >> ML_BITS; if (ll==15) { /* long literal length */ ll += read_long_length_no_check(&ip); } if ((size_t)(oend-op) < ll) return -1; /* output buffer overflow */ LZ4_memmove(op, ip, ll); /* support in-place decompression */ op += ll; ip += ll; if ((size_t)(oend-op) < MFLIMIT) { if (op==oend) break; /* end of block */ DEBUGLOG(5, "invalid: literals end at distance %zi from end of block", oend-op); /* incorrect end of block : * last match must start at least MFLIMIT==12 bytes before end of output block */ return -1; } } /* match */ { size_t ml = token & 15; size_t const offset = LZ4_readLE16(ip); ip+=2; if (ml==15) { /* long literal length */ ml += read_long_length_no_check(&ip); } ml += MINMATCH; if ((size_t)(oend-op) < ml) return -1; /* output buffer overflow */ { const BYTE* match = op - offset; /* out of range */ if (offset > (size_t)(op - prefixStart) + dictSize) { DEBUGLOG(6, "offset out of range"); return -1; } /* check special case : extDict */ if (offset > (size_t)(op - prefixStart)) { /* extDict scenario */ const BYTE* const dictEnd = dictStart + dictSize; const BYTE* extMatch = dictEnd - (offset - (size_t)(op-prefixStart)); size_t const extml = (size_t)(dictEnd - extMatch); if (extml > ml) { /* match entirely within extDict */ LZ4_memmove(op, extMatch, ml); op += ml; ml = 0; } else { /* match split between extDict & prefix */ LZ4_memmove(op, extMatch, extml); op += extml; ml -= extml; } match = prefixStart; } /* match copy - slow variant, supporting overlap copy */ { size_t u; for (u=0; u= ipmax before start of loop. Returns initial_error if so. * @error (output) - error code. Must be set to 0 before call. **/ typedef size_t Rvl_t; static const Rvl_t rvl_error = (Rvl_t)(-1); LZ4_FORCE_INLINE Rvl_t read_variable_length(const BYTE** ip, const BYTE* ilimit, int initial_check) { Rvl_t s, length = 0; assert(ip != NULL); assert(*ip != NULL); assert(ilimit != NULL); if (initial_check && unlikely((*ip) >= ilimit)) { /* read limit reached */ return rvl_error; } do { s = **ip; (*ip)++; length += s; if (unlikely((*ip) > ilimit)) { /* read limit reached */ return rvl_error; } /* accumulator overflow detection (32-bit mode only) */ if ((sizeof(length)<8) && unlikely(length > ((Rvl_t)(-1)/2)) ) { return rvl_error; } } while (s==255); return length; } /*! LZ4_decompress_generic() : * This generic decompression function covers all use cases. * It shall be instantiated several times, using different sets of directives. * Note that it is important for performance that this function really get inlined, * in order to remove useless branches during compilation optimization. */ LZ4_FORCE_INLINE int LZ4_decompress_generic( const char* const src, char* const dst, int srcSize, int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */ earlyEnd_directive partialDecoding, /* full, partial */ dict_directive dict, /* noDict, withPrefix64k, usingExtDict */ const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */ const BYTE* const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note : = 0 if noDict */ ) { if ((src == NULL) || (outputSize < 0)) { return -1; } { const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; BYTE* op = (BYTE*) dst; BYTE* const oend = op + outputSize; BYTE* cpy; const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize; const int checkOffset = (dictSize < (int)(64 KB)); /* Set up the "end" pointers for the shortcut. */ const BYTE* const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/; const BYTE* const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/; const BYTE* match; size_t offset; unsigned token; size_t length; DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, outputSize); /* Special cases */ assert(lowPrefix <= op); if (unlikely(outputSize==0)) { /* Empty output buffer */ if (partialDecoding) return 0; return ((srcSize==1) && (*ip==0)) ? 0 : -1; } if (unlikely(srcSize==0)) { return -1; } /* LZ4_FAST_DEC_LOOP: * designed for modern OoO performance cpus, * where copying reliably 32-bytes is preferable to an unpredictable branch. * note : fast loop may show a regression for some client arm chips. */ #if LZ4_FAST_DEC_LOOP if ((oend - op) < FASTLOOP_SAFE_DISTANCE) { DEBUGLOG(6, "skip fast decode loop"); goto safe_decode; } /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */ DEBUGLOG(6, "using fast decode loop"); while (1) { /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */ assert(oend - op >= FASTLOOP_SAFE_DISTANCE); assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ /* decode literal length */ if (length == RUN_MASK) { size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); if (addl == rvl_error) { DEBUGLOG(6, "error reading long literal length"); goto _output_error; } length += addl; if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ /* copy literals */ LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); if ((op+length>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; } LZ4_wildCopy32(op, ip, op+length); ip += length; op += length; } else if (ip <= iend-(16 + 1/*max lit + offset + nextToken*/)) { /* We don't need to check oend, since we check it once for each loop below */ DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length); /* Literals can only be <= 14, but hope compilers optimize better when copy by a register size */ LZ4_memcpy(op, ip, 16); ip += length; op += length; } else { goto safe_literal_copy; } /* get offset */ offset = LZ4_readLE16(ip); ip+=2; DEBUGLOG(6, " offset = %zu", offset); match = op - offset; assert(match <= op); /* overflow check */ /* get matchlength */ length = token & ML_MASK; if (length == ML_MASK) { size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); if (addl == rvl_error) { DEBUGLOG(6, "error reading long match length"); goto _output_error; } length += addl; length += MINMATCH; if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */ if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { DEBUGLOG(6, "Error : offset outside buffers"); goto _output_error; } if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { goto safe_match_copy; } } else { length += MINMATCH; if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { goto safe_match_copy; } /* Fastpath check: skip LZ4_wildCopy32 when true */ if ((dict == withPrefix64k) || (match >= lowPrefix)) { if (offset >= 8) { assert(match >= lowPrefix); assert(match <= op); assert(op + 18 <= oend); LZ4_memcpy(op, match, 8); LZ4_memcpy(op+8, match+8, 8); LZ4_memcpy(op+16, match+16, 2); op += length; continue; } } } if ( checkOffset && (unlikely(match + dictSize < lowPrefix)) ) { DEBUGLOG(6, "Error : pos=%zi, offset=%zi => outside buffers", op-lowPrefix, op-match); goto _output_error; } /* match starting within external dictionary */ if ((dict==usingExtDict) && (match < lowPrefix)) { assert(dictEnd != NULL); if (unlikely(op+length > oend-LASTLITERALS)) { if (partialDecoding) { DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd"); length = MIN(length, (size_t)(oend-op)); } else { DEBUGLOG(6, "end-of-block condition violated") goto _output_error; } } if (length <= (size_t)(lowPrefix-match)) { /* match fits entirely within external dictionary : just copy */ LZ4_memmove(op, dictEnd - (lowPrefix-match), length); op += length; } else { /* match stretches into both external dictionary and current block */ size_t const copySize = (size_t)(lowPrefix - match); size_t const restSize = length - copySize; LZ4_memcpy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ BYTE* const endOfMatch = op + restSize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) { *op++ = *copyFrom++; } } else { LZ4_memcpy(op, lowPrefix, restSize); op += restSize; } } continue; } /* copy match within block */ cpy = op + length; assert((op <= oend) && (oend-op >= 32)); if (unlikely(offset<16)) { LZ4_memcpy_using_offset(op, match, cpy, offset); } else { LZ4_wildCopy32(op, match, cpy); } op = cpy; /* wildcopy correction */ } safe_decode: #endif /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */ DEBUGLOG(6, "using safe decode loop"); while (1) { assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ /* A two-stage shortcut for the most common case: * 1) If the literal length is 0..14, and there is enough space, * enter the shortcut and copy 16 bytes on behalf of the literals * (in the fast mode, only 8 bytes can be safely copied this way). * 2) Further if the match length is 4..18, copy 18 bytes in a similar * manner; but we ensure that there's enough space in the output for * those 18 bytes earlier, upon entering the shortcut (in other words, * there is a combined check for both stages). */ if ( (length != RUN_MASK) /* strictly "less than" on input, to re-enter the loop with at least one byte */ && likely((ip < shortiend) & (op <= shortoend)) ) { /* Copy the literals */ LZ4_memcpy(op, ip, 16); op += length; ip += length; /* The second stage: prepare for match copying, decode full info. * If it doesn't work out, the info won't be wasted. */ length = token & ML_MASK; /* match length */ offset = LZ4_readLE16(ip); ip += 2; match = op - offset; assert(match <= op); /* check overflow */ /* Do not deal with overlapping matches. */ if ( (length != ML_MASK) && (offset >= 8) && (dict==withPrefix64k || match >= lowPrefix) ) { /* Copy the match. */ LZ4_memcpy(op + 0, match + 0, 8); LZ4_memcpy(op + 8, match + 8, 8); LZ4_memcpy(op +16, match +16, 2); op += length + MINMATCH; /* Both stages worked, load the next token. */ continue; } /* The second stage didn't work out, but the info is ready. * Propel it right to the point of match copying. */ goto _copy_match; } /* decode literal length */ if (length == RUN_MASK) { size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); if (addl == rvl_error) { goto _output_error; } length += addl; if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ } #if LZ4_FAST_DEC_LOOP safe_literal_copy: #endif /* copy literals */ cpy = op+length; LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) { /* We've either hit the input parsing restriction or the output parsing restriction. * In the normal scenario, decoding a full block, it must be the last sequence, * otherwise it's an error (invalid input or dimensions). * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow. */ if (partialDecoding) { /* Since we are partial decoding we may be in this block because of the output parsing * restriction, which is not valid since the output buffer is allowed to be undersized. */ DEBUGLOG(7, "partialDecoding: copying literals, close to input or output end") DEBUGLOG(7, "partialDecoding: literal length = %u", (unsigned)length); DEBUGLOG(7, "partialDecoding: remaining space in dstBuffer : %i", (int)(oend - op)); DEBUGLOG(7, "partialDecoding: remaining space in srcBuffer : %i", (int)(iend - ip)); /* Finishing in the middle of a literals segment, * due to lack of input. */ if (ip+length > iend) { length = (size_t)(iend-ip); cpy = op + length; } /* Finishing in the middle of a literals segment, * due to lack of output space. */ if (cpy > oend) { cpy = oend; assert(op<=oend); length = (size_t)(oend-op); } } else { /* We must be on the last sequence (or invalid) because of the parsing limitations * so check that we exactly consume the input and don't overrun the output buffer. */ if ((ip+length != iend) || (cpy > oend)) { DEBUGLOG(6, "should have been last run of literals") DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend); DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend); goto _output_error; } } LZ4_memmove(op, ip, length); /* supports overlapping memory regions, for in-place decompression scenarios */ ip += length; op += length; /* Necessarily EOF when !partialDecoding. * When partialDecoding, it is EOF if we've either * filled the output buffer or * can't proceed with reading an offset for following match. */ if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) { break; } } else { LZ4_wildCopy8(op, ip, cpy); /* can overwrite up to 8 bytes beyond cpy */ ip += length; op = cpy; } /* get offset */ offset = LZ4_readLE16(ip); ip+=2; match = op - offset; /* get matchlength */ length = token & ML_MASK; _copy_match: if (length == ML_MASK) { size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); if (addl == rvl_error) { goto _output_error; } length += addl; if (unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ } length += MINMATCH; #if LZ4_FAST_DEC_LOOP safe_match_copy: #endif if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */ /* match starting within external dictionary */ if ((dict==usingExtDict) && (match < lowPrefix)) { assert(dictEnd != NULL); if (unlikely(op+length > oend-LASTLITERALS)) { if (partialDecoding) length = MIN(length, (size_t)(oend-op)); else goto _output_error; /* doesn't respect parsing restriction */ } if (length <= (size_t)(lowPrefix-match)) { /* match fits entirely within external dictionary : just copy */ LZ4_memmove(op, dictEnd - (lowPrefix-match), length); op += length; } else { /* match stretches into both external dictionary and current block */ size_t const copySize = (size_t)(lowPrefix - match); size_t const restSize = length - copySize; LZ4_memcpy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ BYTE* const endOfMatch = op + restSize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) *op++ = *copyFrom++; } else { LZ4_memcpy(op, lowPrefix, restSize); op += restSize; } } continue; } assert(match >= lowPrefix); /* copy match within block */ cpy = op + length; /* partialDecoding : may end anywhere within the block */ assert(op<=oend); if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) { size_t const mlen = MIN(length, (size_t)(oend-op)); const BYTE* const matchEnd = match + mlen; BYTE* const copyEnd = op + mlen; if (matchEnd > op) { /* overlap copy */ while (op < copyEnd) { *op++ = *match++; } } else { LZ4_memcpy(op, match, mlen); } op = copyEnd; if (op == oend) { break; } continue; } if (unlikely(offset<8)) { LZ4_write32(op, 0); /* silence msan warning when offset==0 */ op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; match += inc32table[offset]; LZ4_memcpy(op+4, match, 4); match -= dec64table[offset]; } else { LZ4_memcpy(op, match, 8); match += 8; } op += 8; if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) { BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1); if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ if (op < oCopyLimit) { LZ4_wildCopy8(op, match, oCopyLimit); match += oCopyLimit - op; op = oCopyLimit; } while (op < cpy) { *op++ = *match++; } } else { LZ4_memcpy(op, match, 8); if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); } } op = cpy; /* wildcopy correction */ } /* end of decoding */ DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst)); return (int) (((char*)op)-dst); /* Nb of output bytes decoded */ /* Overflow error detected */ _output_error: return (int) (-(((const char*)ip)-src))-1; } } /*===== Instantiate the API decoding functions. =====*/ LZ4_FORCE_O2 int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, decode_full_block, noDict, (BYTE*)dest, NULL, 0); } LZ4_FORCE_O2 int LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity) { dstCapacity = MIN(targetOutputSize, dstCapacity); return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity, partial_decode, noDict, (BYTE*)dst, NULL, 0); } LZ4_FORCE_O2 int LZ4_decompress_fast(const char* source, char* dest, int originalSize) { DEBUGLOG(5, "LZ4_decompress_fast"); return LZ4_decompress_unsafe_generic( (const BYTE*)source, (BYTE*)dest, originalSize, 0, NULL, 0); } /*===== Instantiate a few more decoding cases, used more than once. =====*/ LZ4_FORCE_O2 /* Exported, an obsolete API function. */ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 0); } LZ4_FORCE_O2 static int LZ4_decompress_safe_partial_withPrefix64k(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity) { dstCapacity = MIN(targetOutputSize, dstCapacity); return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, partial_decode, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 0); } /* Another obsolete API function, paired with the previous one. */ int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) { return LZ4_decompress_unsafe_generic( (const BYTE*)source, (BYTE*)dest, originalSize, 64 KB, NULL, 0); } LZ4_FORCE_O2 static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize, size_t prefixSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, noDict, (BYTE*)dest-prefixSize, NULL, 0); } LZ4_FORCE_O2 static int LZ4_decompress_safe_partial_withSmallPrefix(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, size_t prefixSize) { dstCapacity = MIN(targetOutputSize, dstCapacity); return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, partial_decode, noDict, (BYTE*)dest-prefixSize, NULL, 0); } LZ4_FORCE_O2 int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize) { DEBUGLOG(5, "LZ4_decompress_safe_forceExtDict"); return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } LZ4_FORCE_O2 int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const void* dictStart, size_t dictSize) { dstCapacity = MIN(targetOutputSize, dstCapacity); return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity, partial_decode, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } LZ4_FORCE_O2 static int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize, const void* dictStart, size_t dictSize) { return LZ4_decompress_unsafe_generic( (const BYTE*)source, (BYTE*)dest, originalSize, 0, (const BYTE*)dictStart, dictSize); } /* The "double dictionary" mode, for use with e.g. ring buffers: the first part * of the dictionary is passed as prefix, and the second via dictStart + dictSize. * These routines are used only once, in LZ4_decompress_*_continue(). */ LZ4_FORCE_INLINE int LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize, size_t prefixSize, const void* dictStart, size_t dictSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, usingExtDict, (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize); } /*===== streaming decompression functions =====*/ #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_streamDecode_t* LZ4_createStreamDecode(void) { LZ4_STATIC_ASSERT(sizeof(LZ4_streamDecode_t) >= sizeof(LZ4_streamDecode_t_internal)); return (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); } int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) { if (LZ4_stream == NULL) { return 0; } /* support free on NULL */ FREEMEM(LZ4_stream); return 0; } #endif /*! LZ4_setStreamDecode() : * Use this function to instruct where to find the dictionary. * This function is not necessary if previous data is still available where it was decoded. * Loading a size of 0 is allowed (same effect as no dictionary). * @return : 1 if OK, 0 if error */ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) { LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; lz4sd->prefixSize = (size_t)dictSize; if (dictSize) { assert(dictionary != NULL); lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; } else { lz4sd->prefixEnd = (const BYTE*) dictionary; } lz4sd->externalDict = NULL; lz4sd->extDictSize = 0; return 1; } /*! LZ4_decoderRingBufferSize() : * when setting a ring buffer for streaming decompression (optional scenario), * provides the minimum size of this ring buffer * to be compatible with any source respecting maxBlockSize condition. * Note : in a ring buffer scenario, * blocks are presumed decompressed next to each other. * When not enough space remains for next block (remainingSize < maxBlockSize), * decoding resumes from beginning of ring buffer. * @return : minimum ring buffer size, * or 0 if there is an error (invalid maxBlockSize). */ int LZ4_decoderRingBufferSize(int maxBlockSize) { if (maxBlockSize < 0) return 0; if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0; if (maxBlockSize < 16) maxBlockSize = 16; return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize); } /* *_continue() : These decoding functions allow decompression of multiple blocks in "streaming" mode. Previously decoded blocks must still be available at the memory position where they were decoded. If it's not possible, save the relevant part of decoded data into a safe buffer, and indicate where it stands using LZ4_setStreamDecode() */ LZ4_FORCE_O2 int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; int result; if (lz4sd->prefixSize == 0) { /* The first call, no dictionary yet. */ assert(lz4sd->extDictSize == 0); result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize); if (result <= 0) return result; lz4sd->prefixSize = (size_t)result; lz4sd->prefixEnd = (BYTE*)dest + result; } else if (lz4sd->prefixEnd == (BYTE*)dest) { /* They're rolling the current segment. */ if (lz4sd->prefixSize >= 64 KB - 1) result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize); else if (lz4sd->extDictSize == 0) result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, lz4sd->prefixSize); else result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize, lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += (size_t)result; lz4sd->prefixEnd += result; } else { /* The buffer wraps around, or they're switching to another buffer. */ lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = (size_t)result; lz4sd->prefixEnd = (BYTE*)dest + result; } return result; } LZ4_FORCE_O2 int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) { LZ4_streamDecode_t_internal* const lz4sd = (assert(LZ4_streamDecode!=NULL), &LZ4_streamDecode->internal_donotuse); int result; DEBUGLOG(5, "LZ4_decompress_fast_continue (toDecodeSize=%i)", originalSize); assert(originalSize >= 0); if (lz4sd->prefixSize == 0) { DEBUGLOG(5, "first invocation : no prefix nor extDict"); assert(lz4sd->extDictSize == 0); result = LZ4_decompress_fast(source, dest, originalSize); if (result <= 0) return result; lz4sd->prefixSize = (size_t)originalSize; lz4sd->prefixEnd = (BYTE*)dest + originalSize; } else if (lz4sd->prefixEnd == (BYTE*)dest) { DEBUGLOG(5, "continue using existing prefix"); result = LZ4_decompress_unsafe_generic( (const BYTE*)source, (BYTE*)dest, originalSize, lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += (size_t)originalSize; lz4sd->prefixEnd += originalSize; } else { DEBUGLOG(5, "prefix becomes extDict"); lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_fast_extDict(source, dest, originalSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = (size_t)originalSize; lz4sd->prefixEnd = (BYTE*)dest + originalSize; } return result; } /* Advanced decoding functions : *_usingDict() : These decoding functions work the same as "_continue" ones, the dictionary must be explicitly provided within parameters */ int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { if (dictSize==0) return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize); if (dictStart+dictSize == dest) { if (dictSize >= 64 KB - 1) { return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize); } assert(dictSize >= 0); return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, (size_t)dictSize); } assert(dictSize >= 0); return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize); } int LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const char* dictStart, int dictSize) { if (dictSize==0) return LZ4_decompress_safe_partial(source, dest, compressedSize, targetOutputSize, dstCapacity); if (dictStart+dictSize == dest) { if (dictSize >= 64 KB - 1) { return LZ4_decompress_safe_partial_withPrefix64k(source, dest, compressedSize, targetOutputSize, dstCapacity); } assert(dictSize >= 0); return LZ4_decompress_safe_partial_withSmallPrefix(source, dest, compressedSize, targetOutputSize, dstCapacity, (size_t)dictSize); } assert(dictSize >= 0); return LZ4_decompress_safe_partial_forceExtDict(source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, (size_t)dictSize); } int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) { if (dictSize==0 || dictStart+dictSize == dest) return LZ4_decompress_unsafe_generic( (const BYTE*)source, (BYTE*)dest, originalSize, (size_t)dictSize, NULL, 0); assert(dictSize >= 0); return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize); } /*=************************************************* * Obsolete Functions ***************************************************/ /* obsolete compression functions */ int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } int LZ4_compress(const char* src, char* dest, int srcSize) { return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize)); } int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1); } int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); } /* These decompression functions are deprecated and should no longer be used. They are only provided here for compatibility with older user programs. - LZ4_uncompress is totally equivalent to LZ4_decompress_fast - LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe */ int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } /* Obsolete Streaming functions */ int LZ4_sizeofStreamState(void) { return sizeof(LZ4_stream_t); } int LZ4_resetStreamState(void* state, char* inputBuffer) { (void)inputBuffer; LZ4_resetStream((LZ4_stream_t*)state); return 0; } #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) void* LZ4_create (char* inputBuffer) { (void)inputBuffer; return LZ4_createStream(); } #endif char* LZ4_slideInputBuffer (void* state) { /* avoid const char * -> char * conversion warning */ return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary; } #endif /* LZ4_COMMONDEFS_ONLY */ ================================================ FILE: lib/LZ4F/lz4.h ================================================ /* * LZ4 - Fast LZ compression algorithm * Header File * Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 homepage : http://www.lz4.org - LZ4 source repository : https://github.com/lz4/lz4 */ #if defined (__cplusplus) extern "C" { #endif #ifndef LZ4_H_2983827168210 #define LZ4_H_2983827168210 /* --- Dependency --- */ #include /* size_t */ /** Introduction LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core, scalable with multi-cores CPU. It features an extremely fast decoder, with speed in multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. The LZ4 compression library provides in-memory compression and decompression functions. It gives full buffer control to user. Compression can be done in: - a single step (described as Simple Functions) - a single step, reusing a context (described in Advanced Functions) - unbounded multiple steps (described as Streaming compression) lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md). Decompressing such a compressed block requires additional metadata. Exact metadata depends on exact decompression function. For the typical case of LZ4_decompress_safe(), metadata includes block's compressed size, and maximum bound of decompressed size. Each application is free to encode and pass such metadata in whichever way it wants. lz4.h only handle blocks, it can not generate Frames. Blocks are different from Frames (doc/lz4_Frame_format.md). Frames bundle both blocks and metadata in a specified manner. Embedding metadata is required for compressed data to be self-contained and portable. Frame format is delivered through a companion API, declared in lz4frame.h. The `lz4` CLI can only manage frames. */ /*^*************************************************************** * Export parameters *****************************************************************/ /* * LZ4_DLL_EXPORT : * Enable exporting of functions when building a Windows DLL * LZ4LIB_VISIBILITY : * Control library symbols visibility. */ #ifndef LZ4LIB_VISIBILITY # if defined(__GNUC__) && (__GNUC__ >= 4) # define LZ4LIB_VISIBILITY __attribute__ ((visibility ("default"))) # else # define LZ4LIB_VISIBILITY # endif #endif #if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) # define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY #elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) # define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ #else # define LZ4LIB_API LZ4LIB_VISIBILITY #endif /*! LZ4_FREESTANDING : * When this macro is set to 1, it enables "freestanding mode" that is * suitable for typical freestanding environment which doesn't support * standard C library. * * - LZ4_FREESTANDING is a compile-time switch. * - It requires the following macros to be defined: * LZ4_memcpy, LZ4_memmove, LZ4_memset. * - It only enables LZ4/HC functions which don't use heap. * All LZ4F_* functions are not supported. * - See tests/freestanding.c to check its basic setup. */ #if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1) # define LZ4_HEAPMODE 0 # define LZ4HC_HEAPMODE 0 # define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1 # if !defined(LZ4_memcpy) # error "LZ4_FREESTANDING requires macro 'LZ4_memcpy'." # endif # if !defined(LZ4_memset) # error "LZ4_FREESTANDING requires macro 'LZ4_memset'." # endif # if !defined(LZ4_memmove) # error "LZ4_FREESTANDING requires macro 'LZ4_memmove'." # endif #elif ! defined(LZ4_FREESTANDING) # define LZ4_FREESTANDING 0 #endif /*------ Version ------*/ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */ #define LZ4_VERSION_RELEASE 4 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) #define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE #define LZ4_QUOTE(str) #str #define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) #define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) /* requires v1.7.3+ */ LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version; requires v1.3.0+ */ LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; useful to check dll version; requires v1.7.5+ */ /*-************************************ * Tuning parameter **************************************/ #define LZ4_MEMORY_USAGE_MIN 10 #define LZ4_MEMORY_USAGE_DEFAULT 14 #define LZ4_MEMORY_USAGE_MAX 20 /*! * LZ4_MEMORY_USAGE : * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; ) * Increasing memory usage improves compression ratio, at the cost of speed. * Reduced memory usage may improve speed at the cost of ratio, thanks to better cache locality. * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache */ #ifndef LZ4_MEMORY_USAGE # define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT #endif #if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN) # error "LZ4_MEMORY_USAGE is too small !" #endif #if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX) # error "LZ4_MEMORY_USAGE is too large !" #endif /*-************************************ * Simple Functions **************************************/ /*! LZ4_compress_default() : * Compresses 'srcSize' bytes from buffer 'src' * into already allocated 'dst' buffer of size 'dstCapacity'. * Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize). * It also runs faster, so it's a recommended setting. * If the function cannot compress 'src' into a more limited 'dst' budget, * compression stops *immediately*, and the function result is zero. * In which case, 'dst' content is undefined (invalid). * srcSize : max supported value is LZ4_MAX_INPUT_SIZE. * dstCapacity : size of buffer 'dst' (which must be already allocated) * @return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity) * or 0 if compression fails * Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer). */ LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity); /*! LZ4_decompress_safe() : * @compressedSize : is the exact complete size of the compressed block. * @dstCapacity : is the size of destination buffer (which must be already allocated), * is an upper bound of decompressed size. * @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity) * If destination buffer is not large enough, decoding will stop and output an error code (negative value). * If the source stream is detected malformed, the function will stop decoding and return a negative result. * Note 1 : This function is protected against malicious data packets : * it will never writes outside 'dst' buffer, nor read outside 'source' buffer, * even if the compressed block is maliciously modified to order the decoder to do these actions. * In such case, the decoder stops immediately, and considers the compressed block malformed. * Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them. * The implementation is free to send / store / derive this information in whichever way is most beneficial. * If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead. */ LZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity); /*-************************************ * Advanced Functions **************************************/ #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) /*! LZ4_compressBound() : Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) This function is primarily useful for memory allocation purposes (destination buffer size). Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize) inputSize : max supported value is LZ4_MAX_INPUT_SIZE return : maximum output size in a "worst case" scenario or 0, if input size is incorrect (too large or negative) */ LZ4LIB_API int LZ4_compressBound(int inputSize); /*! LZ4_compress_fast() : Same as LZ4_compress_default(), but allows selection of "acceleration" factor. The larger the acceleration value, the faster the algorithm, but also the lesser the compression. It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. An acceleration value of "1" is the same as regular LZ4_compress_default() Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c). Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c). */ LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); /*! LZ4_compress_fast_extState() : * Same as LZ4_compress_fast(), using an externally allocated memory space for its state. * Use LZ4_sizeofState() to know how much memory must be allocated, * and allocate it on 8-bytes boundaries (using `malloc()` typically). * Then, provide this buffer as `void* state` to compression function. */ LZ4LIB_API int LZ4_sizeofState(void); LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); /*! LZ4_compress_destSize() : * Reverse the logic : compresses as much data as possible from 'src' buffer * into already allocated buffer 'dst', of size >= 'targetDestSize'. * This function either compresses the entire 'src' content into 'dst' if it's large enough, * or fill 'dst' buffer completely with as much data as possible from 'src'. * note: acceleration parameter is fixed to "default". * * *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'. * New value is necessarily <= input value. * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize) * or 0 if compression fails. * * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed in v1.9.2+): * the produced compressed content could, in specific circumstances, * require to be decompressed into a destination buffer larger * by at least 1 byte than the content to decompress. * If an application uses `LZ4_compress_destSize()`, * it's highly recommended to update liblz4 to v1.9.2 or better. * If this can't be done or ensured, * the receiving decompression function should provide * a dstCapacity which is > decompressedSize, by at least 1 byte. * See https://github.com/lz4/lz4/issues/859 for details */ LZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize); /*! LZ4_decompress_safe_partial() : * Decompress an LZ4 compressed block, of size 'srcSize' at position 'src', * into destination buffer 'dst' of size 'dstCapacity'. * Up to 'targetOutputSize' bytes will be decoded. * The function stops decoding on reaching this objective. * This can be useful to boost performance * whenever only the beginning of a block is required. * * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize) * If source stream is detected malformed, function returns a negative result. * * Note 1 : @return can be < targetOutputSize, if compressed block contains less data. * * Note 2 : targetOutputSize must be <= dstCapacity * * Note 3 : this function effectively stops decoding on reaching targetOutputSize, * so dstCapacity is kind of redundant. * This is because in older versions of this function, * decoding operation would still write complete sequences. * Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize, * it could write more bytes, though only up to dstCapacity. * Some "margin" used to be required for this operation to work properly. * Thankfully, this is no longer necessary. * The function nonetheless keeps the same signature, in an effort to preserve API compatibility. * * Note 4 : If srcSize is the exact size of the block, * then targetOutputSize can be any value, * including larger than the block's decompressed size. * The function will, at most, generate block's decompressed size. * * Note 5 : If srcSize is _larger_ than block's compressed size, * then targetOutputSize **MUST** be <= block's decompressed size. * Otherwise, *silent corruption will occur*. */ LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity); /*-********************************************* * Streaming Compression Functions ***********************************************/ typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ /** Note about RC_INVOKED - RC_INVOKED is predefined symbol of rc.exe (the resource compiler which is part of MSVC/Visual Studio). https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros - Since rc.exe is a legacy compiler, it truncates long symbol (> 30 chars) and reports warning "RC4011: identifier truncated". - To eliminate the warning, we surround long preprocessor symbol with "#if !defined(RC_INVOKED) ... #endif" block that means "skip this block when rc.exe is trying to read it". */ #if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */ #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr); #endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ #endif /*! LZ4_resetStream_fast() : v1.9.0+ * Use this to prepare an LZ4_stream_t for a new chain of dependent blocks * (e.g., LZ4_compress_fast_continue()). * * An LZ4_stream_t must be initialized once before usage. * This is automatically done when created by LZ4_createStream(). * However, should the LZ4_stream_t be simply declared on stack (for example), * it's necessary to initialize it first, using LZ4_initStream(). * * After init, start any new stream with LZ4_resetStream_fast(). * A same LZ4_stream_t can be re-used multiple times consecutively * and compress multiple streams, * provided that it starts each new stream with LZ4_resetStream_fast(). * * LZ4_resetStream_fast() is much faster than LZ4_initStream(), * but is not compatible with memory regions containing garbage data. * * Note: it's only useful to call LZ4_resetStream_fast() * in the context of streaming compression. * The *extState* functions perform their own resets. * Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive. */ LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr); /*! LZ4_loadDict() : * Use this function to reference a static dictionary into LZ4_stream_t. * The dictionary must remain available during compression. * LZ4_loadDict() triggers a reset, so any previous data will be forgotten. * The same dictionary will have to be loaded on decompression side for successful decoding. * Dictionary are useful for better compression of small data (KB range). * While LZ4 accept any input as dictionary, * results are generally better when using Zstandard's Dictionary Builder. * Loading a size of 0 is allowed, and is the same as reset. * @return : loaded dictionary size, in bytes (necessarily <= 64 KB) */ LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); /*! LZ4_compress_fast_continue() : * Compress 'src' content using data from previously compressed blocks, for better compression ratio. * 'dst' buffer must be already allocated. * If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. * * @return : size of compressed block * or 0 if there is an error (typically, cannot fit into 'dst'). * * Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block. * Each block has precise boundaries. * Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata. * It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together. * * Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory ! * * Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB. * Make sure that buffers are separated, by at least one byte. * This construction ensures that each block only depends on previous block. * * Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB. * * Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed. */ LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); /*! LZ4_saveDict() : * If last 64KB data cannot be guaranteed to remain available at its current memory location, * save it into a safer place (char* safeBuffer). * This is schematically equivalent to a memcpy() followed by LZ4_loadDict(), * but is much faster, because LZ4_saveDict() doesn't need to rebuild tables. * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error. */ LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize); /*-********************************************** * Streaming Decompression Functions * Bufferless synchronous API ************************************************/ typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */ /*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() : * creation / destruction of streaming decompression tracking context. * A tracking context can be re-used multiple times. */ #if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */ #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); #endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ #endif /*! LZ4_setStreamDecode() : * An LZ4_streamDecode_t context can be allocated once and re-used multiple times. * Use this function to start decompression of a new stream of blocks. * A dictionary can optionally be set. Use NULL or size 0 for a reset order. * Dictionary is presumed stable : it must remain accessible and unmodified during next decompression. * @return : 1 if OK, 0 if error */ LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); /*! LZ4_decoderRingBufferSize() : v1.8.2+ * Note : in a ring buffer scenario (optional), * blocks are presumed decompressed next to each other * up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize), * at which stage it resumes from beginning of ring buffer. * When setting such a ring buffer for streaming decompression, * provides the minimum size of this ring buffer * to be compatible with any source respecting maxBlockSize condition. * @return : minimum ring buffer size, * or 0 if there is an error (invalid maxBlockSize). */ LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize); #define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */ /*! LZ4_decompress_safe_continue() : * This decoding function allows decompression of consecutive blocks in "streaming" mode. * The difference with the usual independent blocks is that * new blocks are allowed to find references into former blocks. * A block is an unsplittable entity, and must be presented entirely to the decompression function. * LZ4_decompress_safe_continue() only accepts one block at a time. * It's modeled after `LZ4_decompress_safe()` and behaves similarly. * * @LZ4_streamDecode : decompression state, tracking the position in memory of past data * @compressedSize : exact complete size of one compressed block. * @dstCapacity : size of destination buffer (which must be already allocated), * must be an upper bound of decompressed size. * @return : number of bytes decompressed into destination buffer (necessarily <= dstCapacity) * If destination buffer is not large enough, decoding will stop and output an error code (negative value). * If the source stream is detected malformed, the function will stop decoding and return a negative result. * * The last 64KB of previously decoded data *must* remain available and unmodified * at the memory position where they were previously decoded. * If less than 64KB of data has been decoded, all the data must be present. * * Special : if decompression side sets a ring buffer, it must respect one of the following conditions : * - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize). * maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes. * In which case, encoding and decoding buffers do not need to be synchronized. * Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize. * - Synchronized mode : * Decompression buffer size is _exactly_ the same as compression buffer size, * and follows exactly same update rule (block boundaries at same positions), * and decoding function is provided with exact decompressed size of each block (exception for last block of the stream), * _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB). * - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes. * In which case, encoding and decoding buffers do not need to be synchronized, * and encoding ring buffer can have any size, including small ones ( < 64 KB). * * Whenever these conditions are not possible, * save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression, * then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block. */ LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int srcSize, int dstCapacity); /*! LZ4_decompress_safe_usingDict() : * Works the same as * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_safe_continue() * However, it's stateless: it doesn't need any LZ4_streamDecode_t state. * Dictionary is presumed stable : it must remain accessible and unmodified during decompression. * Performance tip : Decompression speed can be substantially increased * when dst == dictStart + dictSize. */ LZ4LIB_API int LZ4_decompress_safe_usingDict(const char* src, char* dst, int srcSize, int dstCapacity, const char* dictStart, int dictSize); /*! LZ4_decompress_safe_partial_usingDict() : * Behaves the same as LZ4_decompress_safe_partial() * with the added ability to specify a memory segment for past data. * Performance tip : Decompression speed can be substantially increased * when dst == dictStart + dictSize. */ LZ4LIB_API int LZ4_decompress_safe_partial_usingDict(const char* src, char* dst, int compressedSize, int targetOutputSize, int maxOutputSize, const char* dictStart, int dictSize); #endif /* LZ4_H_2983827168210 */ /*^************************************* * !!!!!! STATIC LINKING ONLY !!!!!! ***************************************/ /*-**************************************************************************** * Experimental section * * Symbols declared in this section must be considered unstable. Their * signatures or semantics may change, or they may be removed altogether in the * future. They are therefore only safe to depend on when the caller is * statically linked against the library. * * To protect against unsafe usage, not only are the declarations guarded, * the definitions are hidden by default * when building LZ4 as a shared/dynamic library. * * In order to access these declarations, * define LZ4_STATIC_LINKING_ONLY in your application * before including LZ4's headers. * * In order to make their implementations accessible dynamically, you must * define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library. ******************************************************************************/ #ifdef LZ4_STATIC_LINKING_ONLY #ifndef LZ4_STATIC_3504398509 #define LZ4_STATIC_3504398509 #ifdef LZ4_PUBLISH_STATIC_FUNCTIONS #define LZ4LIB_STATIC_API LZ4LIB_API #else #define LZ4LIB_STATIC_API #endif /*! LZ4_compress_fast_extState_fastReset() : * A variant of LZ4_compress_fast_extState(). * * Using this variant avoids an expensive initialization step. * It is only safe to call if the state buffer is known to be correctly initialized already * (see above comment on LZ4_resetStream_fast() for a definition of "correctly initialized"). * From a high level, the difference is that * this function initializes the provided state with a call to something like LZ4_resetStream_fast() * while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream(). */ LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); /*! LZ4_attach_dictionary() : * This is an experimental API that allows * efficient use of a static dictionary many times. * * Rather than re-loading the dictionary buffer into a working context before * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a * working LZ4_stream_t, this function introduces a no-copy setup mechanism, * in which the working stream references the dictionary stream in-place. * * Several assumptions are made about the state of the dictionary stream. * Currently, only streams which have been prepared by LZ4_loadDict() should * be expected to work. * * Alternatively, the provided dictionaryStream may be NULL, * in which case any existing dictionary stream is unset. * * If a dictionary is provided, it replaces any pre-existing stream history. * The dictionary contents are the only history that can be referenced and * logically immediately precede the data compressed in the first subsequent * compression call. * * The dictionary will only remain attached to the working stream through the * first compression call, at the end of which it is cleared. The dictionary * stream (and source buffer) must remain in-place / accessible / unchanged * through the completion of the first compression call on the stream. */ LZ4LIB_STATIC_API void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream); /*! In-place compression and decompression * * It's possible to have input and output sharing the same buffer, * for highly constrained memory environments. * In both cases, it requires input to lay at the end of the buffer, * and decompression to start at beginning of the buffer. * Buffer size must feature some margin, hence be larger than final size. * * |<------------------------buffer--------------------------------->| * |<-----------compressed data--------->| * |<-----------decompressed size------------------>| * |<----margin---->| * * This technique is more useful for decompression, * since decompressed size is typically larger, * and margin is short. * * In-place decompression will work inside any buffer * which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize). * This presumes that decompressedSize > compressedSize. * Otherwise, it means compression actually expanded data, * and it would be more efficient to store such data with a flag indicating it's not compressed. * This can happen when data is not compressible (already compressed, or encrypted). * * For in-place compression, margin is larger, as it must be able to cope with both * history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX, * and data expansion, which can happen when input is not compressible. * As a consequence, buffer size requirements are much higher, * and memory savings offered by in-place compression are more limited. * * There are ways to limit this cost for compression : * - Reduce history size, by modifying LZ4_DISTANCE_MAX. * Note that it is a compile-time constant, so all compressions will apply this limit. * Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX, * so it's a reasonable trick when inputs are known to be small. * - Require the compressor to deliver a "maximum compressed size". * This is the `dstCapacity` parameter in `LZ4_compress*()`. * When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail, * in which case, the return code will be 0 (zero). * The caller must be ready for these cases to happen, * and typically design a backup scheme to send data uncompressed. * The combination of both techniques can significantly reduce * the amount of margin required for in-place compression. * * In-place compression can work in any buffer * which size is >= (maxCompressedSize) * with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success. * LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX, * so it's possible to reduce memory requirements by playing with them. */ #define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) (((compressedSize) >> 8) + 32) #define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize)) /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */ #ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at compile time */ # define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */ #endif #define LZ4_COMPRESS_INPLACE_MARGIN (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */ #define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */ #endif /* LZ4_STATIC_3504398509 */ #endif /* LZ4_STATIC_LINKING_ONLY */ #ifndef LZ4_H_98237428734687 #define LZ4_H_98237428734687 /*-************************************************************ * Private Definitions ************************************************************** * Do not use these definitions directly. * They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. * Accessing members will expose user code to API and/or ABI break in future versions of the library. **************************************************************/ #define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # include typedef int8_t LZ4_i8; typedef uint8_t LZ4_byte; typedef uint16_t LZ4_u16; typedef uint32_t LZ4_u32; #else typedef signed char LZ4_i8; typedef unsigned char LZ4_byte; typedef unsigned short LZ4_u16; typedef unsigned int LZ4_u32; #endif /*! LZ4_stream_t : * Never ever use below internal definitions directly ! * These definitions are not API/ABI safe, and may change in future versions. * If you need static allocation, declare or allocate an LZ4_stream_t object. **/ typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; struct LZ4_stream_t_internal { LZ4_u32 hashTable[LZ4_HASH_SIZE_U32]; const LZ4_byte* dictionary; const LZ4_stream_t_internal* dictCtx; LZ4_u32 currentOffset; LZ4_u32 tableType; LZ4_u32 dictSize; /* Implicit padding to ensure structure is aligned */ }; #define LZ4_STREAM_MINSIZE ((1UL << LZ4_MEMORY_USAGE) + 32) /* static size, for inter-version compatibility */ union LZ4_stream_u { char minStateSize[LZ4_STREAM_MINSIZE]; LZ4_stream_t_internal internal_donotuse; }; /* previously typedef'd to LZ4_stream_t */ /*! LZ4_initStream() : v1.9.0+ * An LZ4_stream_t structure must be initialized at least once. * This is automatically done when invoking LZ4_createStream(), * but it's not when the structure is simply declared on stack (for example). * * Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t. * It can also initialize any arbitrary buffer of sufficient size, * and will @return a pointer of proper type upon initialization. * * Note : initialization fails if size and alignment conditions are not respected. * In which case, the function will @return NULL. * Note2: An LZ4_stream_t structure guarantees correct alignment and size. * Note3: Before v1.9.0, use LZ4_resetStream() instead **/ LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size); /*! LZ4_streamDecode_t : * Never ever use below internal definitions directly ! * These definitions are not API/ABI safe, and may change in future versions. * If you need static allocation, declare or allocate an LZ4_streamDecode_t object. **/ typedef struct { const LZ4_byte* externalDict; const LZ4_byte* prefixEnd; size_t extDictSize; size_t prefixSize; } LZ4_streamDecode_t_internal; #define LZ4_STREAMDECODE_MINSIZE 32 union LZ4_streamDecode_u { char minStateSize[LZ4_STREAMDECODE_MINSIZE]; LZ4_streamDecode_t_internal internal_donotuse; } ; /* previously typedef'd to LZ4_streamDecode_t */ /*-************************************ * Obsolete Functions **************************************/ /*! Deprecation warnings * * Deprecated functions make the compiler generate a warning when invoked. * This is meant to invite users to update their source code. * Should deprecation warnings be a problem, it is generally possible to disable them, * typically with -Wno-deprecated-declarations for gcc * or _CRT_SECURE_NO_WARNINGS in Visual. * * Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS * before including the header file. */ #ifdef LZ4_DISABLE_DEPRECATE_WARNINGS # define LZ4_DEPRECATED(message) /* disable deprecation warnings */ #else # if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ # define LZ4_DEPRECATED(message) [[deprecated(message)]] # elif defined(_MSC_VER) # define LZ4_DEPRECATED(message) __declspec(deprecated(message)) # elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45)) # define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) # elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31) # define LZ4_DEPRECATED(message) __attribute__((deprecated)) # else # pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler") # define LZ4_DEPRECATED(message) /* disabled */ # endif #endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ /*! Obsolete compression functions (since v1.7.3) */ LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* src, char* dest, int srcSize); LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize); LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); /*! Obsolete decompression functions (since v1.8.0) */ LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize); LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); /* Obsolete streaming functions (since v1.7.0) * degraded functionality; do not use! * * In order to perform streaming compression, these functions depended on data * that is no longer tracked in the state. They have been preserved as well as * possible: using them will still produce a correct output. However, they don't * actually retain any history between compression calls. The compression ratio * achieved will therefore be no better than compressing each chunk * independently. */ LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer); LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void); LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer); LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state); /*! Obsolete streaming decoding functions (since v1.7.0) */ LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); /*! Obsolete LZ4_decompress_fast variants (since v1.9.0) : * These functions used to be faster than LZ4_decompress_safe(), * but this is no longer the case. They are now slower. * This is because LZ4_decompress_fast() doesn't know the input size, * and therefore must progress more cautiously into the input buffer to not read beyond the end of block. * On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability. * As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated. * * The last remaining LZ4_decompress_fast() specificity is that * it can decompress a block without knowing its compressed size. * Such functionality can be achieved in a more secure manner * by employing LZ4_decompress_safe_partial(). * * Parameters: * originalSize : is the uncompressed size to regenerate. * `dst` must be already allocated, its size must be >= 'originalSize' bytes. * @return : number of bytes read from source buffer (== compressed size). * The function expects to finish at block's end exactly. * If the source stream is detected malformed, the function stops decoding and returns a negative result. * note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer. * However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds. * Also, since match offsets are not validated, match reads from 'src' may underflow too. * These issues never happen if input (compressed) data is correct. * But they may happen if input data is invalid (error or intentional tampering). * As a consequence, use these functions in trusted environments with trusted data **only**. */ LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize); LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead") LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize); LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize); /*! LZ4_resetStream() : * An LZ4_stream_t structure must be initialized at least once. * This is done with LZ4_initStream(), or LZ4_resetStream(). * Consider switching to LZ4_initStream(), * invoking LZ4_resetStream() will trigger deprecation warnings in the future. */ LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); #endif /* LZ4_H_98237428734687 */ #if defined (__cplusplus) } #endif ================================================ FILE: lib/LZ4F/lz4file.c ================================================ /* * LZ4 file library * Copyright (C) 2022, Xiaomi Inc. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at : * - LZ4 homepage : http://www.lz4.org * - LZ4 source repository : https://github.com/lz4/lz4 */ #include #include #include "lz4.h" #include "lz4file.h" struct LZ4_readFile_s { LZ4F_dctx* dctxPtr; FILE* fp; LZ4_byte* srcBuf; size_t srcBufNext; size_t srcBufSize; size_t srcBufMaxSize; }; struct LZ4_writeFile_s { LZ4F_cctx* cctxPtr; FILE* fp; LZ4_byte* dstBuf; size_t maxWriteSize; size_t dstBufMaxSize; LZ4F_errorCode_t errCode; }; LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp) { char buf[LZ4F_HEADER_SIZE_MAX]; size_t consumedSize; LZ4F_errorCode_t ret; LZ4F_frameInfo_t info; if (fp == NULL || lz4fRead == NULL) { return -LZ4F_ERROR_GENERIC; } *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t)); if (*lz4fRead == NULL) { return -LZ4F_ERROR_allocation_failed; } ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_getVersion()); if (LZ4F_isError(ret)) { free(*lz4fRead); return ret; } (*lz4fRead)->fp = fp; consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp); if (consumedSize != sizeof(buf)) { LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); free(*lz4fRead); return -LZ4F_ERROR_GENERIC; } ret = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize); if (LZ4F_isError(ret)) { LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); free(*lz4fRead); return ret; } switch (info.blockSizeID) { case LZ4F_default : case LZ4F_max64KB : (*lz4fRead)->srcBufMaxSize = 64 * 1024; break; case LZ4F_max256KB: (*lz4fRead)->srcBufMaxSize = 256 * 1024; break; case LZ4F_max1MB: (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024; break; case LZ4F_max4MB: (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024; break; default: LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); free(*lz4fRead); return -LZ4F_ERROR_maxBlockSize_invalid; } (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize); if ((*lz4fRead)->srcBuf == NULL) { LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); free(lz4fRead); return -LZ4F_ERROR_allocation_failed; } (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize; memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize); return ret; } size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size) { LZ4_byte* p = (LZ4_byte*)buf; size_t next = 0; if (lz4fRead == NULL || buf == NULL) return -LZ4F_ERROR_GENERIC; while (next < size) { size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext; size_t dstsize = size - next; size_t ret; if (srcsize == 0) { ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp); if (ret > 0) { lz4fRead->srcBufSize = ret; srcsize = lz4fRead->srcBufSize; lz4fRead->srcBufNext = 0; } else if (ret == 0) { break; } else { return -LZ4F_ERROR_GENERIC; } } ret = LZ4F_decompress(lz4fRead->dctxPtr, p, &dstsize, lz4fRead->srcBuf + lz4fRead->srcBufNext, &srcsize, NULL); if (LZ4F_isError(ret)) { return ret; } lz4fRead->srcBufNext += srcsize; next += dstsize; p += dstsize; } return next; } LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead) { if (lz4fRead == NULL) return -LZ4F_ERROR_GENERIC; LZ4F_freeDecompressionContext(lz4fRead->dctxPtr); free(lz4fRead->srcBuf); free(lz4fRead); return LZ4F_OK_NoError; } LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr) { LZ4_byte buf[LZ4F_HEADER_SIZE_MAX]; size_t ret; if (fp == NULL || lz4fWrite == NULL) return -LZ4F_ERROR_GENERIC; *lz4fWrite = (LZ4_writeFile_t*)malloc(sizeof(LZ4_writeFile_t)); if (*lz4fWrite == NULL) { return -LZ4F_ERROR_allocation_failed; } if (prefsPtr != NULL) { switch (prefsPtr->frameInfo.blockSizeID) { case LZ4F_default : case LZ4F_max64KB : (*lz4fWrite)->maxWriteSize = 64 * 1024; break; case LZ4F_max256KB: (*lz4fWrite)->maxWriteSize = 256 * 1024; break; case LZ4F_max1MB: (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024; break; case LZ4F_max4MB: (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024; break; default: free(lz4fWrite); return -LZ4F_ERROR_maxBlockSize_invalid; } } else { (*lz4fWrite)->maxWriteSize = 64 * 1024; } (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr); (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize); if ((*lz4fWrite)->dstBuf == NULL) { free(*lz4fWrite); return -LZ4F_ERROR_allocation_failed; } ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_getVersion()); if (LZ4F_isError(ret)) { free((*lz4fWrite)->dstBuf); free(*lz4fWrite); return ret; } ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr); if (LZ4F_isError(ret)) { LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr); free((*lz4fWrite)->dstBuf); free(*lz4fWrite); return ret; } if (ret != fwrite(buf, 1, ret, fp)) { LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr); free((*lz4fWrite)->dstBuf); free(*lz4fWrite); return -LZ4F_ERROR_GENERIC; } (*lz4fWrite)->fp = fp; (*lz4fWrite)->errCode = LZ4F_OK_NoError; return LZ4F_OK_NoError; } size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, const void* buf, size_t size) { const LZ4_byte* p = (const LZ4_byte*)buf; size_t remain = size; size_t chunk; size_t ret; if (lz4fWrite == NULL || buf == NULL) return -LZ4F_ERROR_GENERIC; while (remain) { if (remain > lz4fWrite->maxWriteSize) chunk = lz4fWrite->maxWriteSize; else chunk = remain; ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr, lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize, p, chunk, NULL); if (LZ4F_isError(ret)) { lz4fWrite->errCode = ret; return ret; } if(ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) { lz4fWrite->errCode = -LZ4F_ERROR_GENERIC; return -LZ4F_ERROR_GENERIC; } p += chunk; remain -= chunk; } return size; } LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite) { LZ4F_errorCode_t ret = LZ4F_OK_NoError; if (lz4fWrite == NULL) return -LZ4F_ERROR_GENERIC; if (lz4fWrite->errCode == LZ4F_OK_NoError) { ret = LZ4F_compressEnd(lz4fWrite->cctxPtr, lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize, NULL); if (LZ4F_isError(ret)) { goto out; } if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) { ret = -LZ4F_ERROR_GENERIC; } } out: LZ4F_freeCompressionContext(lz4fWrite->cctxPtr); free(lz4fWrite->dstBuf); free(lz4fWrite); return ret; } ================================================ FILE: lib/LZ4F/lz4file.h ================================================ /* LZ4 file library Header File Copyright (C) 2022, Xiaomi Inc. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 source repository : https://github.com/lz4/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ #if defined (__cplusplus) extern "C" { #endif #ifndef LZ4FILE_H #define LZ4FILE_H #include #include "lz4frame_static.h" typedef struct LZ4_readFile_s LZ4_readFile_t; typedef struct LZ4_writeFile_s LZ4_writeFile_t; /*! LZ4F_readOpen() : * Set read lz4file handle. * `lz4f` will set a lz4file handle. * `fp` must be the return value of the lz4 file opened by fopen. */ LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp); /*! LZ4F_read() : * Read lz4file content to buffer. * `lz4f` must use LZ4_readOpen to set first. * `buf` read data buffer. * `size` read data buffer size. */ LZ4FLIB_STATIC_API size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size); /*! LZ4F_readClose() : * Close lz4file handle. * `lz4f` must use LZ4_readOpen to set first. */ LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead); /*! LZ4F_writeOpen() : * Set write lz4file handle. * `lz4f` will set a lz4file handle. * `fp` must be the return value of the lz4 file opened by fopen. */ LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr); /*! LZ4F_write() : * Write buffer to lz4file. * `lz4f` must use LZ4F_writeOpen to set first. * `buf` write data buffer. * `size` write data buffer size. */ LZ4FLIB_STATIC_API size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, const void* buf, size_t size); /*! LZ4F_writeClose() : * Close lz4file handle. * `lz4f` must use LZ4F_writeOpen to set first. */ LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite); #endif /* LZ4FILE_H */ #if defined (__cplusplus) } #endif ================================================ FILE: lib/LZ4F/lz4frame.c ================================================ /* * LZ4 auto-framing library * Copyright (C) 2011-2016, Yann Collet. * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at : * - LZ4 homepage : http://www.lz4.org * - LZ4 source repository : https://github.com/lz4/lz4 */ /* LZ4F is a stand-alone API to create LZ4-compressed Frames * in full conformance with specification v1.6.1 . * This library rely upon memory management capabilities (malloc, free) * provided either by , * or redirected towards another library of user's choice * (see Memory Routines below). */ /*-************************************ * Compiler Options **************************************/ #ifdef _MSC_VER /* Visual Studio */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #endif /*-************************************ * Tuning parameters **************************************/ /* * LZ4F_HEAPMODE : * Control how LZ4F_compressFrame allocates the Compression State, * either on stack (0:default, fastest), or in memory heap (1:requires malloc()). */ #ifndef LZ4F_HEAPMODE # define LZ4F_HEAPMODE 0 #endif /*-************************************ * Library declarations **************************************/ #define LZ4F_STATIC_LINKING_ONLY #include "lz4frame.h" #define LZ4_STATIC_LINKING_ONLY #include "lz4.h" #define LZ4_HC_STATIC_LINKING_ONLY #include "lz4hc.h" #define XXH_STATIC_LINKING_ONLY #include "xxhash.h" /*-************************************ * Memory routines **************************************/ /* * User may redirect invocations of * malloc(), calloc() and free() * towards another library or solution of their choice * by modifying below section. **/ #include /* memset, memcpy, memmove */ #ifndef LZ4_SRC_INCLUDED /* avoid redefinition when sources are coalesced */ # define MEM_INIT(p,v,s) memset((p),(v),(s)) #endif #ifndef LZ4_SRC_INCLUDED /* avoid redefinition when sources are coalesced */ # include /* malloc, calloc, free */ # define ALLOC(s) malloc(s) # define ALLOC_AND_ZERO(s) calloc(1,(s)) # define FREEMEM(p) free(p) #endif static void* LZ4F_calloc(size_t s, LZ4F_CustomMem cmem) { /* custom calloc defined : use it */ if (cmem.customCalloc != NULL) { return cmem.customCalloc(cmem.opaqueState, s); } /* nothing defined : use default 's calloc() */ if (cmem.customAlloc == NULL) { return ALLOC_AND_ZERO(s); } /* only custom alloc defined : use it, and combine it with memset() */ { void* const p = cmem.customAlloc(cmem.opaqueState, s); if (p != NULL) MEM_INIT(p, 0, s); return p; } } static void* LZ4F_malloc(size_t s, LZ4F_CustomMem cmem) { /* custom malloc defined : use it */ if (cmem.customAlloc != NULL) { return cmem.customAlloc(cmem.opaqueState, s); } /* nothing defined : use default 's malloc() */ return ALLOC(s); } static void LZ4F_free(void* p, LZ4F_CustomMem cmem) { /* custom malloc defined : use it */ if (cmem.customFree != NULL) { cmem.customFree(cmem.opaqueState, p); return; } /* nothing defined : use default 's free() */ FREEMEM(p); } /*-************************************ * Debug **************************************/ #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1) # include #else # ifndef assert # define assert(condition) ((void)0) # endif #endif #define LZ4F_STATIC_ASSERT(c) { enum { LZ4F_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */ #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) && !defined(DEBUGLOG) # include static int g_debuglog_enable = 1; # define DEBUGLOG(l, ...) { \ if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ fprintf(stderr, __FILE__ ": "); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, " \n"); \ } } #else # define DEBUGLOG(l, ...) {} /* disabled */ #endif /*-************************************ * Basic Types **************************************/ #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; #else typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; typedef signed int S32; typedef unsigned long long U64; #endif /* unoptimized version; solves endianness & alignment issues */ static U32 LZ4F_readLE32 (const void* src) { const BYTE* const srcPtr = (const BYTE*)src; U32 value32 = srcPtr[0]; value32 += ((U32)srcPtr[1])<< 8; value32 += ((U32)srcPtr[2])<<16; value32 += ((U32)srcPtr[3])<<24; return value32; } static void LZ4F_writeLE32 (void* dst, U32 value32) { BYTE* const dstPtr = (BYTE*)dst; dstPtr[0] = (BYTE)value32; dstPtr[1] = (BYTE)(value32 >> 8); dstPtr[2] = (BYTE)(value32 >> 16); dstPtr[3] = (BYTE)(value32 >> 24); } static U64 LZ4F_readLE64 (const void* src) { const BYTE* const srcPtr = (const BYTE*)src; U64 value64 = srcPtr[0]; value64 += ((U64)srcPtr[1]<<8); value64 += ((U64)srcPtr[2]<<16); value64 += ((U64)srcPtr[3]<<24); value64 += ((U64)srcPtr[4]<<32); value64 += ((U64)srcPtr[5]<<40); value64 += ((U64)srcPtr[6]<<48); value64 += ((U64)srcPtr[7]<<56); return value64; } static void LZ4F_writeLE64 (void* dst, U64 value64) { BYTE* const dstPtr = (BYTE*)dst; dstPtr[0] = (BYTE)value64; dstPtr[1] = (BYTE)(value64 >> 8); dstPtr[2] = (BYTE)(value64 >> 16); dstPtr[3] = (BYTE)(value64 >> 24); dstPtr[4] = (BYTE)(value64 >> 32); dstPtr[5] = (BYTE)(value64 >> 40); dstPtr[6] = (BYTE)(value64 >> 48); dstPtr[7] = (BYTE)(value64 >> 56); } /*-************************************ * Constants **************************************/ #ifndef LZ4_SRC_INCLUDED /* avoid double definition */ # define KB *(1<<10) # define MB *(1<<20) # define GB *(1<<30) #endif #define _1BIT 0x01 #define _2BITS 0x03 #define _3BITS 0x07 #define _4BITS 0x0F #define _8BITS 0xFF #define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U #define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB static const size_t minFHSize = LZ4F_HEADER_SIZE_MIN; /* 7 */ static const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX; /* 19 */ static const size_t BHSize = LZ4F_BLOCK_HEADER_SIZE; /* block header : size, and compress flag */ static const size_t BFSize = LZ4F_BLOCK_CHECKSUM_SIZE; /* block footer : checksum (optional) */ /*-************************************ * Structures and local types **************************************/ typedef enum { LZ4B_COMPRESSED, LZ4B_UNCOMPRESSED} LZ4F_blockCompression_t; typedef struct LZ4F_cctx_s { LZ4F_CustomMem cmem; LZ4F_preferences_t prefs; U32 version; U32 cStage; /* 0 : compression uninitialized ; 1 : initialized, can compress */ const LZ4F_CDict* cdict; size_t maxBlockSize; size_t maxBufferSize; BYTE* tmpBuff; /* internal buffer, for streaming */ BYTE* tmpIn; /* starting position of data compress within internal buffer (>= tmpBuff) */ size_t tmpInSize; /* amount of data to compress after tmpIn */ U64 totalInSize; XXH32_state_t xxh; void* lz4CtxPtr; U16 lz4CtxAlloc; /* sized for: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */ U16 lz4CtxState; /* in use as: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */ LZ4F_blockCompression_t blockCompression; } LZ4F_cctx_t; /*-************************************ * Error management **************************************/ #define LZ4F_GENERATE_STRING(STRING) #STRING, static const char* LZ4F_errorStrings[] = { LZ4F_LIST_ERRORS(LZ4F_GENERATE_STRING) }; unsigned LZ4F_isError(LZ4F_errorCode_t code) { return (code > (LZ4F_errorCode_t)(-LZ4F_ERROR_maxCode)); } const char* LZ4F_getErrorName(LZ4F_errorCode_t code) { static const char* codeError = "Unspecified error code"; if (LZ4F_isError(code)) return LZ4F_errorStrings[-(int)(code)]; return codeError; } LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult) { if (!LZ4F_isError(functionResult)) return LZ4F_OK_NoError; return (LZ4F_errorCodes)(-(ptrdiff_t)functionResult); } static LZ4F_errorCode_t LZ4F_returnErrorCode(LZ4F_errorCodes code) { /* A compilation error here means sizeof(ptrdiff_t) is not large enough */ LZ4F_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t)); return (LZ4F_errorCode_t)-(ptrdiff_t)code; } #define RETURN_ERROR(e) return LZ4F_returnErrorCode(LZ4F_ERROR_ ## e) #define RETURN_ERROR_IF(c,e) do { if (c) RETURN_ERROR(e); } while (0) #define FORWARD_IF_ERROR(r) do { if (LZ4F_isError(r)) return (r); } while (0) unsigned LZ4F_getVersion(void) { return LZ4F_VERSION; } int LZ4F_compressionLevel_max(void) { return LZ4HC_CLEVEL_MAX; } size_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID) { static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB }; if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT; if (blockSizeID < LZ4F_max64KB || blockSizeID > LZ4F_max4MB) RETURN_ERROR(maxBlockSize_invalid); { int const blockSizeIdx = (int)blockSizeID - (int)LZ4F_max64KB; return blockSizes[blockSizeIdx]; } } /*-************************************ * Private functions **************************************/ #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) static BYTE LZ4F_headerChecksum (const void* header, size_t length) { U32 const xxh = XXH32(header, length, 0); return (BYTE)(xxh >> 8); } /*-************************************ * Simple-pass compression functions **************************************/ static LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSID, const size_t srcSize) { LZ4F_blockSizeID_t proposedBSID = LZ4F_max64KB; size_t maxBlockSize = 64 KB; while (requestedBSID > proposedBSID) { if (srcSize <= maxBlockSize) return proposedBSID; proposedBSID = (LZ4F_blockSizeID_t)((int)proposedBSID + 1); maxBlockSize <<= 2; } return requestedBSID; } /*! LZ4F_compressBound_internal() : * Provides dstCapacity given a srcSize to guarantee operation success in worst case situations. * prefsPtr is optional : if NULL is provided, preferences will be set to cover worst case scenario. * @return is always the same for a srcSize and prefsPtr, so it can be relied upon to size reusable buffers. * When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() operations. */ static size_t LZ4F_compressBound_internal(size_t srcSize, const LZ4F_preferences_t* preferencesPtr, size_t alreadyBuffered) { LZ4F_preferences_t prefsNull = LZ4F_INIT_PREFERENCES; prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled; /* worst case */ prefsNull.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled; /* worst case */ { const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr; U32 const flush = prefsPtr->autoFlush | (srcSize==0); LZ4F_blockSizeID_t const blockID = prefsPtr->frameInfo.blockSizeID; size_t const blockSize = LZ4F_getBlockSize(blockID); size_t const maxBuffered = blockSize - 1; size_t const bufferedSize = MIN(alreadyBuffered, maxBuffered); size_t const maxSrcSize = srcSize + bufferedSize; unsigned const nbFullBlocks = (unsigned)(maxSrcSize / blockSize); size_t const partialBlockSize = maxSrcSize & (blockSize-1); size_t const lastBlockSize = flush ? partialBlockSize : 0; unsigned const nbBlocks = nbFullBlocks + (lastBlockSize>0); size_t const blockCRCSize = BFSize * prefsPtr->frameInfo.blockChecksumFlag; size_t const frameEnd = BHSize + (prefsPtr->frameInfo.contentChecksumFlag*BFSize); return ((BHSize + blockCRCSize) * nbBlocks) + (blockSize * nbFullBlocks) + lastBlockSize + frameEnd; } } size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr) { LZ4F_preferences_t prefs; size_t const headerSize = maxFHSize; /* max header size, including optional fields */ if (preferencesPtr!=NULL) prefs = *preferencesPtr; else MEM_INIT(&prefs, 0, sizeof(prefs)); prefs.autoFlush = 1; return headerSize + LZ4F_compressBound_internal(srcSize, &prefs, 0);; } /*! LZ4F_compressFrame_usingCDict() : * Compress srcBuffer using a dictionary, in a single step. * cdict can be NULL, in which case, no dictionary is used. * dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr). * The LZ4F_preferences_t structure is optional : you may provide NULL as argument, * however, it's the only way to provide a dictID, so it's not recommended. * @return : number of bytes written into dstBuffer, * or an error code if it fails (can be tested using LZ4F_isError()) */ size_t LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_CDict* cdict, const LZ4F_preferences_t* preferencesPtr) { LZ4F_preferences_t prefs; LZ4F_compressOptions_t options; BYTE* const dstStart = (BYTE*) dstBuffer; BYTE* dstPtr = dstStart; BYTE* const dstEnd = dstStart + dstCapacity; if (preferencesPtr!=NULL) prefs = *preferencesPtr; else MEM_INIT(&prefs, 0, sizeof(prefs)); if (prefs.frameInfo.contentSize != 0) prefs.frameInfo.contentSize = (U64)srcSize; /* auto-correct content size if selected (!=0) */ prefs.frameInfo.blockSizeID = LZ4F_optimalBSID(prefs.frameInfo.blockSizeID, srcSize); prefs.autoFlush = 1; if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID)) prefs.frameInfo.blockMode = LZ4F_blockIndependent; /* only one block => no need for inter-block link */ MEM_INIT(&options, 0, sizeof(options)); options.stableSrc = 1; RETURN_ERROR_IF(dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs), dstMaxSize_tooSmall); { size_t const headerSize = LZ4F_compressBegin_usingCDict(cctx, dstBuffer, dstCapacity, cdict, &prefs); /* write header */ FORWARD_IF_ERROR(headerSize); dstPtr += headerSize; /* header size */ } assert(dstEnd >= dstPtr); { size_t const cSize = LZ4F_compressUpdate(cctx, dstPtr, (size_t)(dstEnd-dstPtr), srcBuffer, srcSize, &options); FORWARD_IF_ERROR(cSize); dstPtr += cSize; } assert(dstEnd >= dstPtr); { size_t const tailSize = LZ4F_compressEnd(cctx, dstPtr, (size_t)(dstEnd-dstPtr), &options); /* flush last block, and generate suffix */ FORWARD_IF_ERROR(tailSize); dstPtr += tailSize; } assert(dstEnd >= dstStart); return (size_t)(dstPtr - dstStart); } /*! LZ4F_compressFrame() : * Compress an entire srcBuffer into a valid LZ4 frame, in a single step. * dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr). * The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default. * @return : number of bytes written into dstBuffer. * or an error code if it fails (can be tested using LZ4F_isError()) */ size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr) { size_t result; #if (LZ4F_HEAPMODE) LZ4F_cctx_t* cctxPtr; result = LZ4F_createCompressionContext(&cctxPtr, LZ4F_VERSION); FORWARD_IF_ERROR(result); #else LZ4F_cctx_t cctx; LZ4_stream_t lz4ctx; LZ4F_cctx_t* const cctxPtr = &cctx; MEM_INIT(&cctx, 0, sizeof(cctx)); cctx.version = LZ4F_VERSION; cctx.maxBufferSize = 5 MB; /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */ if ( preferencesPtr == NULL || preferencesPtr->compressionLevel < LZ4HC_CLEVEL_MIN ) { LZ4_initStream(&lz4ctx, sizeof(lz4ctx)); cctxPtr->lz4CtxPtr = &lz4ctx; cctxPtr->lz4CtxAlloc = 1; cctxPtr->lz4CtxState = 1; } #endif DEBUGLOG(4, "LZ4F_compressFrame"); result = LZ4F_compressFrame_usingCDict(cctxPtr, dstBuffer, dstCapacity, srcBuffer, srcSize, NULL, preferencesPtr); #if (LZ4F_HEAPMODE) LZ4F_freeCompressionContext(cctxPtr); #else if ( preferencesPtr != NULL && preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN ) { LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem); } #endif return result; } /*-*************************************************** * Dictionary compression *****************************************************/ struct LZ4F_CDict_s { LZ4F_CustomMem cmem; void* dictContent; LZ4_stream_t* fastCtx; LZ4_streamHC_t* HCCtx; }; /* typedef'd to LZ4F_CDict within lz4frame_static.h */ LZ4F_CDict* LZ4F_createCDict_advanced(LZ4F_CustomMem cmem, const void* dictBuffer, size_t dictSize) { const char* dictStart = (const char*)dictBuffer; LZ4F_CDict* const cdict = (LZ4F_CDict*)LZ4F_malloc(sizeof(*cdict), cmem); DEBUGLOG(4, "LZ4F_createCDict_advanced"); if (!cdict) return NULL; cdict->cmem = cmem; if (dictSize > 64 KB) { dictStart += dictSize - 64 KB; dictSize = 64 KB; } cdict->dictContent = LZ4F_malloc(dictSize, cmem); cdict->fastCtx = (LZ4_stream_t*)LZ4F_malloc(sizeof(LZ4_stream_t), cmem); if (cdict->fastCtx) LZ4_initStream(cdict->fastCtx, sizeof(LZ4_stream_t)); cdict->HCCtx = (LZ4_streamHC_t*)LZ4F_malloc(sizeof(LZ4_streamHC_t), cmem); if (cdict->HCCtx) LZ4_initStream(cdict->HCCtx, sizeof(LZ4_streamHC_t)); if (!cdict->dictContent || !cdict->fastCtx || !cdict->HCCtx) { LZ4F_freeCDict(cdict); return NULL; } memcpy(cdict->dictContent, dictStart, dictSize); LZ4_loadDict (cdict->fastCtx, (const char*)cdict->dictContent, (int)dictSize); LZ4_setCompressionLevel(cdict->HCCtx, LZ4HC_CLEVEL_DEFAULT); LZ4_loadDictHC(cdict->HCCtx, (const char*)cdict->dictContent, (int)dictSize); return cdict; } /*! LZ4F_createCDict() : * When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once. * LZ4F_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay. * LZ4F_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. * @dictBuffer can be released after LZ4F_CDict creation, since its content is copied within CDict * @return : digested dictionary for compression, or NULL if failed */ LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize) { DEBUGLOG(4, "LZ4F_createCDict"); return LZ4F_createCDict_advanced(LZ4F_defaultCMem, dictBuffer, dictSize); } void LZ4F_freeCDict(LZ4F_CDict* cdict) { if (cdict==NULL) return; /* support free on NULL */ LZ4F_free(cdict->dictContent, cdict->cmem); LZ4F_free(cdict->fastCtx, cdict->cmem); LZ4F_free(cdict->HCCtx, cdict->cmem); LZ4F_free(cdict, cdict->cmem); } /*-********************************* * Advanced compression functions ***********************************/ LZ4F_cctx* LZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version) { LZ4F_cctx* const cctxPtr = (LZ4F_cctx*)LZ4F_calloc(sizeof(LZ4F_cctx), customMem); if (cctxPtr==NULL) return NULL; cctxPtr->cmem = customMem; cctxPtr->version = version; cctxPtr->cStage = 0; /* Uninitialized. Next stage : init cctx */ return cctxPtr; } /*! LZ4F_createCompressionContext() : * The first thing to do is to create a compressionContext object, which will be used in all compression operations. * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure. * The version provided MUST be LZ4F_VERSION. It is intended to track potential incompatible differences between different binaries. * The function will provide a pointer to an allocated LZ4F_compressionContext_t object. * If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation. * Object can release its memory using LZ4F_freeCompressionContext(); **/ LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** LZ4F_compressionContextPtr, unsigned version) { assert(LZ4F_compressionContextPtr != NULL); /* considered a violation of narrow contract */ /* in case it nonetheless happen in production */ RETURN_ERROR_IF(LZ4F_compressionContextPtr == NULL, parameter_null); *LZ4F_compressionContextPtr = LZ4F_createCompressionContext_advanced(LZ4F_defaultCMem, version); RETURN_ERROR_IF(*LZ4F_compressionContextPtr==NULL, allocation_failed); return LZ4F_OK_NoError; } LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctxPtr) { if (cctxPtr != NULL) { /* support free on NULL */ LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem); /* note: LZ4_streamHC_t and LZ4_stream_t are simple POD types */ LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem); LZ4F_free(cctxPtr, cctxPtr->cmem); } return LZ4F_OK_NoError; } /** * This function prepares the internal LZ4(HC) stream for a new compression, * resetting the context and attaching the dictionary, if there is one. * * It needs to be called at the beginning of each independent compression * stream (i.e., at the beginning of a frame in blockLinked mode, or at the * beginning of each block in blockIndependent mode). */ static void LZ4F_initStream(void* ctx, const LZ4F_CDict* cdict, int level, LZ4F_blockMode_t blockMode) { if (level < LZ4HC_CLEVEL_MIN) { if (cdict != NULL || blockMode == LZ4F_blockLinked) { /* In these cases, we will call LZ4_compress_fast_continue(), * which needs an already reset context. Otherwise, we'll call a * one-shot API. The non-continued APIs internally perform their own * resets at the beginning of their calls, where they know what * tableType they need the context to be in. So in that case this * would be misguided / wasted work. */ LZ4_resetStream_fast((LZ4_stream_t*)ctx); } LZ4_attach_dictionary((LZ4_stream_t *)ctx, cdict ? cdict->fastCtx : NULL); } else { LZ4_resetStreamHC_fast((LZ4_streamHC_t*)ctx, level); LZ4_attach_HC_dictionary((LZ4_streamHC_t *)ctx, cdict ? cdict->HCCtx : NULL); } } static int ctxTypeID_to_size(int ctxTypeID) { switch(ctxTypeID) { case 1: return LZ4_sizeofState(); case 2: return LZ4_sizeofStateHC(); default: return 0; } } /*! LZ4F_compressBegin_usingCDict() : * init streaming compression AND writes frame header into @dstBuffer. * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes. * @return : number of bytes written into @dstBuffer for the header * or an error code (can be tested using LZ4F_isError()) */ size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_CDict* cdict, const LZ4F_preferences_t* preferencesPtr) { LZ4F_preferences_t const prefNull = LZ4F_INIT_PREFERENCES; BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; RETURN_ERROR_IF(dstCapacity < maxFHSize, dstMaxSize_tooSmall); if (preferencesPtr == NULL) preferencesPtr = &prefNull; cctxPtr->prefs = *preferencesPtr; /* cctx Management */ { U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2; int requiredSize = ctxTypeID_to_size(ctxTypeID); int allocatedSize = ctxTypeID_to_size(cctxPtr->lz4CtxAlloc); if (allocatedSize < requiredSize) { /* not enough space allocated */ LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem); if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) { /* must take ownership of memory allocation, * in order to respect custom allocator contract */ cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_stream_t), cctxPtr->cmem); if (cctxPtr->lz4CtxPtr) LZ4_initStream(cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t)); } else { cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_streamHC_t), cctxPtr->cmem); if (cctxPtr->lz4CtxPtr) LZ4_initStreamHC(cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t)); } RETURN_ERROR_IF(cctxPtr->lz4CtxPtr == NULL, allocation_failed); cctxPtr->lz4CtxAlloc = ctxTypeID; cctxPtr->lz4CtxState = ctxTypeID; } else if (cctxPtr->lz4CtxState != ctxTypeID) { /* otherwise, a sufficient buffer is already allocated, * but we need to reset it to the correct context type */ if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) { LZ4_initStream((LZ4_stream_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t)); } else { LZ4_initStreamHC((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t)); LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel); } cctxPtr->lz4CtxState = ctxTypeID; } } /* Buffer Management */ if (cctxPtr->prefs.frameInfo.blockSizeID == 0) cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT; cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID); { size_t const requiredBuffSize = preferencesPtr->autoFlush ? ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 64 KB : 0) : /* only needs past data up to window size */ cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 128 KB : 0); if (cctxPtr->maxBufferSize < requiredBuffSize) { cctxPtr->maxBufferSize = 0; LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem); cctxPtr->tmpBuff = (BYTE*)LZ4F_malloc(requiredBuffSize, cctxPtr->cmem); RETURN_ERROR_IF(cctxPtr->tmpBuff == NULL, allocation_failed); cctxPtr->maxBufferSize = requiredBuffSize; } } cctxPtr->tmpIn = cctxPtr->tmpBuff; cctxPtr->tmpInSize = 0; (void)XXH32_reset(&(cctxPtr->xxh), 0); /* context init */ cctxPtr->cdict = cdict; if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) { /* frame init only for blockLinked : blockIndependent will be init at each block */ LZ4F_initStream(cctxPtr->lz4CtxPtr, cdict, cctxPtr->prefs.compressionLevel, LZ4F_blockLinked); } if (preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN) { LZ4_favorDecompressionSpeed((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, (int)preferencesPtr->favorDecSpeed); } /* Magic Number */ LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER); dstPtr += 4; { BYTE* const headerStart = dstPtr; /* FLG Byte */ *dstPtr++ = (BYTE)(((1 & _2BITS) << 6) /* Version('01') */ + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5) + ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4) + ((unsigned)(cctxPtr->prefs.frameInfo.contentSize > 0) << 3) + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2) + (cctxPtr->prefs.frameInfo.dictID > 0) ); /* BD Byte */ *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4); /* Optional Frame content size field */ if (cctxPtr->prefs.frameInfo.contentSize) { LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize); dstPtr += 8; cctxPtr->totalInSize = 0; } /* Optional dictionary ID field */ if (cctxPtr->prefs.frameInfo.dictID) { LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID); dstPtr += 4; } /* Header CRC Byte */ *dstPtr = LZ4F_headerChecksum(headerStart, (size_t)(dstPtr - headerStart)); dstPtr++; } cctxPtr->cStage = 1; /* header written, now request input data block */ return (size_t)(dstPtr - dstStart); } /*! LZ4F_compressBegin() : * init streaming compression AND writes frame header into @dstBuffer. * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes. * @preferencesPtr can be NULL, in which case default parameters are selected. * @return : number of bytes written into dstBuffer for the header * or an error code (can be tested using LZ4F_isError()) */ size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_preferences_t* preferencesPtr) { return LZ4F_compressBegin_usingCDict(cctxPtr, dstBuffer, dstCapacity, NULL, preferencesPtr); } /* LZ4F_compressBound() : * @return minimum capacity of dstBuffer for a given srcSize to handle worst case scenario. * LZ4F_preferences_t structure is optional : if NULL, preferences will be set to cover worst case scenario. * This function cannot fail. */ size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr) { if (preferencesPtr && preferencesPtr->autoFlush) { return LZ4F_compressBound_internal(srcSize, preferencesPtr, 0); } return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1); } typedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level, const LZ4F_CDict* cdict); /*! LZ4F_makeBlock(): * compress a single block, add header and optional checksum. * assumption : dst buffer capacity is >= BHSize + srcSize + crcSize */ static size_t LZ4F_makeBlock(void* dst, const void* src, size_t srcSize, compressFunc_t compress, void* lz4ctx, int level, const LZ4F_CDict* cdict, LZ4F_blockChecksum_t crcFlag) { BYTE* const cSizePtr = (BYTE*)dst; U32 cSize; assert(compress != NULL); cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize), (int)(srcSize), (int)(srcSize-1), level, cdict); if (cSize == 0 || cSize >= srcSize) { cSize = (U32)srcSize; LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG); memcpy(cSizePtr+BHSize, src, srcSize); } else { LZ4F_writeLE32(cSizePtr, cSize); } if (crcFlag) { U32 const crc32 = XXH32(cSizePtr+BHSize, cSize, 0); /* checksum of compressed data */ LZ4F_writeLE32(cSizePtr+BHSize+cSize, crc32); } return BHSize + cSize + ((U32)crcFlag)*BFSize; } static int LZ4F_compressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) { int const acceleration = (level < 0) ? -level + 1 : 1; DEBUGLOG(5, "LZ4F_compressBlock (srcSize=%i)", srcSize); LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent); if (cdict) { return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration); } else { return LZ4_compress_fast_extState_fastReset(ctx, src, dst, srcSize, dstCapacity, acceleration); } } static int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) { int const acceleration = (level < 0) ? -level + 1 : 1; (void)cdict; /* init once at beginning of frame */ DEBUGLOG(5, "LZ4F_compressBlock_continue (srcSize=%i)", srcSize); return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration); } static int LZ4F_compressBlockHC(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) { LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent); if (cdict) { return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity); } return LZ4_compress_HC_extStateHC_fastReset(ctx, src, dst, srcSize, dstCapacity, level); } static int LZ4F_compressBlockHC_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) { (void)level; (void)cdict; /* init once at beginning of frame */ return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity); } static int LZ4F_doNotCompressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict) { (void)ctx; (void)src; (void)dst; (void)srcSize; (void)dstCapacity; (void)level; (void)cdict; return 0; } static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level, LZ4F_blockCompression_t compressMode) { if (compressMode == LZ4B_UNCOMPRESSED) return LZ4F_doNotCompressBlock; if (level < LZ4HC_CLEVEL_MIN) { if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlock; return LZ4F_compressBlock_continue; } if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlockHC; return LZ4F_compressBlockHC_continue; } /* Save history (up to 64KB) into @tmpBuff */ static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr) { if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB); return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB); } typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus; static const LZ4F_compressOptions_t k_cOptionsNull = { 0, { 0, 0, 0 } }; /*! LZ4F_compressUpdateImpl() : * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. * When successful, the function always entirely consumes @srcBuffer. * src data is either buffered or compressed into @dstBuffer. * If the block compression does not match the compression of the previous block, the old data is flushed * and operations continue with the new compression mode. * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr) when block compression is turned on. * @compressOptionsPtr is optional : provide NULL to mean "default". * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. * or an error code if it fails (which can be tested using LZ4F_isError()) * After an error, the state is left in a UB state, and must be re-initialized. */ static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr, LZ4F_blockCompression_t blockCompression) { size_t const blockSize = cctxPtr->maxBlockSize; const BYTE* srcPtr = (const BYTE*)srcBuffer; const BYTE* const srcEnd = srcPtr + srcSize; BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; LZ4F_lastBlockStatus lastBlockCompressed = notDone; compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, blockCompression); size_t bytesWritten; DEBUGLOG(4, "LZ4F_compressUpdate (srcSize=%zu)", srcSize); RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized); /* state must be initialized and waiting for next block */ if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize)) RETURN_ERROR(dstMaxSize_tooSmall); if (blockCompression == LZ4B_UNCOMPRESSED && dstCapacity < srcSize) RETURN_ERROR(dstMaxSize_tooSmall); /* flush currently written block, to continue with new block compression */ if (cctxPtr->blockCompression != blockCompression) { bytesWritten = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr); dstPtr += bytesWritten; cctxPtr->blockCompression = blockCompression; } if (compressOptionsPtr == NULL) compressOptionsPtr = &k_cOptionsNull; /* complete tmp buffer */ if (cctxPtr->tmpInSize > 0) { /* some data already within tmp buffer */ size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize; assert(blockSize > cctxPtr->tmpInSize); if (sizeToCopy > srcSize) { /* add src to tmpIn buffer */ memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize); srcPtr = srcEnd; cctxPtr->tmpInSize += srcSize; /* still needs some CRC */ } else { /* complete tmpIn block and then compress it */ lastBlockCompressed = fromTmpBuffer; memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy); srcPtr += sizeToCopy; dstPtr += LZ4F_makeBlock(dstPtr, cctxPtr->tmpIn, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize; cctxPtr->tmpInSize = 0; } } while ((size_t)(srcEnd - srcPtr) >= blockSize) { /* compress full blocks */ lastBlockCompressed = fromSrcBuffer; dstPtr += LZ4F_makeBlock(dstPtr, srcPtr, blockSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); srcPtr += blockSize; } if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) { /* autoFlush : remaining input (< blockSize) is compressed */ lastBlockCompressed = fromSrcBuffer; dstPtr += LZ4F_makeBlock(dstPtr, srcPtr, (size_t)(srcEnd - srcPtr), compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); srcPtr = srcEnd; } /* preserve dictionary within @tmpBuff whenever necessary */ if ((cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) && (lastBlockCompressed==fromSrcBuffer)) { /* linked blocks are only supported in compressed mode, see LZ4F_uncompressedUpdate */ assert(blockCompression == LZ4B_COMPRESSED); if (compressOptionsPtr->stableSrc) { cctxPtr->tmpIn = cctxPtr->tmpBuff; /* src is stable : dictionary remains in src across invocations */ } else { int const realDictSize = LZ4F_localSaveDict(cctxPtr); assert(0 <= realDictSize && realDictSize <= 64 KB); cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; } } /* keep tmpIn within limits */ if (!(cctxPtr->prefs.autoFlush) /* no autoflush : there may be some data left within internal buffer */ && (cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) ) /* not enough room to store next block */ { /* only preserve 64KB within internal buffer. Ensures there is enough room for next block. * note: this situation necessarily implies lastBlockCompressed==fromTmpBuffer */ int const realDictSize = LZ4F_localSaveDict(cctxPtr); cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; assert((cctxPtr->tmpIn + blockSize) <= (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)); } /* some input data left, necessarily < blockSize */ if (srcPtr < srcEnd) { /* fill tmp buffer */ size_t const sizeToCopy = (size_t)(srcEnd - srcPtr); memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy); cctxPtr->tmpInSize = sizeToCopy; } if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) (void)XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize); cctxPtr->totalInSize += srcSize; return (size_t)(dstPtr - dstStart); } /*! LZ4F_compressUpdate() : * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. * When successful, the function always entirely consumes @srcBuffer. * src data is either buffered or compressed into @dstBuffer. * If previously an uncompressed block was written, buffered data is flushed * before appending compressed data is continued. * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr). * @compressOptionsPtr is optional : provide NULL to mean "default". * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. * or an error code if it fails (which can be tested using LZ4F_isError()) * After an error, the state is left in a UB state, and must be re-initialized. */ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr) { return LZ4F_compressUpdateImpl(cctxPtr, dstBuffer, dstCapacity, srcBuffer, srcSize, compressOptionsPtr, LZ4B_COMPRESSED); } /*! LZ4F_compressUpdate() : * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. * When successful, the function always entirely consumes @srcBuffer. * src data is either buffered or compressed into @dstBuffer. * If previously an uncompressed block was written, buffered data is flushed * before appending compressed data is continued. * This is only supported when LZ4F_blockIndependent is used * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr). * @compressOptionsPtr is optional : provide NULL to mean "default". * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered. * or an error code if it fails (which can be tested using LZ4F_isError()) * After an error, the state is left in a UB state, and must be re-initialized. */ size_t LZ4F_uncompressedUpdate(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr) { return LZ4F_compressUpdateImpl(cctxPtr, dstBuffer, dstCapacity, srcBuffer, srcSize, compressOptionsPtr, LZ4B_UNCOMPRESSED); } /*! LZ4F_flush() : * When compressed data must be sent immediately, without waiting for a block to be filled, * invoke LZ4_flush(), which will immediately compress any remaining data stored within LZ4F_cctx. * The result of the function is the number of bytes written into dstBuffer. * It can be zero, this means there was no data left within LZ4F_cctx. * The function outputs an error code if it fails (can be tested using LZ4F_isError()) * LZ4F_compressOptions_t* is optional. NULL is a valid argument. */ size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* compressOptionsPtr) { BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; compressFunc_t compress; if (cctxPtr->tmpInSize == 0) return 0; /* nothing to flush */ RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized); RETURN_ERROR_IF(dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize), dstMaxSize_tooSmall); (void)compressOptionsPtr; /* not useful (yet) */ /* select compression function */ compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, cctxPtr->blockCompression); /* compress tmp buffer */ dstPtr += LZ4F_makeBlock(dstPtr, cctxPtr->tmpIn, cctxPtr->tmpInSize, compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel, cctxPtr->cdict, cctxPtr->prefs.frameInfo.blockChecksumFlag); assert(((void)"flush overflows dstBuffer!", (size_t)(dstPtr - dstStart) <= dstCapacity)); if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) cctxPtr->tmpIn += cctxPtr->tmpInSize; cctxPtr->tmpInSize = 0; /* keep tmpIn within limits */ if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) { /* necessarily LZ4F_blockLinked */ int const realDictSize = LZ4F_localSaveDict(cctxPtr); cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize; } return (size_t)(dstPtr - dstStart); } /*! LZ4F_compressEnd() : * When you want to properly finish the compressed frame, just call LZ4F_compressEnd(). * It will flush whatever data remained within compressionContext (like LZ4_flush()) * but also properly finalize the frame, with an endMark and an (optional) checksum. * LZ4F_compressOptions_t structure is optional : you can provide NULL as argument. * @return: the number of bytes written into dstBuffer (necessarily >= 4 (endMark size)) * or an error code if it fails (can be tested using LZ4F_isError()) * The context can then be used again to compress a new frame, starting with LZ4F_compressBegin(). */ size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* compressOptionsPtr) { BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* dstPtr = dstStart; size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr); DEBUGLOG(5,"LZ4F_compressEnd: dstCapacity=%u", (unsigned)dstCapacity); FORWARD_IF_ERROR(flushSize); dstPtr += flushSize; assert(flushSize <= dstCapacity); dstCapacity -= flushSize; RETURN_ERROR_IF(dstCapacity < 4, dstMaxSize_tooSmall); LZ4F_writeLE32(dstPtr, 0); dstPtr += 4; /* endMark */ if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) { U32 const xxh = XXH32_digest(&(cctxPtr->xxh)); RETURN_ERROR_IF(dstCapacity < 8, dstMaxSize_tooSmall); DEBUGLOG(5,"Writing 32-bit content checksum"); LZ4F_writeLE32(dstPtr, xxh); dstPtr+=4; /* content Checksum */ } cctxPtr->cStage = 0; /* state is now re-usable (with identical preferences) */ if (cctxPtr->prefs.frameInfo.contentSize) { if (cctxPtr->prefs.frameInfo.contentSize != cctxPtr->totalInSize) RETURN_ERROR(frameSize_wrong); } return (size_t)(dstPtr - dstStart); } /*-*************************************************** * Frame Decompression *****************************************************/ typedef enum { dstage_getFrameHeader=0, dstage_storeFrameHeader, dstage_init, dstage_getBlockHeader, dstage_storeBlockHeader, dstage_copyDirect, dstage_getBlockChecksum, dstage_getCBlock, dstage_storeCBlock, dstage_flushOut, dstage_getSuffix, dstage_storeSuffix, dstage_getSFrameSize, dstage_storeSFrameSize, dstage_skipSkippable } dStage_t; struct LZ4F_dctx_s { LZ4F_CustomMem cmem; LZ4F_frameInfo_t frameInfo; U32 version; dStage_t dStage; U64 frameRemainingSize; size_t maxBlockSize; size_t maxBufferSize; BYTE* tmpIn; size_t tmpInSize; size_t tmpInTarget; BYTE* tmpOutBuffer; const BYTE* dict; size_t dictSize; BYTE* tmpOut; size_t tmpOutSize; size_t tmpOutStart; XXH32_state_t xxh; XXH32_state_t blockChecksum; int skipChecksum; BYTE header[LZ4F_HEADER_SIZE_MAX]; }; /* typedef'd to LZ4F_dctx in lz4frame.h */ LZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version) { LZ4F_dctx* const dctx = (LZ4F_dctx*)LZ4F_calloc(sizeof(LZ4F_dctx), customMem); if (dctx == NULL) return NULL; dctx->cmem = customMem; dctx->version = version; return dctx; } /*! LZ4F_createDecompressionContext() : * Create a decompressionContext object, which will track all decompression operations. * Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object. * Object can later be released using LZ4F_freeDecompressionContext(). * @return : if != 0, there was an error during context creation. */ LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber) { assert(LZ4F_decompressionContextPtr != NULL); /* violation of narrow contract */ RETURN_ERROR_IF(LZ4F_decompressionContextPtr == NULL, parameter_null); /* in case it nonetheless happen in production */ *LZ4F_decompressionContextPtr = LZ4F_createDecompressionContext_advanced(LZ4F_defaultCMem, versionNumber); if (*LZ4F_decompressionContextPtr == NULL) { /* failed allocation */ RETURN_ERROR(allocation_failed); } return LZ4F_OK_NoError; } LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx) { LZ4F_errorCode_t result = LZ4F_OK_NoError; if (dctx != NULL) { /* can accept NULL input, like free() */ result = (LZ4F_errorCode_t)dctx->dStage; LZ4F_free(dctx->tmpIn, dctx->cmem); LZ4F_free(dctx->tmpOutBuffer, dctx->cmem); LZ4F_free(dctx, dctx->cmem); } return result; } /*==--- Streaming Decompression operations ---==*/ void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx) { dctx->dStage = dstage_getFrameHeader; dctx->dict = NULL; dctx->dictSize = 0; dctx->skipChecksum = 0; } /*! LZ4F_decodeHeader() : * input : `src` points at the **beginning of the frame** * output : set internal values of dctx, such as * dctx->frameInfo and dctx->dStage. * Also allocates internal buffers. * @return : nb Bytes read from src (necessarily <= srcSize) * or an error code (testable with LZ4F_isError()) */ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize) { unsigned blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, dictIDFlag, blockSizeID; size_t frameHeaderSize; const BYTE* srcPtr = (const BYTE*)src; DEBUGLOG(5, "LZ4F_decodeHeader"); /* need to decode header to get frameInfo */ RETURN_ERROR_IF(srcSize < minFHSize, frameHeader_incomplete); /* minimal frame header size */ MEM_INIT(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo)); /* special case : skippable frames */ if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) { dctx->frameInfo.frameType = LZ4F_skippableFrame; if (src == (void*)(dctx->header)) { dctx->tmpInSize = srcSize; dctx->tmpInTarget = 8; dctx->dStage = dstage_storeSFrameSize; return srcSize; } else { dctx->dStage = dstage_getSFrameSize; return 4; } } /* control magic number */ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) { DEBUGLOG(4, "frame header error : unknown magic number"); RETURN_ERROR(frameType_unknown); } #endif dctx->frameInfo.frameType = LZ4F_frame; /* Flags */ { U32 const FLG = srcPtr[4]; U32 const version = (FLG>>6) & _2BITS; blockChecksumFlag = (FLG>>4) & _1BIT; blockMode = (FLG>>5) & _1BIT; contentSizeFlag = (FLG>>3) & _1BIT; contentChecksumFlag = (FLG>>2) & _1BIT; dictIDFlag = FLG & _1BIT; /* validate */ if (((FLG>>1)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bit */ if (version != 1) RETURN_ERROR(headerVersion_wrong); /* Version Number, only supported value */ } /* Frame Header Size */ frameHeaderSize = minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0); if (srcSize < frameHeaderSize) { /* not enough input to fully decode frame header */ if (srcPtr != dctx->header) memcpy(dctx->header, srcPtr, srcSize); dctx->tmpInSize = srcSize; dctx->tmpInTarget = frameHeaderSize; dctx->dStage = dstage_storeFrameHeader; return srcSize; } { U32 const BD = srcPtr[5]; blockSizeID = (BD>>4) & _3BITS; /* validate */ if (((BD>>7)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bit */ if (blockSizeID < 4) RETURN_ERROR(maxBlockSize_invalid); /* 4-7 only supported values for the time being */ if (((BD>>0)&_4BITS) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bits */ } /* check header */ assert(frameHeaderSize > 5); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION { BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5); RETURN_ERROR_IF(HC != srcPtr[frameHeaderSize-1], headerChecksum_invalid); } #endif /* save */ dctx->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode; dctx->frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)blockChecksumFlag; dctx->frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)contentChecksumFlag; dctx->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID; dctx->maxBlockSize = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID); if (contentSizeFlag) dctx->frameRemainingSize = dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6); if (dictIDFlag) dctx->frameInfo.dictID = LZ4F_readLE32(srcPtr + frameHeaderSize - 5); dctx->dStage = dstage_init; return frameHeaderSize; } /*! LZ4F_headerSize() : * @return : size of frame header * or an error code, which can be tested using LZ4F_isError() */ size_t LZ4F_headerSize(const void* src, size_t srcSize) { RETURN_ERROR_IF(src == NULL, srcPtr_wrong); /* minimal srcSize to determine header size */ if (srcSize < LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH) RETURN_ERROR(frameHeader_incomplete); /* special case : skippable frames */ if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) return 8; /* control magic number */ #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER) RETURN_ERROR(frameType_unknown); #endif /* Frame Header Size */ { BYTE const FLG = ((const BYTE*)src)[4]; U32 const contentSizeFlag = (FLG>>3) & _1BIT; U32 const dictIDFlag = FLG & _1BIT; return minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0); } } /*! LZ4F_getFrameInfo() : * This function extracts frame parameters (max blockSize, frame checksum, etc.). * Usage is optional. Objective is to provide relevant information for allocation purposes. * This function works in 2 situations : * - At the beginning of a new frame, in which case it will decode this information from `srcBuffer`, and start the decoding process. * Amount of input data provided must be large enough to successfully decode the frame header. * A header size is variable, but is guaranteed to be <= LZ4F_HEADER_SIZE_MAX bytes. It's possible to provide more input data than this minimum. * - After decoding has been started. In which case, no input is read, frame parameters are extracted from dctx. * The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value). * Decompression must resume from (srcBuffer + *srcSizePtr). * @return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call, * or an error code which can be tested using LZ4F_isError() * note 1 : in case of error, dctx is not modified. Decoding operations can resume from where they stopped. * note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure. */ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoPtr, const void* srcBuffer, size_t* srcSizePtr) { LZ4F_STATIC_ASSERT(dstage_getFrameHeader < dstage_storeFrameHeader); if (dctx->dStage > dstage_storeFrameHeader) { /* frameInfo already decoded */ size_t o=0, i=0; *srcSizePtr = 0; *frameInfoPtr = dctx->frameInfo; /* returns : recommended nb of bytes for LZ4F_decompress() */ return LZ4F_decompress(dctx, NULL, &o, NULL, &i, NULL); } else { if (dctx->dStage == dstage_storeFrameHeader) { /* frame decoding already started, in the middle of header => automatic fail */ *srcSizePtr = 0; RETURN_ERROR(frameDecoding_alreadyStarted); } else { size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr); if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; } if (*srcSizePtr < hSize) { *srcSizePtr=0; RETURN_ERROR(frameHeader_incomplete); } { size_t decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize); if (LZ4F_isError(decodeResult)) { *srcSizePtr = 0; } else { *srcSizePtr = decodeResult; decodeResult = BHSize; /* block header size */ } *frameInfoPtr = dctx->frameInfo; return decodeResult; } } } } /* LZ4F_updateDict() : * only used for LZ4F_blockLinked mode * Condition : @dstPtr != NULL */ static void LZ4F_updateDict(LZ4F_dctx* dctx, const BYTE* dstPtr, size_t dstSize, const BYTE* dstBufferStart, unsigned withinTmp) { assert(dstPtr != NULL); if (dctx->dictSize==0) dctx->dict = (const BYTE*)dstPtr; /* will lead to prefix mode */ assert(dctx->dict != NULL); if (dctx->dict + dctx->dictSize == dstPtr) { /* prefix mode, everything within dstBuffer */ dctx->dictSize += dstSize; return; } assert(dstPtr >= dstBufferStart); if ((size_t)(dstPtr - dstBufferStart) + dstSize >= 64 KB) { /* history in dstBuffer becomes large enough to become dictionary */ dctx->dict = (const BYTE*)dstBufferStart; dctx->dictSize = (size_t)(dstPtr - dstBufferStart) + dstSize; return; } assert(dstSize < 64 KB); /* if dstSize >= 64 KB, dictionary would be set into dstBuffer directly */ /* dstBuffer does not contain whole useful history (64 KB), so it must be saved within tmpOutBuffer */ assert(dctx->tmpOutBuffer != NULL); if (withinTmp && (dctx->dict == dctx->tmpOutBuffer)) { /* continue history within tmpOutBuffer */ /* withinTmp expectation : content of [dstPtr,dstSize] is same as [dict+dictSize,dstSize], so we just extend it */ assert(dctx->dict + dctx->dictSize == dctx->tmpOut + dctx->tmpOutStart); dctx->dictSize += dstSize; return; } if (withinTmp) { /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */ size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer); size_t copySize = 64 KB - dctx->tmpOutSize; const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart; if (dctx->tmpOutSize > 64 KB) copySize = 0; if (copySize > preserveSize) copySize = preserveSize; memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize); dctx->dict = dctx->tmpOutBuffer; dctx->dictSize = preserveSize + dctx->tmpOutStart + dstSize; return; } if (dctx->dict == dctx->tmpOutBuffer) { /* copy dst into tmp to complete dict */ if (dctx->dictSize + dstSize > dctx->maxBufferSize) { /* tmp buffer not large enough */ size_t const preserveSize = 64 KB - dstSize; memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize); dctx->dictSize = preserveSize; } memcpy(dctx->tmpOutBuffer + dctx->dictSize, dstPtr, dstSize); dctx->dictSize += dstSize; return; } /* join dict & dest into tmp */ { size_t preserveSize = 64 KB - dstSize; if (preserveSize > dctx->dictSize) preserveSize = dctx->dictSize; memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize); memcpy(dctx->tmpOutBuffer + preserveSize, dstPtr, dstSize); dctx->dict = dctx->tmpOutBuffer; dctx->dictSize = preserveSize + dstSize; } } /*! LZ4F_decompress() : * Call this function repetitively to regenerate compressed data in srcBuffer. * The function will attempt to decode up to *srcSizePtr bytes from srcBuffer * into dstBuffer of capacity *dstSizePtr. * * The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value). * * The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value). * If number of bytes read is < number of bytes provided, then decompression operation is not complete. * Remaining data will have to be presented again in a subsequent invocation. * * The function result is an hint of the better srcSize to use for next call to LZ4F_decompress. * Schematically, it's the size of the current (or remaining) compressed block + header of next block. * Respecting the hint provides a small boost to performance, since it allows less buffer shuffling. * Note that this is just a hint, and it's always possible to any srcSize value. * When a frame is fully decoded, @return will be 0. * If decompression failed, @return is an error code which can be tested using LZ4F_isError(). */ size_t LZ4F_decompress(LZ4F_dctx* dctx, void* dstBuffer, size_t* dstSizePtr, const void* srcBuffer, size_t* srcSizePtr, const LZ4F_decompressOptions_t* decompressOptionsPtr) { LZ4F_decompressOptions_t optionsNull; const BYTE* const srcStart = (const BYTE*)srcBuffer; const BYTE* const srcEnd = srcStart + *srcSizePtr; const BYTE* srcPtr = srcStart; BYTE* const dstStart = (BYTE*)dstBuffer; BYTE* const dstEnd = dstStart ? dstStart + *dstSizePtr : NULL; BYTE* dstPtr = dstStart; const BYTE* selectedIn = NULL; unsigned doAnotherStage = 1; size_t nextSrcSizeHint = 1; DEBUGLOG(5, "LZ4F_decompress : %p,%u => %p,%u", srcBuffer, (unsigned)*srcSizePtr, dstBuffer, (unsigned)*dstSizePtr); if (dstBuffer == NULL) assert(*dstSizePtr == 0); MEM_INIT(&optionsNull, 0, sizeof(optionsNull)); if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull; *srcSizePtr = 0; *dstSizePtr = 0; assert(dctx != NULL); dctx->skipChecksum |= (decompressOptionsPtr->skipChecksums != 0); /* once set, disable for the remainder of the frame */ /* behaves as a state machine */ while (doAnotherStage) { switch(dctx->dStage) { case dstage_getFrameHeader: DEBUGLOG(6, "dstage_getFrameHeader"); if ((size_t)(srcEnd-srcPtr) >= maxFHSize) { /* enough to decode - shortcut */ size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, (size_t)(srcEnd-srcPtr)); /* will update dStage appropriately */ FORWARD_IF_ERROR(hSize); srcPtr += hSize; break; } dctx->tmpInSize = 0; if (srcEnd-srcPtr == 0) return minFHSize; /* 0-size input */ dctx->tmpInTarget = minFHSize; /* minimum size to decode header */ dctx->dStage = dstage_storeFrameHeader; /* fall-through */ case dstage_storeFrameHeader: DEBUGLOG(6, "dstage_storeFrameHeader"); { size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr)); memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); dctx->tmpInSize += sizeToCopy; srcPtr += sizeToCopy; } if (dctx->tmpInSize < dctx->tmpInTarget) { nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize; /* rest of header + nextBlockHeader */ doAnotherStage = 0; /* not enough src data, ask for some more */ break; } FORWARD_IF_ERROR( LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget) ); /* will update dStage appropriately */ break; case dstage_init: DEBUGLOG(6, "dstage_init"); if (dctx->frameInfo.contentChecksumFlag) (void)XXH32_reset(&(dctx->xxh), 0); /* internal buffers allocation */ { size_t const bufferNeeded = dctx->maxBlockSize + ((dctx->frameInfo.blockMode==LZ4F_blockLinked) ? 128 KB : 0); if (bufferNeeded > dctx->maxBufferSize) { /* tmp buffers too small */ dctx->maxBufferSize = 0; /* ensure allocation will be re-attempted on next entry*/ LZ4F_free(dctx->tmpIn, dctx->cmem); dctx->tmpIn = (BYTE*)LZ4F_malloc(dctx->maxBlockSize + BFSize /* block checksum */, dctx->cmem); RETURN_ERROR_IF(dctx->tmpIn == NULL, allocation_failed); LZ4F_free(dctx->tmpOutBuffer, dctx->cmem); dctx->tmpOutBuffer= (BYTE*)LZ4F_malloc(bufferNeeded, dctx->cmem); RETURN_ERROR_IF(dctx->tmpOutBuffer== NULL, allocation_failed); dctx->maxBufferSize = bufferNeeded; } } dctx->tmpInSize = 0; dctx->tmpInTarget = 0; dctx->tmpOut = dctx->tmpOutBuffer; dctx->tmpOutStart = 0; dctx->tmpOutSize = 0; dctx->dStage = dstage_getBlockHeader; /* fall-through */ case dstage_getBlockHeader: if ((size_t)(srcEnd - srcPtr) >= BHSize) { selectedIn = srcPtr; srcPtr += BHSize; } else { /* not enough input to read cBlockSize field */ dctx->tmpInSize = 0; dctx->dStage = dstage_storeBlockHeader; } if (dctx->dStage == dstage_storeBlockHeader) /* can be skipped */ case dstage_storeBlockHeader: { size_t const remainingInput = (size_t)(srcEnd - srcPtr); size_t const wantedData = BHSize - dctx->tmpInSize; size_t const sizeToCopy = MIN(wantedData, remainingInput); memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy); srcPtr += sizeToCopy; dctx->tmpInSize += sizeToCopy; if (dctx->tmpInSize < BHSize) { /* not enough input for cBlockSize */ nextSrcSizeHint = BHSize - dctx->tmpInSize; doAnotherStage = 0; break; } selectedIn = dctx->tmpIn; } /* if (dctx->dStage == dstage_storeBlockHeader) */ /* decode block header */ { U32 const blockHeader = LZ4F_readLE32(selectedIn); size_t const nextCBlockSize = blockHeader & 0x7FFFFFFFU; size_t const crcSize = dctx->frameInfo.blockChecksumFlag * BFSize; if (blockHeader==0) { /* frameEnd signal, no more block */ DEBUGLOG(5, "end of frame"); dctx->dStage = dstage_getSuffix; break; } if (nextCBlockSize > dctx->maxBlockSize) { RETURN_ERROR(maxBlockSize_invalid); } if (blockHeader & LZ4F_BLOCKUNCOMPRESSED_FLAG) { /* next block is uncompressed */ dctx->tmpInTarget = nextCBlockSize; DEBUGLOG(5, "next block is uncompressed (size %u)", (U32)nextCBlockSize); if (dctx->frameInfo.blockChecksumFlag) { (void)XXH32_reset(&dctx->blockChecksum, 0); } dctx->dStage = dstage_copyDirect; break; } /* next block is a compressed block */ dctx->tmpInTarget = nextCBlockSize + crcSize; dctx->dStage = dstage_getCBlock; if (dstPtr==dstEnd || srcPtr==srcEnd) { nextSrcSizeHint = BHSize + nextCBlockSize + crcSize; doAnotherStage = 0; } break; } case dstage_copyDirect: /* uncompressed block */ DEBUGLOG(6, "dstage_copyDirect"); { size_t sizeToCopy; if (dstPtr == NULL) { sizeToCopy = 0; } else { size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr)); sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize); memcpy(dstPtr, srcPtr, sizeToCopy); if (!dctx->skipChecksum) { if (dctx->frameInfo.blockChecksumFlag) { (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy); } if (dctx->frameInfo.contentChecksumFlag) (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy); } if (dctx->frameInfo.contentSize) dctx->frameRemainingSize -= sizeToCopy; /* history management (linked blocks only)*/ if (dctx->frameInfo.blockMode == LZ4F_blockLinked) { LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0); } srcPtr += sizeToCopy; dstPtr += sizeToCopy; } if (sizeToCopy == dctx->tmpInTarget) { /* all done */ if (dctx->frameInfo.blockChecksumFlag) { dctx->tmpInSize = 0; dctx->dStage = dstage_getBlockChecksum; } else dctx->dStage = dstage_getBlockHeader; /* new block */ break; } dctx->tmpInTarget -= sizeToCopy; /* need to copy more */ } nextSrcSizeHint = dctx->tmpInTarget + +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0) + BHSize /* next header size */; doAnotherStage = 0; break; /* check block checksum for recently transferred uncompressed block */ case dstage_getBlockChecksum: DEBUGLOG(6, "dstage_getBlockChecksum"); { const void* crcSrc; if ((srcEnd-srcPtr >= 4) && (dctx->tmpInSize==0)) { crcSrc = srcPtr; srcPtr += 4; } else { size_t const stillToCopy = 4 - dctx->tmpInSize; size_t const sizeToCopy = MIN(stillToCopy, (size_t)(srcEnd-srcPtr)); memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); dctx->tmpInSize += sizeToCopy; srcPtr += sizeToCopy; if (dctx->tmpInSize < 4) { /* all input consumed */ doAnotherStage = 0; break; } crcSrc = dctx->header; } if (!dctx->skipChecksum) { U32 const readCRC = LZ4F_readLE32(crcSrc); U32 const calcCRC = XXH32_digest(&dctx->blockChecksum); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION DEBUGLOG(6, "compare block checksum"); if (readCRC != calcCRC) { DEBUGLOG(4, "incorrect block checksum: %08X != %08X", readCRC, calcCRC); RETURN_ERROR(blockChecksum_invalid); } #else (void)readCRC; (void)calcCRC; #endif } } dctx->dStage = dstage_getBlockHeader; /* new block */ break; case dstage_getCBlock: DEBUGLOG(6, "dstage_getCBlock"); if ((size_t)(srcEnd-srcPtr) < dctx->tmpInTarget) { dctx->tmpInSize = 0; dctx->dStage = dstage_storeCBlock; break; } /* input large enough to read full block directly */ selectedIn = srcPtr; srcPtr += dctx->tmpInTarget; if (0) /* always jump over next block */ case dstage_storeCBlock: { size_t const wantedData = dctx->tmpInTarget - dctx->tmpInSize; size_t const inputLeft = (size_t)(srcEnd-srcPtr); size_t const sizeToCopy = MIN(wantedData, inputLeft); memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy); dctx->tmpInSize += sizeToCopy; srcPtr += sizeToCopy; if (dctx->tmpInSize < dctx->tmpInTarget) { /* need more input */ nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + (dctx->frameInfo.blockChecksumFlag ? BFSize : 0) + BHSize /* next header size */; doAnotherStage = 0; break; } selectedIn = dctx->tmpIn; } /* At this stage, input is large enough to decode a block */ /* First, decode and control block checksum if it exists */ if (dctx->frameInfo.blockChecksumFlag) { assert(dctx->tmpInTarget >= 4); dctx->tmpInTarget -= 4; assert(selectedIn != NULL); /* selectedIn is defined at this stage (either srcPtr, or dctx->tmpIn) */ { U32 const readBlockCrc = LZ4F_readLE32(selectedIn + dctx->tmpInTarget); U32 const calcBlockCrc = XXH32(selectedIn, dctx->tmpInTarget, 0); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION RETURN_ERROR_IF(readBlockCrc != calcBlockCrc, blockChecksum_invalid); #else (void)readBlockCrc; (void)calcBlockCrc; #endif } } /* decode directly into destination buffer if there is enough room */ if ( ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize) /* unless the dictionary is stored in tmpOut: * in which case it's faster to decode within tmpOut * to benefit from prefix speedup */ && !(dctx->dict!= NULL && (const BYTE*)dctx->dict + dctx->dictSize == dctx->tmpOut) ) { const char* dict = (const char*)dctx->dict; size_t dictSize = dctx->dictSize; int decodedSize; assert(dstPtr != NULL); if (dict && dictSize > 1 GB) { /* overflow control : dctx->dictSize is an int, avoid truncation / sign issues */ dict += dictSize - 64 KB; dictSize = 64 KB; } decodedSize = LZ4_decompress_safe_usingDict( (const char*)selectedIn, (char*)dstPtr, (int)dctx->tmpInTarget, (int)dctx->maxBlockSize, dict, (int)dictSize); RETURN_ERROR_IF(decodedSize < 0, decompressionFailed); if ((dctx->frameInfo.contentChecksumFlag) && (!dctx->skipChecksum)) XXH32_update(&(dctx->xxh), dstPtr, (size_t)decodedSize); if (dctx->frameInfo.contentSize) dctx->frameRemainingSize -= (size_t)decodedSize; /* dictionary management */ if (dctx->frameInfo.blockMode==LZ4F_blockLinked) { LZ4F_updateDict(dctx, dstPtr, (size_t)decodedSize, dstStart, 0); } dstPtr += decodedSize; dctx->dStage = dstage_getBlockHeader; /* end of block, let's get another one */ break; } /* not enough place into dst : decode into tmpOut */ /* manage dictionary */ if (dctx->frameInfo.blockMode == LZ4F_blockLinked) { if (dctx->dict == dctx->tmpOutBuffer) { /* truncate dictionary to 64 KB if too big */ if (dctx->dictSize > 128 KB) { memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - 64 KB, 64 KB); dctx->dictSize = 64 KB; } dctx->tmpOut = dctx->tmpOutBuffer + dctx->dictSize; } else { /* dict not within tmpOut */ size_t const reservedDictSpace = MIN(dctx->dictSize, 64 KB); dctx->tmpOut = dctx->tmpOutBuffer + reservedDictSpace; } } /* Decode block into tmpOut */ { const char* dict = (const char*)dctx->dict; size_t dictSize = dctx->dictSize; int decodedSize; if (dict && dictSize > 1 GB) { /* the dictSize param is an int, avoid truncation / sign issues */ dict += dictSize - 64 KB; dictSize = 64 KB; } decodedSize = LZ4_decompress_safe_usingDict( (const char*)selectedIn, (char*)dctx->tmpOut, (int)dctx->tmpInTarget, (int)dctx->maxBlockSize, dict, (int)dictSize); RETURN_ERROR_IF(decodedSize < 0, decompressionFailed); if (dctx->frameInfo.contentChecksumFlag && !dctx->skipChecksum) XXH32_update(&(dctx->xxh), dctx->tmpOut, (size_t)decodedSize); if (dctx->frameInfo.contentSize) dctx->frameRemainingSize -= (size_t)decodedSize; dctx->tmpOutSize = (size_t)decodedSize; dctx->tmpOutStart = 0; dctx->dStage = dstage_flushOut; } /* fall-through */ case dstage_flushOut: /* flush decoded data from tmpOut to dstBuffer */ DEBUGLOG(6, "dstage_flushOut"); if (dstPtr != NULL) { size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr)); memcpy(dstPtr, dctx->tmpOut + dctx->tmpOutStart, sizeToCopy); /* dictionary management */ if (dctx->frameInfo.blockMode == LZ4F_blockLinked) LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 1 /*withinTmp*/); dctx->tmpOutStart += sizeToCopy; dstPtr += sizeToCopy; } if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */ dctx->dStage = dstage_getBlockHeader; /* get next block */ break; } /* could not flush everything : stop there, just request a block header */ doAnotherStage = 0; nextSrcSizeHint = BHSize; break; case dstage_getSuffix: RETURN_ERROR_IF(dctx->frameRemainingSize, frameSize_wrong); /* incorrect frame size decoded */ if (!dctx->frameInfo.contentChecksumFlag) { /* no checksum, frame is completed */ nextSrcSizeHint = 0; LZ4F_resetDecompressionContext(dctx); doAnotherStage = 0; break; } if ((srcEnd - srcPtr) < 4) { /* not enough size for entire CRC */ dctx->tmpInSize = 0; dctx->dStage = dstage_storeSuffix; } else { selectedIn = srcPtr; srcPtr += 4; } if (dctx->dStage == dstage_storeSuffix) /* can be skipped */ case dstage_storeSuffix: { size_t const remainingInput = (size_t)(srcEnd - srcPtr); size_t const wantedData = 4 - dctx->tmpInSize; size_t const sizeToCopy = MIN(wantedData, remainingInput); memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy); srcPtr += sizeToCopy; dctx->tmpInSize += sizeToCopy; if (dctx->tmpInSize < 4) { /* not enough input to read complete suffix */ nextSrcSizeHint = 4 - dctx->tmpInSize; doAnotherStage=0; break; } selectedIn = dctx->tmpIn; } /* if (dctx->dStage == dstage_storeSuffix) */ /* case dstage_checkSuffix: */ /* no direct entry, avoid initialization risks */ if (!dctx->skipChecksum) { U32 const readCRC = LZ4F_readLE32(selectedIn); U32 const resultCRC = XXH32_digest(&(dctx->xxh)); #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION RETURN_ERROR_IF(readCRC != resultCRC, contentChecksum_invalid); #else (void)readCRC; (void)resultCRC; #endif } nextSrcSizeHint = 0; LZ4F_resetDecompressionContext(dctx); doAnotherStage = 0; break; case dstage_getSFrameSize: if ((srcEnd - srcPtr) >= 4) { selectedIn = srcPtr; srcPtr += 4; } else { /* not enough input to read cBlockSize field */ dctx->tmpInSize = 4; dctx->tmpInTarget = 8; dctx->dStage = dstage_storeSFrameSize; } if (dctx->dStage == dstage_storeSFrameSize) case dstage_storeSFrameSize: { size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr) ); memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy); srcPtr += sizeToCopy; dctx->tmpInSize += sizeToCopy; if (dctx->tmpInSize < dctx->tmpInTarget) { /* not enough input to get full sBlockSize; wait for more */ nextSrcSizeHint = dctx->tmpInTarget - dctx->tmpInSize; doAnotherStage = 0; break; } selectedIn = dctx->header + 4; } /* if (dctx->dStage == dstage_storeSFrameSize) */ /* case dstage_decodeSFrameSize: */ /* no direct entry */ { size_t const SFrameSize = LZ4F_readLE32(selectedIn); dctx->frameInfo.contentSize = SFrameSize; dctx->tmpInTarget = SFrameSize; dctx->dStage = dstage_skipSkippable; break; } case dstage_skipSkippable: { size_t const skipSize = MIN(dctx->tmpInTarget, (size_t)(srcEnd-srcPtr)); srcPtr += skipSize; dctx->tmpInTarget -= skipSize; doAnotherStage = 0; nextSrcSizeHint = dctx->tmpInTarget; if (nextSrcSizeHint) break; /* still more to skip */ /* frame fully skipped : prepare context for a new frame */ LZ4F_resetDecompressionContext(dctx); break; } } /* switch (dctx->dStage) */ } /* while (doAnotherStage) */ /* preserve history within tmpOut whenever necessary */ LZ4F_STATIC_ASSERT((unsigned)dstage_init == 2); if ( (dctx->frameInfo.blockMode==LZ4F_blockLinked) /* next block will use up to 64KB from previous ones */ && (dctx->dict != dctx->tmpOutBuffer) /* dictionary is not already within tmp */ && (dctx->dict != NULL) /* dictionary exists */ && (!decompressOptionsPtr->stableDst) /* cannot rely on dst data to remain there for next call */ && ((unsigned)(dctx->dStage)-2 < (unsigned)(dstage_getSuffix)-2) ) /* valid stages : [init ... getSuffix[ */ { if (dctx->dStage == dstage_flushOut) { size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer); size_t copySize = 64 KB - dctx->tmpOutSize; const BYTE* oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart; if (dctx->tmpOutSize > 64 KB) copySize = 0; if (copySize > preserveSize) copySize = preserveSize; assert(dctx->tmpOutBuffer != NULL); memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize); dctx->dict = dctx->tmpOutBuffer; dctx->dictSize = preserveSize + dctx->tmpOutStart; } else { const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize; size_t const newDictSize = MIN(dctx->dictSize, 64 KB); memcpy(dctx->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize); dctx->dict = dctx->tmpOutBuffer; dctx->dictSize = newDictSize; dctx->tmpOut = dctx->tmpOutBuffer + newDictSize; } } *srcSizePtr = (size_t)(srcPtr - srcStart); *dstSizePtr = (size_t)(dstPtr - dstStart); return nextSrcSizeHint; } /*! LZ4F_decompress_usingDict() : * Same as LZ4F_decompress(), using a predefined dictionary. * Dictionary is used "in place", without any preprocessing. * It must remain accessible throughout the entire frame decoding. */ size_t LZ4F_decompress_usingDict(LZ4F_dctx* dctx, void* dstBuffer, size_t* dstSizePtr, const void* srcBuffer, size_t* srcSizePtr, const void* dict, size_t dictSize, const LZ4F_decompressOptions_t* decompressOptionsPtr) { if (dctx->dStage <= dstage_init) { dctx->dict = (const BYTE*)dict; dctx->dictSize = dictSize; } return LZ4F_decompress(dctx, dstBuffer, dstSizePtr, srcBuffer, srcSizePtr, decompressOptionsPtr); } ================================================ FILE: lib/LZ4F/lz4frame.h ================================================ /* LZ4F - LZ4-Frame library Header File Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 source repository : https://github.com/lz4/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ /* LZ4F is a stand-alone API able to create and decode LZ4 frames * conformant with specification v1.6.1 in doc/lz4_Frame_format.md . * Generated frames are compatible with `lz4` CLI. * * LZ4F also offers streaming capabilities. * * lz4.h is not required when using lz4frame.h, * except to extract common constants such as LZ4_VERSION_NUMBER. * */ #ifndef LZ4F_H_09782039843 #define LZ4F_H_09782039843 #if defined (__cplusplus) extern "C" { #endif /* --- Dependency --- */ #include /* size_t */ /** * Introduction * * lz4frame.h implements LZ4 frame specification: see doc/lz4_Frame_format.md . * LZ4 Frames are compatible with `lz4` CLI, * and designed to be interoperable with any system. **/ /*-*************************************************************** * Compiler specifics *****************************************************************/ /* LZ4_DLL_EXPORT : * Enable exporting of functions when building a Windows DLL * LZ4FLIB_VISIBILITY : * Control library symbols visibility. */ #ifndef LZ4FLIB_VISIBILITY # if defined(__GNUC__) && (__GNUC__ >= 4) # define LZ4FLIB_VISIBILITY __attribute__ ((visibility ("default"))) # else # define LZ4FLIB_VISIBILITY # endif #endif #if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) # define LZ4FLIB_API __declspec(dllexport) LZ4FLIB_VISIBILITY #elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) # define LZ4FLIB_API __declspec(dllimport) LZ4FLIB_VISIBILITY #else # define LZ4FLIB_API LZ4FLIB_VISIBILITY #endif #ifdef LZ4F_DISABLE_DEPRECATE_WARNINGS # define LZ4F_DEPRECATE(x) x #else # if defined(_MSC_VER) # define LZ4F_DEPRECATE(x) x /* __declspec(deprecated) x - only works with C++ */ # elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) # define LZ4F_DEPRECATE(x) x __attribute__((deprecated)) # else # define LZ4F_DEPRECATE(x) x /* no deprecation warning for this compiler */ # endif #endif /*-************************************ * Error management **************************************/ typedef size_t LZ4F_errorCode_t; LZ4FLIB_API unsigned LZ4F_isError(LZ4F_errorCode_t code); /**< tells when a function result is an error code */ LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /**< return error code string; for debugging */ /*-************************************ * Frame compression types ************************************* */ /* #define LZ4F_ENABLE_OBSOLETE_ENUMS // uncomment to enable obsolete enums */ #ifdef LZ4F_ENABLE_OBSOLETE_ENUMS # define LZ4F_OBSOLETE_ENUM(x) , LZ4F_DEPRECATE(x) = LZ4F_##x #else # define LZ4F_OBSOLETE_ENUM(x) #endif /* The larger the block size, the (slightly) better the compression ratio, * though there are diminishing returns. * Larger blocks also increase memory usage on both compression and decompression sides. */ typedef enum { LZ4F_default=0, LZ4F_max64KB=4, LZ4F_max256KB=5, LZ4F_max1MB=6, LZ4F_max4MB=7 LZ4F_OBSOLETE_ENUM(max64KB) LZ4F_OBSOLETE_ENUM(max256KB) LZ4F_OBSOLETE_ENUM(max1MB) LZ4F_OBSOLETE_ENUM(max4MB) } LZ4F_blockSizeID_t; /* Linked blocks sharply reduce inefficiencies when using small blocks, * they compress better. * However, some LZ4 decoders are only compatible with independent blocks */ typedef enum { LZ4F_blockLinked=0, LZ4F_blockIndependent LZ4F_OBSOLETE_ENUM(blockLinked) LZ4F_OBSOLETE_ENUM(blockIndependent) } LZ4F_blockMode_t; typedef enum { LZ4F_noContentChecksum=0, LZ4F_contentChecksumEnabled LZ4F_OBSOLETE_ENUM(noContentChecksum) LZ4F_OBSOLETE_ENUM(contentChecksumEnabled) } LZ4F_contentChecksum_t; typedef enum { LZ4F_noBlockChecksum=0, LZ4F_blockChecksumEnabled } LZ4F_blockChecksum_t; typedef enum { LZ4F_frame=0, LZ4F_skippableFrame LZ4F_OBSOLETE_ENUM(skippableFrame) } LZ4F_frameType_t; #ifdef LZ4F_ENABLE_OBSOLETE_ENUMS typedef LZ4F_blockSizeID_t blockSizeID_t; typedef LZ4F_blockMode_t blockMode_t; typedef LZ4F_frameType_t frameType_t; typedef LZ4F_contentChecksum_t contentChecksum_t; #endif /*! LZ4F_frameInfo_t : * makes it possible to set or read frame parameters. * Structure must be first init to 0, using memset() or LZ4F_INIT_FRAMEINFO, * setting all parameters to default. * It's then possible to update selectively some parameters */ typedef struct { LZ4F_blockSizeID_t blockSizeID; /* max64KB, max256KB, max1MB, max4MB; 0 == default */ LZ4F_blockMode_t blockMode; /* LZ4F_blockLinked, LZ4F_blockIndependent; 0 == default */ LZ4F_contentChecksum_t contentChecksumFlag; /* 1: frame terminated with 32-bit checksum of decompressed data; 0: disabled (default) */ LZ4F_frameType_t frameType; /* read-only field : LZ4F_frame or LZ4F_skippableFrame */ unsigned long long contentSize; /* Size of uncompressed content ; 0 == unknown */ unsigned dictID; /* Dictionary ID, sent by compressor to help decoder select correct dictionary; 0 == no dictID provided */ LZ4F_blockChecksum_t blockChecksumFlag; /* 1: each block followed by a checksum of block's compressed data; 0: disabled (default) */ } LZ4F_frameInfo_t; #define LZ4F_INIT_FRAMEINFO { LZ4F_default, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0ULL, 0U, LZ4F_noBlockChecksum } /* v1.8.3+ */ /*! LZ4F_preferences_t : * makes it possible to supply advanced compression instructions to streaming interface. * Structure must be first init to 0, using memset() or LZ4F_INIT_PREFERENCES, * setting all parameters to default. * All reserved fields must be set to zero. */ typedef struct { LZ4F_frameInfo_t frameInfo; int compressionLevel; /* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger "fast acceleration" */ unsigned autoFlush; /* 1: always flush; reduces usage of internal buffers */ unsigned favorDecSpeed; /* 1: parser favors decompression speed vs compression ratio. Only works for high compression modes (>= LZ4HC_CLEVEL_OPT_MIN) */ /* v1.8.2+ */ unsigned reserved[3]; /* must be zero for forward compatibility */ } LZ4F_preferences_t; #define LZ4F_INIT_PREFERENCES { LZ4F_INIT_FRAMEINFO, 0, 0u, 0u, { 0u, 0u, 0u } } /* v1.8.3+ */ /*-********************************* * Simple compression function ***********************************/ LZ4FLIB_API int LZ4F_compressionLevel_max(void); /* v1.8.0+ */ /*! LZ4F_compressFrameBound() : * Returns the maximum possible compressed size with LZ4F_compressFrame() given srcSize and preferences. * `preferencesPtr` is optional. It can be replaced by NULL, in which case, the function will assume default preferences. * Note : this result is only usable with LZ4F_compressFrame(). * It may also be relevant to LZ4F_compressUpdate() _only if_ no flush() operation is ever performed. */ LZ4FLIB_API size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr); /*! LZ4F_compressFrame() : * Compress srcBuffer content into an LZ4-compressed frame. * It's a one shot operation, all input content is consumed, and all output is generated. * * Note : it's a stateless operation (no LZ4F_cctx state needed). * In order to reduce load on the allocator, LZ4F_compressFrame(), by default, * uses the stack to allocate space for the compression state and some table. * If this usage of the stack is too much for your application, * consider compiling `lz4frame.c` with compile-time macro LZ4F_HEAPMODE set to 1 instead. * All state allocations will use the Heap. * It also means each invocation of LZ4F_compressFrame() will trigger several internal alloc/free invocations. * * @dstCapacity MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr). * @preferencesPtr is optional : one can provide NULL, in which case all preferences are set to default. * @return : number of bytes written into dstBuffer. * or an error code if it fails (can be tested using LZ4F_isError()) */ LZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr); /*-*********************************** * Advanced compression functions *************************************/ typedef struct LZ4F_cctx_s LZ4F_cctx; /* incomplete type */ typedef LZ4F_cctx* LZ4F_compressionContext_t; /* for compatibility with older APIs, prefer using LZ4F_cctx */ typedef struct { unsigned stableSrc; /* 1 == src content will remain present on future calls to LZ4F_compress(); skip copying src content within tmp buffer */ unsigned reserved[3]; } LZ4F_compressOptions_t; /*--- Resource Management ---*/ #define LZ4F_VERSION 100 /* This number can be used to check for an incompatible API breaking change */ LZ4FLIB_API unsigned LZ4F_getVersion(void); /*! LZ4F_createCompressionContext() : * The first thing to do is to create a compressionContext object, * which will keep track of operation state during streaming compression. * This is achieved using LZ4F_createCompressionContext(), which takes as argument a version, * and a pointer to LZ4F_cctx*, to write the resulting pointer into. * @version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL. * The function provides a pointer to a fully allocated LZ4F_cctx object. * @cctxPtr MUST be != NULL. * If @return != zero, context creation failed. * A created compression context can be employed multiple times for consecutive streaming operations. * Once all streaming compression jobs are completed, * the state object can be released using LZ4F_freeCompressionContext(). * Note1 : LZ4F_freeCompressionContext() is always successful. Its return value can be ignored. * Note2 : LZ4F_freeCompressionContext() works fine with NULL input pointers (do nothing). **/ LZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version); LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx); /*---- Compression ----*/ #define LZ4F_HEADER_SIZE_MIN 7 /* LZ4 Frame header size can vary, depending on selected parameters */ #define LZ4F_HEADER_SIZE_MAX 19 /* Size in bytes of a block header in little-endian format. Highest bit indicates if block data is uncompressed */ #define LZ4F_BLOCK_HEADER_SIZE 4 /* Size in bytes of a block checksum footer in little-endian format. */ #define LZ4F_BLOCK_CHECKSUM_SIZE 4 /* Size in bytes of the content checksum. */ #define LZ4F_CONTENT_CHECKSUM_SIZE 4 /*! LZ4F_compressBegin() : * will write the frame header into dstBuffer. * dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes. * `prefsPtr` is optional : NULL can be provided to set all preferences to default. * @return : number of bytes written into dstBuffer for the header * or an error code (which can be tested using LZ4F_isError()) */ LZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_preferences_t* prefsPtr); /*! LZ4F_compressBound() : * Provides minimum dstCapacity required to guarantee success of * LZ4F_compressUpdate(), given a srcSize and preferences, for a worst case scenario. * When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() instead. * Note that the result is only valid for a single invocation of LZ4F_compressUpdate(). * When invoking LZ4F_compressUpdate() multiple times, * if the output buffer is gradually filled up instead of emptied and re-used from its start, * one must check if there is enough remaining capacity before each invocation, using LZ4F_compressBound(). * @return is always the same for a srcSize and prefsPtr. * prefsPtr is optional : when NULL is provided, preferences will be set to cover worst case scenario. * tech details : * @return if automatic flushing is not enabled, includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes. * It also includes frame footer (ending + checksum), since it might be generated by LZ4F_compressEnd(). * @return doesn't include frame header, as it was already generated by LZ4F_compressBegin(). */ LZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* prefsPtr); /*! LZ4F_compressUpdate() : * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary. * Important rule: dstCapacity MUST be large enough to ensure operation success even in worst case situations. * This value is provided by LZ4F_compressBound(). * If this condition is not respected, LZ4F_compress() will fail (result is an errorCode). * After an error, the state is left in a UB state, and must be re-initialized or freed. * If previously an uncompressed block was written, buffered data is flushed * before appending compressed data is continued. * `cOptPtr` is optional : NULL can be provided, in which case all options are set to default. * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered). * or an error code if it fails (which can be tested using LZ4F_isError()) */ LZ4FLIB_API size_t LZ4F_compressUpdate(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* cOptPtr); /*! LZ4F_flush() : * When data must be generated and sent immediately, without waiting for a block to be completely filled, * it's possible to call LZ4_flush(). It will immediately compress any data buffered within cctx. * `dstCapacity` must be large enough to ensure the operation will be successful. * `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default. * @return : nb of bytes written into dstBuffer (can be zero, when there is no data stored within cctx) * or an error code if it fails (which can be tested using LZ4F_isError()) * Note : LZ4F_flush() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr). */ LZ4FLIB_API size_t LZ4F_flush(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* cOptPtr); /*! LZ4F_compressEnd() : * To properly finish an LZ4 frame, invoke LZ4F_compressEnd(). * It will flush whatever data remained within `cctx` (like LZ4_flush()) * and properly finalize the frame, with an endMark and a checksum. * `cOptPtr` is optional : NULL can be provided, in which case all options will be set to default. * @return : nb of bytes written into dstBuffer, necessarily >= 4 (endMark), * or an error code if it fails (which can be tested using LZ4F_isError()) * Note : LZ4F_compressEnd() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr). * A successful call to LZ4F_compressEnd() makes `cctx` available again for another compression task. */ LZ4FLIB_API size_t LZ4F_compressEnd(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* cOptPtr); /*-********************************* * Decompression functions ***********************************/ typedef struct LZ4F_dctx_s LZ4F_dctx; /* incomplete type */ typedef LZ4F_dctx* LZ4F_decompressionContext_t; /* compatibility with previous API versions */ typedef struct { unsigned stableDst; /* pledges that last 64KB decompressed data will remain available unmodified between invocations. * This optimization skips storage operations in tmp buffers. */ unsigned skipChecksums; /* disable checksum calculation and verification, even when one is present in frame, to save CPU time. * Setting this option to 1 once disables all checksums for the rest of the frame. */ unsigned reserved1; /* must be set to zero for forward compatibility */ unsigned reserved0; /* idem */ } LZ4F_decompressOptions_t; /* Resource management */ /*! LZ4F_createDecompressionContext() : * Create an LZ4F_dctx object, to track all decompression operations. * @version provided MUST be LZ4F_VERSION. * @dctxPtr MUST be valid. * The function fills @dctxPtr with the value of a pointer to an allocated and initialized LZ4F_dctx object. * The @return is an errorCode, which can be tested using LZ4F_isError(). * dctx memory can be released using LZ4F_freeDecompressionContext(); * Result of LZ4F_freeDecompressionContext() indicates current state of decompressionContext when being released. * That is, it should be == 0 if decompression has been completed fully and correctly. */ LZ4FLIB_API LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** dctxPtr, unsigned version); LZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx); /*-*********************************** * Streaming decompression functions *************************************/ #define LZ4F_MAGICNUMBER 0x184D2204U #define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U #define LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH 5 /*! LZ4F_headerSize() : v1.9.0+ * Provide the header size of a frame starting at `src`. * `srcSize` must be >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH, * which is enough to decode the header length. * @return : size of frame header * or an error code, which can be tested using LZ4F_isError() * note : Frame header size is variable, but is guaranteed to be * >= LZ4F_HEADER_SIZE_MIN bytes, and <= LZ4F_HEADER_SIZE_MAX bytes. */ LZ4FLIB_API size_t LZ4F_headerSize(const void* src, size_t srcSize); /*! LZ4F_getFrameInfo() : * This function extracts frame parameters (max blockSize, dictID, etc.). * Its usage is optional: user can also invoke LZ4F_decompress() directly. * * Extracted information will fill an existing LZ4F_frameInfo_t structure. * This can be useful for allocation and dictionary identification purposes. * * LZ4F_getFrameInfo() can work in the following situations : * * 1) At the beginning of a new frame, before any invocation of LZ4F_decompress(). * It will decode header from `srcBuffer`, * consuming the header and starting the decoding process. * * Input size must be large enough to contain the full frame header. * Frame header size can be known beforehand by LZ4F_headerSize(). * Frame header size is variable, but is guaranteed to be >= LZ4F_HEADER_SIZE_MIN bytes, * and not more than <= LZ4F_HEADER_SIZE_MAX bytes. * Hence, blindly providing LZ4F_HEADER_SIZE_MAX bytes or more will always work. * It's allowed to provide more input data than the header size, * LZ4F_getFrameInfo() will only consume the header. * * If input size is not large enough, * aka if it's smaller than header size, * function will fail and return an error code. * * 2) After decoding has been started, * it's possible to invoke LZ4F_getFrameInfo() anytime * to extract already decoded frame parameters stored within dctx. * * Note that, if decoding has barely started, * and not yet read enough information to decode the header, * LZ4F_getFrameInfo() will fail. * * The number of bytes consumed from srcBuffer will be updated in *srcSizePtr (necessarily <= original value). * LZ4F_getFrameInfo() only consumes bytes when decoding has not yet started, * and when decoding the header has been successful. * Decompression must then resume from (srcBuffer + *srcSizePtr). * * @return : a hint about how many srcSize bytes LZ4F_decompress() expects for next call, * or an error code which can be tested using LZ4F_isError(). * note 1 : in case of error, dctx is not modified. Decoding operation can resume from beginning safely. * note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure. */ LZ4FLIB_API size_t LZ4F_getFrameInfo(LZ4F_dctx* dctx, LZ4F_frameInfo_t* frameInfoPtr, const void* srcBuffer, size_t* srcSizePtr); /*! LZ4F_decompress() : * Call this function repetitively to regenerate data compressed in `srcBuffer`. * * The function requires a valid dctx state. * It will read up to *srcSizePtr bytes from srcBuffer, * and decompress data into dstBuffer, of capacity *dstSizePtr. * * The nb of bytes consumed from srcBuffer will be written into *srcSizePtr (necessarily <= original value). * The nb of bytes decompressed into dstBuffer will be written into *dstSizePtr (necessarily <= original value). * * The function does not necessarily read all input bytes, so always check value in *srcSizePtr. * Unconsumed source data must be presented again in subsequent invocations. * * `dstBuffer` can freely change between each consecutive function invocation. * `dstBuffer` content will be overwritten. * * Note: if `LZ4F_getFrameInfo()` is called before `LZ4F_decompress()`, srcBuffer must be updated to reflect * the number of bytes consumed after reading the frame header. Failure to update srcBuffer before calling * `LZ4F_decompress()` will cause decompression failure or, even worse, successful but incorrect decompression. * See the `LZ4F_getFrameInfo()` docs for details. * * @return : an hint of how many `srcSize` bytes LZ4F_decompress() expects for next call. * Schematically, it's the size of the current (or remaining) compressed block + header of next block. * Respecting the hint provides some small speed benefit, because it skips intermediate buffers. * This is just a hint though, it's always possible to provide any srcSize. * * When a frame is fully decoded, @return will be 0 (no more data expected). * When provided with more bytes than necessary to decode a frame, * LZ4F_decompress() will stop reading exactly at end of current frame, and @return 0. * * If decompression failed, @return is an error code, which can be tested using LZ4F_isError(). * After a decompression error, the `dctx` context is not resumable. * Use LZ4F_resetDecompressionContext() to return to clean state. * * After a frame is fully decoded, dctx can be used again to decompress another frame. */ LZ4FLIB_API size_t LZ4F_decompress(LZ4F_dctx* dctx, void* dstBuffer, size_t* dstSizePtr, const void* srcBuffer, size_t* srcSizePtr, const LZ4F_decompressOptions_t* dOptPtr); /*! LZ4F_resetDecompressionContext() : added in v1.8.0 * In case of an error, the context is left in "undefined" state. * In which case, it's necessary to reset it, before re-using it. * This method can also be used to abruptly stop any unfinished decompression, * and start a new one using same context resources. */ LZ4FLIB_API void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx); /* always successful */ #if defined (__cplusplus) } #endif #endif /* LZ4F_H_09782039843 */ #if defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843) #define LZ4F_H_STATIC_09782039843 #if defined (__cplusplus) extern "C" { #endif /* These declarations are not stable and may change in the future. * They are therefore only safe to depend on * when the caller is statically linked against the library. * To access their declarations, define LZ4F_STATIC_LINKING_ONLY. * * By default, these symbols aren't published into shared/dynamic libraries. * You can override this behavior and force them to be published * by defining LZ4F_PUBLISH_STATIC_FUNCTIONS. * Use at your own risk. */ #ifdef LZ4F_PUBLISH_STATIC_FUNCTIONS # define LZ4FLIB_STATIC_API LZ4FLIB_API #else # define LZ4FLIB_STATIC_API #endif /* --- Error List --- */ #define LZ4F_LIST_ERRORS(ITEM) \ ITEM(OK_NoError) \ ITEM(ERROR_GENERIC) \ ITEM(ERROR_maxBlockSize_invalid) \ ITEM(ERROR_blockMode_invalid) \ ITEM(ERROR_contentChecksumFlag_invalid) \ ITEM(ERROR_compressionLevel_invalid) \ ITEM(ERROR_headerVersion_wrong) \ ITEM(ERROR_blockChecksum_invalid) \ ITEM(ERROR_reservedFlag_set) \ ITEM(ERROR_allocation_failed) \ ITEM(ERROR_srcSize_tooLarge) \ ITEM(ERROR_dstMaxSize_tooSmall) \ ITEM(ERROR_frameHeader_incomplete) \ ITEM(ERROR_frameType_unknown) \ ITEM(ERROR_frameSize_wrong) \ ITEM(ERROR_srcPtr_wrong) \ ITEM(ERROR_decompressionFailed) \ ITEM(ERROR_headerChecksum_invalid) \ ITEM(ERROR_contentChecksum_invalid) \ ITEM(ERROR_frameDecoding_alreadyStarted) \ ITEM(ERROR_compressionState_uninitialized) \ ITEM(ERROR_parameter_null) \ ITEM(ERROR_maxCode) #define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, /* enum list is exposed, to handle specific errors */ typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) _LZ4F_dummy_error_enum_for_c89_never_used } LZ4F_errorCodes; LZ4FLIB_STATIC_API LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult); /*! LZ4F_getBlockSize() : * Return, in scalar format (size_t), * the maximum block size associated with blockSizeID. **/ LZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID); /*! LZ4F_uncompressedUpdate() : * LZ4F_uncompressedUpdate() can be called repetitively to add as much data uncompressed data as necessary. * Important rule: dstCapacity MUST be large enough to store the entire source buffer as * no compression is done for this operation * If this condition is not respected, LZ4F_uncompressedUpdate() will fail (result is an errorCode). * After an error, the state is left in a UB state, and must be re-initialized or freed. * If previously a compressed block was written, buffered data is flushed * before appending uncompressed data is continued. * This is only supported when LZ4F_blockIndependent is used * `cOptPtr` is optional : NULL can be provided, in which case all options are set to default. * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered). * or an error code if it fails (which can be tested using LZ4F_isError()) */ LZ4FLIB_STATIC_API size_t LZ4F_uncompressedUpdate(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* cOptPtr); /********************************** * Bulk processing dictionary API *********************************/ /* A Dictionary is useful for the compression of small messages (KB range). * It dramatically improves compression efficiency. * * LZ4 can ingest any input as dictionary, though only the last 64 KB are useful. * Best results are generally achieved by using Zstandard's Dictionary Builder * to generate a high-quality dictionary from a set of samples. * * Loading a dictionary has a cost, since it involves construction of tables. * The Bulk processing dictionary API makes it possible to share this cost * over an arbitrary number of compression jobs, even concurrently, * markedly improving compression latency for these cases. * * The same dictionary will have to be used on the decompression side * for decoding to be successful. * To help identify the correct dictionary at decoding stage, * the frame header allows optional embedding of a dictID field. */ typedef struct LZ4F_CDict_s LZ4F_CDict; /*! LZ4_createCDict() : * When compressing multiple messages / blocks using the same dictionary, it's recommended to load it just once. * LZ4_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay. * LZ4_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only. * `dictBuffer` can be released after LZ4_CDict creation, since its content is copied within CDict */ LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize); LZ4FLIB_STATIC_API void LZ4F_freeCDict(LZ4F_CDict* CDict); /*! LZ4_compressFrame_usingCDict() : * Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary. * cctx must point to a context created by LZ4F_createCompressionContext(). * If cdict==NULL, compress without a dictionary. * dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr). * If this condition is not respected, function will fail (@return an errorCode). * The LZ4F_preferences_t structure is optional : you may provide NULL as argument, * but it's not recommended, as it's the only way to provide dictID in the frame header. * @return : number of bytes written into dstBuffer. * or an error code if it fails (can be tested using LZ4F_isError()) */ LZ4FLIB_STATIC_API size_t LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const LZ4F_CDict* cdict, const LZ4F_preferences_t* preferencesPtr); /*! LZ4F_compressBegin_usingCDict() : * Inits streaming dictionary compression, and writes the frame header into dstBuffer. * dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes. * `prefsPtr` is optional : you may provide NULL as argument, * however, it's the only way to provide dictID in the frame header. * @return : number of bytes written into dstBuffer for the header, * or an error code (which can be tested using LZ4F_isError()) */ LZ4FLIB_STATIC_API size_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_CDict* cdict, const LZ4F_preferences_t* prefsPtr); /*! LZ4F_decompress_usingDict() : * Same as LZ4F_decompress(), using a predefined dictionary. * Dictionary is used "in place", without any preprocessing. ** It must remain accessible throughout the entire frame decoding. */ LZ4FLIB_STATIC_API size_t LZ4F_decompress_usingDict(LZ4F_dctx* dctxPtr, void* dstBuffer, size_t* dstSizePtr, const void* srcBuffer, size_t* srcSizePtr, const void* dict, size_t dictSize, const LZ4F_decompressOptions_t* decompressOptionsPtr); /*! Custom memory allocation : v1.9.4+ * These prototypes make it possible to pass custom allocation/free functions. * LZ4F_customMem is provided at state creation time, using LZ4F_create*_advanced() listed below. * All allocation/free operations will be completed using these custom variants instead of regular ones. */ typedef void* (*LZ4F_AllocFunction) (void* opaqueState, size_t size); typedef void* (*LZ4F_CallocFunction) (void* opaqueState, size_t size); typedef void (*LZ4F_FreeFunction) (void* opaqueState, void* address); typedef struct { LZ4F_AllocFunction customAlloc; LZ4F_CallocFunction customCalloc; /* optional; when not defined, uses customAlloc + memset */ LZ4F_FreeFunction customFree; void* opaqueState; } LZ4F_CustomMem; static #ifdef __GNUC__ __attribute__((__unused__)) #endif LZ4F_CustomMem const LZ4F_defaultCMem = { NULL, NULL, NULL, NULL }; /**< this constant defers to stdlib's functions */ LZ4FLIB_STATIC_API LZ4F_cctx* LZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version); LZ4FLIB_STATIC_API LZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version); LZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict_advanced(LZ4F_CustomMem customMem, const void* dictBuffer, size_t dictSize); #if defined (__cplusplus) } #endif #endif /* defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843) */ ================================================ FILE: lib/LZ4F/lz4frame_static.h ================================================ /* LZ4 auto-framing library Header File for static linking only Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 source repository : https://github.com/lz4/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ #ifndef LZ4FRAME_STATIC_H_0398209384 #define LZ4FRAME_STATIC_H_0398209384 /* The declarations that formerly were made here have been merged into * lz4frame.h, protected by the LZ4F_STATIC_LINKING_ONLY macro. Going forward, * it is recommended to simply include that header directly. */ #define LZ4F_STATIC_LINKING_ONLY #include "lz4frame.h" #endif /* LZ4FRAME_STATIC_H_0398209384 */ ================================================ FILE: lib/LZ4F/lz4hc.c ================================================ /* LZ4 HC - High Compression Mode of LZ4 Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 source repository : https://github.com/lz4/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ /* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */ /* ************************************* * Tuning Parameter ***************************************/ /*! HEAPMODE : * Select how stateless HC compression functions like `LZ4_compress_HC()` * allocate memory for their workspace: * in stack (0:fastest), or in heap (1:default, requires malloc()). * Since workspace is rather large, heap mode is recommended. **/ #ifndef LZ4HC_HEAPMODE # define LZ4HC_HEAPMODE 1 #endif /*=== Dependency ===*/ #define LZ4_HC_STATIC_LINKING_ONLY #include "lz4hc.h" /*=== Common definitions ===*/ #if defined(__GNUC__) # pragma GCC diagnostic ignored "-Wunused-function" #endif #if defined (__clang__) # pragma clang diagnostic ignored "-Wunused-function" #endif #define LZ4_COMMONDEFS_ONLY #ifndef LZ4_SRC_INCLUDED #include "lz4.c" /* LZ4_count, constants, mem */ #endif /*=== Enums ===*/ typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive; /*=== Constants ===*/ #define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH) #define LZ4_OPT_NUM (1<<12) /*=== Macros ===*/ #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG)) #define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */ #define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */ /* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */ #define UPDATABLE(ip, op, anchor) &ip, &op, &anchor #define LZ4HC_HASHSIZE 4 static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); } /************************************** * HC Compression **************************************/ static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4) { MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable)); MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); } static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start) { size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart); size_t newStartingOffset = bufferSize + hc4->dictLimit; DEBUGLOG(5, "LZ4HC_init_internal"); assert(newStartingOffset >= bufferSize); /* check overflow */ if (newStartingOffset > 1 GB) { LZ4HC_clearTables(hc4); newStartingOffset = 0; } newStartingOffset += 64 KB; hc4->nextToUpdate = (U32)newStartingOffset; hc4->prefixStart = start; hc4->end = start; hc4->dictStart = start; hc4->dictLimit = (U32)newStartingOffset; hc4->lowLimit = (U32)newStartingOffset; } /* Update chains up to ip (excluded) */ LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) { U16* const chainTable = hc4->chainTable; U32* const hashTable = hc4->hashTable; const BYTE* const prefixPtr = hc4->prefixStart; U32 const prefixIdx = hc4->dictLimit; U32 const target = (U32)(ip - prefixPtr) + prefixIdx; U32 idx = hc4->nextToUpdate; assert(ip >= prefixPtr); assert(target >= prefixIdx); while (idx < target) { U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx); size_t delta = idx - hashTable[h]; if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX; DELTANEXTU16(chainTable, idx) = (U16)delta; hashTable[h] = idx; idx++; } hc4->nextToUpdate = target; } /** LZ4HC_countBack() : * @return : negative value, nb of common bytes before ip/match */ LZ4_FORCE_INLINE int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match, const BYTE* const iMin, const BYTE* const mMin) { int back = 0; int const min = (int)MAX(iMin - ip, mMin - match); assert(min <= 0); assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31)); assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31)); while ( (back > min) && (ip[back-1] == match[back-1]) ) back--; return back; } #if defined(_MSC_VER) # define LZ4HC_rotl32(x,r) _rotl(x,r) #else # define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r))) #endif static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern) { size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3; if (bitsToRotate == 0) return pattern; return LZ4HC_rotl32(pattern, (int)bitsToRotate); } /* LZ4HC_countPattern() : * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */ static unsigned LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32) { const BYTE* const iStart = ip; reg_t const pattern = (sizeof(pattern)==8) ? (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32; while (likely(ip < iEnd-(sizeof(pattern)-1))) { reg_t const diff = LZ4_read_ARCH(ip) ^ pattern; if (!diff) { ip+=sizeof(pattern); continue; } ip += LZ4_NbCommonBytes(diff); return (unsigned)(ip - iStart); } if (LZ4_isLittleEndian()) { reg_t patternByte = pattern; while ((ip>= 8; } } else { /* big endian */ U32 bitOffset = (sizeof(pattern)*8) - 8; while (ip < iEnd) { BYTE const byte = (BYTE)(pattern >> bitOffset); if (*ip != byte) break; ip ++; bitOffset -= 8; } } return (unsigned)(ip - iStart); } /* LZ4HC_reverseCountPattern() : * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) * read using natural platform endianness */ static unsigned LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern) { const BYTE* const iStart = ip; while (likely(ip >= iLow+4)) { if (LZ4_read32(ip-4) != pattern) break; ip -= 4; } { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */ while (likely(ip>iLow)) { if (ip[-1] != *bytePtr) break; ip--; bytePtr--; } } return (unsigned)(iStart - ip); } /* LZ4HC_protectDictEnd() : * Checks if the match is in the last 3 bytes of the dictionary, so reading the * 4 byte MINMATCH would overflow. * @returns true if the match index is okay. */ static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex) { return ((U32)((dictLimit - 1) - matchIndex) >= 3); } typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e; typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e; typedef struct { int off; int len; } LZ4HC_match_t; LZ4_FORCE_INLINE LZ4HC_match_t LZ4HC_InsertAndGetWiderMatch ( LZ4HC_CCtx_internal* const hc4, const BYTE* const ip, const BYTE* const iLowLimit, const BYTE* const iHighLimit, int longest, const BYTE** startpos, const int maxNbAttempts, const int patternAnalysis, const int chainSwap, const dictCtx_directive dict, const HCfavor_e favorDecSpeed) { U16* const chainTable = hc4->chainTable; U32* const hashTable = hc4->hashTable; const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx; const BYTE* const prefixPtr = hc4->prefixStart; const U32 prefixIdx = hc4->dictLimit; const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx; const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex); const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX; const BYTE* const dictStart = hc4->dictStart; const U32 dictIdx = hc4->lowLimit; const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx; int const lookBackLength = (int)(ip-iLowLimit); int nbAttempts = maxNbAttempts; U32 matchChainPos = 0; U32 const pattern = LZ4_read32(ip); U32 matchIndex; repeat_state_e repeat = rep_untested; size_t srcPatternLength = 0; int offset = 0; DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch"); assert(startpos != NULL); *startpos = ip; /* in case there is no solution */ /* First Match */ LZ4HC_Insert(hc4, ip); /* insert all prior positions up to ip (excluded) */ matchIndex = hashTable[LZ4HC_hashPtr(ip)]; DEBUGLOG(7, "First candidate match for pos %u found at index %u / %u (lowestMatchIndex)", ipIndex, matchIndex, lowestMatchIndex); while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) { int matchLength=0; nbAttempts--; assert(matchIndex < ipIndex); if (favorDecSpeed && (ipIndex - matchIndex < 8)) { /* do nothing: * favorDecSpeed intentionally skips matches with offset < 8 */ } else if (matchIndex >= prefixIdx) { /* within current Prefix */ const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx); assert(matchPtr < ip); assert(longest >= 1); if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) { if (LZ4_read32(matchPtr) == pattern) { int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0; matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); matchLength -= back; if (matchLength > longest) { longest = matchLength; offset = (int)(ipIndex - matchIndex); *startpos = ip + back; DEBUGLOG(7, "Found match of len=%i within prefix, offset=%i, back=%i", longest, offset, -back); } } } } else { /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */ const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx); assert(matchIndex >= dictIdx); if ( likely(matchIndex <= prefixIdx - 4) && (LZ4_read32(matchPtr) == pattern) ) { int back = 0; const BYTE* vLimit = ip + (prefixIdx - matchIndex); if (vLimit > iHighLimit) vLimit = iHighLimit; matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; if ((ip+matchLength == vLimit) && (vLimit < iHighLimit)) matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit); back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0; matchLength -= back; if (matchLength > longest) { longest = matchLength; offset = (int)(ipIndex - matchIndex); *startpos = ip + back; DEBUGLOG(7, "Found match of len=%i within dict, offset=%i, back=%i", longest, offset, -back); } } } if (chainSwap && matchLength==longest) { /* better match => select a better chain */ assert(lookBackLength==0); /* search forward only */ if (matchIndex + (U32)longest <= ipIndex) { int const kTrigger = 4; U32 distanceToNextMatch = 1; int const end = longest - MINMATCH + 1; int step = 1; int accel = 1 << kTrigger; int pos; for (pos = 0; pos < end; pos += step) { U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos); step = (accel++ >> kTrigger); if (candidateDist > distanceToNextMatch) { distanceToNextMatch = candidateDist; matchChainPos = (U32)pos; accel = 1 << kTrigger; } } if (distanceToNextMatch > 1) { if (distanceToNextMatch > matchIndex) break; /* avoid overflow */ matchIndex -= distanceToNextMatch; continue; } } } { U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex); if (patternAnalysis && distNextMatch==1 && matchChainPos==0) { U32 const matchCandidateIdx = matchIndex-1; /* may be a repeated pattern */ if (repeat == rep_untested) { if ( ((pattern & 0xFFFF) == (pattern >> 16)) & ((pattern & 0xFF) == (pattern >> 24)) ) { DEBUGLOG(7, "Repeat pattern detected, char %02X", pattern >> 24); repeat = rep_confirmed; srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern); } else { repeat = rep_not; } } if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex) && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) { const int extDict = matchCandidateIdx < prefixIdx; const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx); if (LZ4_read32(matchPtr) == pattern) { /* good candidate */ const BYTE* const iLimit = extDict ? dictEnd : iHighLimit; size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern); if (extDict && matchPtr + forwardPatternLength == iLimit) { U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern); forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern); } { const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr; size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern); size_t currentSegmentLength; if (!extDict && matchPtr - backLength == prefixPtr && dictIdx < prefixIdx) { U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern); backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern); } /* Limit backLength not go further than lowestMatchIndex */ backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex); assert(matchCandidateIdx - backLength >= lowestMatchIndex); currentSegmentLength = backLength + forwardPatternLength; /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */ if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */ && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */ U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */ if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) matchIndex = newMatchIndex; else { /* Can only happen if started in the prefix */ assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict); matchIndex = prefixIdx; } } else { U32 const newMatchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */ if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) { assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict); matchIndex = prefixIdx; } else { matchIndex = newMatchIndex; if (lookBackLength==0) { /* no back possible */ size_t const maxML = MIN(currentSegmentLength, srcPatternLength); if ((size_t)longest < maxML) { assert(prefixPtr - prefixIdx + matchIndex != ip); if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break; assert(maxML < 2 GB); longest = (int)maxML; offset = (int)(ipIndex - matchIndex); *startpos = ip; DEBUGLOG(7, "Found repeat pattern match of len=%i, offset=%i", longest, offset); } { U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex); if (distToNextPattern > matchIndex) break; /* avoid overflow */ matchIndex -= distToNextPattern; } } } } } continue; } } } } /* PA optimization */ /* follow current chain */ matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos); } /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */ if ( dict == usingDictCtxHc && nbAttempts > 0 && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) { size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit; U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)]; assert(dictEndOffset <= 1 GB); matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset; if (dictMatchIndex>0) DEBUGLOG(7, "dictEndOffset = %zu, dictMatchIndex = %u => relative matchIndex = %i", dictEndOffset, dictMatchIndex, (int)dictMatchIndex - (int)dictEndOffset); while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) { const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex; if (LZ4_read32(matchPtr) == pattern) { int mlt; int back = 0; const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex); if (vLimit > iHighLimit) vLimit = iHighLimit; mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0; mlt -= back; if (mlt > longest) { longest = mlt; offset = (int)(ipIndex - matchIndex); *startpos = ip + back; DEBUGLOG(7, "found match of length %i within extDictCtx", longest); } } { U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex); dictMatchIndex -= nextOffset; matchIndex -= nextOffset; } } } { LZ4HC_match_t md; assert(longest >= 0); md.len = longest; md.off = offset; return md; } } LZ4_FORCE_INLINE LZ4HC_match_t LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */ const BYTE* const ip, const BYTE* const iLimit, const int maxNbAttempts, const int patternAnalysis, const dictCtx_directive dict) { const BYTE* uselessPtr = ip; DEBUGLOG(7, "LZ4HC_InsertAndFindBestMatch"); /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), * but this won't be the case here, as we define iLowLimit==ip, * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */ return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio); } /* LZ4HC_encodeSequence() : * @return : 0 if ok, * 1 if buffer issue detected */ LZ4_FORCE_INLINE int LZ4HC_encodeSequence ( const BYTE** _ip, BYTE** _op, const BYTE** _anchor, int matchLength, int offset, limitedOutput_directive limit, BYTE* oend) { #define ip (*_ip) #define op (*_op) #define anchor (*_anchor) size_t length; BYTE* const token = op++; #if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6) static const BYTE* start = NULL; static U32 totalCost = 0; U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start); U32 const ll = (U32)(ip - anchor); U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0; U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0; U32 const cost = 1 + llAdd + ll + 2 + mlAdd; if (start==NULL) start = anchor; /* only works for single segment */ /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */ DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5i, cost:%4u + %5u", pos, (U32)(ip - anchor), matchLength, offset, cost, totalCost); totalCost += cost; #endif /* Encode Literal length */ length = (size_t)(ip - anchor); LZ4_STATIC_ASSERT(notLimited == 0); /* Check output limit */ if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) { DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)", (int)length, (int)(oend - op)); return 1; } if (length >= RUN_MASK) { size_t len = length - RUN_MASK; *token = (RUN_MASK << ML_BITS); for(; len >= 255 ; len -= 255) *op++ = 255; *op++ = (BYTE)len; } else { *token = (BYTE)(length << ML_BITS); } /* Copy Literals */ LZ4_wildCopy8(op, anchor, op + length); op += length; /* Encode Offset */ assert(offset <= LZ4_DISTANCE_MAX ); assert(offset > 0); LZ4_writeLE16(op, (U16)(offset)); op += 2; /* Encode MatchLength */ assert(matchLength >= MINMATCH); length = (size_t)matchLength - MINMATCH; if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) { DEBUGLOG(6, "Not enough room to write match length"); return 1; /* Check output limit */ } if (length >= ML_MASK) { *token += ML_MASK; length -= ML_MASK; for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; } if (length >= 255) { length -= 255; *op++ = 255; } *op++ = (BYTE)length; } else { *token += (BYTE)(length); } /* Prepare next loop */ ip += matchLength; anchor = ip; return 0; } #undef ip #undef op #undef anchor LZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( LZ4HC_CCtx_internal* const ctx, const char* const source, char* const dest, int* srcSizePtr, int const maxOutputSize, int maxNbAttempts, const limitedOutput_directive limit, const dictCtx_directive dict ) { const int inputSize = *srcSizePtr; const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */ const BYTE* ip = (const BYTE*) source; const BYTE* anchor = ip; const BYTE* const iend = ip + inputSize; const BYTE* const mflimit = iend - MFLIMIT; const BYTE* const matchlimit = (iend - LASTLITERALS); BYTE* optr = (BYTE*) dest; BYTE* op = (BYTE*) dest; BYTE* oend = op + maxOutputSize; const BYTE* start0; const BYTE* start2 = NULL; const BYTE* start3 = NULL; LZ4HC_match_t m0, m1, m2, m3; const LZ4HC_match_t nomatch = {0, 0}; /* init */ DEBUGLOG(5, "LZ4HC_compress_hashChain (dict?=>%i)", dict); *srcSizePtr = 0; if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ /* Main Loop */ while (ip <= mflimit) { m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict); if (m1.len encode ML1 immediately */ optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend)) goto _dest_overflow; continue; } if (start0 < ip) { /* first match was skipped at least once */ if (start2 < ip + m0.len) { /* squeezing ML1 between ML0(original ML1) and ML2 */ ip = start0; m1 = m0; /* restore initial Match1 */ } } /* Here, start0==ip */ if ((start2 - ip) < 3) { /* First Match too small : removed */ ip = start2; m1 = m2; goto _Search2; } _Search3: if ((start2 - ip) < OPTIMAL_ML) { int correction; int new_ml = m1.len; if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; if (ip+new_ml > start2 + m2.len - MINMATCH) new_ml = (int)(start2 - ip) + m2.len - MINMATCH; correction = new_ml - (int)(start2 - ip); if (correction > 0) { start2 += correction; m2.len -= correction; } } if (start2 + m2.len <= mflimit) { m3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + m2.len - 3, start2, matchlimit, m2.len, &start3, maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio); } else { m3 = nomatch; /* do not search further */ } if (m3.len <= m2.len) { /* No better match => encode ML1 and ML2 */ /* ip & ref are known; Now for ml */ if (start2 < ip+m1.len) m1.len = (int)(start2 - ip); /* Now, encode 2 sequences */ optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend)) goto _dest_overflow; ip = start2; optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m2.len, m2.off, limit, oend)) { m1 = m2; goto _dest_overflow; } continue; } if (start3 < ip+m1.len+3) { /* Not enough space for match 2 : remove it */ if (start3 >= (ip+m1.len)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */ if (start2 < ip+m1.len) { int correction = (int)(ip+m1.len - start2); start2 += correction; m2.len -= correction; if (m2.len < MINMATCH) { start2 = start3; m2 = m3; } } optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend)) goto _dest_overflow; ip = start3; m1 = m3; start0 = start2; m0 = m2; goto _Search2; } start2 = start3; m2 = m3; goto _Search3; } /* * OK, now we have 3 ascending matches; * let's write the first one ML1. * ip & ref are known; Now decide ml. */ if (start2 < ip+m1.len) { if ((start2 - ip) < OPTIMAL_ML) { int correction; if (m1.len > OPTIMAL_ML) m1.len = OPTIMAL_ML; if (ip + m1.len > start2 + m2.len - MINMATCH) m1.len = (int)(start2 - ip) + m2.len - MINMATCH; correction = m1.len - (int)(start2 - ip); if (correction > 0) { start2 += correction; m2.len -= correction; } } else { m1.len = (int)(start2 - ip); } } optr = op; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend)) goto _dest_overflow; /* ML2 becomes ML1 */ ip = start2; m1 = m2; /* ML3 becomes ML2 */ start2 = start3; m2 = m3; /* let's find a new ML3 */ goto _Search3; } _last_literals: /* Encode Last Literals */ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */ size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255; size_t const totalSize = 1 + llAdd + lastRunSize; if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit && (op + totalSize > oend)) { if (limit == limitedOutput) return 0; /* adapt lastRunSize to fill 'dest' */ lastRunSize = (size_t)(oend - op) - 1 /*token*/; llAdd = (lastRunSize + 256 - RUN_MASK) / 256; lastRunSize -= llAdd; } DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize); ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */ if (lastRunSize >= RUN_MASK) { size_t accumulator = lastRunSize - RUN_MASK; *op++ = (RUN_MASK << ML_BITS); for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255; *op++ = (BYTE) accumulator; } else { *op++ = (BYTE)(lastRunSize << ML_BITS); } LZ4_memcpy(op, anchor, lastRunSize); op += lastRunSize; } /* End */ *srcSizePtr = (int) (((const char*)ip) - source); return (int) (((char*)op)-dest); _dest_overflow: if (limit == fillOutput) { /* Assumption : ip, anchor, ml and ref must be set correctly */ size_t const ll = (size_t)(ip - anchor); size_t const ll_addbytes = (ll + 240) / 255; size_t const ll_totalCost = 1 + ll_addbytes + ll; BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */ DEBUGLOG(6, "Last sequence overflowing"); op = optr; /* restore correct out pointer */ if (op + ll_totalCost <= maxLitPos) { /* ll validated; now adjust match length */ size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost)); size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255); assert(maxMlSize < INT_MAX); assert(m1.len >= 0); if ((size_t)m1.len > maxMlSize) m1.len = (int)maxMlSize; if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + m1.len >= MFLIMIT) { LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, notLimited, oend); } } goto _last_literals; } /* compression failed */ return 0; } static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx, const char* const source, char* dst, int* srcSizePtr, int dstCapacity, int const nbSearches, size_t sufficient_len, const limitedOutput_directive limit, int const fullUpdate, const dictCtx_directive dict, const HCfavor_e favorDecSpeed); LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal ( LZ4HC_CCtx_internal* const ctx, const char* const src, char* const dst, int* const srcSizePtr, int const dstCapacity, int cLevel, const limitedOutput_directive limit, const dictCtx_directive dict ) { typedef enum { lz4hc, lz4opt } lz4hc_strat_e; typedef struct { lz4hc_strat_e strat; int nbSearches; U32 targetLength; } cParams_t; static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = { { lz4hc, 2, 16 }, /* 0, unused */ { lz4hc, 2, 16 }, /* 1, unused */ { lz4hc, 2, 16 }, /* 2, unused */ { lz4hc, 4, 16 }, /* 3 */ { lz4hc, 8, 16 }, /* 4 */ { lz4hc, 16, 16 }, /* 5 */ { lz4hc, 32, 16 }, /* 6 */ { lz4hc, 64, 16 }, /* 7 */ { lz4hc, 128, 16 }, /* 8 */ { lz4hc, 256, 16 }, /* 9 */ { lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/ { lz4opt, 512,128 }, /*11 */ { lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */ }; DEBUGLOG(5, "LZ4HC_compress_generic_internal(src=%p, srcSize=%d)", src, *srcSizePtr); if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */ if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */ ctx->end += *srcSizePtr; if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */ cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel); { cParams_t const cParam = clTable[cLevel]; HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio; int result; if (cParam.strat == lz4hc) { result = LZ4HC_compress_hashChain(ctx, src, dst, srcSizePtr, dstCapacity, cParam.nbSearches, limit, dict); } else { assert(cParam.strat == lz4opt); result = LZ4HC_compress_optimal(ctx, src, dst, srcSizePtr, dstCapacity, cParam.nbSearches, cParam.targetLength, limit, cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */ dict, favor); } if (result <= 0) ctx->dirty = 1; return result; } } static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock); static int LZ4HC_compress_generic_noDictCtx ( LZ4HC_CCtx_internal* const ctx, const char* const src, char* const dst, int* const srcSizePtr, int const dstCapacity, int cLevel, limitedOutput_directive limit ) { assert(ctx->dictCtx == NULL); return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx); } static int LZ4HC_compress_generic_dictCtx ( LZ4HC_CCtx_internal* const ctx, const char* const src, char* const dst, int* const srcSizePtr, int const dstCapacity, int cLevel, limitedOutput_directive limit ) { const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit); assert(ctx->dictCtx != NULL); if (position >= 64 KB) { ctx->dictCtx = NULL; return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); } else if (position == 0 && *srcSizePtr > 4 KB) { LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal)); LZ4HC_setExternalDict(ctx, (const BYTE *)src); ctx->compressionLevel = (short)cLevel; return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); } else { return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc); } } static int LZ4HC_compress_generic ( LZ4HC_CCtx_internal* const ctx, const char* const src, char* const dst, int* const srcSizePtr, int const dstCapacity, int cLevel, limitedOutput_directive limit ) { if (ctx->dictCtx == NULL) { return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); } else { return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); } } int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); } static size_t LZ4_streamHC_t_alignment(void) { #if LZ4_ALIGN_TEST typedef struct { char c; LZ4_streamHC_t t; } t_a; return sizeof(t_a) - sizeof(LZ4_streamHC_t); #else return 1; /* effectively disabled */ #endif } /* state is presumed correctly initialized, * in which case its size and alignment have already been validate */ int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) { LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0; LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel); LZ4HC_init_internal (ctx, (const BYTE*)src); if (dstCapacity < LZ4_compressBound(srcSize)) return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput); else return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited); } int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) { LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); if (ctx==NULL) return 0; /* init failure */ return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel); } int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) { int cSize; #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t)); if (statePtr==NULL) return 0; #else LZ4_streamHC_t state; LZ4_streamHC_t* const statePtr = &state; #endif DEBUGLOG(5, "LZ4_compress_HC") cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel); #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 FREEMEM(statePtr); #endif return cSize; } /* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */ int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel) { LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); if (ctx==NULL) return 0; /* init failure */ LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source); LZ4_setCompressionLevel(ctx, cLevel); return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput); } /************************************** * Streaming Functions **************************************/ /* allocation */ #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_streamHC_t* LZ4_createStreamHC(void) { LZ4_streamHC_t* const state = (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t)); if (state == NULL) return NULL; LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT); return state; } int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr); if (!LZ4_streamHCPtr) return 0; /* support free on NULL */ FREEMEM(LZ4_streamHCPtr); return 0; } #endif LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size) { LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer; DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size); /* check conditions */ if (buffer == NULL) return NULL; if (size < sizeof(LZ4_streamHC_t)) return NULL; if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL; /* init */ { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse); MEM_INIT(hcstate, 0, sizeof(*hcstate)); } LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT); return LZ4_streamHCPtr; } /* just a stub */ void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) { LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel); } void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) { LZ4HC_CCtx_internal* const s = &LZ4_streamHCPtr->internal_donotuse; DEBUGLOG(5, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel); if (s->dirty) { LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); } else { assert(s->end >= s->prefixStart); s->dictLimit += (U32)(s->end - s->prefixStart); s->prefixStart = NULL; s->end = NULL; s->dictCtx = NULL; } LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel); } void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) { DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel); if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT; if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX; LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel; } void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor) { LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0); } /* LZ4_loadDictHC() : * LZ4_streamHCPtr is presumed properly initialized */ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize) { LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize); assert(LZ4_streamHCPtr != NULL); if (dictSize > 64 KB) { dictionary += (size_t)dictSize - 64 KB; dictSize = 64 KB; } /* need a full initialization, there are bad side-effects when using resetFast() */ { int const cLevel = ctxPtr->compressionLevel; LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel); } LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary); ctxPtr->end = (const BYTE*)dictionary + dictSize; if (dictSize >= LZ4HC_HASHSIZE) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); return dictSize; } void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) { working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL; } /* compression */ static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) { DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock); if (ctxPtr->end >= ctxPtr->prefixStart + 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ /* Only one memory segment for extDict, so any previous extDict is lost at this stage */ ctxPtr->lowLimit = ctxPtr->dictLimit; ctxPtr->dictStart = ctxPtr->prefixStart; ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart); ctxPtr->prefixStart = newBlock; ctxPtr->end = newBlock; ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */ /* cannot reference an extDict and a dictCtx at the same time */ ctxPtr->dictCtx = NULL; } static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int dstCapacity, limitedOutput_directive limit) { LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)", LZ4_streamHCPtr, src, *srcSizePtr, limit); assert(ctxPtr != NULL); /* auto-init if forgotten */ if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src); /* Check overflow */ if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) { size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart); if (dictSize > 64 KB) dictSize = 64 KB; LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize); } /* Check if blocks follow each other */ if ((const BYTE*)src != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src); /* Check overlapping input/dictionary space */ { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr; const BYTE* const dictBegin = ctxPtr->dictStart; const BYTE* const dictEnd = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit); if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) { if (sourceEnd > dictEnd) sourceEnd = dictEnd; ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart); ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart); /* invalidate dictionary is it's too small */ if (ctxPtr->dictLimit - ctxPtr->lowLimit < LZ4HC_HASHSIZE) { ctxPtr->lowLimit = ctxPtr->dictLimit; ctxPtr->dictStart = ctxPtr->prefixStart; } } } return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit); } int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity) { DEBUGLOG(5, "LZ4_compress_HC_continue"); if (dstCapacity < LZ4_compressBound(srcSize)) return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput); else return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited); } int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize) { return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput); } /* LZ4_saveDictHC : * save history content * into a user-provided buffer * which is then used to continue compression */ int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize) { LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart); DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize); assert(prefixSize >= 0); if (dictSize > 64 KB) dictSize = 64 KB; if (dictSize < 4) dictSize = 0; if (dictSize > prefixSize) dictSize = prefixSize; if (safeBuffer == NULL) assert(dictSize == 0); if (dictSize > 0) LZ4_memmove(safeBuffer, streamPtr->end - dictSize, (size_t)dictSize); { U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit; streamPtr->end = (safeBuffer == NULL) ? NULL : (const BYTE*)safeBuffer + dictSize; streamPtr->prefixStart = (const BYTE*)safeBuffer; streamPtr->dictLimit = endIndex - (U32)dictSize; streamPtr->lowLimit = endIndex - (U32)dictSize; streamPtr->dictStart = streamPtr->prefixStart; if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit; } return dictSize; } /*************************************************** * Deprecated Functions ***************************************************/ /* These functions currently generate deprecation warnings */ /* Wrappers for deprecated compression functions */ int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); } int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); } int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); } int LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); } int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); } int LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); } int LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); } int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); } /* Deprecated streaming functions */ int LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); } /* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t) * @return : 0 on success, !=0 if error */ int LZ4_resetStreamStateHC(void* state, char* inputBuffer) { LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4)); if (hc4 == NULL) return 1; /* init failed */ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer); return 0; } #if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) void* LZ4_createHC (const char* inputBuffer) { LZ4_streamHC_t* const hc4 = LZ4_createStreamHC(); if (hc4 == NULL) return NULL; /* not enough memory */ LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer); return hc4; } int LZ4_freeHC (void* LZ4HC_Data) { if (!LZ4HC_Data) return 0; /* support free on NULL */ FREEMEM(LZ4HC_Data); return 0; } #endif int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel) { return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited); } int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel) { return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput); } char* LZ4_slideInputBufferHC(void* LZ4HC_Data) { LZ4HC_CCtx_internal* const s = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse; const BYTE* const bufferStart = s->prefixStart - s->dictLimit + s->lowLimit; LZ4_resetStreamHC_fast((LZ4_streamHC_t*)LZ4HC_Data, s->compressionLevel); /* ugly conversion trick, required to evade (const char*) -> (char*) cast-qual warning :( */ return (char*)(uptrval)bufferStart; } /* ================================================ * LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX]) * ===============================================*/ typedef struct { int price; int off; int mlen; int litlen; } LZ4HC_optimal_t; /* price in bytes */ LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen) { int price = litlen; assert(litlen >= 0); if (litlen >= (int)RUN_MASK) price += 1 + ((litlen-(int)RUN_MASK) / 255); return price; } /* requires mlen >= MINMATCH */ LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen) { int price = 1 + 2 ; /* token + 16-bit offset */ assert(litlen >= 0); assert(mlen >= MINMATCH); price += LZ4HC_literalsPrice(litlen); if (mlen >= (int)(ML_MASK+MINMATCH)) price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255); return price; } LZ4_FORCE_INLINE LZ4HC_match_t LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx, const BYTE* ip, const BYTE* const iHighLimit, int minLen, int nbSearches, const dictCtx_directive dict, const HCfavor_e favorDecSpeed) { LZ4HC_match_t const match0 = { 0 , 0 }; /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), * but this won't be the case here, as we define iLowLimit==ip, ** so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */ LZ4HC_match_t md = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed); if (md.len <= minLen) return match0; if (favorDecSpeed) { if ((md.len>18) & (md.len<=36)) md.len=18; /* favor shortcut */ } return md; } static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, const char* const source, char* dst, int* srcSizePtr, int dstCapacity, int const nbSearches, size_t sufficient_len, const limitedOutput_directive limit, int const fullUpdate, const dictCtx_directive dict, const HCfavor_e favorDecSpeed) { int retval = 0; #define TRAILING_LITERALS 3 #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS)); #else LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */ #endif const BYTE* ip = (const BYTE*) source; const BYTE* anchor = ip; const BYTE* const iend = ip + *srcSizePtr; const BYTE* const mflimit = iend - MFLIMIT; const BYTE* const matchlimit = iend - LASTLITERALS; BYTE* op = (BYTE*) dst; BYTE* opSaved = (BYTE*) dst; BYTE* oend = op + dstCapacity; int ovml = MINMATCH; /* overflow - last sequence */ int ovoff = 0; /* init */ #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 if (opt == NULL) goto _return_label; #endif DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity); *srcSizePtr = 0; if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1; /* Main Loop */ while (ip <= mflimit) { int const llen = (int)(ip - anchor); int best_mlen, best_off; int cur, last_match_pos = 0; LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed); if (firstMatch.len==0) { ip++; continue; } if ((size_t)firstMatch.len > sufficient_len) { /* good enough solution : immediate encoding */ int const firstML = firstMatch.len; opSaved = op; if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, firstMatch.off, limit, oend) ) { /* updates ip, op and anchor */ ovml = firstML; ovoff = firstMatch.off; goto _dest_overflow; } continue; } /* set prices for first positions (literals) */ { int rPos; for (rPos = 0 ; rPos < MINMATCH ; rPos++) { int const cost = LZ4HC_literalsPrice(llen + rPos); opt[rPos].mlen = 1; opt[rPos].off = 0; opt[rPos].litlen = llen + rPos; opt[rPos].price = cost; DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup", rPos, cost, opt[rPos].litlen); } } /* set prices using initial match */ { int mlen = MINMATCH; int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */ int const offset = firstMatch.off; assert(matchML < LZ4_OPT_NUM); for ( ; mlen <= matchML ; mlen++) { int const cost = LZ4HC_sequencePrice(llen, mlen); opt[mlen].mlen = mlen; opt[mlen].off = offset; opt[mlen].litlen = llen; opt[mlen].price = cost; DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup", mlen, cost, mlen); } } last_match_pos = firstMatch.len; { int addLit; for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) { opt[last_match_pos+addLit].mlen = 1; /* literal */ opt[last_match_pos+addLit].off = 0; opt[last_match_pos+addLit].litlen = addLit; opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit); DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit); } } /* check further positions */ for (cur = 1; cur < last_match_pos; cur++) { const BYTE* const curPtr = ip + cur; LZ4HC_match_t newMatch; if (curPtr > mflimit) break; DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u", cur, opt[cur].price, opt[cur+1].price, cur+1); if (fullUpdate) { /* not useful to search here if next position has same (or lower) cost */ if ( (opt[cur+1].price <= opt[cur].price) /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */ && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) ) continue; } else { /* not useful to search here if next position has same (or lower) cost */ if (opt[cur+1].price <= opt[cur].price) continue; } DEBUGLOG(7, "search at rPos:%u", cur); if (fullUpdate) newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed); else /* only test matches of minimum length; slightly faster, but misses a few bytes */ newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed); if (!newMatch.len) continue; if ( ((size_t)newMatch.len > sufficient_len) || (newMatch.len + cur >= LZ4_OPT_NUM) ) { /* immediate encoding */ best_mlen = newMatch.len; best_off = newMatch.off; last_match_pos = cur + 1; goto encode; } /* before match : set price with literals at beginning */ { int const baseLitlen = opt[cur].litlen; int litlen; for (litlen = 1; litlen < MINMATCH; litlen++) { int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen); int const pos = cur + litlen; if (price < opt[pos].price) { opt[pos].mlen = 1; /* literal */ opt[pos].off = 0; opt[pos].litlen = baseLitlen+litlen; opt[pos].price = price; DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", pos, price, opt[pos].litlen); } } } /* set prices using match at position = cur */ { int const matchML = newMatch.len; int ml = MINMATCH; assert(cur + newMatch.len < LZ4_OPT_NUM); for ( ; ml <= matchML ; ml++) { int const pos = cur + ml; int const offset = newMatch.off; int price; int ll; DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)", pos, last_match_pos); if (opt[cur].mlen == 1) { ll = opt[cur].litlen; price = ((cur > ll) ? opt[cur - ll].price : 0) + LZ4HC_sequencePrice(ll, ml); } else { ll = 0; price = opt[cur].price + LZ4HC_sequencePrice(0, ml); } assert((U32)favorDecSpeed <= 1); if (pos > last_match_pos+TRAILING_LITERALS || price <= opt[pos].price - (int)favorDecSpeed) { DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)", pos, price, ml); assert(pos < LZ4_OPT_NUM); if ( (ml == matchML) /* last pos of last match */ && (last_match_pos < pos) ) last_match_pos = pos; opt[pos].mlen = ml; opt[pos].off = offset; opt[pos].litlen = ll; opt[pos].price = price; } } } /* complete following positions with literals */ { int addLit; for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) { opt[last_match_pos+addLit].mlen = 1; /* literal */ opt[last_match_pos+addLit].off = 0; opt[last_match_pos+addLit].litlen = addLit; opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit); DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit); } } } /* for (cur = 1; cur <= last_match_pos; cur++) */ assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS); best_mlen = opt[last_match_pos].mlen; best_off = opt[last_match_pos].off; cur = last_match_pos - best_mlen; encode: /* cur, last_match_pos, best_mlen, best_off must be set */ assert(cur < LZ4_OPT_NUM); assert(last_match_pos >= 1); /* == 1 when only one candidate */ DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos); { int candidate_pos = cur; int selected_matchLength = best_mlen; int selected_offset = best_off; while (1) { /* from end to beginning */ int const next_matchLength = opt[candidate_pos].mlen; /* can be 1, means literal */ int const next_offset = opt[candidate_pos].off; DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength); opt[candidate_pos].mlen = selected_matchLength; opt[candidate_pos].off = selected_offset; selected_matchLength = next_matchLength; selected_offset = next_offset; if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */ assert(next_matchLength > 0); /* can be 1, means literal */ candidate_pos -= next_matchLength; } } /* encode all recorded sequences in order */ { int rPos = 0; /* relative position (to ip) */ while (rPos < last_match_pos) { int const ml = opt[rPos].mlen; int const offset = opt[rPos].off; if (ml == 1) { ip++; rPos++; continue; } /* literal; note: can end up with several literals, in which case, skip them */ rPos += ml; assert(ml >= MINMATCH); assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX)); opSaved = op; if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) { /* updates ip, op and anchor */ ovml = ml; ovoff = offset; goto _dest_overflow; } } } } /* while (ip <= mflimit) */ _last_literals: /* Encode Last Literals */ { size_t lastRunSize = (size_t)(iend - anchor); /* literals */ size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255; size_t const totalSize = 1 + llAdd + lastRunSize; if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit && (op + totalSize > oend)) { if (limit == limitedOutput) { /* Check output limit */ retval = 0; goto _return_label; } /* adapt lastRunSize to fill 'dst' */ lastRunSize = (size_t)(oend - op) - 1 /*token*/; llAdd = (lastRunSize + 256 - RUN_MASK) / 256; lastRunSize -= llAdd; } DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize); ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */ if (lastRunSize >= RUN_MASK) { size_t accumulator = lastRunSize - RUN_MASK; *op++ = (RUN_MASK << ML_BITS); for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255; *op++ = (BYTE) accumulator; } else { *op++ = (BYTE)(lastRunSize << ML_BITS); } LZ4_memcpy(op, anchor, lastRunSize); op += lastRunSize; } /* End */ *srcSizePtr = (int) (((const char*)ip) - source); retval = (int) ((char*)op-dst); goto _return_label; _dest_overflow: if (limit == fillOutput) { /* Assumption : ip, anchor, ovml and ovref must be set correctly */ size_t const ll = (size_t)(ip - anchor); size_t const ll_addbytes = (ll + 240) / 255; size_t const ll_totalCost = 1 + ll_addbytes + ll; BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */ DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved)); op = opSaved; /* restore correct out pointer */ if (op + ll_totalCost <= maxLitPos) { /* ll validated; now adjust match length */ size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost)); size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255); assert(maxMlSize < INT_MAX); assert(ovml >= 0); if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize; if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) { DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml); DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor); LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovoff, notLimited, oend); DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor); } } goto _last_literals; } _return_label: #if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 FREEMEM(opt); #endif return retval; } ================================================ FILE: lib/LZ4F/lz4hc.h ================================================ /* LZ4 HC - High Compression Mode of LZ4 Header File Copyright (C) 2011-2020, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 source repository : https://github.com/lz4/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ #ifndef LZ4_HC_H_19834876238432 #define LZ4_HC_H_19834876238432 #if defined (__cplusplus) extern "C" { #endif /* --- Dependency --- */ /* note : lz4hc requires lz4.h/lz4.c for compilation */ #include "lz4.h" /* stddef, LZ4LIB_API, LZ4_DEPRECATED */ /* --- Useful constants --- */ #define LZ4HC_CLEVEL_MIN 3 #define LZ4HC_CLEVEL_DEFAULT 9 #define LZ4HC_CLEVEL_OPT_MIN 10 #define LZ4HC_CLEVEL_MAX 12 /*-************************************ * Block Compression **************************************/ /*! LZ4_compress_HC() : * Compress data from `src` into `dst`, using the powerful but slower "HC" algorithm. * `dst` must be already allocated. * Compression is guaranteed to succeed if `dstCapacity >= LZ4_compressBound(srcSize)` (see "lz4.h") * Max supported `srcSize` value is LZ4_MAX_INPUT_SIZE (see "lz4.h") * `compressionLevel` : any value between 1 and LZ4HC_CLEVEL_MAX will work. * Values > LZ4HC_CLEVEL_MAX behave the same as LZ4HC_CLEVEL_MAX. * @return : the number of bytes written into 'dst' * or 0 if compression fails. */ LZ4LIB_API int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel); /* Note : * Decompression functions are provided within "lz4.h" (BSD license) */ /*! LZ4_compress_HC_extStateHC() : * Same as LZ4_compress_HC(), but using an externally allocated memory segment for `state`. * `state` size is provided by LZ4_sizeofStateHC(). * Memory segment must be aligned on 8-bytes boundaries (which a normal malloc() should do properly). */ LZ4LIB_API int LZ4_sizeofStateHC(void); LZ4LIB_API int LZ4_compress_HC_extStateHC(void* stateHC, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel); /*! LZ4_compress_HC_destSize() : v1.9.0+ * Will compress as much data as possible from `src` * to fit into `targetDstSize` budget. * Result is provided in 2 parts : * @return : the number of bytes written into 'dst' (necessarily <= targetDstSize) * or 0 if compression fails. * `srcSizePtr` : on success, *srcSizePtr is updated to indicate how much bytes were read from `src` */ LZ4LIB_API int LZ4_compress_HC_destSize(void* stateHC, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int compressionLevel); /*-************************************ * Streaming Compression * Bufferless synchronous API **************************************/ typedef union LZ4_streamHC_u LZ4_streamHC_t; /* incomplete type (defined later) */ /*! LZ4_createStreamHC() and LZ4_freeStreamHC() : * These functions create and release memory for LZ4 HC streaming state. * Newly created states are automatically initialized. * A same state can be used multiple times consecutively, * starting with LZ4_resetStreamHC_fast() to start a new stream of blocks. */ LZ4LIB_API LZ4_streamHC_t* LZ4_createStreamHC(void); LZ4LIB_API int LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr); /* These functions compress data in successive blocks of any size, using previous blocks as dictionary, to improve compression ratio. One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks. There is an exception for ring buffers, which can be smaller than 64 KB. Ring-buffer scenario is automatically detected and handled within LZ4_compress_HC_continue(). Before starting compression, state must be allocated and properly initialized. LZ4_createStreamHC() does both, though compression level is set to LZ4HC_CLEVEL_DEFAULT. Selecting the compression level can be done with LZ4_resetStreamHC_fast() (starts a new stream) or LZ4_setCompressionLevel() (anytime, between blocks in the same stream) (experimental). LZ4_resetStreamHC_fast() only works on states which have been properly initialized at least once, which is automatically the case when state is created using LZ4_createStreamHC(). After reset, a first "fictional block" can be designated as initial dictionary, using LZ4_loadDictHC() (Optional). Invoke LZ4_compress_HC_continue() to compress each successive block. The number of blocks is unlimited. Previous input blocks, including initial dictionary when present, must remain accessible and unmodified during compression. It's allowed to update compression level anytime between blocks, using LZ4_setCompressionLevel() (experimental). 'dst' buffer should be sized to handle worst case scenarios (see LZ4_compressBound(), it ensures compression success). In case of failure, the API does not guarantee recovery, so the state _must_ be reset. To ensure compression success whenever `dst` buffer size cannot be made >= LZ4_compressBound(), consider using LZ4_compress_HC_continue_destSize(). Whenever previous input blocks can't be preserved unmodified in-place during compression of next blocks, it's possible to copy the last blocks into a more stable memory space, using LZ4_saveDictHC(). Return value of LZ4_saveDictHC() is the size of dictionary effectively saved into 'safeBuffer' (<= 64 KB) After completing a streaming compression, it's possible to start a new stream of blocks, using the same LZ4_streamHC_t state, just by resetting it, using LZ4_resetStreamHC_fast(). */ LZ4LIB_API void LZ4_resetStreamHC_fast(LZ4_streamHC_t* streamHCPtr, int compressionLevel); /* v1.9.0+ */ LZ4LIB_API int LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize); LZ4LIB_API int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr, const char* src, char* dst, int srcSize, int maxDstSize); /*! LZ4_compress_HC_continue_destSize() : v1.9.0+ * Similar to LZ4_compress_HC_continue(), * but will read as much data as possible from `src` * to fit into `targetDstSize` budget. * Result is provided into 2 parts : * @return : the number of bytes written into 'dst' (necessarily <= targetDstSize) * or 0 if compression fails. * `srcSizePtr` : on success, *srcSizePtr will be updated to indicate how much bytes were read from `src`. * Note that this function may not consume the entire input. */ LZ4LIB_API int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDstSize); LZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize); /*^********************************************** * !!!!!! STATIC LINKING ONLY !!!!!! ***********************************************/ /*-****************************************************************** * PRIVATE DEFINITIONS : * Do not use these definitions directly. * They are merely exposed to allow static allocation of `LZ4_streamHC_t`. * Declare an `LZ4_streamHC_t` directly, rather than any type below. * Even then, only do so in the context of static linking, as definitions may change between versions. ********************************************************************/ #define LZ4HC_DICTIONARY_LOGSIZE 16 #define LZ4HC_MAXD (1<= LZ4HC_CLEVEL_OPT_MIN. */ LZ4LIB_STATIC_API void LZ4_favorDecompressionSpeed( LZ4_streamHC_t* LZ4_streamHCPtr, int favor); /*! LZ4_resetStreamHC_fast() : v1.9.0+ * When an LZ4_streamHC_t is known to be in a internally coherent state, * it can often be prepared for a new compression with almost no work, only * sometimes falling back to the full, expensive reset that is always required * when the stream is in an indeterminate state (i.e., the reset performed by * LZ4_resetStreamHC()). * * LZ4_streamHCs are guaranteed to be in a valid state when: * - returned from LZ4_createStreamHC() * - reset by LZ4_resetStreamHC() * - memset(stream, 0, sizeof(LZ4_streamHC_t)) * - the stream was in a valid state and was reset by LZ4_resetStreamHC_fast() * - the stream was in a valid state and was then used in any compression call * that returned success * - the stream was in an indeterminate state and was used in a compression * call that fully reset the state (LZ4_compress_HC_extStateHC()) and that * returned success * * Note: * A stream that was last used in a compression call that returned an error * may be passed to this function. However, it will be fully reset, which will * clear any existing history and settings from the context. */ LZ4LIB_STATIC_API void LZ4_resetStreamHC_fast( LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel); /*! LZ4_compress_HC_extStateHC_fastReset() : * A variant of LZ4_compress_HC_extStateHC(). * * Using this variant avoids an expensive initialization step. It is only safe * to call if the state buffer is known to be correctly initialized already * (see above comment on LZ4_resetStreamHC_fast() for a definition of * "correctly initialized"). From a high level, the difference is that this * function initializes the provided state with a call to * LZ4_resetStreamHC_fast() while LZ4_compress_HC_extStateHC() starts with a * call to LZ4_resetStreamHC(). */ LZ4LIB_STATIC_API int LZ4_compress_HC_extStateHC_fastReset ( void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel); /*! LZ4_attach_HC_dictionary() : * This is an experimental API that allows for the efficient use of a * static dictionary many times. * * Rather than re-loading the dictionary buffer into a working context before * each compression, or copying a pre-loaded dictionary's LZ4_streamHC_t into a * working LZ4_streamHC_t, this function introduces a no-copy setup mechanism, * in which the working stream references the dictionary stream in-place. * * Several assumptions are made about the state of the dictionary stream. * Currently, only streams which have been prepared by LZ4_loadDictHC() should * be expected to work. * * Alternatively, the provided dictionary stream pointer may be NULL, in which * case any existing dictionary stream is unset. * * A dictionary should only be attached to a stream without any history (i.e., * a stream that has just been reset). * * The dictionary will remain attached to the working stream only for the * current stream session. Calls to LZ4_resetStreamHC(_fast) will remove the * dictionary context association from the working stream. The dictionary * stream (and source buffer) must remain in-place / accessible / unchanged * through the lifetime of the stream session. */ LZ4LIB_STATIC_API void LZ4_attach_HC_dictionary( LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream); #if defined (__cplusplus) } #endif #endif /* LZ4_HC_SLO_098092834 */ #endif /* LZ4_HC_STATIC_LINKING_ONLY */ ================================================ FILE: lib/LZ4F/xxhash.c ================================================ /* * xxHash - Fast Hash algorithm * Copyright (C) 2012-2016, Yann Collet * * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You can contact the author at : * - xxHash homepage: http://www.xxhash.com * - xxHash source repository : https://github.com/Cyan4973/xxHash */ /* ************************************* * Tuning parameters ***************************************/ /*!XXH_FORCE_MEMORY_ACCESS : * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. * The below switch allow to select different access method for improved performance. * Method 0 (default) : use `memcpy()`. Safe and portable. * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. * Method 2 : direct access. This method doesn't depend on compiler but violate C standard. * It can generate buggy code on targets which do not support unaligned memory accesses. * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) * See http://stackoverflow.com/a/32095106/646947 for details. * Prefer these methods in priority order (0 > 1 > 2) */ #ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ # if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) # define XXH_FORCE_MEMORY_ACCESS 2 # elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ || defined(__ARM_ARCH_7S__) )) # define XXH_FORCE_MEMORY_ACCESS 1 # endif #endif /*!XXH_ACCEPT_NULL_INPUT_POINTER : * If input pointer is NULL, xxHash default behavior is to dereference it, triggering a segfault. * When this macro is enabled, xxHash actively checks input for null pointer. * It it is, result for null input pointers is the same as a null-length input. */ #ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */ # define XXH_ACCEPT_NULL_INPUT_POINTER 0 #endif /*!XXH_FORCE_NATIVE_FORMAT : * By default, xxHash library provides endian-independent Hash values, based on little-endian convention. * Results are therefore identical for little-endian and big-endian CPU. * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. * Should endian-independence be of no importance for your application, you may set the #define below to 1, * to improve speed for Big-endian CPU. * This option has no impact on Little_Endian CPU. */ #ifndef XXH_FORCE_NATIVE_FORMAT /* can be defined externally */ # define XXH_FORCE_NATIVE_FORMAT 0 #endif /*!XXH_FORCE_ALIGN_CHECK : * This is a minor performance trick, only useful with lots of very small keys. * It means : check for aligned/unaligned input. * The check costs one initial branch per hash; * set it to 0 when the input is guaranteed to be aligned, * or when alignment doesn't matter for performance. */ #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ # if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) # define XXH_FORCE_ALIGN_CHECK 0 # else # define XXH_FORCE_ALIGN_CHECK 1 # endif #endif /* ************************************* * Includes & Memory related functions ***************************************/ /*! Modify the local functions below should you wish to use some other memory routines * for malloc(), free() */ #include static void* XXH_malloc(size_t s) { return malloc(s); } static void XXH_free (void* p) { free(p); } /*! and for memcpy() */ #include static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } #include /* assert */ #define XXH_STATIC_LINKING_ONLY #include "xxhash.h" /* ************************************* * Compiler Specific Options ***************************************/ #ifdef _MSC_VER /* Visual Studio */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # define FORCE_INLINE static __forceinline #else # if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ # ifdef __GNUC__ # define FORCE_INLINE static inline __attribute__((always_inline)) # else # define FORCE_INLINE static inline # endif # else # define FORCE_INLINE static # endif /* __STDC_VERSION__ */ #endif /* ************************************* * Basic Types ***************************************/ #ifndef MEM_MODULE # if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; # else typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; # endif #endif #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ static U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */ typedef union { U32 u32; } __attribute__((packed)) unalign; static U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; } #else /* portable and safe solution. Generally efficient. * see : http://stackoverflow.com/a/32095106/646947 */ static U32 XXH_read32(const void* memPtr) { U32 val; memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ /* **************************************** * Compiler-specific Functions and Macros ******************************************/ #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ #if defined(_MSC_VER) # define XXH_rotl32(x,r) _rotl(x,r) # define XXH_rotl64(x,r) _rotl64(x,r) #else # define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r))) # define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r))) #endif #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap32 _byteswap_ulong #elif XXH_GCC_VERSION >= 403 # define XXH_swap32 __builtin_bswap32 #else static U32 XXH_swap32 (U32 x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } #endif /* ************************************* * Architecture Macros ***************************************/ typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; /* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */ #ifndef XXH_CPU_LITTLE_ENDIAN static int XXH_isLittleEndian(void) { const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ return one.c[0]; } # define XXH_CPU_LITTLE_ENDIAN XXH_isLittleEndian() #endif /* *************************** * Memory reads *****************************/ typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align) { if (align==XXH_unaligned) return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); else return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr); } FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian) { return XXH_readLE32_align(ptr, endian, XXH_unaligned); } static U32 XXH_readBE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr); } /* ************************************* * Macros ***************************************/ #define XXH_STATIC_ASSERT(c) { enum { XXH_sa = 1/(int)(!!(c)) }; } /* use after variable declarations */ XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; } /* ******************************************************************* * 32-bit hash functions *********************************************************************/ static const U32 PRIME32_1 = 2654435761U; static const U32 PRIME32_2 = 2246822519U; static const U32 PRIME32_3 = 3266489917U; static const U32 PRIME32_4 = 668265263U; static const U32 PRIME32_5 = 374761393U; static U32 XXH32_round(U32 seed, U32 input) { seed += input * PRIME32_2; seed = XXH_rotl32(seed, 13); seed *= PRIME32_1; return seed; } /* mix all bits */ static U32 XXH32_avalanche(U32 h32) { h32 ^= h32 >> 15; h32 *= PRIME32_2; h32 ^= h32 >> 13; h32 *= PRIME32_3; h32 ^= h32 >> 16; return(h32); } #define XXH_get32bits(p) XXH_readLE32_align(p, endian, align) static U32 XXH32_finalize(U32 h32, const void* ptr, size_t len, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)ptr; #define PROCESS1 \ h32 += (*p++) * PRIME32_5; \ h32 = XXH_rotl32(h32, 11) * PRIME32_1 ; #define PROCESS4 \ h32 += XXH_get32bits(p) * PRIME32_3; \ p+=4; \ h32 = XXH_rotl32(h32, 17) * PRIME32_4 ; switch(len&15) /* or switch(bEnd - p) */ { case 12: PROCESS4; /* fallthrough */ case 8: PROCESS4; /* fallthrough */ case 4: PROCESS4; return XXH32_avalanche(h32); case 13: PROCESS4; /* fallthrough */ case 9: PROCESS4; /* fallthrough */ case 5: PROCESS4; PROCESS1; return XXH32_avalanche(h32); case 14: PROCESS4; /* fallthrough */ case 10: PROCESS4; /* fallthrough */ case 6: PROCESS4; PROCESS1; PROCESS1; return XXH32_avalanche(h32); case 15: PROCESS4; /* fallthrough */ case 11: PROCESS4; /* fallthrough */ case 7: PROCESS4; /* fallthrough */ case 3: PROCESS1; /* fallthrough */ case 2: PROCESS1; /* fallthrough */ case 1: PROCESS1; /* fallthrough */ case 0: return XXH32_avalanche(h32); } assert(0); return h32; /* reaching this point is deemed impossible */ } FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)input; const BYTE* bEnd = p + len; U32 h32; #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) if (p==NULL) { len=0; bEnd=p=(const BYTE*)(size_t)16; } #endif if (len>=16) { const BYTE* const limit = bEnd - 15; U32 v1 = seed + PRIME32_1 + PRIME32_2; U32 v2 = seed + PRIME32_2; U32 v3 = seed + 0; U32 v4 = seed - PRIME32_1; do { v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4; v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4; v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4; v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4; } while (p < limit); h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); } else { h32 = seed + PRIME32_5; } h32 += (U32)len; return XXH32_finalize(h32, p, len&15, endian, align); } XXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed) { #if 0 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH32_state_t state; XXH32_reset(&state, seed); XXH32_update(&state, input, len); return XXH32_digest(&state); #else XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 3) == 0) { /* Input is 4-bytes aligned, leverage the speed benefit */ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); else return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); } } if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); else return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); #endif } /*====== Hash streaming ======*/ XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void) { return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t)); } XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState) { memcpy(dstState, srcState, sizeof(*dstState)); } XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed) { XXH32_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ memset(&state, 0, sizeof(state)); state.v1 = seed + PRIME32_1 + PRIME32_2; state.v2 = seed + PRIME32_2; state.v3 = seed + 0; state.v4 = seed - PRIME32_1; /* do not write into reserved, planned to be removed in a future version */ memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved)); return XXH_OK; } FORCE_INLINE XXH_errorcode XXH32_update_endian(XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian) { if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) return XXH_OK; #else return XXH_ERROR; #endif { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; state->total_len_32 += (unsigned)len; state->large_len |= (len>=16) | (state->total_len_32>=16); if (state->memsize + len < 16) { /* fill in tmp buffer */ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len); state->memsize += (unsigned)len; return XXH_OK; } if (state->memsize) { /* some data left from previous update */ XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize); { const U32* p32 = state->mem32; state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++; state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++; state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++; state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian)); } p += 16-state->memsize; state->memsize = 0; } if (p <= bEnd-16) { const BYTE* const limit = bEnd - 16; U32 v1 = state->v1; U32 v2 = state->v2; U32 v3 = state->v3; U32 v4 = state->v4; do { v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4; v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4; v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4; v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4; } while (p<=limit); state->v1 = v1; state->v2 = v2; state->v3 = v3; state->v4 = v4; } if (p < bEnd) { XXH_memcpy(state->mem32, p, (size_t)(bEnd-p)); state->memsize = (unsigned)(bEnd-p); } } return XXH_OK; } XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len) { XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH32_update_endian(state_in, input, len, XXH_littleEndian); else return XXH32_update_endian(state_in, input, len, XXH_bigEndian); } FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian) { U32 h32; if (state->large_len) { h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18); } else { h32 = state->v3 /* == seed */ + PRIME32_5; } h32 += state->total_len_32; return XXH32_finalize(h32, state->mem32, state->memsize, endian, XXH_aligned); } XXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in) { XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH32_digest_endian(state_in, XXH_littleEndian); else return XXH32_digest_endian(state_in, XXH_bigEndian); } /*====== Canonical representation ======*/ /*! Default XXH result types are basic unsigned 32 and 64 bits. * The canonical representation follows human-readable write convention, aka big-endian (large digits first). * These functions allow transformation of hash result into and from its canonical format. * This way, hash values can be written into a file or buffer, remaining comparable across different systems. */ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash); memcpy(dst, &hash, sizeof(*dst)); } XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src) { return XXH_readBE32(src); } #ifndef XXH_NO_LONG_LONG /* ******************************************************************* * 64-bit hash functions *********************************************************************/ /*====== Memory access ======*/ #ifndef MEM_MODULE # define MEM_MODULE # if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include typedef uint64_t U64; # else /* if compiler doesn't support unsigned long long, replace by another 64-bit type */ typedef unsigned long long U64; # endif #endif #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ static U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ /* currently only defined for gcc and icc */ typedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64; static U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; } #else /* portable and safe solution. Generally efficient. * see : http://stackoverflow.com/a/32095106/646947 */ static U64 XXH_read64(const void* memPtr) { U64 val; memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap64 _byteswap_uint64 #elif XXH_GCC_VERSION >= 403 # define XXH_swap64 __builtin_bswap64 #else static U64 XXH_swap64 (U64 x) { return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | ((x >> 8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL); } #endif FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align) { if (align==XXH_unaligned) return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); else return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr); } FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian) { return XXH_readLE64_align(ptr, endian, XXH_unaligned); } static U64 XXH_readBE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr); } /*====== xxh64 ======*/ static const U64 PRIME64_1 = 11400714785074694791ULL; static const U64 PRIME64_2 = 14029467366897019727ULL; static const U64 PRIME64_3 = 1609587929392839161ULL; static const U64 PRIME64_4 = 9650029242287828579ULL; static const U64 PRIME64_5 = 2870177450012600261ULL; static U64 XXH64_round(U64 acc, U64 input) { acc += input * PRIME64_2; acc = XXH_rotl64(acc, 31); acc *= PRIME64_1; return acc; } static U64 XXH64_mergeRound(U64 acc, U64 val) { val = XXH64_round(0, val); acc ^= val; acc = acc * PRIME64_1 + PRIME64_4; return acc; } static U64 XXH64_avalanche(U64 h64) { h64 ^= h64 >> 33; h64 *= PRIME64_2; h64 ^= h64 >> 29; h64 *= PRIME64_3; h64 ^= h64 >> 32; return h64; } #define XXH_get64bits(p) XXH_readLE64_align(p, endian, align) static U64 XXH64_finalize(U64 h64, const void* ptr, size_t len, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)ptr; #define PROCESS1_64 \ h64 ^= (*p++) * PRIME64_5; \ h64 = XXH_rotl64(h64, 11) * PRIME64_1; #define PROCESS4_64 \ h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; \ p+=4; \ h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; #define PROCESS8_64 { \ U64 const k1 = XXH64_round(0, XXH_get64bits(p)); \ p+=8; \ h64 ^= k1; \ h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; \ } switch(len&31) { case 24: PROCESS8_64; /* fallthrough */ case 16: PROCESS8_64; /* fallthrough */ case 8: PROCESS8_64; return XXH64_avalanche(h64); case 28: PROCESS8_64; /* fallthrough */ case 20: PROCESS8_64; /* fallthrough */ case 12: PROCESS8_64; /* fallthrough */ case 4: PROCESS4_64; return XXH64_avalanche(h64); case 25: PROCESS8_64; /* fallthrough */ case 17: PROCESS8_64; /* fallthrough */ case 9: PROCESS8_64; PROCESS1_64; return XXH64_avalanche(h64); case 29: PROCESS8_64; /* fallthrough */ case 21: PROCESS8_64; /* fallthrough */ case 13: PROCESS8_64; /* fallthrough */ case 5: PROCESS4_64; PROCESS1_64; return XXH64_avalanche(h64); case 26: PROCESS8_64; /* fallthrough */ case 18: PROCESS8_64; /* fallthrough */ case 10: PROCESS8_64; PROCESS1_64; PROCESS1_64; return XXH64_avalanche(h64); case 30: PROCESS8_64; /* fallthrough */ case 22: PROCESS8_64; /* fallthrough */ case 14: PROCESS8_64; /* fallthrough */ case 6: PROCESS4_64; PROCESS1_64; PROCESS1_64; return XXH64_avalanche(h64); case 27: PROCESS8_64; /* fallthrough */ case 19: PROCESS8_64; /* fallthrough */ case 11: PROCESS8_64; PROCESS1_64; PROCESS1_64; PROCESS1_64; return XXH64_avalanche(h64); case 31: PROCESS8_64; /* fallthrough */ case 23: PROCESS8_64; /* fallthrough */ case 15: PROCESS8_64; /* fallthrough */ case 7: PROCESS4_64; /* fallthrough */ case 3: PROCESS1_64; /* fallthrough */ case 2: PROCESS1_64; /* fallthrough */ case 1: PROCESS1_64; /* fallthrough */ case 0: return XXH64_avalanche(h64); } /* impossible to reach */ assert(0); return 0; /* unreachable, but some compilers complain without it */ } FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align) { const BYTE* p = (const BYTE*)input; const BYTE* bEnd = p + len; U64 h64; #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) if (p==NULL) { len=0; bEnd=p=(const BYTE*)(size_t)32; } #endif if (len>=32) { const BYTE* const limit = bEnd - 32; U64 v1 = seed + PRIME64_1 + PRIME64_2; U64 v2 = seed + PRIME64_2; U64 v3 = seed + 0; U64 v4 = seed - PRIME64_1; do { v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8; v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8; v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8; v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8; } while (p<=limit); h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); h64 = XXH64_mergeRound(h64, v1); h64 = XXH64_mergeRound(h64, v2); h64 = XXH64_mergeRound(h64, v3); h64 = XXH64_mergeRound(h64, v4); } else { h64 = seed + PRIME64_5; } h64 += (U64) len; return XXH64_finalize(h64, p, len, endian, align); } XXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed) { #if 0 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */ XXH64_state_t state; XXH64_reset(&state, seed); XXH64_update(&state, input, len); return XXH64_digest(&state); #else XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if (XXH_FORCE_ALIGN_CHECK) { if ((((size_t)input) & 7)==0) { /* Input is aligned, let's leverage the speed advantage */ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned); else return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned); } } if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); else return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned); #endif } /*====== Hash Streaming ======*/ XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void) { return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); } XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr) { XXH_free(statePtr); return XXH_OK; } XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState) { memcpy(dstState, srcState, sizeof(*dstState)); } XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed) { XXH64_state_t state; /* using a local state to memcpy() in order to avoid strict-aliasing warnings */ memset(&state, 0, sizeof(state)); state.v1 = seed + PRIME64_1 + PRIME64_2; state.v2 = seed + PRIME64_2; state.v3 = seed + 0; state.v4 = seed - PRIME64_1; /* do not write into reserved, planned to be removed in a future version */ memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved)); return XXH_OK; } FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian) { if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) return XXH_OK; #else return XXH_ERROR; #endif { const BYTE* p = (const BYTE*)input; const BYTE* const bEnd = p + len; state->total_len += len; if (state->memsize + len < 32) { /* fill in tmp buffer */ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len); state->memsize += (U32)len; return XXH_OK; } if (state->memsize) { /* tmp buffer is full */ XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize); state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian)); state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian)); state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian)); state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian)); p += 32-state->memsize; state->memsize = 0; } if (p+32 <= bEnd) { const BYTE* const limit = bEnd - 32; U64 v1 = state->v1; U64 v2 = state->v2; U64 v3 = state->v3; U64 v4 = state->v4; do { v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8; v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8; v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8; v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8; } while (p<=limit); state->v1 = v1; state->v2 = v2; state->v3 = v3; state->v4 = v4; } if (p < bEnd) { XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); state->memsize = (unsigned)(bEnd-p); } } return XXH_OK; } XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len) { XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH64_update_endian(state_in, input, len, XXH_littleEndian); else return XXH64_update_endian(state_in, input, len, XXH_bigEndian); } FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian) { U64 h64; if (state->total_len >= 32) { U64 const v1 = state->v1; U64 const v2 = state->v2; U64 const v3 = state->v3; U64 const v4 = state->v4; h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); h64 = XXH64_mergeRound(h64, v1); h64 = XXH64_mergeRound(h64, v2); h64 = XXH64_mergeRound(h64, v3); h64 = XXH64_mergeRound(h64, v4); } else { h64 = state->v3 /*seed*/ + PRIME64_5; } h64 += (U64) state->total_len; return XXH64_finalize(h64, state->mem64, (size_t)state->total_len, endian, XXH_aligned); } XXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in) { XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN; if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT) return XXH64_digest_endian(state_in, XXH_littleEndian); else return XXH64_digest_endian(state_in, XXH_bigEndian); } /*====== Canonical representation ======*/ XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash) { XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash); memcpy(dst, &hash, sizeof(*dst)); } XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src) { return XXH_readBE64(src); } #endif /* XXH_NO_LONG_LONG */ ================================================ FILE: lib/LZ4F/xxhash.h ================================================ /* xxHash - Extremely Fast Hash algorithm Header File Copyright (C) 2012-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - xxHash source repository : https://github.com/Cyan4973/xxHash */ /* Notice extracted from xxHash homepage : xxHash is an extremely fast Hash algorithm, running at RAM speed limits. It also successfully passes all tests from the SMHasher suite. Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz) Name Speed Q.Score Author xxHash 5.4 GB/s 10 CrapWow 3.2 GB/s 2 Andrew MumurHash 3a 2.7 GB/s 10 Austin Appleby SpookyHash 2.0 GB/s 10 Bob Jenkins SBox 1.4 GB/s 9 Bret Mulvey Lookup3 1.2 GB/s 9 Bob Jenkins SuperFastHash 1.2 GB/s 1 Paul Hsieh CityHash64 1.05 GB/s 10 Pike & Alakuijala FNV 0.55 GB/s 5 Fowler, Noll, Vo CRC32 0.43 GB/s 9 MD5-32 0.33 GB/s 10 Ronald L. Rivest SHA1-32 0.28 GB/s 10 Q.Score is a measure of quality of the hash function. It depends on successfully passing SMHasher test set. 10 is a perfect score. A 64-bit version, named XXH64, is available since r35. It offers much better speed, but for 64-bit applications only. Name Speed on 64 bits Speed on 32 bits XXH64 13.8 GB/s 1.9 GB/s XXH32 6.8 GB/s 6.0 GB/s */ #ifndef XXHASH_H_5627135585666179 #define XXHASH_H_5627135585666179 1 #if defined (__cplusplus) extern "C" { #endif /* **************************** * Definitions ******************************/ #include /* size_t */ typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; /* **************************** * API modifier ******************************/ /** XXH_INLINE_ALL (and XXH_PRIVATE_API) * This is useful to include xxhash functions in `static` mode * in order to inline them, and remove their symbol from the public list. * Inlining can offer dramatic performance improvement on small keys. * Methodology : * #define XXH_INLINE_ALL * #include "xxhash.h" * `xxhash.c` is automatically included. * It's not useful to compile and link it as a separate module. */ #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) # ifndef XXH_STATIC_LINKING_ONLY # define XXH_STATIC_LINKING_ONLY # endif # if defined(__GNUC__) # define XXH_PUBLIC_API static __inline __attribute__((unused)) # elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) # define XXH_PUBLIC_API static inline # elif defined(_MSC_VER) # define XXH_PUBLIC_API static __inline # else /* this version may generate warnings for unused static functions */ # define XXH_PUBLIC_API static # endif #else # define XXH_PUBLIC_API /* do nothing */ #endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */ /*! XXH_NAMESPACE, aka Namespace Emulation : * * If you want to include _and expose_ xxHash functions from within your own library, * but also want to avoid symbol collisions with other libraries which may also include xxHash, * * you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library * with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values). * * Note that no change is required within the calling program as long as it includes `xxhash.h` : * regular symbol name will be automatically translated by this header. */ #ifdef XXH_NAMESPACE # define XXH_CAT(A,B) A##B # define XXH_NAME2(A,B) XXH_CAT(A,B) # define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber) # define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32) # define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState) # define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState) # define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset) # define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update) # define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest) # define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState) # define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash) # define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical) # define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64) # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) # define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState) # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) # define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState) # define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash) # define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical) #endif /* ************************************* * Version ***************************************/ #define XXH_VERSION_MAJOR 0 #define XXH_VERSION_MINOR 6 #define XXH_VERSION_RELEASE 5 #define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE) XXH_PUBLIC_API unsigned XXH_versionNumber (void); /*-********************************************************************** * 32-bit hash ************************************************************************/ typedef unsigned int XXH32_hash_t; /*! XXH32() : Calculate the 32-bit hash of sequence "length" bytes stored at memory address "input". The memory between input & input+length must be valid (allocated and read-accessible). "seed" can be used to alter the result predictably. Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */ XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed); /*====== Streaming ======*/ typedef struct XXH32_state_s XXH32_state_t; /* incomplete type */ XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void); XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr); XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state); XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned int seed); XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length); XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr); /* * Streaming functions generate the xxHash of an input provided in multiple segments. * Note that, for small input, they are slower than single-call functions, due to state management. * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized. * * XXH state must first be allocated, using XXH*_createState() . * * Start a new hash by initializing state with a seed, using XXH*_reset(). * * Then, feed the hash state by calling XXH*_update() as many times as necessary. * The function returns an error code, with 0 meaning OK, and any other value meaning there is an error. * * Finally, a hash value can be produced anytime, by using XXH*_digest(). * This function returns the nn-bits hash as an int or long long. * * It's still possible to continue inserting input into the hash state after a digest, * and generate some new hashes later on, by calling again XXH*_digest(). * * When done, free XXH state space if it was allocated dynamically. */ /*====== Canonical representation ======*/ typedef struct { unsigned char digest[4]; } XXH32_canonical_t; XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash); XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src); /* Default result type for XXH functions are primitive unsigned 32 and 64 bits. * The canonical representation uses human-readable write convention, aka big-endian (large digits first). * These functions allow transformation of hash result into and from its canonical format. * This way, hash values can be written into a file / memory, and remain comparable on different systems and programs. */ #ifndef XXH_NO_LONG_LONG /*-********************************************************************** * 64-bit hash ************************************************************************/ typedef unsigned long long XXH64_hash_t; /*! XXH64() : Calculate the 64-bit hash of sequence of length "len" stored at memory address "input". "seed" can be used to alter the result predictably. This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark). */ XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed); /*====== Streaming ======*/ typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void); XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr); XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state); XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed); XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); /*====== Canonical representation ======*/ typedef struct { unsigned char digest[8]; } XXH64_canonical_t; XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash); XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src); #endif /* XXH_NO_LONG_LONG */ #ifdef XXH_STATIC_LINKING_ONLY /* ================================================================================================ This section contains declarations which are not guaranteed to remain stable. They may change in future versions, becoming incompatible with a different version of the library. These declarations should only be used with static linking. Never use them in association with dynamic linking ! =================================================================================================== */ /* These definitions are only present to allow * static allocation of XXH state, on stack or in a struct for example. * Never **ever** use members directly. */ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) # include struct XXH32_state_s { uint32_t total_len_32; uint32_t large_len; uint32_t v1; uint32_t v2; uint32_t v3; uint32_t v4; uint32_t mem32[4]; uint32_t memsize; uint32_t reserved; /* never read nor write, might be removed in a future version */ }; /* typedef'd to XXH32_state_t */ struct XXH64_state_s { uint64_t total_len; uint64_t v1; uint64_t v2; uint64_t v3; uint64_t v4; uint64_t mem64[4]; uint32_t memsize; uint32_t reserved[2]; /* never read nor write, might be removed in a future version */ }; /* typedef'd to XXH64_state_t */ # else struct XXH32_state_s { unsigned total_len_32; unsigned large_len; unsigned v1; unsigned v2; unsigned v3; unsigned v4; unsigned mem32[4]; unsigned memsize; unsigned reserved; /* never read nor write, might be removed in a future version */ }; /* typedef'd to XXH32_state_t */ # ifndef XXH_NO_LONG_LONG /* remove 64-bit support */ struct XXH64_state_s { unsigned long long total_len; unsigned long long v1; unsigned long long v2; unsigned long long v3; unsigned long long v4; unsigned long long mem64[4]; unsigned memsize; unsigned reserved[2]; /* never read nor write, might be removed in a future version */ }; /* typedef'd to XXH64_state_t */ # endif # endif #if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API) # include "xxhash.c" /* include xxhash function bodies as `static`, for inlining */ #endif #endif /* XXH_STATIC_LINKING_ONLY */ #if defined (__cplusplus) } #endif #endif /* XXHASH_H_5627135585666179 */ ================================================ FILE: lib/SOIL2/SOIL2.c ================================================ /* Fork by Martin Lucas Golini Original author Jonathan Dummer 2007-07-26-10.36 Simple OpenGL Image Library 2 Public Domain using Sean Barret's stb_image as a base Thanks to: * Sean Barret - for the awesome stb_image * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts * everybody at gamedev.net */ #define SOIL_CHECK_FOR_GL_ERRORS 0 #if defined( __APPLE_CC__ ) || defined ( __APPLE__ ) #include #if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR ) #define SOIL_PLATFORM_IOS #include #else #define SOIL_PLATFORM_OSX #endif #elif defined( __ANDROID__ ) || defined( ANDROID ) #define SOIL_PLATFORM_ANDROID #elif ( defined ( linux ) || defined( __linux__ ) || defined( __FreeBSD__ ) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined( __DragonFly__ ) || defined( __SVR4 ) ) #define SOIL_X11_PLATFORM #endif #if ( defined( SOIL_PLATFORM_IOS ) || defined( SOIL_PLATFORM_ANDROID ) ) && ( !defined( SOIL_GLES1 ) && !defined( SOIL_GLES2 ) ) #define SOIL_GLES2 #endif #if ( defined( SOIL_GLES2 ) || defined( SOIL_GLES1 ) ) && !defined( SOIL_NO_EGL ) && !defined( SOIL_PLATFORM_IOS ) #include #endif #if defined( SOIL_GLES2 ) #ifdef SOIL_PLATFORM_IOS #include #include #else #include #include #endif #define APIENTRY GL_APIENTRY #elif defined( SOIL_GLES1 ) #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES #endif #ifdef SOIL_PLATFORM_IOS #include #include #else #include #include #endif #define APIENTRY GL_APIENTRY #else #if defined( __WIN32__ ) || defined( _WIN32 ) || defined( WIN32 ) #define SOIL_PLATFORM_WIN32 #define WIN32_LEAN_AND_MEAN #include #include #include #elif defined(__APPLE__) || defined(__APPLE_CC__) /* I can't test this Apple stuff! */ #include #include #define APIENTRY #elif defined( SOIL_X11_PLATFORM ) #include #include #else #include #endif #endif #ifndef GL_BGRA #define GL_BGRA 0x80E1 #endif #ifndef GL_RG #define GL_RG 0x8227 #endif #ifndef GL_UNSIGNED_SHORT_4_4_4_4 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #endif #ifndef GL_UNSIGNED_SHORT_5_5_5_1 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #endif #ifndef GL_UNSIGNED_SHORT_5_6_5 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #endif #ifndef GL_UNSIGNED_BYTE_3_3_2 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #endif #include "SOIL2.h" #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" #include "image_helper.h" #include "image_DXT.h" #include "pvr_helper.h" #include "pkm_helper.h" #include #include unsigned long SOIL_version() { return SOIL_COMPILED_VERSION; } /* error reporting */ const char *result_string_pointer = "SOIL initialized"; /* for loading cube maps */ enum{ SOIL_CAPABILITY_UNKNOWN = -1, SOIL_CAPABILITY_NONE = 0, SOIL_CAPABILITY_PRESENT = 1 }; static int has_cubemap_capability = SOIL_CAPABILITY_UNKNOWN; int query_cubemap_capability( void ); #define SOIL_TEXTURE_WRAP_R 0x8072 #define SOIL_CLAMP_TO_EDGE 0x812F #define SOIL_NORMAL_MAP 0x8511 #define SOIL_REFLECTION_MAP 0x8512 #define SOIL_TEXTURE_CUBE_MAP 0x8513 #define SOIL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define SOIL_PROXY_TEXTURE_CUBE_MAP 0x851B #define SOIL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C /* for non-power-of-two texture */ #define SOIL_IS_POW2( v ) ( ( v & ( v - 1 ) ) == 0 ) static int has_NPOT_capability = SOIL_CAPABILITY_UNKNOWN; int query_NPOT_capability( void ); /* for texture rectangles */ static int has_tex_rectangle_capability = SOIL_CAPABILITY_UNKNOWN; int query_tex_rectangle_capability( void ); #define SOIL_TEXTURE_RECTANGLE_ARB 0x84F5 #define SOIL_MAX_RECTANGLE_TEXTURE_SIZE_ARB 0x84F8 /* for using DXT compression */ static int has_DXT_capability = SOIL_CAPABILITY_UNKNOWN; int query_DXT_capability( void ); static int has_3Dc_capability = SOIL_CAPABILITY_UNKNOWN; int query_3Dc_capability( void ); #define SOIL_GL_SRGB 0x8C40 #define SOIL_GL_SRGB_ALPHA 0x8C42 #define SOIL_RGB_S3TC_DXT1 0x83F0 #define SOIL_RGBA_S3TC_DXT1 0x83F1 #define SOIL_RGBA_S3TC_DXT3 0x83F2 #define SOIL_RGBA_S3TC_DXT5 0x83F3 #define SOIL_COMPRESSED_RG_RGTC2 0x8DBD #define SOIL_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C #define SOIL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F static int has_sRGB_capability = SOIL_CAPABILITY_UNKNOWN; int query_sRGB_capability( void ); typedef void (APIENTRY * P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data); static P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL; typedef void (APIENTRY *P_SOIL_GLGENERATEMIPMAPPROC)(GLenum target); static P_SOIL_GLGENERATEMIPMAPPROC soilGlGenerateMipmap = NULL; static int has_gen_mipmap_capability = SOIL_CAPABILITY_UNKNOWN; static int query_gen_mipmap_capability( void ); static int has_PVR_capability = SOIL_CAPABILITY_UNKNOWN; int query_PVR_capability( void ); static int has_BGRA8888_capability = SOIL_CAPABILITY_UNKNOWN; int query_BGRA8888_capability( void ); static int has_ETC1_capability = SOIL_CAPABILITY_UNKNOWN; int query_ETC1_capability( void ); /* GL_IMG_texture_compression_pvrtc */ #define SOIL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 #define SOIL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 #define SOIL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 #define SOIL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 #define SOIL_GL_ETC1_RGB8_OES 0x8D64 #if defined( SOIL_X11_PLATFORM ) || defined( SOIL_PLATFORM_WIN32 ) || defined( SOIL_PLATFORM_OSX ) || defined(__HAIKU__) typedef const GLubyte *(APIENTRY * P_SOIL_glGetStringiFunc) (GLenum, GLuint); static P_SOIL_glGetStringiFunc soilGlGetStringiFunc = NULL; static int isAtLeastGL3() { static int is_gl3 = SOIL_CAPABILITY_UNKNOWN; if ( SOIL_CAPABILITY_UNKNOWN == is_gl3 ) { const char * verstr = (const char *) glGetString( GL_VERSION ); is_gl3 = ( verstr && ( atoi(verstr) >= 3 ) && strstr( verstr, " ES " ) == NULL ); } return is_gl3; } #else static int isAtLeastGL3() { return SOIL_CAPABILITY_NONE; } #endif #ifdef SOIL_PLATFORM_WIN32 static HMODULE openglModule = NULL; static int soilTestWinProcPointer(const PROC pTest) { ptrdiff_t iTest; if(!pTest) return 0; iTest = (ptrdiff_t)pTest; if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0; return 1; } #endif #if defined(__sgi) || defined (__sun) || defined(__HAIKU__) #include void* dlGetProcAddress (const char* name) { static void* h = NULL; static void* gpa; if (h == NULL) { if ((h = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL)) == NULL) return NULL; gpa = dlsym(h, "glXGetProcAddress"); } if (gpa != NULL) return ((void*(*)(const GLubyte*))gpa)((const GLubyte*)name); else return dlsym(h, (const char*)name); } #endif void * SOIL_GL_GetProcAddress(const char *proc) { void *func = NULL; #if defined( SOIL_PLATFORM_IOS ) func = dlsym( RTLD_DEFAULT, proc ); #elif defined( SOIL_GLES2 ) || defined( SOIL_GLES1 ) #ifndef SOIL_NO_EGL func = eglGetProcAddress( proc ); #else func = NULL; #endif #elif defined( SOIL_PLATFORM_WIN32 ) if ( NULL == openglModule ) openglModule = LoadLibraryA("opengl32.dll"); func = (void*)wglGetProcAddress(proc); if (!soilTestWinProcPointer((const PROC)func)) { func = (void *)GetProcAddress(openglModule, proc); } #elif defined( SOIL_PLATFORM_OSX ) /* I can't test this Apple stuff! */ CFBundleRef bundle; CFURLRef bundleURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true ); CFStringRef extensionName = CFStringCreateWithCString( kCFAllocatorDefault, proc, kCFStringEncodingASCII ); bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); assert( bundle != NULL ); func = CFBundleGetFunctionPointerForName( bundle, extensionName ); CFRelease( bundleURL ); CFRelease( extensionName ); CFRelease( bundle ); #elif defined( SOIL_X11_PLATFORM ) func = #if !defined(GLX_VERSION_1_4) glXGetProcAddressARB #else glXGetProcAddress #endif ( (const GLubyte *)proc ); #elif defined(__sgi) || defined (__sun) || defined(__HAIKU__) func = dlGetProcAddress(proc); #endif return func; } /* Based on the SDL2 implementation */ int SOIL_GL_ExtensionSupported(const char *extension) { const char *extensions; const char *start; const char *where, *terminator; /* Extension names should not have spaces. */ where = strchr(extension, ' '); if (where || *extension == '\0') { return 0; } #if defined( SOIL_X11_PLATFORM ) || defined( SOIL_PLATFORM_WIN32 ) || defined( SOIL_PLATFORM_OSX ) || defined(__HAIKU__) /* Lookup the available extensions */ if ( isAtLeastGL3() ) { GLint num_exts = 0; GLint i; if ( NULL == soilGlGetStringiFunc ) { soilGlGetStringiFunc = (P_SOIL_glGetStringiFunc)SOIL_GL_GetProcAddress("glGetStringi"); if ( NULL == soilGlGetStringiFunc ) { return 0; } } #ifndef GL_NUM_EXTENSIONS #define GL_NUM_EXTENSIONS 0x821D #endif glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts); for (i = 0; i < num_exts; i++) { const char *thisext = (const char *) soilGlGetStringiFunc(GL_EXTENSIONS, i); if (strcmp(thisext, extension) == 0) { return 1; } } return 0; } #endif /* Try the old way with glGetString(GL_EXTENSIONS) ... */ extensions = (const char *) glGetString(GL_EXTENSIONS); if (!extensions) { return 0; } /* * It takes a bit of care to be fool-proof about parsing the OpenGL * extensions string. Don't be fooled by sub-strings, etc. */ start = extensions; for (;;) { where = strstr(start, extension); if (!where) break; terminator = where + strlen(extension); if (where == start || *(where - 1) == ' ') if (*terminator == ' ' || *terminator == '\0') return 1; start = terminator; } return 0; } /* other functions */ unsigned int SOIL_internal_create_OGL_texture ( const unsigned char *const data, int *width, int *height, int channels, unsigned int reuse_texture_ID, unsigned int flags, unsigned int opengl_texture_type, unsigned int opengl_texture_target, unsigned int texture_check_size_enum ); /* and the code magic begins here [8^) */ unsigned int SOIL_load_OGL_texture ( const char *filename, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* img; int width, height, channels; unsigned int tex_id; /* does the user want direct uploading of the image as a DDS file? */ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) { /* 1st try direct loading of the image as a DDS file note: direct uploading will only load what is in the DDS file, no MIPmaps will be generated, the image will not be flipped, etc. */ tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 0 ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } if( flags & SOIL_FLAG_PVR_LOAD_DIRECT ) { tex_id = SOIL_direct_load_PVR( filename, reuse_texture_ID, flags, 0 ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } if( flags & SOIL_FLAG_ETC1_LOAD_DIRECT ) { tex_id = SOIL_direct_load_ETC1( filename, reuse_texture_ID, flags ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } /* try to load the image */ img = SOIL_load_image( filename, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* OK, make it a texture! */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, reuse_texture_ID, flags, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_MAX_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); /* and return the handle, such as it is */ return tex_id; } unsigned int SOIL_load_OGL_HDR_texture ( const char *filename, int fake_HDR_format, int rescale_to_max, unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* img = NULL; int width, height, channels; unsigned int tex_id; /* no direct uploading of the image as a DDS file */ /* error check */ if( (fake_HDR_format != SOIL_HDR_RGBE) && (fake_HDR_format != SOIL_HDR_RGBdivA) && (fake_HDR_format != SOIL_HDR_RGBdivA2) ) { result_string_pointer = "Invalid fake HDR format specified"; return 0; } /* check if the image is HDR */ if ( stbi_is_hdr( filename ) ) { /* try to load the image (only the HDR type) */ img = stbi_load( filename, &width, &height, &channels, 4 ); } /* channels holds the original number of channels, which may have been forced */ if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* the load worked, do I need to convert it? */ if( fake_HDR_format == SOIL_HDR_RGBdivA ) { RGBE_to_RGBdivA( img, width, height, rescale_to_max ); } else if( fake_HDR_format == SOIL_HDR_RGBdivA2 ) { RGBE_to_RGBdivA2( img, width, height, rescale_to_max ); } /* OK, make it a texture! */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, reuse_texture_ID, flags, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_MAX_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); /* and return the handle, such as it is */ return tex_id; } unsigned int SOIL_load_OGL_texture_from_memory ( const unsigned char *const buffer, int buffer_length, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* img; int width, height, channels; unsigned int tex_id; /* does the user want direct uploading of the image as a DDS file? */ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) { /* 1st try direct loading of the image as a DDS file note: direct uploading will only load what is in the DDS file, no MIPmaps will be generated, the image will not be flipped, etc. */ tex_id = SOIL_direct_load_DDS_from_memory( buffer, buffer_length, reuse_texture_ID, flags, 0 ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } if( flags & SOIL_FLAG_PVR_LOAD_DIRECT ) { tex_id = SOIL_direct_load_PVR_from_memory( buffer, buffer_length, reuse_texture_ID, flags, 0 ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } if( flags & SOIL_FLAG_ETC1_LOAD_DIRECT ) { tex_id = SOIL_direct_load_ETC1_from_memory( buffer, buffer_length, reuse_texture_ID, flags ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } /* try to load the image */ img = SOIL_load_image_from_memory( buffer, buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* OK, make it a texture! */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, reuse_texture_ID, flags, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_MAX_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); /* and return the handle, such as it is */ return tex_id; } unsigned int SOIL_load_OGL_cubemap ( const char *x_pos_file, const char *x_neg_file, const char *y_pos_file, const char *y_neg_file, const char *z_pos_file, const char *z_neg_file, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* img; int width, height, channels; unsigned int tex_id; /* error checking */ if( (x_pos_file == NULL) || (x_neg_file == NULL) || (y_pos_file == NULL) || (y_neg_file == NULL) || (z_pos_file == NULL) || (z_neg_file == NULL) ) { result_string_pointer = "Invalid cube map files list"; return 0; } /* capability checking */ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) { result_string_pointer = "No cube map capability present"; return 0; } /* 1st face: try to load the image */ img = SOIL_load_image( x_pos_file, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, and create a texture ID if necessary */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, reuse_texture_ID, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image( x_neg_file, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image( y_pos_file, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image( y_neg_file, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image( z_pos_file, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image( z_neg_file, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* and return the handle, such as it is */ return tex_id; } unsigned int SOIL_load_OGL_cubemap_from_memory ( const unsigned char *const x_pos_buffer, int x_pos_buffer_length, const unsigned char *const x_neg_buffer, int x_neg_buffer_length, const unsigned char *const y_pos_buffer, int y_pos_buffer_length, const unsigned char *const y_neg_buffer, int y_neg_buffer_length, const unsigned char *const z_pos_buffer, int z_pos_buffer_length, const unsigned char *const z_neg_buffer, int z_neg_buffer_length, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* img; int width, height, channels; unsigned int tex_id; /* error checking */ if( (x_pos_buffer == NULL) || (x_neg_buffer == NULL) || (y_pos_buffer == NULL) || (y_neg_buffer == NULL) || (z_pos_buffer == NULL) || (z_neg_buffer == NULL) ) { result_string_pointer = "Invalid cube map buffers list"; return 0; } /* capability checking */ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) { result_string_pointer = "No cube map capability present"; return 0; } /* 1st face: try to load the image */ img = SOIL_load_image_from_memory( x_pos_buffer, x_pos_buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, and create a texture ID if necessary */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, reuse_texture_ID, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image_from_memory( x_neg_buffer, x_neg_buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image_from_memory( y_pos_buffer, y_pos_buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image_from_memory( y_neg_buffer, y_neg_buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image_from_memory( z_pos_buffer, z_pos_buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* continue? */ if( tex_id != 0 ) { /* 1st face: try to load the image */ img = SOIL_load_image_from_memory( z_neg_buffer, z_neg_buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* upload the texture, but reuse the assigned texture ID */ tex_id = SOIL_internal_create_OGL_texture( img, &width, &height, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); /* and nuke the image data */ SOIL_free_image_data( img ); } /* and return the handle, such as it is */ return tex_id; } unsigned int SOIL_load_OGL_single_cubemap ( const char *filename, const char face_order[6], int force_channels, unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* img; int width, height, channels, i; unsigned int tex_id = 0; /* error checking */ if( filename == NULL ) { result_string_pointer = "Invalid single cube map file name"; return 0; } /* does the user want direct uploading of the image as a DDS file? */ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) { /* 1st try direct loading of the image as a DDS file note: direct uploading will only load what is in the DDS file, no MIPmaps will be generated, the image will not be flipped, etc. */ tex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 1 ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } if ( flags & SOIL_FLAG_PVR_LOAD_DIRECT ) { tex_id = SOIL_direct_load_PVR( filename, reuse_texture_ID, flags, 1 ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } if ( flags & SOIL_FLAG_ETC1_LOAD_DIRECT ) { return 0; } /* face order checking */ for( i = 0; i < 6; ++i ) { if( (face_order[i] != 'N') && (face_order[i] != 'S') && (face_order[i] != 'W') && (face_order[i] != 'E') && (face_order[i] != 'U') && (face_order[i] != 'D') ) { result_string_pointer = "Invalid single cube map face order"; return 0; }; } /* capability checking */ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) { result_string_pointer = "No cube map capability present"; return 0; } /* 1st off, try to load the full image */ img = SOIL_load_image( filename, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* now, does this image have the right dimensions? */ if( (width != 6*height) && (6*width != height) ) { SOIL_free_image_data( img ); result_string_pointer = "Single cubemap image must have a 6:1 ratio"; return 0; } /* try the image split and create */ tex_id = SOIL_create_OGL_single_cubemap( img, width, height, channels, face_order, reuse_texture_ID, flags ); /* nuke the temporary image data and return the texture handle */ SOIL_free_image_data( img ); return tex_id; } unsigned int SOIL_load_OGL_single_cubemap_from_memory ( const unsigned char *const buffer, int buffer_length, const char face_order[6], int force_channels, unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* img; int width, height, channels, i; unsigned int tex_id = 0; /* error checking */ if( buffer == NULL ) { result_string_pointer = "Invalid single cube map buffer"; return 0; } /* does the user want direct uploading of the image as a DDS file? */ if( flags & SOIL_FLAG_DDS_LOAD_DIRECT ) { /* 1st try direct loading of the image as a DDS file note: direct uploading will only load what is in the DDS file, no MIPmaps will be generated, the image will not be flipped, etc. */ tex_id = SOIL_direct_load_DDS_from_memory( buffer, buffer_length, reuse_texture_ID, flags, 1 ); if( tex_id ) { /* hey, it worked!! */ return tex_id; } } if ( flags & SOIL_FLAG_PVR_LOAD_DIRECT ) { tex_id = SOIL_direct_load_PVR_from_memory( buffer, buffer_length, reuse_texture_ID, flags, 1 ); if ( tex_id ) { /* hey, it worked!! */ return tex_id; } } if ( flags & SOIL_FLAG_ETC1_LOAD_DIRECT ) { return 0; } /* face order checking */ for( i = 0; i < 6; ++i ) { if( (face_order[i] != 'N') && (face_order[i] != 'S') && (face_order[i] != 'W') && (face_order[i] != 'E') && (face_order[i] != 'U') && (face_order[i] != 'D') ) { result_string_pointer = "Invalid single cube map face order"; return 0; }; } /* capability checking */ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) { result_string_pointer = "No cube map capability present"; return 0; } /* 1st off, try to load the full image */ img = SOIL_load_image_from_memory( buffer, buffer_length, &width, &height, &channels, force_channels ); /* channels holds the original number of channels, which may have been forced */ if( (force_channels >= 1) && (force_channels <= 4) ) { channels = force_channels; } if( NULL == img ) { /* image loading failed */ result_string_pointer = stbi_failure_reason(); return 0; } /* now, does this image have the right dimensions? */ if( (width != 6*height) && (6*width != height) ) { SOIL_free_image_data( img ); result_string_pointer = "Single cubemap image must have a 6:1 ratio"; return 0; } /* try the image split and create */ tex_id = SOIL_create_OGL_single_cubemap( img, width, height, channels, face_order, reuse_texture_ID, flags ); /* nuke the temporary image data and return the texture handle */ SOIL_free_image_data( img ); return tex_id; } unsigned int SOIL_create_OGL_single_cubemap ( const unsigned char *const data, int width, int height, int channels, const char face_order[6], unsigned int reuse_texture_ID, unsigned int flags ) { /* variables */ unsigned char* sub_img; int dw, dh, sz, i; unsigned int tex_id; /* error checking */ if( data == NULL ) { result_string_pointer = "Invalid single cube map image data"; return 0; } /* face order checking */ for( i = 0; i < 6; ++i ) { if( (face_order[i] != 'N') && (face_order[i] != 'S') && (face_order[i] != 'W') && (face_order[i] != 'E') && (face_order[i] != 'U') && (face_order[i] != 'D') ) { result_string_pointer = "Invalid single cube map face order"; return 0; }; } /* capability checking */ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) { result_string_pointer = "No cube map capability present"; return 0; } /* now, does this image have the right dimensions? */ if( (width != 6*height) && (6*width != height) ) { result_string_pointer = "Single cubemap image must have a 6:1 ratio"; return 0; } /* which way am I stepping? */ if( width > height ) { dw = height; dh = 0; } else { dw = 0; dh = width; } sz = dw+dh; sub_img = (unsigned char *)malloc( sz*sz*channels ); /* do the splitting and uploading */ tex_id = reuse_texture_ID; for( i = 0; i < 6; ++i ) { int x, y, idx = 0; unsigned int cubemap_target = 0; /* copy in the sub-image */ for( y = i*dh; y < i*dh+sz; ++y ) { for( x = i*dw*channels; x < (i*dw+sz)*channels; ++x ) { sub_img[idx++] = data[y*width*channels+x]; } } /* what is my texture target? remember, this coordinate system is LHS if viewed from inside the cube! */ switch( face_order[i] ) { case 'N': cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z; break; case 'S': cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z; break; case 'W': cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X; break; case 'E': cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X; break; case 'U': cubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y; break; case 'D': cubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y; break; } /* upload it as a texture */ tex_id = SOIL_internal_create_OGL_texture( sub_img, &sz, &sz, channels, tex_id, flags, SOIL_TEXTURE_CUBE_MAP, cubemap_target, SOIL_MAX_CUBE_MAP_TEXTURE_SIZE ); } /* and nuke the image and sub-image data */ SOIL_free_image_data( sub_img ); /* and return the handle, such as it is */ return tex_id; } unsigned int SOIL_create_OGL_texture ( const unsigned char *const data, int *width, int *height, int channels, unsigned int reuse_texture_ID, unsigned int flags ) { /* wrapper function for 2D textures */ return SOIL_internal_create_OGL_texture( data, width, height, channels, reuse_texture_ID, flags, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_MAX_TEXTURE_SIZE ); } #if SOIL_CHECK_FOR_GL_ERRORS void check_for_GL_errors( const char *calling_location ) { /* check for errors */ GLenum err_code = glGetError(); while( GL_NO_ERROR != err_code ) { printf( "OpenGL Error @ %s: %i", calling_location, err_code ); err_code = glGetError(); } } #else void check_for_GL_errors( const char *calling_location ) { /* no check for errors */ } #endif static void createMipmaps(const unsigned char *const img, int width, int height, int channels, unsigned int flags, unsigned int opengl_texture_target, unsigned int internal_texture_format, unsigned int original_texture_format, int DXT_mode) { if ( ( flags & SOIL_FLAG_GL_MIPMAPS ) && query_gen_mipmap_capability() == SOIL_CAPABILITY_PRESENT ) { soilGlGenerateMipmap(opengl_texture_target); } else { int MIPlevel = 1; int MIPwidth = (width+1) / 2; int MIPheight = (height+1) / 2; unsigned char *resampled = (unsigned char*)malloc( channels*MIPwidth*MIPheight ); while( ((1< 0; --i ) { unsigned char temp = img[index1]; img[index1] = img[index2]; img[index2] = temp; ++index1; ++index2; } } } /* does the user want me to scale the colors into the NTSC safe RGB range? */ if( flags & SOIL_FLAG_NTSC_SAFE_RGB ) { scale_image_RGB_to_NTSC_safe( img, iwidth, iheight, channels ); } /* does the user want me to convert from straight to pre-multiplied alpha? (and do we even _have_ alpha?) */ if( flags & SOIL_FLAG_MULTIPLY_ALPHA ) { int i; switch( channels ) { case 2: for( i = 0; i < 2*iwidth*iheight; i += 2 ) { img[i] = (img[i] * img[i+1] + 128) >> 8; } break; case 4: for( i = 0; i < 4*iwidth*iheight; i += 4 ) { img[i+0] = (img[i+0] * img[i+3] + 128) >> 8; img[i+1] = (img[i+1] * img[i+3] + 128) >> 8; img[i+2] = (img[i+2] * img[i+3] + 128) >> 8; } break; default: /* no other number of channels contains alpha data */ break; } } /* do I need to make it a power of 2? */ if( ( ( flags & SOIL_FLAG_POWER_OF_TWO) && ( !SOIL_IS_POW2(iwidth) || !SOIL_IS_POW2(iheight) ) ) || /* user asked for it and the texture is not power of 2 */ ( (flags & SOIL_FLAG_MIPMAPS)&& !( ( flags & SOIL_FLAG_GL_MIPMAPS ) && query_gen_mipmap_capability() == SOIL_CAPABILITY_PRESENT && query_NPOT_capability() == SOIL_CAPABILITY_PRESENT ) ) || /* need it for the MIP-maps when mipmaps required and not GL mipmaps required and supported */ (iwidth > max_supported_size) || /* it's too big, (make sure it's */ (iheight > max_supported_size) ) /* 2^n for later down-sampling) */ { int new_width = 1; int new_height = 1; while( new_width < iwidth ) { new_width *= 2; } while( new_height < iheight ) { new_height *= 2; } /* still? */ if( (new_width != iwidth) || (new_height != iheight) ) { /* yep, resize */ unsigned char *resampled = (unsigned char*)malloc( channels*new_width*new_height ); up_scale_image( NULL != img ? img : data, iwidth, iheight, channels, resampled, new_width, new_height ); /* nuke the old guy ( if a copy exists ), then point it at the new guy */ SOIL_free_image_data( img ); img = resampled; *width = new_width; *height = new_height; iwidth = new_width; iheight = new_height; } } /* now, if it is too large... */ if( (iwidth > max_supported_size) || (iheight > max_supported_size) ) { /* I've already made it a power of two, so simply use the MIPmapping code to reduce its size to the allowable maximum. */ unsigned char *resampled; int reduce_block_x = 1, reduce_block_y = 1; int new_width, new_height; if( iwidth > max_supported_size ) { reduce_block_x = iwidth / max_supported_size; } if( iheight > max_supported_size ) { reduce_block_y = iheight / max_supported_size; } new_width = iwidth / reduce_block_x; new_height = iheight / reduce_block_y; resampled = (unsigned char*)malloc( channels*new_width*new_height ); /* perform the actual reduction */ mipmap_image( NULL != img ? img : data, iwidth, iheight, channels, resampled, reduce_block_x, reduce_block_y ); /* nuke the old guy, then point it at the new guy */ SOIL_free_image_data( img ); img = resampled; *width = new_width; *height = new_height; iwidth = new_width; iheight = new_height; } /* does the user want us to use YCoCg color space? */ if( flags & SOIL_FLAG_CoCg_Y ) { /* this will only work with RGB and RGBA images */ convert_RGB_to_YCoCg( img, iwidth, iheight, channels ); } /* create the OpenGL texture ID handle (note: allowing a forced texture ID lets me reload a texture) */ tex_id = reuse_texture_ID; if( tex_id == 0 ) { glGenTextures( 1, &tex_id ); } check_for_GL_errors( "glGenTextures" ); /* Note: sometimes glGenTextures fails (usually no OpenGL context) */ if( tex_id ) { /* and what type am I using as the internal texture format? */ switch( channels ) { case 1: original_texture_format = GL_LUMINANCE; break; case 2: original_texture_format = GL_LUMINANCE_ALPHA; break; case 3: original_texture_format = GL_RGB; break; case 4: original_texture_format = GL_RGBA; break; } internal_texture_format = original_texture_format; /* does the user want me to, and can I, save as DXT? */ if( flags & SOIL_FLAG_COMPRESS_TO_DXT ) { DXT_mode = query_DXT_capability(); if( DXT_mode == SOIL_CAPABILITY_PRESENT ) { /* I can use DXT, whether I compress it or OpenGL does */ if( (channels & 1) == 1 ) { /* 1 or 3 channels = DXT1 */ internal_texture_format = sRGB_texture ? SOIL_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT : SOIL_RGB_S3TC_DXT1; } else { /* 2 or 4 channels = DXT5 */ internal_texture_format = sRGB_texture ? SOIL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : SOIL_RGBA_S3TC_DXT5; } } } else if ( sRGB_texture ) { switch( channels ) { case 3: internal_texture_format = SOIL_GL_SRGB; break; case 4: internal_texture_format = SOIL_GL_SRGB_ALPHA; break; } } /* bind an OpenGL texture ID */ glBindTexture( opengl_texture_type, tex_id ); check_for_GL_errors( "glBindTexture" ); /* set the unpack aligment */ glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_aligment); if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT,1); } /* upload the main image */ if( DXT_mode == SOIL_CAPABILITY_PRESENT ) { /* user wants me to do the DXT conversion! */ int DDS_size; unsigned char *DDS_data = NULL; if( (channels & 1) == 1 ) { /* RGB, use DXT1 */ DDS_data = convert_image_to_DXT1( NULL != img ? img : data, iwidth, iheight, channels, &DDS_size ); } else { /* RGBA, use DXT5 */ DDS_data = convert_image_to_DXT5( NULL != img ? img : data, iwidth, iheight, channels, &DDS_size ); } if( DDS_data ) { soilGlCompressedTexImage2D( opengl_texture_target, 0, internal_texture_format, iwidth, iheight, 0, DDS_size, DDS_data ); check_for_GL_errors( "glCompressedTexImage2D" ); SOIL_free_image_data( DDS_data ); /* printf( "Internal DXT compressor\n" ); */ } else { /* my compression failed, try the OpenGL driver's version */ glTexImage2D( opengl_texture_target, 0, internal_texture_format, iwidth, iheight, 0, original_texture_format, GL_UNSIGNED_BYTE, NULL != img ? img : data ); check_for_GL_errors( "glTexImage2D" ); /* printf( "OpenGL DXT compressor\n" ); */ } } else { /* user want OpenGL to do all the work! */ glTexImage2D( opengl_texture_target, 0, internal_texture_format, iwidth, iheight, 0, original_texture_format, GL_UNSIGNED_BYTE, NULL != img ? img : data ); check_for_GL_errors( "glTexImage2D" ); /*printf( "OpenGL DXT compressor\n" ); */ } /* are any MIPmaps desired? */ if( flags & SOIL_FLAG_MIPMAPS || flags & SOIL_FLAG_GL_MIPMAPS ) { createMipmaps( NULL != img ? img : data, iwidth, iheight, channels, flags, opengl_texture_target, internal_texture_format, original_texture_format, DXT_mode ); /* instruct OpenGL to use the MIPmaps */ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); check_for_GL_errors( "GL_TEXTURE_MIN/MAG_FILTER" ); } else { /* instruct OpenGL _NOT_ to use the MIPmaps */ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); check_for_GL_errors( "GL_TEXTURE_MIN/MAG_FILTER" ); } /* recover the unpack aligment */ if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment); } /* does the user want clamping, or wrapping? */ if( flags & SOIL_FLAG_TEXTURE_REPEATS ) { glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT ); if( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP ) { /* SOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported */ glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT ); } check_for_GL_errors( "GL_TEXTURE_WRAP_*" ); } else { unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; /* unsigned int clamp_mode = GL_CLAMP; */ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode ); if( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP ) { /* SOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported */ glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode ); } check_for_GL_errors( "GL_TEXTURE_WRAP_*" ); } /* done */ result_string_pointer = "Image loaded as an OpenGL texture"; } else { /* failed */ result_string_pointer = "Failed to generate an OpenGL texture name; missing OpenGL context?"; } SOIL_free_image_data( img ); return tex_id; } int SOIL_save_screenshot ( const char *filename, int image_type, int x, int y, int width, int height ) { unsigned char *pixel_data; int i, j; int save_result; GLint pack_aligment; /* error checks */ if( (width < 1) || (height < 1) ) { result_string_pointer = "Invalid screenshot dimensions"; return 0; } if( (x < 0) || (y < 0) ) { result_string_pointer = "Invalid screenshot location"; return 0; } if( filename == NULL ) { result_string_pointer = "Invalid screenshot filename"; return 0; } glGetIntegerv(GL_PACK_ALIGNMENT, &pack_aligment); if ( 1 != pack_aligment ) { glPixelStorei(GL_PACK_ALIGNMENT,1); } /* Get the data from OpenGL */ pixel_data = (unsigned char*)malloc( 3*width*height ); glReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixel_data); if ( 1 != pack_aligment ) { glPixelStorei(GL_PACK_ALIGNMENT, pack_aligment); } /* invert the image */ for( j = 0; j*2 < height; ++j ) { int index1 = j * width * 3; int index2 = (height - 1 - j) * width * 3; for( i = width * 3; i > 0; --i ) { unsigned char temp = pixel_data[index1]; pixel_data[index1] = pixel_data[index2]; pixel_data[index2] = temp; ++index1; ++index2; } } /* save the image */ save_result = SOIL_save_image( filename, image_type, width, height, 3, pixel_data); /* And free the memory */ SOIL_free_image_data( pixel_data ); return save_result; } unsigned char* SOIL_load_image ( const char *filename, int *width, int *height, int *channels, int force_channels ) { unsigned char *result = stbi_load( filename, width, height, channels, force_channels ); if( result == NULL ) { result_string_pointer = stbi_failure_reason(); } else { result_string_pointer = "Image loaded"; } return result; } unsigned char* SOIL_load_image_from_memory ( const unsigned char *const buffer, int buffer_length, int *width, int *height, int *channels, int force_channels ) { unsigned char *result = stbi_load_from_memory( buffer, buffer_length, width, height, channels, force_channels ); if( result == NULL ) { result_string_pointer = stbi_failure_reason(); } else { result_string_pointer = "Image loaded from memory"; } return result; } int SOIL_save_image ( const char *filename, int image_type, int width, int height, int channels, const unsigned char *const data ) { return SOIL_save_image_quality( filename, image_type, width, height, channels, data, 80 ); } int SOIL_save_image_quality ( const char *filename, int image_type, int width, int height, int channels, const unsigned char *const data, int quality ) { int save_result; /* error check */ if( (width < 1) || (height < 1) || (channels < 1) || (channels > 4) || (data == NULL) || (filename == NULL) ) { return 0; } if( image_type == SOIL_SAVE_TYPE_BMP ) { save_result = stbi_write_bmp( filename, width, height, channels, (const void*)data ); } else if( image_type == SOIL_SAVE_TYPE_TGA ) { save_result = stbi_write_tga( filename, width, height, channels, (const void*)data ); } else if( image_type == SOIL_SAVE_TYPE_DDS ) { save_result = save_image_as_DDS( filename, width, height, channels, (const unsigned char *const)data ); } else if( image_type == SOIL_SAVE_TYPE_PNG ) { save_result = stbi_write_png( filename, width, height, channels, (const void*)data, 0 ); } else if ( image_type == SOIL_SAVE_TYPE_JPG ) { save_result = stbi_write_jpg( filename, width, height, channels, (const void*)data, quality ); } else if ( image_type == SOIL_SAVE_TYPE_QOI ) { save_result = stbi_write_qoi( filename, width, height, channels, (const void*)data ); } else { save_result = 0; } if( save_result == 0 ) { result_string_pointer = "Saving the image failed"; } else { result_string_pointer = "Image saved"; } return save_result; } typedef struct { unsigned char* buffer; int allocated; // number of bytes allocated to the buffer int written; // number of bytes written to the buffer int alloc_block_size; // size of blocks to alloc as memory is required } stbi_write_context; void write_to_memory(void* context, void* data, int size) { stbi_write_context* ctx = (stbi_write_context*)context; if(ctx == 0) return; if (ctx->buffer == 0) { // safety ctx->written = 0; ctx->allocated = 0; // first alloc while (ctx->allocated < (ctx->written + size)) { ctx->allocated += ctx->alloc_block_size; } ctx->buffer = (unsigned char*) malloc(ctx->allocated); } else if((ctx->written + size) > ctx->allocated) { ctx->allocated += ctx->alloc_block_size; while (ctx->allocated < (ctx->written + size)) { ctx->allocated += ctx->alloc_block_size; } unsigned char* rebuff = (unsigned char*)realloc(ctx->buffer, ctx->allocated); if (rebuff == 0) { // out of memory free(ctx->buffer); ctx->buffer = 0; ctx->allocated = 0; return; } else { ctx->buffer = rebuff; } } if(ctx->buffer == 0) return; memcpy(ctx->buffer + ctx->written, data, size); ctx->written += size; } // release the returned memory with SOIL_free_image_data unsigned char* SOIL_write_image_to_memory_quality ( int image_type, int width, int height, int channels, const unsigned char* const data, int quality, int* imageSize ) { int save_result; /* error check */ if ((width < 1) || (height < 1) || (channels < 1) || (channels > 4) || (data == NULL) || (imageSize == NULL) ) { return 0; } unsigned char* imageMemory = NULL; *imageSize = 0; stbi_write_context context; context.alloc_block_size = 4096; // 4k chunks context.buffer = 0; context.allocated = 0; context.written = 0; if (image_type == SOIL_SAVE_TYPE_BMP) { save_result = stbi_write_bmp_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data); } else if (image_type == SOIL_SAVE_TYPE_TGA) { save_result = stbi_write_tga_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data); } else if (image_type == SOIL_SAVE_TYPE_DDS) { save_result = 0; // not supported thru stbi } else if (image_type == SOIL_SAVE_TYPE_PNG) { save_result = stbi_write_png_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data, 0); } else if (image_type == SOIL_SAVE_TYPE_JPG) { save_result = stbi_write_jpg_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data, quality); } else { save_result = 0; } if (save_result) { imageMemory = context.buffer; *imageSize = context.written; } else { if (context.buffer) free(context.buffer); } if (save_result == 0) { result_string_pointer = "writing the image failed"; } else { result_string_pointer = "Image written"; } return imageMemory; } // release the returned memory with SOIL_free_image_data unsigned char* SOIL_write_image_to_memory ( int image_type, int width, int height, int channels, const unsigned char* const data, int* imageSize ) { return SOIL_write_image_to_memory_quality(image_type, width, height, channels, data, 80, imageSize); } void SOIL_free_image_data ( unsigned char *img_data ) { if ( img_data ) free( (void*)img_data ); } const char* SOIL_last_result ( void ) { return result_string_pointer; } /* This circumvent a VS2022 compiler bug */ #ifdef _MSC_VER #pragma optimize( "", off ) #endif static inline int calc_total_block_size( int w, int h, int block_size ) { return ( ( w + 3 ) >> 2 ) * ( ( h + 3 ) >> 2 ) * block_size; } #ifdef _MSC_VER #pragma optimize( "", on ) #endif unsigned int SOIL_direct_load_DDS_from_memory( const unsigned char *const buffer, int buffer_length, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap) { unsigned int buffer_index = 0; unsigned int tex_ID = 0; unsigned int internal_format = 0; unsigned char *DDS_data; unsigned int DDS_main_size; unsigned int DDS_full_size; int mipmaps, block_size = 16; unsigned int cf_target, ogl_target_start, ogl_target_end; unsigned int opengl_texture_type; unsigned int format_type = GL_UNSIGNED_BYTE; /* 1st off, does the filename even exist? */ if( NULL == buffer ) { /* we can't do it! */ result_string_pointer = "NULL buffer"; return 0; } if( buffer_length < (int)sizeof( DDS_header ) ) { /* we can't do it! */ result_string_pointer = "DDS file was too small to contain the DDS header"; return 0; } // Try reading in the header DDS_header header; memcpy( (void *)( &header ), (const void *)buffer, sizeof( DDS_header ) ); buffer_index += sizeof(DDS_header); /* guilty until proven innocent */ result_string_pointer = "Failed to read a known DDS header"; /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */ unsigned int flag = ( 'D' << 0 ) | ( 'D' << 8 ) | ( 'S' << 16 ) | ( ' ' << 24 ); if( header.dwMagic != flag ) { goto quick_exit; } if( header.dwSize != 124 ) { goto quick_exit; } /* I need all of these */ flag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; if( ( header.dwFlags & flag ) != flag ) { goto quick_exit; } /* According to the MSDN spec, the dwFlags should contain DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if uncompressed. Some DDS writers do not conform to the spec, so I need to make my reader more tolerant */ /* I need one of these */ flag = DDPF_FOURCC | DDPF_RGB | DDPF_LUMINANCE; if( ( header.sPixelFormat.dwFlags & flag ) == 0 ) { goto quick_exit; } if( header.sPixelFormat.dwSize != 32 ) { goto quick_exit; } if( ( header.sCaps.dwCaps1 & DDSCAPS_TEXTURE ) == 0 ) { goto quick_exit; } enum Magics { DXT1 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( 'T' << 16 ) | ( '1' << 24 ), DXT3 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( 'T' << 16 ) | ( '3' << 24 ), DXT5 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( 'T' << 16 ) | ( '5' << 24 ), ATI2 = ( 'A' << 0 ) | ( 'T' << 8 ) | ( 'I' << 16 ) | ( '2' << 24 ), DX10 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( '1' << 16 ) | ( '0' << 24 ), }; // DX10 has an extended header DDS_HEADER_DXT10 dx10_header; if (header.sPixelFormat.dwFourCC == DX10) { memcpy((void*)(&dx10_header), (const void*)&buffer[buffer_index], sizeof(DDS_HEADER_DXT10)); buffer_index += sizeof(dx10_header); } // make sure it is a type we can upload if ((header.sPixelFormat.dwFlags & DDPF_FOURCC) && header.sPixelFormat.dwFourCC != DXT1 && header.sPixelFormat.dwFourCC != DXT3 && header.sPixelFormat.dwFourCC != DXT5 && header.sPixelFormat.dwFourCC != ATI2 && header.sPixelFormat.dwFourCC != DX10 ){ goto quick_exit; } /* OK, validated the header, let's load the image data */ result_string_pointer = "DDS header loaded and validated"; const int width = header.dwWidth; const int height = header.dwHeight; int uncompressed = 1 - ( header.sPixelFormat.dwFlags & DDPF_FOURCC ) / DDPF_FOURCC; int cubemap = ( header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP ) / DDSCAPS2_CUBEMAP; if( uncompressed ) { if( header.sPixelFormat.dwRGBBitCount == 8 ) { if( ( header.sPixelFormat.dwRBitMask == 0xe0 ) && ( header.sPixelFormat.dwGBitMask == 0x1c ) && ( header.sPixelFormat.dwBBitMask == 0x3 ) ) { internal_format = GL_RGB; format_type = GL_UNSIGNED_BYTE_3_3_2; block_size = 1; } else { internal_format = GL_LUMINANCE; block_size = 1; } } else if( header.sPixelFormat.dwRGBBitCount == 16 ) { if( ( header.sPixelFormat.dwRBitMask == 0xf800 ) && ( header.sPixelFormat.dwGBitMask == 0x7e0 ) && ( header.sPixelFormat.dwBBitMask == 0x1f ) ) { // DXGI_FORMAT_B5G6R5_UNORM internal_format = GL_RGBA; format_type = GL_UNSIGNED_SHORT_5_5_5_1; block_size = 2; } else if( ( header.sPixelFormat.dwRBitMask == 0xf00 ) && ( header.sPixelFormat.dwGBitMask == 0xf0 ) && ( header.sPixelFormat.dwBBitMask == 0xf ) && ( header.sPixelFormat.dwAlphaBitMask == 0xf000 ) ) { // D3DFMT_A4R4G4B4 internal_format = GL_RGBA; format_type = GL_UNSIGNED_SHORT_4_4_4_4; block_size = 2; } else if( ( header.sPixelFormat.dwRBitMask == 0x7c00 ) && ( header.sPixelFormat.dwGBitMask == 0x3e0 ) && ( header.sPixelFormat.dwBBitMask == 0x1f ) ) { // DXGI_FORMAT_B5G5R5A1_UNORM internal_format = GL_RGBA; format_type = GL_UNSIGNED_SHORT_5_5_5_1; block_size = 2; } else { internal_format = GL_RG; block_size = 2; } } else { internal_format = GL_RGB; block_size = 3; if( header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS ) { internal_format = GL_RGBA; block_size = 4; } } DDS_main_size = width * height * block_size; } else { if( header.sPixelFormat.dwFourCC == ATI2 ) { if( query_3Dc_capability() != SOIL_CAPABILITY_PRESENT ) { /* we can't do it! */ result_string_pointer = "Direct upload of 3Dc images not supported by the OpenGL driver"; return 0; } } else { if( query_DXT_capability() != SOIL_CAPABILITY_PRESENT ) { /* we can't do it! */ result_string_pointer = "Direct upload of S3TC images not supported by the OpenGL driver"; return 0; } } switch( header.sPixelFormat.dwFourCC ) { case DXT1: internal_format = SOIL_RGBA_S3TC_DXT1; block_size = 8; break; case DXT3: internal_format = SOIL_RGBA_S3TC_DXT3; block_size = 16; break; case DXT5: internal_format = SOIL_RGBA_S3TC_DXT5; block_size = 16; break; case ATI2: block_size = 16; internal_format = SOIL_COMPRESSED_RG_RGTC2; break; case DX10: if (dx10_header.dxgiFormat != DXGI_FORMAT_BC5_UNORM) { result_string_pointer = "The DX10 reader only supports BC5 unorm at the moment"; return 0; } block_size = 16; internal_format = SOIL_COMPRESSED_RG_RGTC2; break; } DDS_main_size = ( ( width + 3 ) >> 2 ) * ( ( height + 3 ) >> 2 ) * block_size; } if( cubemap ) { /* does the user want a cubemap? */ if( !loading_as_cubemap ) { /* we can't do it! */ result_string_pointer = "DDS image was a cubemap"; return 0; } /* can we even handle cubemaps with the OpenGL driver? */ if( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT ) { /* we can't do it! */ result_string_pointer = "Direct upload of cubemap images not supported by the OpenGL driver"; return 0; } ogl_target_start = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X; ogl_target_end = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z; opengl_texture_type = SOIL_TEXTURE_CUBE_MAP; } else { /* does the user want a non-cubemap? */ if( loading_as_cubemap ) { /* we can't do it! */ result_string_pointer = "DDS image was not a cubemap"; return 0; } ogl_target_start = GL_TEXTURE_2D; ogl_target_end = GL_TEXTURE_2D; opengl_texture_type = GL_TEXTURE_2D; } if( ( header.sCaps.dwCaps1 & DDSCAPS_MIPMAP ) && ( header.dwMipMapCount > 1 ) ) { mipmaps = header.dwMipMapCount - 1; DDS_full_size = DDS_main_size; for( int i = 1; i <= mipmaps; ++i ) { int w = width >> i; int h = height >> i; if( w < 1 ) { w = 1; } if( h < 1 ) { h = 1; } if( uncompressed ) { /* uncompressed DDS, simple MIPmap size calculation */ DDS_full_size += w * h * block_size; } else { /* compressed DDS, MIPmap size calculation is block based */ DDS_full_size += calc_total_block_size( w, h, block_size ); } } } else { mipmaps = 0; DDS_full_size = DDS_main_size; } DDS_data = (unsigned char *)malloc( DDS_full_size ); /* got the image data RAM, create or use an existing OpenGL texture handle */ tex_ID = reuse_texture_ID; if( tex_ID == 0 ) { glGenTextures( 1, &tex_ID ); } /* bind an OpenGL texture ID */ glBindTexture( opengl_texture_type, tex_ID ); /* do this for each face of the cubemap! */ for( cf_target = ogl_target_start; cf_target <= ogl_target_end; ++cf_target ) { if( buffer_index + DDS_full_size <= (unsigned int)buffer_length ) { unsigned int byte_offset = DDS_main_size; memcpy( (void *)DDS_data, (const void *)( &buffer[buffer_index] ), DDS_full_size ); buffer_index += DDS_full_size; /* upload the main chunk */ if( uncompressed ) { if( ( header.sPixelFormat.dwRBitMask == 0xff0000 ) && ( ( block_size == 3 && internal_format == GL_RGB ) || ( block_size == 4 && internal_format == GL_RGBA ) ) ) { for( int i = 0; i < (int)DDS_full_size; i += block_size ) { unsigned char temp = DDS_data[i]; DDS_data[i] = DDS_data[i + 2]; DDS_data[i + 2] = temp; } } else if( block_size == 2 && ( header.sPixelFormat.dwRBitMask == 0xf800 || header.sPixelFormat.dwRBitMask == 0x7c00 ) ) { // convert to R5G5B5A1 for( int i = 0; i < (int)DDS_full_size; i += block_size ) { unsigned short pixel = DDS_data[i] << 0 | DDS_data[i + 1] << 8; char r = ( ( pixel & header.sPixelFormat.dwRBitMask ) >> 10 ); char g = ( ( pixel & header.sPixelFormat.dwGBitMask ) >> 5 ); char b = ( ( pixel & header.sPixelFormat.dwBBitMask ) >> 0 ); char a = 1; if( header.sPixelFormat.dwAlphaBitMask != 0 ) { a = ( pixel & header.sPixelFormat.dwAlphaBitMask ) >> 15; } unsigned short pixel_new = ( r << 11 ) | ( g << 6 ) | ( b << 1 ) | a; DDS_data[i] = ( pixel_new >> 0 ) & 0xff; DDS_data[i + 1] = ( pixel_new >> 8 ) & 0xff; } } else if( block_size == 2 && ( header.sPixelFormat.dwRBitMask == 0xf00 ) && ( header.sPixelFormat.dwGBitMask == 0xf0 ) && ( header.sPixelFormat.dwBBitMask == 0xf ) && ( header.sPixelFormat.dwAlphaBitMask == 0xf000 ) ) { for( int i = 0; i < (int)DDS_full_size; i += block_size ) { unsigned short pixel = DDS_data[i] << 0 | DDS_data[i + 1] << 8; char r = ( ( pixel & header.sPixelFormat.dwRBitMask ) >> 8 ); char g = ( ( pixel & header.sPixelFormat.dwGBitMask ) >> 4 ); char b = ( ( pixel & header.sPixelFormat.dwBBitMask ) >> 0 ); char a = ( ( pixel & header.sPixelFormat.dwAlphaBitMask ) >> 12 ); unsigned short pixel_new = ( r << 12 ) | ( g << 8 ) | ( b << 4 ) | a; DDS_data[i] = ( pixel_new >> 0 ) & 0xff; DDS_data[i + 1] = ( pixel_new >> 8 ) & 0xff; } } glTexImage2D( cf_target, 0, internal_format, width, height, 0, internal_format, format_type, DDS_data ); } else { soilGlCompressedTexImage2D( cf_target, 0, internal_format, width, height, 0, DDS_main_size, DDS_data ); } /* upload the mipmaps, if we have them */ for( int i = 1; i <= mipmaps; ++i ) { int w, h, mip_size; w = width >> i; h = height >> i; if( w < 1 ) { w = 1; } if( h < 1 ) { h = 1; } /* upload this mipmap */ if( uncompressed ) { mip_size = w * h * block_size; glTexImage2D( cf_target, i, internal_format, w, h, 0, internal_format, format_type, &DDS_data[byte_offset] ); } else { mip_size = ( ( w + 3 ) / 4 ) * ( ( h + 3 ) / 4 ) * block_size; soilGlCompressedTexImage2D( cf_target, i, internal_format, w, h, 0, mip_size, &DDS_data[byte_offset] ); } /* and move to the next mipmap */ byte_offset += mip_size; } /* it worked! */ result_string_pointer = "DDS file loaded"; } else { glDeleteTextures( 1, &tex_ID ); tex_ID = 0; cf_target = ogl_target_end + 1; result_string_pointer = "DDS file was too small for expected image data"; } } /* end reading each face */ SOIL_free_image_data( DDS_data ); if( tex_ID ) { /* did I have MIPmaps? */ if( mipmaps > 0 ) { /* instruct OpenGL to use the MIPmaps */ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); } else { /* instruct OpenGL _NOT_ to use the MIPmaps */ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); } /* does the user want clamping, or wrapping? */ if( flags & SOIL_FLAG_TEXTURE_REPEATS ) { glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT ); } else { unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; /* unsigned int clamp_mode = GL_CLAMP; */ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode ); glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode ); } } quick_exit: return tex_ID; } unsigned int SOIL_direct_load_DDS( const char *filename, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap ) { FILE *f; unsigned char *buffer; size_t buffer_length, bytes_read; unsigned int tex_ID = 0; /* error checks */ if( NULL == filename ) { result_string_pointer = "NULL filename"; return 0; } f = fopen( filename, "rb" ); if( NULL == f ) { /* the file doesn't seem to exist (or be open-able) */ result_string_pointer = "Can not find DDS file"; return 0; } fseek( f, 0, SEEK_END ); buffer_length = ftell( f ); fseek( f, 0, SEEK_SET ); buffer = (unsigned char *) malloc( buffer_length ); if( NULL == buffer ) { result_string_pointer = "malloc failed"; fclose( f ); return 0; } bytes_read = fread( (void*)buffer, 1, buffer_length, f ); fclose( f ); if( bytes_read < buffer_length ) { /* huh? */ buffer_length = bytes_read; } /* now try to do the loading */ tex_ID = SOIL_direct_load_DDS_from_memory( (const unsigned char *const)buffer, (int)buffer_length, reuse_texture_ID, flags, loading_as_cubemap ); SOIL_free_image_data( buffer ); return tex_ID; } unsigned int SOIL_direct_load_PVR_from_memory( const unsigned char *const buffer, int buffer_length, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap ) { PVR_Texture_Header* header = (PVR_Texture_Header*)buffer; int num_surfs = 1; GLuint tex_ID = 0; GLenum PVR_format = 0; GLenum PVR_type = GL_RGB; unsigned int opengl_texture_type = loading_as_cubemap ? SOIL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; int is_PVRTC_supported = query_PVR_capability() == SOIL_CAPABILITY_PRESENT; int is_BGRA8888_supported = query_BGRA8888_capability() == SOIL_CAPABILITY_PRESENT; int is_compressed_format_supported = 0; int is_compressed_format = 0; int mipmaps = 0; int i; GLint unpack_aligment; // Check the header size if ( header->dwHeaderSize != sizeof(PVR_Texture_Header) ) { if ( header->dwHeaderSize == PVRTEX_V1_HEADER_SIZE ) { result_string_pointer = "this is an old pvr ( update the PVR file )"; if ( loading_as_cubemap ) { if( header->dwpfFlags & PVRTEX_CUBEMAP ) { num_surfs = 6; } else { result_string_pointer = "tried to load a non-cubemap PVR as cubemap"; return 0; } } } else { result_string_pointer = "invalid PVR header"; return 0; } } else { if ( loading_as_cubemap ) { // Header V2 if( header->dwNumSurfs < 1 ) { if( header->dwpfFlags & PVRTEX_CUBEMAP ) { num_surfs = 6; } else { result_string_pointer = "tried to load a non-cubemap PVR as cubemap"; return 0; } } else { num_surfs = header->dwNumSurfs; } } } // Check the magic identifier if ( header->dwPVR != PVRTEX_IDENTIFIER ) { result_string_pointer = "invalid PVR header"; return 0; } /* Only accept untwiddled data UNLESS texture format is PVRTC */ if ( ((header->dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE) && ((header->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC2) && ((header->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC4) ) { // We need to load untwiddled textures -- hw will twiddle for us. result_string_pointer = "pvr is not compressed ( untwiddled texture )"; return 0; } switch( header->dwpfFlags & PVRTEX_PIXELTYPE ) { case OGL_RGBA_4444: PVR_format = GL_UNSIGNED_SHORT_4_4_4_4; PVR_type = GL_RGBA; break; case OGL_RGBA_5551: PVR_format = GL_UNSIGNED_SHORT_5_5_5_1; PVR_type = GL_RGBA; break; case OGL_RGBA_8888: PVR_format = GL_UNSIGNED_BYTE; PVR_type = GL_RGBA; break; case OGL_RGB_565: PVR_format = GL_UNSIGNED_SHORT_5_6_5; PVR_type = GL_RGB; break; case OGL_RGB_555: result_string_pointer = "failed: pixel type OGL_RGB_555 not supported."; return 0; case OGL_RGB_888: PVR_format = GL_UNSIGNED_BYTE; PVR_type = GL_RGB; break; case OGL_I_8: PVR_format = GL_UNSIGNED_BYTE; PVR_type = GL_LUMINANCE; break; case OGL_AI_88: PVR_format = GL_UNSIGNED_BYTE; PVR_type = GL_LUMINANCE_ALPHA; break; case MGLPT_PVRTC2: case OGL_PVRTC2: if(is_PVRTC_supported) { is_compressed_format_supported = is_compressed_format = 1; PVR_format = header->dwAlphaBitMask==0 ? SOIL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG : SOIL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG ; // PVRTC2 } else { result_string_pointer = "error: PVRTC2 not supported.Decompress the texture first."; return 0; } break; case MGLPT_PVRTC4: case OGL_PVRTC4: if(is_PVRTC_supported) { is_compressed_format_supported = is_compressed_format = 1; PVR_format = header->dwAlphaBitMask==0 ? SOIL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG : SOIL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ; // PVRTC4 } else { result_string_pointer = "error: PVRTC4 not supported. Decompress the texture first."; return 0; } break; case OGL_BGRA_8888: if(is_BGRA8888_supported) { PVR_format = GL_UNSIGNED_BYTE; PVR_type = GL_BGRA; break; } else { result_string_pointer = "Unable to load GL_BGRA texture as extension GL_IMG_texture_format_BGRA8888 is unsupported."; return 0; } default: // NOT SUPPORTED result_string_pointer = "failed: pixel type not supported."; return 0; } #ifdef SOIL_GLES1 // check that this data is cube map data or not. if( loading_as_cubemap ) { result_string_pointer = "cube map textures are not available in GLES1.x."; return 0; } #endif // load the texture up tex_ID = reuse_texture_ID; if( tex_ID == 0 ) { glGenTextures( 1, &tex_ID ); } glBindTexture( opengl_texture_type, tex_ID ); if( glGetError() ) { result_string_pointer = "failed: glBindTexture() failed."; return 0; } glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_aligment); if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT,1); // Never have row-aligned in headers } #define _MAX( a, b ) (( a <= b )? b : a) for(i=0; idwHeaderSize + header->dwTextureDataSize * i; char *cur_texture_ptr = 0; int mipmap_level; unsigned int width= header->dwWidth, height = header->dwHeight; unsigned int compressed_image_size = 0; mipmaps = ( ( flags & SOIL_FLAG_MIPMAPS ) && (header->dwpfFlags & PVRTEX_MIPMAP) ) ? header->dwMipMapCount : 0; for(mipmap_level = 0; mipmap_level <= mipmaps; width = _MAX(width/2, (unsigned int)1), height = _MAX(height/2, (unsigned int)1), mipmap_level++ ) { // Do Alpha-swap if needed cur_texture_ptr = texture_ptr; // Load the Texture /* If the texture is PVRTC then use GLCompressedTexImage2D */ if( is_compressed_format ) { /* Calculate how many bytes this MIP level occupies */ if ((header->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) { compressed_image_size = ( _MAX(width, PVRTC2_MIN_TEXWIDTH) * _MAX(height, PVRTC2_MIN_TEXHEIGHT) * header->dwBitCount + 7 ) / 8; } else {// PVRTC4 case compressed_image_size = ( _MAX(width, PVRTC4_MIN_TEXWIDTH) * _MAX(height, PVRTC4_MIN_TEXHEIGHT) * header->dwBitCount + 7 ) / 8; } if ( is_compressed_format_supported ) { /* Load compressed texture data at selected MIP level */ if ( loading_as_cubemap ) { soilGlCompressedTexImage2D( SOIL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mipmap_level, PVR_format, width, height, 0, compressed_image_size, cur_texture_ptr ); } else { soilGlCompressedTexImage2D( opengl_texture_type, mipmap_level, PVR_format, width, height, 0, compressed_image_size, cur_texture_ptr ); } } else { result_string_pointer = "failed: GPU doesnt support compressed textures"; } } else { /* Load uncompressed texture data at selected MIP level */ if ( loading_as_cubemap ) { glTexImage2D( SOIL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mipmap_level, PVR_type, width, height, 0, PVR_type, PVR_format, cur_texture_ptr ); } else { glTexImage2D( opengl_texture_type, mipmap_level, PVR_type, width, height, 0, PVR_type, PVR_format, cur_texture_ptr ); } } if( glGetError() ) { result_string_pointer = "failed: glCompressedTexImage2D() failed."; if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment); } return 0; } // offset the texture pointer by one mip-map level /* PVRTC case */ if ( is_compressed_format ) { texture_ptr += compressed_image_size; } else { /* New formula that takes into account bit counts inferior to 8 (e.g. 1 bpp) */ texture_ptr += (width * height * header->dwBitCount + 7) / 8; } } } #undef _MAX if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment); } if( tex_ID ) { /* did I have MIPmaps? */ if( mipmaps ) { /* instruct OpenGL to use the MIPmaps */ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); } else { /* instruct OpenGL _NOT_ to use the MIPmaps */ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); } /* does the user want clamping, or wrapping? */ if( flags & SOIL_FLAG_TEXTURE_REPEATS ) { glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT ); } else { unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; /* unsigned int clamp_mode = GL_CLAMP; */ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode ); glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode ); } } return tex_ID; } unsigned int SOIL_direct_load_PVR( const char *filename, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap ) { FILE *f; unsigned char *buffer; size_t buffer_length, bytes_read; unsigned int tex_ID = 0; /* error checks */ if( NULL == filename ) { result_string_pointer = "NULL filename"; return 0; } f = fopen( filename, "rb" ); if( NULL == f ) { /* the file doesn't seem to exist (or be open-able) */ result_string_pointer = "Can not find PVR file"; return 0; } fseek( f, 0, SEEK_END ); buffer_length = ftell( f ); fseek( f, 0, SEEK_SET ); buffer = (unsigned char *) malloc( buffer_length ); if( NULL == buffer ) { result_string_pointer = "malloc failed"; fclose( f ); return 0; } bytes_read = fread( (void*)buffer, 1, buffer_length, f ); fclose( f ); if( bytes_read < buffer_length ) { /* huh? */ buffer_length = bytes_read; } /* now try to do the loading */ tex_ID = SOIL_direct_load_PVR_from_memory( (const unsigned char *const)buffer, (int)buffer_length, reuse_texture_ID, flags, loading_as_cubemap ); SOIL_free_image_data( buffer ); return tex_ID; } unsigned int SOIL_direct_load_ETC1_from_memory( const unsigned char *const buffer, int buffer_length, unsigned int reuse_texture_ID, int flags ) { GLuint tex_ID = 0; PKMHeader* header = (PKMHeader*)buffer; unsigned int opengl_texture_type = GL_TEXTURE_2D; unsigned int width; unsigned int height; unsigned long compressed_image_size = buffer_length - PKM_HEADER_SIZE; char *texture_ptr = (char*)buffer + PKM_HEADER_SIZE; GLint unpack_aligment; if ( query_ETC1_capability() != SOIL_CAPABILITY_PRESENT ) { result_string_pointer = "error: ETC1 not supported. Decompress the texture first."; return 0; } if ( 0 != strcmp( header->aName, "PKM 10" ) ) { result_string_pointer = "error: PKM 10 header not found."; return 0; } width = (header->iWidthMSB << 8) | header->iWidthLSB; height = (header->iHeightMSB << 8) | header->iHeightLSB; compressed_image_size = (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; // load the texture up tex_ID = reuse_texture_ID; if( tex_ID == 0 ) { glGenTextures( 1, &tex_ID ); } glBindTexture( opengl_texture_type, tex_ID ); if( glGetError() ) { result_string_pointer = "failed: glBindTexture() failed."; return 0; } glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_aligment); if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT,1); // Never have row-aligned in headers } soilGlCompressedTexImage2D( opengl_texture_type, 0, SOIL_GL_ETC1_RGB8_OES, width, height, 0, compressed_image_size, texture_ptr ); if( glGetError() ) { result_string_pointer = "failed: glCompressedTexImage2D() failed."; if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment); } return 0; } if ( 1 != unpack_aligment ) { glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment); } if( tex_ID ) { /* No MIPmaps for ETC1 */ glTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); /* does the user want clamping, or wrapping? */ if( flags & SOIL_FLAG_TEXTURE_REPEATS ) { glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT ); glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT ); } else { unsigned int clamp_mode = SOIL_CLAMP_TO_EDGE; /* unsigned int clamp_mode = GL_CLAMP; */ glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode ); glTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode ); glTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode ); } } return tex_ID; } unsigned int SOIL_direct_load_ETC1(const char *filename, unsigned int reuse_texture_ID, int flags ) { FILE *f; unsigned char *buffer; size_t buffer_length, bytes_read; unsigned int tex_ID = 0; /* error checks */ if( NULL == filename ) { result_string_pointer = "NULL filename"; return 0; } f = fopen( filename, "rb" ); if( NULL == f ) { /* the file doesn't seem to exist (or be open-able) */ result_string_pointer = "Can not find PVR file"; return 0; } fseek( f, 0, SEEK_END ); buffer_length = ftell( f ); fseek( f, 0, SEEK_SET ); buffer = (unsigned char *) malloc( buffer_length ); if( NULL == buffer ) { result_string_pointer = "malloc failed"; fclose( f ); return 0; } bytes_read = fread( (void*)buffer, 1, buffer_length, f ); fclose( f ); if( bytes_read < buffer_length ) { /* huh? */ buffer_length = bytes_read; } /* now try to do the loading */ tex_ID = SOIL_direct_load_ETC1_from_memory( (const unsigned char *const)buffer, (int)buffer_length, reuse_texture_ID, flags ); SOIL_free_image_data( buffer ); return tex_ID; } int query_NPOT_capability( void ) { /* check for the capability */ if( has_NPOT_capability == SOIL_CAPABILITY_UNKNOWN ) { /* we haven't yet checked for the capability, do so */ if( (0 == SOIL_GL_ExtensionSupported( "GL_ARB_texture_non_power_of_two" ) ) && (0 == SOIL_GL_ExtensionSupported( "GL_OES_texture_npot" ) ) && !isAtLeastGL3() ) { /* not there, flag the failure */ has_NPOT_capability = SOIL_CAPABILITY_NONE; } else { /* it's there! */ has_NPOT_capability = SOIL_CAPABILITY_PRESENT; } #if defined( __emscripten__ ) || defined( EMSCRIPTEN ) has_NPOT_capability = SOIL_CAPABILITY_PRESENT; #endif } /* let the user know if we can do non-power-of-two textures or not */ return has_NPOT_capability; } int query_tex_rectangle_capability( void ) { /* check for the capability */ if( has_tex_rectangle_capability == SOIL_CAPABILITY_UNKNOWN ) { /* we haven't yet checked for the capability, do so */ if( (0 == SOIL_GL_ExtensionSupported( "GL_ARB_texture_rectangle" ) ) && (0 == SOIL_GL_ExtensionSupported( "GL_EXT_texture_rectangle" ) ) && (0 == SOIL_GL_ExtensionSupported( "GL_NV_texture_rectangle" ) ) && !isAtLeastGL3() ) { /* not there, flag the failure */ has_tex_rectangle_capability = SOIL_CAPABILITY_NONE; } else { /* it's there! */ has_tex_rectangle_capability = SOIL_CAPABILITY_PRESENT; } } /* let the user know if we can do texture rectangles or not */ return has_tex_rectangle_capability; } int query_cubemap_capability( void ) { /* check for the capability */ if( has_cubemap_capability == SOIL_CAPABILITY_UNKNOWN ) { /* we haven't yet checked for the capability, do so */ if( (0 == SOIL_GL_ExtensionSupported( "GL_ARB_texture_cube_map" ) ) && (0 == SOIL_GL_ExtensionSupported( "GL_EXT_texture_cube_map" ) ) && !isAtLeastGL3() ) { /* not there, flag the failure */ has_cubemap_capability = SOIL_CAPABILITY_NONE; } else { /* it's there! */ has_cubemap_capability = SOIL_CAPABILITY_PRESENT; } } /* let the user know if we can do cubemaps or not */ return has_cubemap_capability; } static P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC get_glCompressedTexImage2D_addr() { /* and find the address of the extension function */ P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL; #if defined( SOIL_PLATFORM_WIN32 ) || defined( SOIL_PLATFORM_OSX ) || defined( SOIL_X11_PLATFORM ) ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)SOIL_GL_GetProcAddress( "glCompressedTexImage2D" ); #else ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)&glCompressedTexImage2D; #endif return ext_addr; } int query_DXT_capability( void ) { /* check for the capability */ if( has_DXT_capability == SOIL_CAPABILITY_UNKNOWN ) { /* we haven't yet checked for the capability, do so */ if ( 0 == SOIL_GL_ExtensionSupported( "GL_EXT_texture_compression_s3tc" ) && 0 == SOIL_GL_ExtensionSupported( "WEBGL_compressed_texture_s3tc ") && 0 == SOIL_GL_ExtensionSupported( "WEBKIT_WEBGL_compressed_texture_s3tc") && 0 == SOIL_GL_ExtensionSupported( "MOZ_WEBGL_compressed_texture_s3tc" ) ) { /* not there, flag the failure */ has_DXT_capability = SOIL_CAPABILITY_NONE; } else { P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = get_glCompressedTexImage2D_addr(); /* Flag it so no checks needed later */ if( NULL == ext_addr ) { /* hmm, not good!! This should not happen, but does on my laptop's VIA chipset. The GL_EXT_texture_compression_s3tc spec requires that ARB_texture_compression be present too. this means I can upload and have the OpenGL drive do the conversion, but I can't use my own routines or load DDS files from disk and upload them directly [8^( */ has_DXT_capability = SOIL_CAPABILITY_NONE; } else { /* all's well! */ soilGlCompressedTexImage2D = ext_addr; has_DXT_capability = SOIL_CAPABILITY_PRESENT; } } } /* let the user know if we can do DXT or not */ return has_DXT_capability; } int query_3Dc_capability(void) { /* check for the capability */ if (has_3Dc_capability == SOIL_CAPABILITY_UNKNOWN) { /* we haven't yet checked for the capability, do so */ if (0 == SOIL_GL_ExtensionSupported( "ARB_texture_compression_rgtc") && 0 == SOIL_GL_ExtensionSupported( "GL_ARB_texture_compression_rgtc") && 0 == SOIL_GL_ExtensionSupported( "GL_EXT_texture_compression_rgtc") ) { /* not there, flag the failure */ has_3Dc_capability = SOIL_CAPABILITY_NONE; } else { P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = get_glCompressedTexImage2D_addr(); /* Flag it so no checks needed later */ if (NULL == ext_addr) { /* hmm, not good!! This should not happen, but does on my laptop's VIA chipset. The GL_EXT_texture_compression_s3tc spec requires that ARB_texture_compression be present too. this means I can upload and have the OpenGL drive do the conversion, but I can't use my own routines or load DDS files from disk and upload them directly [8^( */ has_3Dc_capability = SOIL_CAPABILITY_NONE; } else { /* all's well! */ soilGlCompressedTexImage2D = ext_addr; has_3Dc_capability = SOIL_CAPABILITY_PRESENT; } } } /* let the user know if we can do DXT or not */ return has_3Dc_capability; } int query_PVR_capability( void ) { /* check for the capability */ if( has_PVR_capability == SOIL_CAPABILITY_UNKNOWN ) { /* we haven't yet checked for the capability, do so */ if (0 == SOIL_GL_ExtensionSupported( "GL_IMG_texture_compression_pvrtc" ) ) { /* not there, flag the failure */ has_PVR_capability = SOIL_CAPABILITY_NONE; } else { if ( NULL == soilGlCompressedTexImage2D ) { soilGlCompressedTexImage2D = get_glCompressedTexImage2D_addr(); } /* it's there! */ has_PVR_capability = SOIL_CAPABILITY_PRESENT; } } /* let the user know if we can do cubemaps or not */ return has_PVR_capability; } int query_BGRA8888_capability( void ) { /* check for the capability */ if( has_BGRA8888_capability == SOIL_CAPABILITY_UNKNOWN ) { /* we haven't yet checked for the capability, do so */ if (0 == SOIL_GL_ExtensionSupported( "GL_IMG_texture_format_BGRA8888" ) ) { /* not there, flag the failure */ has_BGRA8888_capability = SOIL_CAPABILITY_NONE; } else { /* it's there! */ has_BGRA8888_capability = SOIL_CAPABILITY_PRESENT; } } /* let the user know if we can do cubemaps or not */ return has_BGRA8888_capability; } int query_sRGB_capability( void ) { if ( has_sRGB_capability == SOIL_CAPABILITY_UNKNOWN ) { if (0 == SOIL_GL_ExtensionSupported( "GL_EXT_texture_sRGB" ) && 0 == SOIL_GL_ExtensionSupported( "GL_EXT_sRGB" ) && 0 == SOIL_GL_ExtensionSupported( "EXT_sRGB" ) && !isAtLeastGL3() ) { has_sRGB_capability = SOIL_CAPABILITY_NONE; } else { has_sRGB_capability = SOIL_CAPABILITY_PRESENT; } } return has_sRGB_capability; } int query_ETC1_capability( void ) { /* check for the capability */ if( has_ETC1_capability == SOIL_CAPABILITY_UNKNOWN ) { /* we haven't yet checked for the capability, do so */ if (0 == SOIL_GL_ExtensionSupported( "GL_OES_compressed_ETC1_RGB8_texture" ) ) { /* not there, flag the failure */ has_ETC1_capability = SOIL_CAPABILITY_NONE; } else { if ( NULL == soilGlCompressedTexImage2D ) { soilGlCompressedTexImage2D = get_glCompressedTexImage2D_addr(); } /* it's there! */ has_ETC1_capability = SOIL_CAPABILITY_PRESENT; } } /* let the user know if we can do cubemaps or not */ return has_ETC1_capability; } int query_gen_mipmap_capability( void ) { /* check for the capability */ P_SOIL_GLGENERATEMIPMAPPROC ext_addr = NULL; if( has_gen_mipmap_capability == SOIL_CAPABILITY_UNKNOWN ) { if ( 0 == SOIL_GL_ExtensionSupported( "GL_ARB_framebuffer_object" ) && 0 == SOIL_GL_ExtensionSupported( "GL_EXT_framebuffer_object" ) && 0 == SOIL_GL_ExtensionSupported( "GL_OES_framebuffer_object" ) && !isAtLeastGL3() ) { /* not there, flag the failure */ has_gen_mipmap_capability = SOIL_CAPABILITY_NONE; } else { #if !defined( SOIL_GLES1 ) && !defined( SOIL_GLES2 ) ext_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress("glGenerateMipmap"); if(ext_addr == NULL) { ext_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress("glGenerateMipmapEXT"); } #elif !defined( SOIL_NO_EGL ) ext_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress("glGenerateMipmapOES"); if(ext_addr == NULL) { ext_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress("glGenerateMipmap"); } #elif defined( SOIL_GLES2 ) ext_addr = &glGenerateMipmap; #else /** SOIL_GLES1 */ ext_addr = &glGenerateMipmapOES; #endif } if(ext_addr == NULL) { /* this should never happen */ has_gen_mipmap_capability = SOIL_CAPABILITY_NONE; } else { /* it's there! */ has_gen_mipmap_capability = SOIL_CAPABILITY_PRESENT; soilGlGenerateMipmap = ext_addr; } } return has_gen_mipmap_capability; } ================================================ FILE: lib/SOIL2/SOIL2.h ================================================ /** @mainpage SOIL2 Fork by Martin Lucas Golini Original author Jonathan Dummer 2007-07-26-10.36 Simple OpenGL Image Library 2 A tiny c library for uploading images as textures into OpenGL. Also saving and loading of images is supported. I'm using Sean's Tool Box image loader as a base: http://www.nothings.org/ I'm upgrading it to load TGA and DDS files, and a direct path for loading DDS files straight into OpenGL textures, when applicable. Image Formats: - BMP load & save - TGA load & save - DDS load & save - PNG load & save - JPG load & save - QOI load & save - PSD load - HDR load - PIC load OpenGL Texture Features: - resample to power-of-two sizes - MIPmap generation - compressed texture S3TC formats (if supported) - can pre-multiply alpha for you, for better compositing - can flip image about the y-axis (except pre-compressed DDS files) Thanks to: * Sean Barret - for the awesome stb_image * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts * everybody at gamedev.net **/ #ifndef HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY #define HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY #ifdef __cplusplus extern "C" { #endif #define SOIL_MAJOR_VERSION 1 #define SOIL_MINOR_VERSION 3 #define SOIL_PATCH_LEVEL 0 #define SOIL_VERSION_NUM( X, Y, Z ) ( (X)*1000 + (Y)*100 + ( Z ) ) #define SOIL_COMPILED_VERSION \ SOIL_VERSION_NUM( SOIL_MAJOR_VERSION, SOIL_MINOR_VERSION, SOIL_PATCH_LEVEL ) #define SOIL_VERSION_ATLEAST( X, Y, Z ) ( SOIL_COMPILED_VERSION >= SOIL_VERSION_NUM( X, Y, Z ) ) unsigned long SOIL_version(); /** The format of images that may be loaded (force_channels). SOIL_LOAD_AUTO leaves the image in whatever format it was found. SOIL_LOAD_L forces the image to load as Luminous (greyscale) SOIL_LOAD_LA forces the image to load as Luminous with Alpha SOIL_LOAD_RGB forces the image to load as Red Green Blue SOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha **/ enum { SOIL_LOAD_AUTO = 0, SOIL_LOAD_L = 1, SOIL_LOAD_LA = 2, SOIL_LOAD_RGB = 3, SOIL_LOAD_RGBA = 4 }; /** Passed in as reuse_texture_ID, will cause SOIL to register a new texture ID using glGenTextures(). If the value passed into reuse_texture_ID > 0 then SOIL will just re-use that texture ID (great for reloading image assets in-game!) **/ enum { SOIL_CREATE_NEW_ID = 0 }; /** flags you can pass into SOIL_load_OGL_texture() and SOIL_create_OGL_texture(). (note that if SOIL_FLAG_DDS_LOAD_DIRECT is used the rest of the flags with the exception of SOIL_FLAG_TEXTURE_REPEATS will be ignored while loading already-compressed DDS files.) SOIL_FLAG_POWER_OF_TWO: force the image to be POT SOIL_FLAG_MIPMAPS: generate mipmaps for the texture SOIL_FLAG_TEXTURE_REPEATS: otherwise will clamp SOIL_FLAG_MULTIPLY_ALPHA: for using (GL_ONE,GL_ONE_MINUS_SRC_ALPHA) blending SOIL_FLAG_INVERT_Y: flip the image vertically SOIL_FLAG_COMPRESS_TO_DXT: if the card can display them, will convert RGB to DXT1, RGBA to DXT5 SOIL_FLAG_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing ( if supported ) SOIL_FLAG_NTSC_SAFE_RGB: clamps RGB components to the range [16,235] SOIL_FLAG_CoCg_Y: Google YCoCg; RGB=>CoYCg, RGBA=>CoCgAY SOIL_FLAG_TEXTURE_RECTANGE: uses ARB_texture_rectangle ; pixel indexed & no repeat or MIPmaps or cubemaps SOIL_FLAG_PVR_LOAD_DIRECT: will load PVR files directly without _ANY_ additional processing ( if supported ) **/ enum { SOIL_FLAG_POWER_OF_TWO = 1, SOIL_FLAG_MIPMAPS = 2, SOIL_FLAG_TEXTURE_REPEATS = 4, SOIL_FLAG_MULTIPLY_ALPHA = 8, SOIL_FLAG_INVERT_Y = 16, SOIL_FLAG_COMPRESS_TO_DXT = 32, SOIL_FLAG_DDS_LOAD_DIRECT = 64, SOIL_FLAG_NTSC_SAFE_RGB = 128, SOIL_FLAG_CoCg_Y = 256, SOIL_FLAG_TEXTURE_RECTANGLE = 512, SOIL_FLAG_PVR_LOAD_DIRECT = 1024, SOIL_FLAG_ETC1_LOAD_DIRECT = 2048, SOIL_FLAG_GL_MIPMAPS = 4096, SOIL_FLAG_SRGB_COLOR_SPACE = 8192 }; /** The types of images that may be saved. (TGA supports uncompressed RGB / RGBA) (BMP supports uncompressed RGB) (DDS supports DXT1 and DXT5) (PNG supports RGB / RGBA) **/ enum { SOIL_SAVE_TYPE_TGA = 0, SOIL_SAVE_TYPE_BMP = 1, SOIL_SAVE_TYPE_PNG = 2, SOIL_SAVE_TYPE_DDS = 3, SOIL_SAVE_TYPE_JPG = 4, SOIL_SAVE_TYPE_QOI = 5 }; /** Defines the order of faces in a DDS cubemap. I recommend that you use the same order in single image cubemap files, so they will be interchangeable with DDS cubemaps when using SOIL. **/ #define SOIL_DDS_CUBEMAP_FACE_ORDER "EWUDNS" /** The types of internal fake HDR representations SOIL_HDR_RGBE: RGB * pow( 2.0, A - 128.0 ) SOIL_HDR_RGBdivA: RGB / A SOIL_HDR_RGBdivA2: RGB / (A*A) **/ enum { SOIL_HDR_RGBE = 0, SOIL_HDR_RGBdivA = 1, SOIL_HDR_RGBdivA2 = 2 }; /** Loads an image from disk into an OpenGL texture. \param filename the name of the file to upload as a texture \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_load_OGL_texture ( const char *filename, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ); /** Loads 6 images from disk into an OpenGL cubemap texture. \param x_pos_file the name of the file to upload as the +x cube face \param x_neg_file the name of the file to upload as the -x cube face \param y_pos_file the name of the file to upload as the +y cube face \param y_neg_file the name of the file to upload as the -y cube face \param z_pos_file the name of the file to upload as the +z cube face \param z_neg_file the name of the file to upload as the -z cube face \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_load_OGL_cubemap ( const char *x_pos_file, const char *x_neg_file, const char *y_pos_file, const char *y_neg_file, const char *z_pos_file, const char *z_neg_file, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ); /** Loads 1 image from disk and splits it into an OpenGL cubemap texture. \param filename the name of the file to upload as a texture \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_load_OGL_single_cubemap ( const char *filename, const char face_order[6], int force_channels, unsigned int reuse_texture_ID, unsigned int flags ); /** Loads an HDR image from disk into an OpenGL texture. \param filename the name of the file to upload as a texture \param fake_HDR_format SOIL_HDR_RGBE, SOIL_HDR_RGBdivA, SOIL_HDR_RGBdivA2 \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_load_OGL_HDR_texture ( const char *filename, int fake_HDR_format, int rescale_to_max, unsigned int reuse_texture_ID, unsigned int flags ); /** Loads an image from RAM into an OpenGL texture. \param buffer the image data in RAM just as if it were still in a file \param buffer_length the size of the buffer in bytes \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_load_OGL_texture_from_memory ( const unsigned char *const buffer, int buffer_length, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ); /** Loads 6 images from memory into an OpenGL cubemap texture. \param x_pos_buffer the image data in RAM to upload as the +x cube face \param x_pos_buffer_length the size of the above buffer \param x_neg_buffer the image data in RAM to upload as the +x cube face \param x_neg_buffer_length the size of the above buffer \param y_pos_buffer the image data in RAM to upload as the +x cube face \param y_pos_buffer_length the size of the above buffer \param y_neg_buffer the image data in RAM to upload as the +x cube face \param y_neg_buffer_length the size of the above buffer \param z_pos_buffer the image data in RAM to upload as the +x cube face \param z_pos_buffer_length the size of the above buffer \param z_neg_buffer the image data in RAM to upload as the +x cube face \param z_neg_buffer_length the size of the above buffer \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_load_OGL_cubemap_from_memory ( const unsigned char *const x_pos_buffer, int x_pos_buffer_length, const unsigned char *const x_neg_buffer, int x_neg_buffer_length, const unsigned char *const y_pos_buffer, int y_pos_buffer_length, const unsigned char *const y_neg_buffer, int y_neg_buffer_length, const unsigned char *const z_pos_buffer, int z_pos_buffer_length, const unsigned char *const z_neg_buffer, int z_neg_buffer_length, int force_channels, unsigned int reuse_texture_ID, unsigned int flags ); /** Loads 1 image from RAM and splits it into an OpenGL cubemap texture. \param buffer the image data in RAM just as if it were still in a file \param buffer_length the size of the buffer in bytes \param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc. \param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_load_OGL_single_cubemap_from_memory ( const unsigned char *const buffer, int buffer_length, const char face_order[6], int force_channels, unsigned int reuse_texture_ID, unsigned int flags ); /** Creates a 2D OpenGL texture from raw image data. Note that the raw data is _NOT_ freed after the upload (so the user can load various versions). \param data the raw data to be uploaded as an OpenGL texture \param width the pointer of the width of the image in pixels ( if the texture size change, width will be overrided with the new width ) \param height the pointer of the height of the image in pixels ( if the texture size change, height will be overrided with the new height ) \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_create_OGL_texture ( const unsigned char *const data, int *width, int *height, int channels, unsigned int reuse_texture_ID, unsigned int flags ); /** Creates an OpenGL cubemap texture by splitting up 1 image into 6 parts. \param data the raw data to be uploaded as an OpenGL texture \param width the width of the image in pixels \param height the height of the image in pixels \param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA \param face_order the order of the faces in the file, and combination of NSWEUD, for North, South, Up, etc. \param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture) \param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT \return 0-failed, otherwise returns the OpenGL texture handle **/ unsigned int SOIL_create_OGL_single_cubemap ( const unsigned char *const data, int width, int height, int channels, const char face_order[6], unsigned int reuse_texture_ID, unsigned int flags ); /** Captures the OpenGL window (RGB) and saves it to disk \return 0 if it failed, otherwise returns 1 **/ int SOIL_save_screenshot ( const char *filename, int image_type, int x, int y, int width, int height ); /** Loads an image from disk into an array of unsigned chars. Note that *channels return the original channel count of the image. If force_channels was other than SOIL_LOAD_AUTO, the resulting image has force_channels, but *channels may be different (if the original image had a different channel count). \return 0 if failed, otherwise returns 1 **/ unsigned char* SOIL_load_image ( const char *filename, int *width, int *height, int *channels, int force_channels ); /** Loads an image from memory into an array of unsigned chars. Note that *channels return the original channel count of the image. If force_channels was other than SOIL_LOAD_AUTO, the resulting image has force_channels, but *channels may be different (if the original image had a different channel count). \return 0 if failed, otherwise returns 1 **/ unsigned char* SOIL_load_image_from_memory ( const unsigned char *const buffer, int buffer_length, int *width, int *height, int *channels, int force_channels ); /** Saves an image from an array of unsigned chars (RGBA) to disk \param quality parameter only used for SOIL_SAVE_TYPE_JPG files, values accepted between 0 and 100. \return 0 if failed, otherwise returns 1 **/ int SOIL_save_image_quality ( const char *filename, int image_type, int width, int height, int channels, const unsigned char *const data, int quality ); int SOIL_save_image ( const char *filename, int image_type, int width, int height, int channels, const unsigned char *const data ); /** Saves an image from an array of unsigned chars (RGBA) to a memory buffer in the target format. Free the buffer with SOIL_free_image_data. \param quality parameter only used for SOIL_SAVE_TYPE_JPG files, values accepted between 0 and 100. \param imageSize returns the byte count of the image. \return 0 if failed, otherwise returns 1 **/ unsigned char* SOIL_write_image_to_memory_quality ( int image_type, int width, int height, int channels, const unsigned char* const data, int quality, int* imageSize ); unsigned char* SOIL_write_image_to_memory ( int image_type, int width, int height, int channels, const unsigned char* const data, int* imageSize ); /** Frees the image data (note, this is just C's "free()"...this function is present mostly so C++ programmers don't forget to use "free()" and call "delete []" instead [8^) **/ void SOIL_free_image_data ( unsigned char *img_data ); /** This function resturn a pointer to a string describing the last thing that happened inside SOIL. It can be used to determine why an image failed to load. **/ const char* SOIL_last_result ( void ); /** @return The address of the GL function proc, or NULL if the function is not found. */ void * SOIL_GL_GetProcAddress ( const char *proc ); /** @return 1 if an OpenGL extension is supported for the current context, 0 otherwise. */ int SOIL_GL_ExtensionSupported ( const char *extension ); /** Loads the DDS texture directly to the GPU memory ( if supported ) */ unsigned int SOIL_direct_load_DDS( const char *filename, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap ); /** Loads the DDS texture directly to the GPU memory ( if supported ) */ unsigned int SOIL_direct_load_DDS_from_memory( const unsigned char *const buffer, int buffer_length, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap ); /** Loads the PVR texture directly to the GPU memory ( if supported ) */ unsigned int SOIL_direct_load_PVR( const char *filename, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap ); /** Loads the PVR texture directly to the GPU memory ( if supported ) */ unsigned int SOIL_direct_load_PVR_from_memory( const unsigned char *const buffer, int buffer_length, unsigned int reuse_texture_ID, int flags, int loading_as_cubemap ); /** Loads the PVR texture directly to the GPU memory ( if supported ) */ unsigned int SOIL_direct_load_ETC1(const char *filename, unsigned int reuse_texture_ID, int flags ); /** Loads the PVR texture directly to the GPU memory ( if supported ) */ unsigned int SOIL_direct_load_ETC1_from_memory(const unsigned char *const buffer, int buffer_length, unsigned int reuse_texture_ID, int flags ); #ifdef __cplusplus } #endif #endif /* HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY */ ================================================ FILE: lib/SOIL2/image_DXT.c ================================================ /* Jonathan Dummer 2007-07-31-10.32 simple DXT compression / decompression code public domain */ #include "image_DXT.h" #include #include #include #include /* set this =1 if you want to use the covarince matrix method... which is better than my method of using standard deviations overall, except on the infintesimal chance that the power method fails for finding the largest eigenvector */ #define USE_COV_MAT 1 /********* Function Prototypes *********/ /* Takes a 4x4 block of pixels and compresses it into 8 bytes in DXT1 format (color only, no alpha). Speed is valued over prettyness, at least for now. */ void compress_DDS_color_block( int channels, const unsigned char *const uncompressed, unsigned char compressed[8] ); /* Takes a 4x4 block of pixels and compresses the alpha component it into 8 bytes for use in DXT5 DDS files. Speed is valued over prettyness, at least for now. */ void compress_DDS_alpha_block( const unsigned char *const uncompressed, unsigned char compressed[8] ); /********* Actual Exposed Functions *********/ int save_image_as_DDS ( const char *filename, int width, int height, int channels, const unsigned char *const data ) { /* variables */ FILE *fout; unsigned char *DDS_data; DDS_header header; int DDS_size; /* error check */ if( (NULL == filename) || (width < 1) || (height < 1) || (channels < 1) || (channels > 4) || (data == NULL ) ) { return 0; } /* Convert the image */ if( (channels & 1) == 1 ) { /* no alpha, just use DXT1 */ DDS_data = convert_image_to_DXT1( data, width, height, channels, &DDS_size ); } else { /* has alpha, so use DXT5 */ DDS_data = convert_image_to_DXT5( data, width, height, channels, &DDS_size ); } /* save it */ memset( &header, 0, sizeof( DDS_header ) ); header.dwMagic = ('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24); header.dwSize = 124; header.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE; header.dwWidth = width; header.dwHeight = height; header.dwPitchOrLinearSize = DDS_size; header.sPixelFormat.dwSize = 32; header.sPixelFormat.dwFlags = DDPF_FOURCC; if( (channels & 1) == 1 ) { header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24); } else { header.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24); } header.sCaps.dwCaps1 = DDSCAPS_TEXTURE; /* write it out */ fout = fopen( filename, "wb"); fwrite( &header, sizeof( DDS_header ), 1, fout ); fwrite( DDS_data, 1, DDS_size, fout ); fclose( fout ); /* done */ free( DDS_data ); return 1; } unsigned char* convert_image_to_DXT1( const unsigned char *const uncompressed, int width, int height, int channels, int *out_size ) { unsigned char *compressed; int i, j, x, y; unsigned char ublock[16*3]; unsigned char cblock[8]; int index = 0, chan_step = 1; /* error check */ *out_size = 0; if( (width < 1) || (height < 1) || (NULL == uncompressed) || (channels < 1) || (channels > 4) ) { return NULL; } /* for channels == 1 or 2, I do not step forward for R,G,B values */ if( channels < 3 ) { chan_step = 0; } /* get the RAM for the compressed image (8 bytes per 4x4 pixel block) */ *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 8; compressed = (unsigned char*)malloc( *out_size ); /* go through each block */ for( j = 0; j < height; j += 4 ) { for( i = 0; i < width; i += 4 ) { /* copy this block into a new one */ int idx = 0; int mx = 4, my = 4; if( j+4 >= height ) { my = height - j; } if( i+4 >= width ) { mx = width - i; } for( y = 0; y < my; ++y ) { for( x = 0; x < mx; ++x ) { ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; } for( x = mx; x < 4; ++x ) { ublock[idx++] = ublock[0]; ublock[idx++] = ublock[1]; ublock[idx++] = ublock[2]; } } for( y = my; y < 4; ++y ) { for( x = 0; x < 4; ++x ) { ublock[idx++] = ublock[0]; ublock[idx++] = ublock[1]; ublock[idx++] = ublock[2]; } } /* compress the block */ compress_DDS_color_block( 3, ublock, cblock ); /* copy the data from the block into the main block */ for( x = 0; x < 8; ++x ) { compressed[index++] = cblock[x]; } } } return compressed; } unsigned char* convert_image_to_DXT5( const unsigned char *const uncompressed, int width, int height, int channels, int *out_size ) { unsigned char *compressed; int i, j, x, y; unsigned char ublock[16*4]; unsigned char cblock[8]; int index = 0, chan_step = 1; int has_alpha; /* error check */ *out_size = 0; if( (width < 1) || (height < 1) || (NULL == uncompressed) || (channels < 1) || ( channels > 4) ) { return NULL; } /* for channels == 1 or 2, I do not step forward for R,G,B vales */ if( channels < 3 ) { chan_step = 0; } /* # channels = 1 or 3 have no alpha, 2 & 4 do have alpha */ has_alpha = 1 - (channels & 1); /* get the RAM for the compressed image (16 bytes per 4x4 pixel block) */ *out_size = ((width+3) >> 2) * ((height+3) >> 2) * 16; compressed = (unsigned char*)malloc( *out_size ); /* go through each block */ for( j = 0; j < height; j += 4 ) { for( i = 0; i < width; i += 4 ) { /* local variables, and my block counter */ int idx = 0; int mx = 4, my = 4; if( j+4 >= height ) { my = height - j; } if( i+4 >= width ) { mx = width - i; } for( y = 0; y < my; ++y ) { for( x = 0; x < mx; ++x ) { ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels]; ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step]; ublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step]; ublock[idx++] = has_alpha * uncompressed[(j+y)*width*channels+(i+x)*channels+channels-1] + (1-has_alpha)*255; } for( x = mx; x < 4; ++x ) { ublock[idx++] = ublock[0]; ublock[idx++] = ublock[1]; ublock[idx++] = ublock[2]; ublock[idx++] = ublock[3]; } } for( y = my; y < 4; ++y ) { for( x = 0; x < 4; ++x ) { ublock[idx++] = ublock[0]; ublock[idx++] = ublock[1]; ublock[idx++] = ublock[2]; ublock[idx++] = ublock[3]; } } /* now compress the alpha block */ compress_DDS_alpha_block( ublock, cblock ); /* copy the data from the compressed alpha block into the main buffer */ for( x = 0; x < 8; ++x ) { compressed[index++] = cblock[x]; } /* then compress the color block */ compress_DDS_color_block( 4, ublock, cblock ); /* copy the data from the compressed color block into the main buffer */ for( x = 0; x < 8; ++x ) { compressed[index++] = cblock[x]; } } } return compressed; } /********* Helper Functions *********/ int convert_bit_range( int c, int from_bits, int to_bits ) { int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); return (b + (b >> from_bits)) >> from_bits; } int rgb_to_565( int r, int g, int b ) { return (convert_bit_range( r, 8, 5 ) << 11) | (convert_bit_range( g, 8, 6 ) << 05) | (convert_bit_range( b, 8, 5 ) << 00); } void rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) { *r = convert_bit_range( (c >> 11) & 31, 5, 8 ); *g = convert_bit_range( (c >> 05) & 63, 6, 8 ); *b = convert_bit_range( (c >> 00) & 31, 5, 8 ); } void compute_color_line_STDEV( const unsigned char *const uncompressed, int channels, float point[3], float direction[3] ) { const float inv_16 = 1.0f / 16.0f; int i; float sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f; float sum_rr = 0.0f, sum_gg = 0.0f, sum_bb = 0.0f; float sum_rg = 0.0f, sum_rb = 0.0f, sum_gb = 0.0f; /* calculate all data needed for the covariance matrix ( to compare with _rygdxt code) */ for( i = 0; i < 16*channels; i += channels ) { sum_r += uncompressed[i+0]; sum_rr += uncompressed[i+0] * uncompressed[i+0]; sum_g += uncompressed[i+1]; sum_gg += uncompressed[i+1] * uncompressed[i+1]; sum_b += uncompressed[i+2]; sum_bb += uncompressed[i+2] * uncompressed[i+2]; sum_rg += uncompressed[i+0] * uncompressed[i+1]; sum_rb += uncompressed[i+0] * uncompressed[i+2]; sum_gb += uncompressed[i+1] * uncompressed[i+2]; } /* convert the sums to averages */ sum_r *= inv_16; sum_g *= inv_16; sum_b *= inv_16; /* and convert the squares to the squares of the value - avg_value */ sum_rr -= 16.0f * sum_r * sum_r; sum_gg -= 16.0f * sum_g * sum_g; sum_bb -= 16.0f * sum_b * sum_b; sum_rg -= 16.0f * sum_r * sum_g; sum_rb -= 16.0f * sum_r * sum_b; sum_gb -= 16.0f * sum_g * sum_b; /* the point on the color line is the average */ point[0] = sum_r; point[1] = sum_g; point[2] = sum_b; #if USE_COV_MAT /* The following idea was from ryg. (https://mollyrocket.com/forums/viewtopic.php?t=392) The method worked great (less RMSE than mine) most of the time, but had some issues handling some simple boundary cases, like full green next to full red, which would generate a covariance matrix like this: | 1 -1 0 | | -1 1 0 | | 0 0 0 | For a given starting vector, the power method can generate all zeros! So no starting with {1,1,1} as I was doing! This kind of error is still a slight posibillity, but will be very rare. */ /* use the covariance matrix directly (1st iteration, don't use all 1.0 values!) */ sum_r = 1.0f; sum_g = 2.718281828f; sum_b = 3.141592654f; direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; /* 2nd iteration, use results from the 1st guy */ sum_r = direction[0]; sum_g = direction[1]; sum_b = direction[2]; direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; /* 3rd iteration, use results from the 2nd guy */ sum_r = direction[0]; sum_g = direction[1]; sum_b = direction[2]; direction[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb; direction[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb; direction[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb; #else /* use my standard deviation method (very robust, a tiny bit slower and less accurate) */ direction[0] = sqrt( sum_rr ); direction[1] = sqrt( sum_gg ); direction[2] = sqrt( sum_bb ); /* which has a greater component */ if( sum_gg > sum_rr ) { /* green has greater component, so base the other signs off of green */ if( sum_rg < 0.0f ) { direction[0] = -direction[0]; } if( sum_gb < 0.0f ) { direction[2] = -direction[2]; } } else { /* red has a greater component */ if( sum_rg < 0.0f ) { direction[1] = -direction[1]; } if( sum_rb < 0.0f ) { direction[2] = -direction[2]; } } #endif } void LSE_master_colors_max_min( int *cmax, int *cmin, int channels, const unsigned char *const uncompressed ) { int i, j; /* the master colors */ int c0[3], c1[3]; /* used for fitting the line */ float sum_x[] = { 0.0f, 0.0f, 0.0f }; float sum_x2[] = { 0.0f, 0.0f, 0.0f }; float dot_max = 1.0f, dot_min = -1.0f; float vec_len2 = 0.0f; float dot; /* error check */ if( (channels < 3) || (channels > 4) ) { return; } compute_color_line_STDEV( uncompressed, channels, sum_x, sum_x2 ); vec_len2 = 1.0f / ( 0.00001f + sum_x2[0]*sum_x2[0] + sum_x2[1]*sum_x2[1] + sum_x2[2]*sum_x2[2] ); /* finding the max and min vector values */ dot_max = ( sum_x2[0] * uncompressed[0] + sum_x2[1] * uncompressed[1] + sum_x2[2] * uncompressed[2] ); dot_min = dot_max; for( i = 1; i < 16; ++i ) { dot = ( sum_x2[0] * uncompressed[i*channels+0] + sum_x2[1] * uncompressed[i*channels+1] + sum_x2[2] * uncompressed[i*channels+2] ); if( dot < dot_min ) { dot_min = dot; } else if( dot > dot_max ) { dot_max = dot; } } /* and the offset (from the average location) */ dot = sum_x2[0]*sum_x[0] + sum_x2[1]*sum_x[1] + sum_x2[2]*sum_x[2]; dot_min -= dot; dot_max -= dot; /* post multiply by the scaling factor */ dot_min *= vec_len2; dot_max *= vec_len2; /* OK, build the master colors */ for( i = 0; i < 3; ++i ) { /* color 0 */ c0[i] = (int)(0.5f + sum_x[i] + dot_max * sum_x2[i]); if( c0[i] < 0 ) { c0[i] = 0; } else if( c0[i] > 255 ) { c0[i] = 255; } /* color 1 */ c1[i] = (int)(0.5f + sum_x[i] + dot_min * sum_x2[i]); if( c1[i] < 0 ) { c1[i] = 0; } else if( c1[i] > 255 ) { c1[i] = 255; } } /* down_sample (with rounding?) */ i = rgb_to_565( c0[0], c0[1], c0[2] ); j = rgb_to_565( c1[0], c1[1], c1[2] ); if( i > j ) { *cmax = i; *cmin = j; } else { *cmax = j; *cmin = i; } } void compress_DDS_color_block ( int channels, const unsigned char *const uncompressed, unsigned char compressed[8] ) { /* variables */ int i; int next_bit; int enc_c0, enc_c1; int c0[4], c1[4]; float color_line[] = { 0.0f, 0.0f, 0.0f, 0.0f }; float vec_len2 = 0.0f, dot_offset = 0.0f; /* stupid order */ int swizzle4[] = { 0, 2, 3, 1 }; /* get the master colors */ LSE_master_colors_max_min( &enc_c0, &enc_c1, channels, uncompressed ); /* store the 565 color 0 and color 1 */ compressed[0] = (enc_c0 >> 0) & 255; compressed[1] = (enc_c0 >> 8) & 255; compressed[2] = (enc_c1 >> 0) & 255; compressed[3] = (enc_c1 >> 8) & 255; /* zero out the compressed data */ compressed[4] = 0; compressed[5] = 0; compressed[6] = 0; compressed[7] = 0; /* reconstitute the master color vectors */ rgb_888_from_565( enc_c0, &c0[0], &c0[1], &c0[2] ); rgb_888_from_565( enc_c1, &c1[0], &c1[1], &c1[2] ); /* the new vector */ vec_len2 = 0.0f; for( i = 0; i < 3; ++i ) { color_line[i] = (float)(c1[i] - c0[i]); vec_len2 += color_line[i] * color_line[i]; } if( vec_len2 > 0.0f ) { vec_len2 = 1.0f / vec_len2; } /* pre-proform the scaling */ color_line[0] *= vec_len2; color_line[1] *= vec_len2; color_line[2] *= vec_len2; /* compute the offset (constant) portion of the dot product */ dot_offset = color_line[0]*c0[0] + color_line[1]*c0[1] + color_line[2]*c0[2]; /* store the rest of the bits */ next_bit = 8*4; for( i = 0; i < 16; ++i ) { /* find the dot product of this color, to place it on the line (should be [-1,1]) */ int next_value = 0; float dot_product = color_line[0] * uncompressed[i*channels+0] + color_line[1] * uncompressed[i*channels+1] + color_line[2] * uncompressed[i*channels+2] - dot_offset; /* map to [0,3] */ next_value = (int)( dot_product * 3.0f + 0.5f ); if( next_value > 3 ) { next_value = 3; } else if( next_value < 0 ) { next_value = 0; } /* OK, store this value */ compressed[next_bit >> 3] |= swizzle4[ next_value ] << (next_bit & 7); next_bit += 2; } /* done compressing to DXT1 */ } void compress_DDS_alpha_block ( const unsigned char *const uncompressed, unsigned char compressed[8] ) { /* variables */ int i; int next_bit; int a0, a1; float scale_me; /* stupid order */ int swizzle8[] = { 1, 7, 6, 5, 4, 3, 2, 0 }; /* get the alpha limits (a0 > a1) */ a0 = a1 = uncompressed[3]; for( i = 4+3; i < 16*4; i += 4 ) { if( uncompressed[i] > a0 ) { a0 = uncompressed[i]; } else if( uncompressed[i] < a1 ) { a1 = uncompressed[i]; } } /* store those limits, and zero the rest of the compressed dataset */ compressed[0] = a0; compressed[1] = a1; /* zero out the compressed data */ compressed[2] = 0; compressed[3] = 0; compressed[4] = 0; compressed[5] = 0; compressed[6] = 0; compressed[7] = 0; /* store the all of the alpha values */ next_bit = 8*2; scale_me = 7.9999f / (a0 - a1); for( i = 3; i < 16*4; i += 4 ) { /* convert this alpha value to a 3 bit number */ int svalue; int value = (int)((uncompressed[i] - a1) * scale_me); svalue = swizzle8[ value&7 ]; /* OK, store this value, start with the 1st byte */ compressed[next_bit >> 3] |= svalue << (next_bit & 7); if( (next_bit & 7) > 5 ) { /* spans 2 bytes, fill in the start of the 2nd byte */ compressed[1 + (next_bit >> 3)] |= svalue >> (8 - (next_bit & 7) ); } next_bit += 3; } /* done compressing to DXT1 */ } ================================================ FILE: lib/SOIL2/image_DXT.h ================================================ /* Jonathan Dummer 2007-07-31-10.32 simple DXT compression / decompression code public domain */ #ifndef HEADER_IMAGE_DXT #define HEADER_IMAGE_DXT #include /** Converts an image from an array of unsigned chars (RGB or RGBA) to DXT1 or DXT5, then saves the converted image to disk. \return 0 if failed, otherwise returns 1 **/ int save_image_as_DDS ( const char *filename, int width, int height, int channels, const unsigned char *const data ); /** take an image and convert it to DXT1 (no alpha) **/ unsigned char* convert_image_to_DXT1 ( const unsigned char *const uncompressed, int width, int height, int channels, int *out_size ); /** take an image and convert it to DXT5 (with alpha) **/ unsigned char* convert_image_to_DXT5 ( const unsigned char *const uncompressed, int width, int height, int channels, int *out_size ); // A bunch of DirectDraw Surface structures and flags typedef struct { uint32_t dwMagic; uint32_t dwSize; uint32_t dwFlags; uint32_t dwHeight; uint32_t dwWidth; uint32_t dwPitchOrLinearSize; uint32_t dwDepth; uint32_t dwMipMapCount; uint32_t dwReserved1[ 11 ]; /* DDPIXELFORMAT */ struct { uint32_t dwSize; uint32_t dwFlags; uint32_t dwFourCC; uint32_t dwRGBBitCount; uint32_t dwRBitMask; uint32_t dwGBitMask; uint32_t dwBBitMask; uint32_t dwAlphaBitMask; } sPixelFormat; /* DDCAPS2 */ struct { uint32_t dwCaps1; uint32_t dwCaps2; uint32_t dwDDSX; uint32_t dwReserved; } sCaps; unsigned int dwReserved2; } DDS_header; typedef enum { DXGI_FORMAT_UNKNOWN = 0, DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, DXGI_FORMAT_R32G32B32A32_FLOAT = 2, DXGI_FORMAT_R32G32B32A32_UINT = 3, DXGI_FORMAT_R32G32B32A32_SINT = 4, DXGI_FORMAT_R32G32B32_TYPELESS = 5, DXGI_FORMAT_R32G32B32_FLOAT = 6, DXGI_FORMAT_R32G32B32_UINT = 7, DXGI_FORMAT_R32G32B32_SINT = 8, DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, DXGI_FORMAT_R16G16B16A16_FLOAT = 10, DXGI_FORMAT_R16G16B16A16_UNORM = 11, DXGI_FORMAT_R16G16B16A16_UINT = 12, DXGI_FORMAT_R16G16B16A16_SNORM = 13, DXGI_FORMAT_R16G16B16A16_SINT = 14, DXGI_FORMAT_R32G32_TYPELESS = 15, DXGI_FORMAT_R32G32_FLOAT = 16, DXGI_FORMAT_R32G32_UINT = 17, DXGI_FORMAT_R32G32_SINT = 18, DXGI_FORMAT_R32G8X24_TYPELESS = 19, DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, DXGI_FORMAT_R10G10B10A2_UNORM = 24, DXGI_FORMAT_R10G10B10A2_UINT = 25, DXGI_FORMAT_R11G11B10_FLOAT = 26, DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, DXGI_FORMAT_R8G8B8A8_UNORM = 28, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, DXGI_FORMAT_R8G8B8A8_UINT = 30, DXGI_FORMAT_R8G8B8A8_SNORM = 31, DXGI_FORMAT_R8G8B8A8_SINT = 32, DXGI_FORMAT_R16G16_TYPELESS = 33, DXGI_FORMAT_R16G16_FLOAT = 34, DXGI_FORMAT_R16G16_UNORM = 35, DXGI_FORMAT_R16G16_UINT = 36, DXGI_FORMAT_R16G16_SNORM = 37, DXGI_FORMAT_R16G16_SINT = 38, DXGI_FORMAT_R32_TYPELESS = 39, DXGI_FORMAT_D32_FLOAT = 40, DXGI_FORMAT_R32_FLOAT = 41, DXGI_FORMAT_R32_UINT = 42, DXGI_FORMAT_R32_SINT = 43, DXGI_FORMAT_R24G8_TYPELESS = 44, DXGI_FORMAT_D24_UNORM_S8_UINT = 45, DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, DXGI_FORMAT_R8G8_TYPELESS = 48, DXGI_FORMAT_R8G8_UNORM = 49, DXGI_FORMAT_R8G8_UINT = 50, DXGI_FORMAT_R8G8_SNORM = 51, DXGI_FORMAT_R8G8_SINT = 52, DXGI_FORMAT_R16_TYPELESS = 53, DXGI_FORMAT_R16_FLOAT = 54, DXGI_FORMAT_D16_UNORM = 55, DXGI_FORMAT_R16_UNORM = 56, DXGI_FORMAT_R16_UINT = 57, DXGI_FORMAT_R16_SNORM = 58, DXGI_FORMAT_R16_SINT = 59, DXGI_FORMAT_R8_TYPELESS = 60, DXGI_FORMAT_R8_UNORM = 61, DXGI_FORMAT_R8_UINT = 62, DXGI_FORMAT_R8_SNORM = 63, DXGI_FORMAT_R8_SINT = 64, DXGI_FORMAT_A8_UNORM = 65, DXGI_FORMAT_R1_UNORM = 66, DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, DXGI_FORMAT_R8G8_B8G8_UNORM = 68, DXGI_FORMAT_G8R8_G8B8_UNORM = 69, DXGI_FORMAT_BC1_TYPELESS = 70, DXGI_FORMAT_BC1_UNORM = 71, DXGI_FORMAT_BC1_UNORM_SRGB = 72, DXGI_FORMAT_BC2_TYPELESS = 73, DXGI_FORMAT_BC2_UNORM = 74, DXGI_FORMAT_BC2_UNORM_SRGB = 75, DXGI_FORMAT_BC3_TYPELESS = 76, DXGI_FORMAT_BC3_UNORM = 77, DXGI_FORMAT_BC3_UNORM_SRGB = 78, DXGI_FORMAT_BC4_TYPELESS = 79, DXGI_FORMAT_BC4_UNORM = 80, DXGI_FORMAT_BC4_SNORM = 81, DXGI_FORMAT_BC5_TYPELESS = 82, DXGI_FORMAT_BC5_UNORM = 83, DXGI_FORMAT_BC5_SNORM = 84, DXGI_FORMAT_B5G6R5_UNORM = 85, DXGI_FORMAT_B5G5R5A1_UNORM = 86, DXGI_FORMAT_B8G8R8A8_UNORM = 87, DXGI_FORMAT_B8G8R8X8_UNORM = 88, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, DXGI_FORMAT_BC6H_TYPELESS = 94, DXGI_FORMAT_BC6H_UF16 = 95, DXGI_FORMAT_BC6H_SF16 = 96, DXGI_FORMAT_BC7_TYPELESS = 97, DXGI_FORMAT_BC7_UNORM = 98, DXGI_FORMAT_BC7_UNORM_SRGB = 99, DXGI_FORMAT_AYUV = 100, DXGI_FORMAT_Y410 = 101, DXGI_FORMAT_Y416 = 102, DXGI_FORMAT_NV12 = 103, DXGI_FORMAT_P010 = 104, DXGI_FORMAT_P016 = 105, DXGI_FORMAT_420_OPAQUE = 106, DXGI_FORMAT_YUY2 = 107, DXGI_FORMAT_Y210 = 108, DXGI_FORMAT_Y216 = 109, DXGI_FORMAT_NV11 = 110, DXGI_FORMAT_AI44 = 111, DXGI_FORMAT_IA44 = 112, DXGI_FORMAT_P8 = 113, DXGI_FORMAT_A8P8 = 114, DXGI_FORMAT_B4G4R4A4_UNORM = 115, DXGI_FORMAT_P208 = 130, DXGI_FORMAT_V208 = 131, DXGI_FORMAT_V408 = 132, DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE, DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE, DXGI_FORMAT_FORCE_UINT = 0xffffffff } DXGI_FORMAT; typedef struct { DXGI_FORMAT dxgiFormat; uint32_t resourceDimension; uint32_t miscFlag; uint32_t arraySize; uint32_t miscFlags2; } DDS_HEADER_DXT10; /* the following constants were copied directly off the MSDN website */ /* The dwFlags member of the original DDSURFACEDESC2 structure can be set to one or more of the following values. */ #define DDSD_CAPS 0x00000001 #define DDSD_HEIGHT 0x00000002 #define DDSD_WIDTH 0x00000004 #define DDSD_PITCH 0x00000008 #define DDSD_PIXELFORMAT 0x00001000 #define DDSD_MIPMAPCOUNT 0x00020000 #define DDSD_LINEARSIZE 0x00080000 #define DDSD_DEPTH 0x00800000 /* DirectDraw Pixel Format */ #define DDPF_ALPHAPIXELS 0x00000001 #define DDPF_FOURCC 0x00000004 #define DDPF_RGB 0x00000040 #define DDPF_LUMINANCE 0x20000 /* The dwCaps1 member of the DDSCAPS2 structure can be set to one or more of the following values. */ #define DDSCAPS_COMPLEX 0x00000008 #define DDSCAPS_TEXTURE 0x00001000 #define DDSCAPS_MIPMAP 0x00400000 /* The dwCaps2 member of the DDSCAPS2 structure can be set to one or more of the following values. */ #define DDSCAPS2_CUBEMAP 0x00000200 #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 #define DDSCAPS2_VOLUME 0x00200000 #endif /* HEADER_IMAGE_DXT */ ================================================ FILE: lib/SOIL2/image_helper.c ================================================ /* Jonathan Dummer image helper functions MIT license */ #include "image_helper.h" #include #include /* Upscaling the image uses simple bilinear interpolation */ int up_scale_image ( const unsigned char* const orig, int width, int height, int channels, unsigned char* resampled, int resampled_width, int resampled_height ) { float dx, dy; int x, y, c; /* error(s) check */ if ( (width < 1) || (height < 1) || (resampled_width < 2) || (resampled_height < 2) || (channels < 1) || (NULL == orig) || (NULL == resampled) ) { /* signify badness */ return 0; } /* for each given pixel in the new map, find the exact location from the original map which would contribute to this guy */ dx = (width - 1.0f) / (resampled_width - 1.0f); dy = (height - 1.0f) / (resampled_height - 1.0f); for ( y = 0; y < resampled_height; ++y ) { /* find the base y index and fractional offset from that */ float sampley = y * dy; int inty = (int)sampley; /* if( inty < 0 ) { inty = 0; } else */ if( inty > height - 2 ) { inty = height - 2; } sampley -= inty; for ( x = 0; x < resampled_width; ++x ) { float samplex = x * dx; int intx = (int)samplex; int base_index; /* find the base x index and fractional offset from that */ /* if( intx < 0 ) { intx = 0; } else */ if( intx > width - 2 ) { intx = width - 2; } samplex -= intx; /* base index into the original image */ base_index = (inty * width + intx) * channels; for ( c = 0; c < channels; ++c ) { /* do the sampling */ float value = 0.5f; value += orig[base_index] *(1.0f-samplex)*(1.0f-sampley); value += orig[base_index+channels] *(samplex)*(1.0f-sampley); value += orig[base_index+width*channels] *(1.0f-samplex)*(sampley); value += orig[base_index+width*channels+channels] *(samplex)*(sampley); /* move to the next channel */ ++base_index; /* save the new value */ resampled[y*resampled_width*channels+x*channels+c] = (unsigned char)(value); } } } /* done */ return 1; } int mipmap_image ( const unsigned char* const orig, int width, int height, int channels, unsigned char* resampled, int block_size_x, int block_size_y ) { int mip_width, mip_height; int i, j, c; /* error check */ if( (width < 1) || (height < 1) || (channels < 1) || (orig == NULL) || (resampled == NULL) || (block_size_x < 1) || (block_size_y < 1) ) { /* nothing to do */ return 0; } mip_width = width / block_size_x; mip_height = height / block_size_y; if( mip_width < 1 ) { mip_width = 1; } if( mip_height < 1 ) { mip_height = 1; } for( j = 0; j < mip_height; ++j ) { for( i = 0; i < mip_width; ++i ) { for( c = 0; c < channels; ++c ) { const int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c; int sum_value; int u,v; int u_block = block_size_x; int v_block = block_size_y; int block_area; /* do a bit of checking so we don't over-run the boundaries (necessary for non-square textures!) */ if( block_size_x * (i+1) > width ) { u_block = width - i*block_size_y; } if( block_size_y * (j+1) > height ) { v_block = height - j*block_size_y; } block_area = u_block*v_block; /* for this pixel, see what the average of all the values in the block are. note: start the sum at the rounding value, not at 0 */ sum_value = block_area >> 1; for( v = 0; v < v_block; ++v ) for( u = 0; u < u_block; ++u ) { sum_value += orig[index + v*width*channels + u*channels]; } resampled[j*mip_width*channels + i*channels + c] = sum_value / block_area; } } } return 1; } int scale_image_RGB_to_NTSC_safe ( unsigned char* orig, int width, int height, int channels ) { const float scale_lo = 16.0f - 0.499f; const float scale_hi = 235.0f + 0.499f; int i, j; int nc = channels; unsigned char scale_LUT[256]; /* error check */ if( (width < 1) || (height < 1) || (channels < 1) || (orig == NULL) ) { /* nothing to do */ return 0; } /* set up the scaling Look Up Table */ for( i = 0; i < 256; ++i ) { scale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo); } /* for channels = 2 or 4, ignore the alpha component */ nc -= 1 - (channels & 1); /* OK, go through the image and scale any non-alpha components */ for( i = 0; i < width*height*channels; i += channels ) { for( j = 0; j < nc; ++j ) { orig[i+j] = scale_LUT[orig[i+j]]; } } return 1; } unsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); } /* This function takes the RGB components of the image and converts them into YCoCg. 3 components will be re-ordered to CoYCg (for optimum DXT1 compression), while 4 components will be ordered CoCgAY (for DXT5 compression). */ int convert_RGB_to_YCoCg ( unsigned char* orig, int width, int height, int channels ) { int i; /* error check */ if( (width < 1) || (height < 1) || (channels < 3) || (channels > 4) || (orig == NULL) ) { /* nothing to do */ return -1; } /* do the conversion */ if( channels == 3 ) { for( i = 0; i < width*height*3; i += 3 ) { int r = orig[i+0]; int g = (orig[i+1] + 1) >> 1; int b = orig[i+2]; int tmp = (2 + r + b) >> 2; /* Co */ orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); /* Y */ orig[i+1] = clamp_byte( g + tmp ); /* Cg */ orig[i+2] = clamp_byte( 128 + g - tmp ); } } else { for( i = 0; i < width*height*4; i += 4 ) { int r = orig[i+0]; int g = (orig[i+1] + 1) >> 1; int b = orig[i+2]; unsigned char a = orig[i+3]; int tmp = (2 + r + b) >> 2; /* Co */ orig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) ); /* Cg */ orig[i+1] = clamp_byte( 128 + g - tmp ); /* Alpha */ orig[i+2] = a; /* Y */ orig[i+3] = clamp_byte( g + tmp ); } } /* done */ return 0; } /* This function takes the YCoCg components of the image and converts them into RGB. See above. */ int convert_YCoCg_to_RGB ( unsigned char* orig, int width, int height, int channels ) { int i; /* error check */ if( (width < 1) || (height < 1) || (channels < 3) || (channels > 4) || (orig == NULL) ) { /* nothing to do */ return -1; } /* do the conversion */ if( channels == 3 ) { for( i = 0; i < width*height*3; i += 3 ) { int co = orig[i+0] - 128; int y = orig[i+1]; int cg = orig[i+2] - 128; /* R */ orig[i+0] = clamp_byte( y + co - cg ); /* G */ orig[i+1] = clamp_byte( y + cg ); /* B */ orig[i+2] = clamp_byte( y - co - cg ); } } else { for( i = 0; i < width*height*4; i += 4 ) { int co = orig[i+0] - 128; int cg = orig[i+1] - 128; unsigned char a = orig[i+2]; int y = orig[i+3]; /* R */ orig[i+0] = clamp_byte( y + co - cg ); /* G */ orig[i+1] = clamp_byte( y + cg ); /* B */ orig[i+2] = clamp_byte( y - co - cg ); /* A */ orig[i+3] = a; } } /* done */ return 0; } float find_max_RGBE ( unsigned char *image, int width, int height ) { float max_val = 0.0f; unsigned char *img = image; int i, j; for( i = width * height; i > 0; --i ) { /* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ float scale = (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); for( j = 0; j < 3; ++j ) { if( img[j] * scale > max_val ) { max_val = img[j] * scale; } } /* next pixel */ img += 4; } return max_val; } int RGBE_to_RGBdivA ( unsigned char *image, int width, int height, int rescale_to_max ) { /* local variables */ int i, iv; unsigned char *img = image; float scale = 1.0f; /* error check */ if( (!image) || (width < 1) || (height < 1) ) { return 0; } /* convert (note: no negative numbers, but 0.0 is possible) */ if( rescale_to_max ) { scale = 255.0f / find_max_RGBE( image, width, height ); } for( i = width * height; i > 0; --i ) { /* decode this pixel, and find the max */ float r,g,b,e, m; /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ e = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); r = e * img[0]; g = e * img[1]; b = e * img[2]; m = (r > g) ? r : g; m = (b > m) ? b : m; /* and encode it into RGBdivA */ iv = (m != 0.0f) ? (int)(255.0f / m) : 1; iv = (iv < 1) ? 1 : iv; img[3] = (iv > 255) ? 255 : iv; iv = (int)(img[3] * r + 0.5f); img[0] = (iv > 255) ? 255 : iv; iv = (int)(img[3] * g + 0.5f); img[1] = (iv > 255) ? 255 : iv; iv = (int)(img[3] * b + 0.5f); img[2] = (iv > 255) ? 255 : iv; /* and on to the next pixel */ img += 4; } return 1; } int RGBE_to_RGBdivA2 ( unsigned char *image, int width, int height, int rescale_to_max ) { /* local variables */ int i, iv; unsigned char *img = image; float scale = 1.0f; /* error check */ if( (!image) || (width < 1) || (height < 1) ) { return 0; } /* convert (note: no negative numbers, but 0.0 is possible) */ if( rescale_to_max ) { scale = 255.0f * 255.0f / find_max_RGBE( image, width, height ); } for( i = width * height; i > 0; --i ) { /* decode this pixel, and find the max */ float r,g,b,e, m; /* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */ e = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 ); r = e * img[0]; g = e * img[1]; b = e * img[2]; m = (r > g) ? r : g; m = (b > m) ? b : m; /* and encode it into RGBdivA */ iv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1; iv = (iv < 1) ? 1 : iv; img[3] = (iv > 255) ? 255 : iv; iv = (int)(img[3] * img[3] * r / 255.0f + 0.5f); img[0] = (iv > 255) ? 255 : iv; iv = (int)(img[3] * img[3] * g / 255.0f + 0.5f); img[1] = (iv > 255) ? 255 : iv; iv = (int)(img[3] * img[3] * b / 255.0f + 0.5f); img[2] = (iv > 255) ? 255 : iv; /* and on to the next pixel */ img += 4; } return 1; } ================================================ FILE: lib/SOIL2/image_helper.h ================================================ /* Jonathan Dummer Image helper functions MIT license */ #ifndef HEADER_IMAGE_HELPER #define HEADER_IMAGE_HELPER #ifdef __cplusplus extern "C" { #endif /** This function upscales an image. Not to be used to create MIPmaps, but to make it square, or to make it a power-of-two sized. **/ int up_scale_image ( const unsigned char* const orig, int width, int height, int channels, unsigned char* resampled, int resampled_width, int resampled_height ); /** This function downscales an image. Used for creating MIPmaps, the incoming image should be a power-of-two sized. **/ int mipmap_image ( const unsigned char* const orig, int width, int height, int channels, unsigned char* resampled, int block_size_x, int block_size_y ); /** This function takes the RGB components of the image and scales each channel from [0,255] to [16,235]. This makes the colors "Safe" for display on NTSC displays. Note that this is _NOT_ a good idea for loading images like normal- or height-maps! **/ int scale_image_RGB_to_NTSC_safe ( unsigned char* orig, int width, int height, int channels ); /** This function takes the RGB components of the image and converts them into YCoCg. 3 components will be re-ordered to CoYCg (for optimum DXT1 compression), while 4 components will be ordered CoCgAY (for DXT5 compression). **/ int convert_RGB_to_YCoCg ( unsigned char* orig, int width, int height, int channels ); /** This function takes the YCoCg components of the image and converts them into RGB. See above. **/ int convert_YCoCg_to_RGB ( unsigned char* orig, int width, int height, int channels ); /** Converts an HDR image from an array of unsigned chars (RGBE) to RGBdivA \return 0 if failed, otherwise returns 1 **/ int RGBE_to_RGBdivA ( unsigned char *image, int width, int height, int rescale_to_max ); /** Converts an HDR image from an array of unsigned chars (RGBE) to RGBdivA2 \return 0 if failed, otherwise returns 1 **/ int RGBE_to_RGBdivA2 ( unsigned char *image, int width, int height, int rescale_to_max ); #ifdef __cplusplus } #endif #endif /* HEADER_IMAGE_HELPER */ ================================================ FILE: lib/SOIL2/pkm_helper.h ================================================ #ifndef PKM_HELPER_H #define PKM_HELPER_H typedef struct { char aName[6]; unsigned short iBlank; unsigned char iPaddedWidthMSB; unsigned char iPaddedWidthLSB; unsigned char iPaddedHeightMSB; unsigned char iPaddedHeightLSB; unsigned char iWidthMSB; unsigned char iWidthLSB; unsigned char iHeightMSB; unsigned char iHeightLSB; } PKMHeader; #define PKM_HEADER_SIZE 16 #endif ================================================ FILE: lib/SOIL2/pvr_helper.h ================================================ #ifndef PVR_HELPER_H #define PVR_HELPER_H // Taken from PowerVR SDK /*!*************************************************************************** Describes the header of a PVR header-texture *****************************************************************************/ typedef struct { unsigned int dwHeaderSize; /*!< size of the structure */ unsigned int dwHeight; /*!< height of surface to be created */ unsigned int dwWidth; /*!< width of input surface */ unsigned int dwMipMapCount; /*!< number of mip-map levels requested */ unsigned int dwpfFlags; /*!< pixel format flags */ unsigned int dwTextureDataSize; /*!< Total size in bytes */ unsigned int dwBitCount; /*!< number of bits per pixel */ unsigned int dwRBitMask; /*!< mask for red bit */ unsigned int dwGBitMask; /*!< mask for green bits */ unsigned int dwBBitMask; /*!< mask for blue bits */ unsigned int dwAlphaBitMask; /*!< mask for alpha channel */ unsigned int dwPVR; /*!< magic number identifying pvr file */ unsigned int dwNumSurfs; /*!< the number of surfaces present in the pvr */ } PVR_Texture_Header; /***************************************************************************** * ENUMS *****************************************************************************/ enum PixelType { MGLPT_ARGB_4444 = 0x00, MGLPT_ARGB_1555, MGLPT_RGB_565, MGLPT_RGB_555, MGLPT_RGB_888, MGLPT_ARGB_8888, MGLPT_ARGB_8332, MGLPT_I_8, MGLPT_AI_88, MGLPT_1_BPP, MGLPT_VY1UY0, MGLPT_Y1VY0U, MGLPT_PVRTC2, MGLPT_PVRTC4, MGLPT_PVRTC2_2, MGLPT_PVRTC2_4, OGL_RGBA_4444= 0x10, OGL_RGBA_5551, OGL_RGBA_8888, OGL_RGB_565, OGL_RGB_555, OGL_RGB_888, OGL_I_8, OGL_AI_88, OGL_PVRTC2, OGL_PVRTC4, // OGL_BGRA_8888 extension OGL_BGRA_8888, D3D_DXT1 = 0x20, D3D_DXT2, D3D_DXT3, D3D_DXT4, D3D_DXT5, D3D_RGB_332, D3D_AI_44, D3D_LVU_655, D3D_XLVU_8888, D3D_QWVU_8888, //10 bits per channel D3D_ABGR_2101010, D3D_ARGB_2101010, D3D_AWVU_2101010, //16 bits per channel D3D_GR_1616, D3D_VU_1616, D3D_ABGR_16161616, //HDR formats D3D_R16F, D3D_GR_1616F, D3D_ABGR_16161616F, //32 bits per channel D3D_R32F, D3D_GR_3232F, D3D_ABGR_32323232F, // Ericsson ETC_RGB_4BPP, ETC_RGBA_EXPLICIT, ETC_RGBA_INTERPOLATED, // DX10 ePT_DX10_R32G32B32A32_FLOAT= 0x50, ePT_DX10_R32G32B32A32_UINT , ePT_DX10_R32G32B32A32_SINT, ePT_DX10_R32G32B32_FLOAT, ePT_DX10_R32G32B32_UINT, ePT_DX10_R32G32B32_SINT, ePT_DX10_R16G16B16A16_FLOAT , ePT_DX10_R16G16B16A16_UNORM, ePT_DX10_R16G16B16A16_UINT , ePT_DX10_R16G16B16A16_SNORM , ePT_DX10_R16G16B16A16_SINT , ePT_DX10_R32G32_FLOAT , ePT_DX10_R32G32_UINT , ePT_DX10_R32G32_SINT , ePT_DX10_R10G10B10A2_UNORM , ePT_DX10_R10G10B10A2_UINT , ePT_DX10_R11G11B10_FLOAT , ePT_DX10_R8G8B8A8_UNORM , ePT_DX10_R8G8B8A8_UNORM_SRGB , ePT_DX10_R8G8B8A8_UINT , ePT_DX10_R8G8B8A8_SNORM , ePT_DX10_R8G8B8A8_SINT , ePT_DX10_R16G16_FLOAT , ePT_DX10_R16G16_UNORM , ePT_DX10_R16G16_UINT , ePT_DX10_R16G16_SNORM , ePT_DX10_R16G16_SINT , ePT_DX10_R32_FLOAT , ePT_DX10_R32_UINT , ePT_DX10_R32_SINT , ePT_DX10_R8G8_UNORM , ePT_DX10_R8G8_UINT , ePT_DX10_R8G8_SNORM , ePT_DX10_R8G8_SINT , ePT_DX10_R16_FLOAT , ePT_DX10_R16_UNORM , ePT_DX10_R16_UINT , ePT_DX10_R16_SNORM , ePT_DX10_R16_SINT , ePT_DX10_R8_UNORM, ePT_DX10_R8_UINT, ePT_DX10_R8_SNORM, ePT_DX10_R8_SINT, ePT_DX10_A8_UNORM, ePT_DX10_R1_UNORM, ePT_DX10_R9G9B9E5_SHAREDEXP, ePT_DX10_R8G8_B8G8_UNORM, ePT_DX10_G8R8_G8B8_UNORM, ePT_DX10_BC1_UNORM, ePT_DX10_BC1_UNORM_SRGB, ePT_DX10_BC2_UNORM, ePT_DX10_BC2_UNORM_SRGB, ePT_DX10_BC3_UNORM, ePT_DX10_BC3_UNORM_SRGB, ePT_DX10_BC4_UNORM, ePT_DX10_BC4_SNORM, ePT_DX10_BC5_UNORM, ePT_DX10_BC5_SNORM, //ePT_DX10_B5G6R5_UNORM, // defined but obsolete - won't actually load in DX10 //ePT_DX10_B5G5R5A1_UNORM, //ePT_DX10_B8G8R8A8_UNORM, //ePT_DX10_B8G8R8X8_UNORM, // OpenVG /* RGB{A,X} channel ordering */ ePT_VG_sRGBX_8888 = 0x90, ePT_VG_sRGBA_8888, ePT_VG_sRGBA_8888_PRE, ePT_VG_sRGB_565, ePT_VG_sRGBA_5551, ePT_VG_sRGBA_4444, ePT_VG_sL_8, ePT_VG_lRGBX_8888, ePT_VG_lRGBA_8888, ePT_VG_lRGBA_8888_PRE, ePT_VG_lL_8, ePT_VG_A_8, ePT_VG_BW_1, /* {A,X}RGB channel ordering */ ePT_VG_sXRGB_8888, ePT_VG_sARGB_8888, ePT_VG_sARGB_8888_PRE, ePT_VG_sARGB_1555, ePT_VG_sARGB_4444, ePT_VG_lXRGB_8888, ePT_VG_lARGB_8888, ePT_VG_lARGB_8888_PRE, /* BGR{A,X} channel ordering */ ePT_VG_sBGRX_8888, ePT_VG_sBGRA_8888, ePT_VG_sBGRA_8888_PRE, ePT_VG_sBGR_565, ePT_VG_sBGRA_5551, ePT_VG_sBGRA_4444, ePT_VG_lBGRX_8888, ePT_VG_lBGRA_8888, ePT_VG_lBGRA_8888_PRE, /* {A,X}BGR channel ordering */ ePT_VG_sXBGR_8888, ePT_VG_sABGR_8888 , ePT_VG_sABGR_8888_PRE, ePT_VG_sABGR_1555, ePT_VG_sABGR_4444, ePT_VG_lXBGR_8888, ePT_VG_lABGR_8888, ePT_VG_lABGR_8888_PRE, // max cap for iterating END_OF_PIXEL_TYPES, MGLPT_NOTYPE = 0xff }; /***************************************************************************** * constants *****************************************************************************/ #define PVRTEX_MIPMAP (1<<8) // has mip map levels #define PVRTEX_TWIDDLE (1<<9) // is twiddled #define PVRTEX_BUMPMAP (1<<10) // has normals encoded for a bump map #define PVRTEX_TILING (1<<11) // is bordered for tiled pvr #define PVRTEX_CUBEMAP (1<<12) // is a cubemap/skybox #define PVRTEX_FALSEMIPCOL (1<<13) // #define PVRTEX_VOLUME (1<<14) #define PVRTEX_PIXELTYPE 0xff // pixel type is always in the last 16bits of the flags #define PVRTEX_IDENTIFIER 0x21525650 // the pvr identifier is the characters 'P','V','R' #define PVRTEX_V1_HEADER_SIZE 44 // old header size was 44 for identification purposes #define PVRTC2_MIN_TEXWIDTH 16 #define PVRTC2_MIN_TEXHEIGHT 8 #define PVRTC4_MIN_TEXWIDTH 8 #define PVRTC4_MIN_TEXHEIGHT 8 #define ETC_MIN_TEXWIDTH 4 #define ETC_MIN_TEXHEIGHT 4 #define DXT_MIN_TEXWIDTH 4 #define DXT_MIN_TEXHEIGHT 4 #endif ================================================ FILE: lib/SOIL2/stb_image.h ================================================ /* stb_image - v2.27 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: #define STB_IMAGE_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. // i.e. it should look like this: #include ... #include ... #include ... #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free QUICK NOTES: Primarily of interest to game developers and other people who can avoid problematic images and only need the trivial interface JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) PNG 1/2/4/8/16-bit-per-channel TGA (not sure what subset, if a subset) BMP non-1bpp, non-RLE PSD (composited view only, no extra channels, 8/16 bit-per-channel) GIF (*comp always reports as 4-channel) HDR (radiance rgbE format) PIC (Softimage PIC) PNM (PPM and PGM binary only) Animated GIF still needs a proper API, but here's one way to do it: http://gist.github.com/urraka/685d9a6340b26b830d49 - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - decode from arbitrary I/O callbacks - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) Full documentation under "DOCUMENTATION" below. LICENSE See end of file for license information. RECENT REVISION HISTORY: 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically 2.23 (2019-08-11) fix clang static analysis warning 2.22 (2019-03-04) gif fixes, fix warnings 2.21 (2019-02-25) fix typo in comment 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 RGB-format JPEG; remove white matting in PSD; allocate large structures on the stack; correct channel count for PNG & BMP 2.10 (2016-01-22) avoid warning introduced in 2.09 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED See end of file for full revision history. ============================ Contributors ========================= Image formats Extensions, features Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) github:urraka (animated gif) Junggon Kim (PNM comments) Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) socks-the-fox (16-bit PNG) Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen Carmelo J Fdez-Aguera Bug & warning fixes Marc LeBlanc David Woo Guillaume George Martins Mozeiko Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski Phil Jordan Dave Moore Roy Eltham Hayaki Saito Nathan Reed Won Chun Luke Graham Johan Duparc Nick Verigakis the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh Janez Zemva John Bartholomew Michal Cichon github:romigrou Jonathan Blow Ken Hamada Tero Hanninen github:svdijk Eugene Golushkov Laurent Gomila Cort Stratton github:snagar Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus Josh Tobin Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 Brad Weinberger Matvey Cherevko github:mosra Luca Sas Alexander Veselov Zack Middleton [reserved] Ryan C. Gordon [reserved] [reserved] DO NOT ADD YOUR NAME HERE Jacko Dirks To add your name to the credits, pick a random blank space in the middle and fill it. 80% of merge conflicts on stb PRs are due to people adding their name at the end of the credits. */ #ifndef STBI_INCLUDE_STB_IMAGE_H #define STBI_INCLUDE_STB_IMAGE_H // DOCUMENTATION // // Limitations: // - no 12-bit-per-channel JPEG // - no JPEGs with arithmetic coding // - GIF always returns *comp=4 // // Basic usage (see HDR discussion below for HDR usage): // int x,y,n; // unsigned char *data = stbi_load(filename, &x, &y, &n, 0); // // ... process data if not NULL ... // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 // stbi_image_free(data) // // Standard parameters: // int *x -- outputs image width in pixels // int *y -- outputs image height in pixels // int *channels_in_file -- outputs # of image components in image file // int desired_channels -- if non-zero, # of image components requested in result // // The return value from an image loader is an 'unsigned char *' which points // to the pixel data, or NULL on an allocation failure or if the image is // corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, // with each pixel consisting of N interleaved 8-bit components; the first // pixel pointed to is top-left-most in the image. There is no padding between // image scanlines or between pixels, regardless of format. The number of // components N is 'desired_channels' if desired_channels is non-zero, or // *channels_in_file otherwise. If desired_channels is non-zero, // *channels_in_file has the number of components that _would_ have been // output otherwise. E.g. if you set desired_channels to 4, you will always // get RGBA output, but you can check *channels_in_file to see if it's trivially // opaque because e.g. there were only 3 channels in the source image. // // An output image with N components has the following components interleaved // in this order in each pixel: // // N=#comp components // 1 grey // 2 grey, alpha // 3 red, green, blue // 4 red, green, blue, alpha // // If image loading fails for any reason, the return value will be NULL, // and *x, *y, *channels_in_file will be unchanged. The function // stbi_failure_reason() can be queried for an extremely brief, end-user // unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS // to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly // more user-friendly ones. // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // // To query the width, height and component count of an image without having to // decode the full file, you can use the stbi_info family of functions: // // int x,y,n,ok; // ok = stbi_info(filename, &x, &y, &n); // // returns ok=1 and sets x, y, n if image is a supported format, // // 0 otherwise. // // Note that stb_image pervasively uses ints in its public API for sizes, // including sizes of memory buffers. This is now part of the API and thus // hard to change without causing breakage. As a result, the various image // loaders all have certain limits on image size; these differ somewhat // by format but generally boil down to either just under 2GB or just under // 1GB. When the decoded image would be larger than this, stb_image decoding // will fail. // // Additionally, stb_image will reject image files that have any of their // dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, // which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, // the only way to have an image with such dimensions load correctly // is for it to have a rather extreme aspect ratio. Either way, the // assumption here is that such larger images are likely to be malformed // or malicious. If you do need to load an image with individual dimensions // larger than that, and it still fits in the overall size limit, you can // #define STBI_MAX_DIMENSIONS on your own to be something larger. // // =========================================================================== // // UNICODE: // // If compiling for Windows and you wish to use Unicode filenames, compile // with // #define STBI_WINDOWS_UTF8 // and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert // Windows wchar_t filenames to utf8. // // =========================================================================== // // Philosophy // // stb libraries are designed with the following priorities: // // 1. easy to use // 2. easy to maintain // 3. good performance // // Sometimes I let "good performance" creep up in priority over "easy to maintain", // and for best performance I may provide less-easy-to-use APIs that give higher // performance, in addition to the easy-to-use ones. Nevertheless, it's important // to keep in mind that from the standpoint of you, a client of this library, // all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. // // Some secondary priorities arise directly from the first two, some of which // provide more explicit reasons why performance can't be emphasized. // // - Portable ("ease of use") // - Small source code footprint ("easy to maintain") // - No dependencies ("ease of use") // // =========================================================================== // // I/O callbacks // // I/O callbacks allow you to read from arbitrary sources, like packaged // files or some other source. Data read from callbacks are processed // through a small internal buffer (currently 128 bytes) to try to reduce // overhead. // // The three functions you must define are "read" (reads some bytes of data), // "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). // // =========================================================================== // // SIMD support // // The JPEG decoder will try to automatically use SIMD kernels on x86 when // supported by the compiler. For ARM Neon support, you must explicitly // request it. // // (The old do-it-yourself SIMD API is no longer supported in the current // code.) // // On x86, SSE2 will automatically be used when available based on a run-time // test; if not, the generic C versions are used as a fall-back. On ARM targets, // the typical path is to have separate builds for NEON and non-NEON devices // (at least this is true for iOS and Android). Therefore, the NEON support is // toggled by a build flag: define STBI_NEON to get NEON loops. // // If for some reason you do not want to use any of SIMD code, or if // you have issues compiling it, you can disable it entirely by // defining STBI_NO_SIMD. // // =========================================================================== // // HDR image support (disable by defining STBI_NO_HDR) // // stb_image supports loading HDR images in general, and currently the Radiance // .HDR file format specifically. You can still load any file through the existing // interface; if you attempt to load an HDR file, it will be automatically remapped // to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; // both of these constants can be reconfigured through this interface: // // stbi_hdr_to_ldr_gamma(2.2f); // stbi_hdr_to_ldr_scale(1.0f); // // (note, do not use _inverse_ constants; stbi_image will invert them // appropriately). // // Additionally, there is a new, parallel interface for loading files as // (linear) floats to preserve the full dynamic range: // // float *data = stbi_loadf(filename, &x, &y, &n, 0); // // If you load LDR images through this interface, those images will // be promoted to floating point values, run through the inverse of // constants corresponding to the above: // // stbi_ldr_to_hdr_scale(1.0f); // stbi_ldr_to_hdr_gamma(2.2f); // // Finally, given a filename (or an open file or memory block--see header // file for details) containing image data, you can query for the "most // appropriate" interface to use (that is, whether the image is HDR or // not), using: // // stbi_is_hdr(char *filename); // // =========================================================================== // // iPhone PNG support: // // We optionally support converting iPhone-formatted PNGs (which store // premultiplied BGRA) back to RGB, even though they're internally encoded // differently. To enable this conversion, call // stbi_convert_iphone_png_to_rgb(1). // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly // says there's premultiplied data (currently only happens in iPhone images, // and only if iPhone convert-to-rgb processing is on). // // =========================================================================== // // ADDITIONAL CONFIGURATION // // - You can suppress implementation of any of the decoders to reduce // your code footprint by #defining one or more of the following // symbols before creating the implementation. // // STBI_NO_JPEG // STBI_NO_PNG // STBI_NO_BMP // STBI_NO_PSD // STBI_NO_TGA // STBI_NO_GIF // STBI_NO_HDR // STBI_NO_PIC // STBI_NO_PNM (.ppm and .pgm) // // - You can request *only* certain decoders and suppress all other ones // (this will be more forward-compatible, as addition of new decoders // doesn't require you to disable them explicitly): // // STBI_ONLY_JPEG // STBI_ONLY_PNG // STBI_ONLY_BMP // STBI_ONLY_PSD // STBI_ONLY_TGA // STBI_ONLY_GIF // STBI_ONLY_HDR // STBI_ONLY_PIC // STBI_ONLY_PNM (.ppm and .pgm) // // - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB // // - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater // than that size (in either width or height) without further processing. // This is to let programs in the wild set an upper bound to prevent // denial-of-service attacks on untrusted data, as one could generate a // valid image of gigantic dimensions and force stb_image to allocate a // huge block of memory and spend disproportionate time decoding it. By // default this is set to (1 << 24), which is 16777216, but that's still // very big. #ifndef STBI_NO_STDIO #include #endif // STBI_NO_STDIO #define STBI_VERSION 1 enum { STBI_default = 0, // only used for desired_channels STBI_grey = 1, STBI_grey_alpha = 2, STBI_rgb = 3, STBI_rgb_alpha = 4 }; #include typedef unsigned char stbi_uc; typedef unsigned short stbi_us; #ifdef __cplusplus extern "C" { #endif #ifndef STBIDEF #ifdef STB_IMAGE_STATIC #define STBIDEF static #else #define STBIDEF extern #endif #endif ////////////////////////////////////////////////////////////////////////////// // // PRIMARY API - works on images of any type // // // load image by filename, open file, or memory buffer // typedef struct { int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative int (*eof) (void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; //////////////////////////////////// // // 8-bits-per-channel interface // STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif #ifndef STBI_NO_GIF STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); #endif #ifdef STBI_WINDOWS_UTF8 STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); #endif //////////////////////////////////// // // 16-bits-per-channel interface // STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); #endif //////////////////////////////////// // // float-per-channel interface // #ifndef STBI_NO_LINEAR STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); #endif #endif #ifndef STBI_NO_HDR STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); STBIDEF void stbi_hdr_to_ldr_scale(float scale); #endif // STBI_NO_HDR #ifndef STBI_NO_LINEAR STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); STBIDEF void stbi_ldr_to_hdr_scale(float scale); #endif // STBI_NO_LINEAR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); #ifndef STBI_NO_STDIO STBIDEF int stbi_is_hdr (char const *filename); STBIDEF int stbi_is_hdr_from_file(FILE *f); #endif // STBI_NO_STDIO // get a VERY brief reason for failure // on most compilers (and ALL modern mainstream compilers) this is threadsafe STBIDEF const char *stbi_failure_reason (void); // free the loaded image -- this is just free() STBIDEF void stbi_image_free (void *retval_from_stbi_load); // get image dimensions & components without fully decoding STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); #ifndef STBI_NO_STDIO STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); STBIDEF int stbi_is_16_bit (char const *filename); STBIDEF int stbi_is_16_bit_from_file(FILE *f); #endif // for image formats that explicitly notate that they have premultiplied alpha, // we just return the colors as stored in the file. set this flag to force // unpremultiplication. results are undefined if the unpremultiply overflow. STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); // indicate whether we should process iphone images back to canonical format, // or just pass them through "as-is" STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); // flip the image vertically, so the first pixel in the output array is the bottom left STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); // as above, but only applies to images loaded on the thread that calls the function // this function is only available if your compiler supports thread-local variables; // calling it will fail to link if your compiler doesn't STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); #ifndef STBI_NO_DDS #include "stbi_DDS.h" #endif #ifndef STBI_NO_PVR #include "stbi_pvr.h" #endif #ifndef STBI_NO_PKM #include "stbi_pkm.h" #endif #ifndef STBI_NO_QOI #include "stbi_qoi.h" #endif #ifndef STBI_NO_EXT #include "stbi_ext.h" #endif #ifdef __cplusplus } #endif // // //// end header file ///////////////////////////////////////////////////// #endif // STBI_INCLUDE_STB_IMAGE_H #ifdef STB_IMAGE_IMPLEMENTATION #if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ || defined(STBI_ONLY_QOI) || defined(STBI_ONLY_ZLIB) #ifndef STBI_ONLY_JPEG #define STBI_NO_JPEG #endif #ifndef STBI_ONLY_PNG #define STBI_NO_PNG #endif #ifndef STBI_ONLY_BMP #define STBI_NO_BMP #endif #ifndef STBI_ONLY_PSD #define STBI_NO_PSD #endif #ifndef STBI_ONLY_TGA #define STBI_NO_TGA #endif #ifndef STBI_ONLY_GIF #define STBI_NO_GIF #endif #ifndef STBI_ONLY_HDR #define STBI_NO_HDR #endif #ifndef STBI_ONLY_PIC #define STBI_NO_PIC #endif #ifndef STBI_ONLY_PNM #define STBI_NO_PNM #endif #ifndef STBI_ONLY_QOI #define STBI_NO_QOI #endif #endif #if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) #define STBI_NO_ZLIB #endif #include #include // ptrdiff_t on osx #include #include #include #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) #include // ldexp, pow #endif #ifndef STBI_NO_STDIO #include #endif #ifndef STBI_ASSERT #include #define STBI_ASSERT(x) assert(x) #endif #ifdef __cplusplus #define STBI_EXTERN extern "C" #else #define STBI_EXTERN extern #endif #ifndef _MSC_VER #ifdef __cplusplus #define stbi_inline inline #else #define stbi_inline #endif #else #define stbi_inline __forceinline #endif #ifndef STBI_NO_THREAD_LOCALS #if defined(__cplusplus) && __cplusplus >= 201103L #define STBI_THREAD_LOCAL thread_local #elif defined(__GNUC__) && __GNUC__ < 5 #define STBI_THREAD_LOCAL __thread #elif defined(_MSC_VER) #define STBI_THREAD_LOCAL __declspec(thread) #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) #define STBI_THREAD_LOCAL _Thread_local #endif #ifndef STBI_THREAD_LOCAL #if defined(__GNUC__) #define STBI_THREAD_LOCAL __thread #endif #endif #endif #ifdef _MSC_VER typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; typedef signed int stbi__int32; #else #include typedef uint16_t stbi__uint16; typedef int16_t stbi__int16; typedef uint32_t stbi__uint32; typedef int32_t stbi__int32; #endif // should produce compiler error if size is wrong typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef _MSC_VER #define STBI_NOTUSED(v) (void)(v) #else #define STBI_NOTUSED(v) (void)sizeof(v) #endif #ifdef _MSC_VER #define STBI_HAS_LROTL #endif #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) // ok #elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) // ok #else #error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." #endif #ifndef STBI_MALLOC #define STBI_MALLOC(sz) malloc(sz) #define STBI_REALLOC(p,newsz) realloc(p,newsz) #define STBI_FREE(p) free(p) #endif #ifndef STBI_REALLOC_SIZED #define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) #endif // x86/x64 detection #if defined(__x86_64__) || defined(_M_X64) #define STBI__X64_TARGET #elif defined(__i386) || defined(_M_IX86) #define STBI__X86_TARGET #endif #if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) // Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET // // 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the // Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. // As a result, enabling SSE2 on 32-bit MinGW is dangerous when not // simultaneously enabling "-mstackrealign". // // See https://github.com/nothings/stb/issues/81 for more information. // // So default to no SSE2 on 32-bit MinGW. If you've read this far and added // -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. #define STBI_NO_SIMD #endif #if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) #define STBI_SSE2 #include #ifdef _MSC_VER #if _MSC_VER >= 1400 // not VC6 #include // __cpuid static int stbi__cpuid3(void) { int info[4]; __cpuid(info,1); return info[3]; } #else static int stbi__cpuid3(void) { int res; __asm { mov eax,1 cpuid mov res,edx } return res; } #endif #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) static int stbi__sse2_available(void) { int info3 = stbi__cpuid3(); return ((info3 >> 26) & 1) != 0; } #endif #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) static int stbi__sse2_available(void) { // If we're even attempting to compile this on GCC/Clang, that means // -msse2 is on, which means the compiler is allowed to use SSE2 // instructions at will, and so are we. return 1; } #endif #endif #endif // ARM NEON #if defined(STBI_NO_SIMD) && defined(STBI_NEON) #undef STBI_NEON #endif #ifdef STBI_NEON #include #ifdef _MSC_VER #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name #else #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #endif #endif #ifndef STBI_SIMD_ALIGN #define STBI_SIMD_ALIGN(type, name) type name #endif #ifndef STBI_MAX_DIMENSIONS #define STBI_MAX_DIMENSIONS (1 << 24) #endif /////////////////////////////////////////////// // // stbi__context struct and start_xxx functions // stbi__context structure is our basic context used by all images, so it // contains all the IO context, plus some basic image information typedef struct { stbi__uint32 img_x, img_y; int img_n, img_out_n; stbi_io_callbacks io; void *io_user_data; int read_from_callbacks; int buflen; stbi_uc buffer_start[128]; int callback_already_read; stbi_uc *img_buffer, *img_buffer_end; stbi_uc *img_buffer_original, *img_buffer_original_end; } stbi__context; static void stbi__refill_buffer(stbi__context *s); // initialize a memory-decode context static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { s->io.read = NULL; s->read_from_callbacks = 0; s->callback_already_read = 0; s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; } // initialize a callback-based context static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) { s->io = *c; s->io_user_data = user; s->buflen = sizeof(s->buffer_start); s->read_from_callbacks = 1; s->callback_already_read = 0; s->img_buffer = s->img_buffer_original = s->buffer_start; stbi__refill_buffer(s); s->img_buffer_original_end = s->img_buffer_end; } #ifndef STBI_NO_STDIO static int stbi__stdio_read(void *user, char *data, int size) { return (int) fread(data,1,size,(FILE*) user); } static void stbi__stdio_skip(void *user, int n) { int ch; fseek((FILE*) user, n, SEEK_CUR); ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ if (ch != EOF) { ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ } } static int stbi__stdio_eof(void *user) { return feof((FILE*) user) || ferror((FILE *) user); } static stbi_io_callbacks stbi__stdio_callbacks = { stbi__stdio_read, stbi__stdio_skip, stbi__stdio_eof, }; static void stbi__start_file(stbi__context *s, FILE *f) { stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); } //static void stop_file(stbi__context *s) { } #endif // !STBI_NO_STDIO static void stbi__rewind(stbi__context *s) { // conceptually rewind SHOULD rewind to the beginning of the stream, // but we just rewind to the beginning of the initial buffer, because // we only use it after doing 'test', which only ever looks at at most 92 bytes s->img_buffer = s->img_buffer_original; s->img_buffer_end = s->img_buffer_original_end; } enum { STBI_ORDER_RGB, STBI_ORDER_BGR }; typedef struct { int bits_per_channel; int num_channels; int channel_order; } stbi__result_info; #ifndef STBI_NO_JPEG static int stbi__jpeg_test(stbi__context *s); static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNG static int stbi__png_test(stbi__context *s); static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__png_is16(stbi__context *s); #endif #ifndef STBI_NO_BMP static int stbi__bmp_test(stbi__context *s); static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_TGA static int stbi__tga_test(stbi__context *s); static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PSD static int stbi__psd_test(stbi__context *s); static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__psd_is16(stbi__context *s); #endif #ifndef STBI_NO_HDR static int stbi__hdr_test(stbi__context *s); static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PIC static int stbi__pic_test(stbi__context *s); static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_GIF static int stbi__gif_test(stbi__context *s); static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNM static int stbi__pnm_test(stbi__context *s); static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_is16(stbi__context *s); #endif #ifndef STBI_NO_DDS static int stbi__dds_test(stbi__context *s); static void *stbi__dds_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__dds_info(stbi__context *s, int *x, int *y, int *comp, int *iscompressed); #endif #ifndef STBI_NO_PVR static int stbi__pvr_test(stbi__context *s); static void *stbi__pvr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__pvr_info(stbi__context *s, int *x, int *y, int *comp, int * iscompressed); #endif #ifndef STBI_NO_PKM static int stbi__pkm_test(stbi__context *s); static void *stbi__pkm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__pkm_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_QOI static int stbi__qoi_test(stbi__context *s); static void *stbi__qoi_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__qoi_info(stbi__context *s, int *x, int *y, int *comp); #endif static #ifdef STBI_THREAD_LOCAL STBI_THREAD_LOCAL #endif const char *stbi__g_failure_reason; STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } #ifndef STBI_NO_FAILURE_STRINGS static int stbi__err(const char *str) { stbi__g_failure_reason = str; return 0; } #endif static void *stbi__malloc(size_t size) { return STBI_MALLOC(size); } // stb_image uses ints pervasively, including for offset calculations. // therefore the largest decoded image size we can support with the // current code, even on 64-bit targets, is INT_MAX. this is not a // significant limitation for the intended use case. // // we do, however, need to make sure our size calculations don't // overflow. hence a few helper functions for size calculations that // multiply integers together, making sure that they're non-negative // and no overflow occurs. // return 1 if the sum is valid, 0 on overflow. // negative terms are considered invalid. static int stbi__addsizes_valid(int a, int b) { if (b < 0) return 0; // now 0 <= b <= INT_MAX, hence also // 0 <= INT_MAX - b <= INTMAX. // And "a + b <= INT_MAX" (which might overflow) is the // same as a <= INT_MAX - b (no overflow) return a <= INT_MAX - b; } // returns 1 if the product is valid, 0 on overflow. // negative factors are considered invalid. static int stbi__mul2sizes_valid(int a, int b) { if (a < 0 || b < 0) return 0; if (b == 0) return 1; // mul-by-0 is always safe // portable way to check for no overflows in a*b return a <= INT_MAX/b; } #if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow static int stbi__mad2sizes_valid(int a, int b, int add) { return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); } #endif // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow static int stbi__mad3sizes_valid(int a, int b, int c, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && stbi__addsizes_valid(a*b*c, add); } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); } #endif #if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // mallocs with size overflow checking static void *stbi__malloc_mad2(int a, int b, int add) { if (!stbi__mad2sizes_valid(a, b, add)) return NULL; return stbi__malloc(a*b + add); } #endif static void *stbi__malloc_mad3(int a, int b, int c, int add) { if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; return stbi__malloc(a*b*c + add); } #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; return stbi__malloc(a*b*c*d + add); } #endif // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char #ifdef STBI_NO_FAILURE_STRINGS #define stbi__err(x,y) 0 #elif defined(STBI_FAILURE_USERMSG) #define stbi__err(x,y) stbi__err(y) #else #define stbi__err(x,y) stbi__err(x) #endif #define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) #define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) STBIDEF void stbi_image_free(void *retval_from_stbi_load) { STBI_FREE(retval_from_stbi_load); } #ifndef STBI_NO_LINEAR static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); #endif #ifndef STBI_NO_HDR static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif static int stbi__vertically_flip_on_load_global = 0; STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } #ifndef STBI_THREAD_LOCAL #define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global #else static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) { stbi__vertically_flip_on_load_local = flag_true_if_should_flip; stbi__vertically_flip_on_load_set = 1; } #define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ ? stbi__vertically_flip_on_load_local \ : stbi__vertically_flip_on_load_global) #endif // STBI_THREAD_LOCAL static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order ri->num_channels = 0; // test the formats with a very explicit header first (at least a FOURCC // or distinctive magic number first) #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_BMP if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_GIF if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PSD if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); #else STBI_NOTUSED(bpc); #endif #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_DDS if (stbi__dds_test(s)) return stbi__dds_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_PVR if (stbi__pvr_test(s)) return stbi__pvr_load(s,x,y,comp,req_comp); #endif #ifndef STBI_NO_PKM if (stbi__pkm_test(s)) return stbi__pkm_load(s,x,y,comp,req_comp); #endif // then the formats that can end up attempting to load with just 1 or 2 // bytes matching expectations; these are prone to false positives, so // try them later #ifndef STBI_NO_JPEG if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_QOI if (stbi__qoi_test(s)) return stbi__qoi_load(s,x,y,comp,req_comp, ri); #endif #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); } #endif #ifndef STBI_NO_TGA // test tga last because it's a crappy test! if (stbi__tga_test(s)) return stbi__tga_load(s,x,y,comp,req_comp, ri); #endif return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); } static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) { int i; int img_len = w * h * channels; stbi_uc *reduced; reduced = (stbi_uc *) stbi__malloc(img_len); if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); for (i = 0; i < img_len; ++i) reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling STBI_FREE(orig); return reduced; } static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) { int i; int img_len = w * h * channels; stbi__uint16 *enlarged; enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); for (i = 0; i < img_len; ++i) enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff STBI_FREE(orig); return enlarged; } static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) { int row; size_t bytes_per_row = (size_t)w * bytes_per_pixel; stbi_uc temp[2048]; stbi_uc *bytes = (stbi_uc *)image; for (row = 0; row < (h>>1); row++) { stbi_uc *row0 = bytes + row*bytes_per_row; stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; // swap row0 with row1 size_t bytes_left = bytes_per_row; while (bytes_left) { size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); memcpy(temp, row0, bytes_copy); memcpy(row0, row1, bytes_copy); memcpy(row1, temp, bytes_copy); row0 += bytes_copy; row1 += bytes_copy; bytes_left -= bytes_copy; } } } #ifndef STBI_NO_GIF static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) { int slice; int slice_size = w * h * bytes_per_pixel; stbi_uc *bytes = (stbi_uc *)image; for (slice = 0; slice < z; ++slice) { stbi__vertical_flip(bytes, w, h, bytes_per_pixel); bytes += slice_size; } } #endif static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi__result_info ri; void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); if (result == NULL) return NULL; // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); if (ri.bits_per_channel != 8) { result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 8; } // @TODO: move stbi__convert_format to here if (stbi__vertically_flip_on_load) { int channels = req_comp ? req_comp : *comp; stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); } return (unsigned char *) result; } static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi__result_info ri; void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); if (result == NULL) return NULL; // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); if (ri.bits_per_channel != 16) { result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 16; } // @TODO: move stbi__convert_format16 to here // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision if (stbi__vertically_flip_on_load) { int channels = req_comp ? req_comp : *comp; stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); } return (stbi__uint16 *) result; } #if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { if (stbi__vertically_flip_on_load && result != NULL) { int channels = req_comp ? req_comp : *comp; stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); } } #endif #ifndef STBI_NO_STDIO #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); } #endif static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; #if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; #if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != fopen_s(&f, filename, mode)) f=0; #else f = fopen(filename, mode); #endif return f; } STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) { FILE *f = stbi__fopen(filename, "rb"); unsigned char *result; if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); result = stbi_load_from_file(f,x,y,comp,req_comp); fclose(f); return result; } STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { unsigned char *result; stbi__context s; stbi__start_file(&s,f); result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); if (result) { // need to 'unget' all the characters in the IO buffer fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); } return result; } STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) { stbi__uint16 *result; stbi__context s; stbi__start_file(&s,f); result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); if (result) { // need to 'unget' all the characters in the IO buffer fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); } return result; } STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) { FILE *f = stbi__fopen(filename, "rb"); stbi__uint16 *result; if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); result = stbi_load_from_file_16(f,x,y,comp,req_comp); fclose(f); return result; } #endif //!STBI_NO_STDIO STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); } STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); } STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); } STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); } #ifndef STBI_NO_GIF STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { unsigned char *result; stbi__context s; stbi__start_mem(&s,buffer,len); result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); if (stbi__vertically_flip_on_load) { stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); } return result; } #endif #ifndef STBI_NO_LINEAR static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) { unsigned char *data; #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { stbi__result_info ri; float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); if (hdr_data) stbi__float_postprocess(hdr_data,x,y,comp,req_comp); return hdr_data; } #endif data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); if (data) return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); } STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi__loadf_main(&s,x,y,comp,req_comp); } STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__loadf_main(&s,x,y,comp,req_comp); } #ifndef STBI_NO_STDIO STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) { float *result; FILE *f = stbi__fopen(filename, "rb"); if (!f) return stbi__errpf("can't fopen", "Unable to open file"); result = stbi_loadf_from_file(f,x,y,comp,req_comp); fclose(f); return result; } STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_file(&s,f); return stbi__loadf_main(&s,x,y,comp,req_comp); } #endif // !STBI_NO_STDIO #endif // !STBI_NO_LINEAR // these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is // defined, for API simplicity; if STBI_NO_LINEAR is defined, it always // reports false! STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) { #ifndef STBI_NO_HDR stbi__context s; stbi__start_mem(&s,buffer,len); return stbi__hdr_test(&s); #else STBI_NOTUSED(buffer); STBI_NOTUSED(len); return 0; #endif } #ifndef STBI_NO_STDIO STBIDEF int stbi_is_hdr (char const *filename) { FILE *f = stbi__fopen(filename, "rb"); int result=0; if (f) { result = stbi_is_hdr_from_file(f); fclose(f); } return result; } STBIDEF int stbi_is_hdr_from_file(FILE *f) { #ifndef STBI_NO_HDR long pos = ftell(f); int res; stbi__context s; stbi__start_file(&s,f); res = stbi__hdr_test(&s); fseek(f, pos, SEEK_SET); return res; #else STBI_NOTUSED(f); return 0; #endif } #endif // !STBI_NO_STDIO STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) { #ifndef STBI_NO_HDR stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__hdr_test(&s); #else STBI_NOTUSED(clbk); STBI_NOTUSED(user); return 0; #endif } #ifndef STBI_NO_LINEAR static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } #endif static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } ////////////////////////////////////////////////////////////////////////////// // // Common code used by all image loaders // enum { STBI__SCAN_load=0, STBI__SCAN_type, STBI__SCAN_header }; static void stbi__refill_buffer(stbi__context *s) { int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); if (n == 0) { // at end of file, treat same as if from memory, but need to handle case // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file s->read_from_callbacks = 0; s->img_buffer = s->buffer_start; s->img_buffer_end = s->buffer_start+1; *s->img_buffer = 0; } else { s->img_buffer = s->buffer_start; s->img_buffer_end = s->buffer_start + n; } } stbi_inline static stbi_uc stbi__get8(stbi__context *s) { if (s->img_buffer < s->img_buffer_end) return *s->img_buffer++; if (s->read_from_callbacks) { stbi__refill_buffer(s); return *s->img_buffer++; } return 0; } #if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing #else stbi_inline static int stbi__at_eof(stbi__context *s) { if (s->io.read) { if (!(s->io.eof)(s->io_user_data)) return 0; // if feof() is true, check if buffer = end // special case: we've only got the special 0 character at the end if (s->read_from_callbacks == 0) return 1; } return s->img_buffer >= s->img_buffer_end; } #endif #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) // nothing #else static void stbi__skip(stbi__context *s, int n) { if (n == 0) return; // already there! if (n < 0) { s->img_buffer = s->img_buffer_end; return; } if (s->io.read) { int blen = (int) (s->img_buffer_end - s->img_buffer); if (blen < n) { s->img_buffer = s->img_buffer_end; (s->io.skip)(s->io_user_data, n - blen); return; } } s->img_buffer += n; } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) // nothing #else static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { if (s->io.read) { int blen = (int) (s->img_buffer_end - s->img_buffer); if (blen < n) { int res, count; memcpy(buffer, s->img_buffer, blen); count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); res = (count == (n-blen)); s->img_buffer = s->img_buffer_end; return res; } } if (s->img_buffer+n <= s->img_buffer_end) { memcpy(buffer, s->img_buffer, n); s->img_buffer += n; return 1; } else return 0; } #endif #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) // nothing #else static int stbi__get16be(stbi__context *s) { int z = stbi__get8(s); return (z << 8) + stbi__get8(s); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) && defined(STBI_NO_QOI) // nothing #else static stbi__uint32 stbi__get32be(stbi__context *s) { stbi__uint32 z = stbi__get16be(s); return (z << 16) + stbi__get16be(s); } #endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing #else static int stbi__get16le(stbi__context *s) { int z = stbi__get8(s); return z + (stbi__get8(s) << 8); } #endif #ifndef STBI_NO_BMP static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); z += (stbi__uint32)stbi__get16le(s) << 16; return z; } #endif #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing #else ////////////////////////////////////////////////////////////////////////////// // // generic converter from built-in img_n to req_comp // individual types do this automatically as much as possible (e.g. jpeg // does all cases internally since it needs to colorspace convert anyway, // and it never has alpha, so very few cases ). png can automatically // interleave an alpha=255 channel, but falls back to this for other cases // // assume data buffer is malloced, so malloc a new one and free that one // only failure mode is malloc failing static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) // nothing #else static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; unsigned char *good; if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); if (good == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } for (j=0; j < (int) y; ++j) { unsigned char *src = data + j * x * img_n ; unsigned char *dest = good + j * x * req_comp; #define STBI__COMBO(a,b) ((a)*8+(b)) #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros switch (STBI__COMBO(img_n, req_comp)) { STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; STBI__CASE(2,1) { dest[0]=src[0]; } break; STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } STBI_FREE(data); return good; } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) // nothing #else static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); } #endif #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) // nothing #else static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; stbi__uint16 *good; if (req_comp == img_n) return data; STBI_ASSERT(req_comp >= 1 && req_comp <= 4); good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); if (good == NULL) { STBI_FREE(data); return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); } for (j=0; j < (int) y; ++j) { stbi__uint16 *src = data + j * x * img_n ; stbi__uint16 *dest = good + j * x * req_comp; #define STBI__COMBO(a,b) ((a)*8+(b)) #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) // convert source image with img_n components to one with req_comp components; // avoid switch per pixel, so use switch per scanline and massive macros switch (STBI__COMBO(img_n, req_comp)) { STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; STBI__CASE(2,1) { dest[0]=src[0]; } break; STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } STBI_FREE(data); return good; } #endif #ifndef STBI_NO_LINEAR static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { int i,k,n; float *output; if (!data) return NULL; output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; for (i=0; i < x*y; ++i) { for (k=0; k < n; ++k) { output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); } } if (n < comp) { for (i=0; i < x*y; ++i) { output[i*comp + n] = data[i*comp + n]/255.0f; } } STBI_FREE(data); return output; } #endif #ifndef STBI_NO_HDR #define stbi__float2int(x) ((int) (x)) static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) { int i,k,n; stbi_uc *output; if (!data) return NULL; output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; for (i=0; i < x*y; ++i) { for (k=0; k < n; ++k) { float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; if (z < 0) z = 0; if (z > 255) z = 255; output[i*comp + k] = (stbi_uc) stbi__float2int(z); } if (k < comp) { float z = data[i*comp+k] * 255 + 0.5f; if (z < 0) z = 0; if (z > 255) z = 255; output[i*comp + k] = (stbi_uc) stbi__float2int(z); } } STBI_FREE(data); return output; } #endif ////////////////////////////////////////////////////////////////////////////// // // "baseline" JPEG/JFIF decoder // // simple implementation // - doesn't support delayed output of y-dimension // - simple interface (only one output format: 8-bit interleaved RGB) // - doesn't try to recover corrupt jpegs // - doesn't allow partial loading, loading multiple at once // - still fast on x86 (copying globals into locals doesn't help x86) // - allocates lots of intermediate memory (full size of all components) // - non-interleaved case requires this anyway // - allows good upsampling (see next) // high-quality // - upsampled channels are bilinearly interpolated, even across blocks // - quality integer IDCT derived from IJG's 'slow' // performance // - fast huffman; reasonable integer IDCT // - some SIMD kernels for common paths on targets with SSE2/NEON // - uses a lot of intermediate memory, could cache poorly #ifndef STBI_NO_JPEG // huffman decoding acceleration #define FAST_BITS 9 // larger handles more cases; smaller stomps less cache typedef struct { stbi_uc fast[1 << FAST_BITS]; // weirdly, repacking this into AoS is a 10% speed loss, instead of a win stbi__uint16 code[256]; stbi_uc values[256]; stbi_uc size[257]; unsigned int maxcode[18]; int delta[17]; // old 'firstsymbol' - old 'firstcode' } stbi__huffman; typedef struct { stbi__context *s; stbi__huffman huff_dc[4]; stbi__huffman huff_ac[4]; stbi__uint16 dequant[4][64]; stbi__int16 fast_ac[4][1 << FAST_BITS]; // sizes for components, interleaved MCUs int img_h_max, img_v_max; int img_mcu_x, img_mcu_y; int img_mcu_w, img_mcu_h; // definition of jpeg image component struct { int id; int h,v; int tq; int hd,ha; int dc_pred; int x,y,w2,h2; stbi_uc *data; void *raw_data, *raw_coeff; stbi_uc *linebuf; short *coeff; // progressive only int coeff_w, coeff_h; // number of 8x8 coefficient blocks } img_comp[4]; stbi__uint32 code_buffer; // jpeg entropy-coded buffer int code_bits; // number of valid bits unsigned char marker; // marker seen while filling entropy buffer int nomore; // flag if we saw a marker so must stop int progressive; int spec_start; int spec_end; int succ_high; int succ_low; int eob_run; int jfif; int app14_color_transform; // Adobe APP14 tag int rgb; int scan_n, order[4]; int restart_interval, todo; // kernels void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); } stbi__jpeg; static int stbi__build_huffman(stbi__huffman *h, int *count) { int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) for (i=0; i < 16; ++i) for (j=0; j < count[i]; ++j) h->size[k++] = (stbi_uc) (i+1); h->size[k] = 0; // compute actual symbols (from jpeg spec) code = 0; k = 0; for(j=1; j <= 16; ++j) { // compute delta to add to code to compute symbol id h->delta[j] = k - code; if (h->size[k] == j) { while (h->size[k] == j) h->code[k++] = (stbi__uint16) (code++); if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); } // compute largest code + 1 for this size, preshifted as needed later h->maxcode[j] = code << (16-j); code <<= 1; } h->maxcode[j] = 0xffffffff; // build non-spec acceleration table; 255 is flag for not-accelerated memset(h->fast, 255, 1 << FAST_BITS); for (i=0; i < k; ++i) { int s = h->size[i]; if (s <= FAST_BITS) { int c = h->code[i] << (FAST_BITS-s); int m = 1 << (FAST_BITS-s); for (j=0; j < m; ++j) { h->fast[c+j] = (stbi_uc) i; } } } return 1; } // build a table that decodes both magnitude and value of small ACs in // one go. static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) { int i; for (i=0; i < (1 << FAST_BITS); ++i) { stbi_uc fast = h->fast[i]; fast_ac[i] = 0; if (fast < 255) { int rs = h->values[fast]; int run = (rs >> 4) & 15; int magbits = rs & 15; int len = h->size[fast]; if (magbits && len + magbits <= FAST_BITS) { // magnitude code followed by receive_extend code int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); int m = 1 << (magbits - 1); if (k < m) k += (~0U << magbits) + 1; // if the result is small enough, we can fit it in fast_ac table if (k >= -128 && k <= 127) fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); } } } } static void stbi__grow_buffer_unsafe(stbi__jpeg *j) { do { unsigned int b = j->nomore ? 0 : stbi__get8(j->s); if (b == 0xff) { int c = stbi__get8(j->s); while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes if (c != 0) { j->marker = (unsigned char) c; j->nomore = 1; return; } } j->code_buffer |= b << (24 - j->code_bits); j->code_bits += 8; } while (j->code_bits <= 24); } // (1 << n) - 1 static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; // decode a jpeg huffman value from the bitstream stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) { unsigned int temp; int c,k; if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); // look at the top FAST_BITS and determine what symbol ID it is, // if the code is <= FAST_BITS c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); k = h->fast[c]; if (k < 255) { int s = h->size[k]; if (s > j->code_bits) return -1; j->code_buffer <<= s; j->code_bits -= s; return h->values[k]; } // naive test is to shift the code_buffer down so k bits are // valid, then test against maxcode. To speed this up, we've // preshifted maxcode left so that it has (16-k) 0s at the // end; in other words, regardless of the number of bits, it // wants to be compared against something shifted to have 16; // that way we don't need to shift inside the loop. temp = j->code_buffer >> 16; for (k=FAST_BITS+1 ; ; ++k) if (temp < h->maxcode[k]) break; if (k == 17) { // error! code not found j->code_bits -= 16; return -1; } if (k > j->code_bits) return -1; // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol j->code_bits -= k; j->code_buffer <<= k; return h->values[c]; } // bias[n] = (-1<code_bits < n) stbi__grow_buffer_unsafe(j); sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; return k; } stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; return k & 0x80000000; } // given a value that's at position X in the zigzag stream, // where does it appear in the 8x8 matrix coded as row-major? static const stbi_uc stbi__jpeg_dezigzag[64+15] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, // let corrupt input sample past end 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }; // decode one 64-entry block-- static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) { int diff,dc,k; int t; if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); t = stbi__jpeg_huff_decode(j, hdc); if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec k = 1; do { unsigned int zig; int c,r,s; if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); r = fac[c]; if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location zig = stbi__jpeg_dezigzag[k++]; data[zig] = (short) ((r >> 8) * dequant[zig]); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); s = rs & 15; r = rs >> 4; if (s == 0) { if (rs != 0xf0) break; // end block k += 16; } else { k += r; // decode into unzigzag'd location zig = stbi__jpeg_dezigzag[k++]; data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); } } } while (k < 64); return 1; } static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) { int diff,dc; int t; if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); if (j->succ_high == 0) { // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) data[0] += (short) (1 << j->succ_low); } return 1; } // @OPTIMIZE: store non-zigzagged during the decode passes, // and only de-zigzag when dequantizing static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) { int k; if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); if (j->succ_high == 0) { int shift = j->succ_low; if (j->eob_run) { --j->eob_run; return 1; } k = j->spec_start; do { unsigned int zig; int c,r,s; if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); r = fac[c]; if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; data[zig] = (short) ((r >> 8) * (1 << shift)); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); s = rs & 15; r = rs >> 4; if (s == 0) { if (r < 15) { j->eob_run = (1 << r); if (r) j->eob_run += stbi__jpeg_get_bits(j, r); --j->eob_run; break; } k += 16; } else { k += r; zig = stbi__jpeg_dezigzag[k++]; data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); } } } while (k <= j->spec_end); } else { // refinement scan for these AC coefficients short bit = (short) (1 << j->succ_low); if (j->eob_run) { --j->eob_run; for (k = j->spec_start; k <= j->spec_end; ++k) { short *p = &data[stbi__jpeg_dezigzag[k]]; if (*p != 0) if (stbi__jpeg_get_bit(j)) if ((*p & bit)==0) { if (*p > 0) *p += bit; else *p -= bit; } } } else { k = j->spec_start; do { int r,s; int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); s = rs & 15; r = rs >> 4; if (s == 0) { if (r < 15) { j->eob_run = (1 << r) - 1; if (r) j->eob_run += stbi__jpeg_get_bits(j, r); r = 64; // force end of block } else { // r=15 s=0 should write 16 0s, so we just do // a run of 15 0s and then write s (which is 0), // so we don't have to do anything special here } } else { if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); // sign bit if (stbi__jpeg_get_bit(j)) s = bit; else s = -bit; } // advance by r while (k <= j->spec_end) { short *p = &data[stbi__jpeg_dezigzag[k++]]; if (*p != 0) { if (stbi__jpeg_get_bit(j)) if ((*p & bit)==0) { if (*p > 0) *p += bit; else *p -= bit; } } else { if (r == 0) { *p = (short) s; break; } --r; } } } while (k <= j->spec_end); } } return 1; } // take a -128..127 value and stbi__clamp it and convert to 0..255 stbi_inline static stbi_uc stbi__clamp(int x) { // trick to use a single test to catch both cases if ((unsigned int) x > 255) { if (x < 0) return 0; if (x > 255) return 255; } return (stbi_uc) x; } #define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) #define stbi__fsh(x) ((x) * 4096) // derived from jidctint -- DCT_ISLOW #define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ p2 = s2; \ p3 = s6; \ p1 = (p2+p3) * stbi__f2f(0.5411961f); \ t2 = p1 + p3*stbi__f2f(-1.847759065f); \ t3 = p1 + p2*stbi__f2f( 0.765366865f); \ p2 = s0; \ p3 = s4; \ t0 = stbi__fsh(p2+p3); \ t1 = stbi__fsh(p2-p3); \ x0 = t0+t3; \ x3 = t0-t3; \ x1 = t1+t2; \ x2 = t1-t2; \ t0 = s7; \ t1 = s5; \ t2 = s3; \ t3 = s1; \ p3 = t0+t2; \ p4 = t1+t3; \ p1 = t0+t3; \ p2 = t1+t2; \ p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ t0 = t0*stbi__f2f( 0.298631336f); \ t1 = t1*stbi__f2f( 2.053119869f); \ t2 = t2*stbi__f2f( 3.072711026f); \ t3 = t3*stbi__f2f( 1.501321110f); \ p1 = p5 + p1*stbi__f2f(-0.899976223f); \ p2 = p5 + p2*stbi__f2f(-2.562915447f); \ p3 = p3*stbi__f2f(-1.961570560f); \ p4 = p4*stbi__f2f(-0.390180644f); \ t3 += p1+p4; \ t2 += p2+p3; \ t1 += p2+p4; \ t0 += p1+p3; static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) { int i,val[64],*v=val; stbi_uc *o; short *d = data; // columns for (i=0; i < 8; ++i,++d, ++v) { // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 && d[40]==0 && d[48]==0 && d[56]==0) { // no shortcut 0 seconds // (1|2|3|4|5|6|7)==0 0 seconds // all separate -0.047 seconds // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds int dcterm = d[0]*4; v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; } else { STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) // constants scaled things up by 1<<12; let's bring them back // down, but keep 2 extra bits of precision x0 += 512; x1 += 512; x2 += 512; x3 += 512; v[ 0] = (x0+t3) >> 10; v[56] = (x0-t3) >> 10; v[ 8] = (x1+t2) >> 10; v[48] = (x1-t2) >> 10; v[16] = (x2+t1) >> 10; v[40] = (x2-t1) >> 10; v[24] = (x3+t0) >> 10; v[32] = (x3-t0) >> 10; } } for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { // no fast case since the first 1D IDCT spread components out STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) // constants scaled things up by 1<<12, plus we had 1<<2 from first // loop, plus horizontal and vertical each scale by sqrt(8) so together // we've got an extra 1<<3, so 1<<17 total we need to remove. // so we want to round that, which means adding 0.5 * 1<<17, // aka 65536. Also, we'll end up with -128 to 127 that we want // to encode as 0..255 by adding 128, so we'll add that before the shift x0 += 65536 + (128<<17); x1 += 65536 + (128<<17); x2 += 65536 + (128<<17); x3 += 65536 + (128<<17); // tried computing the shifts into temps, or'ing the temps to see // if any were out of range, but that was slower o[0] = stbi__clamp((x0+t3) >> 17); o[7] = stbi__clamp((x0-t3) >> 17); o[1] = stbi__clamp((x1+t2) >> 17); o[6] = stbi__clamp((x1-t2) >> 17); o[2] = stbi__clamp((x2+t1) >> 17); o[5] = stbi__clamp((x2-t1) >> 17); o[3] = stbi__clamp((x3+t0) >> 17); o[4] = stbi__clamp((x3-t0) >> 17); } } #ifdef STBI_SSE2 // sse2 integer IDCT. not the fastest possible implementation but it // produces bit-identical results to the generic C version so it's // fully "transparent". static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { // This is constructed to match our regular (generic) integer IDCT exactly. __m128i row0, row1, row2, row3, row4, row5, row6, row7; __m128i tmp; // dot product constant: even elems=x, odd elems=y #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) // out(1) = c1[even]*x + c1[odd]*y #define dct_rot(out0,out1, x,y,c0,c1) \ __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) // out = in << 12 (in 16-bit, out 32-bit) #define dct_widen(out, in) \ __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) // wide add #define dct_wadd(out, a, b) \ __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ __m128i out##_h = _mm_add_epi32(a##_h, b##_h) // wide sub #define dct_wsub(out, a, b) \ __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) // butterfly a/b, add bias, then shift by "s" and pack #define dct_bfly32o(out0, out1, a,b,bias,s) \ { \ __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ dct_wadd(sum, abiased, b); \ dct_wsub(dif, abiased, b); \ out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ } // 8-bit interleave step (for transposes) #define dct_interleave8(a, b) \ tmp = a; \ a = _mm_unpacklo_epi8(a, b); \ b = _mm_unpackhi_epi8(tmp, b) // 16-bit interleave step (for transposes) #define dct_interleave16(a, b) \ tmp = a; \ a = _mm_unpacklo_epi16(a, b); \ b = _mm_unpackhi_epi16(tmp, b) #define dct_pass(bias,shift) \ { \ /* even part */ \ dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ __m128i sum04 = _mm_add_epi16(row0, row4); \ __m128i dif04 = _mm_sub_epi16(row0, row4); \ dct_widen(t0e, sum04); \ dct_widen(t1e, dif04); \ dct_wadd(x0, t0e, t3e); \ dct_wsub(x3, t0e, t3e); \ dct_wadd(x1, t1e, t2e); \ dct_wsub(x2, t1e, t2e); \ /* odd part */ \ dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ __m128i sum17 = _mm_add_epi16(row1, row7); \ __m128i sum35 = _mm_add_epi16(row3, row5); \ dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ dct_wadd(x4, y0o, y4o); \ dct_wadd(x5, y1o, y5o); \ dct_wadd(x6, y2o, y5o); \ dct_wadd(x7, y3o, y4o); \ dct_bfly32o(row0,row7, x0,x7,bias,shift); \ dct_bfly32o(row1,row6, x1,x6,bias,shift); \ dct_bfly32o(row2,row5, x2,x5,bias,shift); \ dct_bfly32o(row3,row4, x3,x4,bias,shift); \ } __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); // rounding biases in column/row passes, see stbi__idct_block for explanation. __m128i bias_0 = _mm_set1_epi32(512); __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); // load row0 = _mm_load_si128((const __m128i *) (data + 0*8)); row1 = _mm_load_si128((const __m128i *) (data + 1*8)); row2 = _mm_load_si128((const __m128i *) (data + 2*8)); row3 = _mm_load_si128((const __m128i *) (data + 3*8)); row4 = _mm_load_si128((const __m128i *) (data + 4*8)); row5 = _mm_load_si128((const __m128i *) (data + 5*8)); row6 = _mm_load_si128((const __m128i *) (data + 6*8)); row7 = _mm_load_si128((const __m128i *) (data + 7*8)); // column pass dct_pass(bias_0, 10); { // 16bit 8x8 transpose pass 1 dct_interleave16(row0, row4); dct_interleave16(row1, row5); dct_interleave16(row2, row6); dct_interleave16(row3, row7); // transpose pass 2 dct_interleave16(row0, row2); dct_interleave16(row1, row3); dct_interleave16(row4, row6); dct_interleave16(row5, row7); // transpose pass 3 dct_interleave16(row0, row1); dct_interleave16(row2, row3); dct_interleave16(row4, row5); dct_interleave16(row6, row7); } // row pass dct_pass(bias_1, 17); { // pack __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 __m128i p1 = _mm_packus_epi16(row2, row3); __m128i p2 = _mm_packus_epi16(row4, row5); __m128i p3 = _mm_packus_epi16(row6, row7); // 8bit 8x8 transpose pass 1 dct_interleave8(p0, p2); // a0e0a1e1... dct_interleave8(p1, p3); // c0g0c1g1... // transpose pass 2 dct_interleave8(p0, p1); // a0c0e0g0... dct_interleave8(p2, p3); // b0d0f0h0... // transpose pass 3 dct_interleave8(p0, p2); // a0b0c0d0... dct_interleave8(p1, p3); // a4b4c4d4... // store _mm_storel_epi64((__m128i *) out, p0); out += out_stride; _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; _mm_storel_epi64((__m128i *) out, p2); out += out_stride; _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; _mm_storel_epi64((__m128i *) out, p1); out += out_stride; _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; _mm_storel_epi64((__m128i *) out, p3); out += out_stride; _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); } #undef dct_const #undef dct_rot #undef dct_widen #undef dct_wadd #undef dct_wsub #undef dct_bfly32o #undef dct_interleave8 #undef dct_interleave16 #undef dct_pass } #endif // STBI_SSE2 #ifdef STBI_NEON // NEON integer IDCT. should produce bit-identical // results to the generic C version. static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); #define dct_long_mul(out, inq, coeff) \ int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) #define dct_long_mac(out, acc, inq, coeff) \ int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) #define dct_widen(out, inq) \ int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) // wide add #define dct_wadd(out, a, b) \ int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ int32x4_t out##_h = vaddq_s32(a##_h, b##_h) // wide sub #define dct_wsub(out, a, b) \ int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ int32x4_t out##_h = vsubq_s32(a##_h, b##_h) // butterfly a/b, then shift using "shiftop" by "s" and pack #define dct_bfly32o(out0,out1, a,b,shiftop,s) \ { \ dct_wadd(sum, a, b); \ dct_wsub(dif, a, b); \ out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ } #define dct_pass(shiftop, shift) \ { \ /* even part */ \ int16x8_t sum26 = vaddq_s16(row2, row6); \ dct_long_mul(p1e, sum26, rot0_0); \ dct_long_mac(t2e, p1e, row6, rot0_1); \ dct_long_mac(t3e, p1e, row2, rot0_2); \ int16x8_t sum04 = vaddq_s16(row0, row4); \ int16x8_t dif04 = vsubq_s16(row0, row4); \ dct_widen(t0e, sum04); \ dct_widen(t1e, dif04); \ dct_wadd(x0, t0e, t3e); \ dct_wsub(x3, t0e, t3e); \ dct_wadd(x1, t1e, t2e); \ dct_wsub(x2, t1e, t2e); \ /* odd part */ \ int16x8_t sum15 = vaddq_s16(row1, row5); \ int16x8_t sum17 = vaddq_s16(row1, row7); \ int16x8_t sum35 = vaddq_s16(row3, row5); \ int16x8_t sum37 = vaddq_s16(row3, row7); \ int16x8_t sumodd = vaddq_s16(sum17, sum35); \ dct_long_mul(p5o, sumodd, rot1_0); \ dct_long_mac(p1o, p5o, sum17, rot1_1); \ dct_long_mac(p2o, p5o, sum35, rot1_2); \ dct_long_mul(p3o, sum37, rot2_0); \ dct_long_mul(p4o, sum15, rot2_1); \ dct_wadd(sump13o, p1o, p3o); \ dct_wadd(sump24o, p2o, p4o); \ dct_wadd(sump23o, p2o, p3o); \ dct_wadd(sump14o, p1o, p4o); \ dct_long_mac(x4, sump13o, row7, rot3_0); \ dct_long_mac(x5, sump24o, row5, rot3_1); \ dct_long_mac(x6, sump23o, row3, rot3_2); \ dct_long_mac(x7, sump14o, row1, rot3_3); \ dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ } // load row0 = vld1q_s16(data + 0*8); row1 = vld1q_s16(data + 1*8); row2 = vld1q_s16(data + 2*8); row3 = vld1q_s16(data + 3*8); row4 = vld1q_s16(data + 4*8); row5 = vld1q_s16(data + 5*8); row6 = vld1q_s16(data + 6*8); row7 = vld1q_s16(data + 7*8); // add DC bias row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); // column pass dct_pass(vrshrn_n_s32, 10); // 16bit 8x8 transpose { // these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. // whether compilers actually get this is another story, sadly. #define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } #define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } #define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } // pass 1 dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 dct_trn16(row2, row3); dct_trn16(row4, row5); dct_trn16(row6, row7); // pass 2 dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 dct_trn32(row1, row3); dct_trn32(row4, row6); dct_trn32(row5, row7); // pass 3 dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 dct_trn64(row1, row5); dct_trn64(row2, row6); dct_trn64(row3, row7); #undef dct_trn16 #undef dct_trn32 #undef dct_trn64 } // row pass // vrshrn_n_s32 only supports shifts up to 16, we need // 17. so do a non-rounding shift of 16 first then follow // up with a rounding shift by 1. dct_pass(vshrn_n_s32, 16); { // pack and round uint8x8_t p0 = vqrshrun_n_s16(row0, 1); uint8x8_t p1 = vqrshrun_n_s16(row1, 1); uint8x8_t p2 = vqrshrun_n_s16(row2, 1); uint8x8_t p3 = vqrshrun_n_s16(row3, 1); uint8x8_t p4 = vqrshrun_n_s16(row4, 1); uint8x8_t p5 = vqrshrun_n_s16(row5, 1); uint8x8_t p6 = vqrshrun_n_s16(row6, 1); uint8x8_t p7 = vqrshrun_n_s16(row7, 1); // again, these can translate into one instruction, but often don't. #define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } #define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } #define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } // sadly can't use interleaved stores here since we only write // 8 bytes to each scan line! // 8x8 8-bit transpose pass 1 dct_trn8_8(p0, p1); dct_trn8_8(p2, p3); dct_trn8_8(p4, p5); dct_trn8_8(p6, p7); // pass 2 dct_trn8_16(p0, p2); dct_trn8_16(p1, p3); dct_trn8_16(p4, p6); dct_trn8_16(p5, p7); // pass 3 dct_trn8_32(p0, p4); dct_trn8_32(p1, p5); dct_trn8_32(p2, p6); dct_trn8_32(p3, p7); // store vst1_u8(out, p0); out += out_stride; vst1_u8(out, p1); out += out_stride; vst1_u8(out, p2); out += out_stride; vst1_u8(out, p3); out += out_stride; vst1_u8(out, p4); out += out_stride; vst1_u8(out, p5); out += out_stride; vst1_u8(out, p6); out += out_stride; vst1_u8(out, p7); #undef dct_trn8_8 #undef dct_trn8_16 #undef dct_trn8_32 } #undef dct_long_mul #undef dct_long_mac #undef dct_widen #undef dct_wadd #undef dct_wsub #undef dct_bfly32o #undef dct_pass } #endif // STBI_NEON #define STBI__MARKER_none 0xff // if there's a pending marker from the entropy stream, return that // otherwise, fetch from the stream and get a marker. if there's no // marker, return 0xff, which is never a valid marker value static stbi_uc stbi__get_marker(stbi__jpeg *j) { stbi_uc x; if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } x = stbi__get8(j->s); if (x != 0xff) return STBI__MARKER_none; while (x == 0xff) x = stbi__get8(j->s); // consume repeated 0xff fill bytes return x; } // in each scan, we'll have scan_n components, and the order // of the components is specified by order[] #define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) // after a restart interval, stbi__jpeg_reset the entropy decoder and // the dc prediction static void stbi__jpeg_reset(stbi__jpeg *j) { j->code_bits = 0; j->code_buffer = 0; j->nomore = 0; j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; j->marker = STBI__MARKER_none; j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; j->eob_run = 0; // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, // since we don't even allow 1<<30 pixels } static int stbi__parse_entropy_coded_data(stbi__jpeg *z) { stbi__jpeg_reset(z); if (!z->progressive) { if (z->scan_n == 1) { int i,j; STBI_SIMD_ALIGN(short, data[64]); int n = z->order[0]; // non-interleaved data, we just need to process one block at a time, // in trivial scanline order // number of blocks to do just depends on how many actual "pixels" this // component has, independent of interleaved MCU blocking and such int w = (z->img_comp[n].x+7) >> 3; int h = (z->img_comp[n].y+7) >> 3; for (j=0; j < h; ++j) { for (i=0; i < w; ++i) { int ha = z->img_comp[n].ha; if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); // every data block is an MCU, so countdown the restart interval if (--z->todo <= 0) { if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); // if it's NOT a restart, then just bail, so we get corrupt data // rather than no data if (!STBI__RESTART(z->marker)) return 1; stbi__jpeg_reset(z); } } } return 1; } else { // interleaved int i,j,k,x,y; STBI_SIMD_ALIGN(short, data[64]); for (j=0; j < z->img_mcu_y; ++j) { for (i=0; i < z->img_mcu_x; ++i) { // scan an interleaved mcu... process scan_n components in order for (k=0; k < z->scan_n; ++k) { int n = z->order[k]; // scan out an mcu's worth of this component; that's just determined // by the basic H and V specified for the component for (y=0; y < z->img_comp[n].v; ++y) { for (x=0; x < z->img_comp[n].h; ++x) { int x2 = (i*z->img_comp[n].h + x)*8; int y2 = (j*z->img_comp[n].v + y)*8; int ha = z->img_comp[n].ha; if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); } } } // after all interleaved components, that's an interleaved MCU, // so now count down the restart interval if (--z->todo <= 0) { if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); if (!STBI__RESTART(z->marker)) return 1; stbi__jpeg_reset(z); } } } return 1; } } else { if (z->scan_n == 1) { int i,j; int n = z->order[0]; // non-interleaved data, we just need to process one block at a time, // in trivial scanline order // number of blocks to do just depends on how many actual "pixels" this // component has, independent of interleaved MCU blocking and such int w = (z->img_comp[n].x+7) >> 3; int h = (z->img_comp[n].y+7) >> 3; for (j=0; j < h; ++j) { for (i=0; i < w; ++i) { short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); if (z->spec_start == 0) { if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) return 0; } else { int ha = z->img_comp[n].ha; if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) return 0; } // every data block is an MCU, so countdown the restart interval if (--z->todo <= 0) { if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); if (!STBI__RESTART(z->marker)) return 1; stbi__jpeg_reset(z); } } } return 1; } else { // interleaved int i,j,k,x,y; for (j=0; j < z->img_mcu_y; ++j) { for (i=0; i < z->img_mcu_x; ++i) { // scan an interleaved mcu... process scan_n components in order for (k=0; k < z->scan_n; ++k) { int n = z->order[k]; // scan out an mcu's worth of this component; that's just determined // by the basic H and V specified for the component for (y=0; y < z->img_comp[n].v; ++y) { for (x=0; x < z->img_comp[n].h; ++x) { int x2 = (i*z->img_comp[n].h + x); int y2 = (j*z->img_comp[n].v + y); short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) return 0; } } } // after all interleaved components, that's an interleaved MCU, // so now count down the restart interval if (--z->todo <= 0) { if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); if (!STBI__RESTART(z->marker)) return 1; stbi__jpeg_reset(z); } } } return 1; } } } static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) { int i; for (i=0; i < 64; ++i) data[i] *= dequant[i]; } static void stbi__jpeg_finish(stbi__jpeg *z) { if (z->progressive) { // dequantize and idct the data int i,j,n; for (n=0; n < z->s->img_n; ++n) { int w = (z->img_comp[n].x+7) >> 3; int h = (z->img_comp[n].y+7) >> 3; for (j=0; j < h; ++j) { for (i=0; i < w; ++i) { short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); } } } } } static int stbi__process_marker(stbi__jpeg *z, int m) { int L; switch (m) { case STBI__MARKER_none: // no marker found return stbi__err("expected marker","Corrupt JPEG"); case 0xDD: // DRI - specify restart interval if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); z->restart_interval = stbi__get16be(z->s); return 1; case 0xDB: // DQT - define quantization table L = stbi__get16be(z->s)-2; while (L > 0) { int q = stbi__get8(z->s); int p = q >> 4, sixteen = (p != 0); int t = q & 15,i; if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); for (i=0; i < 64; ++i) z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); L -= (sixteen ? 129 : 65); } return L==0; case 0xC4: // DHT - define huffman table L = stbi__get16be(z->s)-2; while (L > 0) { stbi_uc *v; int sizes[16],i,n=0; int q = stbi__get8(z->s); int tc = q >> 4; int th = q & 15; if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); for (i=0; i < 16; ++i) { sizes[i] = stbi__get8(z->s); n += sizes[i]; } L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; v = z->huff_dc[th].values; } else { if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; v = z->huff_ac[th].values; } for (i=0; i < n; ++i) v[i] = stbi__get8(z->s); if (tc != 0) stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); L -= n; } return L==0; } // check for comment block or APP blocks if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { L = stbi__get16be(z->s); if (L < 2) { if (m == 0xFE) return stbi__err("bad COM len","Corrupt JPEG"); else return stbi__err("bad APP len","Corrupt JPEG"); } L -= 2; if (m == 0xE0 && L >= 5) { // JFIF APP0 segment static const unsigned char tag[5] = {'J','F','I','F','\0'}; int ok = 1; int i; for (i=0; i < 5; ++i) if (stbi__get8(z->s) != tag[i]) ok = 0; L -= 5; if (ok) z->jfif = 1; } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; int ok = 1; int i; for (i=0; i < 6; ++i) if (stbi__get8(z->s) != tag[i]) ok = 0; L -= 6; if (ok) { stbi__get8(z->s); // version stbi__get16be(z->s); // flags0 stbi__get16be(z->s); // flags1 z->app14_color_transform = stbi__get8(z->s); // color transform L -= 6; } } stbi__skip(z->s, L); return 1; } return stbi__err("unknown marker","Corrupt JPEG"); } // after we see SOS static int stbi__process_scan_header(stbi__jpeg *z) { int i; int Ls = stbi__get16be(z->s); z->scan_n = stbi__get8(z->s); if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); for (i=0; i < z->scan_n; ++i) { int id = stbi__get8(z->s), which; int q = stbi__get8(z->s); for (which = 0; which < z->s->img_n; ++which) if (z->img_comp[which].id == id) break; if (which == z->s->img_n) return 0; // no match z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); z->order[i] = which; } { int aa; z->spec_start = stbi__get8(z->s); z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 aa = stbi__get8(z->s); z->succ_high = (aa >> 4); z->succ_low = (aa & 15); if (z->progressive) { if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) return stbi__err("bad SOS", "Corrupt JPEG"); } else { if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); z->spec_end = 63; } } return 1; } static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) { int i; for (i=0; i < ncomp; ++i) { if (z->img_comp[i].raw_data) { STBI_FREE(z->img_comp[i].raw_data); z->img_comp[i].raw_data = NULL; z->img_comp[i].data = NULL; } if (z->img_comp[i].raw_coeff) { STBI_FREE(z->img_comp[i].raw_coeff); z->img_comp[i].raw_coeff = 0; z->img_comp[i].coeff = 0; } if (z->img_comp[i].linebuf) { STBI_FREE(z->img_comp[i].linebuf); z->img_comp[i].linebuf = NULL; } } return why; } static int stbi__process_frame_header(stbi__jpeg *z, int scan) { stbi__context *s = z->s; int Lf,p,i,q, h_max=1,v_max=1,c; Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); c = stbi__get8(s); if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); s->img_n = c; for (i=0; i < c; ++i) { z->img_comp[i].data = NULL; z->img_comp[i].linebuf = NULL; } if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); z->rgb = 0; for (i=0; i < s->img_n; ++i) { static const unsigned char rgb[3] = { 'R', 'G', 'B' }; z->img_comp[i].id = stbi__get8(s); if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) ++z->rgb; q = stbi__get8(s); z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); } if (scan != STBI__SCAN_load) return 1; if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); for (i=0; i < s->img_n; ++i) { if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; } // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios // and I've never seen a non-corrupted JPEG file actually use them for (i=0; i < s->img_n; ++i) { if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); } // compute interleaved mcu info z->img_h_max = h_max; z->img_v_max = v_max; z->img_mcu_w = h_max * 8; z->img_mcu_h = v_max * 8; // these sizes can't be more than 17 bits z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; for (i=0; i < s->img_n; ++i) { // number of effective pixels (e.g. for non-interleaved MCU) z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; // to simplify generation, we'll allocate enough memory to decode // the bogus oversized data from using interleaved MCUs and their // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't // discard the extra data until colorspace conversion // // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) // so these muls can't overflow with 32-bit ints (which we require) z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; z->img_comp[i].coeff = 0; z->img_comp[i].raw_coeff = 0; z->img_comp[i].linebuf = NULL; z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); if (z->img_comp[i].raw_data == NULL) return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); // align blocks for idct using mmx/sse z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); if (z->progressive) { // w2, h2 are multiples of 8 (see above) z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); if (z->img_comp[i].raw_coeff == NULL) return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); } } return 1; } // use comparisons since in some cases we handle more than one case (e.g. SOF) #define stbi__DNL(x) ((x) == 0xdc) #define stbi__SOI(x) ((x) == 0xd8) #define stbi__EOI(x) ((x) == 0xd9) #define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) #define stbi__SOS(x) ((x) == 0xda) #define stbi__SOF_progressive(x) ((x) == 0xc2) static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { int m; z->jfif = 0; z->app14_color_transform = -1; // valid values are 0,1,2 z->marker = STBI__MARKER_none; // initialize cached marker to empty m = stbi__get_marker(z); if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); if (scan == STBI__SCAN_type) return 1; m = stbi__get_marker(z); while (!stbi__SOF(m)) { if (!stbi__process_marker(z,m)) return 0; m = stbi__get_marker(z); while (m == STBI__MARKER_none) { // some files have extra padding after their blocks, so ok, we'll scan if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); m = stbi__get_marker(z); } } z->progressive = stbi__SOF_progressive(m); if (!stbi__process_frame_header(z, scan)) return 0; return 1; } // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { int m; for (m = 0; m < 4; m++) { j->img_comp[m].raw_data = NULL; j->img_comp[m].raw_coeff = NULL; } j->restart_interval = 0; if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; m = stbi__get_marker(j); while (!stbi__EOI(m)) { if (stbi__SOS(m)) { if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { // handle 0s at the end of image data from IP Kamera 9060 while (!stbi__at_eof(j->s)) { int x = stbi__get8(j->s); if (x == 255) { j->marker = stbi__get8(j->s); break; } } // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); } else { if (!stbi__process_marker(j, m)) return 0; } m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); return 1; } // static jfif-centered resampling (across block boundaries) typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, int w, int hs); #define stbi__div4(x) ((stbi_uc) ((x) >> 2)) static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { STBI_NOTUSED(out); STBI_NOTUSED(in_far); STBI_NOTUSED(w); STBI_NOTUSED(hs); return in_near; } static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { // need to generate two samples vertically for every one in input int i; STBI_NOTUSED(hs); for (i=0; i < w; ++i) out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); return out; } static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { // need to generate two samples horizontally for every one in input int i; stbi_uc *input = in_near; if (w == 1) { // if only one sample, can't do any interpolation out[0] = out[1] = input[0]; return out; } out[0] = input[0]; out[1] = stbi__div4(input[0]*3 + input[1] + 2); for (i=1; i < w-1; ++i) { int n = 3*input[i]+2; out[i*2+0] = stbi__div4(n+input[i-1]); out[i*2+1] = stbi__div4(n+input[i+1]); } out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); out[i*2+1] = input[w-1]; STBI_NOTUSED(in_far); STBI_NOTUSED(hs); return out; } #define stbi__div16(x) ((stbi_uc) ((x) >> 4)) static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { // need to generate 2x2 samples for every one in input int i,t0,t1; if (w == 1) { out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); return out; } t1 = 3*in_near[0] + in_far[0]; out[0] = stbi__div4(t1+2); for (i=1; i < w; ++i) { t0 = t1; t1 = 3*in_near[i]+in_far[i]; out[i*2-1] = stbi__div16(3*t0 + t1 + 8); out[i*2 ] = stbi__div16(3*t1 + t0 + 8); } out[w*2-1] = stbi__div4(t1+2); STBI_NOTUSED(hs); return out; } #if defined(STBI_SSE2) || defined(STBI_NEON) static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { // need to generate 2x2 samples for every one in input int i=0,t0,t1; if (w == 1) { out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); return out; } t1 = 3*in_near[0] + in_far[0]; // process groups of 8 pixels for as long as we can. // note we can't handle the last pixel in a row in this loop // because we need to handle the filter boundary conditions. for (; i < ((w-1) & ~7); i += 8) { #if defined(STBI_SSE2) // load and perform the vertical filtering pass // this uses 3*x + y = 4*x + (y - x) __m128i zero = _mm_setzero_si128(); __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); __m128i farw = _mm_unpacklo_epi8(farb, zero); __m128i nearw = _mm_unpacklo_epi8(nearb, zero); __m128i diff = _mm_sub_epi16(farw, nearw); __m128i nears = _mm_slli_epi16(nearw, 2); __m128i curr = _mm_add_epi16(nears, diff); // current row // horizontal filter works the same based on shifted vers of current // row. "prev" is current row shifted right by 1 pixel; we need to // insert the previous pixel value (from t1). // "next" is current row shifted left by 1 pixel, with first pixel // of next block of 8 pixels added in. __m128i prv0 = _mm_slli_si128(curr, 2); __m128i nxt0 = _mm_srli_si128(curr, 2); __m128i prev = _mm_insert_epi16(prv0, t1, 0); __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); // horizontal filter, polyphase implementation since it's convenient: // even pixels = 3*cur + prev = cur*4 + (prev - cur) // odd pixels = 3*cur + next = cur*4 + (next - cur) // note the shared term. __m128i bias = _mm_set1_epi16(8); __m128i curs = _mm_slli_epi16(curr, 2); __m128i prvd = _mm_sub_epi16(prev, curr); __m128i nxtd = _mm_sub_epi16(next, curr); __m128i curb = _mm_add_epi16(curs, bias); __m128i even = _mm_add_epi16(prvd, curb); __m128i odd = _mm_add_epi16(nxtd, curb); // interleave even and odd pixels, then undo scaling. __m128i int0 = _mm_unpacklo_epi16(even, odd); __m128i int1 = _mm_unpackhi_epi16(even, odd); __m128i de0 = _mm_srli_epi16(int0, 4); __m128i de1 = _mm_srli_epi16(int1, 4); // pack and write output __m128i outv = _mm_packus_epi16(de0, de1); _mm_storeu_si128((__m128i *) (out + i*2), outv); #elif defined(STBI_NEON) // load and perform the vertical filtering pass // this uses 3*x + y = 4*x + (y - x) uint8x8_t farb = vld1_u8(in_far + i); uint8x8_t nearb = vld1_u8(in_near + i); int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); int16x8_t curr = vaddq_s16(nears, diff); // current row // horizontal filter works the same based on shifted vers of current // row. "prev" is current row shifted right by 1 pixel; we need to // insert the previous pixel value (from t1). // "next" is current row shifted left by 1 pixel, with first pixel // of next block of 8 pixels added in. int16x8_t prv0 = vextq_s16(curr, curr, 7); int16x8_t nxt0 = vextq_s16(curr, curr, 1); int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); // horizontal filter, polyphase implementation since it's convenient: // even pixels = 3*cur + prev = cur*4 + (prev - cur) // odd pixels = 3*cur + next = cur*4 + (next - cur) // note the shared term. int16x8_t curs = vshlq_n_s16(curr, 2); int16x8_t prvd = vsubq_s16(prev, curr); int16x8_t nxtd = vsubq_s16(next, curr); int16x8_t even = vaddq_s16(curs, prvd); int16x8_t odd = vaddq_s16(curs, nxtd); // undo scaling and round, then store with even/odd phases interleaved uint8x8x2_t o; o.val[0] = vqrshrun_n_s16(even, 4); o.val[1] = vqrshrun_n_s16(odd, 4); vst2_u8(out + i*2, o); #endif // "previous" value for next iter t1 = 3*in_near[i+7] + in_far[i+7]; } t0 = t1; t1 = 3*in_near[i] + in_far[i]; out[i*2] = stbi__div16(3*t1 + t0 + 8); for (++i; i < w; ++i) { t0 = t1; t1 = 3*in_near[i]+in_far[i]; out[i*2-1] = stbi__div16(3*t0 + t1 + 8); out[i*2 ] = stbi__div16(3*t1 + t0 + 8); } out[w*2-1] = stbi__div4(t1+2); STBI_NOTUSED(hs); return out; } #endif static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { // resample with nearest-neighbor int i,j; STBI_NOTUSED(in_far); for (i=0; i < w; ++i) for (j=0; j < hs; ++j) out[i*hs+j] = in_near[i]; return out; } // this is a reduced-precision calculation of YCbCr-to-RGB introduced // to make sure the code produces the same results in both SIMD and scalar #define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) { int i; for (i=0; i < count; ++i) { int y_fixed = (y[i] << 20) + (1<<19); // rounding int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; r = y_fixed + cr* stbi__float2fixed(1.40200f); g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); b = y_fixed + cb* stbi__float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } out[0] = (stbi_uc)r; out[1] = (stbi_uc)g; out[2] = (stbi_uc)b; out[3] = 255; out += step; } } #if defined(STBI_SSE2) || defined(STBI_NEON) static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) { int i = 0; #ifdef STBI_SSE2 // step == 3 is pretty ugly on the final interleave, and i'm not convinced // it's useful in practice (you wouldn't use it for textures, for example). // so just accelerate step == 4 case. if (step == 4) { // this is a fairly straightforward implementation and not super-optimized. __m128i signflip = _mm_set1_epi8(-0x80); __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); __m128i xw = _mm_set1_epi16(255); // alpha channel for (; i+7 < count; i += 8) { // load __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 // unpack to short (and left-shift cr, cb by 8) __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); // color transform __m128i yws = _mm_srli_epi16(yw, 4); __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); __m128i rws = _mm_add_epi16(cr0, yws); __m128i gwt = _mm_add_epi16(cb0, yws); __m128i bws = _mm_add_epi16(yws, cb1); __m128i gws = _mm_add_epi16(gwt, cr1); // descale __m128i rw = _mm_srai_epi16(rws, 4); __m128i bw = _mm_srai_epi16(bws, 4); __m128i gw = _mm_srai_epi16(gws, 4); // back to byte, set up for transpose __m128i brb = _mm_packus_epi16(rw, bw); __m128i gxb = _mm_packus_epi16(gw, xw); // transpose to interleave channels __m128i t0 = _mm_unpacklo_epi8(brb, gxb); __m128i t1 = _mm_unpackhi_epi8(brb, gxb); __m128i o0 = _mm_unpacklo_epi16(t0, t1); __m128i o1 = _mm_unpackhi_epi16(t0, t1); // store _mm_storeu_si128((__m128i *) (out + 0), o0); _mm_storeu_si128((__m128i *) (out + 16), o1); out += 32; } } #endif #ifdef STBI_NEON // in this version, step=3 support would be easy to add. but is there demand? if (step == 4) { // this is a fairly straightforward implementation and not super-optimized. uint8x8_t signflip = vdup_n_u8(0x80); int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); for (; i+7 < count; i += 8) { // load uint8x8_t y_bytes = vld1_u8(y + i); uint8x8_t cr_bytes = vld1_u8(pcr + i); uint8x8_t cb_bytes = vld1_u8(pcb + i); int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); // expand to s16 int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); int16x8_t crw = vshll_n_s8(cr_biased, 7); int16x8_t cbw = vshll_n_s8(cb_biased, 7); // color transform int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); int16x8_t rws = vaddq_s16(yws, cr0); int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); int16x8_t bws = vaddq_s16(yws, cb1); // undo scaling, round, convert to byte uint8x8x4_t o; o.val[0] = vqrshrun_n_s16(rws, 4); o.val[1] = vqrshrun_n_s16(gws, 4); o.val[2] = vqrshrun_n_s16(bws, 4); o.val[3] = vdup_n_u8(255); // store, interleaving r/g/b/a vst4_u8(out, o); out += 8*4; } } #endif for (; i < count; ++i) { int y_fixed = (y[i] << 20) + (1<<19); // rounding int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; r = y_fixed + cr* stbi__float2fixed(1.40200f); g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); b = y_fixed + cb* stbi__float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } out[0] = (stbi_uc)r; out[1] = (stbi_uc)g; out[2] = (stbi_uc)b; out[3] = 255; out += step; } } #endif // set up the kernels static void stbi__setup_jpeg(stbi__jpeg *j) { j->idct_block_kernel = stbi__idct_block; j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; #ifdef STBI_SSE2 if (stbi__sse2_available()) { j->idct_block_kernel = stbi__idct_simd; j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; } #endif #ifdef STBI_NEON j->idct_block_kernel = stbi__idct_simd; j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; #endif } // clean up the temporary component buffers static void stbi__cleanup_jpeg(stbi__jpeg *j) { stbi__free_jpeg_components(j, j->s->img_n, 0); } typedef struct { resample_row_func resample; stbi_uc *line0,*line1; int hs,vs; // expansion factor in each axis int w_lores; // horizontal pixels pre-expansion int ystep; // how far through vertical expansion we are int ypos; // which pre-expansion row we're on } stbi__resample; // fast 0..255 * 0..255 => 0..255 rounded multiplication static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) { unsigned int t = x*y + 128; return (stbi_uc) ((t + (t >>8)) >> 8); } static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) { int n, decode_n, is_rgb; z->s->img_n = 0; // make stbi__cleanup_jpeg safe // validate req_comp if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); // load a jpeg image from whichever source, but leave in YCbCr format if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } // determine actual number of components to generate n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); if (z->s->img_n == 3 && n < 3 && !is_rgb) decode_n = 1; else decode_n = z->s->img_n; // nothing to do if no components requested; check this now to avoid // accessing uninitialized coutput[0] later if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } // resample and color-convert { int k; unsigned int i,j; stbi_uc *output; stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; stbi__resample res_comp[4]; for (k=0; k < decode_n; ++k) { stbi__resample *r = &res_comp[k]; // allocate line buffer big enough for upsampling off the edges // with upsample factor of 4 z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } r->hs = z->img_h_max / z->img_comp[k].h; r->vs = z->img_v_max / z->img_comp[k].v; r->ystep = r->vs >> 1; r->w_lores = (z->s->img_x + r->hs-1) / r->hs; r->ypos = 0; r->line0 = r->line1 = z->img_comp[k].data; if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; else r->resample = stbi__resample_row_generic; } // can't error after this so, this is safe output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } // now go ahead and resample for (j=0; j < z->s->img_y; ++j) { stbi_uc *out = output + n * z->s->img_x * j; for (k=0; k < decode_n; ++k) { stbi__resample *r = &res_comp[k]; int y_bot = r->ystep >= (r->vs >> 1); coutput[k] = r->resample(z->img_comp[k].linebuf, y_bot ? r->line1 : r->line0, y_bot ? r->line0 : r->line1, r->w_lores, r->hs); if (++r->ystep >= r->vs) { r->ystep = 0; r->line0 = r->line1; if (++r->ypos < z->img_comp[k].y) r->line1 += z->img_comp[k].w2; } } if (n >= 3) { stbi_uc *y = coutput[0]; if (z->s->img_n == 3) { if (is_rgb) { for (i=0; i < z->s->img_x; ++i) { out[0] = y[i]; out[1] = coutput[1][i]; out[2] = coutput[2][i]; out[3] = 255; out += n; } } else { z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); } } else if (z->s->img_n == 4) { if (z->app14_color_transform == 0) { // CMYK for (i=0; i < z->s->img_x; ++i) { stbi_uc m = coutput[3][i]; out[0] = stbi__blinn_8x8(coutput[0][i], m); out[1] = stbi__blinn_8x8(coutput[1][i], m); out[2] = stbi__blinn_8x8(coutput[2][i], m); out[3] = 255; out += n; } } else if (z->app14_color_transform == 2) { // YCCK z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); for (i=0; i < z->s->img_x; ++i) { stbi_uc m = coutput[3][i]; out[0] = stbi__blinn_8x8(255 - out[0], m); out[1] = stbi__blinn_8x8(255 - out[1], m); out[2] = stbi__blinn_8x8(255 - out[2], m); out += n; } } else { // YCbCr + alpha? Ignore the fourth channel for now z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); } } else for (i=0; i < z->s->img_x; ++i) { out[0] = out[1] = out[2] = y[i]; out[3] = 255; // not used if n==3 out += n; } } else { if (is_rgb) { if (n == 1) for (i=0; i < z->s->img_x; ++i) *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); else { for (i=0; i < z->s->img_x; ++i, out += 2) { out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); out[1] = 255; } } } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { for (i=0; i < z->s->img_x; ++i) { stbi_uc m = coutput[3][i]; stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); out[0] = stbi__compute_y(r, g, b); out[1] = 255; out += n; } } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { for (i=0; i < z->s->img_x; ++i) { out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); out[1] = 255; out += n; } } else { stbi_uc *y = coutput[0]; if (n == 1) for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; else for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } } } } stbi__cleanup_jpeg(z); *out_x = z->s->img_x; *out_y = z->s->img_y; if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output return output; } } static void * stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__errpuc("outofmem", "Out of memory"); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); result = load_jpeg_image(j, x,y,comp,req_comp); STBI_FREE(j); return result; } static int stbi__jpeg_test(stbi__context *s) { int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__err("outofmem", "Out of memory"); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); stbi__rewind(s); STBI_FREE(j); return r; } static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) { if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { stbi__rewind( j->s ); return 0; } if (x) *x = j->s->img_x; if (y) *y = j->s->img_y; if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; return 1; } static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); if (!j) return stbi__err("outofmem", "Out of memory"); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); return result; } #endif // public domain zlib decode v0.2 Sean Barrett 2006-11-18 // simple implementation // - all input must be provided in an upfront buffer // - all output is written to a single output buffer (can malloc/realloc) // performance // - fast huffman #ifndef STBI_NO_ZLIB // fast-way is faster to check than jpeg huffman, but slow way is slower #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) #define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) typedef struct { stbi__uint16 fast[1 << STBI__ZFAST_BITS]; stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; stbi_uc size[STBI__ZNSYMS]; stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) { n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); return n; } stbi_inline static int stbi__bit_reverse(int v, int bits) { STBI_ASSERT(bits <= 16); // to bit reverse n bits, reverse 16 and shift // e.g. 11 bits, bit reverse and shift away 5 return stbi__bitreverse16(v) >> (16-bits); } static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) { int i,k=0; int code, next_code[16], sizes[17]; // DEFLATE spec for generating codes memset(sizes, 0, sizeof(sizes)); memset(z->fast, 0, sizeof(z->fast)); for (i=0; i < num; ++i) ++sizes[sizelist[i]]; sizes[0] = 0; for (i=1; i < 16; ++i) if (sizes[i] > (1 << i)) return stbi__err("bad sizes", "Corrupt PNG"); code = 0; for (i=1; i < 16; ++i) { next_code[i] = code; z->firstcode[i] = (stbi__uint16) code; z->firstsymbol[i] = (stbi__uint16) k; code = (code + sizes[i]); if (sizes[i]) if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); z->maxcode[i] = code << (16-i); // preshift for inner loop code <<= 1; k += sizes[i]; } z->maxcode[16] = 0x10000; // sentinel for (i=0; i < num; ++i) { int s = sizelist[i]; if (s) { int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); z->size [c] = (stbi_uc ) s; z->value[c] = (stbi__uint16) i; if (s <= STBI__ZFAST_BITS) { int j = stbi__bit_reverse(next_code[s],s); while (j < (1 << STBI__ZFAST_BITS)) { z->fast[j] = fastv; j += (1 << s); } } ++next_code[s]; } } return 1; } // zlib-from-memory implementation for PNG reading // because PNG allows splitting the zlib stream arbitrarily, // and it's annoying structurally to have PNG call ZLIB call PNG, // we require PNG read all the IDATs and combine them into a single // memory buffer typedef struct { stbi_uc *zbuffer, *zbuffer_end; int num_bits; stbi__uint32 code_buffer; char *zout; char *zout_start; char *zout_end; int z_expandable; stbi__zhuffman z_length, z_distance; } stbi__zbuf; stbi_inline static int stbi__zeof(stbi__zbuf *z) { return (z->zbuffer >= z->zbuffer_end); } stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { return stbi__zeof(z) ? 0 : *z->zbuffer++; } static void stbi__fill_bits(stbi__zbuf *z) { do { if (z->code_buffer >= (1U << z->num_bits)) { z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ return; } z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); } stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) { unsigned int k; if (z->num_bits < n) stbi__fill_bits(z); k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; z->num_bits -= n; return k; } static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) { int b,s,k; // not resolved by fast table, so compute it the slow way // use jpeg approach, which requires MSbits at top k = stbi__bit_reverse(a->code_buffer, 16); for (s=STBI__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; return z->value[b]; } stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { int b,s; if (a->num_bits < 16) { if (stbi__zeof(a)) { return -1; /* report error for unexpected end of data. */ } stbi__fill_bits(a); } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { s = b >> 9; a->code_buffer >>= s; a->num_bits -= s; return b & 511; } return stbi__zhuffman_decode_slowpath(a, z); } static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; unsigned int cur, limit, old_limit; z->zout = zout; if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); cur = (unsigned int) (z->zout - z->zout_start); limit = old_limit = (unsigned) (z->zout_end - z->zout_start); if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); while (cur + n > limit) { if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); limit *= 2; } q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); STBI_NOTUSED(old_limit); if (q == NULL) return stbi__err("outofmem", "Out of memory"); z->zout_start = q; z->zout = q + cur; z->zout_end = q + limit; return 1; } static const int stbi__zlength_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; static const int stbi__zlength_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; static const int stbi__zdist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static int stbi__parse_huffman_block(stbi__zbuf *a) { char *zout = a->zout; for(;;) { int z = stbi__zhuffman_decode(a, &a->z_length); if (z < 256) { if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes if (zout >= a->zout_end) { if (!stbi__zexpand(a, zout, 1)) return 0; zout = a->zout; } *zout++ = (char) z; } else { stbi_uc *p; int len,dist; if (z == 256) { a->zout = zout; return 1; } z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); if (zout + len > a->zout_end) { if (!stbi__zexpand(a, zout, len)) return 0; zout = a->zout; } p = (stbi_uc *) (zout - dist); if (dist == 1) { // run of one byte; common in images. stbi_uc v = *p; if (len) { do *zout++ = v; while (--len); } } else { if (len) { do *zout++ = *p++; while (--len); } } } } } static int stbi__compute_huffman_codes(stbi__zbuf *a) { static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; stbi__zhuffman z_codelength; stbi_uc lencodes[286+32+137];//padding for maximum single op stbi_uc codelength_sizes[19]; int i,n; int hlit = stbi__zreceive(a,5) + 257; int hdist = stbi__zreceive(a,5) + 1; int hclen = stbi__zreceive(a,4) + 4; int ntot = hlit + hdist; memset(codelength_sizes, 0, sizeof(codelength_sizes)); for (i=0; i < hclen; ++i) { int s = stbi__zreceive(a,3); codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; } if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; n = 0; while (n < ntot) { int c = stbi__zhuffman_decode(a, &z_codelength); if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); if (c < 16) lencodes[n++] = (stbi_uc) c; else { stbi_uc fill = 0; if (c == 16) { c = stbi__zreceive(a,2)+3; if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); fill = lencodes[n-1]; } else if (c == 17) { c = stbi__zreceive(a,3)+3; } else if (c == 18) { c = stbi__zreceive(a,7)+11; } else { return stbi__err("bad codelengths", "Corrupt PNG"); } if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); memset(lencodes+n, fill, c); n += c; } } if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; return 1; } static int stbi__parse_uncompressed_block(stbi__zbuf *a) { stbi_uc header[4]; int len,nlen,k; if (a->num_bits & 7) stbi__zreceive(a, a->num_bits & 7); // discard // drain the bit-packed data into header k = 0; while (a->num_bits > 0) { header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check a->code_buffer >>= 8; a->num_bits -= 8; } if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); // now fill header the normal way while (k < 4) header[k++] = stbi__zget8(a); len = header[1] * 256 + header[0]; nlen = header[3] * 256 + header[2]; if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); if (a->zout + len > a->zout_end) if (!stbi__zexpand(a, a->zout, len)) return 0; memcpy(a->zout, a->zbuffer, len); a->zbuffer += len; a->zout += len; return 1; } static int stbi__parse_zlib_header(stbi__zbuf *a) { int cmf = stbi__zget8(a); int cm = cmf & 15; /* int cinfo = cmf >> 4; */ int flg = stbi__zget8(a); if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png // window = 1 << (8 + cinfo)... but who cares, we fully buffer output return 1; } static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 }; static const stbi_uc stbi__zdefault_distance[32] = { 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 }; /* Init algorithm: { int i; // use <= to match clearly with spec for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; } */ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) { int final, type; if (parse_header) if (!stbi__parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; do { final = stbi__zreceive(a,1); type = stbi__zreceive(a,2); if (type == 0) { if (!stbi__parse_uncompressed_block(a)) return 0; } else if (type == 3) { return 0; } else { if (type == 1) { // use fixed code lengths if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; } if (!stbi__parse_huffman_block(a)) return 0; } } while (!final); return 1; } static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) { a->zout_start = obuf; a->zout = obuf; a->zout_end = obuf + olen; a->z_expandable = exp; return stbi__parse_zlib(a, parse_header); } STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) { stbi__zbuf a; char *p = (char *) stbi__malloc(initial_size); if (p == NULL) return NULL; a.zbuffer = (stbi_uc *) buffer; a.zbuffer_end = (stbi_uc *) buffer + len; if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { STBI_FREE(a.zout_start); return NULL; } } STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) { return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); } STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) { stbi__zbuf a; char *p = (char *) stbi__malloc(initial_size); if (p == NULL) return NULL; a.zbuffer = (stbi_uc *) buffer; a.zbuffer_end = (stbi_uc *) buffer + len; if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { STBI_FREE(a.zout_start); return NULL; } } STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) { stbi__zbuf a; a.zbuffer = (stbi_uc *) ibuffer; a.zbuffer_end = (stbi_uc *) ibuffer + ilen; if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) return (int) (a.zout - a.zout_start); else return -1; } STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) { stbi__zbuf a; char *p = (char *) stbi__malloc(16384); if (p == NULL) return NULL; a.zbuffer = (stbi_uc *) buffer; a.zbuffer_end = (stbi_uc *) buffer+len; if (stbi__do_zlib(&a, p, 16384, 1, 0)) { if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { STBI_FREE(a.zout_start); return NULL; } } STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) { stbi__zbuf a; a.zbuffer = (stbi_uc *) ibuffer; a.zbuffer_end = (stbi_uc *) ibuffer + ilen; if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) return (int) (a.zout - a.zout_start); else return -1; } #endif // public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 // simple implementation // - only 8-bit samples // - no CRC checking // - allocates lots of intermediate memory // - avoids problem of streaming data between subsystems // - avoids explicit window management // performance // - uses stb_zlib, a PD zlib implementation with fast huffman decoding #ifndef STBI_NO_PNG typedef struct { stbi__uint32 length; stbi__uint32 type; } stbi__pngchunk; static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) { stbi__pngchunk c; c.length = stbi__get32be(s); c.type = stbi__get32be(s); return c; } static int stbi__check_png_header(stbi__context *s) { static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; int i; for (i=0; i < 8; ++i) if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); return 1; } typedef struct { stbi__context *s; stbi_uc *idata, *expanded, *out; int depth; } stbi__png; enum { STBI__F_none=0, STBI__F_sub=1, STBI__F_up=2, STBI__F_avg=3, STBI__F_paeth=4, // synthetic filters used for first scanline to avoid needing a dummy row of 0s STBI__F_avg_first, STBI__F_paeth_first }; static stbi_uc first_row_filter[5] = { STBI__F_none, STBI__F_sub, STBI__F_none, STBI__F_avg_first, STBI__F_paeth_first }; static int stbi__paeth(int a, int b, int c) { int p = a + b - c; int pa = abs(p-a); int pb = abs(p-b); int pc = abs(p-c); if (pa <= pb && pa <= pc) return a; if (pb <= pc) return b; return c; } static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; // create the png data from post-deflated data static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) { int bytes = (depth == 16? 2 : 1); stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n*bytes; stbi__uint32 img_len, img_width_bytes; int k; int img_n = s->img_n; // copy it into a local for later int output_bytes = out_n*bytes; int filter_bytes = img_n*bytes; int width = x; STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); img_len = (img_width_bytes + 1) * y; // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), // so just check for raw_len < img_len always. if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); for (j=0; j < y; ++j) { stbi_uc *cur = a->out + stride*j; stbi_uc *prior; int filter = *raw++; if (filter > 4) return stbi__err("invalid filter","Corrupt PNG"); if (depth < 8) { if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place filter_bytes = 1; width = img_width_bytes; } prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; // handle first byte explicitly for (k=0; k < filter_bytes; ++k) { switch (filter) { case STBI__F_none : cur[k] = raw[k]; break; case STBI__F_sub : cur[k] = raw[k]; break; case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; case STBI__F_avg_first : cur[k] = raw[k]; break; case STBI__F_paeth_first: cur[k] = raw[k]; break; } } if (depth == 8) { if (img_n != out_n) cur[img_n] = 255; // first pixel raw += img_n; cur += out_n; prior += out_n; } else if (depth == 16) { if (img_n != out_n) { cur[filter_bytes] = 255; // first pixel top byte cur[filter_bytes+1] = 255; // first pixel bottom byte } raw += filter_bytes; cur += output_bytes; prior += output_bytes; } else { raw += 1; cur += 1; prior += 1; } // this is a little gross, so that we don't switch per-pixel or per-component if (depth < 8 || img_n == out_n) { int nk = (width - 1)*filter_bytes; #define STBI__CASE(f) \ case f: \ for (k=0; k < nk; ++k) switch (filter) { // "none" filter turns into a memcpy here; make that explicit. case STBI__F_none: memcpy(cur, raw, nk); break; STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; } #undef STBI__CASE raw += nk; } else { STBI_ASSERT(img_n+1 == out_n); #define STBI__CASE(f) \ case f: \ for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ for (k=0; k < filter_bytes; ++k) switch (filter) { STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; } #undef STBI__CASE // the loop above sets the high byte of the pixels' alpha, but for // 16 bit png files we also need the low byte set. we'll do that here. if (depth == 16) { cur = a->out + stride*j; // start at the beginning of the row again for (i=0; i < x; ++i,cur+=output_bytes) { cur[filter_bytes+1] = 255; } } } } // we make a separate pass to expand bits to pixels; for performance, // this could run two scanlines behind the above code, so it won't // intefere with filtering but will still be in the cache. if (depth < 8) { for (j=0; j < y; ++j) { stbi_uc *cur = a->out + stride*j; stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range // note that the final byte might overshoot and write more data than desired. // we can allocate enough data that this never writes out of memory, but it // could also overwrite the next scanline. can it overwrite non-empty data // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. // so we need to explicitly clamp the final ones if (depth == 4) { for (k=x*img_n; k >= 2; k-=2, ++in) { *cur++ = scale * ((*in >> 4) ); *cur++ = scale * ((*in ) & 0x0f); } if (k > 0) *cur++ = scale * ((*in >> 4) ); } else if (depth == 2) { for (k=x*img_n; k >= 4; k-=4, ++in) { *cur++ = scale * ((*in >> 6) ); *cur++ = scale * ((*in >> 4) & 0x03); *cur++ = scale * ((*in >> 2) & 0x03); *cur++ = scale * ((*in ) & 0x03); } if (k > 0) *cur++ = scale * ((*in >> 6) ); if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); } else if (depth == 1) { for (k=x*img_n; k >= 8; k-=8, ++in) { *cur++ = scale * ((*in >> 7) ); *cur++ = scale * ((*in >> 6) & 0x01); *cur++ = scale * ((*in >> 5) & 0x01); *cur++ = scale * ((*in >> 4) & 0x01); *cur++ = scale * ((*in >> 3) & 0x01); *cur++ = scale * ((*in >> 2) & 0x01); *cur++ = scale * ((*in >> 1) & 0x01); *cur++ = scale * ((*in ) & 0x01); } if (k > 0) *cur++ = scale * ((*in >> 7) ); if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); } if (img_n != out_n) { int q; // insert alpha = 255 cur = a->out + stride*j; if (img_n == 1) { for (q=x-1; q >= 0; --q) { cur[q*2+1] = 255; cur[q*2+0] = cur[q]; } } else { STBI_ASSERT(img_n == 3); for (q=x-1; q >= 0; --q) { cur[q*4+3] = 255; cur[q*4+2] = cur[q*3+2]; cur[q*4+1] = cur[q*3+1]; cur[q*4+0] = cur[q*3+0]; } } } } } else if (depth == 16) { // force the image data from big-endian to platform-native. // this is done in a separate pass due to the decoding relying // on the data being untouched, but could probably be done // per-line during decode if care is taken. stbi_uc *cur = a->out; stbi__uint16 *cur16 = (stbi__uint16*)cur; for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { *cur16 = (cur[0] << 8) | cur[1]; } } return 1; } static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) { int bytes = (depth == 16 ? 2 : 1); int out_bytes = out_n * bytes; stbi_uc *final; int p; if (!interlaced) return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); // de-interlacing final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); if (!final) return stbi__err("outofmem", "Out of memory"); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; int xspc[] = { 8,8,4,4,2,2,1 }; int yspc[] = { 8,8,8,4,4,2,2 }; int i,j,x,y; // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { STBI_FREE(final); return 0; } for (j=0; j < y; ++j) { for (i=0; i < x; ++i) { int out_y = j*yspc[p]+yorig[p]; int out_x = i*xspc[p]+xorig[p]; memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, a->out + (j*x+i)*out_bytes, out_bytes); } } STBI_FREE(a->out); image_data += img_len; image_data_len -= img_len; } } a->out = final; return 1; } static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) { stbi__context *s = z->s; stbi__uint32 i, pixel_count = s->img_x * s->img_y; stbi_uc *p = z->out; // compute color-based transparency, assuming we've // already got 255 as the alpha value in the output STBI_ASSERT(out_n == 2 || out_n == 4); if (out_n == 2) { for (i=0; i < pixel_count; ++i) { p[1] = (p[0] == tc[0] ? 0 : 255); p += 2; } } else { for (i=0; i < pixel_count; ++i) { if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) p[3] = 0; p += 4; } } return 1; } static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) { stbi__context *s = z->s; stbi__uint32 i, pixel_count = s->img_x * s->img_y; stbi__uint16 *p = (stbi__uint16*) z->out; // compute color-based transparency, assuming we've // already got 65535 as the alpha value in the output STBI_ASSERT(out_n == 2 || out_n == 4); if (out_n == 2) { for (i = 0; i < pixel_count; ++i) { p[1] = (p[0] == tc[0] ? 0 : 65535); p += 2; } } else { for (i = 0; i < pixel_count; ++i) { if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) p[3] = 0; p += 4; } } return 1; } static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) { stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; stbi_uc *p, *temp_out, *orig = a->out; p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); if (p == NULL) return stbi__err("outofmem", "Out of memory"); // between here and free(out) below, exitting would leak temp_out = p; if (pal_img_n == 3) { for (i=0; i < pixel_count; ++i) { int n = orig[i]*4; p[0] = palette[n ]; p[1] = palette[n+1]; p[2] = palette[n+2]; p += 3; } } else { for (i=0; i < pixel_count; ++i) { int n = orig[i]*4; p[0] = palette[n ]; p[1] = palette[n+1]; p[2] = palette[n+2]; p[3] = palette[n+3]; p += 4; } } STBI_FREE(a->out); a->out = temp_out; STBI_NOTUSED(len); return 1; } static int stbi__unpremultiply_on_load_global = 0; static int stbi__de_iphone_flag_global = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { stbi__de_iphone_flag_global = flag_true_if_should_convert; } #ifndef STBI_THREAD_LOCAL #define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global #define stbi__de_iphone_flag stbi__de_iphone_flag_global #else static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) { stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; stbi__unpremultiply_on_load_set = 1; } STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) { stbi__de_iphone_flag_local = flag_true_if_should_convert; stbi__de_iphone_flag_set = 1; } #define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ ? stbi__unpremultiply_on_load_local \ : stbi__unpremultiply_on_load_global) #define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ ? stbi__de_iphone_flag_local \ : stbi__de_iphone_flag_global) #endif // STBI_THREAD_LOCAL static void stbi__de_iphone(stbi__png *z) { stbi__context *s = z->s; stbi__uint32 i, pixel_count = s->img_x * s->img_y; stbi_uc *p = z->out; if (s->img_out_n == 3) { // convert bgr to rgb for (i=0; i < pixel_count; ++i) { stbi_uc t = p[0]; p[0] = p[2]; p[2] = t; p += 3; } } else { STBI_ASSERT(s->img_out_n == 4); if (stbi__unpremultiply_on_load) { // convert bgr to rgb and unpremultiply for (i=0; i < pixel_count; ++i) { stbi_uc a = p[3]; stbi_uc t = p[0]; if (a) { stbi_uc half = a / 2; p[0] = (p[2] * 255 + half) / a; p[1] = (p[1] * 255 + half) / a; p[2] = ( t * 255 + half) / a; } else { p[0] = p[2]; p[2] = t; } p += 4; } } else { // convert bgr to rgb for (i=0; i < pixel_count; ++i) { stbi_uc t = p[0]; p[0] = p[2]; p[2] = t; p += 4; } } } } #define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { stbi_uc palette[1024], pal_img_n=0; stbi_uc has_trans=0, tc[3]={0}; stbi__uint16 tc16[3]; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; int first=1,k,interlace=0, color=0, is_iphone=0; stbi__context *s = z->s; z->expanded = NULL; z->idata = NULL; z->out = NULL; if (!stbi__check_png_header(s)) return 0; if (scan == STBI__SCAN_type) return 1; for (;;) { stbi__pngchunk c = stbi__get_chunk_header(s); switch (c.type) { case STBI__PNG_TYPE('C','g','B','I'): is_iphone = 1; stbi__skip(s, c.length); break; case STBI__PNG_TYPE('I','H','D','R'): { int comp,filter; if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); s->img_x = stbi__get32be(s); s->img_y = stbi__get32be(s); if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); // if SCAN_header, have to scan to see if we have a tRNS } break; } case STBI__PNG_TYPE('P','L','T','E'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); pal_len = c.length / 3; if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); for (i=0; i < pal_len; ++i) { palette[i*4+0] = stbi__get8(s); palette[i*4+1] = stbi__get8(s); palette[i*4+2] = stbi__get8(s); palette[i*4+3] = 255; } break; } case STBI__PNG_TYPE('t','R','N','S'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); if (pal_img_n) { if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); pal_img_n = 4; for (i=0; i < c.length; ++i) palette[i*4+3] = stbi__get8(s); } else { if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; if (z->depth == 16) { for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger } } break; } case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; stbi_uc *p; if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; while (ioff + c.length > idata_limit) idata_limit *= 2; STBI_NOTUSED(idata_limit_old); p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); z->idata = p; } if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); ioff += c.length; break; } case STBI__PNG_TYPE('I','E','N','D'): { stbi__uint32 raw_len, bpl; if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (scan != STBI__SCAN_load) return 1; if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); // initial guess for decoded data size to avoid unnecessary reallocs bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); if (z->expanded == NULL) return 0; // zlib should set error STBI_FREE(z->idata); z->idata = NULL; if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) s->img_out_n = s->img_n+1; else s->img_out_n = s->img_n; if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; if (has_trans) { if (z->depth == 16) { if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; } else { if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; } } if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) stbi__de_iphone(z); if (pal_img_n) { // pal_img_n == 3 or 4 s->img_n = pal_img_n; // record the actual colors we had s->img_out_n = pal_img_n; if (req_comp >= 3) s->img_out_n = req_comp; if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) return 0; } else if (has_trans) { // non-paletted image with tRNS -> source image has (constant) alpha ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; // end of PNG chunk, read and skip CRC stbi__get32be(s); return 1; } default: // if critical, fail if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if ((c.type & (1 << 29)) == 0) { #ifndef STBI_NO_FAILURE_STRINGS // not threadsafe static char invalid_chunk[] = "XXXX PNG chunk not known"; invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); #endif return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); } stbi__skip(s, c.length); break; } // end of PNG chunk, read and skip CRC stbi__get32be(s); } } static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) { void *result=NULL; if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { if (p->depth <= 8) ri->bits_per_channel = 8; else if (p->depth == 16) ri->bits_per_channel = 16; else return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { if (ri->bits_per_channel == 8) result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); else result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); p->s->img_out_n = req_comp; if (result == NULL) return result; } *x = p->s->img_x; *y = p->s->img_y; if (n) *n = p->s->img_n; } STBI_FREE(p->out); p->out = NULL; STBI_FREE(p->expanded); p->expanded = NULL; STBI_FREE(p->idata); p->idata = NULL; return result; } static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi__png p; p.s = s; return stbi__do_png(&p, x,y,comp,req_comp, ri); } static int stbi__png_test(stbi__context *s) { int r; r = stbi__check_png_header(s); stbi__rewind(s); return r; } static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) { if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { stbi__rewind( p->s ); return 0; } if (x) *x = p->s->img_x; if (y) *y = p->s->img_y; if (comp) *comp = p->s->img_n; return 1; } static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) { stbi__png p; p.s = s; return stbi__png_info_raw(&p, x, y, comp); } static int stbi__png_is16(stbi__context *s) { stbi__png p; p.s = s; if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) return 0; if (p.depth != 16) { stbi__rewind(p.s); return 0; } return 1; } #endif // Microsoft/Windows BMP image #ifndef STBI_NO_BMP static int stbi__bmp_test_raw(stbi__context *s) { int r; int sz; if (stbi__get8(s) != 'B') return 0; if (stbi__get8(s) != 'M') return 0; stbi__get32le(s); // discard filesize stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved stbi__get32le(s); // discard data offset sz = stbi__get32le(s); r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); return r; } static int stbi__bmp_test(stbi__context *s) { int r = stbi__bmp_test_raw(s); stbi__rewind(s); return r; } // returns 0..31 for the highest set bit static int stbi__high_bit(unsigned int z) { int n=0; if (z == 0) return -1; if (z >= 0x10000) { n += 16; z >>= 16; } if (z >= 0x00100) { n += 8; z >>= 8; } if (z >= 0x00010) { n += 4; z >>= 4; } if (z >= 0x00004) { n += 2; z >>= 2; } if (z >= 0x00002) { n += 1;/* >>= 1;*/ } return n; } static int stbi__bitcount(unsigned int a) { a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits a = (a + (a >> 8)); // max 16 per 8 bits a = (a + (a >> 16)); // max 32 per 8 bits return a & 0xff; } // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. static int stbi__shiftsigned(unsigned int v, int shift, int bits) { static unsigned int mul_table[9] = { 0, 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, }; static unsigned int shift_table[9] = { 0, 0,0,1,0,2,4,6,0, }; if (shift < 0) v <<= -shift; else v >>= shift; STBI_ASSERT(v < 256); v >>= (8-bits); STBI_ASSERT(bits >= 0 && bits <= 8); return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; } typedef struct { int bpp, offset, hsz; unsigned int mr,mg,mb,ma, all_a; int extra_read; } stbi__bmp_data; static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) { // BI_BITFIELDS specifies masks explicitly, don't override if (compress == 3) return 1; if (compress == 0) { if (info->bpp == 16) { info->mr = 31u << 10; info->mg = 31u << 5; info->mb = 31u << 0; } else if (info->bpp == 32) { info->mr = 0xffu << 16; info->mg = 0xffu << 8; info->mb = 0xffu << 0; info->ma = 0xffu << 24; info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 } else { // otherwise, use defaults, which is all-0 info->mr = info->mg = info->mb = info->ma = 0; } return 1; } return 0; // error } static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { int hsz; if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); stbi__get32le(s); // discard filesize stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); info->mr = info->mg = info->mb = info->ma = 0; info->extra_read = 14; if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { s->img_x = stbi__get16le(s); s->img_y = stbi__get16le(s); } else { s->img_x = stbi__get32le(s); s->img_y = stbi__get32le(s); } if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); info->bpp = stbi__get16le(s); if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard hres stbi__get32le(s); // discard vres stbi__get32le(s); // discard colorsused stbi__get32le(s); // discard max important if (hsz == 40 || hsz == 56) { if (hsz == 56) { stbi__get32le(s); stbi__get32le(s); stbi__get32le(s); stbi__get32le(s); } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { stbi__bmp_set_mask_defaults(info, compress); } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->extra_read += 12; // not documented, but generated by photoshop and handled by mspaint if (info->mr == info->mg && info->mg == info->mb) { // ?!?!? return stbi__errpuc("bad BMP", "bad BMP"); } } else return stbi__errpuc("bad BMP", "bad BMP"); } } else { // V4/V5 header int i; if (hsz != 108 && hsz != 124) return stbi__errpuc("bad BMP", "bad BMP"); info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->ma = stbi__get32le(s); if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs stbi__bmp_set_mask_defaults(info, compress); stbi__get32le(s); // discard color space for (i=0; i < 12; ++i) stbi__get32le(s); // discard color space parameters if (hsz == 124) { stbi__get32le(s); // discard rendering intent stbi__get32le(s); // discard offset of profile data stbi__get32le(s); // discard size of profile data stbi__get32le(s); // discard reserved } } } return (void *) 1; } static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *out; unsigned int mr=0,mg=0,mb=0,ma=0, all_a; stbi_uc pal[256][4]; int psize=0,i,j,width; int flip_vertically, pad, target; stbi__bmp_data info; STBI_NOTUSED(ri); info.all_a = 255; if (stbi__bmp_parse_header(s, &info) == NULL) return NULL; // error code already set flip_vertically = ((int) s->img_y) > 0; s->img_y = abs((int) s->img_y); if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); mr = info.mr; mg = info.mg; mb = info.mb; ma = info.ma; all_a = info.all_a; if (info.hsz == 12) { if (info.bpp < 24) psize = (info.offset - info.extra_read - 24) / 3; } else { if (info.bpp < 16) psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { return stbi__errpuc("bad offset", "Corrupt BMP"); } } if (info.bpp == 24 && ma == 0xff000000) s->img_n = 3; else s->img_n = ma ? 4 : 3; if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 target = req_comp; else target = s->img_n; // if they want monochrome, we'll post-convert // sanity-check size if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) return stbi__errpuc("too large", "Corrupt BMP"); out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (info.bpp < 16) { int z=0; if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } for (i=0; i < psize; ++i) { pal[i][2] = stbi__get8(s); pal[i][1] = stbi__get8(s); pal[i][0] = stbi__get8(s); if (info.hsz != 12) stbi__get8(s); pal[i][3] = 255; } stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); if (info.bpp == 1) width = (s->img_x + 7) >> 3; else if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.bpp == 8) width = s->img_x; else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } pad = (-width)&3; if (info.bpp == 1) { for (j=0; j < (int) s->img_y; ++j) { int bit_offset = 7, v = stbi__get8(s); for (i=0; i < (int) s->img_x; ++i) { int color = (v>>bit_offset)&0x1; out[z++] = pal[color][0]; out[z++] = pal[color][1]; out[z++] = pal[color][2]; if (target == 4) out[z++] = 255; if (i+1 == (int) s->img_x) break; if((--bit_offset) < 0) { bit_offset = 7; v = stbi__get8(s); } } stbi__skip(s, pad); } } else { for (j=0; j < (int) s->img_y; ++j) { for (i=0; i < (int) s->img_x; i += 2) { int v=stbi__get8(s),v2=0; if (info.bpp == 4) { v2 = v & 15; v >>= 4; } out[z++] = pal[v][0]; out[z++] = pal[v][1]; out[z++] = pal[v][2]; if (target == 4) out[z++] = 255; if (i+1 == (int) s->img_x) break; v = (info.bpp == 8) ? stbi__get8(s) : v2; out[z++] = pal[v][0]; out[z++] = pal[v][1]; out[z++] = pal[v][2]; if (target == 4) out[z++] = 255; } stbi__skip(s, pad); } } } else { int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int z = 0; int easy=0; stbi__skip(s, info.offset - info.extra_read - info.hsz); if (info.bpp == 24) width = 3 * s->img_x; else if (info.bpp == 16) width = 2*s->img_x; else /* bpp = 32 and pad = 0 */ width=0; pad = (-width) & 3; if (info.bpp == 24) { easy = 1; } else if (info.bpp == 32) { if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) easy = 2; } if (!easy) { if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } // right shift amt to put high bit in position #7 rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } } for (j=0; j < (int) s->img_y; ++j) { if (easy) { for (i=0; i < (int) s->img_x; ++i) { unsigned char a; out[z+2] = stbi__get8(s); out[z+1] = stbi__get8(s); out[z+0] = stbi__get8(s); z += 3; a = (easy == 2 ? stbi__get8(s) : 255); all_a |= a; if (target == 4) out[z++] = a; } } else { int bpp = info.bpp; for (i=0; i < (int) s->img_x; ++i) { stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); unsigned int a; out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); all_a |= a; if (target == 4) out[z++] = STBI__BYTECAST(a); } } stbi__skip(s, pad); } } // if alpha channel is all 0s, replace with all 255s if (target == 4 && all_a == 0) for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) out[i] = 255; if (flip_vertically) { stbi_uc t; for (j=0; j < (int) s->img_y>>1; ++j) { stbi_uc *p1 = out + j *s->img_x*target; stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; for (i=0; i < (int) s->img_x*target; ++i) { t = p1[i]; p1[i] = p2[i]; p2[i] = t; } } } if (req_comp && req_comp != target) { out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); if (out == NULL) return out; // stbi__convert_format frees input on failure } *x = s->img_x; *y = s->img_y; if (comp) *comp = s->img_n; return out; } #endif // Targa Truevision - TGA // by Jonathan Dummer #ifndef STBI_NO_TGA // returns STBI_rgb or whatever, 0 on error static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) { // only RGB or RGBA (incl. 16bit) or grey allowed if (is_rgb16) *is_rgb16 = 0; switch(bits_per_pixel) { case 8: return STBI_grey; case 16: if(is_grey) return STBI_grey_alpha; // fallthrough case 15: if(is_rgb16) *is_rgb16 = 1; return STBI_rgb; case 24: // fallthrough case 32: return bits_per_pixel/8; default: return 0; } } static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) { int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; int sz, tga_colormap_type; stbi__get8(s); // discard Offset tga_colormap_type = stbi__get8(s); // colormap type if( tga_colormap_type > 1 ) { stbi__rewind(s); return 0; // only RGB or indexed allowed } tga_image_type = stbi__get8(s); // image type if ( tga_colormap_type == 1 ) { // colormapped (paletted) image if (tga_image_type != 1 && tga_image_type != 9) { stbi__rewind(s); return 0; } stbi__skip(s,4); // skip index of first colormap entry and number of entries sz = stbi__get8(s); // check bits per palette color entry if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { stbi__rewind(s); return 0; } stbi__skip(s,4); // skip image x and y origin tga_colormap_bpp = sz; } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { stbi__rewind(s); return 0; // only RGB or grey allowed, +/- RLE } stbi__skip(s,9); // skip colormap specification and image x/y origin tga_colormap_bpp = 0; } tga_w = stbi__get16le(s); if( tga_w < 1 ) { stbi__rewind(s); return 0; // test width } tga_h = stbi__get16le(s); if( tga_h < 1 ) { stbi__rewind(s); return 0; // test height } tga_bits_per_pixel = stbi__get8(s); // bits per pixel stbi__get8(s); // ignore alpha bits if (tga_colormap_bpp != 0) { if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { // when using a colormap, tga_bits_per_pixel is the size of the indexes // I don't think anything but 8 or 16bit indexes makes sense stbi__rewind(s); return 0; } tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); } else { tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); } if(!tga_comp) { stbi__rewind(s); return 0; } if (x) *x = tga_w; if (y) *y = tga_h; if (comp) *comp = tga_comp; return 1; // seems to have passed everything } static int stbi__tga_test(stbi__context *s) { int res = 0; int sz, tga_color_type; stbi__get8(s); // discard Offset tga_color_type = stbi__get8(s); // color type if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed sz = stbi__get8(s); // image type if ( tga_color_type == 1 ) { // colormapped (paletted) image if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 stbi__skip(s,4); // skip index of first colormap entry and number of entries sz = stbi__get8(s); // check bits per palette color entry if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; stbi__skip(s,4); // skip image x and y origin } else { // "normal" image w/o colormap if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE stbi__skip(s,9); // skip colormap specification and image x/y origin } if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height sz = stbi__get8(s); // bits per pixel if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; res = 1; // if we got this far, everything's good and we can return 1 instead of 0 errorEnd: stbi__rewind(s); return res; } // read 16bit value and convert to 24bit RGB static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) { stbi__uint16 px = (stbi__uint16)stbi__get16le(s); stbi__uint16 fiveBitMask = 31; // we have 3 channels with 5bits each int r = (px >> 10) & fiveBitMask; int g = (px >> 5) & fiveBitMask; int b = px & fiveBitMask; // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later out[0] = (stbi_uc)((r * 255)/31); out[1] = (stbi_uc)((g * 255)/31); out[2] = (stbi_uc)((b * 255)/31); // some people claim that the most significant bit might be used for alpha // (possibly if an alpha-bit is set in the "image descriptor byte") // but that only made 16bit test images completely translucent.. // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { // read in the TGA header stuff int tga_offset = stbi__get8(s); int tga_indexed = stbi__get8(s); int tga_image_type = stbi__get8(s); int tga_is_RLE = 0; int tga_palette_start = stbi__get16le(s); int tga_palette_len = stbi__get16le(s); int tga_palette_bits = stbi__get8(s); int tga_x_origin = stbi__get16le(s); int tga_y_origin = stbi__get16le(s); int tga_width = stbi__get16le(s); int tga_height = stbi__get16le(s); int tga_bits_per_pixel = stbi__get8(s); int tga_comp, tga_rgb16=0; int tga_inverted = stbi__get8(s); // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) // image data unsigned char *tga_data; unsigned char *tga_palette = NULL; int i, j; unsigned char raw_data[4] = {0}; int RLE_count = 0; int RLE_repeating = 0; int read_next_pixel = 1; STBI_NOTUSED(ri); STBI_NOTUSED(tga_x_origin); // @TODO STBI_NOTUSED(tga_y_origin); // @TODO if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); // do a tiny bit of precessing if ( tga_image_type >= 8 ) { tga_image_type -= 8; tga_is_RLE = 1; } tga_inverted = 1 - ((tga_inverted >> 5) & 1); // If I'm paletted, then I'll use the number of bits from the palette if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); // tga info *x = tga_width; *y = tga_height; if (comp) *comp = tga_comp; if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) return stbi__errpuc("too large", "Corrupt TGA"); tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); // skip to the data's starting position (offset usually = 0) stbi__skip(s, tga_offset ); if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { for (i=0; i < tga_height; ++i) { int row = tga_inverted ? tga_height -i - 1 : i; stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; stbi__getn(s, tga_row, tga_width * tga_comp); } } else { // do I need to load a palette? if ( tga_indexed) { if (tga_palette_len == 0) { /* you have to have at least one entry! */ STBI_FREE(tga_data); return stbi__errpuc("bad palette", "Corrupt TGA"); } // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); if (!tga_palette) { STBI_FREE(tga_data); return stbi__errpuc("outofmem", "Out of memory"); } if (tga_rgb16) { stbi_uc *pal_entry = tga_palette; STBI_ASSERT(tga_comp == STBI_rgb); for (i=0; i < tga_palette_len; ++i) { stbi__tga_read_rgb16(s, pal_entry); pal_entry += tga_comp; } } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { STBI_FREE(tga_data); STBI_FREE(tga_palette); return stbi__errpuc("bad palette", "Corrupt TGA"); } } // load the data for (i=0; i < tga_width * tga_height; ++i) { // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? if ( tga_is_RLE ) { if ( RLE_count == 0 ) { // yep, get the next byte as a RLE command int RLE_cmd = stbi__get8(s); RLE_count = 1 + (RLE_cmd & 127); RLE_repeating = RLE_cmd >> 7; read_next_pixel = 1; } else if ( !RLE_repeating ) { read_next_pixel = 1; } } else { read_next_pixel = 1; } // OK, if I need to read a pixel, do it now if ( read_next_pixel ) { // load however much data we did have if ( tga_indexed ) { // read in index, then perform the lookup int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); if ( pal_idx >= tga_palette_len ) { // invalid index pal_idx = 0; } pal_idx *= tga_comp; for (j = 0; j < tga_comp; ++j) { raw_data[j] = tga_palette[pal_idx+j]; } } else if(tga_rgb16) { STBI_ASSERT(tga_comp == STBI_rgb); stbi__tga_read_rgb16(s, raw_data); } else { // read in the data raw for (j = 0; j < tga_comp; ++j) { raw_data[j] = stbi__get8(s); } } // clear the reading flag for the next pixel read_next_pixel = 0; } // end of reading a pixel // copy data for (j = 0; j < tga_comp; ++j) tga_data[i*tga_comp+j] = raw_data[j]; // in case we're in RLE mode, keep counting down --RLE_count; } // do I need to invert the image? if ( tga_inverted ) { for (j = 0; j*2 < tga_height; ++j) { int index1 = j * tga_width * tga_comp; int index2 = (tga_height - 1 - j) * tga_width * tga_comp; for (i = tga_width * tga_comp; i > 0; --i) { unsigned char temp = tga_data[index1]; tga_data[index1] = tga_data[index2]; tga_data[index2] = temp; ++index1; ++index2; } } } // clear my palette, if I had one if ( tga_palette != NULL ) { STBI_FREE( tga_palette ); } } // swap RGB - if the source data was RGB16, it already is in the right order if (tga_comp >= 3 && !tga_rgb16) { unsigned char* tga_pixel = tga_data; for (i=0; i < tga_width * tga_height; ++i) { unsigned char temp = tga_pixel[0]; tga_pixel[0] = tga_pixel[2]; tga_pixel[2] = temp; tga_pixel += tga_comp; } } // convert to target component count if (req_comp && req_comp != tga_comp) tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); // the things I do to get rid of an error message, and yet keep // Microsoft's C compilers happy... [8^( tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0; STBI_NOTUSED(tga_palette_start); // OK, done return tga_data; } #endif // ************************************************************************************************* // Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB #ifndef STBI_NO_PSD static int stbi__psd_test(stbi__context *s) { int r = (stbi__get32be(s) == 0x38425053); stbi__rewind(s); return r; } static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) { int count, nleft, len; count = 0; while ((nleft = pixelCount - count) > 0) { len = stbi__get8(s); if (len == 128) { // No-op. } else if (len < 128) { // Copy next len+1 bytes literally. len++; if (len > nleft) return 0; // corrupt data count += len; while (len) { *p = stbi__get8(s); p += 4; len--; } } else if (len > 128) { stbi_uc val; // Next -len+1 bytes in the dest are replicated from next source byte. // (Interpret len as a negative 8-bit int.) len = 257 - len; if (len > nleft) return 0; // corrupt data val = stbi__get8(s); count += len; while (len) { *p = val; p += 4; len--; } } } return 1; } static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { int pixelCount; int channelCount, compression; int channel, i; int bitdepth; int w,h; stbi_uc *out; STBI_NOTUSED(ri); // Check identifier if (stbi__get32be(s) != 0x38425053) // "8BPS" return stbi__errpuc("not PSD", "Corrupt PSD image"); // Check file type version. if (stbi__get16be(s) != 1) return stbi__errpuc("wrong version", "Unsupported version of PSD image"); // Skip 6 reserved bytes. stbi__skip(s, 6 ); // Read the number of channels (R, G, B, A, etc). channelCount = stbi__get16be(s); if (channelCount < 0 || channelCount > 16) return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); // Read the rows and columns of the image. h = stbi__get32be(s); w = stbi__get32be(s); if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); // Make sure the depth is 8 bits. bitdepth = stbi__get16be(s); if (bitdepth != 8 && bitdepth != 16) return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); // Make sure the color mode is RGB. // Valid options are: // 0: Bitmap // 1: Grayscale // 2: Indexed color // 3: RGB color // 4: CMYK color // 7: Multichannel // 8: Duotone // 9: Lab color if (stbi__get16be(s) != 3) return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) stbi__skip(s,stbi__get32be(s) ); // Skip the image resources. (resolution, pen tool paths, etc) stbi__skip(s, stbi__get32be(s) ); // Skip the reserved data. stbi__skip(s, stbi__get32be(s) ); // Find out if the data is compressed. // Known values: // 0: no compression // 1: RLE compressed compression = stbi__get16be(s); if (compression > 1) return stbi__errpuc("bad compression", "PSD has an unknown compression format"); // Check size if (!stbi__mad3sizes_valid(4, w, h, 0)) return stbi__errpuc("too large", "Corrupt PSD"); // Create the destination image. if (!compression && bitdepth == 16 && bpc == 16) { out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); ri->bits_per_channel = 16; } else out = (stbi_uc *) stbi__malloc(4 * w*h); if (!out) return stbi__errpuc("outofmem", "Out of memory"); pixelCount = w*h; // Initialize the data to zero. //memset( out, 0, pixelCount * 4 ); // Finally, the image data. if (compression) { // RLE as used by .PSD and .TIFF // Loop until you get the number of unpacked bytes you are expecting: // Read the next source byte into n. // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. // Else if n is 128, noop. // Endloop // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, // which we're going to just skip. stbi__skip(s, h * channelCount * 2 ); // Read the RLE data by channel. for (channel = 0; channel < 4; channel++) { stbi_uc *p; p = out+channel; if (channel >= channelCount) { // Fill this channel with default data. for (i = 0; i < pixelCount; i++, p += 4) *p = (channel == 3 ? 255 : 0); } else { // Read the RLE data. if (!stbi__psd_decode_rle(s, p, pixelCount)) { STBI_FREE(out); return stbi__errpuc("corrupt", "bad RLE data"); } } } } else { // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. // Read the data by channel. for (channel = 0; channel < 4; channel++) { if (channel >= channelCount) { // Fill this channel with default data. if (bitdepth == 16 && bpc == 16) { stbi__uint16 *q = ((stbi__uint16 *) out) + channel; stbi__uint16 val = channel == 3 ? 65535 : 0; for (i = 0; i < pixelCount; i++, q += 4) *q = val; } else { stbi_uc *p = out+channel; stbi_uc val = channel == 3 ? 255 : 0; for (i = 0; i < pixelCount; i++, p += 4) *p = val; } } else { if (ri->bits_per_channel == 16) { // output bpc stbi__uint16 *q = ((stbi__uint16 *) out) + channel; for (i = 0; i < pixelCount; i++, q += 4) *q = (stbi__uint16) stbi__get16be(s); } else { stbi_uc *p = out+channel; if (bitdepth == 16) { // input bpc for (i = 0; i < pixelCount; i++, p += 4) *p = (stbi_uc) (stbi__get16be(s) >> 8); } else { for (i = 0; i < pixelCount; i++, p += 4) *p = stbi__get8(s); } } } } } // remove weird white matte from PSD if (channelCount >= 4) { if (ri->bits_per_channel == 16) { for (i=0; i < w*h; ++i) { stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; if (pixel[3] != 0 && pixel[3] != 65535) { float a = pixel[3] / 65535.0f; float ra = 1.0f / a; float inv_a = 65535.0f * (1 - ra); pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); } } } else { for (i=0; i < w*h; ++i) { unsigned char *pixel = out + 4*i; if (pixel[3] != 0 && pixel[3] != 255) { float a = pixel[3] / 255.0f; float ra = 1.0f / a; float inv_a = 255.0f * (1 - ra); pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); } } } } // convert to desired output format if (req_comp && req_comp != 4) { if (ri->bits_per_channel == 16) out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); else out = stbi__convert_format(out, 4, req_comp, w, h); if (out == NULL) return out; // stbi__convert_format frees input on failure } if (comp) *comp = 4; *y = h; *x = w; return out; } #endif // ************************************************************************************************* // Softimage PIC loader // by Tom Seddon // // See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format // See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ #ifndef STBI_NO_PIC static int stbi__pic_is4(stbi__context *s,const char *str) { int i; for (i=0; i<4; ++i) if (stbi__get8(s) != (stbi_uc)str[i]) return 0; return 1; } static int stbi__pic_test_core(stbi__context *s) { int i; if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) return 0; for(i=0;i<84;++i) stbi__get8(s); if (!stbi__pic_is4(s,"PICT")) return 0; return 1; } typedef struct { stbi_uc size,type,channel; } stbi__pic_packet; static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) { int mask=0x80, i; for (i=0; i<4; ++i, mask>>=1) { if (channel & mask) { if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); dest[i]=stbi__get8(s); } } return dest; } static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) { int mask=0x80,i; for (i=0;i<4; ++i, mask>>=1) if (channel&mask) dest[i]=src[i]; } static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) { int act_comp=0,num_packets=0,y,chained; stbi__pic_packet packets[10]; // this will (should...) cater for even some bizarre stuff like having data // for the same channel in multiple packets. do { stbi__pic_packet *packet; if (num_packets==sizeof(packets)/sizeof(packets[0])) return stbi__errpuc("bad format","too many packets"); packet = &packets[num_packets++]; chained = stbi__get8(s); packet->size = stbi__get8(s); packet->type = stbi__get8(s); packet->channel = stbi__get8(s); act_comp |= packet->channel; if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); } while (chained); *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? for(y=0; ytype) { default: return stbi__errpuc("bad format","packet has bad compression type"); case 0: {//uncompressed int x; for(x=0;xchannel,dest)) return 0; break; } case 1://Pure RLE { int left=width, i; while (left>0) { stbi_uc count,value[4]; count=stbi__get8(s); if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); if (count > left) count = (stbi_uc) left; if (!stbi__readval(s,packet->channel,value)) return 0; for(i=0; ichannel,dest,value); left -= count; } } break; case 2: {//Mixed RLE int left=width; while (left>0) { int count = stbi__get8(s), i; if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); if (count >= 128) { // Repeated stbi_uc value[4]; if (count==128) count = stbi__get16be(s); else count -= 127; if (count > left) return stbi__errpuc("bad file","scanline overrun"); if (!stbi__readval(s,packet->channel,value)) return 0; for(i=0;ichannel,dest,value); } else { // Raw ++count; if (count>left) return stbi__errpuc("bad file","scanline overrun"); for(i=0;ichannel,dest)) return 0; } left-=count; } break; } } } } return result; } static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) { stbi_uc *result; int i, x,y, internal_comp; STBI_NOTUSED(ri); if (!comp) comp = &internal_comp; for (i=0; i<92; ++i) stbi__get8(s); x = stbi__get16be(s); y = stbi__get16be(s); if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); stbi__get32be(s); //skip `ratio' stbi__get16be(s); //skip `fields' stbi__get16be(s); //skip `pad' // intermediate buffer is RGBA result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); if (!result) return stbi__errpuc("outofmem", "Out of memory"); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { STBI_FREE(result); result=0; } *px = x; *py = y; if (req_comp == 0) req_comp = *comp; result=stbi__convert_format(result,4,req_comp,x,y); return result; } static int stbi__pic_test(stbi__context *s) { int r = stbi__pic_test_core(s); stbi__rewind(s); return r; } #endif // ************************************************************************************************* // GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb #ifndef STBI_NO_GIF typedef struct { stbi__int16 prefix; stbi_uc first; stbi_uc suffix; } stbi__gif_lzw; typedef struct { int w,h; stbi_uc *out; // output buffer (always 4 components) stbi_uc *background; // The current "background" as far as a gif is concerned stbi_uc *history; int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; stbi__gif_lzw codes[8192]; stbi_uc *color_table; int parse, step; int lflags; int start_x, start_y; int max_x, max_y; int cur_x, cur_y; int line_size; int delay; } stbi__gif; static int stbi__gif_test_raw(stbi__context *s) { int sz; if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; sz = stbi__get8(s); if (sz != '9' && sz != '7') return 0; if (stbi__get8(s) != 'a') return 0; return 1; } static int stbi__gif_test(stbi__context *s) { int r = stbi__gif_test_raw(s); stbi__rewind(s); return r; } static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) { int i; for (i=0; i < num_entries; ++i) { pal[i][2] = stbi__get8(s); pal[i][1] = stbi__get8(s); pal[i][0] = stbi__get8(s); pal[i][3] = transp == i ? 0 : 255; } } static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) { stbi_uc version; if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return stbi__err("not GIF", "Corrupt GIF"); version = stbi__get8(s); if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); stbi__g_failure_reason = ""; g->w = stbi__get16le(s); g->h = stbi__get16le(s); g->flags = stbi__get8(s); g->bgindex = stbi__get8(s); g->ratio = stbi__get8(s); g->transparent = -1; if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments if (is_info) return 1; if (g->flags & 0x80) stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); return 1; } static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); if (!g) return stbi__err("outofmem", "Out of memory"); if (!stbi__gif_header(s, g, comp, 1)) { STBI_FREE(g); stbi__rewind( s ); return 0; } if (x) *x = g->w; if (y) *y = g->h; STBI_FREE(g); return 1; } static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty if (g->codes[code].prefix >= 0) stbi__out_gif_code(g, g->codes[code].prefix); if (g->cur_y >= g->max_y) return; idx = g->cur_x + g->cur_y; p = &g->out[idx]; g->history[idx / 4] = 1; c = &g->color_table[g->codes[code].suffix * 4]; if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; p[3] = c[3]; } g->cur_x += 4; if (g->cur_x >= g->max_x) { g->cur_x = g->start_x; g->cur_y += g->step; while (g->cur_y >= g->max_y && g->parse > 0) { g->step = (1 << g->parse) * g->line_size; g->cur_y = g->start_y + (g->step >> 1); --g->parse; } } } static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) { stbi_uc lzw_cs; stbi__int32 len, init_code; stbi__uint32 first; stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; stbi__gif_lzw *p; lzw_cs = stbi__get8(s); if (lzw_cs > 12) return NULL; clear = 1 << lzw_cs; first = 1; codesize = lzw_cs + 1; codemask = (1 << codesize) - 1; bits = 0; valid_bits = 0; for (init_code = 0; init_code < clear; init_code++) { g->codes[init_code].prefix = -1; g->codes[init_code].first = (stbi_uc) init_code; g->codes[init_code].suffix = (stbi_uc) init_code; } // support no starting clear code avail = clear+2; oldcode = -1; len = 0; for(;;) { if (valid_bits < codesize) { if (len == 0) { len = stbi__get8(s); // start new block if (len == 0) return g->out; } --len; bits |= (stbi__int32) stbi__get8(s) << valid_bits; valid_bits += 8; } else { stbi__int32 code = bits & codemask; bits >>= codesize; valid_bits -= codesize; // @OPTIMIZE: is there some way we can accelerate the non-clear path? if (code == clear) { // clear code codesize = lzw_cs + 1; codemask = (1 << codesize) - 1; avail = clear + 2; oldcode = -1; first = 0; } else if (code == clear + 1) { // end of stream code stbi__skip(s, len); while ((len = stbi__get8(s)) > 0) stbi__skip(s,len); return g->out; } else if (code <= avail) { if (first) { return stbi__errpuc("no clear code", "Corrupt GIF"); } if (oldcode >= 0) { p = &g->codes[avail++]; if (avail > 8192) { return stbi__errpuc("too many codes", "Corrupt GIF"); } p->prefix = (stbi__int16) oldcode; p->first = g->codes[oldcode].first; p->suffix = (code == avail) ? p->first : g->codes[code].first; } else if (code == avail) return stbi__errpuc("illegal code in raster", "Corrupt GIF"); stbi__out_gif_code(g, (stbi__uint16) code); if ((avail & codemask) == 0 && avail <= 0x0FFF) { codesize++; codemask = (1 << codesize) - 1; } oldcode = code; } else { return stbi__errpuc("illegal code in raster", "Corrupt GIF"); } } } } // this function is designed to support animated gifs, although stb_image doesn't support it // two back is the image from two frames ago, used for a very specific disposal format static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { int dispose; int first_frame; int pi; int pcount; STBI_NOTUSED(req_comp); // on first frame, any non-written pixels get the background colour (non-transparent) first_frame = 0; if (g->out == 0) { if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) return stbi__errpuc("too large", "GIF image is too large"); pcount = g->w * g->h; g->out = (stbi_uc *) stbi__malloc(4 * pcount); g->background = (stbi_uc *) stbi__malloc(4 * pcount); g->history = (stbi_uc *) stbi__malloc(pcount); if (!g->out || !g->background || !g->history) return stbi__errpuc("outofmem", "Out of memory"); // image is treated as "transparent" at the start - ie, nothing overwrites the current background; // background colour is only used for pixels that are not rendered first frame, after that "background" // color refers to the color that was there the previous frame. memset(g->out, 0x00, 4 * pcount); memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) memset(g->history, 0x00, pcount); // pixels that were affected previous frame first_frame = 1; } else { // second frame - how do we dispose of the previous one? dispose = (g->eflags & 0x1C) >> 2; pcount = g->w * g->h; if ((dispose == 3) && (two_back == 0)) { dispose = 2; // if I don't have an image to revert back to, default to the old background } if (dispose == 3) { // use previous graphic for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); } } } else if (dispose == 2) { // restore what was changed last frame to background before that frame; for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); } } } else { // This is a non-disposal case eithe way, so just // leave the pixels as is, and they will become the new background // 1: do not dispose // 0: not specified. } // background is what out is after the undoing of the previou frame; memcpy( g->background, g->out, 4 * g->w * g->h ); } // clear my history; memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame for (;;) { int tag = stbi__get8(s); switch (tag) { case 0x2C: /* Image Descriptor */ { stbi__int32 x, y, w, h; stbi_uc *o; x = stbi__get16le(s); y = stbi__get16le(s); w = stbi__get16le(s); h = stbi__get16le(s); if (((x + w) > (g->w)) || ((y + h) > (g->h))) return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); g->line_size = g->w * 4; g->start_x = x * 4; g->start_y = y * g->line_size; g->max_x = g->start_x + w * 4; g->max_y = g->start_y + h * g->line_size; g->cur_x = g->start_x; g->cur_y = g->start_y; // if the width of the specified rectangle is 0, that means // we may not see *any* pixels or the image is malformed; // to make sure this is caught, move the current y down to // max_y (which is what out_gif_code checks). if (w == 0) g->cur_y = g->max_y; g->lflags = stbi__get8(s); if (g->lflags & 0x40) { g->step = 8 * g->line_size; // first interlaced spacing g->parse = 3; } else { g->step = g->line_size; g->parse = 0; } if (g->lflags & 0x80) { stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); g->color_table = (stbi_uc *) g->lpal; } else if (g->flags & 0x80) { g->color_table = (stbi_uc *) g->pal; } else return stbi__errpuc("missing color table", "Corrupt GIF"); o = stbi__process_gif_raster(s, g); if (!o) return NULL; // if this was the first frame, pcount = g->w * g->h; if (first_frame && (g->bgindex > 0)) { // if first frame, any pixel not drawn to gets the background color for (pi = 0; pi < pcount; ++pi) { if (g->history[pi] == 0) { g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); } } } return o; } case 0x21: // Comment Extension. { int len; int ext = stbi__get8(s); if (ext == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { g->eflags = stbi__get8(s); g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. // unset old transparent if (g->transparent >= 0) { g->pal[g->transparent][3] = 255; } if (g->eflags & 0x01) { g->transparent = stbi__get8(s); if (g->transparent >= 0) { g->pal[g->transparent][3] = 0; } } else { // don't need transparent stbi__skip(s, 1); g->transparent = -1; } } else { stbi__skip(s, len); break; } } while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); } break; } case 0x3B: // gif stream termination code return (stbi_uc *) s; // using '1' causes warning on some compilers default: return stbi__errpuc("unknown code", "Corrupt GIF"); } } } static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) { STBI_FREE(g->out); STBI_FREE(g->history); STBI_FREE(g->background); if (out) STBI_FREE(out); if (delays && *delays) STBI_FREE(*delays); return stbi__errpuc("outofmem", "Out of memory"); } static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { int layers = 0; stbi_uc *u = 0; stbi_uc *out = 0; stbi_uc *two_back = 0; stbi__gif g; int stride; int out_size = 0; int delays_size = 0; STBI_NOTUSED(out_size); STBI_NOTUSED(delays_size); memset(&g, 0, sizeof(g)); if (delays) { *delays = 0; } do { u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker if (u) { *x = g.w; *y = g.h; ++layers; stride = g.w * g.h * 4; if (out) { void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); if (!tmp) return stbi__load_gif_main_outofmem(&g, out, delays); else { out = (stbi_uc*) tmp; out_size = layers * stride; } if (delays) { int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); if (!new_delays) return stbi__load_gif_main_outofmem(&g, out, delays); *delays = new_delays; delays_size = layers * sizeof(int); } } else { out = (stbi_uc*)stbi__malloc( layers * stride ); if (!out) return stbi__load_gif_main_outofmem(&g, out, delays); out_size = layers * stride; if (delays) { *delays = (int*) stbi__malloc( layers * sizeof(int) ); if (!*delays) return stbi__load_gif_main_outofmem(&g, out, delays); delays_size = layers * sizeof(int); } } memcpy( out + ((layers - 1) * stride), u, stride ); if (layers >= 2) { two_back = out - 2 * stride; } if (delays) { (*delays)[layers - 1U] = g.delay; } } } while (u != 0); // free temp buffer; STBI_FREE(g.out); STBI_FREE(g.history); STBI_FREE(g.background); // do the final conversion after loading everything; if (req_comp && req_comp != 4) out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); *z = layers; return out; } else { return stbi__errpuc("not GIF", "Image was not as a gif type."); } } static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *u = 0; stbi__gif g; memset(&g, 0, sizeof(g)); STBI_NOTUSED(ri); u = stbi__gif_load_next(s, &g, comp, req_comp, 0); if (u == (stbi_uc *) s) u = 0; // end of animated gif marker if (u) { *x = g.w; *y = g.h; // moved conversion to after successful load so that the same // can be done for multiple frames. if (req_comp && req_comp != 4) u = stbi__convert_format(u, 4, req_comp, g.w, g.h); } else if (g.out) { // if there was an error and we allocated an image buffer, free it! STBI_FREE(g.out); } // free buffers needed for multiple frame loading; STBI_FREE(g.history); STBI_FREE(g.background); return u; } static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) { return stbi__gif_info_raw(s,x,y,comp); } #endif // ************************************************************************************************* // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR static int stbi__hdr_test_core(stbi__context *s, const char *signature) { int i; for (i=0; signature[i]; ++i) if (stbi__get8(s) != signature[i]) return 0; stbi__rewind(s); return 1; } static int stbi__hdr_test(stbi__context* s) { int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); stbi__rewind(s); if(!r) { r = stbi__hdr_test_core(s, "#?RGBE\n"); stbi__rewind(s); } return r; } #define STBI__HDR_BUFLEN 1024 static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) { int len=0; char c = '\0'; c = (char) stbi__get8(z); while (!stbi__at_eof(z) && c != '\n') { buffer[len++] = c; if (len == STBI__HDR_BUFLEN-1) { // flush to end of line while (!stbi__at_eof(z) && stbi__get8(z) != '\n') ; break; } c = (char) stbi__get8(z); } buffer[len] = 0; return buffer; } static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) { if ( input[3] != 0 ) { float f1; // Exponent f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); if (req_comp <= 2) output[0] = (input[0] + input[1] + input[2]) * f1 / 3; else { output[0] = input[0] * f1; output[1] = input[1] * f1; output[2] = input[2] * f1; } if (req_comp == 2) output[1] = 1; if (req_comp == 4) output[3] = 1; } else { switch (req_comp) { case 4: output[3] = 1; /* fallthrough */ case 3: output[0] = output[1] = output[2] = 0; break; case 2: output[1] = 1; /* fallthrough */ case 1: output[0] = 0; break; } } } static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { char buffer[STBI__HDR_BUFLEN]; char *token; int valid = 0; int width, height; stbi_uc *scanline; float *hdr_data; int len; unsigned char count, value; int i, j, k, c1,c2, z; const char *headerToken; STBI_NOTUSED(ri); // Check identifier headerToken = stbi__hdr_gettoken(s,buffer); if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) return stbi__errpf("not HDR", "Corrupt HDR image"); // Parse header for(;;) { token = stbi__hdr_gettoken(s,buffer); if (token[0] == 0) break; if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; } if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); // Parse width and height // can't use sscanf() if we're not using stdio! token = stbi__hdr_gettoken(s,buffer); if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); token += 3; height = (int) strtol(token, &token, 10); while (*token == ' ') ++token; if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); token += 3; width = (int) strtol(token, NULL, 10); if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); *x = width; *y = height; if (comp) *comp = 3; if (req_comp == 0) req_comp = 3; if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) return stbi__errpf("too large", "HDR image is too large"); // Read data hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); if (!hdr_data) return stbi__errpf("outofmem", "Out of memory"); // Load image data // image data is stored as some number of sca if ( width < 8 || width >= 32768) { // Read flat data for (j=0; j < height; ++j) { for (i=0; i < width; ++i) { stbi_uc rgbe[4]; main_decode_loop: stbi__getn(s, rgbe, 4); stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); } } } else { // Read RLE-encoded data scanline = NULL; for (j = 0; j < height; ++j) { c1 = stbi__get8(s); c2 = stbi__get8(s); len = stbi__get8(s); if (c1 != 2 || c2 != 2 || (len & 0x80)) { // not run-length encoded, so we have to actually use THIS data as a decoded // pixel (note this can't be a valid pixel--one of RGB must be >= 128) stbi_uc rgbe[4]; rgbe[0] = (stbi_uc) c1; rgbe[1] = (stbi_uc) c2; rgbe[2] = (stbi_uc) len; rgbe[3] = (stbi_uc) stbi__get8(s); stbi__hdr_convert(hdr_data, rgbe, req_comp); i = 1; j = 0; STBI_FREE(scanline); goto main_decode_loop; // yes, this makes no sense } len <<= 8; len |= stbi__get8(s); if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } if (scanline == NULL) { scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); if (!scanline) { STBI_FREE(hdr_data); return stbi__errpf("outofmem", "Out of memory"); } } for (k = 0; k < 4; ++k) { int nleft; i = 0; while ((nleft = width - i) > 0) { count = stbi__get8(s); if (count > 128) { // Run value = stbi__get8(s); count -= 128; if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } } } for (i=0; i < width; ++i) stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); } if (scanline) STBI_FREE(scanline); } return hdr_data; } static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) { char buffer[STBI__HDR_BUFLEN]; char *token; int valid = 0; int dummy; if (!x) x = &dummy; if (!y) y = &dummy; if (!comp) comp = &dummy; if (stbi__hdr_test(s) == 0) { stbi__rewind( s ); return 0; } for(;;) { token = stbi__hdr_gettoken(s,buffer); if (token[0] == 0) break; if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; } if (!valid) { stbi__rewind( s ); return 0; } token = stbi__hdr_gettoken(s,buffer); if (strncmp(token, "-Y ", 3)) { stbi__rewind( s ); return 0; } token += 3; *y = (int) strtol(token, &token, 10); while (*token == ' ') ++token; if (strncmp(token, "+X ", 3)) { stbi__rewind( s ); return 0; } token += 3; *x = (int) strtol(token, NULL, 10); *comp = 3; return 1; } #endif // STBI_NO_HDR #ifndef STBI_NO_BMP static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) { void *p; stbi__bmp_data info; info.all_a = 255; p = stbi__bmp_parse_header(s, &info); if (p == NULL) { stbi__rewind( s ); return 0; } if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) { if (info.bpp == 24 && info.ma == 0xff000000) *comp = 3; else *comp = info.ma ? 4 : 3; } return 1; } #endif #ifndef STBI_NO_PSD static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { int channelCount, dummy, depth; if (!x) x = &dummy; if (!y) y = &dummy; if (!comp) comp = &dummy; if (stbi__get32be(s) != 0x38425053) { stbi__rewind( s ); return 0; } if (stbi__get16be(s) != 1) { stbi__rewind( s ); return 0; } stbi__skip(s, 6); channelCount = stbi__get16be(s); if (channelCount < 0 || channelCount > 16) { stbi__rewind( s ); return 0; } *y = stbi__get32be(s); *x = stbi__get32be(s); depth = stbi__get16be(s); if (depth != 8 && depth != 16) { stbi__rewind( s ); return 0; } if (stbi__get16be(s) != 3) { stbi__rewind( s ); return 0; } *comp = 4; return 1; } static int stbi__psd_is16(stbi__context *s) { int channelCount, depth; if (stbi__get32be(s) != 0x38425053) { stbi__rewind( s ); return 0; } if (stbi__get16be(s) != 1) { stbi__rewind( s ); return 0; } stbi__skip(s, 6); channelCount = stbi__get16be(s); if (channelCount < 0 || channelCount > 16) { stbi__rewind( s ); return 0; } STBI_NOTUSED(stbi__get32be(s)); STBI_NOTUSED(stbi__get32be(s)); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); return 0; } return 1; } #endif #ifndef STBI_NO_PIC static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) { int act_comp=0,num_packets=0,chained,dummy; stbi__pic_packet packets[10]; if (!x) x = &dummy; if (!y) y = &dummy; if (!comp) comp = &dummy; if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { stbi__rewind(s); return 0; } stbi__skip(s, 88); *x = stbi__get16be(s); *y = stbi__get16be(s); if (stbi__at_eof(s)) { stbi__rewind( s); return 0; } if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { stbi__rewind( s ); return 0; } stbi__skip(s, 8); do { stbi__pic_packet *packet; if (num_packets==sizeof(packets)/sizeof(packets[0])) return 0; packet = &packets[num_packets++]; chained = stbi__get8(s); packet->size = stbi__get8(s); packet->type = stbi__get8(s); packet->channel = stbi__get8(s); act_comp |= packet->channel; if (stbi__at_eof(s)) { stbi__rewind( s ); return 0; } if (packet->size != 8) { stbi__rewind( s ); return 0; } } while (chained); *comp = (act_comp & 0x10 ? 4 : 3); return 1; } #endif // ************************************************************************************************* // Portable Gray Map and Portable Pixel Map loader // by Ken Miller // // PGM: http://netpbm.sourceforge.net/doc/pgm.html // PPM: http://netpbm.sourceforge.net/doc/ppm.html // // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) #ifndef STBI_NO_PNM static int stbi__pnm_test(stbi__context *s) { char p, t; p = (char) stbi__get8(s); t = (char) stbi__get8(s); if (p != 'P' || (t != '5' && t != '6')) { stbi__rewind( s ); return 0; } return 1; } static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { stbi_uc *out; STBI_NOTUSED(ri); ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); if (ri->bits_per_channel == 0) return 0; if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); *x = s->img_x; *y = s->img_y; if (comp) *comp = s->img_n; if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) return stbi__errpuc("too large", "PNM too large"); out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); if (req_comp && req_comp != s->img_n) { out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; } static int stbi__pnm_isspace(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) { for (;;) { while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) *c = (char) stbi__get8(s); if (stbi__at_eof(s) || *c != '#') break; while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) *c = (char) stbi__get8(s); } } static int stbi__pnm_isdigit(char c) { return c >= '0' && c <= '9'; } static int stbi__pnm_getinteger(stbi__context *s, char *c) { int value = 0; while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); } return value; } static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { int maxv, dummy; char c, p, t; if (!x) x = &dummy; if (!y) y = &dummy; if (!comp) comp = &dummy; stbi__rewind(s); // Get identifier p = (char) stbi__get8(s); t = (char) stbi__get8(s); if (p != 'P' || (t != '5' && t != '6')) { stbi__rewind(s); return 0; } *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm c = (char) stbi__get8(s); stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value if (maxv > 65535) return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); else if (maxv > 255) return 16; else return 8; } static int stbi__pnm_is16(stbi__context *s) { if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) return 1; return 0; } #endif static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) { #ifndef STBI_NO_JPEG if (stbi__jpeg_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_PNG if (stbi__png_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_GIF if (stbi__gif_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_BMP if (stbi__bmp_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_PSD if (stbi__psd_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_PIC if (stbi__pic_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_PNM if (stbi__pnm_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_HDR if (stbi__hdr_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_DDS if (stbi__dds_info(s, x, y, comp, NULL)) return 1; #endif #ifndef STBI_NO_PVR if (stbi__pvr_info(s, x, y, comp, NULL)) return 1; #endif #ifndef STBI_NO_PKM if (stbi__pkm_info(s, x, y, comp)) return 1; #endif #ifndef STBI_NO_QOI if (stbi__qoi_info(s, x, y, comp)) return 1; #endif // test tga last because it's a crappy test! #ifndef STBI_NO_TGA if (stbi__tga_info(s, x, y, comp)) return 1; #endif return stbi__err("unknown image type", "Image not of any known type, or corrupt"); } static int stbi__is_16_main(stbi__context *s) { #ifndef STBI_NO_PNG if (stbi__png_is16(s)) return 1; #endif #ifndef STBI_NO_PSD if (stbi__psd_is16(s)) return 1; #endif #ifndef STBI_NO_PNM if (stbi__pnm_is16(s)) return 1; #endif return 0; } #ifndef STBI_NO_STDIO STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) { FILE *f = stbi__fopen(filename, "rb"); int result; if (!f) return stbi__err("can't fopen", "Unable to open file"); result = stbi_info_from_file(f, x, y, comp); fclose(f); return result; } STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) { int r; stbi__context s; long pos = ftell(f); stbi__start_file(&s, f); r = stbi__info_main(&s,x,y,comp); fseek(f,pos,SEEK_SET); return r; } STBIDEF int stbi_is_16_bit(char const *filename) { FILE *f = stbi__fopen(filename, "rb"); int result; if (!f) return stbi__err("can't fopen", "Unable to open file"); result = stbi_is_16_bit_from_file(f); fclose(f); return result; } STBIDEF int stbi_is_16_bit_from_file(FILE *f) { int r; stbi__context s; long pos = ftell(f); stbi__start_file(&s, f); r = stbi__is_16_main(&s); fseek(f,pos,SEEK_SET); return r; } #endif // !STBI_NO_STDIO STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi__info_main(&s,x,y,comp); } STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); return stbi__info_main(&s,x,y,comp); } STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi__is_16_main(&s); } STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); return stbi__is_16_main(&s); } // add in my DDS loading support #ifndef STBI_NO_DDS #include "stbi_DDS_c.h" #endif // add in my pvr loading support #ifndef STBI_NO_PVR #include "stbi_pvr_c.h" #endif // add in my pkm ( ETC1 ) loading support #ifndef STBI_NO_PKM #include "stbi_pkm_c.h" #endif #ifndef STBI_NO_EXT #include "stbi_ext_c.h" #endif // Quite OK Image loader // by Jack Bendtsen #ifndef STBI_NO_QOI #include "stbi_qoi_c.h" #endif #endif // STB_IMAGE_IMPLEMENTATION /* revision history: 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug 1-bit BMP *_is_16_bit api avoid warnings 2.16 (2017-07-23) all functions have 16-bit variants; STBI_NO_STDIO works again; compilation fixes; fix rounding in unpremultiply; optimize vertical flip; disable raw_len validation; documentation fixes 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; warning fixes; disable run-time SSE detection on gcc; uniform handling of optional "return" values; thread-safe initialization of zlib tables 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes 2.11 (2016-04-02) allocate large structures on the stack remove white matting for transparent PSD fix reported channel count for PNG & BMP re-enable SSE2 in non-gcc 64-bit support RGB-formatted JPEG read 16-bit PNGs (only as 8-bit) 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED 2.09 (2016-01-16) allow comments in PNM files 16-bit-per-pixel TGA (not bit-per-component) info() for TGA could break due to .hdr handling info() for BMP to shares code instead of sloppy parse can use STBI_REALLOC_SIZED if allocator doesn't support realloc code cleanup 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.07 (2015-09-13) fix compiler warnings partial animated GIF support limited 16-bpc PSD support #ifdef unused functions bug with < 92 byte PIC,PNM,HDR,TGA 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit 2.03 (2015-04-12) extra corruption checking (mmozeiko) stbi_set_flip_vertically_on_load (nguillemot) fix NEON support; fix mingw support 2.02 (2015-01-19) fix incorrect assert, fix warning 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) progressive JPEG (stb) PGM/PPM support (Ken Miller) STBI_MALLOC,STBI_REALLOC,STBI_FREE GIF bugfix -- seemingly never worked STBI_NO_*, STBI_ONLY_* 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) optimize PNG (ryg) fix bug in interlaced PNG with user-specified channel count (stb) 1.46 (2014-08-26) fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG 1.45 (2014-08-16) fix MSVC-ARM internal compiler error by wrapping malloc 1.44 (2014-08-07) various warning fixes from Ronny Chevalier 1.43 (2014-07-15) fix MSVC-only compiler problem in code changed in 1.42 1.42 (2014-07-09) don't define _CRT_SECURE_NO_WARNINGS (affects user code) fixes to stbi__cleanup_jpeg path added STBI_ASSERT to avoid requiring assert.h 1.41 (2014-06-25) fix search&replace from 1.36 that messed up comments/error messages 1.40 (2014-06-22) fix gcc struct-initialization warning 1.39 (2014-06-15) fix to TGA optimization when req_comp != number of components in TGA; fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) add support for BMP version 5 (more ignored fields) 1.38 (2014-06-06) suppress MSVC warnings on integer casts truncating values fix accidental rename of 'skip' field of I/O 1.37 (2014-06-04) remove duplicate typedef 1.36 (2014-06-03) convert to header file single-file library if de-iphone isn't set, load iphone images color-swapped instead of returning NULL 1.35 (2014-05-27) various warnings fix broken STBI_SIMD path fix bug where stbi_load_from_file no longer left file pointer in correct place fix broken non-easy path for 32-bit BMP (possibly never used) TGA optimization by Arseny Kapoulkine 1.34 (unknown) use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case 1.33 (2011-07-14) make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements 1.32 (2011-07-13) support for "info" function for all supported filetypes (SpartanJ) 1.31 (2011-06-20) a few more leak fixes, bug in PNG handling (SpartanJ) 1.30 (2011-06-11) added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) removed deprecated format-specific test/load functions removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) fix inefficiency in decoding 32-bit BMP (David Woo) 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) 1.27 (2010-08-01) cast-to-stbi_uc to fix warnings 1.26 (2010-07-24) fix bug in file buffering for PNG reported by SpartanJ 1.25 (2010-07-17) refix trans_data warning (Won Chun) 1.24 (2010-07-12) perf improvements reading from files on platforms with lock-heavy fgetc() minor perf improvements for jpeg deprecated type-specific functions so we'll get feedback if they're needed attempt to fix trans_data warning (Won Chun) 1.23 fixed bug in iPhone support 1.22 (2010-07-10) removed image *writing* support stbi_info support from Jetro Lauha GIF support from Jean-Marc Lienher iPhone PNG-extensions from James Brown warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) 1.21 fix use of 'stbi_uc' in header (reported by jon blow) 1.20 added support for Softimage PIC, by Tom Seddon 1.19 bug in interlaced PNG corruption check (found by ryg) 1.18 (2008-08-02) fix a threading bug (local mutable static) 1.17 support interlaced PNG 1.16 major bugfix - stbi__convert_format converted one too many pixels 1.15 initialize some fields for thread safety 1.14 fix threadsafe conversion bug header-file-only version (#define STBI_HEADER_FILE_ONLY before including) 1.13 threadsafe 1.12 const qualifiers in the API 1.11 Support installable IDCT, colorspace conversion routines 1.10 Fixes for 64-bit (don't use "unsigned long") optimized upsampling by Fabian "ryg" Giesen 1.09 Fix format-conversion for PSD code (bad global variables!) 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz 1.07 attempt to fix C++ warning/errors again 1.06 attempt to fix C++ warning/errors again 1.05 fix TGA loading to return correct *comp and use good luminance calc 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR 1.02 support for (subset of) HDR files, float interface for preferred access to them 1.01 fix bug: possible bug in handling right-side up bmps... not sure fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all 1.00 interface to zlib that skips zlib header 0.99 correct handling of alpha in palette 0.98 TGA loader by lonesock; dynamically add loaders (untested) 0.97 jpeg errors on too large a file; also catch another malloc failure 0.96 fix detection of invalid v value - particleman@mollyrocket forum 0.95 during header scan, seek to markers in case of padding 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same 0.93 handle jpegtran output; verbose errors 0.92 read 4,8,16,24,32-bit BMP files of several formats 0.91 output 24-bit Windows 3.0 BMP files 0.90 fix a few more warnings; bump version number to approach 1.0 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd 0.60 fix compiling as c++ 0.59 fix warnings: merge Dave Moore's -Wall fixes 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available 0.56 fix bug: zlib uncompressed mode len vs. nlen 0.55 fix bug: restart_interval not initialized to 0 0.54 allow NULL for 'int *comp' 0.53 fix bug in png 3->4; speedup png decoding 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments 0.51 obey req_comp requests, 1-component jpegs return as 1-component, on 'test' only check type, not whether we support this variant 0.50 (2006-11-19) first released version */ /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ */ ================================================ FILE: lib/SOIL2/stb_image_write.h ================================================ /* stb_image_write - v1.16 - public domain - http://nothings.org/stb writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 no warranty implied; use at your own risk Before #including, #define STB_IMAGE_WRITE_IMPLEMENTATION in the file that you want to have the implementation. Will probably not work correctly with strict-aliasing optimizations. ABOUT: This header file is a library for writing images to C stdio or a callback. The PNG output is not optimal; it is 20-50% larger than the file written by a decent optimizing implementation; though providing a custom zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. This library is designed for source code compactness and simplicity, not optimal image file size or run-time performance. BUILDING: You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace malloc,realloc,free. You can #define STBIW_MEMMOVE() to replace memmove() You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function for PNG compression (instead of the builtin one), it must have the following signature: unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); The returned data will be freed with STBIW_FREE() (free() by default), so it must be heap allocated with STBIW_MALLOC() (malloc() by default), UNICODE: If compiling for Windows and you wish to use Unicode filenames, compile with #define STBIW_WINDOWS_UTF8 and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert Windows wchar_t filenames to utf8. USAGE: There are five functions, one for each image file format: int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality); int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically There are also five equivalent functions that use an arbitrary write function. You are expected to open/close your file-equivalent before and after calling these: int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); where the callback is: void stbi_write_func(void *context, void *data, int size); You can configure it with these global variables: int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode You can define STBI_WRITE_NO_STDIO to disable the file variant of these functions, so the library will not use stdio.h at all. However, this will also disable HDR writing, because it requires stdio for formatted output. Each function returns 0 on failure and non-0 on success. The functions create an image file defined by the parameters. The image is a rectangle of pixels stored from left-to-right, top-to-bottom. Each pixel contains 'comp' channels of data stored interleaved with 8-bits per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. The *data pointer points to the first byte of the top-left-most pixel. For PNG, "stride_in_bytes" is the distance in bytes from the first byte of a row of pixels to the first byte of the next row of pixels. PNG creates output files with the same number of components as the input. The BMP format expands Y to RGB in the file format and does not output alpha. PNG supports writing rectangles of data even when the bytes storing rows of data are not consecutive in memory (e.g. sub-rectangles of a larger image), by supplying the stride between the beginning of adjacent rows. The other formats do not. (Thus you cannot write a native-format BMP through the BMP writer, both because it is in BGR order and because it may have padding at the end of the line.) PNG allows you to set the deflate compression level by setting the global variable 'stbi_write_png_compression_level' (it defaults to 8). HDR expects linear float data. Since the format is always 32-bit rgb(e) data, alpha (if provided) is discarded, and for monochrome data it is replicated across all three channels. TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed data, set the global variable 'stbi_write_tga_with_rle' to 0. JPEG does ignore alpha channels in input data; quality is between 1 and 100. Higher quality looks better but results in a bigger image. JPEG baseline (no JPEG progressive). CREDITS: Sean Barrett - PNG/BMP/TGA Baldur Karlsson - HDR Jean-Sebastien Guay - TGA monochrome Tim Kelsey - misc enhancements Alan Hickman - TGA RLE Emmanuel Julien - initial file IO callback implementation Jon Olick - original jo_jpeg.cpp code Daniel Gibson - integrate JPEG, allow external zlib Aarni Koskela - allow choosing PNG filter bugfixes: github:Chribba Guillaume Chereau github:jry2 github:romigrou Sergio Gonzalez Jonas Karlsson Filip Wasil Thatcher Ulrich github:poppolopoppo Patrick Boettcher github:xeekworx Cap Petschulat Simon Rodriguez Ivan Tikhonov github:ignotion Adam Schackart Andrew Kensler LICENSE See end of file for license information. */ #ifndef INCLUDE_STB_IMAGE_WRITE_H #define INCLUDE_STB_IMAGE_WRITE_H #include // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' #ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC #define STBIWDEF static #else #ifdef __cplusplus #define STBIWDEF extern "C" #else #define STBIWDEF extern #endif #endif #endif #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations STBIWDEF int stbi_write_tga_with_rle; STBIWDEF int stbi_write_png_compression_level; STBIWDEF int stbi_write_force_png_filter; #endif #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); #ifndef STBI_WRITE_NO_QOI STBIWDEF int stbi_write_qoi(char const *filename, int w, int h, int comp, const void *data); #endif #ifdef STBIW_WINDOWS_UTF8 STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); #endif #endif typedef void stbi_write_func(void *context, void *data, int size); STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); #ifndef STBI_WRITE_NO_QOI STBIWDEF int stbi_write_qoi_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); #endif STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); #endif//INCLUDE_STB_IMAGE_WRITE_H #ifdef STB_IMAGE_WRITE_IMPLEMENTATION #ifdef _WIN32 #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #ifndef _CRT_NONSTDC_NO_DEPRECATE #define _CRT_NONSTDC_NO_DEPRECATE #endif #endif #ifndef STBI_WRITE_NO_STDIO #include #endif // STBI_WRITE_NO_STDIO #include #include #include #include #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) // ok #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) // ok #else #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." #endif #ifndef STBIW_MALLOC #define STBIW_MALLOC(sz) malloc(sz) #define STBIW_REALLOC(p,newsz) realloc(p,newsz) #define STBIW_FREE(p) free(p) #endif #ifndef STBIW_REALLOC_SIZED #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) #endif #ifndef STBIW_MEMMOVE #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) #endif #ifndef STBIW_ASSERT #include #define STBIW_ASSERT(x) assert(x) #endif #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) #ifdef STB_IMAGE_WRITE_STATIC static int stbi_write_png_compression_level = 8; static int stbi_write_tga_with_rle = 1; static int stbi_write_force_png_filter = -1; #else int stbi_write_png_compression_level = 8; int stbi_write_tga_with_rle = 1; int stbi_write_force_png_filter = -1; #endif static int stbi__flip_vertically_on_write = 0; STBIWDEF void stbi_flip_vertically_on_write(int flag) { stbi__flip_vertically_on_write = flag; } typedef struct { stbi_write_func *func; void *context; unsigned char buffer[64]; int buf_used; } stbi__write_context; // initialize a callback-based context static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) { s->func = c; s->context = context; } #ifndef STBI_WRITE_NO_STDIO static void stbi__stdio_write(void *context, void *data, int size) { fwrite(data,1,size,(FILE*) context); } #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) #ifdef __cplusplus #define STBIW_EXTERN extern "C" #else #define STBIW_EXTERN extern #endif STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); } #endif static FILE *stbiw__fopen(char const *filename, char const *mode) { FILE *f; #if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; #if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != fopen_s(&f, filename, mode)) f=0; #else f = fopen(filename, mode); #endif return f; } static int stbi__start_write_file(stbi__write_context *s, const char *filename) { FILE *f = stbiw__fopen(filename, "wb"); stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); return f != NULL; } static void stbi__end_write_file(stbi__write_context *s) { fclose((FILE *)s->context); } #endif // !STBI_WRITE_NO_STDIO typedef unsigned int stbiw_uint32; typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) { while (*fmt) { switch (*fmt++) { case ' ': break; case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); s->func(s->context,&x,1); break; } case '2': { int x = va_arg(v,int); unsigned char b[2]; b[0] = STBIW_UCHAR(x); b[1] = STBIW_UCHAR(x>>8); s->func(s->context,b,2); break; } case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4]; b[0]=STBIW_UCHAR(x); b[1]=STBIW_UCHAR(x>>8); b[2]=STBIW_UCHAR(x>>16); b[3]=STBIW_UCHAR(x>>24); s->func(s->context,b,4); break; } default: STBIW_ASSERT(0); return; } } } static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) { va_list v; va_start(v, fmt); stbiw__writefv(s, fmt, v); va_end(v); } static void stbiw__write_flush(stbi__write_context *s) { if (s->buf_used) { s->func(s->context, &s->buffer, s->buf_used); s->buf_used = 0; } } static void stbiw__putc(stbi__write_context *s, unsigned char c) { s->func(s->context, &c, 1); } static void stbiw__write1(stbi__write_context *s, unsigned char a) { if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) stbiw__write_flush(s); s->buffer[s->buf_used++] = a; } static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { int n; if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) stbiw__write_flush(s); n = s->buf_used; s->buf_used = n+3; s->buffer[n+0] = a; s->buffer[n+1] = b; s->buffer[n+2] = c; } static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) { unsigned char bg[3] = { 255, 0, 255}, px[3]; int k; if (write_alpha < 0) stbiw__write1(s, d[comp - 1]); switch (comp) { case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case case 1: if (expand_mono) stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp else stbiw__write1(s, d[0]); // monochrome TGA break; case 4: if (!write_alpha) { // composite against pink background for (k = 0; k < 3; ++k) px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); break; } /* FALLTHROUGH */ case 3: stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); break; } if (write_alpha > 0) stbiw__write1(s, d[comp - 1]); } static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) { stbiw_uint32 zero = 0; int i,j, j_end; if (y <= 0) return; if (stbi__flip_vertically_on_write) vdir *= -1; if (vdir < 0) { j_end = -1; j = y-1; } else { j_end = y; j = 0; } for (; j != j_end; j += vdir) { for (i=0; i < x; ++i) { unsigned char *d = (unsigned char *) data + (j*x+i)*comp; stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); } stbiw__write_flush(s); s->func(s->context, &zero, scanline_pad); } } static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) { if (y < 0 || x < 0) { return 0; } else { va_list v; va_start(v, fmt); stbiw__writefv(s, fmt, v); va_end(v); stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); return 1; } } static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) { if (comp != 4) { // write RGB bitmap int pad = (-x*3) & 3; return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, "11 4 22 4" "4 44 22 444444", 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header } else { // RGBA bitmaps need a v4 header // use BI_BITFIELDS mode with 32bpp and alpha mask // (straight BI_RGB with alpha mask doesn't work in most readers) return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", 'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header } } STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_bmp_core(&s, x, y, comp, data); } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_bmp_core(&s, x, y, comp, data); stbi__end_write_file(&s); return r; } else return 0; } #endif //!STBI_WRITE_NO_STDIO static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) { int has_alpha = (comp == 2 || comp == 4); int colorbytes = has_alpha ? comp-1 : comp; int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 if (y < 0 || x < 0) return 0; if (!stbi_write_tga_with_rle) { return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); } else { int i,j,k; int jend, jdir; stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); if (stbi__flip_vertically_on_write) { j = 0; jend = y; jdir = 1; } else { j = y-1; jend = -1; jdir = -1; } for (; j != jend; j += jdir) { unsigned char *row = (unsigned char *) data + j * x * comp; int len; for (i = 0; i < x; i += len) { unsigned char *begin = row + i * comp; int diff = 1; len = 1; if (i < x - 1) { ++len; diff = memcmp(begin, row + (i + 1) * comp, comp); if (diff) { const unsigned char *prev = begin; for (k = i + 2; k < x && len < 128; ++k) { if (memcmp(prev, row + k * comp, comp)) { prev += comp; ++len; } else { --len; break; } } } else { for (k = i + 2; k < x && len < 128; ++k) { if (!memcmp(begin, row + k * comp, comp)) { ++len; } else { break; } } } } if (diff) { unsigned char header = STBIW_UCHAR(len - 1); stbiw__write1(s, header); for (k = 0; k < len; ++k) { stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); } } else { unsigned char header = STBIW_UCHAR(len - 129); stbiw__write1(s, header); stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); } } } stbiw__write_flush(s); } return 1; } STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_tga_core(&s, x, y, comp, (void *) data); } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); stbi__end_write_file(&s); return r; } else return 0; } #endif // ************************************************************************************************* // Radiance RGBE HDR writer // by Baldur Karlsson #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) #ifndef STBI_WRITE_NO_STDIO static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { int exponent; float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); if (maxcomp < 1e-32f) { rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; } else { float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; rgbe[0] = (unsigned char)(linear[0] * normalize); rgbe[1] = (unsigned char)(linear[1] * normalize); rgbe[2] = (unsigned char)(linear[2] * normalize); rgbe[3] = (unsigned char)(exponent + 128); } } static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) { unsigned char lengthbyte = STBIW_UCHAR(length+128); STBIW_ASSERT(length+128 <= 255); s->func(s->context, &lengthbyte, 1); s->func(s->context, &databyte, 1); } static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) { unsigned char lengthbyte = STBIW_UCHAR(length); STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code s->func(s->context, &lengthbyte, 1); s->func(s->context, data, length); } static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) { unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; unsigned char rgbe[4]; float linear[3]; int x; scanlineheader[2] = (width&0xff00)>>8; scanlineheader[3] = (width&0x00ff); /* skip RLE for images too small or large */ if (width < 8 || width >= 32768) { for (x=0; x < width; x++) { switch (ncomp) { case 4: /* fallthrough */ case 3: linear[2] = scanline[x*ncomp + 2]; linear[1] = scanline[x*ncomp + 1]; linear[0] = scanline[x*ncomp + 0]; break; default: linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; break; } stbiw__linear_to_rgbe(rgbe, linear); s->func(s->context, rgbe, 4); } } else { int c,r; /* encode into scratch buffer */ for (x=0; x < width; x++) { switch(ncomp) { case 4: /* fallthrough */ case 3: linear[2] = scanline[x*ncomp + 2]; linear[1] = scanline[x*ncomp + 1]; linear[0] = scanline[x*ncomp + 0]; break; default: linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; break; } stbiw__linear_to_rgbe(rgbe, linear); scratch[x + width*0] = rgbe[0]; scratch[x + width*1] = rgbe[1]; scratch[x + width*2] = rgbe[2]; scratch[x + width*3] = rgbe[3]; } s->func(s->context, scanlineheader, 4); /* RLE each component separately */ for (c=0; c < 4; c++) { unsigned char *comp = &scratch[width*c]; x = 0; while (x < width) { // find first run r = x; while (r+2 < width) { if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) break; ++r; } if (r+2 >= width) r = width; // dump up to first run while (x < r) { int len = r-x; if (len > 128) len = 128; stbiw__write_dump_data(s, len, &comp[x]); x += len; } // if there's a run, output it if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd // find next byte after run while (r < width && comp[r] == comp[x]) ++r; // output run up to r while (x < r) { int len = r-x; if (len > 127) len = 127; stbiw__write_run_data(s, len, comp[x]); x += len; } } } } } } static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) { if (y <= 0 || x <= 0 || data == NULL) return 0; else { // Each component is stored separately. Allocate scratch space for full output scanline. unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); int i, len; char buffer[128]; char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; s->func(s->context, header, sizeof(header)-1); #ifdef __STDC_LIB_EXT1__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif s->func(s->context, buffer, len); for(i=0; i < y; i++) stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); STBIW_FREE(scratch); return 1; } } STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_hdr_core(&s, x, y, comp, (float *) data); } STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); stbi__end_write_file(&s); return r; } else return 0; } #endif // STBI_WRITE_NO_STDIO ////////////////////////////////////////////////////////////////////////////// // // PNG writer // #ifndef STBIW_ZLIB_COMPRESS // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() #define stbiw__sbraw(a) ((int *) (void *) (a) - 2) #define stbiw__sbm(a) stbiw__sbraw(a)[0] #define stbiw__sbn(a) stbiw__sbraw(a)[1] #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) { int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); STBIW_ASSERT(p); if (p) { if (!*arr) ((int *) p)[1] = 0; *arr = (void *) ((int *) p + 2); stbiw__sbm(*arr) = m; } return *arr; } static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) { while (*bitcount >= 8) { stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); *bitbuffer >>= 8; *bitcount -= 8; } return data; } static int stbiw__zlib_bitrev(int code, int codebits) { int res=0; while (codebits--) { res = (res << 1) | (code & 1); code >>= 1; } return res; } static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) { int i; for (i=0; i < limit && i < 258; ++i) if (a[i] != b[i]) break; return i; } static unsigned int stbiw__zhash(unsigned char *data) { stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); hash ^= hash << 3; hash += hash >> 5; hash ^= hash << 4; hash += hash >> 17; hash ^= hash << 25; hash += hash >> 6; return hash; } #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) #define stbiw__zlib_add(code,codebits) \ (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) // default huffman tables #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) #define stbiw__ZHASH 16384 #endif // STBIW_ZLIB_COMPRESS STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS // user provided a zlib compress implementation, use that return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); #else // use builtin static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; unsigned int bitbuf=0; int i,j, bitcount=0; unsigned char *out = NULL; unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); if (hash_table == NULL) return NULL; if (quality < 5) quality = 5; stbiw__sbpush(out, 0x78); // DEFLATE 32K window stbiw__sbpush(out, 0x5e); // FLEVEL = 1 stbiw__zlib_add(1,1); // BFINAL = 1 stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman for (i=0; i < stbiw__ZHASH; ++i) hash_table[i] = NULL; i=0; while (i < data_len-3) { // hash next 3 bytes of data to be compressed int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; unsigned char *bestloc = 0; unsigned char **hlist = hash_table[h]; int n = stbiw__sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32768) { // if entry lies within window int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); if (d >= best) { best=d; bestloc=hlist[j]; } } } // when hash table entry is too long, delete half the entries if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); stbiw__sbn(hash_table[h]) = quality; } stbiw__sbpush(hash_table[h],data+i); if (bestloc) { // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); hlist = hash_table[h]; n = stbiw__sbcount(hlist); for (j=0; j < n; ++j) { if (hlist[j]-data > i-32767) { int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); if (e > best) { // if next match is better, bail on current match bestloc = NULL; break; } } } } if (bestloc) { int d = (int) (data+i - bestloc); // distance back STBIW_ASSERT(d <= 32767 && best <= 258); for (j=0; best > lengthc[j+1]-1; ++j); stbiw__zlib_huff(j+257); if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); for (j=0; d > distc[j+1]-1; ++j); stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); i += best; } else { stbiw__zlib_huffb(data[i]); ++i; } } // write out final bytes for (;i < data_len; ++i) stbiw__zlib_huffb(data[i]); stbiw__zlib_huff(256); // end of block // pad with 0 bits to byte boundary while (bitcount) stbiw__zlib_add(0,1); for (i=0; i < stbiw__ZHASH; ++i) (void) stbiw__sbfree(hash_table[i]); STBIW_FREE(hash_table); // store uncompressed instead if compression was worse if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 for (j = 0; j < data_len;) { int blocklen = data_len - j; if (blocklen > 32767) blocklen = 32767; stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); memcpy(out+stbiw__sbn(out), data+j, blocklen); stbiw__sbn(out) += blocklen; j += blocklen; } } { // compute adler32 on input unsigned int s1=1, s2=0; int blocklen = (int) (data_len % 5552); j=0; while (j < data_len) { for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } s1 %= 65521; s2 %= 65521; j += blocklen; blocklen = 5552; } stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s2)); stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); stbiw__sbpush(out, STBIW_UCHAR(s1)); } *out_len = stbiw__sbn(out); // make returned pointer freeable STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); return (unsigned char *) stbiw__sbraw(out); #endif // STBIW_ZLIB_COMPRESS } static unsigned int stbiw__crc32(unsigned char *buffer, int len) { #ifdef STBIW_CRC32 return STBIW_CRC32(buffer, len); #else static unsigned int crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; unsigned int crc = ~0u; int i; for (i=0; i < len; ++i) crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; return ~crc; #endif } #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) static void stbiw__wpcrc(unsigned char **data, int len) { unsigned int crc = stbiw__crc32(*data - len - 4, len+4); stbiw__wp32(*data, crc); } static unsigned char stbiw__paeth(int a, int b, int c) { int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); if (pb <= pc) return STBIW_UCHAR(b); return STBIW_UCHAR(c); } // @OPTIMIZE: provide an option that always forces left-predict or paeth predict static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) { static int mapping[] = { 0,1,2,3,4 }; static int firstmap[] = { 0,1,0,5,6 }; int *mymap = (y != 0) ? mapping : firstmap; int i; int type = mymap[filter_type]; unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; if (type==0) { memcpy(line_buffer, z, width*n); return; } // first loop isn't optimized since it's just one pixel for (i = 0; i < n; ++i) { switch (type) { case 1: line_buffer[i] = z[i]; break; case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; case 5: line_buffer[i] = z[i]; break; case 6: line_buffer[i] = z[i]; break; } } switch (type) { case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; } } STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { int force_filter = stbi_write_force_png_filter; int ctype[5] = { -1, 0, 4, 2, 6 }; unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; unsigned char *out,*o, *filt, *zlib; signed char *line_buffer; int j,zlen; if (stride_bytes == 0) stride_bytes = x * n; if (force_filter >= 5) { force_filter = -1; } filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } for (j=0; j < y; ++j) { int filter_type; if (force_filter > -1) { filter_type = force_filter; stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); } else { // Estimate the best filter by running through all of them: int best_filter = 0, best_filter_val = 0x7fffffff, est, i; for (filter_type = 0; filter_type < 5; filter_type++) { stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); // Estimate the entropy of the line using this filter; the less, the better. est = 0; for (i = 0; i < x*n; ++i) { est += abs((signed char) line_buffer[i]); } if (est < best_filter_val) { best_filter_val = est; best_filter = filter_type; } } if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); filter_type = best_filter; } } // when we get here, filter_type contains the filter type, and line_buffer contains the data filt[j*(x*n+1)] = (unsigned char) filter_type; STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); } STBIW_FREE(line_buffer); zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); STBIW_FREE(filt); if (!zlib) return 0; // each tag requires 12 bytes of overhead out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); if (!out) return 0; *out_len = 8 + 12+13 + 12+zlen + 12; o=out; STBIW_MEMMOVE(o,sig,8); o+= 8; stbiw__wp32(o, 13); // header length stbiw__wptag(o, "IHDR"); stbiw__wp32(o, x); stbiw__wp32(o, y); *o++ = 8; *o++ = STBIW_UCHAR(ctype[n]); *o++ = 0; *o++ = 0; *o++ = 0; stbiw__wpcrc(&o,13); stbiw__wp32(o, zlen); stbiw__wptag(o, "IDAT"); STBIW_MEMMOVE(o, zlib, zlen); o += zlen; STBIW_FREE(zlib); stbiw__wpcrc(&o, zlen); stbiw__wp32(o,0); stbiw__wptag(o, "IEND"); stbiw__wpcrc(&o,0); STBIW_ASSERT(o == out + *out_len); return out; } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) { FILE *f; int len; unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; f = stbiw__fopen(filename, "wb"); if (!f) { STBIW_FREE(png); return 0; } fwrite(png, 1, len, f); fclose(f); STBIW_FREE(png); return 1; } #endif STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) { int len; unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); if (png == NULL) return 0; func(context, png, len); STBIW_FREE(png); return 1; } /* *************************************************************************** * * JPEG writer * * This is based on Jon Olick's jo_jpeg.cpp: * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html */ static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { int bitBuf = *bitBufP, bitCnt = *bitCntP; bitCnt += bs[1]; bitBuf |= bs[0] << (24 - bitCnt); while(bitCnt >= 8) { unsigned char c = (bitBuf >> 16) & 255; stbiw__putc(s, c); if(c == 255) { stbiw__putc(s, 0); } bitBuf <<= 8; bitCnt -= 8; } *bitBufP = bitBuf; *bitCntP = bitCnt; } static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; float z1, z2, z3, z4, z5, z11, z13; float tmp0 = d0 + d7; float tmp7 = d0 - d7; float tmp1 = d1 + d6; float tmp6 = d1 - d6; float tmp2 = d2 + d5; float tmp5 = d2 - d5; float tmp3 = d3 + d4; float tmp4 = d3 - d4; // Even part float tmp10 = tmp0 + tmp3; // phase 2 float tmp13 = tmp0 - tmp3; float tmp11 = tmp1 + tmp2; float tmp12 = tmp1 - tmp2; d0 = tmp10 + tmp11; // phase 3 d4 = tmp10 - tmp11; z1 = (tmp12 + tmp13) * 0.707106781f; // c4 d2 = tmp13 + z1; // phase 5 d6 = tmp13 - z1; // Odd part tmp10 = tmp4 + tmp5; // phase 2 tmp11 = tmp5 + tmp6; tmp12 = tmp6 + tmp7; // The rotator is modified from fig 4-8 to avoid extra negations. z5 = (tmp10 - tmp12) * 0.382683433f; // c6 z2 = tmp10 * 0.541196100f + z5; // c2-c6 z4 = tmp12 * 1.306562965f + z5; // c2+c6 z3 = tmp11 * 0.707106781f; // c4 z11 = tmp7 + z3; // phase 5 z13 = tmp7 - z3; *d5p = z13 + z2; // phase 6 *d3p = z13 - z2; *d1p = z11 + z4; *d7p = z11 - z4; *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; } static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { int tmp1 = val < 0 ? -val : val; val = val < 0 ? val-1 : val; bits[1] = 1; while(tmp1 >>= 1) { ++bits[1]; } bits[0] = val & ((1<0)&&(DU[end0pos]==0); --end0pos) { } // end0pos = first element in reverse order !=0 if(end0pos == 0) { stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); return DU[0]; } for(i = 1; i <= end0pos; ++i) { int startpos = i; int nrzeroes; unsigned short bits[2]; for (; DU[i]==0 && i<=end0pos; ++i) { } nrzeroes = i-startpos; if ( nrzeroes >= 16 ) { int lng = nrzeroes>>4; int nrmarker; for (nrmarker=1; nrmarker <= lng; ++nrmarker) stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); nrzeroes &= 15; } stbiw__jpg_calcBits(DU[i], bits); stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); } if(end0pos != 63) { stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); } return DU[0]; } static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { // Constants that don't pollute global namespace static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; static const unsigned char std_ac_luminance_values[] = { 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa }; static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; static const unsigned char std_ac_chrominance_values[] = { 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa }; // Huffman tables static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; static const unsigned short YAC_HT[256][2] = { {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} }; static const unsigned short UVAC_HT[256][2] = { {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} }; static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; int row, col, i, k, subsample; float fdtbl_Y[64], fdtbl_UV[64]; unsigned char YTable[64], UVTable[64]; if(!data || !width || !height || comp > 4 || comp < 1) { return 0; } quality = quality ? quality : 90; subsample = quality <= 90 ? 1 : 0; quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; quality = quality < 50 ? 5000 / quality : 200 - quality * 2; for(i = 0; i < 64; ++i) { int uvti, yti = (YQT[i]*quality+50)/100; YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); uvti = (UVQT[i]*quality+50)/100; UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); } for(row = 0, k = 0; row < 8; ++row) { for(col = 0; col < 8; ++col, ++k) { fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); } } // Write Headers { static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; s->func(s->context, (void*)head0, sizeof(head0)); s->func(s->context, (void*)YTable, sizeof(YTable)); stbiw__putc(s, 1); s->func(s->context, UVTable, sizeof(UVTable)); s->func(s->context, (void*)head1, sizeof(head1)); s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); stbiw__putc(s, 0x10); // HTYACinfo s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); stbiw__putc(s, 1); // HTUDCinfo s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); stbiw__putc(s, 0x11); // HTUACinfo s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); s->func(s->context, (void*)head2, sizeof(head2)); } // Encode 8x8 macroblocks { static const unsigned short fillBits[] = {0x7F, 7}; int DCY=0, DCU=0, DCV=0; int bitBuf=0, bitCnt=0; // comp == 2 is grey+alpha (alpha is ignored) int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; const unsigned char *dataR = (const unsigned char *)data; const unsigned char *dataG = dataR + ofsG; const unsigned char *dataB = dataR + ofsB; int x, y, pos; if(subsample) { for(y = 0; y < height; y += 16) { for(x = 0; x < width; x += 16) { float Y[256], U[256], V[256]; for(row = y, pos = 0; row < y+16; ++row) { // row >= height => use last input row int clamped_row = (row < height) ? row : height - 1; int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; for(col = x; col < x+16; ++col, ++pos) { // if col >= width => use pixel from last input column int p = base_p + ((col < width) ? col : (width-1))*comp; float r = dataR[p], g = dataG[p], b = dataB[p]; Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; } } DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); // subsample U,V { float subU[64], subV[64]; int yy, xx; for(yy = 0, pos = 0; yy < 8; ++yy) { for(xx = 0; xx < 8; ++xx, ++pos) { int j = yy*32+xx*2; subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; } } DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } } } } else { for(y = 0; y < height; y += 8) { for(x = 0; x < width; x += 8) { float Y[64], U[64], V[64]; for(row = y, pos = 0; row < y+8; ++row) { // row >= height => use last input row int clamped_row = (row < height) ? row : height - 1; int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; for(col = x; col < x+8; ++col, ++pos) { // if col >= width => use pixel from last input column int p = base_p + ((col < width) ? col : (width-1))*comp; float r = dataR[p], g = dataG[p], b = dataB[p]; Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; } } DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } } } // Do the bit alignment of the EOI marker stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); } // EOI stbiw__putc(s, 0xFF); stbiw__putc(s, 0xD9); return 1; } STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); stbi__end_write_file(&s); return r; } else return 0; } #endif #ifndef STBI_WRITE_NO_QOI #include "stbi_qoi_write.h" #endif #endif // STB_IMAGE_WRITE_IMPLEMENTATION /* Revision history 1.16 (2021-07-11) make Deflate code emit uncompressed blocks when it would otherwise expand support writing BMPs with alpha channel 1.15 (2020-07-13) unknown 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels 1.13 1.12 1.11 (2019-08-11) 1.10 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 1.09 (2018-02-11) fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter 1.07 (2017-07-24) doc fix 1.06 (2017-07-23) writing JPEG (using Jon Olick's code) 1.05 ??? 1.04 (2017-03-03) monochrome BMP expansion 1.03 ??? 1.02 (2016-04-02) avoid allocating large structures on the stack 1.01 (2016-01-16) STBIW_REALLOC_SIZED: support allocators with no realloc support avoid race-condition in crc initialization minor compile issues 1.00 (2015-09-14) installable file IO function 0.99 (2015-09-13) warning fixes; TGA rle support 0.98 (2015-04-08) added STBIW_MALLOC, STBIW_ASSERT etc 0.97 (2015-01-18) fixed HDR asserts, rewrote HDR rle logic 0.96 (2015-01-17) add HDR output fix monochrome BMP 0.95 (2014-08-17) add monochrome TGA output 0.94 (2014-05-31) rename private functions to avoid conflicts with stb_image.h 0.93 (2014-05-27) warning fixes 0.92 (2010-08-01) casts to unsigned char to fix warnings 0.91 (2010-07-17) first public release 0.90 first internal release */ /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------ ALTERNATIVE A - MIT License Copyright (c) 2017 Sean Barrett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ ALTERNATIVE B - Public Domain (www.unlicense.org) This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------ */ ================================================ FILE: lib/SOIL2/stbi_DDS.h ================================================ /* adding DDS loading support to stbi */ #ifndef HEADER_STB_IMAGE_DDS_AUGMENTATION #define HEADER_STB_IMAGE_DDS_AUGMENTATION /* is it a DDS file? */ extern int stbi__dds_test_memory (stbi_uc const *buffer, int len); extern int stbi__dds_test_callbacks (stbi_io_callbacks const *clbk, void *user); extern void *stbi__dds_load_from_path (const char *filename, int *x, int *y, int *comp, int req_comp); extern void *stbi__dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); extern void *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO extern int stbi__dds_test_filename (char const *filename); extern int stbi__dds_test_file (FILE *f); extern void *stbi__dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); #endif extern int stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed); extern int stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed); #ifndef STBI_NO_STDIO extern int stbi__dds_info_from_path (char const *filename, int *x, int *y, int *comp, int *iscompressed); extern int stbi__dds_info_from_file (FILE *f, int *x, int *y, int *comp, int *iscompressed); #endif /* // //// end header file /////////////////////////////////////////////////////*/ #endif /* HEADER_STB_IMAGE_DDS_AUGMENTATION */ ================================================ FILE: lib/SOIL2/stbi_DDS_c.h ================================================ /// DDS file support, does decoding, _not_ direct uploading /// (use SOIL for that ;-) #include "image_DXT.h" static int stbi__dds_test(stbi__context *s) { // check the magic number if (stbi__get8(s) != 'D') { stbi__rewind(s); return 0; } if (stbi__get8(s) != 'D') { stbi__rewind(s); return 0; } if (stbi__get8(s) != 'S') { stbi__rewind(s); return 0; } if (stbi__get8(s) != ' ') { stbi__rewind(s); return 0; } // check header size if (stbi__get32le(s) != 124) { stbi__rewind(s); return 0; } // Also rewind because the loader needs to read the header stbi__rewind(s); return 1; } #ifndef STBI_NO_STDIO int stbi__dds_test_filename (char const *filename) { int r; FILE *f = fopen(filename, "rb"); if (!f) return 0; r = stbi__dds_test_file(f); fclose(f); return r; } int stbi__dds_test_file (FILE *f) { stbi__context s; int r,n = ftell(f); stbi__start_file(&s,f); r = stbi__dds_test(&s); fseek(f,n,SEEK_SET); return r; } #endif int stbi__dds_test_memory (stbi_uc const *buffer, int len) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__dds_test(&s); } int stbi__dds_test_callbacks (stbi_io_callbacks const *clbk, void *user) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__dds_test(&s); } // helper functions int stbi_convert_bit_range( int c, int from_bits, int to_bits ) { int b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1); return (b + (b >> from_bits)) >> from_bits; } void stbi_rgb_888_from_565( unsigned int c, int *r, int *g, int *b ) { *r = stbi_convert_bit_range( (c >> 11) & 31, 5, 8 ); *g = stbi_convert_bit_range( (c >> 05) & 63, 6, 8 ); *b = stbi_convert_bit_range( (c >> 00) & 31, 5, 8 ); } void stbi_decode_DXT1_block( unsigned char uncompressed[16*4], unsigned char compressed[8] ) { int next_bit = 4*8; int i, r, g, b; int c0, c1; unsigned char decode_colors[4*4]; // find the 2 primary colors c0 = compressed[0] + (compressed[1] << 8); c1 = compressed[2] + (compressed[3] << 8); stbi_rgb_888_from_565( c0, &r, &g, &b ); decode_colors[0] = r; decode_colors[1] = g; decode_colors[2] = b; decode_colors[3] = 255; stbi_rgb_888_from_565( c1, &r, &g, &b ); decode_colors[4] = r; decode_colors[5] = g; decode_colors[6] = b; decode_colors[7] = 255; if( c0 > c1 ) { // no alpha, 2 interpolated colors decode_colors[8] = (2*decode_colors[0] + decode_colors[4]) / 3; decode_colors[9] = (2*decode_colors[1] + decode_colors[5]) / 3; decode_colors[10] = (2*decode_colors[2] + decode_colors[6]) / 3; decode_colors[11] = 255; decode_colors[12] = (decode_colors[0] + 2*decode_colors[4]) / 3; decode_colors[13] = (decode_colors[1] + 2*decode_colors[5]) / 3; decode_colors[14] = (decode_colors[2] + 2*decode_colors[6]) / 3; decode_colors[15] = 255; } else { // 1 interpolated color, alpha decode_colors[8] = (decode_colors[0] + decode_colors[4]) / 2; decode_colors[9] = (decode_colors[1] + decode_colors[5]) / 2; decode_colors[10] = (decode_colors[2] + decode_colors[6]) / 2; decode_colors[11] = 255; decode_colors[12] = 0; decode_colors[13] = 0; decode_colors[14] = 0; decode_colors[15] = 0; } // decode the block for( i = 0; i < 16*4; i += 4 ) { int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 4; next_bit += 2; uncompressed[i+0] = decode_colors[idx+0]; uncompressed[i+1] = decode_colors[idx+1]; uncompressed[i+2] = decode_colors[idx+2]; uncompressed[i+3] = decode_colors[idx+3]; } // done } void stbi_decode_DXT23_alpha_block( unsigned char uncompressed[16*4], unsigned char compressed[8] ) { int i, next_bit = 0; // each alpha value gets 4 bits for( i = 3; i < 16*4; i += 4 ) { uncompressed[i] = stbi_convert_bit_range( (compressed[next_bit>>3] >> (next_bit&7)) & 15, 4, 8 ); next_bit += 4; } } void stbi_decode_DXT45_alpha_block( unsigned char uncompressed[16*4], unsigned char compressed[8] ) { int i, next_bit = 8*2; unsigned char decode_alpha[8]; // each alpha value gets 3 bits, and the 1st 2 bytes are the range decode_alpha[0] = compressed[0]; decode_alpha[1] = compressed[1]; if( decode_alpha[0] > decode_alpha[1] ) { // 6 step intermediate decode_alpha[2] = (6*decode_alpha[0] + 1*decode_alpha[1]) / 7; decode_alpha[3] = (5*decode_alpha[0] + 2*decode_alpha[1]) / 7; decode_alpha[4] = (4*decode_alpha[0] + 3*decode_alpha[1]) / 7; decode_alpha[5] = (3*decode_alpha[0] + 4*decode_alpha[1]) / 7; decode_alpha[6] = (2*decode_alpha[0] + 5*decode_alpha[1]) / 7; decode_alpha[7] = (1*decode_alpha[0] + 6*decode_alpha[1]) / 7; } else { // 4 step intermediate, pluss full and none decode_alpha[2] = (4*decode_alpha[0] + 1*decode_alpha[1]) / 5; decode_alpha[3] = (3*decode_alpha[0] + 2*decode_alpha[1]) / 5; decode_alpha[4] = (2*decode_alpha[0] + 3*decode_alpha[1]) / 5; decode_alpha[5] = (1*decode_alpha[0] + 4*decode_alpha[1]) / 5; decode_alpha[6] = 0; decode_alpha[7] = 255; } for( i = 3; i < 16*4; i += 4 ) { int idx = 0, bit; bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; idx += bit << 0; ++next_bit; bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; idx += bit << 1; ++next_bit; bit = (compressed[next_bit>>3] >> (next_bit&7)) & 1; idx += bit << 2; ++next_bit; uncompressed[i] = decode_alpha[idx & 7]; } // done } void stbi_decode_DXT_color_block( unsigned char uncompressed[16*4], unsigned char compressed[8] ) { int next_bit = 4*8; int i, r, g, b; int c0, c1; unsigned char decode_colors[4*3]; // find the 2 primary colors c0 = compressed[0] + (compressed[1] << 8); c1 = compressed[2] + (compressed[3] << 8); stbi_rgb_888_from_565( c0, &r, &g, &b ); decode_colors[0] = r; decode_colors[1] = g; decode_colors[2] = b; stbi_rgb_888_from_565( c1, &r, &g, &b ); decode_colors[3] = r; decode_colors[4] = g; decode_colors[5] = b; // Like DXT1, but no choicees: // no alpha, 2 interpolated colors decode_colors[6] = (2*decode_colors[0] + decode_colors[3]) / 3; decode_colors[7] = (2*decode_colors[1] + decode_colors[4]) / 3; decode_colors[8] = (2*decode_colors[2] + decode_colors[5]) / 3; decode_colors[9] = (decode_colors[0] + 2*decode_colors[3]) / 3; decode_colors[10] = (decode_colors[1] + 2*decode_colors[4]) / 3; decode_colors[11] = (decode_colors[2] + 2*decode_colors[5]) / 3; // decode the block for( i = 0; i < 16*4; i += 4 ) { int idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 3; next_bit += 2; uncompressed[i+0] = decode_colors[idx+0]; uncompressed[i+1] = decode_colors[idx+1]; uncompressed[i+2] = decode_colors[idx+2]; } // done } static int stbi__dds_info( stbi__context *s, int *x, int *y, int *comp, int *iscompressed ) { int is_compressed,has_alpha; unsigned int flags; DDS_header header={0}; if( sizeof( DDS_header ) != 128 ) { return 0; } stbi__getn( s, (stbi_uc*)(&header), 128 ); if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) { stbi__rewind( s ); return 0; } if( header.dwSize != 124 ) { stbi__rewind( s ); return 0; } flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; if( (header.dwFlags & flags) != flags ) { stbi__rewind( s ); return 0; } if( header.sPixelFormat.dwSize != 32 ) { stbi__rewind( s ); return 0; } flags = DDPF_FOURCC | DDPF_RGB; if( (header.sPixelFormat.dwFlags & flags) == 0 ) { stbi__rewind( s ); return 0; } if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) { stbi__rewind( s ); return 0; } is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; *x = header.dwWidth; *y = header.dwHeight; if ( !is_compressed ) { *comp = 3; if ( has_alpha ) *comp = 4; } else *comp = 4; if ( iscompressed ) *iscompressed = is_compressed; return 1; } int stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__dds_info( &s, x, y, comp, iscompressed ); } int stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__dds_info( &s, x, y, comp, iscompressed ); } #ifndef STBI_NO_STDIO int stbi__dds_info_from_path(char const *filename, int *x, int *y, int *comp, int *iscompressed) { int res; FILE *f = fopen(filename, "rb"); if (!f) return 0; res = stbi__dds_info_from_file( f, x, y, comp, iscompressed ); fclose(f); return res; } int stbi__dds_info_from_file(FILE *f, int *x, int *y, int *comp, int *iscompressed) { stbi__context s; int res; long n = ftell(f); stbi__start_file(&s, f); res = stbi__dds_info(&s, x, y, comp, iscompressed); fseek(f, n, SEEK_SET); return res; } #endif static void * stbi__dds_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { // all variables go up front stbi_uc *dds_data = NULL; stbi_uc block[16*4]; stbi_uc compressed[8]; int flags, DXT_family; int has_alpha, has_mipmap; int is_compressed, cubemap_faces; int block_pitch, num_blocks; DDS_header header={0}; int i, sz, cf; // load the header if( sizeof( DDS_header ) != 128 ) { return NULL; } stbi__getn( s, (stbi_uc*)(&header), 128 ); // and do some checking if( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL; if( header.dwSize != 124 ) return NULL; flags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; if( (header.dwFlags & flags) != (unsigned int)flags ) return NULL; /* According to the MSDN spec, the dwFlags should contain DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if uncompressed. Some DDS writers do not conform to the spec, so I need to make my reader more tolerant */ if( header.sPixelFormat.dwSize != 32 ) return NULL; flags = DDPF_FOURCC | DDPF_RGB; if( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL; if( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL; // get the image data s->img_x = header.dwWidth; s->img_y = header.dwHeight; s->img_n = 4; is_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC; has_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS; has_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1); cubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP; /* I need cubemaps to have square faces */ cubemap_faces &= (s->img_x == s->img_y); cubemap_faces *= 5; cubemap_faces += 1; block_pitch = (s->img_x+3) >> 2; num_blocks = block_pitch * ((s->img_y+3) >> 2); /* let the user know what's going on */ *x = s->img_x; *y = s->img_y; *comp = s->img_n; /* is this uncompressed? */ if( is_compressed ) { /* compressed */ // note: header.sPixelFormat.dwFourCC is something like (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24)) DXT_family = 1 + (header.sPixelFormat.dwFourCC >> 24) - '1'; if( (DXT_family < 1) || (DXT_family > 5) ) return NULL; /* check the expected size...oops, nevermind... those non-compliant writers leave dwPitchOrLinearSize == 0 */ // passed all the tests, get the RAM for decoding sz = (s->img_x)*(s->img_y)*4*cubemap_faces; dds_data = (unsigned char*)malloc( sz ); /* do this once for each face */ for( cf = 0; cf < cubemap_faces; ++ cf ) { // now read and decode all the blocks for( i = 0; i < num_blocks; ++i ) { // where are we? int bx, by, bw=4, bh=4; int ref_x = 4 * (i % block_pitch); int ref_y = 4 * (i / block_pitch); // get the next block's worth of compressed data, and decompress it if( DXT_family == 1 ) { // DXT1 stbi__getn( s, compressed, 8 ); stbi_decode_DXT1_block( block, compressed ); } else if( DXT_family < 4 ) { // DXT2/3 stbi__getn( s, compressed, 8 ); stbi_decode_DXT23_alpha_block ( block, compressed ); stbi__getn( s, compressed, 8 ); stbi_decode_DXT_color_block ( block, compressed ); } else { // DXT4/5 stbi__getn( s, compressed, 8 ); stbi_decode_DXT45_alpha_block ( block, compressed ); stbi__getn( s, compressed, 8 ); stbi_decode_DXT_color_block ( block, compressed ); } // is this a partial block? if( ref_x + 4 > (int)s->img_x ) { bw = s->img_x - ref_x; } if( ref_y + 4 > (int)s->img_y ) { bh = s->img_y - ref_y; } // now drop our decompressed data into the buffer for( by = 0; by < bh; ++by ) { int idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x); for( bx = 0; bx < bw*4; ++bx ) { dds_data[idx+bx] = block[by*16+bx]; } } } /* done reading and decoding the main image... stbi__skip MIPmaps if present */ if( has_mipmap ) { int block_size = 16; if( DXT_family == 1 ) { block_size = 8; } for( i = 1; i < (int)header.dwMipMapCount; ++i ) { int mx = s->img_x >> (i + 2); int my = s->img_y >> (i + 2); if( mx < 1 ) { mx = 1; } if( my < 1 ) { my = 1; } stbi__skip( s, mx*my*block_size ); } } }/* per cubemap face */ } else { /* uncompressed */ DXT_family = 0; s->img_n = 3; if( has_alpha ) { s->img_n = 4; } *comp = s->img_n; sz = s->img_x*s->img_y*s->img_n*cubemap_faces; dds_data = (unsigned char*)malloc( sz ); /* do this once for each face */ for( cf = 0; cf < cubemap_faces; ++ cf ) { /* read the main image for this face */ stbi__getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n ); /* done reading and decoding the main image... stbi__skip MIPmaps if present */ if( has_mipmap ) { for( i = 1; i < (int)header.dwMipMapCount; ++i ) { int mx = s->img_x >> i; int my = s->img_y >> i; if( mx < 1 ) { mx = 1; } if( my < 1 ) { my = 1; } stbi__skip( s, mx*my*s->img_n ); } } } /* data was BGR, I need it RGB */ for( i = 0; i < sz; i += s->img_n ) { unsigned char temp = dds_data[i]; dds_data[i] = dds_data[i+2]; dds_data[i+2] = temp; } } /* finished decompressing into RGBA, adjust the y size if we have a cubemap note: sz is already up to date */ s->img_y *= cubemap_faces; *y = s->img_y; // did the user want something else, or // see if all the alpha values are 255 (i.e. no transparency) has_alpha = 0; if( s->img_n == 4) { for( i = 3; (i < sz) && (has_alpha == 0); i += 4 ) { has_alpha |= (dds_data[i] < 255); } } if( (req_comp <= 4) && (req_comp >= 1) ) { // user has some requirements, meet them if( req_comp != s->img_n ) { dds_data = stbi__convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y ); *comp = req_comp; } } else { // user had no requirements, only drop to RGB is no alpha if( (has_alpha == 0) && (s->img_n == 4) ) { dds_data = stbi__convert_format( dds_data, 4, 3, s->img_x, s->img_y ); *comp = 3; } } // OK, done return dds_data; } #ifndef STBI_NO_STDIO void *stbi__dds_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_file(&s,f); return stbi__dds_load(&s,x,y,comp,req_comp); } void *stbi__dds_load_from_path (const char *filename, int *x, int *y, int *comp, int req_comp) { void *data; FILE *f = fopen(filename, "rb"); if (!f) return NULL; data = stbi__dds_load_from_file(f,x,y,comp,req_comp); fclose(f); return data; } #endif void *stbi__dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__dds_load(&s,x,y,comp,req_comp); } void *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__dds_load(&s,x,y,comp,req_comp); } ================================================ FILE: lib/SOIL2/stbi_ext.h ================================================ #ifndef HEADER_STB_IMAGE_EXT #define HEADER_STB_IMAGE_EXT enum { STBI_unknown= 0, STBI_jpeg = 1, STBI_png = 2, STBI_bmp = 3, STBI_gif = 4, STBI_tga = 5, STBI_psd = 6, STBI_pic = 7, STBI_pnm = 8, STBI_dds = 9, STBI_pvr = 10, STBI_pkm = 11, STBI_hdr = 12, STBI_qoi = 13 }; extern int stbi_test_from_memory (stbi_uc const *buffer, int len); extern int stbi_test_from_callbacks (stbi_io_callbacks const *clbk, void *user); #ifndef STBI_NO_STDIO extern int stbi_test (char const *filename); extern int stbi_test_from_file (FILE *f); #endif #endif /* HEADER_STB_IMAGE_EXT */ ================================================ FILE: lib/SOIL2/stbi_ext_c.h ================================================ static int stbi_test_main(stbi__context *s) { #ifndef STBI_NO_JPEG if (stbi__jpeg_test(s)) return STBI_jpeg; #endif #ifndef STBI_NO_PNG if (stbi__png_test(s)) return STBI_png; #endif #ifndef STBI_NO_BMP if (stbi__bmp_test(s)) return STBI_bmp; #endif #ifndef STBI_NO_GIF if (stbi__gif_test(s)) return STBI_gif; #endif #ifndef STBI_NO_PSD if (stbi__psd_test(s)) return STBI_psd; #endif #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return STBI_pic; #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return STBI_pnm; #endif #ifndef STBI_NO_DDS if (stbi__dds_test(s)) return STBI_dds; #endif #ifndef STBI_NO_PVR if (stbi__pvr_test(s)) return STBI_pvr; #endif #ifndef STBI_NO_PKM if (stbi__pkm_test(s)) return STBI_pkm; #endif #ifndef STBI_NO_QOI if (stbi__qoi_test(s)) return STBI_qoi; #endif #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) return STBI_hdr; #endif #ifndef STBI_NO_TGA if (stbi__tga_test(s)) return STBI_tga; #endif return STBI_unknown; } #ifndef STBI_NO_STDIO int stbi_test_from_file(FILE *f) { stbi__context s; stbi__start_file(&s,f); return stbi_test_main(&s); } int stbi_test(char const *filename) { FILE *f = fopen(filename, "rb"); int result; if (!f) return STBI_unknown; result = stbi_test_from_file(f); fclose(f); return result; } #endif //!STBI_NO_STDIO int stbi_test_from_memory(stbi_uc const *buffer, int len) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi_test_main(&s); } int stbi_test_from_callbacks(stbi_io_callbacks const *clbk, void *user) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi_test_main(&s); } ================================================ FILE: lib/SOIL2/stbi_pkm.h ================================================ /* adding PKM loading support to stbi */ #ifndef HEADER_STB_IMAGE_PKM_AUGMENTATION #define HEADER_STB_IMAGE_PKM_AUGMENTATION /* is it a PKM file? */ extern int stbi__pkm_test_memory (stbi_uc const *buffer, int len); extern int stbi__pkm_test_callbacks (stbi_io_callbacks const *clbk, void *user); extern void *stbi__pkm_load_from_path (char const *filename, int *x, int *y, int *comp, int req_comp); extern void *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); extern void *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO extern int stbi__pkm_test_filename (char const *filename); extern int stbi__pkm_test_file (FILE *f); extern void *stbi__pkm_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); #endif extern int stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); extern int stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); #ifndef STBI_NO_STDIO extern int stbi__pkm_info_from_path (char const *filename, int *x, int *y, int *comp); extern int stbi__pkm_info_from_file (FILE *f, int *x, int *y, int *comp); #endif /* // //// end header file /////////////////////////////////////////////////////*/ #endif /* HEADER_STB_IMAGE_PKM_AUGMENTATION */ ================================================ FILE: lib/SOIL2/stbi_pkm_c.h ================================================ #include "pkm_helper.h" #include "wfETC.h" static int stbi__pkm_test(stbi__context *s) { // check the magic number if (stbi__get8(s) != 'P') { stbi__rewind(s); return 0; } if (stbi__get8(s) != 'K') { stbi__rewind(s); return 0; } if (stbi__get8(s) != 'M') { stbi__rewind(s); return 0; } if (stbi__get8(s) != ' ') { stbi__rewind(s); return 0; } if (stbi__get8(s) != '1') { stbi__rewind(s); return 0; } if (stbi__get8(s) != '0') { stbi__rewind(s); return 0; } stbi__rewind(s); return 1; } #ifndef STBI_NO_STDIO int stbi__pkm_test_filename (char const *filename) { int r; FILE *f = fopen(filename, "rb"); if (!f) return 0; r = stbi__pkm_test_file(f); fclose(f); return r; } int stbi__pkm_test_file (FILE *f) { stbi__context s; int r,n = ftell(f); stbi__start_file(&s,f); r = stbi__pkm_test(&s); fseek(f,n,SEEK_SET); return r; } #endif int stbi__pkm_test_memory (stbi_uc const *buffer, int len) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__pkm_test(&s); } int stbi__pkm_test_callbacks (stbi_io_callbacks const *clbk, void *user) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__pkm_test(&s); } static int stbi__pkm_info(stbi__context *s, int *x, int *y, int *comp ) { PKMHeader header; unsigned int width, height; stbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) ); if ( 0 != strncmp( header.aName, "PKM 10", sizeof(header.aName) ) ) { stbi__rewind(s); return 0; } width = (header.iWidthMSB << 8) | header.iWidthLSB; height = (header.iHeightMSB << 8) | header.iHeightLSB; *x = s->img_x = width; *y = s->img_y = height; *comp = s->img_n = 3; stbi__rewind(s); return 1; } int stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp ) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__pkm_info( &s, x, y, comp ); } int stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__pkm_info( &s, x, y, comp ); } #ifndef STBI_NO_STDIO int stbi__pkm_info_from_path(char const *filename, int *x, int *y, int *comp) { int res; FILE *f = fopen(filename, "rb"); if (!f) return 0; res = stbi__pkm_info_from_file( f, x, y, comp ); fclose(f); return res; } int stbi__pkm_info_from_file(FILE *f, int *x, int *y, int *comp) { stbi__context s; int res; long n = ftell(f); stbi__start_file(&s, f); res = stbi__pkm_info(&s, x, y, comp); fseek(f, n, SEEK_SET); return res; } #endif static void * stbi__pkm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi_uc *pkm_data = NULL; stbi_uc *pkm_res_data = NULL; PKMHeader header; unsigned int width; unsigned int height; unsigned int compressed_size; stbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) ); if ( 0 != strncmp( header.aName, "PKM 10", sizeof(header.aName) ) ) { return NULL; } width = (header.iWidthMSB << 8) | header.iWidthLSB; height = (header.iHeightMSB << 8) | header.iHeightLSB; *x = s->img_x = width; *y = s->img_y = height; *comp = s->img_n = 4; compressed_size = (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1; pkm_data = (stbi_uc *)malloc(compressed_size); stbi__getn( s, pkm_data, compressed_size ); pkm_res_data = (stbi_uc *)malloc(width * height * s->img_n); wfETC1_DecodeImage(pkm_data, pkm_res_data, width, height); free( pkm_data ); if ( NULL != pkm_res_data ) { if( (req_comp < 4) && (req_comp >= 1) ) { // user has some requirements, meet them if( req_comp != s->img_n ) { pkm_res_data = stbi__convert_format( pkm_res_data, s->img_n, req_comp, s->img_x, s->img_y ); *comp = req_comp; } } return (stbi_uc *)pkm_res_data; } else { free( pkm_res_data ); } return NULL; } #ifndef STBI_NO_STDIO void *stbi__pkm_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_file(&s,f); return stbi__pkm_load(&s,x,y,comp,req_comp); } void *stbi__pkm_load_from_path (char const*filename, int *x, int *y, int *comp, int req_comp) { void *data; FILE *f = fopen(filename, "rb"); if (!f) return NULL; data = stbi__pkm_load_from_file(f,x,y,comp,req_comp); fclose(f); return data; } #endif void *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__pkm_load(&s,x,y,comp,req_comp); } void *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__pkm_load(&s,x,y,comp,req_comp); } ================================================ FILE: lib/SOIL2/stbi_pvr.h ================================================ /* adding PVR loading support to stbi */ #ifndef HEADER_STB_IMAGE_PVR_AUGMENTATION #define HEADER_STB_IMAGE_PVR_AUGMENTATION /* is it a PVR file? */ extern int stbi__pvr_test_memory (stbi_uc const *buffer, int len); extern int stbi__pvr_test_callbacks (stbi_io_callbacks const *clbk, void *user); extern void *stbi__pvr_load_from_path (char const *filename, int *x, int *y, int *comp, int req_comp); extern void *stbi__pvr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); extern void *stbi__pvr_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO extern int stbi__pvr_test_filename (char const *filename); extern int stbi__pvr_test_file (FILE *f); extern void *stbi__pvr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); #endif extern int stbi__pvr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed); extern int stbi__pvr_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed); #ifndef STBI_NO_STDIO extern int stbi__pvr_info_from_path (char const *filename, int *x, int *y, int *comp, int *iscompressed); extern int stbi__pvr_info_from_file (FILE *f, int *x, int *y, int *comp, int *iscompressed); #endif /* // //// end header file /////////////////////////////////////////////////////*/ #endif /* HEADER_STB_IMAGE_PVR_AUGMENTATION */ ================================================ FILE: lib/SOIL2/stbi_pvr_c.h ================================================ #include "pvr_helper.h" static int stbi__pvr_test(stbi__context *s) { // check header size if (stbi__get32le(s) != sizeof(PVR_Texture_Header)) { stbi__rewind(s); return 0; } // stbi__skip until the magic number stbi__skip(s, 10*4); // check the magic number if ( stbi__get32le(s) != PVRTEX_IDENTIFIER ) { stbi__rewind(s); return 0; } // Also rewind because the loader needs to read the header stbi__rewind(s); return 1; } #ifndef STBI_NO_STDIO int stbi__pvr_test_filename (char const *filename) { int r; FILE *f = fopen(filename, "rb"); if (!f) return 0; r = stbi__pvr_test_file(f); fclose(f); return r; } int stbi__pvr_test_file (FILE *f) { stbi__context s; int r,n = ftell(f); stbi__start_file(&s,f); r = stbi__pvr_test(&s); fseek(f,n,SEEK_SET); return r; } #endif int stbi__pvr_test_memory (stbi_uc const *buffer, int len) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__pvr_test(&s); } int stbi__pvr_test_callbacks (stbi_io_callbacks const *clbk, void *user) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__pvr_test(&s); } static int stbi__pvr_info(stbi__context *s, int *x, int *y, int *comp, int * iscompressed ) { PVR_Texture_Header header={0}; stbi__getn( s, (stbi_uc*)(&header), sizeof(PVR_Texture_Header) ); // Check the header size if ( header.dwHeaderSize != sizeof(PVR_Texture_Header) ) { stbi__rewind( s ); return 0; } // Check the magic identifier if ( header.dwPVR != PVRTEX_IDENTIFIER ) { stbi__rewind(s); return 0; } *x = s->img_x = header.dwWidth; *y = s->img_y = header.dwHeight; *comp = s->img_n = ( header.dwBitCount + 7 ) / 8; if ( iscompressed ) *iscompressed = 0; switch ( header.dwpfFlags & PVRTEX_PIXELTYPE ) { case OGL_RGBA_4444: s->img_n = 2; break; case OGL_RGBA_5551: s->img_n = 2; break; case OGL_RGBA_8888: s->img_n = 4; break; case OGL_RGB_565: s->img_n = 2; break; case OGL_RGB_888: s->img_n = 3; break; case OGL_I_8: s->img_n = 1; break; case OGL_AI_88: s->img_n = 2; break; case OGL_PVRTC2: s->img_n = 4; if ( iscompressed ) *iscompressed = 1; break; case OGL_PVRTC4: s->img_n = 4; if ( iscompressed ) *iscompressed = 1; break; case OGL_RGB_555: default: stbi__rewind(s); return 0; } *comp = s->img_n; return 1; } int stbi__pvr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int * iscompressed ) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__pvr_info( &s, x, y, comp, iscompressed ); } int stbi__pvr_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int * iscompressed) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__pvr_info( &s, x, y, comp, iscompressed ); } #ifndef STBI_NO_STDIO int stbi__pvr_info_from_path(char const *filename, int *x, int *y, int *comp, int * iscompressed) { int res; FILE *f = fopen(filename, "rb"); if (!f) return 0; res = stbi__pvr_info_from_file( f, x, y, comp, iscompressed ); fclose(f); return res; } int stbi__pvr_info_from_file(FILE *f, int *x, int *y, int *comp, int * iscompressed) { stbi__context s; int res; long n = ftell(f); stbi__start_file(&s, f); res = stbi__pvr_info(&s, x, y, comp, iscompressed); fseek(f, n, SEEK_SET); return res; } #endif /****************************************************************************** Taken from: @File PVRTDecompress.cpp @Title PVRTDecompress @Copyright Copyright (C) Imagination Technologies Limited. @Platform ANSI compatible @Description PVRTC Texture Decompression. ******************************************************************************/ typedef unsigned char PVRTuint8; typedef unsigned short PVRTuint16; typedef unsigned int PVRTuint32; /***************************************************************************** * defines and consts *****************************************************************************/ #define PT_INDEX (2) // The Punch-through index #define BLK_Y_SIZE (4) // always 4 for all 2D block types #define BLK_X_MAX (8) // Max X dimension for blocks #define BLK_X_2BPP (8) // dimensions for the two formats #define BLK_X_4BPP (4) #define WRAP_COORD(Val, Size) ((Val) & ((Size)-1)) #define POWER_OF_2(X) util_number_is_power_2(X) /* Define an expression to either wrap or clamp large or small vals to the legal coordinate range */ #define PVRT_MIN(a,b) (((a) < (b)) ? (a) : (b)) #define PVRT_MAX(a,b) (((a) > (b)) ? (a) : (b)) #define PVRT_CLAMP(x, l, h) (PVRT_MIN((h), PVRT_MAX((x), (l)))) #define LIMIT_COORD(Val, Size, AssumeImageTiles) \ ((AssumeImageTiles)? WRAP_COORD((Val), (Size)): PVRT_CLAMP((Val), 0, (Size)-1)) /***************************************************************************** * Useful typedefs *****************************************************************************/ typedef PVRTuint32 U32; typedef PVRTuint8 U8; /*********************************************************** DECOMPRESSION ROUTINES ************************************************************/ /*!*********************************************************************** @Struct AMTC_BLOCK_STRUCT @Brief *************************************************************************/ typedef struct { // Uses 64 bits pre block U32 PackedData[2]; }AMTC_BLOCK_STRUCT; /*!*********************************************************************** @Function util_number_is_power_2 @Input input A number @Returns TRUE if the number is an integer power of two, else FALSE. @Description Check that a number is an integer power of two, i.e. 1, 2, 4, 8, ... etc. Returns FALSE for zero. *************************************************************************/ int util_number_is_power_2( unsigned input ) { unsigned minus1; if( !input ) return 0; minus1 = input - 1; return ( (input | minus1) == (input ^ minus1) ) ? 1 : 0; } /*!*********************************************************************** @Function Unpack5554Colour @Input pBlock @Input ABColours @Description Given a block, extract the colour information and convert to 5554 formats *************************************************************************/ static void Unpack5554Colour(const AMTC_BLOCK_STRUCT *pBlock, int ABColours[2][4]) { U32 RawBits[2]; int i; // Extract A and B RawBits[0] = pBlock->PackedData[1] & (0xFFFE); // 15 bits (shifted up by one) RawBits[1] = pBlock->PackedData[1] >> 16; // 16 bits // step through both colours for(i = 0; i < 2; i++) { // If completely opaque if(RawBits[i] & (1<<15)) { // Extract R and G (both 5 bit) ABColours[i][0] = (RawBits[i] >> 10) & 0x1F; ABColours[i][1] = (RawBits[i] >> 5) & 0x1F; /* The precision of Blue depends on A or B. If A then we need to replicate the top bit to get 5 bits in total */ ABColours[i][2] = RawBits[i] & 0x1F; if(i==0) { ABColours[0][2] |= ABColours[0][2] >> 4; } // set 4bit alpha fully on... ABColours[i][3] = 0xF; } else // Else if colour has variable translucency { /* Extract R and G (both 4 bit). (Leave a space on the end for the replication of bits */ ABColours[i][0] = (RawBits[i] >> (8-1)) & 0x1E; ABColours[i][1] = (RawBits[i] >> (4-1)) & 0x1E; // replicate bits to truly expand to 5 bits ABColours[i][0] |= ABColours[i][0] >> 4; ABColours[i][1] |= ABColours[i][1] >> 4; // grab the 3(+padding) or 4 bits of blue and add an extra padding bit ABColours[i][2] = (RawBits[i] & 0xF) << 1; /* expand from 3 to 5 bits if this is from colour A, or 4 to 5 bits if from colour B */ if(i==0) { ABColours[0][2] |= ABColours[0][2] >> 3; } else { ABColours[0][2] |= ABColours[0][2] >> 4; } // Set the alpha bits to be 3 + a zero on the end ABColours[i][3] = (RawBits[i] >> 11) & 0xE; } } } /*!*********************************************************************** @Function UnpackModulations @Input pBlock @Input Do2bitMode @Input ModulationVals @Input ModulationModes @Input StartX @Input StartY @Description Given the block and the texture type and it's relative position in the 2x2 group of blocks, extract the bit patterns for the fully defined pixels. *************************************************************************/ static void UnpackModulations(const AMTC_BLOCK_STRUCT *pBlock, const int Do2bitMode, int ModulationVals[8][16], int ModulationModes[8][16], int StartX, int StartY) { int BlockModMode; U32 ModulationBits; int x, y; BlockModMode= pBlock->PackedData[1] & 1; ModulationBits = pBlock->PackedData[0]; // if it's in an interpolated mode if(Do2bitMode && BlockModMode) { /* run through all the pixels in the block. Note we can now treat all the "stored" values as if they have 2bits (even when they didn't!) */ for(y = 0; y < BLK_Y_SIZE; y++) { for(x = 0; x < BLK_X_2BPP; x++) { ModulationModes[y+StartY][x+StartX] = BlockModMode; // if this is a stored value... if(((x^y)&1) == 0) { ModulationVals[y+StartY][x+StartX] = ModulationBits & 3; ModulationBits >>= 2; } } } } else if(Do2bitMode) // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel { for(y = 0; y < BLK_Y_SIZE; y++) { for(x = 0; x < BLK_X_2BPP; x++) { ModulationModes[y+StartY][x+StartX] = BlockModMode; // double the bits so 0=> 00, and 1=>11 if(ModulationBits & 1) { ModulationVals[y+StartY][x+StartX] = 0x3; } else { ModulationVals[y+StartY][x+StartX] = 0x0; } ModulationBits >>= 1; } } } else // else its the 4bpp mode so each value has 2 bits { for(y = 0; y < BLK_Y_SIZE; y++) { for(x = 0; x < BLK_X_4BPP; x++) { ModulationModes[y+StartY][x+StartX] = BlockModMode; ModulationVals[y+StartY][x+StartX] = ModulationBits & 3; ModulationBits >>= 2; } } } // make sure nothing is left over assert(ModulationBits==0); } /*!*********************************************************************** @Function InterpolateColours @Input ColourP @Input ColourQ @Input ColourR @Input ColourS @Input Do2bitMode @Input x @Input y @Modified Result @Description This performs a HW bit accurate interpolation of either the A or B colours for a particular pixel. NOTE: It is assumed that the source colours are in ARGB 5554 format - This means that some "preparation" of the values will be necessary. *************************************************************************/ static void InterpolateColours(const int ColourP[4], const int ColourQ[4], const int ColourR[4], const int ColourS[4], const int Do2bitMode, const int x, const int y, int Result[4]) { int u, v, uscale; int k; int tmp1, tmp2; int P[4], Q[4], R[4], S[4]; // Copy the colours for(k = 0; k < 4; k++) { P[k] = ColourP[k]; Q[k] = ColourQ[k]; R[k] = ColourR[k]; S[k] = ColourS[k]; } // put the x and y values into the right range v = (y & 0x3) | ((~y & 0x2) << 1); if(Do2bitMode) u = (x & 0x7) | ((~x & 0x4) << 1); else u = (x & 0x3) | ((~x & 0x2) << 1); // get the u and v scale amounts v = v - BLK_Y_SIZE/2; if(Do2bitMode) { u = u - BLK_X_2BPP/2; uscale = 8; } else { u = u - BLK_X_4BPP/2; uscale = 4; } for(k = 0; k < 4; k++) { tmp1 = P[k] * uscale + u * (Q[k] - P[k]); tmp2 = R[k] * uscale + u * (S[k] - R[k]); tmp1 = tmp1 * 4 + v * (tmp2 - tmp1); Result[k] = tmp1; } // Lop off the appropriate number of bits to get us to 8 bit precision if(Do2bitMode) { // do RGB for(k = 0; k < 3; k++) { Result[k] >>= 2; } Result[3] >>= 1; } else { // do RGB (A is ok) for(k = 0; k < 3; k++) { Result[k] >>= 1; } } // sanity check for(k = 0; k < 4; k++) { assert(Result[k] < 256); } /* Convert from 5554 to 8888 do RGB 5.3 => 8 */ for(k = 0; k < 3; k++) { Result[k] += Result[k] >> 5; } Result[3] += Result[3] >> 4; // 2nd sanity check for(k = 0; k < 4; k++) { assert(Result[k] < 256); } } /*!*********************************************************************** @Function GetModulationValue @Input x @Input y @Input Do2bitMode @Input ModulationVals @Input ModulationModes @Input Mod @Input DoPT @Description Get the modulation value as a numerator of a fraction of 8ths *************************************************************************/ static void GetModulationValue(int x, int y, const int Do2bitMode, const int ModulationVals[8][16], const int ModulationModes[8][16], int *Mod, int *DoPT) { static const int RepVals0[4] = {0, 3, 5, 8}; static const int RepVals1[4] = {0, 4, 4, 8}; int ModVal; // Map X and Y into the local 2x2 block y = (y & 0x3) | ((~y & 0x2) << 1); if(Do2bitMode) x = (x & 0x7) | ((~x & 0x4) << 1); else x = (x & 0x3) | ((~x & 0x2) << 1); // assume no PT for now *DoPT = 0; // extract the modulation value. If a simple encoding if(ModulationModes[y][x]==0) { ModVal = RepVals0[ModulationVals[y][x]]; } else if(Do2bitMode) { // if this is a stored value if(((x^y)&1)==0) ModVal = RepVals0[ModulationVals[y][x]]; else if(ModulationModes[y][x] == 1) // else average from the neighbours if H&V interpolation.. { ModVal = (RepVals0[ModulationVals[y-1][x]] + RepVals0[ModulationVals[y+1][x]] + RepVals0[ModulationVals[y][x-1]] + RepVals0[ModulationVals[y][x+1]] + 2) / 4; } else if(ModulationModes[y][x] == 2) // else if H-Only { ModVal = (RepVals0[ModulationVals[y][x-1]] + RepVals0[ModulationVals[y][x+1]] + 1) / 2; } else // else it's V-Only { ModVal = (RepVals0[ModulationVals[y-1][x]] + RepVals0[ModulationVals[y+1][x]] + 1) / 2; } } else // else it's 4BPP and PT encoding { ModVal = RepVals1[ModulationVals[y][x]]; *DoPT = ModulationVals[y][x] == PT_INDEX; } *Mod =ModVal; } static int DisableTwiddlingRoutine = 0; /*!*********************************************************************** @Function TwiddleUV @Input YSize Y dimension of the texture in pixels @Input XSize X dimension of the texture in pixels @Input YPos Pixel Y position @Input XPos Pixel X position @Returns The twiddled offset of the pixel @Description Given the Block (or pixel) coordinates and the dimension of the texture in blocks (or pixels) this returns the twiddled offset of the block (or pixel) from the start of the map. NOTE the dimensions of the texture must be a power of 2 *************************************************************************/ static U32 TwiddleUV(U32 YSize, U32 XSize, U32 YPos, U32 XPos) { U32 Twiddled; U32 MinDimension; U32 MaxValue; U32 SrcBitPos; U32 DstBitPos; int ShiftCount; assert(YPos < YSize); assert(XPos < XSize); assert(POWER_OF_2(YSize)); assert(POWER_OF_2(XSize)); if(YSize < XSize) { MinDimension = YSize; MaxValue = XPos; } else { MinDimension = XSize; MaxValue = YPos; } // Nasty hack to disable twiddling if(DisableTwiddlingRoutine) return (YPos* XSize + XPos); // Step through all the bits in the "minimum" dimension SrcBitPos = 1; DstBitPos = 1; Twiddled = 0; ShiftCount = 0; while(SrcBitPos < MinDimension) { if(YPos & SrcBitPos) { Twiddled |= DstBitPos; } if(XPos & SrcBitPos) { Twiddled |= (DstBitPos << 1); } SrcBitPos <<= 1; DstBitPos <<= 2; ShiftCount += 1; } // prepend any unused bits MaxValue >>= ShiftCount; Twiddled |= (MaxValue << (2*ShiftCount)); return Twiddled; } /***********************************************************/ /* // Decompress // // Takes the compressed input data and outputs the equivalent decompressed // image. */ /***********************************************************/ static void Decompress(AMTC_BLOCK_STRUCT *pCompressedData, const int Do2bitMode, const int XDim, const int YDim, const int AssumeImageTiles, unsigned char* pResultImage) { int x, y; int i, j; int BlkX, BlkY; int BlkXp1, BlkYp1; int XBlockSize; int BlkXDim, BlkYDim; int StartX, StartY; int ModulationVals[8][16]; int ModulationModes[8][16]; int Mod, DoPT; unsigned int uPosition; /* // local neighbourhood of blocks */ AMTC_BLOCK_STRUCT *pBlocks[2][2]; AMTC_BLOCK_STRUCT *pPrevious[2][2] = {{NULL, NULL}, {NULL, NULL}}; /* // Low precision colours extracted from the blocks */ struct { int Reps[2][4]; }Colours5554[2][2]; /* // Interpolated A and B colours for the pixel */ int ASig[4], BSig[4]; int Result[4]; if(Do2bitMode) { XBlockSize = BLK_X_2BPP; } else { XBlockSize = BLK_X_4BPP; } /* // For MBX don't allow the sizes to get too small */ BlkXDim = PVRT_MAX(2, XDim / XBlockSize); BlkYDim = PVRT_MAX(2, YDim / BLK_Y_SIZE); /* // Step through the pixels of the image decompressing each one in turn // // Note that this is a hideously inefficient way to do this! */ for(y = 0; y < YDim; y++) { for(x = 0; x < XDim; x++) { /* // map this pixel to the top left neighbourhood of blocks */ BlkX = (x - XBlockSize/2); BlkY = (y - BLK_Y_SIZE/2); BlkX = LIMIT_COORD(BlkX, XDim, AssumeImageTiles); BlkY = LIMIT_COORD(BlkY, YDim, AssumeImageTiles); BlkX /= XBlockSize; BlkY /= BLK_Y_SIZE; //BlkX = LIMIT_COORD(BlkX, BlkXDim, AssumeImageTiles); //BlkY = LIMIT_COORD(BlkY, BlkYDim, AssumeImageTiles); /* // compute the positions of the other 3 blocks */ BlkXp1 = LIMIT_COORD(BlkX+1, BlkXDim, AssumeImageTiles); BlkYp1 = LIMIT_COORD(BlkY+1, BlkYDim, AssumeImageTiles); /* // Map to block memory locations */ pBlocks[0][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkX); pBlocks[0][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkXp1); pBlocks[1][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkX); pBlocks[1][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkXp1); /* // extract the colours and the modulation information IF the previous values // have changed. */ if(memcmp(pPrevious, pBlocks, 4*sizeof(void*)) != 0) { StartY = 0; for(i = 0; i < 2; i++) { StartX = 0; for(j = 0; j < 2; j++) { Unpack5554Colour(pBlocks[i][j], Colours5554[i][j].Reps); UnpackModulations(pBlocks[i][j], Do2bitMode, ModulationVals, ModulationModes, StartX, StartY); StartX += XBlockSize; }/*end for j*/ StartY += BLK_Y_SIZE; }/*end for i*/ /* // make a copy of the new pointers */ memcpy(pPrevious, pBlocks, 4*sizeof(void*)); }/*end if the blocks have changed*/ /* // decompress the pixel. First compute the interpolated A and B signals */ InterpolateColours(Colours5554[0][0].Reps[0], Colours5554[0][1].Reps[0], Colours5554[1][0].Reps[0], Colours5554[1][1].Reps[0], Do2bitMode, x, y, ASig); InterpolateColours(Colours5554[0][0].Reps[1], Colours5554[0][1].Reps[1], Colours5554[1][0].Reps[1], Colours5554[1][1].Reps[1], Do2bitMode, x, y, BSig); GetModulationValue(x,y, Do2bitMode, (const int (*)[16])ModulationVals, (const int (*)[16])ModulationModes, &Mod, &DoPT); /* // compute the modulated colour */ for(i = 0; i < 4; i++) { Result[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]); Result[i] >>= 3; } if(DoPT) { Result[3] = 0; } /* // Store the result in the output image */ uPosition = (x+y*XDim)<<2; pResultImage[uPosition+0] = (unsigned char)Result[0]; pResultImage[uPosition+1] = (unsigned char)Result[1]; pResultImage[uPosition+2] = (unsigned char)Result[2]; pResultImage[uPosition+3] = (unsigned char)Result[3]; }/*end for x*/ }/*end for y*/ } static void * stbi__pvr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi_uc *pvr_data = NULL; stbi_uc *pvr_res_data = NULL; PVR_Texture_Header header={0}; int iscompressed = 0; int bitmode = 0; unsigned int levelSize = 0; stbi__getn( s, (stbi_uc*)(&header), sizeof(PVR_Texture_Header) ); // Check the header size if ( header.dwHeaderSize != sizeof(PVR_Texture_Header) ) { return NULL; } // Check the magic identifier if ( header.dwPVR != PVRTEX_IDENTIFIER ) { return NULL; } *x = s->img_x = header.dwWidth; *y = s->img_y = header.dwHeight; /* Get if the texture is compressed and the texture mode ( 2bpp or 4bpp ) */ switch ( header.dwpfFlags & PVRTEX_PIXELTYPE ) { case OGL_RGBA_4444: s->img_n = 2; break; case OGL_RGBA_5551: s->img_n = 2; break; case OGL_RGBA_8888: s->img_n = 4; break; case OGL_RGB_565: s->img_n = 2; break; case OGL_RGB_888: s->img_n = 3; break; case OGL_I_8: s->img_n = 1; break; case OGL_AI_88: s->img_n = 2; break; case OGL_PVRTC2: bitmode = 1; s->img_n = 4; iscompressed = 1; break; case OGL_PVRTC4: s->img_n = 4; iscompressed = 1; break; case OGL_RGB_555: default: return NULL; } *comp = s->img_n; // Load only the first mip map level levelSize = (s->img_x * s->img_y * header.dwBitCount + 7) / 8; // get the raw data pvr_data = (stbi_uc *)malloc( levelSize ); stbi__getn( s, pvr_data, levelSize ); // if compressed decompress as RGBA if ( iscompressed ) { pvr_res_data = (stbi_uc *)malloc( s->img_x * s->img_y * 4 ); Decompress( (AMTC_BLOCK_STRUCT*)pvr_data, bitmode, s->img_x, s->img_y, 1, (unsigned char*)pvr_res_data ); free( pvr_data ); } else { // otherwise use the raw data pvr_res_data = pvr_data; } if( (req_comp <= 4) && (req_comp >= 1) ) { // user has some requirements, meet them if( req_comp != s->img_n ) { pvr_res_data = stbi__convert_format( pvr_res_data, s->img_n, req_comp, s->img_x, s->img_y ); *comp = req_comp; } } return pvr_res_data; } #ifndef STBI_NO_STDIO void *stbi__pvr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_file(&s,f); return stbi__pvr_load(&s,x,y,comp,req_comp); } void *stbi__pvr_load_from_path (char const*filename, int *x, int *y, int *comp, int req_comp) { void *data; FILE *f = fopen(filename, "rb"); if (!f) return NULL; data = stbi__pvr_load_from_file(f,x,y,comp,req_comp); fclose(f); return data; } #endif void *stbi__pvr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__pvr_load(&s,x,y,comp,req_comp); } void *stbi__pvr_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__pvr_load(&s,x,y,comp,req_comp); } ================================================ FILE: lib/SOIL2/stbi_qoi.h ================================================ /* adding QOI loading support to stbi */ #ifndef HEADER_STB_IMAGE_QOI_AUGMENTATION #define HEADER_STB_IMAGE_QOI_AUGMENTATION /* is it a QOI file? */ extern int stbi__qoi_test_memory (stbi_uc const *buffer, int len); extern int stbi__qoi_test_callbacks (stbi_io_callbacks const *clbk, void *user); extern void *stbi__qoi_load_from_path (char const *filename, int *x, int *y, int *comp, int req_comp); extern void *stbi__qoi_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); extern void *stbi__qoi_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); #ifndef STBI_NO_STDIO extern int stbi__qoi_test_filename (char const *filename); extern int stbi__qoi_test_file (FILE *f); extern void *stbi__qoi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); #endif extern int stbi__qoi_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); extern int stbi__qoi_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); #ifndef STBI_NO_STDIO extern int stbi__qoi_info_from_path (char const *filename, int *x, int *y, int *comp); extern int stbi__qoi_info_from_file (FILE *f, int *x, int *y, int *comp); #endif /* // //// end header file /////////////////////////////////////////////////////*/ #endif /* HEADER_STB_IMAGE_QOI_AUGMENTATION */ ================================================ FILE: lib/SOIL2/stbi_qoi_c.h ================================================ static int stbi__qoi_test(stbi__context *s) { int i; for (i = 0; i < 4; i++) { if (stbi__get8(s) != "qoif"[i]) { stbi__rewind(s); return 0; } } return 1; } #ifndef STBI_NO_STDIO int stbi__qoi_test_filename(char const *filename) { int r; FILE *f = fopen(filename, "rb"); if (!f) return 0; r = stbi__qoi_test_file(f); fclose(f); return r; } int stbi__qoi_test_file(FILE *f) { stbi__context s; int r,n = ftell(f); stbi__start_file(&s,f); r = stbi__qoi_test(&s); fseek(f,n,SEEK_SET); return r; } #endif int stbi__qoi_test_memory (stbi_uc const *buffer, int len) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__qoi_test(&s); } int stbi__qoi_test_callbacks (stbi_io_callbacks const *clbk, void *user) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__qoi_test(&s); } static int stbi__qoi_info(stbi__context *s, int *x, int *y, int *comp) { stbi__uint32 length; stbi__rewind(s); int i; for (i = 0; i < 4; i++) { if (stbi__get8(s) != "qoif"[i]) { stbi__rewind(s); return 0; } } length = stbi__get32be(s); if (x) *x = (int)length; length = stbi__get32be(s); if (y) *y = (int)length; int channels = stbi__get8(s); // 3 = RGB, 4 = RGBA int colorspace = stbi__get8(s) != 0; // 0 = sRGB with linear alpha, 1 = all channels linear if (comp) *comp = channels; return 1 + colorspace; } int stbi__qoi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp ) { stbi__context s; stbi__start_mem(&s,buffer, len); return stbi__qoi_info( &s, x, y, comp ); } int stbi__qoi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__qoi_info( &s, x, y, comp ); } #ifndef STBI_NO_STDIO int stbi__qoi_info_from_path(char const *filename, int *x, int *y, int *comp) { int res; FILE *f = fopen(filename, "rb"); if (!f) return 0; res = stbi__qoi_info_from_file( f, x, y, comp ); fclose(f); return res; } int stbi__qoi_info_from_file(FILE *f, int *x, int *y, int *comp) { stbi__context s; int res; long n = ftell(f); stbi__start_file(&s, f); res = stbi__qoi_info(&s, x, y, comp); fseek(f, n, SEEK_SET); return res; } #endif static void *stbi__qoi_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { if (!stbi__qoi_info(s, (int*)&s->img_x, (int*)&s->img_y, &s->img_n)) return NULL; if (req_comp == 3 || req_comp == 4) s->img_n = req_comp; if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) *comp = s->img_n; if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__errpuc("too large", "QOI too large"); stbi_uc *out = (stbi_uc *) stbi__malloc_mad3(s->img_x, s->img_y, s->img_n, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); stbi_uc *dst = out; stbi_uc *end = &dst[s->img_x * s->img_y * s->img_n]; stbi__uint32 c = 255; stbi__uint32 recent[0x40]; memset(recent, 0, 0x40*sizeof(stbi__uint32)); while (dst < end) { stbi_uc tag = stbi__get8(s); if (tag == 0xfe) { stbi__uint32 rgb = ((stbi__uint32) stbi__get8(s) << 24) | ((stbi__uint32) stbi__get8(s) << 16) | ((stbi__uint32) stbi__get8(s) << 8); c = (c & 0xff) | rgb; } else if (tag == 0xff) { c = ((stbi__uint32) stbi__get8(s) << 24) | ((stbi__uint32) stbi__get8(s) << 16) | ((stbi__uint32) stbi__get8(s) << 8) | (stbi__uint32) stbi__get8(s); } else if ((tag >> 6) == 0) { c = recent[tag]; } else if ((tag >> 6) == 1) { stbi_uc r = (c >> 24) + ((tag >> 4) & 3) - 2; stbi_uc g = (c >> 16) + ((tag >> 2) & 3) - 2; stbi_uc b = (c >> 8) + (tag & 3) - 2; c = (c & 0xff) | ((stbi__uint32) r << 24) | ((stbi__uint32) g << 16) | ((stbi__uint32) b << 8); } else if ((tag >> 6) == 2) { stbi_uc rb = stbi__get8(s); stbi_uc dg = (tag & 0x3f) - 32; stbi_uc r = (c >> 24) + dg + (rb >> 4) - 8; stbi_uc g = (c >> 16) + dg; stbi_uc b = (c >> 8) + dg + (rb & 0xf) - 8; c = (c & 0xff) | ((stbi__uint32) r << 24) | ((stbi__uint32) g << 16) | ((stbi__uint32) b << 8); } else { int run = tag & 0x3f; if (&dst[run * s->img_n] > end) break; if (s->img_n == 3) { int i; for (i = 0; i < run; i++) { *dst++ = c >> 24; *dst++ = c >> 16; *dst++ = c >> 8; } } else { int i; for (i = 0; i < run; i++) { *dst++ = c >> 24; *dst++ = c >> 16; *dst++ = c >> 8; *dst++ = c; } } } *dst++ = c >> 24; *dst++ = c >> 16; *dst++ = c >> 8; if (s->img_n != 3) *dst++ = c; recent[0x3f & ( ((c >> 24) & 0xff) * 3u + ((c >> 16) & 0xff) * 5u + ((c >> 8) & 0xff) * 7u + (c & 0xff) * 11u )] = c; } if (req_comp) out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); return out; } #ifndef STBI_NO_STDIO void *stbi__qoi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__result_info ri; stbi__start_file(&s,f); return stbi__qoi_load(&s,x,y,comp,req_comp,&ri); } void *stbi__qoi_load_from_path(char const*filename, int *x, int *y, int *comp, int req_comp) { void *data; FILE *f = fopen(filename, "rb"); if (!f) return NULL; data = stbi__qoi_load_from_file(f,x,y,comp,req_comp); fclose(f); return data; } #endif void *stbi__qoi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__result_info ri; stbi__start_mem(&s,buffer, len); return stbi__qoi_load(&s,x,y,comp,req_comp,&ri); } void *stbi__qoi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__result_info ri; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); return stbi__qoi_load(&s,x,y,comp,req_comp,&ri); } ================================================ FILE: lib/SOIL2/stbi_qoi_write.h ================================================ #ifndef NULL #define NULL 0 #endif #define QOI_SRGB 0 #define QOI_LINEAR 1 typedef struct { unsigned int width; unsigned int height; unsigned char channels; unsigned char colorspace; } qoi_desc; #ifndef QOI_ZEROARR #define QOI_ZEROARR(a) memset((a),0,sizeof(a)) #endif #define QOI_OP_INDEX 0x00 /* 00xxxxxx */ #define QOI_OP_DIFF 0x40 /* 01xxxxxx */ #define QOI_OP_LUMA 0x80 /* 10xxxxxx */ #define QOI_OP_RUN 0xc0 /* 11xxxxxx */ #define QOI_OP_RGB 0xfe /* 11111110 */ #define QOI_OP_RGBA 0xff /* 11111111 */ #define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11) #define QOI_MAGIC \ (((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \ ((unsigned int)'i') << 8 | ((unsigned int)'f')) #define QOI_HEADER_SIZE 14 /* 2GB is the max file size that this implementation can safely handle. We guard against anything larger than that, assuming the worst case with 5 bytes per pixel, rounded down to a nice clean value. 400 million pixels ought to be enough for anybody. */ #define QOI_PIXELS_MAX ((unsigned int)400000000) typedef union { struct { unsigned char r, g, b, a; } rgba; unsigned int v; } qoi_rgba_t; static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1}; static void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) { bytes[(*p)++] = (0xff000000 & v) >> 24; bytes[(*p)++] = (0x00ff0000 & v) >> 16; bytes[(*p)++] = (0x0000ff00 & v) >> 8; bytes[(*p)++] = (0x000000ff & v); } static void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) { int i, max_size, p, run; int px_len, px_end, px_pos, channels; unsigned char *bytes; const unsigned char *pixels; qoi_rgba_t index[64]; qoi_rgba_t px, px_prev; if ( data == NULL || out_len == NULL || desc == NULL || desc->width == 0 || desc->height == 0 || desc->channels < 3 || desc->channels > 4 || desc->colorspace > 1 || desc->height >= QOI_PIXELS_MAX / desc->width ) { return NULL; } max_size = desc->width * desc->height * (desc->channels + 1) + QOI_HEADER_SIZE + sizeof(qoi_padding); p = 0; bytes = (unsigned char *) STBIW_MALLOC(max_size); if (!bytes) { return NULL; } qoi_write_32(bytes, &p, QOI_MAGIC); qoi_write_32(bytes, &p, desc->width); qoi_write_32(bytes, &p, desc->height); bytes[p++] = desc->channels; bytes[p++] = desc->colorspace; pixels = (const unsigned char *)data; QOI_ZEROARR(index); run = 0; px_prev.rgba.r = 0; px_prev.rgba.g = 0; px_prev.rgba.b = 0; px_prev.rgba.a = 255; px = px_prev; px_len = desc->width * desc->height * desc->channels; px_end = px_len - desc->channels; channels = desc->channels; for (px_pos = 0; px_pos < px_len; px_pos += channels) { px.rgba.r = pixels[px_pos + 0]; px.rgba.g = pixels[px_pos + 1]; px.rgba.b = pixels[px_pos + 2]; if (channels == 4) { px.rgba.a = pixels[px_pos + 3]; } if (px.v == px_prev.v) { run++; if (run == 62 || px_pos == px_end) { bytes[p++] = QOI_OP_RUN | (run - 1); run = 0; } } else { int index_pos; if (run > 0) { bytes[p++] = QOI_OP_RUN | (run - 1); run = 0; } index_pos = QOI_COLOR_HASH(px) % 64; if (index[index_pos].v == px.v) { bytes[p++] = QOI_OP_INDEX | index_pos; } else { index[index_pos] = px; if (px.rgba.a == px_prev.rgba.a) { signed char vr = px.rgba.r - px_prev.rgba.r; signed char vg = px.rgba.g - px_prev.rgba.g; signed char vb = px.rgba.b - px_prev.rgba.b; signed char vg_r = vr - vg; signed char vg_b = vb - vg; if ( vr > -3 && vr < 2 && vg > -3 && vg < 2 && vb > -3 && vb < 2 ) { bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2); } else if ( vg_r > -9 && vg_r < 8 && vg > -33 && vg < 32 && vg_b > -9 && vg_b < 8 ) { bytes[p++] = QOI_OP_LUMA | (vg + 32); bytes[p++] = (vg_r + 8) << 4 | (vg_b + 8); } else { bytes[p++] = QOI_OP_RGB; bytes[p++] = px.rgba.r; bytes[p++] = px.rgba.g; bytes[p++] = px.rgba.b; } } else { bytes[p++] = QOI_OP_RGBA; bytes[p++] = px.rgba.r; bytes[p++] = px.rgba.g; bytes[p++] = px.rgba.b; bytes[p++] = px.rgba.a; } } } px_prev = px; } for (i = 0; i < (int)sizeof(qoi_padding); i++) { bytes[p++] = qoi_padding[i]; } *out_len = p; return bytes; } static int stbi_write_qoi_core(stbi__write_context *s, int x, int y, int comp, const void*data) { if (y <= 0 || x <= 0 || data == NULL) return 0; qoi_desc desc; desc.width = x; desc.height = y; desc.channels = comp; desc.colorspace = QOI_LINEAR; int out_len = 0; void* res = qoi_encode(data, &desc, &out_len); if (res != NULL) s->func(s->context, res, out_len); return res != NULL ? 1 : 0; } STBIWDEF int stbi_write_qoi_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; stbi__start_write_callbacks(&s, func, context); return stbi_write_qoi_core(&s, x, y, comp, (void *) data); } #ifndef STBI_WRITE_NO_STDIO STBIWDEF int stbi_write_qoi(char const *filename, int x, int y, int comp, const void *data) { stbi__write_context s = { 0 }; if (stbi__start_write_file(&s,filename)) { int r = stbi_write_qoi_core(&s, x, y, comp, (void *) data); stbi__end_write_file(&s); return r; } else return 0; } #endif ================================================ FILE: lib/SOIL2/wfETC.c ================================================ #include "wfETC.h" // specification: http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt #ifdef WF_LITTLE_ENDIAN #define WF_ETC1_COLOR_OFFSET( offset ) ( (64-(offset)) - (4-((offset)%8))*2 ) #define WF_ETC1_PIXEL_OFFSET( offset ) ( (32-(offset)) - (4-((offset)%8))*2 ) #else #define WF_ETC1_COLOR_OFFSET( offset ) (offset-32) #define WF_ETC1_PIXEL_OFFSET( offset ) offset #endif #define WF_INLINE #define WF_ASSUME( expr ) #ifndef WF_EXPECT #if defined __GNUC__ && __GNUC__ #define WF_EXPECT( expr, val ) __builtin_expect( expr, val ) #else #define WF_EXPECT( expr, val ) expr #endif #endif // this table is rearranged from the specification so we do not have to add any logic to index into it const int32_t wfETC_IntensityTables[8][4] = { { 2, 8, -2, -8 }, { 5, 17, -5, -17 }, { 9, 29, -9, -29 }, { 13, 42, -13, -42 }, { 18, 60, -18, -60 }, { 24, 80, -24, -80 }, { 33, 106, -33, -106 }, { 47, 183, -47, -183 } }; WF_INLINE int32_t wfETC_ClampColor( const int32_t x ) { if( x < 0 ) { return 0; } if( x > 255 ) { return 255; } return x; } #define WF_ETC1_BUILD_COLOR( dst, blockIdx, colorIdx, intensityTable, baseColor ) \ dst[ blockIdx ][ colorIdx ] = WF_ETC_RGBA( \ wfETC_ClampColor( intensityTable[ blockIdx ][ colorIdx ] + baseColor[ blockIdx ][ 0 ] ), \ wfETC_ClampColor( intensityTable[ blockIdx ][ colorIdx ] + baseColor[ blockIdx ][ 1 ] ), \ wfETC_ClampColor( intensityTable[ blockIdx ][ colorIdx ] + baseColor[ blockIdx ][ 2 ] ), \ 255 \ ); typedef struct _wfETC1_Block { int32_t baseColorsAndFlags; int32_t pixels; } wfETC1_Block; #define WF_ETC1_CHECK_DIFF_BIT( block ) ( block->baseColorsAndFlags & (1<baseColorsAndFlags & (1<baseColorsAndFlags >> bitOffset ) & 0xf; return color | (color<<4); } const int32_t wfETC1_Color3IdxLUT[] = { 0, 1, 2, 3, -4, -3, -2, -1 }; WF_INLINE void wfETC1_ReadColor53( const wfETC1_Block* block, const uint32_t offset3, int32_t* WF_RESTRICT dst5, int32_t* WF_RESTRICT dst3 ) { // read the 5 bit color and expand to 8 bit { const uint32_t bitOffset = WF_ETC1_COLOR_OFFSET((offset3+3)); const int32_t color = ( block->baseColorsAndFlags >> (bitOffset-3) ) & 0xf8; *dst5 = color | (color>>5); } // read the 3 bit color and expand to 8 bit { const uint32_t bitOffset = WF_ETC1_COLOR_OFFSET(offset3); const int32_t offset = wfETC1_Color3IdxLUT[ ( block->baseColorsAndFlags >> bitOffset ) & 0x7 ]; int32_t color = (*dst5>>3) + offset; color <<= 3; color |= (color>>5) & 0x7; *dst3 = color; } } WF_INLINE int32_t wfETC1_ReadPixel( const wfETC1_Block* block, const uint32_t offset ) { return ( (block->pixels>>WF_ETC1_PIXEL_OFFSET(offset)) & 0x1 ) | ( ( (block->pixels>>WF_ETC1_PIXEL_OFFSET(16+offset)) & 0x1 ) << 1 ) ; } void wfETC1_DecodeBlock( const void* WF_RESTRICT src, void* WF_RESTRICT pDst, const uint32_t dstStride ) { const wfETC1_Block* WF_RESTRICT block = ( wfETC1_Block* )src; int32_t* WF_RESTRICT dst = (int32_t*)pDst; int32_t baseColors[2][3]; // [sub-block][r,g,b] int32_t colors[2][4]; // [sub-block][colorIdx] // individual mode if( WF_ETC1_CHECK_DIFF_BIT( block ) == 0 ) { baseColors[0][0] = wfETC1_ReadColor4( block, 60 ); baseColors[0][1] = wfETC1_ReadColor4( block, 52 ); baseColors[0][2] = wfETC1_ReadColor4( block, 44 ); baseColors[1][0] = wfETC1_ReadColor4( block, 56 ); baseColors[1][1] = wfETC1_ReadColor4( block, 48 ); baseColors[1][2] = wfETC1_ReadColor4( block, 40 ); } // differential mode else { wfETC1_ReadColor53( block, 56, &baseColors[0][0], &baseColors[1][0] ); wfETC1_ReadColor53( block, 48, &baseColors[0][1], &baseColors[1][1] ); wfETC1_ReadColor53( block, 40, &baseColors[0][2], &baseColors[1][2] ); } // build color tables { const int32_t* intensityTable[2] = // [sub-block] { wfETC_IntensityTables[ ( block->baseColorsAndFlags >> WF_ETC1_COLOR_OFFSET(37) ) & 0x7 ], wfETC_IntensityTables[ ( block->baseColorsAndFlags >> WF_ETC1_COLOR_OFFSET(34) ) & 0x7 ] }; WF_ETC1_BUILD_COLOR( colors, 0, 0, intensityTable, baseColors ); WF_ETC1_BUILD_COLOR( colors, 0, 1, intensityTable, baseColors ); WF_ETC1_BUILD_COLOR( colors, 0, 2, intensityTable, baseColors ); WF_ETC1_BUILD_COLOR( colors, 0, 3, intensityTable, baseColors ); WF_ETC1_BUILD_COLOR( colors, 1, 0, intensityTable, baseColors ); WF_ETC1_BUILD_COLOR( colors, 1, 1, intensityTable, baseColors ); WF_ETC1_BUILD_COLOR( colors, 1, 2, intensityTable, baseColors ); WF_ETC1_BUILD_COLOR( colors, 1, 3, intensityTable, baseColors ); } // vertical split if( WF_ETC1_CHECK_FLIP_BIT( block ) == 0 ) { // row 0 dst[0] = colors[0][ wfETC1_ReadPixel( block, 0 ) ]; dst[1] = colors[0][ wfETC1_ReadPixel( block, 4 ) ]; dst[2] = colors[1][ wfETC1_ReadPixel( block, 8 ) ]; dst[3] = colors[1][ wfETC1_ReadPixel( block, 12 ) ]; dst += dstStride; // row 1 dst[0] = colors[0][ wfETC1_ReadPixel( block, 1 ) ]; dst[1] = colors[0][ wfETC1_ReadPixel( block, 5 ) ]; dst[2] = colors[1][ wfETC1_ReadPixel( block, 9 ) ]; dst[3] = colors[1][ wfETC1_ReadPixel( block, 13 ) ]; dst += dstStride; // row 2 dst[0] = colors[0][ wfETC1_ReadPixel( block, 2 ) ]; dst[1] = colors[0][ wfETC1_ReadPixel( block, 6 ) ]; dst[2] = colors[1][ wfETC1_ReadPixel( block, 10 ) ]; dst[3] = colors[1][ wfETC1_ReadPixel( block, 14 ) ]; dst += dstStride; // row 3 dst[0] = colors[0][ wfETC1_ReadPixel( block, 3 ) ]; dst[1] = colors[0][ wfETC1_ReadPixel( block, 7 ) ]; dst[2] = colors[1][ wfETC1_ReadPixel( block, 11 ) ]; dst[3] = colors[1][ wfETC1_ReadPixel( block, 15 ) ]; //dst += dstStride; } // horizontal split else { // row 0 dst[0] = colors[0][ wfETC1_ReadPixel( block, 0 ) ]; dst[1] = colors[0][ wfETC1_ReadPixel( block, 4 ) ]; dst[2] = colors[0][ wfETC1_ReadPixel( block, 8 ) ]; dst[3] = colors[0][ wfETC1_ReadPixel( block, 12 ) ]; dst += dstStride; // row 1 dst[0] = colors[0][ wfETC1_ReadPixel( block, 1 ) ]; dst[1] = colors[0][ wfETC1_ReadPixel( block, 5 ) ]; dst[2] = colors[0][ wfETC1_ReadPixel( block, 9 ) ]; dst[3] = colors[0][ wfETC1_ReadPixel( block, 13 ) ]; dst += dstStride; // row 2 dst[0] = colors[1][ wfETC1_ReadPixel( block, 2 ) ]; dst[1] = colors[1][ wfETC1_ReadPixel( block, 6 ) ]; dst[2] = colors[1][ wfETC1_ReadPixel( block, 10 ) ]; dst[3] = colors[1][ wfETC1_ReadPixel( block, 14 ) ]; dst += dstStride; // row 3 dst[0] = colors[1][ wfETC1_ReadPixel( block, 3 ) ]; dst[1] = colors[1][ wfETC1_ReadPixel( block, 7 ) ]; dst[2] = colors[1][ wfETC1_ReadPixel( block, 11 ) ]; dst[3] = colors[1][ wfETC1_ReadPixel( block, 15 ) ]; //dst += dstStride; } } void wfETC1_DecodeImage( const void* WF_RESTRICT pSrc, void* WF_RESTRICT pDst, const uint32_t width, const uint32_t height ) { const uint8_t* WF_RESTRICT src = (uint8_t*)pSrc; uint8_t* WF_RESTRICT dst = (uint8_t*)pDst; const uint32_t widthBlocks = width/4; const uint32_t heightBlocks = height/4; uint32_t x, y; for( y = 0; y != heightBlocks; ++y ) { for( x = 0; x != widthBlocks; ++x ) { wfETC1_DecodeBlock( src, dst, width ); src += 8; dst += 16; } dst += width*4*3; } } ================================================ FILE: lib/SOIL2/wfETC.h ================================================ #ifndef WF_ETC_H #define WF_ETC_H #define WF_LITTLE_ENDIAN // Qt ordering #define WF_ETC_RGBA( r, g, b, a ) ( ((a)<<24) | ((r)<<16) | ((g)<<8) | (b) ) // colors have been clamped by the time we hit here, so there should be no need to mask #ifdef _MSC_VER #if _MSC_VER < 1300 typedef signed char int8_t; typedef unsigned char uint8_t; typedef signed short int16_t; typedef unsigned short uint16_t; typedef signed int int32_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; #else #include #endif #ifndef WF_RESTRICT #if defined MSC_VER #define WF_RESTRICT __restrict #elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define WF_RESTRICT restrict #else #define WF_RESTRICT #endif #endif #ifdef __cplusplus extern "C" { #endif extern void wfETC1_DecodeBlock( const void* WF_RESTRICT src, void* WF_RESTRICT dst, const uint32_t dstStride /*=4*/ ); //!< stride in pixels; must be a multiple of four extern void wfETC1_DecodeImage( const void* WF_RESTRICT src, void* WF_RESTRICT dst, const uint32_t width, const uint32_t height ); //!< width/height in pixels; must be multiples of four #ifdef __cplusplus } #endif #endif // WF_ETC_H ================================================ FILE: lib/TinyXML-2/tinyxml2.cpp ================================================ /* Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "tinyxml2.h" #include // yes, this one new style header, is in the Android SDK. #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) # include # include #else # include # include #endif #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) // Microsoft Visual Studio, version 2005 and higher. Not WinCE. /*int _snprintf_s( char *buffer, size_t sizeOfBuffer, size_t count, const char *format [, argument] ... );*/ static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) { va_list va; va_start( va, format ); const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); va_end( va ); return result; } static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va ) { const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va ); return result; } #define TIXML_VSCPRINTF _vscprintf #define TIXML_SSCANF sscanf_s #elif defined _MSC_VER // Microsoft Visual Studio 2003 and earlier or WinCE #define TIXML_SNPRINTF _snprintf #define TIXML_VSNPRINTF _vsnprintf #define TIXML_SSCANF sscanf #if (_MSC_VER < 1400 ) && (!defined WINCE) // Microsoft Visual Studio 2003 and not WinCE. #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have. #else // Microsoft Visual Studio 2003 and earlier or WinCE. static inline int TIXML_VSCPRINTF( const char* format, va_list va ) { int len = 512; for (;;) { len = len*2; char* str = new char[len](); const int required = _vsnprintf(str, len, format, va); delete[] str; if ( required != -1 ) { TIXMLASSERT( required >= 0 ); len = required; break; } } TIXMLASSERT( len >= 0 ); return len; } #endif #else // GCC version 3 and higher //#warning( "Using sn* functions." ) #define TIXML_SNPRINTF snprintf #define TIXML_VSNPRINTF vsnprintf static inline int TIXML_VSCPRINTF( const char* format, va_list va ) { int len = vsnprintf( 0, 0, format, va ); TIXMLASSERT( len >= 0 ); return len; } #define TIXML_SSCANF sscanf #endif #if defined(_WIN64) #define TIXML_FSEEK _fseeki64 #define TIXML_FTELL _ftelli64 #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__) #define TIXML_FSEEK fseeko #define TIXML_FTELL ftello #elif defined(__ANDROID__) && __ANDROID_API__ > 24 #define TIXML_FSEEK fseeko64 #define TIXML_FTELL ftello64 #else #define TIXML_FSEEK fseek #define TIXML_FTELL ftell #endif static const char LINE_FEED = static_cast(0x0a); // all line endings are normalized to LF static const char LF = LINE_FEED; static const char CARRIAGE_RETURN = static_cast(0x0d); // CR gets filtered out static const char CR = CARRIAGE_RETURN; static const char SINGLE_QUOTE = '\''; static const char DOUBLE_QUOTE = '\"'; // Bunch of unicode info at: // http://www.unicode.org/faq/utf_bom.html // ef bb bf (Microsoft "lead bytes") - designates UTF-8 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU; static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; namespace tinyxml2 { struct Entity { const char* pattern; int length; char value; }; static const int NUM_ENTITIES = 5; static const Entity entities[NUM_ENTITIES] = { { "quot", 4, DOUBLE_QUOTE }, { "amp", 3, '&' }, { "apos", 4, SINGLE_QUOTE }, { "lt", 2, '<' }, { "gt", 2, '>' } }; StrPair::~StrPair() { Reset(); } void StrPair::TransferTo( StrPair* other ) { if ( this == other ) { return; } // This in effect implements the assignment operator by "moving" // ownership (as in auto_ptr). TIXMLASSERT( other != 0 ); TIXMLASSERT( other->_flags == 0 ); TIXMLASSERT( other->_start == 0 ); TIXMLASSERT( other->_end == 0 ); other->Reset(); other->_flags = _flags; other->_start = _start; other->_end = _end; _flags = 0; _start = 0; _end = 0; } void StrPair::Reset() { if ( _flags & NEEDS_DELETE ) { delete [] _start; } _flags = 0; _start = 0; _end = 0; } void StrPair::SetStr( const char* str, int flags ) { TIXMLASSERT( str ); Reset(); size_t len = strlen( str ); TIXMLASSERT( _start == 0 ); _start = new char[ len+1 ]; memcpy( _start, str, len+1 ); _end = _start + len; _flags = flags | NEEDS_DELETE; } char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr ) { TIXMLASSERT( p ); TIXMLASSERT( endTag && *endTag ); TIXMLASSERT(curLineNumPtr); char* start = p; const char endChar = *endTag; size_t length = strlen( endTag ); // Inner loop of text parsing. while ( *p ) { if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) { Set( start, p, strFlags ); return p + length; } else if (*p == '\n') { ++(*curLineNumPtr); } ++p; TIXMLASSERT( p ); } return 0; } char* StrPair::ParseName( char* p ) { if ( !p || !(*p) ) { return 0; } if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { return 0; } char* const start = p; ++p; while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) { ++p; } Set( start, p, 0 ); return p; } void StrPair::CollapseWhitespace() { // Adjusting _start would cause undefined behavior on delete[] TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 ); // Trim leading space. _start = XMLUtil::SkipWhiteSpace( _start, 0 ); if ( *_start ) { const char* p = _start; // the read pointer char* q = _start; // the write pointer while( *p ) { if ( XMLUtil::IsWhiteSpace( *p )) { p = XMLUtil::SkipWhiteSpace( p, 0 ); if ( *p == 0 ) { break; // don't write to q; this trims the trailing space. } *q = ' '; ++q; } *q = *p; ++q; ++p; } *q = 0; } } const char* StrPair::GetStr() { TIXMLASSERT( _start ); TIXMLASSERT( _end ); if ( _flags & NEEDS_FLUSH ) { *_end = 0; _flags ^= NEEDS_FLUSH; if ( _flags ) { const char* p = _start; // the read pointer char* q = _start; // the write pointer while( p < _end ) { if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) { // CR-LF pair becomes LF // CR alone becomes LF // LF-CR becomes LF if ( *(p+1) == LF ) { p += 2; } else { ++p; } *q = LF; ++q; } else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) { if ( *(p+1) == CR ) { p += 2; } else { ++p; } *q = LF; ++q; } else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) { // Entities handled by tinyXML2: // - special entities in the entity table [in/out] // - numeric character reference [in] // 中 or 中 if ( *(p+1) == '#' ) { const int buflen = 10; char buf[buflen] = { 0 }; int len = 0; const char* adjusted = const_cast( XMLUtil::GetCharacterRef( p, buf, &len ) ); if ( adjusted == 0 ) { *q = *p; ++p; ++q; } else { TIXMLASSERT( 0 <= len && len <= buflen ); TIXMLASSERT( q + len <= adjusted ); p = adjusted; memcpy( q, buf, len ); q += len; } } else { bool entityFound = false; for( int i = 0; i < NUM_ENTITIES; ++i ) { const Entity& entity = entities[i]; if ( strncmp( p + 1, entity.pattern, entity.length ) == 0 && *( p + entity.length + 1 ) == ';' ) { // Found an entity - convert. *q = entity.value; ++q; p += entity.length + 2; entityFound = true; break; } } if ( !entityFound ) { // fixme: treat as error? ++p; ++q; } } } else { *q = *p; ++p; ++q; } } *q = 0; } // The loop below has plenty going on, and this // is a less useful mode. Break it out. if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) { CollapseWhitespace(); } _flags = (_flags & NEEDS_DELETE); } TIXMLASSERT( _start ); return _start; } // --------- XMLUtil ----------- // const char* XMLUtil::writeBoolTrue = "true"; const char* XMLUtil::writeBoolFalse = "false"; void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse) { static const char* defTrue = "true"; static const char* defFalse = "false"; writeBoolTrue = (writeTrue) ? writeTrue : defTrue; writeBoolFalse = (writeFalse) ? writeFalse : defFalse; } const char* XMLUtil::ReadBOM( const char* p, bool* bom ) { TIXMLASSERT( p ); TIXMLASSERT( bom ); *bom = false; const unsigned char* pu = reinterpret_cast(p); // Check for BOM: if ( *(pu+0) == TIXML_UTF_LEAD_0 && *(pu+1) == TIXML_UTF_LEAD_1 && *(pu+2) == TIXML_UTF_LEAD_2 ) { *bom = true; p += 3; } TIXMLASSERT( p ); return p; } void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) { const unsigned long BYTE_MASK = 0xBF; const unsigned long BYTE_MARK = 0x80; const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; if (input < 0x80) { *length = 1; } else if ( input < 0x800 ) { *length = 2; } else if ( input < 0x10000 ) { *length = 3; } else if ( input < 0x200000 ) { *length = 4; } else { *length = 0; // This code won't convert this correctly anyway. return; } output += *length; // Scary scary fall throughs are annotated with carefully designed comments // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc switch (*length) { case 4: --output; *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; //fall through case 3: --output; *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; //fall through case 2: --output; *output = static_cast((input | BYTE_MARK) & BYTE_MASK); input >>= 6; //fall through case 1: --output; *output = static_cast(input | FIRST_BYTE_MARK[*length]); break; default: TIXMLASSERT( false ); } } const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length ) { // Presume an entity, and pull it out. *length = 0; if ( *(p+1) == '#' && *(p+2) ) { unsigned long ucs = 0; TIXMLASSERT( sizeof( ucs ) >= 4 ); ptrdiff_t delta = 0; unsigned mult = 1; static const char SEMICOLON = ';'; if ( *(p+2) == 'x' ) { // Hexadecimal. const char* q = p+3; if ( !(*q) ) { return 0; } q = strchr( q, SEMICOLON ); if ( !q ) { return 0; } TIXMLASSERT( *q == SEMICOLON ); delta = q-p; --q; while ( *q != 'x' ) { unsigned int digit = 0; if ( *q >= '0' && *q <= '9' ) { digit = *q - '0'; } else if ( *q >= 'a' && *q <= 'f' ) { digit = *q - 'a' + 10; } else if ( *q >= 'A' && *q <= 'F' ) { digit = *q - 'A' + 10; } else { return 0; } TIXMLASSERT( digit < 16 ); TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); const unsigned int digitScaled = mult * digit; TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); ucs += digitScaled; TIXMLASSERT( mult <= UINT_MAX / 16 ); mult *= 16; --q; } } else { // Decimal. const char* q = p+2; if ( !(*q) ) { return 0; } q = strchr( q, SEMICOLON ); if ( !q ) { return 0; } TIXMLASSERT( *q == SEMICOLON ); delta = q-p; --q; while ( *q != '#' ) { if ( *q >= '0' && *q <= '9' ) { const unsigned int digit = *q - '0'; TIXMLASSERT( digit < 10 ); TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit ); const unsigned int digitScaled = mult * digit; TIXMLASSERT( ucs <= ULONG_MAX - digitScaled ); ucs += digitScaled; } else { return 0; } TIXMLASSERT( mult <= UINT_MAX / 10 ); mult *= 10; --q; } } // convert the UCS to UTF-8 ConvertUTF32ToUTF8( ucs, value, length ); return p + delta + 1; } return p+1; } void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%d", v ); } void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%u", v ); } void XMLUtil::ToStr( bool v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse); } /* ToStr() of a number is a very tricky topic. https://github.com/leethomason/tinyxml2/issues/106 */ void XMLUtil::ToStr( float v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v ); } void XMLUtil::ToStr( double v, char* buffer, int bufferSize ) { TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v ); } void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize ) { // horrible syntax trick to make the compiler happy about %lld TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast(v)); } void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize ) { // horrible syntax trick to make the compiler happy about %llu TIXML_SNPRINTF(buffer, bufferSize, "%llu", static_cast(v)); } bool XMLUtil::ToInt(const char* str, int* value) { if (IsPrefixHex(str)) { unsigned v; if (TIXML_SSCANF(str, "%x", &v) == 1) { *value = static_cast(v); return true; } } else { if (TIXML_SSCANF(str, "%d", value) == 1) { return true; } } return false; } bool XMLUtil::ToUnsigned(const char* str, unsigned* value) { if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) { return true; } return false; } bool XMLUtil::ToBool( const char* str, bool* value ) { int ival = 0; if ( ToInt( str, &ival )) { *value = (ival==0) ? false : true; return true; } static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 }; static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 }; for (int i = 0; TRUE_VALS[i]; ++i) { if (StringEqual(str, TRUE_VALS[i])) { *value = true; return true; } } for (int i = 0; FALSE_VALS[i]; ++i) { if (StringEqual(str, FALSE_VALS[i])) { *value = false; return true; } } return false; } bool XMLUtil::ToFloat( const char* str, float* value ) { if ( TIXML_SSCANF( str, "%f", value ) == 1 ) { return true; } return false; } bool XMLUtil::ToDouble( const char* str, double* value ) { if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) { return true; } return false; } bool XMLUtil::ToInt64(const char* str, int64_t* value) { if (IsPrefixHex(str)) { unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llx if (TIXML_SSCANF(str, "%llx", &v) == 1) { *value = static_cast(v); return true; } } else { long long v = 0; // horrible syntax trick to make the compiler happy about %lld if (TIXML_SSCANF(str, "%lld", &v) == 1) { *value = static_cast(v); return true; } } return false; } bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) { unsigned long long v = 0; // horrible syntax trick to make the compiler happy about %llu if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) { *value = (uint64_t)v; return true; } return false; } char* XMLDocument::Identify( char* p, XMLNode** node, bool first ) { TIXMLASSERT( node ); TIXMLASSERT( p ); char* const start = p; int const startLine = _parseCurLineNum; p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); if( !*p ) { *node = 0; TIXMLASSERT( p ); return p; } // These strings define the matching patterns: static const char* xmlHeader = { "( _commentPool ); returnNode->_parseLineNum = _parseCurLineNum; p += xmlHeaderLen; } else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) { returnNode = CreateUnlinkedNode( _commentPool ); returnNode->_parseLineNum = _parseCurLineNum; p += commentHeaderLen; } else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) { XMLText* text = CreateUnlinkedNode( _textPool ); returnNode = text; returnNode->_parseLineNum = _parseCurLineNum; p += cdataHeaderLen; text->SetCData( true ); } else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) { returnNode = CreateUnlinkedNode( _commentPool ); returnNode->_parseLineNum = _parseCurLineNum; p += dtdHeaderLen; } else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) { // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag if (WhitespaceMode() == PEDANTIC_WHITESPACE && first && p != start && *(p + elementHeaderLen) == '/') { returnNode = CreateUnlinkedNode(_textPool); returnNode->_parseLineNum = startLine; p = start; // Back it up, all the text counts. _parseCurLineNum = startLine; } else { returnNode = CreateUnlinkedNode(_elementPool); returnNode->_parseLineNum = _parseCurLineNum; p += elementHeaderLen; } } else { returnNode = CreateUnlinkedNode( _textPool ); returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character p = start; // Back it up, all the text counts. _parseCurLineNum = startLine; } TIXMLASSERT( returnNode ); TIXMLASSERT( p ); *node = returnNode; return p; } bool XMLDocument::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); if ( visitor->VisitEnter( *this ) ) { for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) { break; } } } return visitor->VisitExit( *this ); } // --------- XMLNode ----------- // XMLNode::XMLNode( XMLDocument* doc ) : _document( doc ), _parent( 0 ), _value(), _parseLineNum( 0 ), _firstChild( 0 ), _lastChild( 0 ), _prev( 0 ), _next( 0 ), _userData( 0 ), _memPool( 0 ) { } XMLNode::~XMLNode() { DeleteChildren(); if ( _parent ) { _parent->Unlink( this ); } } // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. int XMLNode::ChildElementCount(const char *value) const { int count = 0; const XMLElement *e = FirstChildElement(value); while (e) { e = e->NextSiblingElement(value); count++; } return count; } int XMLNode::ChildElementCount() const { int count = 0; const XMLElement *e = FirstChildElement(); while (e) { e = e->NextSiblingElement(); count++; } return count; } const char* XMLNode::Value() const { // Edge case: XMLDocuments don't have a Value. Return null. if ( this->ToDocument() ) return 0; return _value.GetStr(); } void XMLNode::SetValue( const char* str, bool staticMem ) { if ( staticMem ) { _value.SetInternedStr( str ); } else { _value.SetStr( str ); } } XMLNode* XMLNode::DeepClone(XMLDocument* target) const { XMLNode* clone = this->ShallowClone(target); if (!clone) return 0; for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) { XMLNode* childClone = child->DeepClone(target); TIXMLASSERT(childClone); clone->InsertEndChild(childClone); } return clone; } void XMLNode::DeleteChildren() { while( _firstChild ) { TIXMLASSERT( _lastChild ); DeleteChild( _firstChild ); } _firstChild = _lastChild = 0; } void XMLNode::Unlink( XMLNode* child ) { TIXMLASSERT( child ); TIXMLASSERT( child->_document == _document ); TIXMLASSERT( child->_parent == this ); if ( child == _firstChild ) { _firstChild = _firstChild->_next; } if ( child == _lastChild ) { _lastChild = _lastChild->_prev; } if ( child->_prev ) { child->_prev->_next = child->_next; } if ( child->_next ) { child->_next->_prev = child->_prev; } child->_next = 0; child->_prev = 0; child->_parent = 0; } void XMLNode::DeleteChild( XMLNode* node ) { TIXMLASSERT( node ); TIXMLASSERT( node->_document == _document ); TIXMLASSERT( node->_parent == this ); Unlink( node ); TIXMLASSERT(node->_prev == 0); TIXMLASSERT(node->_next == 0); TIXMLASSERT(node->_parent == 0); DeleteNode( node ); } XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) { TIXMLASSERT( addThis ); if ( addThis->_document != _document ) { TIXMLASSERT( false ); return 0; } InsertChildPreamble( addThis ); if ( _lastChild ) { TIXMLASSERT( _firstChild ); TIXMLASSERT( _lastChild->_next == 0 ); _lastChild->_next = addThis; addThis->_prev = _lastChild; _lastChild = addThis; addThis->_next = 0; } else { TIXMLASSERT( _firstChild == 0 ); _firstChild = _lastChild = addThis; addThis->_prev = 0; addThis->_next = 0; } addThis->_parent = this; return addThis; } XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis ) { TIXMLASSERT( addThis ); if ( addThis->_document != _document ) { TIXMLASSERT( false ); return 0; } InsertChildPreamble( addThis ); if ( _firstChild ) { TIXMLASSERT( _lastChild ); TIXMLASSERT( _firstChild->_prev == 0 ); _firstChild->_prev = addThis; addThis->_next = _firstChild; _firstChild = addThis; addThis->_prev = 0; } else { TIXMLASSERT( _lastChild == 0 ); _firstChild = _lastChild = addThis; addThis->_prev = 0; addThis->_next = 0; } addThis->_parent = this; return addThis; } XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ) { TIXMLASSERT( addThis ); if ( addThis->_document != _document ) { TIXMLASSERT( false ); return 0; } TIXMLASSERT( afterThis ); if ( afterThis->_parent != this ) { TIXMLASSERT( false ); return 0; } if ( afterThis == addThis ) { // Current state: BeforeThis -> AddThis -> OneAfterAddThis // Now AddThis must disappear from it's location and then // reappear between BeforeThis and OneAfterAddThis. // So just leave it where it is. return addThis; } if ( afterThis->_next == 0 ) { // The last node or the only node. return InsertEndChild( addThis ); } InsertChildPreamble( addThis ); addThis->_prev = afterThis; addThis->_next = afterThis->_next; afterThis->_next->_prev = addThis; afterThis->_next = addThis; addThis->_parent = this; return addThis; } const XMLElement* XMLNode::FirstChildElement( const char* name ) const { for( const XMLNode* node = _firstChild; node; node = node->_next ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } const XMLElement* XMLNode::LastChildElement( const char* name ) const { for( const XMLNode* node = _lastChild; node; node = node->_prev ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } const XMLElement* XMLNode::NextSiblingElement( const char* name ) const { for( const XMLNode* node = _next; node; node = node->_next ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const { for( const XMLNode* node = _prev; node; node = node->_prev ) { const XMLElement* element = node->ToElementWithName( name ); if ( element ) { return element; } } return 0; } char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) { // This is a recursive method, but thinking about it "at the current level" // it is a pretty simple flat list: // // // // With a special case: // // // // // Where the closing element (/foo) *must* be the next thing after the opening // element, and the names must match. BUT the tricky bit is that the closing // element will be read by the child. // // 'endTag' is the end tag for this node, it is returned by a call to a child. // 'parentEnd' is the end tag for the parent, which is filled in and returned. XMLDocument::DepthTracker tracker(_document); if (_document->Error()) return 0; bool first = true; while( p && *p ) { XMLNode* node = 0; p = _document->Identify( p, &node, first ); TIXMLASSERT( p ); if ( node == 0 ) { break; } first = false; const int initialLineNum = node->_parseLineNum; StrPair endTag; p = node->ParseDeep( p, &endTag, curLineNumPtr ); if ( !p ) { _document->DeleteNode( node ); if ( !_document->Error() ) { _document->SetError( XML_ERROR_PARSING, initialLineNum, 0); } break; } const XMLDeclaration* const decl = node->ToDeclaration(); if ( decl ) { // Declarations are only allowed at document level // // Multiple declarations are allowed but all declarations // must occur before anything else. // // Optimized due to a security test case. If the first node is // a declaration, and the last node is a declaration, then only // declarations have so far been added. bool wellLocated = false; if (ToDocument()) { if (FirstChild()) { wellLocated = FirstChild() && FirstChild()->ToDeclaration() && LastChild() && LastChild()->ToDeclaration(); } else { wellLocated = true; } } if ( !wellLocated ) { _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value()); _document->DeleteNode( node ); break; } } XMLElement* ele = node->ToElement(); if ( ele ) { // We read the end tag. Return it to the parent. if ( ele->ClosingType() == XMLElement::CLOSING ) { if ( parentEndTag ) { ele->_value.TransferTo( parentEndTag ); } node->_memPool->SetTracked(); // created and then immediately deleted. DeleteNode( node ); return p; } // Handle an end tag returned to this level. // And handle a bunch of annoying errors. bool mismatch = false; if ( endTag.Empty() ) { if ( ele->ClosingType() == XMLElement::OPEN ) { mismatch = true; } } else { if ( ele->ClosingType() != XMLElement::OPEN ) { mismatch = true; } else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) { mismatch = true; } } if ( mismatch ) { _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name()); _document->DeleteNode( node ); break; } } InsertEndChild( node ); } return 0; } /*static*/ void XMLNode::DeleteNode( XMLNode* node ) { if ( node == 0 ) { return; } TIXMLASSERT(node->_document); if (!node->ToDocument()) { node->_document->MarkInUse(node); } MemPool* pool = node->_memPool; node->~XMLNode(); pool->Free( node ); } void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const { TIXMLASSERT( insertThis ); TIXMLASSERT( insertThis->_document == _document ); if (insertThis->_parent) { insertThis->_parent->Unlink( insertThis ); } else { insertThis->_document->MarkInUse(insertThis); insertThis->_memPool->SetTracked(); } } const XMLElement* XMLNode::ToElementWithName( const char* name ) const { const XMLElement* element = this->ToElement(); if ( element == 0 ) { return 0; } if ( name == 0 ) { return element; } if ( XMLUtil::StringEqual( element->Name(), name ) ) { return element; } return 0; } // --------- XMLText ---------- // char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { if ( this->CData() ) { p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 ); } return p; } else { int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES; if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) { flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING; } p = _value.ParseText( p, "<", flags, curLineNumPtr ); if ( p && *p ) { return p-1; } if ( !p ) { _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 ); } } return 0; } XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern? text->SetCData( this->CData() ); return text; } bool XMLText::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLText* text = compare->ToText(); return ( text && XMLUtil::StringEqual( text->Value(), Value() ) ); } bool XMLText::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLComment ---------- // XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc ) { } XMLComment::~XMLComment() { } char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Comment parses as text. p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr ); if ( p == 0 ) { _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 ); } return p; } XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern? return comment; } bool XMLComment::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLComment* comment = compare->ToComment(); return ( comment && XMLUtil::StringEqual( comment->Value(), Value() )); } bool XMLComment::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLDeclaration ---------- // XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc ) { } XMLDeclaration::~XMLDeclaration() { //printf( "~XMLDeclaration\n" ); } char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Declaration parses as text. p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( p == 0 ) { _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 ); } return p; } XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern? return dec; } bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLDeclaration* declaration = compare->ToDeclaration(); return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() )); } bool XMLDeclaration::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLUnknown ---------- // XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc ) { } XMLUnknown::~XMLUnknown() { } char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr ) { // Unknown parses as text. p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr ); if ( !p ) { _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 ); } return p; } XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern? return text; } bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLUnknown* unknown = compare->ToUnknown(); return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() )); } bool XMLUnknown::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); return visitor->Visit( *this ); } // --------- XMLAttribute ---------- // const char* XMLAttribute::Name() const { return _name.GetStr(); } const char* XMLAttribute::Value() const { return _value.GetStr(); } char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr ) { // Parse using the name rules: bug fix, was using ParseText before p = _name.ParseName( p ); if ( !p || !*p ) { return 0; } // Skip white space before = p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( *p != '=' ) { return 0; } ++p; // move up to opening quote p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( *p != '\"' && *p != '\'' ) { return 0; } const char endTag[2] = { *p, 0 }; ++p; // move past opening quote p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr ); return p; } void XMLAttribute::SetName( const char* n ) { _name.SetStr( n ); } XMLError XMLAttribute::QueryIntValue( int* value ) const { if ( XMLUtil::ToInt( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const { if ( XMLUtil::ToUnsigned( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryInt64Value(int64_t* value) const { if (XMLUtil::ToInt64(Value(), value)) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const { if(XMLUtil::ToUnsigned64(Value(), value)) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryBoolValue( bool* value ) const { if ( XMLUtil::ToBool( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryFloatValue( float* value ) const { if ( XMLUtil::ToFloat( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } XMLError XMLAttribute::QueryDoubleValue( double* value ) const { if ( XMLUtil::ToDouble( Value(), value )) { return XML_SUCCESS; } return XML_WRONG_ATTRIBUTE_TYPE; } void XMLAttribute::SetAttribute( const char* v ) { _value.SetStr( v ); } void XMLAttribute::SetAttribute( int v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute( unsigned v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute(int64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); _value.SetStr(buf); } void XMLAttribute::SetAttribute(uint64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); _value.SetStr(buf); } void XMLAttribute::SetAttribute( bool v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute( double v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } void XMLAttribute::SetAttribute( float v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); _value.SetStr( buf ); } // --------- XMLElement ---------- // XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ), _closingType( OPEN ), _rootAttribute( 0 ) { } XMLElement::~XMLElement() { while( _rootAttribute ) { XMLAttribute* next = _rootAttribute->_next; DeleteAttribute( _rootAttribute ); _rootAttribute = next; } } const XMLAttribute* XMLElement::FindAttribute( const char* name ) const { for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) { if ( XMLUtil::StringEqual( a->Name(), name ) ) { return a; } } return 0; } const char* XMLElement::Attribute( const char* name, const char* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return 0; } if ( !value || XMLUtil::StringEqual( a->Value(), value )) { return a->Value(); } return 0; } int XMLElement::IntAttribute(const char* name, int defaultValue) const { int i = defaultValue; QueryIntAttribute(name, &i); return i; } unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const { unsigned i = defaultValue; QueryUnsignedAttribute(name, &i); return i; } int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const { int64_t i = defaultValue; QueryInt64Attribute(name, &i); return i; } uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const { uint64_t i = defaultValue; QueryUnsigned64Attribute(name, &i); return i; } bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const { bool b = defaultValue; QueryBoolAttribute(name, &b); return b; } double XMLElement::DoubleAttribute(const char* name, double defaultValue) const { double d = defaultValue; QueryDoubleAttribute(name, &d); return d; } float XMLElement::FloatAttribute(const char* name, float defaultValue) const { float f = defaultValue; QueryFloatAttribute(name, &f); return f; } const char* XMLElement::GetText() const { /* skip comment node */ const XMLNode* node = FirstChild(); while (node) { if (node->ToComment()) { node = node->NextSibling(); continue; } break; } if ( node && node->ToText() ) { return node->Value(); } return 0; } void XMLElement::SetText( const char* inText ) { if ( FirstChild() && FirstChild()->ToText() ) FirstChild()->SetValue( inText ); else { XMLText* theText = GetDocument()->NewText( inText ); InsertFirstChild( theText ); } } void XMLElement::SetText( int v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText( unsigned v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText(int64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); SetText(buf); } void XMLElement::SetText(uint64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); SetText(buf); } void XMLElement::SetText( bool v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText( float v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } void XMLElement::SetText( double v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); SetText( buf ); } XMLError XMLElement::QueryIntText( int* ival ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToInt( t, ival ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToUnsigned( t, uval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryInt64Text(int64_t* ival) const { if (FirstChild() && FirstChild()->ToText()) { const char* t = FirstChild()->Value(); if (XMLUtil::ToInt64(t, ival)) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const { if(FirstChild() && FirstChild()->ToText()) { const char* t = FirstChild()->Value(); if(XMLUtil::ToUnsigned64(t, uval)) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryBoolText( bool* bval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToBool( t, bval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryDoubleText( double* dval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToDouble( t, dval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } XMLError XMLElement::QueryFloatText( float* fval ) const { if ( FirstChild() && FirstChild()->ToText() ) { const char* t = FirstChild()->Value(); if ( XMLUtil::ToFloat( t, fval ) ) { return XML_SUCCESS; } return XML_CAN_NOT_CONVERT_TEXT; } return XML_NO_TEXT_NODE; } int XMLElement::IntText(int defaultValue) const { int i = defaultValue; QueryIntText(&i); return i; } unsigned XMLElement::UnsignedText(unsigned defaultValue) const { unsigned i = defaultValue; QueryUnsignedText(&i); return i; } int64_t XMLElement::Int64Text(int64_t defaultValue) const { int64_t i = defaultValue; QueryInt64Text(&i); return i; } uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const { uint64_t i = defaultValue; QueryUnsigned64Text(&i); return i; } bool XMLElement::BoolText(bool defaultValue) const { bool b = defaultValue; QueryBoolText(&b); return b; } double XMLElement::DoubleText(double defaultValue) const { double d = defaultValue; QueryDoubleText(&d); return d; } float XMLElement::FloatText(float defaultValue) const { float f = defaultValue; QueryFloatText(&f); return f; } XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name ) { XMLAttribute* last = 0; XMLAttribute* attrib = 0; for( attrib = _rootAttribute; attrib; last = attrib, attrib = attrib->_next ) { if ( XMLUtil::StringEqual( attrib->Name(), name ) ) { break; } } if ( !attrib ) { attrib = CreateAttribute(); TIXMLASSERT( attrib ); if ( last ) { TIXMLASSERT( last->_next == 0 ); last->_next = attrib; } else { TIXMLASSERT( _rootAttribute == 0 ); _rootAttribute = attrib; } attrib->SetName( name ); } return attrib; } void XMLElement::DeleteAttribute( const char* name ) { XMLAttribute* prev = 0; for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) { if ( XMLUtil::StringEqual( name, a->Name() ) ) { if ( prev ) { prev->_next = a->_next; } else { _rootAttribute = a->_next; } DeleteAttribute( a ); break; } prev = a; } } char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr ) { XMLAttribute* prevAttribute = 0; // Read the attributes. while( p ) { p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); if ( !(*p) ) { _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() ); return 0; } // attribute. if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) { XMLAttribute* attrib = CreateAttribute(); TIXMLASSERT( attrib ); attrib->_parseLineNum = _document->_parseCurLineNum; const int attrLineNum = attrib->_parseLineNum; p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr ); if ( !p || Attribute( attrib->Name() ) ) { DeleteAttribute( attrib ); _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() ); return 0; } // There is a minor bug here: if the attribute in the source xml // document is duplicated, it will not be detected and the // attribute will be doubly added. However, tracking the 'prevAttribute' // avoids re-scanning the attribute list. Preferring performance for // now, may reconsider in the future. if ( prevAttribute ) { TIXMLASSERT( prevAttribute->_next == 0 ); prevAttribute->_next = attrib; } else { TIXMLASSERT( _rootAttribute == 0 ); _rootAttribute = attrib; } prevAttribute = attrib; } // end of the tag else if ( *p == '>' ) { ++p; break; } // end of the tag else if ( *p == '/' && *(p+1) == '>' ) { _closingType = CLOSED; return p+2; // done; sealed element. } else { _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 ); return 0; } } return p; } void XMLElement::DeleteAttribute( XMLAttribute* attribute ) { if ( attribute == 0 ) { return; } MemPool* pool = attribute->_memPool; attribute->~XMLAttribute(); pool->Free( attribute ); } XMLAttribute* XMLElement::CreateAttribute() { TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() ); XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute(); TIXMLASSERT( attrib ); attrib->_memPool = &_document->_attributePool; attrib->_memPool->SetTracked(); return attrib; } XMLElement* XMLElement::InsertNewChildElement(const char* name) { XMLElement* node = _document->NewElement(name); return InsertEndChild(node) ? node : 0; } XMLComment* XMLElement::InsertNewComment(const char* comment) { XMLComment* node = _document->NewComment(comment); return InsertEndChild(node) ? node : 0; } XMLText* XMLElement::InsertNewText(const char* text) { XMLText* node = _document->NewText(text); return InsertEndChild(node) ? node : 0; } XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text) { XMLDeclaration* node = _document->NewDeclaration(text); return InsertEndChild(node) ? node : 0; } XMLUnknown* XMLElement::InsertNewUnknown(const char* text) { XMLUnknown* node = _document->NewUnknown(text); return InsertEndChild(node) ? node : 0; } // // // foobar // char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) { // Read the element name. p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr ); // The closing element is the form. It is // parsed just like a regular element then deleted from // the DOM. if ( *p == '/' ) { _closingType = CLOSING; ++p; } p = _value.ParseName( p ); if ( _value.Empty() ) { return 0; } p = ParseAttributes( p, curLineNumPtr ); if ( !p || !*p || _closingType != OPEN ) { return p; } p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr ); return p; } XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const { if ( !doc ) { doc = _document; } XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern? for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) { element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern? } return element; } bool XMLElement::ShallowEqual( const XMLNode* compare ) const { TIXMLASSERT( compare ); const XMLElement* other = compare->ToElement(); if ( other && XMLUtil::StringEqual( other->Name(), Name() )) { const XMLAttribute* a=FirstAttribute(); const XMLAttribute* b=other->FirstAttribute(); while ( a && b ) { if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) { return false; } a = a->Next(); b = b->Next(); } if ( a || b ) { // different count return false; } return true; } return false; } bool XMLElement::Accept( XMLVisitor* visitor ) const { TIXMLASSERT( visitor ); if ( visitor->VisitEnter( *this, _rootAttribute ) ) { for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) { if ( !node->Accept( visitor ) ) { break; } } } return visitor->VisitExit( *this ); } // --------- XMLDocument ----------- // // Warning: List must match 'enum XMLError' const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = { "XML_SUCCESS", "XML_NO_ATTRIBUTE", "XML_WRONG_ATTRIBUTE_TYPE", "XML_ERROR_FILE_NOT_FOUND", "XML_ERROR_FILE_COULD_NOT_BE_OPENED", "XML_ERROR_FILE_READ_ERROR", "XML_ERROR_PARSING_ELEMENT", "XML_ERROR_PARSING_ATTRIBUTE", "XML_ERROR_PARSING_TEXT", "XML_ERROR_PARSING_CDATA", "XML_ERROR_PARSING_COMMENT", "XML_ERROR_PARSING_DECLARATION", "XML_ERROR_PARSING_UNKNOWN", "XML_ERROR_EMPTY_DOCUMENT", "XML_ERROR_MISMATCHED_ELEMENT", "XML_ERROR_PARSING", "XML_CAN_NOT_CONVERT_TEXT", "XML_NO_TEXT_NODE", "XML_ELEMENT_DEPTH_EXCEEDED" }; XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) : XMLNode( 0 ), _writeBOM( false ), _processEntities( processEntities ), _errorID(XML_SUCCESS), _whitespaceMode( whitespaceMode ), _errorStr(), _errorLineNum( 0 ), _charBuffer( 0 ), _parseCurLineNum( 0 ), _parsingDepth(0), _unlinked(), _elementPool(), _attributePool(), _textPool(), _commentPool() { // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+) _document = this; } XMLDocument::~XMLDocument() { Clear(); } void XMLDocument::MarkInUse(const XMLNode* const node) { TIXMLASSERT(node); TIXMLASSERT(node->_parent == 0); for (size_t i = 0; i < _unlinked.Size(); ++i) { if (node == _unlinked[i]) { _unlinked.SwapRemove(i); break; } } } void XMLDocument::Clear() { DeleteChildren(); while( _unlinked.Size()) { DeleteNode(_unlinked[0]); // Will remove from _unlinked as part of delete. } #ifdef TINYXML2_DEBUG const bool hadError = Error(); #endif ClearError(); delete [] _charBuffer; _charBuffer = 0; _parsingDepth = 0; #if 0 _textPool.Trace( "text" ); _elementPool.Trace( "element" ); _commentPool.Trace( "comment" ); _attributePool.Trace( "attribute" ); #endif #ifdef TINYXML2_DEBUG if ( !hadError ) { TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() ); TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() ); TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() ); TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() ); } #endif } void XMLDocument::DeepCopy(XMLDocument* target) const { TIXMLASSERT(target); if (target == this) { return; // technically success - a no-op. } target->Clear(); for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) { target->InsertEndChild(node->DeepClone(target)); } } XMLElement* XMLDocument::NewElement( const char* name ) { XMLElement* ele = CreateUnlinkedNode( _elementPool ); ele->SetName( name ); return ele; } XMLComment* XMLDocument::NewComment( const char* str ) { XMLComment* comment = CreateUnlinkedNode( _commentPool ); comment->SetValue( str ); return comment; } XMLText* XMLDocument::NewText( const char* str ) { XMLText* text = CreateUnlinkedNode( _textPool ); text->SetValue( str ); return text; } XMLDeclaration* XMLDocument::NewDeclaration( const char* str ) { XMLDeclaration* dec = CreateUnlinkedNode( _commentPool ); dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" ); return dec; } XMLUnknown* XMLDocument::NewUnknown( const char* str ) { XMLUnknown* unk = CreateUnlinkedNode( _commentPool ); unk->SetValue( str ); return unk; } static FILE* callfopen( const char* filepath, const char* mode ) { TIXMLASSERT( filepath ); TIXMLASSERT( mode ); #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE) FILE* fp = 0; const errno_t err = fopen_s( &fp, filepath, mode ); if ( err ) { return 0; } #else FILE* fp = fopen( filepath, mode ); #endif return fp; } void XMLDocument::DeleteNode( XMLNode* node ) { TIXMLASSERT( node ); TIXMLASSERT(node->_document == this ); if (node->_parent) { node->_parent->DeleteChild( node ); } else { // Isn't in the tree. // Use the parent delete. // Also, we need to mark it tracked: we 'know' // it was never used. node->_memPool->SetTracked(); // Call the static XMLNode version: XMLNode::DeleteNode(node); } } XMLError XMLDocument::LoadFile( const char* filename ) { if ( !filename ) { TIXMLASSERT( false ); SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); return _errorID; } Clear(); FILE* fp = callfopen( filename, "rb" ); if ( !fp ) { SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ); return _errorID; } LoadFile( fp ); fclose( fp ); return _errorID; } XMLError XMLDocument::LoadFile( FILE* fp ) { Clear(); TIXML_FSEEK( fp, 0, SEEK_SET ); if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } TIXML_FSEEK( fp, 0, SEEK_END ); unsigned long long filelength; { const long long fileLengthSigned = TIXML_FTELL( fp ); TIXML_FSEEK( fp, 0, SEEK_SET ); if ( fileLengthSigned == -1L ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } TIXMLASSERT( fileLengthSigned >= 0 ); filelength = static_cast(fileLengthSigned); } const size_t maxSizeT = static_cast(-1); // We'll do the comparison as an unsigned long long, because that's guaranteed to be at // least 8 bytes, even on a 32-bit platform. if ( filelength >= static_cast(maxSizeT) ) { // Cannot handle files which won't fit in buffer together with null terminator SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } if ( filelength == 0 ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } const size_t size = static_cast(filelength); TIXMLASSERT( _charBuffer == 0 ); _charBuffer = new char[size+1]; const size_t read = fread( _charBuffer, 1, size, fp ); if ( read != size ) { SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 ); return _errorID; } _charBuffer[size] = 0; Parse(); return _errorID; } XMLError XMLDocument::SaveFile( const char* filename, bool compact ) { if ( !filename ) { TIXMLASSERT( false ); SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=" ); return _errorID; } FILE* fp = callfopen( filename, "w" ); if ( !fp ) { SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ); return _errorID; } SaveFile(fp, compact); fclose( fp ); return _errorID; } XMLError XMLDocument::SaveFile( FILE* fp, bool compact ) { // Clear any error from the last save, otherwise it will get reported // for *this* call. ClearError(); XMLPrinter stream( fp, compact ); Print( &stream ); return _errorID; } XMLError XMLDocument::Parse( const char* xml, size_t nBytes ) { Clear(); if ( nBytes == 0 || !xml || !*xml ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return _errorID; } if ( nBytes == static_cast(-1) ) { nBytes = strlen( xml ); } TIXMLASSERT( _charBuffer == 0 ); _charBuffer = new char[ nBytes+1 ]; memcpy( _charBuffer, xml, nBytes ); _charBuffer[nBytes] = 0; Parse(); if ( Error() ) { // clean up now essentially dangling memory. // and the parse fail can put objects in the // pools that are dead and inaccessible. DeleteChildren(); _elementPool.Clear(); _attributePool.Clear(); _textPool.Clear(); _commentPool.Clear(); } return _errorID; } void XMLDocument::Print( XMLPrinter* streamer ) const { if ( streamer ) { Accept( streamer ); } else { XMLPrinter stdoutStreamer( stdout ); Accept( &stdoutStreamer ); } } void XMLDocument::ClearError() { _errorID = XML_SUCCESS; _errorLineNum = 0; _errorStr.Reset(); } void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... ) { TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT); _errorID = error; _errorLineNum = lineNum; _errorStr.Reset(); const size_t BUFFER_SIZE = 1000; char* buffer = new char[BUFFER_SIZE]; TIXMLASSERT(sizeof(error) <= sizeof(int)); TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), static_cast(error), static_cast(error), lineNum); if (format) { size_t len = strlen(buffer); TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": "); len = strlen(buffer); va_list va; va_start(va, format); TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va); va_end(va); } _errorStr.SetStr(buffer); delete[] buffer; } /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID) { TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT ); const char* errorName = _errorNames[errorID]; TIXMLASSERT( errorName && errorName[0] ); return errorName; } const char* XMLDocument::ErrorStr() const { return _errorStr.Empty() ? "" : _errorStr.GetStr(); } void XMLDocument::PrintError() const { printf("%s\n", ErrorStr()); } const char* XMLDocument::ErrorName() const { return ErrorIDToName(_errorID); } void XMLDocument::Parse() { TIXMLASSERT( NoChildren() ); // Clear() must have been called previously TIXMLASSERT( _charBuffer ); _parseCurLineNum = 1; _parseLineNum = 1; char* p = _charBuffer; p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum ); p = const_cast( XMLUtil::ReadBOM( p, &_writeBOM ) ); if ( !*p ) { SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 ); return; } ParseDeep(p, 0, &_parseCurLineNum ); } void XMLDocument::PushDepth() { _parsingDepth++; if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) { SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." ); } } void XMLDocument::PopDepth() { TIXMLASSERT(_parsingDepth > 0); --_parsingDepth; } XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : _elementJustOpened( false ), _stack(), _firstElement( true ), _fp( file ), _depth( depth ), _textDepth( -1 ), _processEntities( true ), _compactMode( compact ), _buffer() { for( int i=0; i(entityValue); TIXMLASSERT( flagIndex < ENTITY_RANGE ); _entityFlag[flagIndex] = true; } _restrictedEntityFlag[static_cast('&')] = true; _restrictedEntityFlag[static_cast('<')] = true; _restrictedEntityFlag[static_cast('>')] = true; // not required, but consistency is nice _buffer.Push( 0 ); } void XMLPrinter::Print( const char* format, ... ) { va_list va; va_start( va, format ); if ( _fp ) { vfprintf( _fp, format, va ); } else { const int len = TIXML_VSCPRINTF( format, va ); // Close out and re-start the va-args va_end( va ); TIXMLASSERT( len >= 0 ); va_start( va, format ); TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 ); char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator. TIXML_VSNPRINTF( p, len+1, format, va ); } va_end( va ); } void XMLPrinter::Write( const char* data, size_t size ) { if ( _fp ) { fwrite ( data , sizeof(char), size, _fp); } else { char* p = _buffer.PushArr( static_cast(size) ) - 1; // back up over the null terminator. memcpy( p, data, size ); p[size] = 0; } } void XMLPrinter::Putc( char ch ) { if ( _fp ) { fputc ( ch, _fp); } else { char* p = _buffer.PushArr( sizeof(char) ) - 1; // back up over the null terminator. p[0] = ch; p[1] = 0; } } void XMLPrinter::PrintSpace( int depth ) { for( int i=0; i 0 && *q < ENTITY_RANGE ) { // Check for entities. If one is found, flush // the stream up until the entity, write the // entity, and keep looking. if ( flag[static_cast(*q)] ) { while ( p < q ) { const size_t delta = q - p; const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast(delta); Write( p, toPrint ); p += toPrint; } bool entityPatternPrinted = false; for( int i=0; i(delta); Write( p, toPrint ); } } else { Write( p ); } } void XMLPrinter::PushHeader( bool writeBOM, bool writeDec ) { if ( writeBOM ) { static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; Write( reinterpret_cast< const char* >( bom ) ); } if ( writeDec ) { PushDeclaration( "xml version=\"1.0\"" ); } } void XMLPrinter::PrepareForNewNode( bool compactMode ) { SealElementIfJustOpened(); if ( compactMode ) { return; } if ( _firstElement ) { PrintSpace (_depth); } else if ( _textDepth < 0) { Putc( '\n' ); PrintSpace( _depth ); } _firstElement = false; } void XMLPrinter::OpenElement( const char* name, bool compactMode ) { PrepareForNewNode( compactMode ); _stack.Push( name ); Write ( "<" ); Write ( name ); _elementJustOpened = true; ++_depth; } void XMLPrinter::PushAttribute( const char* name, const char* value ) { TIXMLASSERT( _elementJustOpened ); Putc ( ' ' ); Write( name ); Write( "=\"" ); PrintString( value, false ); Putc ( '\"' ); } void XMLPrinter::PushAttribute( const char* name, int v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::PushAttribute( const char* name, unsigned v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::PushAttribute(const char* name, int64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); PushAttribute(name, buf); } void XMLPrinter::PushAttribute(const char* name, uint64_t v) { char buf[BUF_SIZE]; XMLUtil::ToStr(v, buf, BUF_SIZE); PushAttribute(name, buf); } void XMLPrinter::PushAttribute( const char* name, bool v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::PushAttribute( const char* name, double v ) { char buf[BUF_SIZE]; XMLUtil::ToStr( v, buf, BUF_SIZE ); PushAttribute( name, buf ); } void XMLPrinter::CloseElement( bool compactMode ) { --_depth; const char* name = _stack.Pop(); if ( _elementJustOpened ) { Write( "/>" ); } else { if ( _textDepth < 0 && !compactMode) { Putc( '\n' ); PrintSpace( _depth ); } Write ( "" ); } if ( _textDepth == _depth ) { _textDepth = -1; } if ( _depth == 0 && !compactMode) { Putc( '\n' ); } _elementJustOpened = false; } void XMLPrinter::SealElementIfJustOpened() { if ( !_elementJustOpened ) { return; } _elementJustOpened = false; Putc( '>' ); } void XMLPrinter::PushText( const char* text, bool cdata ) { _textDepth = _depth-1; SealElementIfJustOpened(); if ( cdata ) { Write( "" ); } else { PrintString( text, true ); } } void XMLPrinter::PushText( int64_t value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( uint64_t value ) { char buf[BUF_SIZE]; XMLUtil::ToStr(value, buf, BUF_SIZE); PushText(buf, false); } void XMLPrinter::PushText( int value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( unsigned value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( bool value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( float value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushText( double value ) { char buf[BUF_SIZE]; XMLUtil::ToStr( value, buf, BUF_SIZE ); PushText( buf, false ); } void XMLPrinter::PushComment( const char* comment ) { PrepareForNewNode( _compactMode ); Write( "" ); } void XMLPrinter::PushDeclaration( const char* value ) { PrepareForNewNode( _compactMode ); Write( "" ); } void XMLPrinter::PushUnknown( const char* value ) { PrepareForNewNode( _compactMode ); Write( "' ); } bool XMLPrinter::VisitEnter( const XMLDocument& doc ) { _processEntities = doc.ProcessEntities(); if ( doc.HasBOM() ) { PushHeader( true, false ); } return true; } bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) { const XMLElement* parentElem = 0; if ( element.Parent() ) { parentElem = element.Parent()->ToElement(); } const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode; OpenElement( element.Name(), compactMode ); while ( attribute ) { PushAttribute( attribute->Name(), attribute->Value() ); attribute = attribute->Next(); } return true; } bool XMLPrinter::VisitExit( const XMLElement& element ) { CloseElement( CompactMode(element) ); return true; } bool XMLPrinter::Visit( const XMLText& text ) { PushText( text.Value(), text.CData() ); return true; } bool XMLPrinter::Visit( const XMLComment& comment ) { PushComment( comment.Value() ); return true; } bool XMLPrinter::Visit( const XMLDeclaration& declaration ) { PushDeclaration( declaration.Value() ); return true; } bool XMLPrinter::Visit( const XMLUnknown& unknown ) { PushUnknown( unknown.Value() ); return true; } } // namespace tinyxml2 ================================================ FILE: lib/TinyXML-2/tinyxml2.h ================================================ /* Original code by Lee Thomason (www.grinninglizard.com) This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #ifndef TINYXML2_INCLUDED #define TINYXML2_INCLUDED #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) # include # include # include # include # include # if defined(__PS3__) # include # endif #else # include # include # include # include # include #endif #include /* gcc: g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe Formatting, Artistic Style: AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h */ #if defined( _DEBUG ) || defined (__DEBUG__) # ifndef TINYXML2_DEBUG # define TINYXML2_DEBUG # endif #endif #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4251) #endif #ifdef _MSC_VER # ifdef TINYXML2_EXPORT # define TINYXML2_LIB __declspec(dllexport) # elif defined(TINYXML2_IMPORT) # define TINYXML2_LIB __declspec(dllimport) # else # define TINYXML2_LIB # endif #elif __GNUC__ >= 4 # define TINYXML2_LIB __attribute__((visibility("default"))) #else # define TINYXML2_LIB #endif #if !defined(TIXMLASSERT) #if defined(TINYXML2_DEBUG) # if defined(_MSC_VER) # // "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like # define TIXMLASSERT( x ) do { if ( !((void)0,(x))) { __debugbreak(); } } while(false) # elif defined (ANDROID_NDK) # include # define TIXMLASSERT( x ) do { if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); } } while(false) # else # include # define TIXMLASSERT assert # endif #else # define TIXMLASSERT( x ) do {} while(false) #endif #endif /* Versioning, past 1.0.14: http://semver.org/ */ static const int TIXML2_MAJOR_VERSION = 10; static const int TIXML2_MINOR_VERSION = 0; static const int TIXML2_PATCH_VERSION = 0; #define TINYXML2_MAJOR_VERSION 10 #define TINYXML2_MINOR_VERSION 0 #define TINYXML2_PATCH_VERSION 0 // A fixed element depth limit is problematic. There needs to be a // limit to avoid a stack overflow. However, that limit varies per // system, and the capacity of the stack. On the other hand, it's a trivial // attack that can result from ill, malicious, or even correctly formed XML, // so there needs to be a limit in place. static const int TINYXML2_MAX_ELEMENT_DEPTH = 500; namespace tinyxml2 { class XMLDocument; class XMLElement; class XMLAttribute; class XMLComment; class XMLText; class XMLDeclaration; class XMLUnknown; class XMLPrinter; /* A class that wraps strings. Normally stores the start and end pointers into the XML file itself, and will apply normalization and entity translation if actually read. Can also store (and memory manage) a traditional char[] Isn't clear why TINYXML2_LIB is needed; but seems to fix #719 */ class TINYXML2_LIB StrPair { public: enum Mode { NEEDS_ENTITY_PROCESSING = 0x01, NEEDS_NEWLINE_NORMALIZATION = 0x02, NEEDS_WHITESPACE_COLLAPSING = 0x04, TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, ATTRIBUTE_NAME = 0, ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION, ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION, COMMENT = NEEDS_NEWLINE_NORMALIZATION }; StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {} ~StrPair(); void Set( char* start, char* end, int flags ) { TIXMLASSERT( start ); TIXMLASSERT( end ); Reset(); _start = start; _end = end; _flags = flags | NEEDS_FLUSH; } const char* GetStr(); bool Empty() const { return _start == _end; } void SetInternedStr( const char* str ) { Reset(); _start = const_cast(str); } void SetStr( const char* str, int flags=0 ); char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr ); char* ParseName( char* in ); void TransferTo( StrPair* other ); void Reset(); private: void CollapseWhitespace(); enum { NEEDS_FLUSH = 0x100, NEEDS_DELETE = 0x200 }; int _flags; char* _start; char* _end; StrPair( const StrPair& other ); // not supported void operator=( const StrPair& other ); // not supported, use TransferTo() }; /* A dynamic array of Plain Old Data. Doesn't support constructors, etc. Has a small initial memory pool, so that low or no usage will not cause a call to new/delete */ template class DynArray { public: DynArray() : _mem( _pool ), _allocated( INITIAL_SIZE ), _size( 0 ) { } ~DynArray() { if ( _mem != _pool ) { delete [] _mem; } } void Clear() { _size = 0; } void Push( T t ) { TIXMLASSERT( _size < INT_MAX ); EnsureCapacity( _size+1 ); _mem[_size] = t; ++_size; } T* PushArr( size_t count ) { TIXMLASSERT( _size <= SIZE_MAX - count ); EnsureCapacity( _size+count ); T* ret = &_mem[_size]; _size += count; return ret; } T Pop() { TIXMLASSERT( _size > 0 ); --_size; return _mem[_size]; } void PopArr( size_t count ) { TIXMLASSERT( _size >= count ); _size -= count; } bool Empty() const { return _size == 0; } T& operator[](size_t i) { TIXMLASSERT( i < _size ); return _mem[i]; } const T& operator[](size_t i) const { TIXMLASSERT( i < _size ); return _mem[i]; } const T& PeekTop() const { TIXMLASSERT( _size > 0 ); return _mem[ _size - 1]; } size_t Size() const { TIXMLASSERT( _size >= 0 ); return _size; } size_t Capacity() const { TIXMLASSERT( _allocated >= INITIAL_SIZE ); return _allocated; } void SwapRemove(size_t i) { TIXMLASSERT(i < _size); TIXMLASSERT(_size > 0); _mem[i] = _mem[_size - 1]; --_size; } const T* Mem() const { TIXMLASSERT( _mem ); return _mem; } T* Mem() { TIXMLASSERT( _mem ); return _mem; } private: DynArray( const DynArray& ); // not supported void operator=( const DynArray& ); // not supported void EnsureCapacity( size_t cap ) { TIXMLASSERT( cap > 0 ); if ( cap > _allocated ) { TIXMLASSERT( cap <= SIZE_MAX / 2 / sizeof(T)); const size_t newAllocated = cap * 2; T* newMem = new T[newAllocated]; TIXMLASSERT( newAllocated >= _size ); memcpy( newMem, _mem, sizeof(T) * _size ); // warning: not using constructors, only works for PODs if ( _mem != _pool ) { delete [] _mem; } _mem = newMem; _allocated = newAllocated; } } T* _mem; T _pool[INITIAL_SIZE]; size_t _allocated; // objects allocated size_t _size; // number objects in use }; /* Parent virtual class of a pool for fast allocation and deallocation of objects. */ class MemPool { public: MemPool() {} virtual ~MemPool() {} virtual size_t ItemSize() const = 0; virtual void* Alloc() = 0; virtual void Free( void* ) = 0; virtual void SetTracked() = 0; }; /* Template child class to create pools of the correct type. */ template< size_t ITEM_SIZE > class MemPoolT : public MemPool { public: MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {} ~MemPoolT() { MemPoolT< ITEM_SIZE >::Clear(); } void Clear() { // Delete the blocks. while( !_blockPtrs.Empty()) { Block* lastBlock = _blockPtrs.Pop(); delete lastBlock; } _root = 0; _currentAllocs = 0; _nAllocs = 0; _maxAllocs = 0; _nUntracked = 0; } virtual size_t ItemSize() const override { return ITEM_SIZE; } size_t CurrentAllocs() const { return _currentAllocs; } virtual void* Alloc() override{ if ( !_root ) { // Need a new block. Block* block = new Block; _blockPtrs.Push( block ); Item* blockItems = block->items; for( size_t i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) { blockItems[i].next = &(blockItems[i + 1]); } blockItems[ITEMS_PER_BLOCK - 1].next = 0; _root = blockItems; } Item* const result = _root; TIXMLASSERT( result != 0 ); _root = _root->next; ++_currentAllocs; if ( _currentAllocs > _maxAllocs ) { _maxAllocs = _currentAllocs; } ++_nAllocs; ++_nUntracked; return result; } virtual void Free( void* mem ) override { if ( !mem ) { return; } --_currentAllocs; Item* item = static_cast( mem ); #ifdef TINYXML2_DEBUG memset( item, 0xfe, sizeof( *item ) ); #endif item->next = _root; _root = item; } void Trace( const char* name ) { printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n", name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs, ITEM_SIZE, _nAllocs, _blockPtrs.Size() ); } void SetTracked() override { --_nUntracked; } size_t Untracked() const { return _nUntracked; } // This number is perf sensitive. 4k seems like a good tradeoff on my machine. // The test file is large, 170k. // Release: VS2010 gcc(no opt) // 1k: 4000 // 2k: 4000 // 4k: 3900 21000 // 16k: 5200 // 32k: 4300 // 64k: 4000 21000 // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK // in private part if ITEMS_PER_BLOCK is private enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE }; private: MemPoolT( const MemPoolT& ); // not supported void operator=( const MemPoolT& ); // not supported union Item { Item* next; char itemData[static_cast(ITEM_SIZE)]; }; struct Block { Item items[ITEMS_PER_BLOCK]; }; DynArray< Block*, 10 > _blockPtrs; Item* _root; size_t _currentAllocs; size_t _nAllocs; size_t _maxAllocs; size_t _nUntracked; }; /** Implements the interface to the "Visitor pattern" (see the Accept() method.) If you call the Accept() method, it requires being passed a XMLVisitor class to handle callbacks. For nodes that contain other nodes (Document, Element) you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs are simply called with Visit(). If you return 'true' from a Visit method, recursive parsing will continue. If you return false, no children of this node or its siblings will be visited. All flavors of Visit methods have a default implementation that returns 'true' (continue visiting). You need to only override methods that are interesting to you. Generally Accept() is called on the XMLDocument, although all nodes support visiting. You should never change the document from a callback. @sa XMLNode::Accept() */ class TINYXML2_LIB XMLVisitor { public: virtual ~XMLVisitor() {} /// Visit a document. virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; } /// Visit a document. virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; } /// Visit an element. virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; } /// Visit an element. virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; } /// Visit a declaration. virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; } /// Visit a text node. virtual bool Visit( const XMLText& /*text*/ ) { return true; } /// Visit a comment node. virtual bool Visit( const XMLComment& /*comment*/ ) { return true; } /// Visit an unknown node. virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; } }; // WARNING: must match XMLDocument::_errorNames[] enum XMLError { XML_SUCCESS = 0, XML_NO_ATTRIBUTE, XML_WRONG_ATTRIBUTE_TYPE, XML_ERROR_FILE_NOT_FOUND, XML_ERROR_FILE_COULD_NOT_BE_OPENED, XML_ERROR_FILE_READ_ERROR, XML_ERROR_PARSING_ELEMENT, XML_ERROR_PARSING_ATTRIBUTE, XML_ERROR_PARSING_TEXT, XML_ERROR_PARSING_CDATA, XML_ERROR_PARSING_COMMENT, XML_ERROR_PARSING_DECLARATION, XML_ERROR_PARSING_UNKNOWN, XML_ERROR_EMPTY_DOCUMENT, XML_ERROR_MISMATCHED_ELEMENT, XML_ERROR_PARSING, XML_CAN_NOT_CONVERT_TEXT, XML_NO_TEXT_NODE, XML_ELEMENT_DEPTH_EXCEEDED, XML_ERROR_COUNT }; /* Utility functionality. */ class TINYXML2_LIB XMLUtil { public: static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr ) { TIXMLASSERT( p ); while( IsWhiteSpace(*p) ) { if (curLineNumPtr && *p == '\n') { ++(*curLineNumPtr); } ++p; } TIXMLASSERT( p ); return p; } static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) { return const_cast( SkipWhiteSpace( const_cast(p), curLineNumPtr ) ); } // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't // correct, but simple, and usually works. static bool IsWhiteSpace( char p ) { return !IsUTF8Continuation(p) && isspace( static_cast(p) ); } inline static bool IsNameStartChar( unsigned char ch ) { if ( ch >= 128 ) { // This is a heuristic guess in attempt to not implement Unicode-aware isalpha() return true; } if ( isalpha( ch ) ) { return true; } return ch == ':' || ch == '_'; } inline static bool IsNameChar( unsigned char ch ) { return IsNameStartChar( ch ) || isdigit( ch ) || ch == '.' || ch == '-'; } inline static bool IsPrefixHex( const char* p) { p = SkipWhiteSpace(p, 0); return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X'); } inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) { if ( p == q ) { return true; } TIXMLASSERT( p ); TIXMLASSERT( q ); TIXMLASSERT( nChar >= 0 ); return strncmp( p, q, static_cast(nChar) ) == 0; } inline static bool IsUTF8Continuation( const char p ) { return ( p & 0x80 ) != 0; } static const char* ReadBOM( const char* p, bool* hasBOM ); // p is the starting location, // the UTF-8 value of the entity will be placed in value, and length filled in. static const char* GetCharacterRef( const char* p, char* value, int* length ); static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); // converts primitive types to strings static void ToStr( int v, char* buffer, int bufferSize ); static void ToStr( unsigned v, char* buffer, int bufferSize ); static void ToStr( bool v, char* buffer, int bufferSize ); static void ToStr( float v, char* buffer, int bufferSize ); static void ToStr( double v, char* buffer, int bufferSize ); static void ToStr(int64_t v, char* buffer, int bufferSize); static void ToStr(uint64_t v, char* buffer, int bufferSize); // converts strings to primitive types static bool ToInt( const char* str, int* value ); static bool ToUnsigned( const char* str, unsigned* value ); static bool ToBool( const char* str, bool* value ); static bool ToFloat( const char* str, float* value ); static bool ToDouble( const char* str, double* value ); static bool ToInt64(const char* str, int64_t* value); static bool ToUnsigned64(const char* str, uint64_t* value); // Changes what is serialized for a boolean value. // Default to "true" and "false". Shouldn't be changed // unless you have a special testing or compatibility need. // Be careful: static, global, & not thread safe. // Be sure to set static const memory as parameters. static void SetBoolSerialization(const char* writeTrue, const char* writeFalse); private: static const char* writeBoolTrue; static const char* writeBoolFalse; }; /** XMLNode is a base class for every object that is in the XML Document Object Model (DOM), except XMLAttributes. Nodes have siblings, a parent, and children which can be navigated. A node is always in a XMLDocument. The type of a XMLNode can be queried, and it can be cast to its more defined type. A XMLDocument allocates memory for all its Nodes. When the XMLDocument gets deleted, all its Nodes will also be deleted. @verbatim A Document can contain: Element (container or leaf) Comment (leaf) Unknown (leaf) Declaration( leaf ) An Element can contain: Element (container or leaf) Text (leaf) Attributes (not on tree) Comment (leaf) Unknown (leaf) @endverbatim */ class TINYXML2_LIB XMLNode { friend class XMLDocument; friend class XMLElement; public: /// Get the XMLDocument that owns this XMLNode. const XMLDocument* GetDocument() const { TIXMLASSERT( _document ); return _document; } /// Get the XMLDocument that owns this XMLNode. XMLDocument* GetDocument() { TIXMLASSERT( _document ); return _document; } /// Safely cast to an Element, or null. virtual XMLElement* ToElement() { return 0; } /// Safely cast to Text, or null. virtual XMLText* ToText() { return 0; } /// Safely cast to a Comment, or null. virtual XMLComment* ToComment() { return 0; } /// Safely cast to a Document, or null. virtual XMLDocument* ToDocument() { return 0; } /// Safely cast to a Declaration, or null. virtual XMLDeclaration* ToDeclaration() { return 0; } /// Safely cast to an Unknown, or null. virtual XMLUnknown* ToUnknown() { return 0; } virtual const XMLElement* ToElement() const { return 0; } virtual const XMLText* ToText() const { return 0; } virtual const XMLComment* ToComment() const { return 0; } virtual const XMLDocument* ToDocument() const { return 0; } virtual const XMLDeclaration* ToDeclaration() const { return 0; } virtual const XMLUnknown* ToUnknown() const { return 0; } // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2. int ChildElementCount(const char *value) const; int ChildElementCount() const; /** The meaning of 'value' changes for the specific type. @verbatim Document: empty (NULL is returned, not an empty string) Element: name of the element Comment: the comment text Unknown: the tag contents Text: the text string @endverbatim */ const char* Value() const; /** Set the Value of an XML node. @sa Value() */ void SetValue( const char* val, bool staticMem=false ); /// Gets the line number the node is in, if the document was parsed from a file. int GetLineNum() const { return _parseLineNum; } /// Get the parent of this node on the DOM. const XMLNode* Parent() const { return _parent; } XMLNode* Parent() { return _parent; } /// Returns true if this node has no children. bool NoChildren() const { return !_firstChild; } /// Get the first child node, or null if none exists. const XMLNode* FirstChild() const { return _firstChild; } XMLNode* FirstChild() { return _firstChild; } /** Get the first child element, or optionally the first child element with the specified name. */ const XMLElement* FirstChildElement( const char* name = 0 ) const; XMLElement* FirstChildElement( const char* name = 0 ) { return const_cast(const_cast(this)->FirstChildElement( name )); } /// Get the last child node, or null if none exists. const XMLNode* LastChild() const { return _lastChild; } XMLNode* LastChild() { return _lastChild; } /** Get the last child element or optionally the last child element with the specified name. */ const XMLElement* LastChildElement( const char* name = 0 ) const; XMLElement* LastChildElement( const char* name = 0 ) { return const_cast(const_cast(this)->LastChildElement(name) ); } /// Get the previous (left) sibling node of this node. const XMLNode* PreviousSibling() const { return _prev; } XMLNode* PreviousSibling() { return _prev; } /// Get the previous (left) sibling element of this node, with an optionally supplied name. const XMLElement* PreviousSiblingElement( const char* name = 0 ) const ; XMLElement* PreviousSiblingElement( const char* name = 0 ) { return const_cast(const_cast(this)->PreviousSiblingElement( name ) ); } /// Get the next (right) sibling node of this node. const XMLNode* NextSibling() const { return _next; } XMLNode* NextSibling() { return _next; } /// Get the next (right) sibling element of this node, with an optionally supplied name. const XMLElement* NextSiblingElement( const char* name = 0 ) const; XMLElement* NextSiblingElement( const char* name = 0 ) { return const_cast(const_cast(this)->NextSiblingElement( name ) ); } /** Add a child node as the last (right) child. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the node does not belong to the same document. */ XMLNode* InsertEndChild( XMLNode* addThis ); XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); } /** Add a child node as the first (left) child. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the node does not belong to the same document. */ XMLNode* InsertFirstChild( XMLNode* addThis ); /** Add a node after the specified child node. If the child node is already part of the document, it is moved from its old location to the new location. Returns the addThis argument or 0 if the afterThis node is not a child of this node, or if the node does not belong to the same document. */ XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); /** Delete all the children of this node. */ void DeleteChildren(); /** Delete a child of this node. */ void DeleteChild( XMLNode* node ); /** Make a copy of this node, but not its children. You may pass in a Document pointer that will be the owner of the new Node. If the 'document' is null, then the node returned will be allocated from the current Document. (this->GetDocument()) Note: if called on a XMLDocument, this will return null. */ virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0; /** Make a copy of this node and all its children. If the 'target' is null, then the nodes will be allocated in the current document. If 'target' is specified, the memory will be allocated in the specified XMLDocument. NOTE: This is probably not the correct tool to copy a document, since XMLDocuments can have multiple top level XMLNodes. You probably want to use XMLDocument::DeepCopy() */ XMLNode* DeepClone( XMLDocument* target ) const; /** Test if 2 nodes are the same, but don't test children. The 2 nodes do not need to be in the same Document. Note: if called on a XMLDocument, this will return false. */ virtual bool ShallowEqual( const XMLNode* compare ) const = 0; /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the XML tree will be conditionally visited and the host will be called back via the XMLVisitor interface. This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this interface versus any other.) The interface has been based on ideas from: - http://www.saxproject.org/ - http://c2.com/cgi/wiki?HierarchicalVisitorPattern Which are both good references for "visiting". An example of using Accept(): @verbatim XMLPrinter printer; tinyxmlDoc.Accept( &printer ); const char* xmlcstr = printer.CStr(); @endverbatim */ virtual bool Accept( XMLVisitor* visitor ) const = 0; /** Set user data into the XMLNode. TinyXML-2 in no way processes or interprets user data. It is initially 0. */ void SetUserData(void* userData) { _userData = userData; } /** Get user data set into the XMLNode. TinyXML-2 in no way processes or interprets user data. It is initially 0. */ void* GetUserData() const { return _userData; } protected: explicit XMLNode( XMLDocument* ); virtual ~XMLNode(); virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr); XMLDocument* _document; XMLNode* _parent; mutable StrPair _value; int _parseLineNum; XMLNode* _firstChild; XMLNode* _lastChild; XMLNode* _prev; XMLNode* _next; void* _userData; private: MemPool* _memPool; void Unlink( XMLNode* child ); static void DeleteNode( XMLNode* node ); void InsertChildPreamble( XMLNode* insertThis ) const; const XMLElement* ToElementWithName( const char* name ) const; XMLNode( const XMLNode& ); // not supported XMLNode& operator=( const XMLNode& ); // not supported }; /** XML text. Note that a text node can have child element nodes, for example: @verbatim This is bold @endverbatim A text node can have 2 ways to output the next. "normal" output and CDATA. It will default to the mode it was parsed from the XML file and you generally want to leave it alone, but you can change the output mode with SetCData() and query it with CData(). */ class TINYXML2_LIB XMLText : public XMLNode { friend class XMLDocument; public: virtual bool Accept( XMLVisitor* visitor ) const override; virtual XMLText* ToText() override { return this; } virtual const XMLText* ToText() const override { return this; } /// Declare whether this should be CDATA or standard text. void SetCData( bool isCData ) { _isCData = isCData; } /// Returns true if this is a CDATA text element. bool CData() const { return _isCData; } virtual XMLNode* ShallowClone( XMLDocument* document ) const override; virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLText( XMLDocument* doc ) : XMLNode( doc ), _isCData( false ) {} virtual ~XMLText() {} char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: bool _isCData; XMLText( const XMLText& ); // not supported XMLText& operator=( const XMLText& ); // not supported }; /** An XML Comment. */ class TINYXML2_LIB XMLComment : public XMLNode { friend class XMLDocument; public: virtual XMLComment* ToComment() override { return this; } virtual const XMLComment* ToComment() const override { return this; } virtual bool Accept( XMLVisitor* visitor ) const override; virtual XMLNode* ShallowClone( XMLDocument* document ) const override; virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLComment( XMLDocument* doc ); virtual ~XMLComment(); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr) override; private: XMLComment( const XMLComment& ); // not supported XMLComment& operator=( const XMLComment& ); // not supported }; /** In correct XML the declaration is the first entry in the file. @verbatim @endverbatim TinyXML-2 will happily read or write files without a declaration, however. The text of the declaration isn't interpreted. It is parsed and written as a string. */ class TINYXML2_LIB XMLDeclaration : public XMLNode { friend class XMLDocument; public: virtual XMLDeclaration* ToDeclaration() override { return this; } virtual const XMLDeclaration* ToDeclaration() const override { return this; } virtual bool Accept( XMLVisitor* visitor ) const override; virtual XMLNode* ShallowClone( XMLDocument* document ) const override; virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLDeclaration( XMLDocument* doc ); virtual ~XMLDeclaration(); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLDeclaration( const XMLDeclaration& ); // not supported XMLDeclaration& operator=( const XMLDeclaration& ); // not supported }; /** Any tag that TinyXML-2 doesn't recognize is saved as an unknown. It is a tag of text, but should not be modified. It will be written back to the XML, unchanged, when the file is saved. DTD tags get thrown into XMLUnknowns. */ class TINYXML2_LIB XMLUnknown : public XMLNode { friend class XMLDocument; public: virtual XMLUnknown* ToUnknown() override { return this; } virtual const XMLUnknown* ToUnknown() const override { return this; } virtual bool Accept( XMLVisitor* visitor ) const override; virtual XMLNode* ShallowClone( XMLDocument* document ) const override; virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: explicit XMLUnknown( XMLDocument* doc ); virtual ~XMLUnknown(); char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLUnknown( const XMLUnknown& ); // not supported XMLUnknown& operator=( const XMLUnknown& ); // not supported }; /** An attribute is a name-value pair. Elements have an arbitrary number of attributes, each with a unique name. @note The attributes are not XMLNodes. You may only query the Next() attribute in a list. */ class TINYXML2_LIB XMLAttribute { friend class XMLElement; public: /// The name of the attribute. const char* Name() const; /// The value of the attribute. const char* Value() const; /// Gets the line number the attribute is in, if the document was parsed from a file. int GetLineNum() const { return _parseLineNum; } /// The next attribute in the list. const XMLAttribute* Next() const { return _next; } /** IntValue interprets the attribute as an integer, and returns the value. If the value isn't an integer, 0 will be returned. There is no error checking; use QueryIntValue() if you need error checking. */ int IntValue() const { int i = 0; QueryIntValue(&i); return i; } int64_t Int64Value() const { int64_t i = 0; QueryInt64Value(&i); return i; } uint64_t Unsigned64Value() const { uint64_t i = 0; QueryUnsigned64Value(&i); return i; } /// Query as an unsigned integer. See IntValue() unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; } /// Query as a boolean. See IntValue() bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; } /// Query as a double. See IntValue() double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; } /// Query as a float. See IntValue() float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; } /** QueryIntValue interprets the attribute as an integer, and returns the value in the provided parameter. The function will return XML_SUCCESS on success, and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful. */ XMLError QueryIntValue( int* value ) const; /// See QueryIntValue XMLError QueryUnsignedValue( unsigned int* value ) const; /// See QueryIntValue XMLError QueryInt64Value(int64_t* value) const; /// See QueryIntValue XMLError QueryUnsigned64Value(uint64_t* value) const; /// See QueryIntValue XMLError QueryBoolValue( bool* value ) const; /// See QueryIntValue XMLError QueryDoubleValue( double* value ) const; /// See QueryIntValue XMLError QueryFloatValue( float* value ) const; /// Set the attribute to a string value. void SetAttribute( const char* value ); /// Set the attribute to value. void SetAttribute( int value ); /// Set the attribute to value. void SetAttribute( unsigned value ); /// Set the attribute to value. void SetAttribute(int64_t value); /// Set the attribute to value. void SetAttribute(uint64_t value); /// Set the attribute to value. void SetAttribute( bool value ); /// Set the attribute to value. void SetAttribute( double value ); /// Set the attribute to value. void SetAttribute( float value ); private: enum { BUF_SIZE = 200 }; XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {} virtual ~XMLAttribute() {} XMLAttribute( const XMLAttribute& ); // not supported void operator=( const XMLAttribute& ); // not supported void SetName( const char* name ); char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr ); mutable StrPair _name; mutable StrPair _value; int _parseLineNum; XMLAttribute* _next; MemPool* _memPool; }; /** The element is a container class. It has a value, the element name, and can contain other elements, text, comments, and unknowns. Elements also contain an arbitrary number of attributes. */ class TINYXML2_LIB XMLElement : public XMLNode { friend class XMLDocument; public: /// Get the name of an element (which is the Value() of the node.) const char* Name() const { return Value(); } /// Set the name of the element. void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); } virtual XMLElement* ToElement() override { return this; } virtual const XMLElement* ToElement() const override { return this; } virtual bool Accept( XMLVisitor* visitor ) const override; /** Given an attribute name, Attribute() returns the value for the attribute of that name, or null if none exists. For example: @verbatim const char* value = ele->Attribute( "foo" ); @endverbatim The 'value' parameter is normally null. However, if specified, the attribute will only be returned if the 'name' and 'value' match. This allow you to write code: @verbatim if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar(); @endverbatim rather than: @verbatim if ( ele->Attribute( "foo" ) ) { if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar(); } @endverbatim */ const char* Attribute( const char* name, const char* value=0 ) const; /** Given an attribute name, IntAttribute() returns the value of the attribute interpreted as an integer. The default value will be returned if the attribute isn't present, or if there is an error. (For a method with error checking, see QueryIntAttribute()). */ int IntAttribute(const char* name, int defaultValue = 0) const; /// See IntAttribute() unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const; /// See IntAttribute() int64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const; /// See IntAttribute() uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const; /// See IntAttribute() bool BoolAttribute(const char* name, bool defaultValue = false) const; /// See IntAttribute() double DoubleAttribute(const char* name, double defaultValue = 0) const; /// See IntAttribute() float FloatAttribute(const char* name, float defaultValue = 0) const; /** Given an attribute name, QueryIntAttribute() returns XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion can't be performed, or XML_NO_ATTRIBUTE if the attribute doesn't exist. If successful, the result of the conversion will be written to 'value'. If not successful, nothing will be written to 'value'. This allows you to provide default value: @verbatim int value = 10; QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 @endverbatim */ XMLError QueryIntAttribute( const char* name, int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryIntValue( value ); } /// See QueryIntAttribute() XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryUnsignedValue( value ); } /// See QueryIntAttribute() XMLError QueryInt64Attribute(const char* name, int64_t* value) const { const XMLAttribute* a = FindAttribute(name); if (!a) { return XML_NO_ATTRIBUTE; } return a->QueryInt64Value(value); } /// See QueryIntAttribute() XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const { const XMLAttribute* a = FindAttribute(name); if(!a) { return XML_NO_ATTRIBUTE; } return a->QueryUnsigned64Value(value); } /// See QueryIntAttribute() XMLError QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryBoolValue( value ); } /// See QueryIntAttribute() XMLError QueryDoubleAttribute( const char* name, double* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryDoubleValue( value ); } /// See QueryIntAttribute() XMLError QueryFloatAttribute( const char* name, float* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) { return XML_NO_ATTRIBUTE; } return a->QueryFloatValue( value ); } /// See QueryIntAttribute() XMLError QueryStringAttribute(const char* name, const char** value) const { const XMLAttribute* a = FindAttribute(name); if (!a) { return XML_NO_ATTRIBUTE; } *value = a->Value(); return XML_SUCCESS; } /** Given an attribute name, QueryAttribute() returns XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion can't be performed, or XML_NO_ATTRIBUTE if the attribute doesn't exist. It is overloaded for the primitive types, and is a generally more convenient replacement of QueryIntAttribute() and related functions. If successful, the result of the conversion will be written to 'value'. If not successful, nothing will be written to 'value'. This allows you to provide default value: @verbatim int value = 10; QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10 @endverbatim */ XMLError QueryAttribute( const char* name, int* value ) const { return QueryIntAttribute( name, value ); } XMLError QueryAttribute( const char* name, unsigned int* value ) const { return QueryUnsignedAttribute( name, value ); } XMLError QueryAttribute(const char* name, int64_t* value) const { return QueryInt64Attribute(name, value); } XMLError QueryAttribute(const char* name, uint64_t* value) const { return QueryUnsigned64Attribute(name, value); } XMLError QueryAttribute( const char* name, bool* value ) const { return QueryBoolAttribute( name, value ); } XMLError QueryAttribute( const char* name, double* value ) const { return QueryDoubleAttribute( name, value ); } XMLError QueryAttribute( const char* name, float* value ) const { return QueryFloatAttribute( name, value ); } XMLError QueryAttribute(const char* name, const char** value) const { return QueryStringAttribute(name, value); } /// Sets the named attribute to value. void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute(const char* name, int64_t value) { XMLAttribute* a = FindOrCreateAttribute(name); a->SetAttribute(value); } /// Sets the named attribute to value. void SetAttribute(const char* name, uint64_t value) { XMLAttribute* a = FindOrCreateAttribute(name); a->SetAttribute(value); } /// Sets the named attribute to value. void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /// Sets the named attribute to value. void SetAttribute( const char* name, float value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } /** Delete an attribute. */ void DeleteAttribute( const char* name ); /// Return the first attribute in the list. const XMLAttribute* FirstAttribute() const { return _rootAttribute; } /// Query a specific attribute in the list. const XMLAttribute* FindAttribute( const char* name ) const; /** Convenience function for easy access to the text inside an element. Although easy and concise, GetText() is limited compared to getting the XMLText child and accessing it directly. If the first child of 'this' is a XMLText, the GetText() returns the character string of the Text node, else null is returned. This is a convenient method for getting the text of simple contained text: @verbatim This is text const char* str = fooElement->GetText(); @endverbatim 'str' will be a pointer to "This is text". Note that this function can be misleading. If the element foo was created from this XML: @verbatim This is text @endverbatim then the value of str would be null. The first child node isn't a text node, it is another element. From this XML: @verbatim This is text @endverbatim GetText() will return "This is ". */ const char* GetText() const; /** Convenience function for easy access to the text inside an element. Although easy and concise, SetText() is limited compared to creating an XMLText child and mutating it directly. If the first child of 'this' is a XMLText, SetText() sets its value to the given string, otherwise it will create a first child that is an XMLText. This is a convenient method for setting the text of simple contained text: @verbatim This is text fooElement->SetText( "Hullaballoo!" ); Hullaballoo! @endverbatim Note that this function can be misleading. If the element foo was created from this XML: @verbatim This is text @endverbatim then it will not change "This is text", but rather prefix it with a text element: @verbatim Hullaballoo!This is text @endverbatim For this XML: @verbatim @endverbatim SetText() will generate @verbatim Hullaballoo! @endverbatim */ void SetText( const char* inText ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( int value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( unsigned value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText(int64_t value); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText(uint64_t value); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( bool value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( double value ); /// Convenience method for setting text inside an element. See SetText() for important limitations. void SetText( float value ); /** Convenience method to query the value of a child text node. This is probably best shown by example. Given you have a document is this form: @verbatim 1 1.4 @endverbatim The QueryIntText() and similar functions provide a safe and easier way to get to the "value" of x and y. @verbatim int x = 0; float y = 0; // types of x and y are contrived for example const XMLElement* xElement = pointElement->FirstChildElement( "x" ); const XMLElement* yElement = pointElement->FirstChildElement( "y" ); xElement->QueryIntText( &x ); yElement->QueryFloatText( &y ); @endverbatim @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted to the requested type, and XML_NO_TEXT_NODE if there is no child text to query. */ XMLError QueryIntText( int* ival ) const; /// See QueryIntText() XMLError QueryUnsignedText( unsigned* uval ) const; /// See QueryIntText() XMLError QueryInt64Text(int64_t* uval) const; /// See QueryIntText() XMLError QueryUnsigned64Text(uint64_t* uval) const; /// See QueryIntText() XMLError QueryBoolText( bool* bval ) const; /// See QueryIntText() XMLError QueryDoubleText( double* dval ) const; /// See QueryIntText() XMLError QueryFloatText( float* fval ) const; int IntText(int defaultValue = 0) const; /// See QueryIntText() unsigned UnsignedText(unsigned defaultValue = 0) const; /// See QueryIntText() int64_t Int64Text(int64_t defaultValue = 0) const; /// See QueryIntText() uint64_t Unsigned64Text(uint64_t defaultValue = 0) const; /// See QueryIntText() bool BoolText(bool defaultValue = false) const; /// See QueryIntText() double DoubleText(double defaultValue = 0) const; /// See QueryIntText() float FloatText(float defaultValue = 0) const; /** Convenience method to create a new XMLElement and add it as last (right) child of this node. Returns the created and inserted element. */ XMLElement* InsertNewChildElement(const char* name); /// See InsertNewChildElement() XMLComment* InsertNewComment(const char* comment); /// See InsertNewChildElement() XMLText* InsertNewText(const char* text); /// See InsertNewChildElement() XMLDeclaration* InsertNewDeclaration(const char* text); /// See InsertNewChildElement() XMLUnknown* InsertNewUnknown(const char* text); // internal: enum ElementClosingType { OPEN, // CLOSED, // CLOSING // }; ElementClosingType ClosingType() const { return _closingType; } virtual XMLNode* ShallowClone( XMLDocument* document ) const override; virtual bool ShallowEqual( const XMLNode* compare ) const override; protected: char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override; private: XMLElement( XMLDocument* doc ); virtual ~XMLElement(); XMLElement( const XMLElement& ); // not supported void operator=( const XMLElement& ); // not supported XMLAttribute* FindOrCreateAttribute( const char* name ); char* ParseAttributes( char* p, int* curLineNumPtr ); static void DeleteAttribute( XMLAttribute* attribute ); XMLAttribute* CreateAttribute(); enum { BUF_SIZE = 200 }; ElementClosingType _closingType; // The attribute list is ordered; there is no 'lastAttribute' // because the list needs to be scanned for dupes before adding // a new attribute. XMLAttribute* _rootAttribute; }; enum Whitespace { PRESERVE_WHITESPACE, COLLAPSE_WHITESPACE, PEDANTIC_WHITESPACE }; /** A Document binds together all the functionality. It can be saved, loaded, and printed to the screen. All Nodes are connected and allocated to a Document. If the Document is deleted, all its Nodes are also deleted. */ class TINYXML2_LIB XMLDocument : public XMLNode { friend class XMLElement; // Gives access to SetError and Push/PopDepth, but over-access for everything else. // Wishing C++ had "internal" scope. friend class XMLNode; friend class XMLText; friend class XMLComment; friend class XMLDeclaration; friend class XMLUnknown; public: /// constructor XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE ); ~XMLDocument(); virtual XMLDocument* ToDocument() override { TIXMLASSERT( this == _document ); return this; } virtual const XMLDocument* ToDocument() const override { TIXMLASSERT( this == _document ); return this; } /** Parse an XML file from a character string. Returns XML_SUCCESS (0) on success, or an errorID. You may optionally pass in the 'nBytes', which is the number of bytes which will be parsed. If not specified, TinyXML-2 will assume 'xml' points to a null terminated string. */ XMLError Parse( const char* xml, size_t nBytes=static_cast(-1) ); /** Load an XML file from disk. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError LoadFile( const char* filename ); /** Load an XML file from disk. You are responsible for providing and closing the FILE*. NOTE: The file should be opened as binary ("rb") not text in order for TinyXML-2 to correctly do newline normalization. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError LoadFile( FILE* ); /** Save the XML file to disk. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError SaveFile( const char* filename, bool compact = false ); /** Save the XML file to disk. You are responsible for providing and closing the FILE*. Returns XML_SUCCESS (0) on success, or an errorID. */ XMLError SaveFile( FILE* fp, bool compact = false ); bool ProcessEntities() const { return _processEntities; } Whitespace WhitespaceMode() const { return _whitespaceMode; } /** Returns true if this document has a leading Byte Order Mark of UTF8. */ bool HasBOM() const { return _writeBOM; } /** Sets whether to write the BOM when writing the file. */ void SetBOM( bool useBOM ) { _writeBOM = useBOM; } /** Return the root element of DOM. Equivalent to FirstChildElement(). To get the first node, use FirstChild(). */ XMLElement* RootElement() { return FirstChildElement(); } const XMLElement* RootElement() const { return FirstChildElement(); } /** Print the Document. If the Printer is not provided, it will print to stdout. If you provide Printer, this can print to a file: @verbatim XMLPrinter printer( fp ); doc.Print( &printer ); @endverbatim Or you can use a printer to print to memory: @verbatim XMLPrinter printer; doc.Print( &printer ); // printer.CStr() has a const char* to the XML @endverbatim */ void Print( XMLPrinter* streamer=0 ) const; virtual bool Accept( XMLVisitor* visitor ) const override; /** Create a new Element associated with this Document. The memory for the Element is managed by the Document. */ XMLElement* NewElement( const char* name ); /** Create a new Comment associated with this Document. The memory for the Comment is managed by the Document. */ XMLComment* NewComment( const char* comment ); /** Create a new Text associated with this Document. The memory for the Text is managed by the Document. */ XMLText* NewText( const char* text ); /** Create a new Declaration associated with this Document. The memory for the object is managed by the Document. If the 'text' param is null, the standard declaration is used.: @verbatim @endverbatim */ XMLDeclaration* NewDeclaration( const char* text=0 ); /** Create a new Unknown associated with this Document. The memory for the object is managed by the Document. */ XMLUnknown* NewUnknown( const char* text ); /** Delete a node associated with this document. It will be unlinked from the DOM. */ void DeleteNode( XMLNode* node ); /// Clears the error flags. void ClearError(); /// Return true if there was an error parsing the document. bool Error() const { return _errorID != XML_SUCCESS; } /// Return the errorID. XMLError ErrorID() const { return _errorID; } const char* ErrorName() const; static const char* ErrorIDToName(XMLError errorID); /** Returns a "long form" error description. A hopefully helpful diagnostic with location, line number, and/or additional info. */ const char* ErrorStr() const; /// A (trivial) utility function that prints the ErrorStr() to stdout. void PrintError() const; /// Return the line where the error occurred, or zero if unknown. int ErrorLineNum() const { return _errorLineNum; } /// Clear the document, resetting it to the initial state. void Clear(); /** Copies this document to a target document. The target will be completely cleared before the copy. If you want to copy a sub-tree, see XMLNode::DeepClone(). NOTE: that the 'target' must be non-null. */ void DeepCopy(XMLDocument* target) const; // internal char* Identify( char* p, XMLNode** node, bool first ); // internal void MarkInUse(const XMLNode* const); virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const override{ return 0; } virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const override{ return false; } private: XMLDocument( const XMLDocument& ); // not supported void operator=( const XMLDocument& ); // not supported bool _writeBOM; bool _processEntities; XMLError _errorID; Whitespace _whitespaceMode; mutable StrPair _errorStr; int _errorLineNum; char* _charBuffer; int _parseCurLineNum; int _parsingDepth; // Memory tracking does add some overhead. // However, the code assumes that you don't // have a bunch of unlinked nodes around. // Therefore it takes less memory to track // in the document vs. a linked list in the XMLNode, // and the performance is the same. DynArray _unlinked; MemPoolT< sizeof(XMLElement) > _elementPool; MemPoolT< sizeof(XMLAttribute) > _attributePool; MemPoolT< sizeof(XMLText) > _textPool; MemPoolT< sizeof(XMLComment) > _commentPool; static const char* _errorNames[XML_ERROR_COUNT]; void Parse(); void SetError( XMLError error, int lineNum, const char* format, ... ); // Something of an obvious security hole, once it was discovered. // Either an ill-formed XML or an excessively deep one can overflow // the stack. Track stack depth, and error out if needed. class DepthTracker { public: explicit DepthTracker(XMLDocument * document) { this->_document = document; document->PushDepth(); } ~DepthTracker() { _document->PopDepth(); } private: XMLDocument * _document; }; void PushDepth(); void PopDepth(); template NodeType* CreateUnlinkedNode( MemPoolT& pool ); }; template inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT& pool ) { TIXMLASSERT( sizeof( NodeType ) == PoolElementSize ); TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() ); NodeType* returnNode = new (pool.Alloc()) NodeType( this ); TIXMLASSERT( returnNode ); returnNode->_memPool = &pool; _unlinked.Push(returnNode); return returnNode; } /** A XMLHandle is a class that wraps a node pointer with null checks; this is an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2 DOM structure. It is a separate utility class. Take an example: @verbatim @endverbatim Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very easy to write a *lot* of code that looks like: @verbatim XMLElement* root = document.FirstChildElement( "Document" ); if ( root ) { XMLElement* element = root->FirstChildElement( "Element" ); if ( element ) { XMLElement* child = element->FirstChildElement( "Child" ); if ( child ) { XMLElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. @endverbatim And that doesn't even cover "else" cases. XMLHandle addresses the verbosity of such code. A XMLHandle checks for null pointers so it is perfectly safe and correct to use: @verbatim XMLHandle docHandle( &document ); XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement(); if ( child2 ) { // do something useful @endverbatim Which is MUCH more concise and useful. It is also safe to copy handles - internally they are nothing more than node pointers. @verbatim XMLHandle handleCopy = handle; @endverbatim See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects. */ class TINYXML2_LIB XMLHandle { public: /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. explicit XMLHandle( XMLNode* node ) : _node( node ) { } /// Create a handle from a node. explicit XMLHandle( XMLNode& node ) : _node( &node ) { } /// Copy constructor XMLHandle( const XMLHandle& ref ) : _node( ref._node ) { } /// Assignment XMLHandle& operator=( const XMLHandle& ref ) { _node = ref._node; return *this; } /// Get the first child of this handle. XMLHandle FirstChild() { return XMLHandle( _node ? _node->FirstChild() : 0 ); } /// Get the first child element of this handle. XMLHandle FirstChildElement( const char* name = 0 ) { return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 ); } /// Get the last child of this handle. XMLHandle LastChild() { return XMLHandle( _node ? _node->LastChild() : 0 ); } /// Get the last child element of this handle. XMLHandle LastChildElement( const char* name = 0 ) { return XMLHandle( _node ? _node->LastChildElement( name ) : 0 ); } /// Get the previous sibling of this handle. XMLHandle PreviousSibling() { return XMLHandle( _node ? _node->PreviousSibling() : 0 ); } /// Get the previous sibling element of this handle. XMLHandle PreviousSiblingElement( const char* name = 0 ) { return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); } /// Get the next sibling of this handle. XMLHandle NextSibling() { return XMLHandle( _node ? _node->NextSibling() : 0 ); } /// Get the next sibling element of this handle. XMLHandle NextSiblingElement( const char* name = 0 ) { return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 ); } /// Safe cast to XMLNode. This can return null. XMLNode* ToNode() { return _node; } /// Safe cast to XMLElement. This can return null. XMLElement* ToElement() { return ( _node ? _node->ToElement() : 0 ); } /// Safe cast to XMLText. This can return null. XMLText* ToText() { return ( _node ? _node->ToText() : 0 ); } /// Safe cast to XMLUnknown. This can return null. XMLUnknown* ToUnknown() { return ( _node ? _node->ToUnknown() : 0 ); } /// Safe cast to XMLDeclaration. This can return null. XMLDeclaration* ToDeclaration() { return ( _node ? _node->ToDeclaration() : 0 ); } private: XMLNode* _node; }; /** A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the same in all regards, except for the 'const' qualifiers. See XMLHandle for API. */ class TINYXML2_LIB XMLConstHandle { public: explicit XMLConstHandle( const XMLNode* node ) : _node( node ) { } explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) { } XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) { } XMLConstHandle& operator=( const XMLConstHandle& ref ) { _node = ref._node; return *this; } const XMLConstHandle FirstChild() const { return XMLConstHandle( _node ? _node->FirstChild() : 0 ); } const XMLConstHandle FirstChildElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 ); } const XMLConstHandle LastChild() const { return XMLConstHandle( _node ? _node->LastChild() : 0 ); } const XMLConstHandle LastChildElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 ); } const XMLConstHandle PreviousSibling() const { return XMLConstHandle( _node ? _node->PreviousSibling() : 0 ); } const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 ); } const XMLConstHandle NextSibling() const { return XMLConstHandle( _node ? _node->NextSibling() : 0 ); } const XMLConstHandle NextSiblingElement( const char* name = 0 ) const { return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 ); } const XMLNode* ToNode() const { return _node; } const XMLElement* ToElement() const { return ( _node ? _node->ToElement() : 0 ); } const XMLText* ToText() const { return ( _node ? _node->ToText() : 0 ); } const XMLUnknown* ToUnknown() const { return ( _node ? _node->ToUnknown() : 0 ); } const XMLDeclaration* ToDeclaration() const { return ( _node ? _node->ToDeclaration() : 0 ); } private: const XMLNode* _node; }; /** Printing functionality. The XMLPrinter gives you more options than the XMLDocument::Print() method. It can: -# Print to memory. -# Print to a file you provide. -# Print XML without a XMLDocument. Print to Memory @verbatim XMLPrinter printer; doc.Print( &printer ); SomeFunction( printer.CStr() ); @endverbatim Print to a File You provide the file pointer. @verbatim XMLPrinter printer( fp ); doc.Print( &printer ); @endverbatim Print without a XMLDocument When loading, an XML parser is very useful. However, sometimes when saving, it just gets in the way. The code is often set up for streaming, and constructing the DOM is just overhead. The Printer supports the streaming case. The following code prints out a trivially simple XML file without ever creating an XML document. @verbatim XMLPrinter printer( fp ); printer.OpenElement( "foo" ); printer.PushAttribute( "foo", "bar" ); printer.CloseElement(); @endverbatim */ class TINYXML2_LIB XMLPrinter : public XMLVisitor { public: /** Construct the printer. If the FILE* is specified, this will print to the FILE. Else it will print to memory, and the result is available in CStr(). If 'compact' is set to true, then output is created with only required whitespace and newlines. */ XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); virtual ~XMLPrinter() {} /** If streaming, write the BOM and declaration. */ void PushHeader( bool writeBOM, bool writeDeclaration ); /** If streaming, start writing an element. The element must be closed with CloseElement() */ void OpenElement( const char* name, bool compactMode=false ); /// If streaming, add an attribute to an open element. void PushAttribute( const char* name, const char* value ); void PushAttribute( const char* name, int value ); void PushAttribute( const char* name, unsigned value ); void PushAttribute( const char* name, int64_t value ); void PushAttribute( const char* name, uint64_t value ); void PushAttribute( const char* name, bool value ); void PushAttribute( const char* name, double value ); /// If streaming, close the Element. virtual void CloseElement( bool compactMode=false ); /// Add a text node. void PushText( const char* text, bool cdata=false ); /// Add a text node from an integer. void PushText( int value ); /// Add a text node from an unsigned. void PushText( unsigned value ); /// Add a text node from a signed 64bit integer. void PushText( int64_t value ); /// Add a text node from an unsigned 64bit integer. void PushText( uint64_t value ); /// Add a text node from a bool. void PushText( bool value ); /// Add a text node from a float. void PushText( float value ); /// Add a text node from a double. void PushText( double value ); /// Add a comment void PushComment( const char* comment ); void PushDeclaration( const char* value ); void PushUnknown( const char* value ); virtual bool VisitEnter( const XMLDocument& /*doc*/ ) override; virtual bool VisitExit( const XMLDocument& /*doc*/ ) override { return true; } virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) override; virtual bool VisitExit( const XMLElement& element ) override; virtual bool Visit( const XMLText& text ) override; virtual bool Visit( const XMLComment& comment ) override; virtual bool Visit( const XMLDeclaration& declaration ) override; virtual bool Visit( const XMLUnknown& unknown ) override; /** If in print to memory mode, return a pointer to the XML file in memory. */ const char* CStr() const { return _buffer.Mem(); } /** If in print to memory mode, return the size of the XML file in memory. (Note the size returned includes the terminating null.) */ size_t CStrSize() const { return _buffer.Size(); } /** If in print to memory mode, reset the buffer to the beginning. */ void ClearBuffer( bool resetToFirstElement = true ) { _buffer.Clear(); _buffer.Push(0); _firstElement = resetToFirstElement; } protected: virtual bool CompactMode( const XMLElement& ) { return _compactMode; } /** Prints out the space before an element. You may override to change the space and tabs used. A PrintSpace() override should call Print(). */ virtual void PrintSpace( int depth ); virtual void Print( const char* format, ... ); virtual void Write( const char* data, size_t size ); virtual void Putc( char ch ); inline void Write(const char* data) { Write(data, strlen(data)); } void SealElementIfJustOpened(); bool _elementJustOpened; DynArray< const char*, 10 > _stack; private: /** Prepares to write a new node. This includes sealing an element that was just opened, and writing any whitespace necessary if not in compact mode. */ void PrepareForNewNode( bool compactMode ); void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities. bool _firstElement; FILE* _fp; int _depth; int _textDepth; bool _processEntities; bool _compactMode; enum { ENTITY_RANGE = 64, BUF_SIZE = 200 }; bool _entityFlag[ENTITY_RANGE]; bool _restrictedEntityFlag[ENTITY_RANGE]; DynArray< char, 20 > _buffer; // Prohibit cloning, intentionally not implemented XMLPrinter( const XMLPrinter& ); XMLPrinter& operator=( const XMLPrinter& ); }; } // namespace tinyxml2 #if defined(_MSC_VER) # pragma warning(pop) #endif #endif // TINYXML2_INCLUDED ================================================ FILE: lib/fkYAML/include/fkYAML/fkyaml_fwd.hpp ================================================ // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_FKYAML_FWD_HPP #define FK_YAML_FKYAML_FWD_HPP #include #include #include #include // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT // Check version definitions if already defined. #if defined(FK_YAML_MAJOR_VERSION) && defined(FK_YAML_MINOR_VERSION) && defined(FK_YAML_PATCH_VERSION) #if FK_YAML_MAJOR_VERSION != 0 || FK_YAML_MINOR_VERSION != 4 || FK_YAML_PATCH_VERSION != 2 #warning Already included a different version of the fkYAML library! #else // define macros to skip defining macros down below. #define FK_YAML_VERCHECK_SUCCEEDED #endif #endif #ifndef FK_YAML_VERCHECK_SUCCEEDED #define FK_YAML_MAJOR_VERSION 0 #define FK_YAML_MINOR_VERSION 4 #define FK_YAML_PATCH_VERSION 2 #define FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) v##major##_##minor##_##patch #define FK_YAML_NAMESPACE_VERSION_CONCAT(major, minor, patch) FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) #define FK_YAML_NAMESPACE_VERSION \ FK_YAML_NAMESPACE_VERSION_CONCAT(FK_YAML_MAJOR_VERSION, FK_YAML_MINOR_VERSION, FK_YAML_PATCH_VERSION) #define FK_YAML_NAMESPACE_BEGIN \ namespace fkyaml { \ inline namespace FK_YAML_NAMESPACE_VERSION { #define FK_YAML_NAMESPACE_END \ } /* inline namespace FK_YAML_NAMESPACE_VERSION */ \ } // namespace fkyaml #define FK_YAML_DETAIL_NAMESPACE_BEGIN \ FK_YAML_NAMESPACE_BEGIN \ namespace detail { #define FK_YAML_DETAIL_NAMESPACE_END \ } /* namespace detail */ \ FK_YAML_NAMESPACE_END #endif // !defined(FK_YAML_VERCHECK_SUCCEEDED) FK_YAML_NAMESPACE_BEGIN /// @brief An ADL friendly converter between basic_node objects and native data objects. /// @tparam ValueType A target data type. /// @sa https://fktn-k.github.io/fkYAML/api/node_value_converter/ template class node_value_converter; /// @brief A class to store value of YAML nodes. /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/ template < template class SequenceType = std::vector, template class MappingType = std::map, typename BooleanType = bool, typename IntegerType = std::int64_t, typename FloatNumberType = double, typename StringType = std::string, template class ConverterType = node_value_converter> class basic_node; /// @brief default YAML node value container. /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/node/ using node = basic_node<>; /// @brief A minimal map-like container which preserves insertion order. /// @tparam Key A type for keys. /// @tparam Value A type for values. /// @tparam IgnoredCompare A placeholder for key comparison. This will be ignored. /// @tparam Allocator A class for allocators. /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/ template class ordered_map; FK_YAML_NAMESPACE_END #endif /* FK_YAML_FKYAML_FWD_HPP */ ================================================ FILE: lib/fkYAML/include/fkYAML/node.hpp ================================================ // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_NODE_HPP #define FK_YAML_NODE_HPP #include #include #include #include #include #include #include #include #include // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP #define FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT // Check version definitions if already defined. #if defined(FK_YAML_MAJOR_VERSION) && defined(FK_YAML_MINOR_VERSION) && defined(FK_YAML_PATCH_VERSION) #if FK_YAML_MAJOR_VERSION != 0 || FK_YAML_MINOR_VERSION != 4 || FK_YAML_PATCH_VERSION != 2 #warning Already included a different version of the fkYAML library! #else // define macros to skip defining macros down below. #define FK_YAML_VERCHECK_SUCCEEDED #endif #endif #ifndef FK_YAML_VERCHECK_SUCCEEDED #define FK_YAML_MAJOR_VERSION 0 #define FK_YAML_MINOR_VERSION 4 #define FK_YAML_PATCH_VERSION 2 #define FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) v##major##_##minor##_##patch #define FK_YAML_NAMESPACE_VERSION_CONCAT(major, minor, patch) FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) #define FK_YAML_NAMESPACE_VERSION \ FK_YAML_NAMESPACE_VERSION_CONCAT(FK_YAML_MAJOR_VERSION, FK_YAML_MINOR_VERSION, FK_YAML_PATCH_VERSION) #define FK_YAML_NAMESPACE_BEGIN \ namespace fkyaml { \ inline namespace FK_YAML_NAMESPACE_VERSION { #define FK_YAML_NAMESPACE_END \ } /* inline namespace FK_YAML_NAMESPACE_VERSION */ \ } // namespace fkyaml #define FK_YAML_DETAIL_NAMESPACE_BEGIN \ FK_YAML_NAMESPACE_BEGIN \ namespace detail { #define FK_YAML_DETAIL_NAMESPACE_END \ } /* namespace detail */ \ FK_YAML_NAMESPACE_END #endif // !defined(FK_YAML_VERCHECK_SUCCEEDED) // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP #define FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP // This file is assumed to be included only by version_macros.hpp file. // To avoid redundant inclusion, do not include version_macros.hpp file as the other files do. // With the MSVC compilers, the value of __cplusplus is by default always "199611L"(C++98). // To avoid that, the library instead references _MSVC_LANG which is always set a correct value. // See https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ for more details. #if defined(_MSVC_LANG) && !defined(__clang__) #define FK_YAML_CPLUSPLUS _MSVC_LANG #else #define FK_YAML_CPLUSPLUS __cplusplus #endif // C++ language standard detection // Skip detection if the definitions listed below already exist. #if !defined(FK_YAML_HAS_CXX_23) && !defined(FK_YAML_HAS_CXX_20) && !defined(FK_YAML_HAS_CXX_17) && \ !defined(FK_YAML_HAS_CXX_14) && !defined(FK_YAML_CXX_11) #if FK_YAML_CPLUSPLUS >= 202302L #define FK_YAML_HAS_CXX_23 #define FK_YAML_HAS_CXX_20 #define FK_YAML_HAS_CXX_17 #define FK_YAML_HAS_CXX_14 #elif FK_YAML_CPLUSPLUS >= 202002L #define FK_YAML_HAS_CXX_20 #define FK_YAML_HAS_CXX_17 #define FK_YAML_HAS_CXX_14 #elif FK_YAML_CPLUSPLUS >= 201703L #define FK_YAML_HAS_CXX_17 #define FK_YAML_HAS_CXX_14 #elif FK_YAML_CPLUSPLUS >= 201402L #define FK_YAML_HAS_CXX_14 #endif // C++11 is the minimum required version of the fkYAML library. #define FK_YAML_HAS_CXX_11 #endif // switch usage of the deprecated attribute. [[deprecated]] is available since C++14. #if defined(FK_YAML_HAS_CXX_14) #define FK_YAML_DEPRECATED(msg) [[deprecated(msg)]] #else #if defined(_MSC_VER) #define FK_YAML_DEPRECATED(msg) __declspec(deprecated(msg)) #elif defined(__GNUC__) || defined(__clang__) #define FK_YAML_DEPRECATED(msg) __attribute__((deprecated(msg))) #else #define FK_YAML_DEPRECATED(msg) #endif #endif // switch usage of inline variables which have been available since C++17. #if defined(FK_YAML_HAS_CXX_17) #define FK_YAML_INLINE_VAR inline #else #define FK_YAML_INLINE_VAR #endif // switch usage of constexpr keyward depending on active C++ standard. #if defined(FK_YAML_HAS_CXX_17) #define FK_YAML_CXX17_CONSTEXPR constexpr #else #define FK_YAML_CXX17_CONSTEXPR #endif // Detect __has_* macros. // The following macros replace redundant `defined(__has_*) && __has_*(...)`. #ifdef __has_include #define FK_YAML_HAS_INCLUDE(header) __has_include(header) #else #define FK_YAML_HAS_INCLUDE(header) (0) #endif #ifdef __has_builtin #define FK_YAML_HAS_BUILTIN(builtin) __has_builtin(builtin) #else #define FK_YAML_HAS_BUILTIN(builtin) (0) #endif #ifdef __has_cpp_attribute #define FK_YAML_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else #define FK_YAML_HAS_CPP_ATTRIBUTE(attr) (0) #endif #ifdef __has_feature #define FK_YAML_HAS_FEATURE(feat) __has_feature(feat) #else #define FK_YAML_HAS_FEATURE(feat) (0) #endif // switch usage of the no_sanitize attribute only when Clang sanitizer is active. #if defined(__clang__) && FK_YAML_HAS_FEATURE(address_sanitizer) #define FK_YAML_NO_SANITIZE(...) __attribute__((no_sanitize(__VA_ARGS__))) #else #define FK_YAML_NO_SANITIZE(...) #endif #if FK_YAML_HAS_INCLUDE() // is available since C++20 #include #endif // // C++ feature detections // // switch usages of the std::to_chars()/std::from_chars() functions which have been available since C++17. #if defined(FK_YAML_HAS_CXX_17) && defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L #define FK_YAML_HAS_TO_CHARS (1) #else #define FK_YAML_HAS_TO_CHARS (0) #endif // switch usage of char8_t which has been available since C++20. #if defined(FK_YAML_HAS_CXX_20) && defined(__cpp_char8_t) && __cpp_char8_t >= 201811L #define FK_YAML_HAS_CHAR8_T (1) #else #define FK_YAML_HAS_CHAR8_T (0) #endif // // utility macros // // switch usage of [[likely]] C++ attribute which has been available since C++20. #if defined(FK_YAML_HAS_CXX_20) && FK_YAML_HAS_CPP_ATTRIBUTE(likely) >= 201803L #define FK_YAML_LIKELY(expr) (!!(expr)) [[likely]] #elif FK_YAML_HAS_BUILTIN(__builtin_expect) #define FK_YAML_LIKELY(expr) (__builtin_expect(!!(expr), 1)) #else #define FK_YAML_LIKELY(expr) (!!(expr)) #endif // switch usage of [[unlikely]] C++ attribute which has been available since C++20. #if defined(FK_YAML_HAS_CXX_20) && FK_YAML_HAS_CPP_ATTRIBUTE(unlikely) >= 201803L #define FK_YAML_UNLIKELY(expr) (!!(expr)) [[unlikely]] #elif FK_YAML_HAS_BUILTIN(__builtin_expect) #define FK_YAML_UNLIKELY(expr) (__builtin_expect(!!(expr), 0)) #else #define FK_YAML_UNLIKELY(expr) (!!(expr)) #endif #endif /* FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP */ #endif /* FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP */ // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_DETAIL_ASSERT_HPP #define FK_YAML_DETAIL_ASSERT_HPP // if FK_YAML_ASSERT is not user-defined. apply the default assert impl. #ifndef FK_YAML_ASSERT #ifndef NDEBUG #include #define FK_YAML_ASSERT(x) assert(x) #else #define FK_YAML_ASSERT(x) #endif #endif #endif /* FK_YAML_DETAIL_ASSERT_HPP */ // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP #define FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP #include #include // #include // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_DETAIL_META_NODE_TRAITS_HPP #define FK_YAML_DETAIL_META_NODE_TRAITS_HPP // #include // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_DETAIL_META_DETECT_HPP #define FK_YAML_DETAIL_META_DETECT_HPP #include #include // #include // #include // _______ __ __ __ _____ __ __ __ // | __| |_/ | \_/ |/ _ \ / \/ \| | fkYAML: A C++ header-only YAML library // | __| _ < \_ _/| ___ | _ | |___ version 0.4.2 // |__| |_| \__| |_| |_| |_|___||___|______| https://github.com/fktn-k/fkYAML // // SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani // SPDX-License-Identifier: MIT #ifndef FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP #define FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP #include #include // #include #ifdef FK_YAML_HAS_CXX_14 #include #endif FK_YAML_DETAIL_NAMESPACE_BEGIN ///////////////////////////////////////////////////////////////////////////////////////////////////////// // For contributors: // This file is for supplementing future C++ STL implementations to utilize some useful features // implemented in C++14 or better. // This file is needed to keep the fkYAML library requirement to C++11. // **DO NOT** implement features which are not included any version of STL in this file. // Such implementations must be in the type_traits.hpp file. ///////////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef FK_YAML_HAS_CXX_14 /// @brief An alias template for std::add_pointer::type with C++11. /// @note std::add_pointer_t is available since C++14. /// @sa https://en.cppreference.com/w/cpp/types/add_pointer /// @tparam T A type to be added a pointer. template using add_pointer_t = typename std::add_pointer::type; /// @brief An alias template for std::enable_if::type with C++11. /// @note std::enable_if_t is available since C++14. /// @sa https://en.cppreference.com/w/cpp/types/enable_if /// @tparam Condition A condition tested at compile time. /// @tparam T The type defined only if Condition is true. template using enable_if_t = typename std::enable_if::type; /// @brief A simple implementation to use std::is_null_pointer with C++11. /// @note std::is_null_pointer is available since C++14. /// @sa https://en.cppreference.com/w/cpp/types/is_null_pointer /// @tparam T The type to be checked if it's equal to std::nullptr_t. template struct is_null_pointer : std::is_same::type> {}; /// @brief An alias template for std::remove_cv::type with C++11. /// @note std::remove_cv_t is available since C++14. /// @sa https://en.cppreference.com/w/cpp/types/remove_cv /// @tparam T A type from which const-volatile qualifiers are removed. template using remove_cv_t = typename std::remove_cv::type; /// @brief An alias template for std::remove_pointer::type with C++11. /// @note std::remove_pointer_t is available since C++14. /// @sa https://en.cppreference.com/w/cpp/types/remove_pointer /// @tparam T A type from which a pointer is removed. template using remove_pointer_t = typename std::remove_pointer::type; /// @brief An alias template for std::remove_reference::type with C++11. /// @note std::remove_reference_t is available since C++14. /// @sa https://en.cppreference.com/w/cpp/types/remove_reference /// @tparam T A type from which a reference is removed. template using remove_reference_t = typename std::remove_reference::type; template struct integer_sequence { using value_type = T; static constexpr std::size_t size() noexcept { return sizeof...(I); } }; #if !FK_YAML_HAS_BUILTIN(__make_integer_seq) && !FK_YAML_HAS_BUILTIN(__integer_pack) namespace make_int_seq_impl { template struct merger; template struct merger, integer_sequence> { using type = integer_sequence; }; template struct generator { using type = typename merger::type, typename generator::type>::type; }; template struct generator { using type = integer_sequence; }; template struct generator { using type = integer_sequence; }; } // namespace make_int_seq_impl #endif template using make_integer_sequence #if FK_YAML_HAS_BUILTIN(__make_integer_seq) // clang defines built-in __make_integer_seq to generate an integer sequence. = __make_integer_seq; #elif FK_YAML_HAS_BUILTIN(__integer_pack) // GCC or other compilers may implement built-in __integer_pack to generate an // integer sequence. = integer_sequence; #else // fallback to the library implementation of make_integer_sequence. = typename make_int_seq_impl::generator::type; #endif template using index_sequence = integer_sequence; template using make_index_sequence = make_integer_sequence; template using index_sequence_for = make_index_sequence; #else // !defined(FK_YAML_HAS_CXX_14) using std::add_pointer_t; using std::enable_if_t; using std::index_sequence; using std::index_sequence_for; using std::integer_sequence; using std::is_null_pointer; using std::make_index_sequence; using std::make_integer_sequence; using std::remove_cv_t; using std::remove_pointer_t; using std::remove_reference_t; #endif // !defined(FK_YAML_HAS_CXX_14) #ifndef FK_YAML_HAS_CXX_17 /// @brief A simple implementation to use std::bool_constant with C++11/C++14. /// @tparam Val template using bool_constant = std::integral_constant; /// @brief A simple implementation to use std::void_t with C++11/C++14. /// @note /// std::conjunction is available since C++17. /// This is applied when no traits are specified as inputs. /// @sa https://en.cppreference.com/w/cpp/types/conjunction /// @tparam Traits Type traits to be checked if their ::value are all true. template struct conjunction : std::true_type {}; /// @brief A partial specialization of conjunction if only one Trait is given. /// @tparam Trait Type trait to be checked if its ::value is true. template struct conjunction : Trait {}; /// @brief A partial specialization of conjunction if more than one traits are given. /// @tparam First The first type trait to be checked if its ::value is true. /// @tparam Rest The rest of traits passed as another conjunction template arguments if First::value is true. template struct conjunction : std::conditional, First>::type {}; /// @brief A simple implementation to use std::disjunction with C++11/C++14. /// @note /// std::disjunction is available since C++17. /// This is applied when no traits are specified as inputs. /// @sa https://en.cppreference.com/w/cpp/types/disjunction /// @tparam Traits Type traits to be checked if at least one of their ::value is true. template struct disjunction : std::false_type {}; /// @brief A partial specialization of disjunction if only one Trait is given. /// @tparam Trait Type trait to be checked if its ::value is true. template struct disjunction : Trait {}; /// @brief A partial specialization of disjunction if more than one traits are given. /// @tparam First The first type trait to be checked if its ::value is true. /// @tparam Rest The rest of traits passed as another conjunction template arguments if First::value is false. template struct disjunction : std::conditional>::type {}; /// @brief A simple implementation to use std::negation with C++11/C++14. /// @note std::negation is available since C++17. /// @sa https://en.cppreference.com/w/cpp/types/negation /// @tparam Trait Type trait whose ::value is negated. template struct negation : std::integral_constant {}; /// @brief A helper for void_t. /// @tparam Types Any types to be transformed to void type. template struct make_void { using type = void; }; /// @brief A simple implementation to use std::void_t with C++11/C++14. /// @note std::void_t is available since C++17. /// @sa https://en.cppreference.com/w/cpp/types/void_t /// @tparam Types Any types to be transformed to void type. template using void_t = typename make_void::type; #else // !defined(FK_YAML_HAS_CXX_17) using std::bool_constant; using std::conjunction; using std::disjunction; using std::negation; using std::void_t; #endif // !defined(FK_YAML_HAS_CXX_17) #ifndef FK_YAML_HAS_CXX_20 /// @brief A simple implementation to use std::remove_cvref_t with C++11/C++14/C++17. /// @note std::remove_cvref & std::remove_cvref_t are available since C++20. /// @sa https://en.cppreference.com/w/cpp/types/remove_cvref /// @tparam T A type from which cv-qualifiers and reference are removed. template using remove_cvref_t = typename std::remove_cv::type>::type; #else using std::remove_cvref_t; #endif /// @brief A wrapper function to call std::unreachable() (since C++23) or similar compiler specific extensions. /// @note This function is implemented only for better code optimization against dead code and thus excluded from /// coverage report. // LCOV_EXCL_START [[noreturn]] inline void unreachable() { // use compiler specific extensions if possible. // undefined behavior should be raised by an empty function with noreturn attribute. #if defined(FK_YAML_HAS_CXX_23) || (defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L) std::unreachable(); #elif defined(_MSC_VER) && !defined(__clang__) // MSVC __assume(false); #else __builtin_unreachable(); #endif } // LCOV_EXCL_STOP FK_YAML_DETAIL_NAMESPACE_END #endif /* FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP */ FK_YAML_DETAIL_NAMESPACE_BEGIN /// @brief A dummy struct to represent detection failure. struct nonesuch { nonesuch() = delete; ~nonesuch() = delete; nonesuch(const nonesuch&) = delete; nonesuch(nonesuch&&) = delete; nonesuch& operator=(const nonesuch&) = delete; nonesuch& operator=(nonesuch&&) = delete; }; /// @brief namespace to implement detector type traits namespace detector_impl { /// @brief A helper for general type detection. /// @tparam Default A type to represent detection failure. /// @tparam AlwaysVoid This must be void type. /// @tparam Op A type for desired operation type. /// @tparam Args Argument types passed to desired operation. template class Op, typename... Args> struct detector : std::false_type { /// @brief A type which represents detection failure. using type = Default; }; /// @brief A partial specialization of detector if desired operation type is found. /// @tparam Default A type to represent detection failure. /// @tparam Op A type for desired operation type. /// @tparam Args Argument types passed to desired operation. template class Op, typename... Args> struct detector>, Op, Args...> : std::true_type { /// @brief A detected type. using type = Op; }; } // namespace detector_impl /// @brief Type traits to detect Op operation with Args argument types /// @tparam Op A desired operation type. /// @tparam Args Argument types passed to desired operation. template