pass through but panic

pull/1212/head
aoowweenn 2017-02-24 08:35:15 +08:00
parent 2afeddd5cb
commit 4045466f73
15 changed files with 3670 additions and 3 deletions

View File

@ -344,7 +344,11 @@ IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
# Why assimp_qt_viewer/CMakeLists.txt still contain similar check?
# Because viewer can be build independently of Assimp.
FIND_PACKAGE(Qt5Widgets QUIET)
set(CMAKE_MODULE_PATH_BACKUP ${CMAKE_MODULE_PATH})
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
FIND_PACKAGE(DevIL QUIET)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
set(CMAKE_MODULE_PATH_BACKUP ${CMAKE_MODULE_PATH})
FIND_PACKAGE(OpenGL QUIET)
IF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND)
ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )

72
FindDevIL.cmake 100644
View File

@ -0,0 +1,72 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#.rst:
# FindDevIL
# ---------
#
#
#
# This module locates the developer's image library.
# http://openil.sourceforge.net/
#
# This module sets:
#
# ::
#
# IL_LIBRARIES - the name of the IL library. These include the full path to
# the core DevIL library. This one has to be linked into the
# application.
# ILU_LIBRARIES - the name of the ILU library. Again, the full path. This
# library is for filters and effects, not actual loading. It
# doesn't have to be linked if the functionality it provides
# is not used.
# ILUT_LIBRARIES - the name of the ILUT library. Full path. This part of the
# library interfaces with OpenGL. It is not strictly needed
# in applications.
# IL_INCLUDE_DIR - where to find the il.h, ilu.h and ilut.h files.
# IL_FOUND - this is set to TRUE if all the above variables were set.
# This will be set to false if ILU or ILUT are not found,
# even if they are not needed. In most systems, if one
# library is found all the others are as well. That's the
# way the DevIL developers release it.
# TODO: Add version support.
# Tested under Linux and Windows (MSVC)
#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
include(FindPackageHandleStandardArgs)
find_path(IL_INCLUDE_DIR il.h
PATH_SUFFIXES include IL
DOC "The path to the directory that contains il.h"
)
#message("IL_INCLUDE_DIR is ${IL_INCLUDE_DIR}")
find_library(IL_LIBRARIES
NAMES IL DEVIL
PATH_SUFFIXES lib64 lib lib32
DOC "The file that corresponds to the base il library."
)
#message("IL_LIBRARIES is ${IL_LIBRARIES}")
find_library(ILUT_LIBRARIES
NAMES ILUT
PATH_SUFFIXES lib64 lib lib32
DOC "The file that corresponds to the il (system?) utility library."
)
#message("ILUT_LIBRARIES is ${ILUT_LIBRARIES}")
find_library(ILU_LIBRARIES
NAMES ILU
PATH_SUFFIXES lib64 lib lib32
DOC "The file that corresponds to the il utility library."
)
#message("ILU_LIBRARIES is ${ILU_LIBRARIES}")
FIND_PACKAGE_HANDLE_STANDARD_ARGS(IL DEFAULT_MSG
IL_LIBRARIES IL_INCLUDE_DIR)

690
FindICU.cmake 100644
View File

@ -0,0 +1,690 @@
# This module can find the International Components for Unicode (ICU) libraries
#
# Requirements:
# - CMake >= 2.8.3 (for new version of find_package_handle_standard_args)
#
# The following variables will be defined for your use:
# - ICU_FOUND : were all of your specified components found?
# - ICU_INCLUDE_DIRS : ICU include directory
# - ICU_LIBRARIES : ICU libraries
# - ICU_VERSION : complete version of ICU (x.y.z)
# - ICU_VERSION_MAJOR : major version of ICU
# - ICU_VERSION_MINOR : minor version of ICU
# - ICU_VERSION_PATCH : patch version of ICU
# - ICU_<COMPONENT>_FOUND : were <COMPONENT> found? (FALSE for non specified component if it is not a dependency)
#
# For windows or non standard installation, define ICU_ROOT_DIR variable to point to the root installation of ICU. Two ways:
# - run cmake with -DICU_ROOT_DIR=<PATH>
# - define an environment variable with the same name before running cmake
# With cmake-gui, before pressing "Configure":
# 1) Press "Add Entry" button
# 2) Add a new entry defined as:
# - Name: ICU_ROOT_DIR
# - Type: choose PATH in the selection list
# - Press "..." button and select the root installation of ICU
#
# Example Usage:
#
# 1. Copy this file in the root of your project source directory
# 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt:
# set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
# 3. Finally call find_package() once, here are some examples to pick from
#
# Require ICU 4.4 or later
# find_package(ICU 4.4 REQUIRED)
#
# if(ICU_FOUND)
# add_executable(myapp myapp.c)
# include_directories(${ICU_INCLUDE_DIRS})
# target_link_libraries(myapp ${ICU_LIBRARIES})
# # with CMake >= 3.0.0, the last two lines can be replaced by the following
# target_link_libraries(myapp ICU::ICU)
# endif(ICU_FOUND)
########## <ICU finding> ##########
find_package(PkgConfig QUIET)
########## Private ##########
if(NOT DEFINED ICU_PUBLIC_VAR_NS)
set(ICU_PUBLIC_VAR_NS "ICU") # Prefix for all ICU relative public variables
endif(NOT DEFINED ICU_PUBLIC_VAR_NS)
if(NOT DEFINED ICU_PRIVATE_VAR_NS)
set(ICU_PRIVATE_VAR_NS "_${ICU_PUBLIC_VAR_NS}") # Prefix for all ICU relative internal variables
endif(NOT DEFINED ICU_PRIVATE_VAR_NS)
if(NOT DEFINED PC_ICU_PRIVATE_VAR_NS)
set(PC_ICU_PRIVATE_VAR_NS "_PC${ICU_PRIVATE_VAR_NS}") # Prefix for all pkg-config relative internal variables
endif(NOT DEFINED PC_ICU_PRIVATE_VAR_NS)
set(${ICU_PRIVATE_VAR_NS}_HINTS )
# <deprecated>
# for future removal
if(DEFINED ENV{ICU_ROOT})
list(APPEND ${ICU_PRIVATE_VAR_NS}_HINTS "$ENV{ICU_ROOT}")
message(AUTHOR_WARNING "ENV{ICU_ROOT} is deprecated in favor of ENV{ICU_ROOT_DIR}")
endif(DEFINED ENV{ICU_ROOT})
if (DEFINED ICU_ROOT)
list(APPEND ${ICU_PRIVATE_VAR_NS}_HINTS "${ICU_ROOT}")
message(AUTHOR_WARNING "ICU_ROOT is deprecated in favor of ICU_ROOT_DIR")
endif(DEFINED ICU_ROOT)
# </deprecated>
if(DEFINED ENV{ICU_ROOT_DIR})
list(APPEND ${ICU_PRIVATE_VAR_NS}_HINTS "$ENV{ICU_ROOT_DIR}")
endif(DEFINED ENV{ICU_ROOT_DIR})
if (DEFINED ICU_ROOT_DIR)
list(APPEND ${ICU_PRIVATE_VAR_NS}_HINTS "${ICU_ROOT_DIR}")
endif(DEFINED ICU_ROOT_DIR)
set(${ICU_PRIVATE_VAR_NS}_COMPONENTS )
# <icu component name> <library name 1> ... <library name N>
macro(_icu_declare_component _NAME)
list(APPEND ${ICU_PRIVATE_VAR_NS}_COMPONENTS ${_NAME})
set("${ICU_PRIVATE_VAR_NS}_COMPONENTS_${_NAME}" ${ARGN})
endmacro(_icu_declare_component)
_icu_declare_component(data icudata)
_icu_declare_component(uc icuuc) # Common and Data libraries
_icu_declare_component(i18n icui18n icuin) # Internationalization library
_icu_declare_component(io icuio ustdio) # Stream and I/O Library
_icu_declare_component(le icule) # Layout library
_icu_declare_component(lx iculx) # Paragraph Layout library
########## Public ##########
set(${ICU_PUBLIC_VAR_NS}_FOUND FALSE)
set(${ICU_PUBLIC_VAR_NS}_LIBRARIES )
set(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS )
set(${ICU_PUBLIC_VAR_NS}_C_FLAGS "")
set(${ICU_PUBLIC_VAR_NS}_CXX_FLAGS "")
set(${ICU_PUBLIC_VAR_NS}_CPP_FLAGS "")
set(${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS "")
set(${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS "")
set(${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS "")
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS})
string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) # may be done in the _icu_declare_component macro
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
# Check components
if(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) # uc required at least
set(${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc)
else(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc)
list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
if(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
message(FATAL_ERROR "Unknown ICU component: ${${ICU_PRIVATE_VAR_NS}_COMPONENT}")
endif(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
endif(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
# if pkg-config is available check components dependencies and append `pkg-config icu-<component> --variable=prefix` to hints
if(PKG_CONFIG_FOUND)
set(${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP})
pkg_check_modules(${PC_ICU_PRIVATE_VAR_NS} "icu-${${ICU_PRIVATE_VAR_NS}_COMPONENT}" QUIET)
if(${PC_ICU_PRIVATE_VAR_NS}_FOUND)
list(APPEND ${ICU_PRIVATE_VAR_NS}_HINTS ${${PC_ICU_PRIVATE_VAR_NS}_PREFIX})
foreach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY ${${PC_ICU_PRIVATE_VAR_NS}_LIBRARIES})
string(REGEX REPLACE "^icu" "" ${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY ${${PC_ICU_PRIVATE_VAR_NS}_LIBRARY})
if(NOT ${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY STREQUAL "data")
list(FIND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS ${${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY} ${ICU_PRIVATE_VAR_NS}_COMPONENT_INDEX)
if(${ICU_PRIVATE_VAR_NS}_COMPONENT_INDEX EQUAL -1)
message(WARNING "Missing component dependency: ${${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY}. Add it to your find_package(ICU) line as COMPONENTS to fix this warning.")
list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS ${${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY})
endif(${ICU_PRIVATE_VAR_NS}_COMPONENT_INDEX EQUAL -1)
endif(NOT ${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY STREQUAL "data")
endforeach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY)
endif(${PC_ICU_PRIVATE_VAR_NS}_FOUND)
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
endif(PKG_CONFIG_FOUND)
# list(APPEND ${ICU_PRIVATE_VAR_NS}_HINTS ENV ICU_ROOT_DIR)
# message("${ICU_PRIVATE_VAR_NS}_HINTS = ${${ICU_PRIVATE_VAR_NS}_HINTS}")
# Includes
find_path(
${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR
NAMES unicode/utypes.h utypes.h
HINTS ${${ICU_PRIVATE_VAR_NS}_HINTS}
PATH_SUFFIXES "include"
DOC "Include directories for ICU"
)
if(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR)
########## <part to keep synced with tests/version/CMakeLists.txt> ##########
if(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/unicode/uvernum.h") # ICU >= 4.4
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/unicode/uvernum.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/unicode/uversion.h") # ICU [2;4.4[
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/unicode/uversion.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/unicode/utypes.h") # ICU [1.4;2[
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/unicode/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/utypes.h") # ICU 1.3
file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
else()
message(FATAL_ERROR "ICU version header not found")
endif()
if(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *ICU_VERSION *\"([0-9]+)\".*") # ICU 1.3
# [1.3;1.4[ as #define ICU_VERSION "3" (no patch version, ie all 1.3.X versions will be detected as 1.3.0)
set(${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR "1")
set(${ICU_PUBLIC_VAR_NS}_VERSION_MINOR "${CMAKE_MATCH_1}")
set(${ICU_PUBLIC_VAR_NS}_VERSION_PATCH "0")
elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION_MAJOR_NUM *([0-9]+).*")
#
# Since version 4.9.1, ICU release version numbering was totaly changed, see:
# - http://site.icu-project.org/download/49
# - http://userguide.icu-project.org/design#TOC-Version-Numbers-in-ICU
#
set(${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR "${CMAKE_MATCH_1}")
string(REGEX REPLACE ".*# *define *U_ICU_VERSION_MINOR_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_VERSION_MINOR "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}")
string(REGEX REPLACE ".*# *define *U_ICU_VERSION_PATCHLEVEL_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_VERSION_PATCH "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}")
elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION *\"(([0-9]+)(\\.[0-9]+)*)\".*") # ICU [1.4;1.8[
# [1.4;1.8[ as #define U_ICU_VERSION "1.4.1.2" but it seems that some 1.4.[12](?:\.\d)? have releasing error and appears as 1.4.0
set(${ICU_PRIVATE_VAR_NS}_FULL_VERSION "${CMAKE_MATCH_1}") # copy CMAKE_MATCH_1, no longer valid on the following if
if(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)$")
set(${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(${ICU_PUBLIC_VAR_NS}_VERSION_MINOR "${CMAKE_MATCH_2}")
set(${ICU_PUBLIC_VAR_NS}_VERSION_PATCH "0")
elseif(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
set(${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(${ICU_PUBLIC_VAR_NS}_VERSION_MINOR "${CMAKE_MATCH_2}")
set(${ICU_PUBLIC_VAR_NS}_VERSION_PATCH "${CMAKE_MATCH_3}")
endif()
else()
message(FATAL_ERROR "failed to detect ICU version")
endif()
set(${ICU_PUBLIC_VAR_NS}_VERSION "${${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR}.${${ICU_PUBLIC_VAR_NS}_VERSION_MINOR}.${${ICU_PUBLIC_VAR_NS}_VERSION_PATCH}")
########## </part to keep synced with tests/version/CMakeLists.txt> ##########
endif(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR)
# Check libraries
if(MSVC)
include(SelectLibraryConfigurations)
endif(MSVC)
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
if(MSVC)
set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES )
set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES )
foreach(${ICU_PRIVATE_VAR_NS}_BASE_NAME ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}})
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}")
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}d")
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR}${${ICU_PUBLIC_VAR_NS}_VERSION_MINOR}")
list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR}${${ICU_PUBLIC_VAR_NS}_VERSION_MINOR}d")
endforeach(${ICU_PRIVATE_VAR_NS}_BASE_NAME)
find_library(
${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_RELEASE
NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES}
HINTS ${${ICU_PRIVATE_VAR_NS}_HINTS}
DOC "Release library for ICU ${${ICU_PRIVATE_VAR_NS}_COMPONENT} component"
)
find_library(
${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_DEBUG
NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES}
HINTS ${${ICU_PRIVATE_VAR_NS}_HINTS}
DOC "Debug library for ICU ${${ICU_PRIVATE_VAR_NS}_COMPONENT} component"
)
select_library_configurations("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}")
list(APPEND ${ICU_PUBLIC_VAR_NS}_LIBRARY ${${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY})
else(MSVC)
find_library(
${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY
NAMES ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}
PATHS ${${ICU_PRIVATE_VAR_NS}_HINTS}
DOC "Library for ICU ${${ICU_PRIVATE_VAR_NS}_COMPONENT} component"
)
if(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY)
set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" TRUE)
list(APPEND ${ICU_PUBLIC_VAR_NS}_LIBRARY ${${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY})
endif(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY)
endif(MSVC)
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
# Try to find out compiler flags
find_program(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE icu-config HINTS ${${ICU_PRIVATE_VAR_NS}_HINTS})
if(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE)
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
endif(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE)
# Check find_package arguments
include(FindPackageHandleStandardArgs)
if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
find_package_handle_standard_args(
${ICU_PUBLIC_VAR_NS}
REQUIRED_VARS ${ICU_PUBLIC_VAR_NS}_LIBRARY ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR
VERSION_VAR ${ICU_PUBLIC_VAR_NS}_VERSION
)
else(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
find_package_handle_standard_args(${ICU_PUBLIC_VAR_NS} "Could NOT find ICU" ${ICU_PUBLIC_VAR_NS}_LIBRARY ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR)
endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
if(${ICU_PUBLIC_VAR_NS}_FOUND)
# <deprecated>
# for compatibility with previous versions, alias old ICU_(MAJOR|MINOR|PATCH)_VERSION to ICU_VERSION_$1
set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION ${${ICU_PUBLIC_VAR_NS}_VERSION_MAJOR})
set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION ${${ICU_PUBLIC_VAR_NS}_VERSION_MINOR})
set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION ${${ICU_PUBLIC_VAR_NS}_VERSION_PATCH})
# </deprecated>
set(${ICU_PUBLIC_VAR_NS}_LIBRARIES ${${ICU_PUBLIC_VAR_NS}_LIBRARY})
set(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS ${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR})
if(NOT CMAKE_VERSION VERSION_LESS "3.0.0")
if(NOT TARGET ICU::ICU)
add_library(ICU::ICU INTERFACE IMPORTED)
endif(NOT TARGET ICU::ICU)
set_target_properties(ICU::ICU PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}")
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
add_library("ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}" UNKNOWN IMPORTED)
if(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_RELEASE)
set_property(TARGET "ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}" APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties("ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}" PROPERTIES IMPORTED_LOCATION_RELEASE "${${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_RELEASE}")
endif(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_RELEASE)
if(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_DEBUG)
set_property(TARGET "ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}" APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties("ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}" PROPERTIES IMPORTED_LOCATION_DEBUG "${${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_DEBUG}")
endif(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY_DEBUG)
if(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY)
set_target_properties("ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}" PROPERTIES IMPORTED_LOCATION "${${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY}")
endif(${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_LIBRARY)
set_property(TARGET ICU::ICU APPEND PROPERTY INTERFACE_LINK_LIBRARIES "ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}")
# set_target_properties("ICU::${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}" PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR}")
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
endif(NOT CMAKE_VERSION VERSION_LESS "3.0.0")
endif(${ICU_PUBLIC_VAR_NS}_FOUND)
mark_as_advanced(
${ICU_PUBLIC_VAR_NS}_INCLUDE_DIR
${ICU_PUBLIC_VAR_NS}_LIBRARY
)
########## </ICU finding> ##########
########## <resource bundle support> ##########
########## Private ##########
function(_icu_extract_locale_from_rb _BUNDLE_SOURCE _RETURN_VAR_NAME)
file(READ "${_BUNDLE_SOURCE}" _BUNDLE_CONTENTS)
string(REGEX REPLACE "//[^\n]*\n" "" _BUNDLE_CONTENTS_WITHOUT_COMMENTS ${_BUNDLE_CONTENTS})
string(REGEX REPLACE "[ \t\n]" "" _BUNDLE_CONTENTS_WITHOUT_COMMENTS_AND_SPACES ${_BUNDLE_CONTENTS_WITHOUT_COMMENTS})
string(REGEX MATCH "^([a-zA-Z_-]+)(:table)?{" LOCALE_FOUND ${_BUNDLE_CONTENTS_WITHOUT_COMMENTS_AND_SPACES})
set("${_RETURN_VAR_NAME}" "${CMAKE_MATCH_1}" PARENT_SCOPE)
endfunction(_icu_extract_locale_from_rb)
########## Public ##########
#
# Prototype:
# icu_generate_resource_bundle([NAME <name>] [PACKAGE] [DESTINATION <location>] [FILES <list of files>])
#
# Common arguments:
# - NAME <name> : name of output package and to create dummy targets
# - FILES <file 1> ... <file N> : list of resource bundles sources
# - DEPENDS <target1> ... <target N> : required to package as library (shared or static), a list of cmake parent targets to link to
# Note: only (PREVIOUSLY DECLARED) add_executable and add_library as dependencies
# - DESTINATION <location> : optional, directory where to install final binary file(s)
# - FORMAT <name> : optional, one of none (ICU4C binary format, default), java (plain java) or xliff (XML), see below
#
# Arguments depending on FORMAT:
# - none (default):
# * PACKAGE : if present, package all resource bundles together. Default is to stop after building individual *.res files
# * TYPE <name> : one of :
# + common or archive (default) : archive all ressource bundles into a single .dat file
# + library or dll : assemble all ressource bundles into a separate and loadable library (.dll/.so)
# + static : integrate all ressource bundles to targets designed by DEPENDS parameter (as a static library)
# * NO_SHARED_FLAGS : only with TYPE in ['library', 'dll', 'static'], do not append ICU_C(XX)_SHARED_FLAGS to targets given as DEPENDS argument
# - JAVA:
# * BUNDLE <name> : required, prefix for generated classnames
# - XLIFF:
# (none)
#
#
# For an archive, the idea is to generate the following dependencies:
#
# root.txt => root.res \
# |
# en.txt => en.res |
# | => pkglist.txt => application.dat
# fr.txt => fr.res |
# |
# and so on /
#
# Lengend: 'A => B' means B depends on A
#
# Steps (correspond to arrows):
# 1) genrb (from .txt to .res)
# 2) generate a file text (pkglist.txt) with all .res files to put together
# 3) build final archive (from *.res/pkglist.txt to .dat)
#
function(icu_generate_resource_bundle)
##### <check for pkgdata/genrb availability> #####
find_program(${ICU_PUBLIC_VAR_NS}_GENRB_EXECUTABLE genrb HINTS ${${ICU_PRIVATE_VAR_NS}_HINTS})
find_program(${ICU_PUBLIC_VAR_NS}_PKGDATA_EXECUTABLE pkgdata HINTS ${${ICU_PRIVATE_VAR_NS}_HINTS})
if(NOT ${ICU_PUBLIC_VAR_NS}_GENRB_EXECUTABLE)
message(FATAL_ERROR "genrb not found")
endif(NOT ${ICU_PUBLIC_VAR_NS}_GENRB_EXECUTABLE)
if(NOT ${ICU_PUBLIC_VAR_NS}_PKGDATA_EXECUTABLE)
message(FATAL_ERROR "pkgdata not found")
endif(NOT ${ICU_PUBLIC_VAR_NS}_PKGDATA_EXECUTABLE)
##### </check for pkgdata/genrb availability> #####
##### <constants> #####
set(TARGET_SEPARATOR "+")
set(__FUNCTION__ "icu_generate_resource_bundle")
set(PACKAGE_TARGET_PREFIX "ICU${TARGET_SEPARATOR}PKG")
set(RESOURCE_TARGET_PREFIX "ICU${TARGET_SEPARATOR}RB")
##### </constants> #####
##### <hash constants> #####
# filename extension of built resource bundle (without dot)
set(BUNDLES__SUFFIX "res")
set(BUNDLES_JAVA_SUFFIX "java")
set(BUNDLES_XLIFF_SUFFIX "xlf")
# alias: none (default) = common = archive ; dll = library ; static
set(PKGDATA__ALIAS "")
set(PKGDATA_COMMON_ALIAS "")
set(PKGDATA_ARCHIVE_ALIAS "")
set(PKGDATA_DLL_ALIAS "LIBRARY")
set(PKGDATA_LIBRARY_ALIAS "LIBRARY")
set(PKGDATA_STATIC_ALIAS "STATIC")
# filename prefix of built package
set(PKGDATA__PREFIX "")
set(PKGDATA_LIBRARY_PREFIX "${CMAKE_SHARED_LIBRARY_PREFIX}")
set(PKGDATA_STATIC_PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}")
# filename extension of built package (with dot)
set(PKGDATA__SUFFIX ".dat")
set(PKGDATA_LIBRARY_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}")
set(PKGDATA_STATIC_SUFFIX "${CMAKE_STATIC_LIBRARY_SUFFIX}")
# pkgdata option mode specific
set(PKGDATA__OPTIONS "-m" "common")
set(PKGDATA_STATIC_OPTIONS "-m" "static")
set(PKGDATA_LIBRARY_OPTIONS "-m" "library")
# cmake library type for output package
set(PKGDATA_LIBRARY__TYPE "")
set(PKGDATA_LIBRARY_STATIC_TYPE STATIC)
set(PKGDATA_LIBRARY_LIBRARY_TYPE SHARED)
##### </hash constants> #####
include(CMakeParseArguments)
cmake_parse_arguments(
PARSED_ARGS # output variable name
# options (true/false) (default value: false)
"PACKAGE;NO_SHARED_FLAGS"
# univalued parameters (default value: "")
"NAME;DESTINATION;TYPE;FORMAT;BUNDLE"
# multivalued parameters (default value: "")
"FILES;DEPENDS"
${ARGN}
)
# assert(${PARSED_ARGS_NAME} != "")
if(NOT PARSED_ARGS_NAME)
message(FATAL_ERROR "${__FUNCTION__}(): no name given, NAME parameter missing")
endif(NOT PARSED_ARGS_NAME)
# assert(length(PARSED_ARGS_FILES) > 0)
list(LENGTH PARSED_ARGS_FILES PARSED_ARGS_FILES_LEN)
if(PARSED_ARGS_FILES_LEN LESS 1)
message(FATAL_ERROR "${__FUNCTION__}() expects at least 1 resource bundle as FILES argument, 0 given")
endif(PARSED_ARGS_FILES_LEN LESS 1)
string(TOUPPER "${PARSED_ARGS_FORMAT}" UPPER_FORMAT)
# assert(${UPPER_FORMAT} in ['', 'java', 'xlif'])
if(NOT DEFINED BUNDLES_${UPPER_FORMAT}_SUFFIX)
message(FATAL_ERROR "${__FUNCTION__}(): unknown FORMAT '${PARSED_ARGS_FORMAT}'")
endif(NOT DEFINED BUNDLES_${UPPER_FORMAT}_SUFFIX)
if(UPPER_FORMAT STREQUAL "JAVA")
# assert(${PARSED_ARGS_BUNDLE} != "")
if(NOT PARSED_ARGS_BUNDLE)
message(FATAL_ERROR "${__FUNCTION__}(): java bundle name expected, BUNDLE parameter missing")
endif(NOT PARSED_ARGS_BUNDLE)
endif(UPPER_FORMAT STREQUAL "JAVA")
if(PARSED_ARGS_PACKAGE)
# assert(${PARSED_ARGS_FORMAT} == "")
if(PARSED_ARGS_FORMAT)
message(FATAL_ERROR "${__FUNCTION__}(): packaging is only supported for binary format, not xlif neither java outputs")
endif(PARSED_ARGS_FORMAT)
string(TOUPPER "${PARSED_ARGS_TYPE}" UPPER_MODE)
# assert(${UPPER_MODE} in ['', 'common', 'archive', 'dll', library'])
if(NOT DEFINED PKGDATA_${UPPER_MODE}_ALIAS)
message(FATAL_ERROR "${__FUNCTION__}(): unknown TYPE '${PARSED_ARGS_TYPE}'")
else(NOT DEFINED PKGDATA_${UPPER_MODE}_ALIAS)
set(TYPE "${PKGDATA_${UPPER_MODE}_ALIAS}")
endif(NOT DEFINED PKGDATA_${UPPER_MODE}_ALIAS)
# Package name: strip file extension if present
get_filename_component(PACKAGE_NAME_WE ${PARSED_ARGS_NAME} NAME_WE)
# Target name to build package
set(PACKAGE_TARGET_NAME "${PACKAGE_TARGET_PREFIX}${TARGET_SEPARATOR}${PACKAGE_NAME_WE}")
# Target name to build intermediate list file
set(PACKAGE_LIST_TARGET_NAME "${PACKAGE_TARGET_NAME}${TARGET_SEPARATOR}PKGLIST")
# Directory (absolute) to set as "current directory" for genrb (does not include package directory, -p)
# We make our "cook" there to prevent any conflict
if(DEFINED CMAKE_PLATFORM_ROOT_BIN) # CMake < 2.8.10
set(RESOURCE_GENRB_CHDIR_DIR "${CMAKE_PLATFORM_ROOT_BIN}/${PACKAGE_TARGET_NAME}.dir/")
else(DEFINED CMAKE_PLATFORM_ROOT_BIN) # CMake >= 2.8.10
set(RESOURCE_GENRB_CHDIR_DIR "${CMAKE_PLATFORM_INFO_DIR}/${PACKAGE_TARGET_NAME}.dir/")
endif(DEFINED CMAKE_PLATFORM_ROOT_BIN)
# Directory (absolute) where resource bundles are built: concatenation of RESOURCE_GENRB_CHDIR_DIR and package name
set(RESOURCE_OUTPUT_DIR "${RESOURCE_GENRB_CHDIR_DIR}/${PACKAGE_NAME_WE}/")
# Output (relative) path for built package
if(MSVC AND TYPE STREQUAL PKGDATA_LIBRARY_ALIAS)
set(PACKAGE_OUTPUT_PATH "${RESOURCE_GENRB_CHDIR_DIR}/${PACKAGE_NAME_WE}/${PKGDATA_${TYPE}_PREFIX}${PACKAGE_NAME_WE}${PKGDATA_${TYPE}_SUFFIX}")
else(MSVC AND TYPE STREQUAL PKGDATA_LIBRARY_ALIAS)
set(PACKAGE_OUTPUT_PATH "${RESOURCE_GENRB_CHDIR_DIR}/${PKGDATA_${TYPE}_PREFIX}${PACKAGE_NAME_WE}${PKGDATA_${TYPE}_SUFFIX}")
endif(MSVC AND TYPE STREQUAL PKGDATA_LIBRARY_ALIAS)
# Output (absolute) path for the list file
set(PACKAGE_LIST_OUTPUT_PATH "${RESOURCE_GENRB_CHDIR_DIR}/pkglist.txt")
file(MAKE_DIRECTORY "${RESOURCE_OUTPUT_DIR}")
else(PARSED_ARGS_PACKAGE)
set(RESOURCE_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/")
# set(RESOURCE_GENRB_CHDIR_DIR "UNUSED")
endif(PARSED_ARGS_PACKAGE)
set(TARGET_RESOURCES )
set(COMPILED_RESOURCES_PATH )
set(COMPILED_RESOURCES_BASENAME )
foreach(RESOURCE_SOURCE ${PARSED_ARGS_FILES})
_icu_extract_locale_from_rb(${RESOURCE_SOURCE} RESOURCE_NAME_WE)
get_filename_component(SOURCE_BASENAME ${RESOURCE_SOURCE} NAME)
get_filename_component(ABSOLUTE_SOURCE ${RESOURCE_SOURCE} ABSOLUTE)
if(UPPER_FORMAT STREQUAL "XLIFF")
if(RESOURCE_NAME_WE STREQUAL "root")
set(XLIFF_LANGUAGE "en")
else(RESOURCE_NAME_WE STREQUAL "root")
string(REGEX REPLACE "[^a-z].*$" "" XLIFF_LANGUAGE "${RESOURCE_NAME_WE}")
endif(RESOURCE_NAME_WE STREQUAL "root")
endif(UPPER_FORMAT STREQUAL "XLIFF")
##### <templates> #####
set(RESOURCE_TARGET_NAME "${RESOURCE_TARGET_PREFIX}${TARGET_SEPARATOR}${PARSED_ARGS_NAME}${TARGET_SEPARATOR}${RESOURCE_NAME_WE}")
set(RESOURCE_OUTPUT__PATH "${RESOURCE_NAME_WE}.res")
if(RESOURCE_NAME_WE STREQUAL "root")
set(RESOURCE_OUTPUT_JAVA_PATH "${PARSED_ARGS_BUNDLE}.java")
else(RESOURCE_NAME_WE STREQUAL "root")
set(RESOURCE_OUTPUT_JAVA_PATH "${PARSED_ARGS_BUNDLE}_${RESOURCE_NAME_WE}.java")
endif(RESOURCE_NAME_WE STREQUAL "root")
set(RESOURCE_OUTPUT_XLIFF_PATH "${RESOURCE_NAME_WE}.xlf")
set(GENRB__OPTIONS "")
set(GENRB_JAVA_OPTIONS "-j" "-b" "${PARSED_ARGS_BUNDLE}")
set(GENRB_XLIFF_OPTIONS "-x" "-l" "${XLIFF_LANGUAGE}")
##### </templates> #####
# build <locale>.txt from <locale>.res
if(PARSED_ARGS_PACKAGE)
add_custom_command(
OUTPUT "${RESOURCE_OUTPUT_DIR}${RESOURCE_OUTPUT_${UPPER_FORMAT}_PATH}"
COMMAND ${CMAKE_COMMAND} -E chdir ${RESOURCE_GENRB_CHDIR_DIR} ${${ICU_PUBLIC_VAR_NS}_GENRB_EXECUTABLE} ${GENRB_${UPPER_FORMAT}_OPTIONS} -d ${PACKAGE_NAME_WE} ${ABSOLUTE_SOURCE}
DEPENDS ${RESOURCE_SOURCE}
)
else(PARSED_ARGS_PACKAGE)
add_custom_command(
OUTPUT "${RESOURCE_OUTPUT_DIR}${RESOURCE_OUTPUT_${UPPER_FORMAT}_PATH}"
COMMAND ${${ICU_PUBLIC_VAR_NS}_GENRB_EXECUTABLE} ${GENRB_${UPPER_FORMAT}_OPTIONS} -d ${RESOURCE_OUTPUT_DIR} ${ABSOLUTE_SOURCE}
DEPENDS ${RESOURCE_SOURCE}
)
endif(PARSED_ARGS_PACKAGE)
# dummy target (ICU+RB+<name>+<locale>) for each locale to build the <locale>.res file from its <locale>.txt by the add_custom_command above
add_custom_target(
"${RESOURCE_TARGET_NAME}" ALL
COMMENT ""
DEPENDS "${RESOURCE_OUTPUT_DIR}${RESOURCE_OUTPUT_${UPPER_FORMAT}_PATH}"
SOURCES ${RESOURCE_SOURCE}
)
if(PARSED_ARGS_DESTINATION AND NOT PARSED_ARGS_PACKAGE)
install(FILES "${RESOURCE_OUTPUT_DIR}${RESOURCE_OUTPUT_${UPPER_FORMAT}_PATH}" DESTINATION ${PARSED_ARGS_DESTINATION} PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
endif(PARSED_ARGS_DESTINATION AND NOT PARSED_ARGS_PACKAGE)
list(APPEND TARGET_RESOURCES "${RESOURCE_TARGET_NAME}")
list(APPEND COMPILED_RESOURCES_PATH "${RESOURCE_OUTPUT_DIR}${RESOURCE_OUTPUT_${UPPER_FORMAT}_PATH}")
list(APPEND COMPILED_RESOURCES_BASENAME "${RESOURCE_NAME_WE}.${BUNDLES_${UPPER_FORMAT}_SUFFIX}")
endforeach(RESOURCE_SOURCE)
# convert semicolon separated list to a space separated list
# NOTE: if the pkglist.txt file starts (or ends?) with a whitespace, pkgdata add an undefined symbol (named <package>_) for it
string(REPLACE ";" " " COMPILED_RESOURCES_BASENAME "${COMPILED_RESOURCES_BASENAME}")
if(PARSED_ARGS_PACKAGE)
# create a text file (pkglist.txt) with the list of the *.res to package together
add_custom_command(
OUTPUT "${PACKAGE_LIST_OUTPUT_PATH}"
COMMAND ${CMAKE_COMMAND} -E echo "${COMPILED_RESOURCES_BASENAME}" > "${PACKAGE_LIST_OUTPUT_PATH}"
DEPENDS ${COMPILED_RESOURCES_PATH}
)
# run pkgdata from pkglist.txt
add_custom_command(
OUTPUT "${PACKAGE_OUTPUT_PATH}"
COMMAND ${CMAKE_COMMAND} -E chdir ${RESOURCE_GENRB_CHDIR_DIR} ${${ICU_PUBLIC_VAR_NS}_PKGDATA_EXECUTABLE} -F ${PKGDATA_${TYPE}_OPTIONS} -s ${PACKAGE_NAME_WE} -p ${PACKAGE_NAME_WE} ${PACKAGE_LIST_OUTPUT_PATH}
DEPENDS "${PACKAGE_LIST_OUTPUT_PATH}"
VERBATIM
)
if(PKGDATA_LIBRARY_${TYPE}_TYPE)
# assert(${PARSED_ARGS_DEPENDS} != "")
if(NOT PARSED_ARGS_DEPENDS)
message(FATAL_ERROR "${__FUNCTION__}(): static and library mode imply a list of targets to link to, DEPENDS parameter missing")
endif(NOT PARSED_ARGS_DEPENDS)
add_library(${PACKAGE_TARGET_NAME} ${PKGDATA_LIBRARY_${TYPE}_TYPE} IMPORTED)
if(MSVC)
string(REGEX REPLACE "${PKGDATA_LIBRARY_SUFFIX}\$" "${CMAKE_IMPORT_LIBRARY_SUFFIX}" PACKAGE_OUTPUT_LIB "${PACKAGE_OUTPUT_PATH}")
set_target_properties(${PACKAGE_TARGET_NAME} PROPERTIES IMPORTED_LOCATION ${PACKAGE_OUTPUT_PATH} IMPORTED_IMPLIB ${PACKAGE_OUTPUT_LIB})
else(MSVC)
set_target_properties(${PACKAGE_TARGET_NAME} PROPERTIES IMPORTED_LOCATION ${PACKAGE_OUTPUT_PATH})
endif(MSVC)
foreach(DEPENDENCY ${PARSED_ARGS_DEPENDS})
target_link_libraries(${DEPENDENCY} ${PACKAGE_TARGET_NAME})
if(NOT PARSED_ARGS_NO_SHARED_FLAGS)
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
list(LENGTH "${ENABLED_LANGUAGES}" ENABLED_LANGUAGES_LENGTH)
if(ENABLED_LANGUAGES_LENGTH GREATER 1)
message(WARNING "Project has more than one language enabled, skip automatic shared flags appending")
else(ENABLED_LANGUAGES_LENGTH GREATER 1)
set_property(TARGET "${DEPENDENCY}" APPEND PROPERTY COMPILE_FLAGS "${${ICU_PUBLIC_VAR_NS}_${ENABLED_LANGUAGES}_SHARED_FLAGS}")
endif(ENABLED_LANGUAGES_LENGTH GREATER 1)
endif(NOT PARSED_ARGS_NO_SHARED_FLAGS)
endforeach(DEPENDENCY)
# http://www.mail-archive.com/cmake-commits@cmake.org/msg01135.html
set(PACKAGE_INTERMEDIATE_TARGET_NAME "${PACKAGE_TARGET_NAME}${TARGET_SEPARATOR}DUMMY")
# dummy intermediate target (ICU+PKG+<name>+DUMMY) to link the package to the produced library by running pkgdata (see add_custom_command above)
add_custom_target(
${PACKAGE_INTERMEDIATE_TARGET_NAME}
COMMENT ""
DEPENDS "${PACKAGE_OUTPUT_PATH}"
)
add_dependencies("${PACKAGE_TARGET_NAME}" "${PACKAGE_INTERMEDIATE_TARGET_NAME}")
else(PKGDATA_LIBRARY_${TYPE}_TYPE)
# dummy target (ICU+PKG+<name>) to run pkgdata (see add_custom_command above)
add_custom_target(
"${PACKAGE_TARGET_NAME}" ALL
COMMENT ""
DEPENDS "${PACKAGE_OUTPUT_PATH}"
)
endif(PKGDATA_LIBRARY_${TYPE}_TYPE)
# dummy target (ICU+PKG+<name>+PKGLIST) to build the file pkglist.txt
add_custom_target(
"${PACKAGE_LIST_TARGET_NAME}" ALL
COMMENT ""
DEPENDS "${PACKAGE_LIST_OUTPUT_PATH}"
)
# package => pkglist.txt
add_dependencies("${PACKAGE_TARGET_NAME}" "${PACKAGE_LIST_TARGET_NAME}")
# pkglist.txt => *.res
add_dependencies("${PACKAGE_LIST_TARGET_NAME}" ${TARGET_RESOURCES})
if(PARSED_ARGS_DESTINATION)
install(FILES "${PACKAGE_OUTPUT_PATH}" DESTINATION ${PARSED_ARGS_DESTINATION} PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
endif(PARSED_ARGS_DESTINATION)
endif(PARSED_ARGS_PACKAGE)
endfunction(icu_generate_resource_bundle)
########## </resource bundle support> ##########
########## <debug> ##########
if(${ICU_PUBLIC_VAR_NS}_DEBUG)
function(icudebug _VARNAME)
if(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = ${${ICU_PUBLIC_VAR_NS}_${_VARNAME}}")
else(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = <UNDEFINED>")
endif(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
endfunction(icudebug)
# IN (args)
icudebug("FIND_COMPONENTS")
icudebug("FIND_REQUIRED")
icudebug("FIND_QUIETLY")
icudebug("FIND_VERSION")
# OUT
# Found
icudebug("FOUND")
# Flags
icudebug("C_FLAGS")
icudebug("CPP_FLAGS")
icudebug("CXX_FLAGS")
icudebug("C_SHARED_FLAGS")
icudebug("CPP_SHARED_FLAGS")
icudebug("CXX_SHARED_FLAGS")
# Linking
icudebug("INCLUDE_DIRS")
icudebug("LIBRARIES")
# Version
icudebug("VERSION_MAJOR")
icudebug("VERSION_MINOR")
icudebug("VERSION_PATCH")
icudebug("VERSION")
# <COMPONENT>_(FOUND|LIBRARY)
set(${ICU_PRIVATE_VAR_NS}_COMPONENT_VARIABLES "FOUND" "LIBRARY" "LIBRARY_RELEASE" "LIBRARY_DEBUG")
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS})
string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT_VARIABLE ${${ICU_PRIVATE_VAR_NS}_COMPONENT_VARIABLES})
icudebug("${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_${${ICU_PRIVATE_VAR_NS}_COMPONENT_VARIABLE}")
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT_VARIABLE)
endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
endif(${ICU_PUBLIC_VAR_NS}_DEBUG)
########## </debug> ##########

View File

@ -657,6 +657,18 @@ ADD_ASSIMP_IMPORTER( 3MF
D3MFOpcPackage.cpp
)
ADD_ASSIMP_IMPORTER( MMD
MMDCpp14.h
MMDImporter.cpp
MMDImporter.h
MMDPmdParser.h
MMDPmxParser.h
MMDPmxParser.cpp
MMDVmdParser.h
)
find_package(ICU COMPONENTS uc io REQUIRED)
SET( Step_SRCS
StepExporter.h
StepExporter.cpp
@ -850,9 +862,11 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
INCLUDE_DIRECTORIES(${C4D_INCLUDES})
ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
INCLUDE_DIRECTORIES(${ICU_INCLUDE_DIRS})
ADD_LIBRARY( assimp ${assimp_src} )
TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} )
TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${ICU_LIBRARIES} )
if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI)

View File

@ -188,6 +188,9 @@ corresponding preprocessor flag to selectively disable formats.
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
# include "X3DImporter.hpp"
#endif
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
# include "MMDImporter.h"
#endif
namespace Assimp {
@ -332,11 +335,14 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
out.push_back( new C4DImporter() );
#endif
#if ( !defined ASSIMP_BUILD_NO_3MF_IMPORTER )
out.push_back(new D3MFImporter() );
out.push_back( new D3MFImporter() );
#endif
#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
out.push_back( new X3DImporter() );
#endif
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
out.push_back( new MMDImporter() );
#endif
}
/** will delete all registered importers. */

41
code/MMDCpp14.h 100644
View File

@ -0,0 +1,41 @@
#pragma once
#ifndef MMD_CPP14_H
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
namespace std {
template<class T> struct _Unique_if {
typedef unique_ptr<T> _Single_object;
};
template<class T> struct _Unique_if<T[]> {
typedef unique_ptr<T[]> _Unknown_bound;
};
template<class T, size_t N> struct _Unique_if<T[N]> {
typedef void _Known_bound;
};
template<class T, class... Args>
typename _Unique_if<T>::_Single_object
make_unique(Args&&... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<class T>
typename _Unique_if<T>::_Unknown_bound
make_unique(size_t n) {
typedef typename remove_extent<T>::type U;
return unique_ptr<T>(new U[n]());
}
template<class T, class... Args>
typename _Unique_if<T>::_Known_bound
make_unique(Args&&...) = delete;
}
#endif

View File

@ -0,0 +1,190 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp team
All rights reserved.
Redistribution and use of this software 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.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
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.
---------------------------------------------------------------------------
*/
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
#include "DefaultIOSystem.h"
#include "MMDImporter.h"
#include "MMDPmxParser.h"
#include "MMDPmdParser.h"
#include "MMDVmdParser.h"
//#include "IOStreamBuffer.h"
#include <memory>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp>
#include <fstream>
#include <iomanip>
static const aiImporterDesc desc = {
"MMD Importer",
"",
"",
"surfaces supported?",
aiImporterFlags_SupportTextFlavour,
0,
0,
0,
0,
"pmx"
};
namespace Assimp {
using namespace std;
// ------------------------------------------------------------------------------------------------
// Default constructor
MMDImporter::MMDImporter() :
m_Buffer(),
//m_pRootObject( NULL ),
m_strAbsPath( "" )
{
DefaultIOSystem io;
m_strAbsPath = io.getOsSeparator();
}
// ------------------------------------------------------------------------------------------------
// Destructor.
MMDImporter::~MMDImporter()
{
//delete m_pRootObject;
//m_pRootObject = NULL;
}
// ------------------------------------------------------------------------------------------------
// Returns true, if file is an pmx file.
bool MMDImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler , bool checkSig ) const
{
if(!checkSig) //Check File Extension
{
return SimpleExtensionCheck(pFile,"pmx");
}
else //Check file Header
{
static const char *pTokens[] = { "PMX " };
return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 1 );
}
}
// ------------------------------------------------------------------------------------------------
const aiImporterDesc* MMDImporter::GetInfo () const
{
return &desc;
}
// ------------------------------------------------------------------------------------------------
// MMD import implementation
void MMDImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler)
{
// Read file by istream
std::filebuf fb;
if( !fb.open(file, std::ios::in | std::ios::binary ) ) {
throw DeadlyImportError( "Failed to open file " + file + "." );
}
std::istream fileStream( &fb );
// Get the file-size and validate it, throwing an exception when fails
fileStream.seekg(0, fileStream.end);
size_t fileSize = fileStream.tellg();
fileStream.seekg(0, fileStream.beg);
if( fileSize < sizeof(pmx::PmxModel) ) {
throw DeadlyImportError( file + " is too small." );
}
pmx::PmxModel model;
model.Read(&fileStream);
CreateDataFromImport(&model, pScene);
}
// ------------------------------------------------------------------------------------------------
void MMDImporter::CreateDataFromImport(const pmx::PmxModel* pModel, aiScene* pScene)
{
if( pModel == NULL ) {
return;
}
pScene->mRootNode = new aiNode;
if ( !pModel->model_name.empty() ) {
pScene->mRootNode->mName.Set(pModel->model_name);
}
else {
ai_assert(false);
}
std::cout << pScene->mRootNode->mName.C_Str() << std::endl;
// workaround, must be deleted
pScene->mNumMeshes = 1;
pScene->mNumMaterials = 1;
pScene->mRootNode->mMeshes = new unsigned int[1];
aiMesh *pMesh = new aiMesh;
pScene->mRootNode->mMeshes[0] = 100;
// workaround
/*
// Create nodes for the whole scene
std::vector<aiMesh*> MeshArray;
for ( size_t index = 0; index < pModel->bone_count; index++ ) {
createNodes( pModel, pModel->bones[i], pScene, MeshArray);
}
if ( pScene->mNumMeshes > 0 ) {
pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
for ( size_t index = 0; index < MeshArray.size(); index++ ) {
pScene->mMeshes[ index ] = MeshArray[ index ];
}
}
// Create all materials
createMaterials( pModel, pScene );
*/
}
// ------------------------------------------------------------------------------------------------
} // Namespace Assimp
#endif // !! ASSIMP_BUILD_NO_MMD_IMPORTER

100
code/MMDImporter.h 100644
View File

@ -0,0 +1,100 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2016, assimp team
All rights reserved.
Redistribution and use of this software 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.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
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.
----------------------------------------------------------------------
*/
#ifndef MMD_FILE_IMPORTER_H_INC
#define MMD_FILE_IMPORTER_H_INC
#include "BaseImporter.h"
#include "MMDPmxParser.h"
#include <assimp/material.h>
#include <vector>
struct aiMesh;
struct aiNode;
namespace Assimp {
/*
namespace MMDFile {
struct Object;
struct Model;
}
*/
// ------------------------------------------------------------------------------------------------
/// \class MMDImporter
/// \brief Imports MMD a pmx/pmd/vmd file
// ------------------------------------------------------------------------------------------------
class MMDImporter : public BaseImporter {
public:
/// \brief Default constructor
MMDImporter();
/// \brief Destructor
~MMDImporter();
public:
/// \brief Returns whether the class can handle the format of the given file.
/// \remark See BaseImporter::CanRead() for details.
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
private:
//! \brief Appends the supported extension.
const aiImporterDesc* GetInfo () const;
//! \brief File import implementation.
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
//! \brief Create the data from imported content.
void CreateDataFromImport(const pmx::PmxModel* pModel, aiScene* pScene);
private:
//! Data buffer
std::vector<char> m_Buffer;
//! Pointer to root object instance
//MMDFile::Object *m_pRootObject;
//! Absolute pathname of model in file system
std::string m_strAbsPath;
};
// ------------------------------------------------------------------------------------------------
} // Namespace Assimp
#endif

630
code/MMDPmdParser.h 100644
View File

@ -0,0 +1,630 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <iostream>
#include <fstream>
#include "MMDCpp14.h"
namespace pmd
{
/// ヘッダ
class PmdHeader
{
public:
/// モデル名
std::string name;
/// モデル名(英語)
std::string name_english;
/// コメント
std::string comment;
/// コメント(英語)
std::string comment_english;
bool Read(std::ifstream* stream)
{
char buffer[256];
stream->read(buffer, 20);
name = std::string(buffer);
stream->read(buffer, 256);
comment = std::string(buffer);
return true;
}
bool ReadExtension(std::ifstream* stream)
{
char buffer[256];
stream->read(buffer, 20);
name_english = std::string(buffer);
stream->read(buffer, 256);
comment_english = std::string(buffer);
return true;
}
};
/// 頂点
class PmdVertex
{
public:
/// 位置
float position[3];
/// 法線
float normal[3];
/// UV座標
float uv[2];
/// 関連ボーンインデックス
uint16_t bone_index[2];
/// ボーンウェイト
uint8_t bone_weight;
/// エッジ不可視
bool edge_invisible;
bool Read(std::ifstream* stream)
{
stream->read((char*) position, sizeof(float) * 3);
stream->read((char*) normal, sizeof(float) * 3);
stream->read((char*) uv, sizeof(float) * 2);
stream->read((char*) bone_index, sizeof(uint16_t) * 2);
stream->read((char*) &bone_weight, sizeof(uint8_t));
stream->read((char*) &edge_invisible, sizeof(uint8_t));
return true;
}
};
/// 材質
class PmdMaterial
{
public:
/// 減衰色
float diffuse[4];
/// 光沢度
float power;
/// 光沢色
float specular[3];
/// 環境色
float ambient[3];
/// トーンインデックス
uint8_t toon_index;
/// エッジ
uint8_t edge_flag;
/// インデックス数
uint32_t index_count;
/// テクスチャファイル名
std::string texture_filename;
/// スフィアファイル名
std::string sphere_filename;
bool Read(std::ifstream* stream)
{
char buffer[20];
stream->read((char*) &diffuse, sizeof(float) * 4);
stream->read((char*) &power, sizeof(float));
stream->read((char*) &specular, sizeof(float) * 3);
stream->read((char*) &ambient, sizeof(float) * 3);
stream->read((char*) &toon_index, sizeof(uint8_t));
stream->read((char*) &edge_flag, sizeof(uint8_t));
stream->read((char*) &index_count, sizeof(uint32_t));
stream->read((char*) &buffer, sizeof(char) * 20);
char* pstar = strchr(buffer, '*');
if (NULL == pstar)
{
texture_filename = std::string(buffer);
sphere_filename.clear();
}
else {
*pstar = NULL;
texture_filename = std::string(buffer);
sphere_filename = std::string(pstar+1);
}
return true;
}
};
enum class BoneType : uint8_t
{
Rotation,
RotationAndMove,
IkEffector,
Unknown,
IkEffectable,
RotationEffectable,
IkTarget,
Invisible,
Twist,
RotationMovement
};
/// ボーン
class PmdBone
{
public:
/// ボーン名
std::string name;
/// ボーン名(英語)
std::string name_english;
/// 親ボーン番号
uint16_t parent_bone_index;
/// 末端ボーン番号
uint16_t tail_pos_bone_index;
/// ボーン種類
BoneType bone_type;
/// IKボーン番号
uint16_t ik_parent_bone_index;
/// ボーンのヘッドの位置
float bone_head_pos[3];
void Read(std::istream *stream)
{
char buffer[20];
stream->read(buffer, 20);
name = std::string(buffer);
stream->read((char*) &parent_bone_index, sizeof(uint16_t));
stream->read((char*) &tail_pos_bone_index, sizeof(uint16_t));
stream->read((char*) &bone_type, sizeof(uint8_t));
stream->read((char*) &ik_parent_bone_index, sizeof(uint16_t));
stream->read((char*) &bone_head_pos, sizeof(float) * 3);
}
void ReadExpantion(std::istream *stream)
{
char buffer[20];
stream->read(buffer, 20);
name_english = std::string(buffer);
}
};
/// IK
class PmdIk
{
public:
/// IKボーン番号
uint16_t ik_bone_index;
/// IKターゲットボーン番号
uint16_t target_bone_index;
/// 再帰回数
uint16_t interations;
/// 角度制限
float angle_limit;
/// 影響下ボーン番号
std::vector<uint16_t> ik_child_bone_index;
void Read(std::istream *stream)
{
stream->read((char *) &ik_bone_index, sizeof(uint16_t));
stream->read((char *) &target_bone_index, sizeof(uint16_t));
uint8_t ik_chain_length;
stream->read((char*) &ik_chain_length, sizeof(uint8_t));
stream->read((char *) &interations, sizeof(uint16_t));
stream->read((char *) &angle_limit, sizeof(float));
ik_child_bone_index.resize(ik_chain_length);
for (int i = 0; i < ik_chain_length; i++)
{
stream->read((char *) &ik_child_bone_index[i], sizeof(uint16_t));
}
}
};
class PmdFaceVertex
{
public:
int vertex_index;
float position[3];
void Read(std::istream *stream)
{
stream->read((char *) &vertex_index, sizeof(int));
stream->read((char *) position, sizeof(float) * 3);
}
};
enum class FaceCategory : uint8_t
{
Base,
Eyebrow,
Eye,
Mouth,
Other
};
class PmdFace
{
public:
std::string name;
FaceCategory type;
std::vector<PmdFaceVertex> vertices;
std::string name_english;
void Read(std::istream *stream)
{
char buffer[20];
stream->read(buffer, 20);
name = std::string(buffer);
int vertex_count;
stream->read((char*) &vertex_count, sizeof(int));
stream->read((char*) &type, sizeof(uint8_t));
vertices.resize(vertex_count);
for (int i = 0; i < vertex_count; i++)
{
vertices[i].Read(stream);
}
}
void ReadExpantion(std::istream *stream)
{
char buffer[20];
stream->read(buffer, 20);
name_english = std::string(buffer);
}
};
/// ボーン枠用の枠名
class PmdBoneDispName
{
public:
std::string bone_disp_name;
std::string bone_disp_name_english;
void Read(std::istream *stream)
{
char buffer[50];
stream->read(buffer, 50);
bone_disp_name = std::string(buffer);
bone_disp_name_english.clear();
}
void ReadExpantion(std::istream *stream)
{
char buffer[50];
stream->read(buffer, 50);
bone_disp_name_english = std::string(buffer);
}
};
class PmdBoneDisp
{
public:
uint16_t bone_index;
uint8_t bone_disp_index;
void Read(std::istream *stream)
{
stream->read((char*) &bone_index, sizeof(uint16_t));
stream->read((char*) &bone_disp_index, sizeof(uint8_t));
}
};
/// 衝突形状
enum class RigidBodyShape : uint8_t
{
/// 球
Sphere = 0,
/// 直方体
Box = 1,
/// カプセル
Cpusel = 2
};
/// 剛体タイプ
enum class RigidBodyType : uint8_t
{
/// ボーン追従
BoneConnected = 0,
/// 物理演算
Physics = 1,
/// 物理演算(Bone位置合せ)
ConnectedPhysics = 2
};
/// 剛体
class PmdRigidBody
{
public:
/// 名前
std::string name;
/// 関連ボーン番号
uint16_t related_bone_index;
/// グループ番号
uint8_t group_index;
/// マスク
uint16_t mask;
/// 形状
RigidBodyShape shape;
/// 大きさ
float size[3];
/// 位置
float position[3];
/// 回転
float orientation[3];
/// 質量
float weight;
/// 移動ダンピング
float linear_damping;
/// 回転ダンピング
float anglar_damping;
/// 反発係数
float restitution;
/// 摩擦係数
float friction;
/// 演算方法
RigidBodyType rigid_type;
void Read(std::istream *stream)
{
char buffer[20];
stream->read(buffer, sizeof(char) * 20);
name = (std::string(buffer));
stream->read((char*) &related_bone_index, sizeof(uint16_t));
stream->read((char*) &group_index, sizeof(uint8_t));
stream->read((char*) &mask, sizeof(uint16_t));
stream->read((char*) &shape, sizeof(uint8_t));
stream->read((char*) size, sizeof(float) * 3);
stream->read((char*) position, sizeof(float) * 3);
stream->read((char*) orientation, sizeof(float) * 3);
stream->read((char*) &weight, sizeof(float));
stream->read((char*) &linear_damping, sizeof(float));
stream->read((char*) &anglar_damping, sizeof(float));
stream->read((char*) &restitution, sizeof(float));
stream->read((char*) &friction, sizeof(float));
stream->read((char*) &rigid_type, sizeof(char));
}
};
/// 剛体の拘束
class PmdConstraint
{
public:
/// 名前
std::string name;
/// 剛体Aのインデックス
uint32_t rigid_body_index_a;
/// 剛体Bのインデックス
uint32_t rigid_body_index_b;
/// 位置
float position[3];
/// 回転
float orientation[3];
/// 最小移動制限
float linear_lower_limit[3];
/// 最大移動制限
float linear_upper_limit[3];
/// 最小回転制限
float angular_lower_limit[3];
/// 最大回転制限
float angular_upper_limit[3];
/// 移動に対する復元力
float linear_stiffness[3];
/// 回転に対する復元力
float angular_stiffness[3];
void Read(std::istream *stream)
{
char buffer[20];
stream->read(buffer, 20);
name = std::string(buffer);
stream->read((char *) &rigid_body_index_a, sizeof(uint32_t));
stream->read((char *) &rigid_body_index_b, sizeof(uint32_t));
stream->read((char *) position, sizeof(float) * 3);
stream->read((char *) orientation, sizeof(float) * 3);
stream->read((char *) linear_lower_limit, sizeof(float) * 3);
stream->read((char *) linear_upper_limit, sizeof(float) * 3);
stream->read((char *) angular_lower_limit, sizeof(float) * 3);
stream->read((char *) angular_upper_limit, sizeof(float) * 3);
stream->read((char *) linear_stiffness, sizeof(float) * 3);
stream->read((char *) angular_stiffness, sizeof(float) * 3);
}
};
/// PMDモデル
class PmdModel
{
public:
float version;
PmdHeader header;
std::vector<PmdVertex> vertices;
std::vector<uint16_t> indices;
std::vector<PmdMaterial> materials;
std::vector<PmdBone> bones;
std::vector<PmdIk> iks;
std::vector<PmdFace> faces;
std::vector<uint16_t> faces_indices;
std::vector<PmdBoneDispName> bone_disp_name;
std::vector<PmdBoneDisp> bone_disp;
std::vector<std::string> toon_filenames;
std::vector<PmdRigidBody> rigid_bodies;
std::vector<PmdConstraint> constraints;
static std::unique_ptr<PmdModel> LoadFromFile(const char *filename)
{
std::ifstream stream(filename, std::ios::binary);
if (stream.fail())
{
std::cerr << "could not open \"" << filename << "\"" << std::endl;
return nullptr;
}
auto result = LoadFromStream(&stream);
stream.close();
return result;
}
/// ファイルからPmdModelを生成する
static std::unique_ptr<PmdModel> LoadFromStream(std::ifstream *stream)
{
auto result = std::make_unique<PmdModel>();
char buffer[100];
// magic
char magic[3];
stream->read(magic, 3);
if (magic[0] != 'P' || magic[1] != 'm' || magic[2] != 'd')
{
std::cerr << "invalid file" << std::endl;
return nullptr;
}
// version
stream->read((char*) &(result->version), sizeof(float));
if (result ->version != 1.0f)
{
std::cerr << "invalid version" << std::endl;
return nullptr;
}
// header
result->header.Read(stream);
// vertices
uint32_t vertex_num;
stream->read((char*) &vertex_num, sizeof(uint32_t));
result->vertices.resize(vertex_num);
for (uint32_t i = 0; i < vertex_num; i++)
{
result->vertices[i].Read(stream);
}
// indices
uint32_t index_num;
stream->read((char*) &index_num, sizeof(uint32_t));
result->indices.resize(index_num);
for (uint32_t i = 0; i < index_num; i++)
{
stream->read((char*) &result->indices[i], sizeof(uint16_t));
}
// materials
uint32_t material_num;
stream->read((char*) &material_num, sizeof(uint32_t));
result->materials.resize(material_num);
for (uint32_t i = 0; i < material_num; i++)
{
result->materials[i].Read(stream);
}
// bones
uint16_t bone_num;
stream->read((char*) &bone_num, sizeof(uint16_t));
result->bones.resize(bone_num);
for (uint32_t i = 0; i < bone_num; i++)
{
result->bones[i].Read(stream);
}
// iks
uint16_t ik_num;
stream->read((char*) &ik_num, sizeof(uint16_t));
result->iks.resize(ik_num);
for (uint32_t i = 0; i < ik_num; i++)
{
result->iks[i].Read(stream);
}
// faces
uint16_t face_num;
stream->read((char*) &face_num, sizeof(uint16_t));
result->faces.resize(face_num);
for (uint32_t i = 0; i < face_num; i++)
{
result->faces[i].Read(stream);
}
// face frames
uint8_t face_frame_num;
stream->read((char*) &face_frame_num, sizeof(uint8_t));
result->faces_indices.resize(face_frame_num);
for (uint32_t i = 0; i < face_frame_num; i++)
{
stream->read((char*) &result->faces_indices[i], sizeof(uint16_t));
}
// bone names
uint8_t bone_disp_num;
stream->read((char*) &bone_disp_num, sizeof(uint8_t));
result->bone_disp_name.resize(bone_disp_num);
for (uint32_t i = 0; i < bone_disp_num; i++)
{
result->bone_disp_name[i].Read(stream);
}
// bone frame
uint32_t bone_frame_num;
stream->read((char*) &bone_frame_num, sizeof(uint32_t));
result->bone_disp.resize(bone_frame_num);
for (uint32_t i = 0; i < bone_frame_num; i++)
{
result->bone_disp[i].Read(stream);
}
// english name
bool english;
stream->read((char*) &english, sizeof(char));
if (english)
{
result->header.ReadExtension(stream);
for (uint32_t i = 0; i < bone_num; i++)
{
result->bones[i].ReadExpantion(stream);
}
for (uint32_t i = 0; i < face_num; i++)
{
if (result->faces[i].type == pmd::FaceCategory::Base)
{
continue;
}
result->faces[i].ReadExpantion(stream);
}
for (uint32_t i = 0; i < result->bone_disp_name.size(); i++)
{
result->bone_disp_name[i].ReadExpantion(stream);
}
}
// toon textures
if (stream->peek() == std::ios::traits_type::eof())
{
result->toon_filenames.clear();
}
else {
result->toon_filenames.resize(10);
for (uint32_t i = 0; i < 10; i++)
{
stream->read(buffer, 100);
result->toon_filenames[i] = std::string(buffer);
}
}
// physics
if (stream->peek() == std::ios::traits_type::eof())
{
result->rigid_bodies.clear();
result->constraints.clear();
}
else {
uint32_t rigid_body_num;
stream->read((char*) &rigid_body_num, sizeof(uint32_t));
result->rigid_bodies.resize(rigid_body_num);
for (uint32_t i = 0; i < rigid_body_num; i++)
{
result->rigid_bodies[i].Read(stream);
}
uint32_t constraint_num;
stream->read((char*) &constraint_num, sizeof(uint32_t));
result->constraints.resize(constraint_num);
for (uint32_t i = 0; i < constraint_num; i++)
{
result->constraints[i].Read(stream);
}
}
if (stream->peek() != std::ios::traits_type::eof())
{
std::cerr << "there is unknown data" << std::endl;
}
return result;
}
};
}

View File

@ -0,0 +1,625 @@
#include <utility>
#include "MMDPmxParser.h"
#ifndef __unix__
#include "EncodingHelper.h"
#else
#include <unicode/ucnv.h>
#endif
namespace pmx
{
/// インデックス値を読み込む
int ReadIndex(std::istream *stream, int size)
{
switch (size)
{
case 1:
uint8_t tmp8;
stream->read((char*) &tmp8, sizeof(uint8_t));
if (255 == tmp8)
{
return -1;
}
else {
return (int) tmp8;
}
case 2:
uint16_t tmp16;
stream->read((char*) &tmp16, sizeof(uint16_t));
if (65535 == tmp16)
{
return -1;
}
else {
return (int) tmp16;
}
case 4:
int tmp32;
stream->read((char*) &tmp32, sizeof(int));
return tmp32;
default:
return -1;
}
}
/// 文字列を読み込む
utfstring ReadString(std::istream *stream, uint8_t encoding)
{
#ifndef __unix__
oguna::EncodingConverter converter = oguna::EncodingConverter();
#endif
int size;
stream->read((char*) &size, sizeof(int));
std::vector<char> buffer;
if (size == 0)
{
#ifndef __unix__
return utfstring(L"");
#else
return utfstring("");
#endif
}
buffer.reserve(size);
stream->read((char*) buffer.data(), size);
if (encoding == 0)
{
// UTF16
#ifndef __unix__
return utfstring((wchar_t*) buffer.data(), size / 2);
#else
utfstring result;
std::vector<char> outbuf;
outbuf.reserve(size*2);
// Always remember to set U_ZERO_ERROR before calling ucnv_convert(),
// otherwise the function will fail.
UErrorCode err = U_ZERO_ERROR;
size = ucnv_convert("UTF-8", "UTF-16LE", (char*)outbuf.data(), outbuf.capacity(), buffer.data(), size, &err);
if(!U_SUCCESS(err)) {
std::cout << "oops, something wrong?" << std::endl;
std::cout << u_errorName(err) << std::endl;
exit(-1);
}
result.assign((const char*)outbuf.data(), size);
return result;
#endif
}
else
{
// UTF8
#ifndef __unix__
utfstring result;
converter.Utf8ToUtf16(buffer.data(), size, &result);
return result;
#else
return utfstring((const char*)buffer.data(), size);
#endif
}
}
void PmxSetting::Read(std::istream *stream)
{
uint8_t count;
stream->read((char*) &count, sizeof(uint8_t));
if (count < 8)
{
throw;
}
stream->read((char*) &encoding, sizeof(uint8_t));
stream->read((char*) &uv, sizeof(uint8_t));
stream->read((char*) &vertex_index_size, sizeof(uint8_t));
stream->read((char*) &texture_index_size, sizeof(uint8_t));
stream->read((char*) &material_index_size, sizeof(uint8_t));
stream->read((char*) &bone_index_size, sizeof(uint8_t));
stream->read((char*) &morph_index_size, sizeof(uint8_t));
stream->read((char*) &rigidbody_index_size, sizeof(uint8_t));
uint8_t temp;
for (int i = 8; i < count; i++)
{
stream->read((char*)&temp, sizeof(uint8_t));
}
}
void PmxVertexSkinningBDEF1::Read(std::istream *stream, PmxSetting *setting)
{
this->bone_index = ReadIndex(stream, setting->bone_index_size);
}
void PmxVertexSkinningBDEF2::Read(std::istream *stream, PmxSetting *setting)
{
this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->bone_weight, sizeof(float));
}
void PmxVertexSkinningBDEF4::Read(std::istream *stream, PmxSetting *setting)
{
this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
this->bone_index3 = ReadIndex(stream, setting->bone_index_size);
this->bone_index4 = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->bone_weight1, sizeof(float));
stream->read((char*) &this->bone_weight2, sizeof(float));
stream->read((char*) &this->bone_weight3, sizeof(float));
stream->read((char*) &this->bone_weight4, sizeof(float));
}
void PmxVertexSkinningSDEF::Read(std::istream *stream, PmxSetting *setting)
{
this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->bone_weight, sizeof(float));
stream->read((char*) this->sdef_c, sizeof(float) * 3);
stream->read((char*) this->sdef_r0, sizeof(float) * 3);
stream->read((char*) this->sdef_r1, sizeof(float) * 3);
}
void PmxVertexSkinningQDEF::Read(std::istream *stream, PmxSetting *setting)
{
this->bone_index1 = ReadIndex(stream, setting->bone_index_size);
this->bone_index2 = ReadIndex(stream, setting->bone_index_size);
this->bone_index3 = ReadIndex(stream, setting->bone_index_size);
this->bone_index4 = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->bone_weight1, sizeof(float));
stream->read((char*) &this->bone_weight2, sizeof(float));
stream->read((char*) &this->bone_weight3, sizeof(float));
stream->read((char*) &this->bone_weight4, sizeof(float));
}
void PmxVertex::Read(std::istream *stream, PmxSetting *setting)
{
stream->read((char*) this->positon, sizeof(float) * 3);
stream->read((char*) this->normal, sizeof(float) * 3);
stream->read((char*) this->uv, sizeof(float) * 2);
for (int i = 0; i < setting->uv; ++i)
{
stream->read((char*) this->uva[i], sizeof(float) * 4);
}
stream->read((char*) &this->skinning_type, sizeof(PmxVertexSkinningType));
switch (this->skinning_type)
{
case PmxVertexSkinningType::BDEF1:
this->skinning = std::make_unique<PmxVertexSkinningBDEF1>();
break;
case PmxVertexSkinningType::BDEF2:
this->skinning = std::make_unique<PmxVertexSkinningBDEF2>();
break;
case PmxVertexSkinningType::BDEF4:
this->skinning = std::make_unique<PmxVertexSkinningBDEF4>();
break;
case PmxVertexSkinningType::SDEF:
this->skinning = std::make_unique<PmxVertexSkinningSDEF>();
break;
case PmxVertexSkinningType::QDEF:
this->skinning = std::make_unique<PmxVertexSkinningQDEF>();
break;
default:
throw "invalid skinning type";
}
this->skinning->Read(stream, setting);
stream->read((char*) &this->edge, sizeof(float));
}
void PmxMaterial::Read(std::istream *stream, PmxSetting *setting)
{
this->material_name = std::move(ReadString(stream, setting->encoding));
this->material_english_name = std::move(ReadString(stream, setting->encoding));
stream->read((char*) this->diffuse, sizeof(float) * 4);
stream->read((char*) this->specular, sizeof(float) * 3);
stream->read((char*) &this->specularlity, sizeof(float));
stream->read((char*) this->ambient, sizeof(float) * 3);
stream->read((char*) &this->flag, sizeof(uint8_t));
stream->read((char*) this->edge_color, sizeof(float) * 4);
stream->read((char*) &this->edge_size, sizeof(float));
this->diffuse_texture_index = ReadIndex(stream, setting->texture_index_size);
this->sphere_texture_index = ReadIndex(stream, setting->texture_index_size);
stream->read((char*) &this->sphere_op_mode, sizeof(uint8_t));
stream->read((char*) &this->common_toon_flag, sizeof(uint8_t));
if (this->common_toon_flag)
{
stream->read((char*) &this->toon_texture_index, sizeof(uint8_t));
}
else {
this->toon_texture_index = ReadIndex(stream, setting->texture_index_size);
}
this->memo = std::move(ReadString(stream, setting->encoding));
stream->read((char*) &this->index_count, sizeof(int));
}
void PmxIkLink::Read(std::istream *stream, PmxSetting *setting)
{
this->link_target = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->angle_lock, sizeof(uint8_t));
if (angle_lock == 1)
{
stream->read((char*) this->max_radian, sizeof(float) * 3);
stream->read((char*) this->min_radian, sizeof(float) * 3);
}
}
void PmxBone::Read(std::istream *stream, PmxSetting *setting)
{
this->bone_name = std::move(ReadString(stream, setting->encoding));
this->bone_english_name = std::move(ReadString(stream, setting->encoding));
stream->read((char*) this->position, sizeof(float) * 3);
this->parent_index = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->level, sizeof(int));
stream->read((char*) &this->bone_flag, sizeof(uint16_t));
if (this->bone_flag & 0x0001) {
this->target_index = ReadIndex(stream, setting->bone_index_size);
}
else {
stream->read((char*)this->offset, sizeof(float) * 3);
}
if (this->bone_flag & (0x0100 | 0x0200)) {
this->grant_parent_index = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->grant_weight, sizeof(float));
}
if (this->bone_flag & 0x0400) {
stream->read((char*)this->lock_axis_orientation, sizeof(float) * 3);
}
if (this->bone_flag & 0x0800) {
stream->read((char*)this->local_axis_x_orientation, sizeof(float) * 3);
stream->read((char*)this->local_axis_y_orientation, sizeof(float) * 3);
}
if (this->bone_flag & 0x2000) {
stream->read((char*) &this->key, sizeof(int));
}
if (this->bone_flag & 0x0020) {
this->ik_target_bone_index = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &ik_loop, sizeof(int));
stream->read((char*) &ik_loop_angle_limit, sizeof(float));
stream->read((char*) &ik_link_count, sizeof(int));
this->ik_links = std::make_unique<PmxIkLink []>(ik_link_count);
for (int i = 0; i < ik_link_count; i++) {
ik_links[i].Read(stream, setting);
}
}
}
void PmxMorphVertexOffset::Read(std::istream *stream, PmxSetting *setting)
{
this->vertex_index = ReadIndex(stream, setting->vertex_index_size);
stream->read((char*)this->position_offset, sizeof(float) * 3);
}
void PmxMorphUVOffset::Read(std::istream *stream, PmxSetting *setting)
{
this->vertex_index = ReadIndex(stream, setting->vertex_index_size);
stream->read((char*)this->uv_offset, sizeof(float) * 4);
}
void PmxMorphBoneOffset::Read(std::istream *stream, PmxSetting *setting)
{
this->bone_index = ReadIndex(stream, setting->bone_index_size);
stream->read((char*)this->translation, sizeof(float) * 3);
stream->read((char*)this->rotation, sizeof(float) * 4);
}
void PmxMorphMaterialOffset::Read(std::istream *stream, PmxSetting *setting)
{
this->material_index = ReadIndex(stream, setting->material_index_size);
stream->read((char*) &this->offset_operation, sizeof(uint8_t));
stream->read((char*)this->diffuse, sizeof(float) * 4);
stream->read((char*)this->specular, sizeof(float) * 3);
stream->read((char*) &this->specularity, sizeof(float));
stream->read((char*)this->ambient, sizeof(float) * 3);
stream->read((char*)this->edge_color, sizeof(float) * 4);
stream->read((char*) &this->edge_size, sizeof(float));
stream->read((char*)this->texture_argb, sizeof(float) * 4);
stream->read((char*)this->sphere_texture_argb, sizeof(float) * 4);
stream->read((char*)this->toon_texture_argb, sizeof(float) * 4);
}
void PmxMorphGroupOffset::Read(std::istream *stream, PmxSetting *setting)
{
this->morph_index = ReadIndex(stream, setting->morph_index_size);
stream->read((char*) &this->morph_weight, sizeof(float));
}
void PmxMorphFlipOffset::Read(std::istream *stream, PmxSetting *setting)
{
this->morph_index = ReadIndex(stream, setting->morph_index_size);
stream->read((char*) &this->morph_value, sizeof(float));
}
void PmxMorphImplusOffset::Read(std::istream *stream, PmxSetting *setting)
{
this->rigid_body_index = ReadIndex(stream, setting->rigidbody_index_size);
stream->read((char*) &this->is_local, sizeof(uint8_t));
stream->read((char*)this->velocity, sizeof(float) * 3);
stream->read((char*)this->angular_torque, sizeof(float) * 3);
}
void PmxMorph::Read(std::istream *stream, PmxSetting *setting)
{
this->morph_name = ReadString(stream, setting->encoding);
this->morph_english_name = ReadString(stream, setting->encoding);
stream->read((char*) &category, sizeof(MorphCategory));
stream->read((char*) &morph_type, sizeof(MorphType));
stream->read((char*) &this->offset_count, sizeof(int));
switch (this->morph_type)
{
case MorphType::Group:
group_offsets = std::make_unique<PmxMorphGroupOffset []>(this->offset_count);
for (int i = 0; i < offset_count; i++)
{
group_offsets[i].Read(stream, setting);
}
break;
case MorphType::Vertex:
vertex_offsets = std::make_unique<PmxMorphVertexOffset []>(this->offset_count);
for (int i = 0; i < offset_count; i++)
{
vertex_offsets[i].Read(stream, setting);
}
break;
case MorphType::Bone:
bone_offsets = std::make_unique<PmxMorphBoneOffset []>(this->offset_count);
for (int i = 0; i < offset_count; i++)
{
bone_offsets[i].Read(stream, setting);
}
break;
case MorphType::Matrial:
material_offsets = std::make_unique<PmxMorphMaterialOffset []>(this->offset_count);
for (int i = 0; i < offset_count; i++)
{
material_offsets[i].Read(stream, setting);
}
break;
case MorphType::UV:
case MorphType::AdditionalUV1:
case MorphType::AdditionalUV2:
case MorphType::AdditionalUV3:
case MorphType::AdditionalUV4:
uv_offsets = std::make_unique<PmxMorphUVOffset []>(this->offset_count);
for (int i = 0; i < offset_count; i++)
{
uv_offsets[i].Read(stream, setting);
}
break;
default:
throw;
}
}
void PmxFrameElement::Read(std::istream *stream, PmxSetting *setting)
{
stream->read((char*) &this->element_target, sizeof(uint8_t));
if (this->element_target == 0x00)
{
this->index = ReadIndex(stream, setting->bone_index_size);
}
else {
this->index = ReadIndex(stream, setting->morph_index_size);
}
}
void PmxFrame::Read(std::istream *stream, PmxSetting *setting)
{
this->frame_name = ReadString(stream, setting->encoding);
this->frame_english_name = ReadString(stream, setting->encoding);
stream->read((char*) &this->frame_flag, sizeof(uint8_t));
stream->read((char*) &this->element_count, sizeof(int));
this->elements = std::make_unique<PmxFrameElement []>(this->element_count);
for (int i = 0; i < this->element_count; i++)
{
this->elements[i].Read(stream, setting);
}
}
void PmxRigidBody::Read(std::istream *stream, PmxSetting *setting)
{
this->girid_body_name = ReadString(stream, setting->encoding);
this->girid_body_english_name = ReadString(stream, setting->encoding);
this->target_bone = ReadIndex(stream, setting->bone_index_size);
stream->read((char*) &this->group, sizeof(uint8_t));
stream->read((char*) &this->mask, sizeof(uint16_t));
stream->read((char*) &this->shape, sizeof(uint8_t));
stream->read((char*) this->size, sizeof(float) * 3);
stream->read((char*) this->position, sizeof(float) * 3);
stream->read((char*) this->orientation, sizeof(float) * 3);
stream->read((char*) &this->mass, sizeof(float));
stream->read((char*) &this->move_attenuation, sizeof(float));
stream->read((char*) &this->rotation_attenuation, sizeof(float));
stream->read((char*) &this->repulsion, sizeof(float));
stream->read((char*) &this->friction, sizeof(float));
stream->read((char*) &this->physics_calc_type, sizeof(uint8_t));
}
void PmxJointParam::Read(std::istream *stream, PmxSetting *setting)
{
this->rigid_body1 = ReadIndex(stream, setting->rigidbody_index_size);
this->rigid_body2 = ReadIndex(stream, setting->rigidbody_index_size);
stream->read((char*) this->position, sizeof(float) * 3);
stream->read((char*) this->orientaiton, sizeof(float) * 3);
stream->read((char*) this->move_limitation_min, sizeof(float) * 3);
stream->read((char*) this->move_limitation_max, sizeof(float) * 3);
stream->read((char*) this->rotation_limitation_min, sizeof(float) * 3);
stream->read((char*) this->rotation_limitation_max, sizeof(float) * 3);
stream->read((char*) this->spring_move_coefficient, sizeof(float) * 3);
stream->read((char*) this->spring_rotation_coefficient, sizeof(float) * 3);
}
void PmxJoint::Read(std::istream *stream, PmxSetting *setting)
{
this->joint_name = ReadString(stream, setting->encoding);
this->joint_english_name = ReadString(stream, setting->encoding);
stream->read((char*) &this->joint_type, sizeof(uint8_t));
this->param.Read(stream, setting);
}
void PmxAncherRigidBody::Read(std::istream *stream, PmxSetting *setting)
{
this->related_rigid_body = ReadIndex(stream, setting->rigidbody_index_size);
this->related_vertex = ReadIndex(stream, setting->vertex_index_size);
stream->read((char*) &this->is_near, sizeof(uint8_t));
}
void PmxSoftBody::Read(std::istream *stream, PmxSetting *setting)
{
// 未実装
std::cerr << "Not Implemented Exception" << std::endl;
throw;
}
void PmxModel::Init()
{
this->version = 0.0f;
this->model_name.clear();
this->model_english_name.clear();
this->model_comment.clear();
this->model_english_comment.clear();
this->vertex_count = 0;
this->vertices = nullptr;
this->index_count = 0;
this->indices = nullptr;
this->texture_count = 0;
this->textures = nullptr;
this->material_count = 0;
this->materials = nullptr;
this->bone_count = 0;
this->bones = nullptr;
this->morph_count = 0;
this->morphs = nullptr;
this->frame_count = 0;
this->frames = nullptr;
this->rigid_body_count = 0;
this->rigid_bodies = nullptr;
this->joint_count = 0;
this->joints = nullptr;
this->soft_body_count = 0;
this->soft_bodies = nullptr;
}
void PmxModel::Read(std::istream *stream)
{
// マジック
char magic[4];
stream->read((char*) magic, sizeof(char) * 4);
if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20)
{
std::cerr << "invalid magic number." << std::endl;
throw;
}
// バージョン
stream->read((char*) &version, sizeof(float));
if (version != 2.0f && version != 2.1f)
{
std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
throw;
}
// ファイル設定
this->setting.Read(stream);
// モデル情報
this->model_name = std::move(ReadString(stream, setting.encoding));
this->model_english_name = std::move(ReadString(stream, setting.encoding));
this->model_comment = std::move(ReadString(stream, setting.encoding));
this->model_english_comment = std::move(ReadString(stream, setting.encoding));
// 頂点
stream->read((char*) &vertex_count, sizeof(int));
this->vertices = std::make_unique<PmxVertex []>(vertex_count);
for (int i = 0; i < vertex_count; i++)
{
vertices[i].Read(stream, &setting);
}
// 面
stream->read((char*) &index_count, sizeof(int));
this->indices = std::make_unique<int []>(index_count);
for (int i = 0; i < index_count; i++)
{
this->indices[i] = ReadIndex(stream, setting.vertex_index_size);
}
// テクスチャ
stream->read((char*) &texture_count, sizeof(int));
this->textures = std::make_unique<utfstring []>(texture_count);
for (int i = 0; i < texture_count; i++)
{
this->textures[i] = ReadString(stream, setting.encoding);
}
// マテリアル
stream->read((char*) &material_count, sizeof(int));
this->materials = std::make_unique<PmxMaterial []>(material_count);
for (int i = 0; i < material_count; i++)
{
this->materials[i].Read(stream, &setting);
}
// ボーン
stream->read((char*) &this->bone_count, sizeof(int));
this->bones = std::make_unique<PmxBone []>(this->bone_count);
for (int i = 0; i < this->bone_count; i++)
{
this->bones[i].Read(stream, &setting);
}
// モーフ
stream->read((char*) &this->morph_count, sizeof(int));
this->morphs = std::make_unique<PmxMorph []>(this->morph_count);
for (int i = 0; i < this->morph_count; i++)
{
this->morphs[i].Read(stream, &setting);
}
// 表示枠
stream->read((char*) &this->frame_count, sizeof(int));
this->frames = std::make_unique<PmxFrame []>(this->frame_count);
for (int i = 0; i < this->frame_count; i++)
{
this->frames[i].Read(stream, &setting);
}
// 剛体
stream->read((char*) &this->rigid_body_count, sizeof(int));
this->rigid_bodies = std::make_unique<PmxRigidBody []>(this->rigid_body_count);
for (int i = 0; i < this->rigid_body_count; i++)
{
this->rigid_bodies[i].Read(stream, &setting);
}
// ジョイント
stream->read((char*) &this->joint_count, sizeof(int));
this->joints = std::make_unique<PmxJoint []>(this->joint_count);
for (int i = 0; i < this->joint_count; i++)
{
this->joints[i].Read(stream, &setting);
}
//// ソフトボディ
//if (this->version == 2.1f)
//{
// stream->read((char*) &this->soft_body_count, sizeof(int));
// this->soft_bodies = std::make_unique<PmxSoftBody []>(this->soft_body_count);
// for (int i = 0; i < this->soft_body_count; i++)
// {
// this->soft_bodies[i].Read(stream, &setting);
// }
//}
}
//std::unique_ptr<PmxModel> ReadFromFile(const char *filename)
//{
// auto stream = std::ifstream(filename, std::ios_base::binary);
// auto pmx = PmxModel::ReadFromStream(&stream);
// if (!stream.eof())
// {
// std::cerr << "don't reach the end of file." << std::endl;
// }
// stream.close();
// return pmx;
//}
//std::unique_ptr<PmxModel> ReadFromStream(std::istream *stream)
//{
// auto pmx = std::make_unique<PmxModel>();
// pmx->Read(stream);
// return pmx;
//}
}

865
code/MMDPmxParser.h 100644
View File

@ -0,0 +1,865 @@
#pragma once
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <memory>
#include "MMDCpp14.h"
namespace pmx
{
#ifndef __unix__
#define utfstring std::wstring
#else
#define utfstring std::string
#endif
/// インデックス設定
class PmxSetting
{
public:
PmxSetting()
: encoding(0)
, uv(0)
, vertex_index_size(0)
, texture_index_size(0)
, material_index_size(0)
, bone_index_size(0)
, morph_index_size(0)
, rigidbody_index_size(0)
{}
/// エンコード方式
uint8_t encoding;
/// 追加UV数
uint8_t uv;
/// 頂点インデックスサイズ
uint8_t vertex_index_size;
/// テクスチャインデックスサイズ
uint8_t texture_index_size;
/// マテリアルインデックスサイズ
uint8_t material_index_size;
/// ボーンインデックスサイズ
uint8_t bone_index_size;
/// モーフインデックスサイズ
uint8_t morph_index_size;
/// 剛体インデックスサイズ
uint8_t rigidbody_index_size;
void Read(std::istream *stream);
};
/// 頂点スキニングタイプ
enum class PmxVertexSkinningType : uint8_t
{
BDEF1 = 0,
BDEF2 = 1,
BDEF4 = 2,
SDEF = 3,
QDEF = 4,
};
/// 頂点スキニング
class PmxVertexSkinning
{
public:
virtual void Read(std::istream *stream, PmxSetting *setting) = 0;
};
class PmxVertexSkinningBDEF1 : public PmxVertexSkinning
{
public:
PmxVertexSkinningBDEF1()
: bone_index(0)
{}
int bone_index;
void Read(std::istream *stresam, PmxSetting *setting);
};
class PmxVertexSkinningBDEF2 : public PmxVertexSkinning
{
public:
PmxVertexSkinningBDEF2()
: bone_index1(0)
, bone_index2(0)
, bone_weight(0.0f)
{}
int bone_index1;
int bone_index2;
float bone_weight;
void Read(std::istream *stresam, PmxSetting *setting);
};
class PmxVertexSkinningBDEF4 : public PmxVertexSkinning
{
public:
PmxVertexSkinningBDEF4()
: bone_index1(0)
, bone_index2(0)
, bone_index3(0)
, bone_index4(0)
, bone_weight1(0.0f)
, bone_weight2(0.0f)
, bone_weight3(0.0f)
, bone_weight4(0.0f)
{}
int bone_index1;
int bone_index2;
int bone_index3;
int bone_index4;
float bone_weight1;
float bone_weight2;
float bone_weight3;
float bone_weight4;
void Read(std::istream *stresam, PmxSetting *setting);
};
class PmxVertexSkinningSDEF : public PmxVertexSkinning
{
public:
PmxVertexSkinningSDEF()
: bone_index1(0)
, bone_index2(0)
, bone_weight(0.0f)
{
for (int i = 0; i < 3; ++i) {
sdef_c[i] = 0.0f;
sdef_r0[i] = 0.0f;
sdef_r1[i] = 0.0f;
}
}
int bone_index1;
int bone_index2;
float bone_weight;
float sdef_c[3];
float sdef_r0[3];
float sdef_r1[3];
void Read(std::istream *stresam, PmxSetting *setting);
};
class PmxVertexSkinningQDEF : public PmxVertexSkinning
{
public:
PmxVertexSkinningQDEF()
: bone_index1(0)
, bone_index2(0)
, bone_index3(0)
, bone_index4(0)
, bone_weight1(0.0f)
, bone_weight2(0.0f)
, bone_weight3(0.0f)
, bone_weight4(0.0f)
{}
int bone_index1;
int bone_index2;
int bone_index3;
int bone_index4;
float bone_weight1;
float bone_weight2;
float bone_weight3;
float bone_weight4;
void Read(std::istream *stresam, PmxSetting *setting);
};
/// 頂点
class PmxVertex
{
public:
PmxVertex()
: edge(0.0f)
{
uv[0] = uv[1] = 0.0f;
for (int i = 0; i < 3; ++i) {
positon[i] = 0.0f;
normal[i] = 0.0f;
}
for (int i = 0; i < 4; ++i) {
for (int k = 0; k < 4; ++k) {
uva[i][k] = 0.0f;
}
}
}
/// 位置
float positon[3];
/// 法線
float normal[3];
/// テクスチャ座標
float uv[2];
/// 追加テクスチャ座標
float uva[4][4];
/// スキニングタイプ
PmxVertexSkinningType skinning_type;
/// スキニング
std::unique_ptr<PmxVertexSkinning> skinning;
/// エッジ倍率
float edge;
void Read(std::istream *stream, PmxSetting *setting);
};
/// マテリアル
class PmxMaterial
{
public:
PmxMaterial()
: specularlity(0.0f)
, flag(0)
, edge_size(0.0f)
, diffuse_texture_index(0)
, sphere_texture_index(0)
, sphere_op_mode(0)
, common_toon_flag(0)
, toon_texture_index(0)
, index_count(0)
{
for (int i = 0; i < 3; ++i) {
specular[i] = 0.0f;
ambient[i] = 0.0f;
edge_color[i] = 0.0f;
}
for (int i = 0; i < 4; ++i) {
diffuse[i] = 0.0f;
}
}
/// モデル名
utfstring material_name;
/// モデル英名
utfstring material_english_name;
/// 減衰色
float diffuse[4];
/// 光沢色
float specular[3];
/// 光沢度
float specularlity;
/// 環境色
float ambient[3];
/// 描画フラグ
uint8_t flag;
/// エッジ色
float edge_color[4];
/// エッジサイズ
float edge_size;
/// アルベドテクスチャインデックス
int diffuse_texture_index;
/// スフィアテクスチャインデックス
int sphere_texture_index;
/// スフィアテクスチャ演算モード
uint8_t sphere_op_mode;
/// 共有トゥーンフラグ
uint8_t common_toon_flag;
/// トゥーンテクスチャインデックス
int toon_texture_index;
/// メモ
utfstring memo;
/// 頂点インデックス数
int index_count;
void Read(std::istream *stream, PmxSetting *setting);
};
/// リンク
class PmxIkLink
{
public:
PmxIkLink()
: link_target(0)
, angle_lock(0)
{
for (int i = 0; i < 3; ++i) {
max_radian[i] = 0.0f;
min_radian[i] = 0.0f;
}
}
/// リンクボーンインデックス
int link_target;
/// 角度制限
uint8_t angle_lock;
/// 最大制限角度
float max_radian[3];
/// 最小制限角度
float min_radian[3];
void Read(std::istream *stream, PmxSetting *settingn);
};
/// ボーン
class PmxBone
{
public:
PmxBone()
: parent_index(0)
, level(0)
, bone_flag(0)
, target_index(0)
, grant_parent_index(0)
, grant_weight(0.0f)
, key(0)
, ik_target_bone_index(0)
, ik_loop(0)
, ik_loop_angle_limit(0.0f)
, ik_link_count(0)
{
for (int i = 0; i < 3; ++i) {
position[i] = 0.0f;
offset[i] = 0.0f;
lock_axis_orientation[i] = 0.0f;
local_axis_x_orientation[i] = 0.0f;
local_axis_y_orientation[i] = 0.0f;
}
}
/// ボーン名
utfstring bone_name;
/// ボーン英名
utfstring bone_english_name;
/// 位置
float position[3];
/// 親ボーンインデックス
int parent_index;
/// 階層
int level;
/// ボーンフラグ
uint16_t bone_flag;
/// 座標オフセット(has Target)
float offset[3];
/// 接続先ボーンインデックス(not has Target)
int target_index;
/// 付与親ボーンインデックス
int grant_parent_index;
/// 付与率
float grant_weight;
/// 固定軸の方向
float lock_axis_orientation[3];
/// ローカル軸のX軸方向
float local_axis_x_orientation[3];
/// ローカル軸のY軸方向
float local_axis_y_orientation[3];
/// 外部親変形のkey値
int key;
/// IKターゲットボーン
int ik_target_bone_index;
/// IKループ回数
int ik_loop;
/// IKループ計算時の角度制限(ラジアン)
float ik_loop_angle_limit;
/// IKリンク数
int ik_link_count;
/// IKリンク
std::unique_ptr<PmxIkLink []> ik_links;
void Read(std::istream *stream, PmxSetting *setting);
};
enum class MorphType : uint8_t
{
Group = 0,
Vertex = 1,
Bone = 2,
UV = 3,
AdditionalUV1 = 4,
AdditionalUV2 = 5,
AdditionalUV3 = 6,
AdditionalUV4 = 7,
Matrial = 8,
Flip = 9,
Implus = 10,
};
enum class MorphCategory : uint8_t
{
ReservedCategory = 0,
Eyebrow = 1,
Eye = 2,
Mouth = 3,
Other = 4,
};
class PmxMorphOffset
{
public:
void virtual Read(std::istream *stream, PmxSetting *setting) = 0;
};
class PmxMorphVertexOffset : public PmxMorphOffset
{
public:
PmxMorphVertexOffset()
: vertex_index(0)
{
for (int i = 0; i < 3; ++i) {
position_offset[i] = 0.0f;
}
}
int vertex_index;
float position_offset[3];
void Read(std::istream *stream, PmxSetting *setting) override;
};
class PmxMorphUVOffset : public PmxMorphOffset
{
public:
PmxMorphUVOffset()
: vertex_index(0)
{
for (int i = 0; i < 4; ++i) {
uv_offset[i] = 0.0f;
}
}
int vertex_index;
float uv_offset[4];
void Read(std::istream *stream, PmxSetting *setting) override;
};
class PmxMorphBoneOffset : public PmxMorphOffset
{
public:
PmxMorphBoneOffset()
: bone_index(0)
{
for (int i = 0; i < 3; ++i) {
translation[i] = 0.0f;
}
for (int i = 0; i < 4; ++i) {
rotation[i] = 0.0f;
}
}
int bone_index;
float translation[3];
float rotation[4];
void Read(std::istream *stream, PmxSetting *setting) override;
};
class PmxMorphMaterialOffset : public PmxMorphOffset
{
public:
PmxMorphMaterialOffset()
: specularity(0.0f)
, edge_size(0.0f)
{
for (int i = 0; i < 3; ++i) {
specular[i] = 0.0f;
ambient[i] = 0.0f;
}
for (int i = 0; i < 4; ++i) {
diffuse[i] = 0.0f;
edge_color[i] = 0.0f;
texture_argb[i] = 0.0f;
sphere_texture_argb[i] = 0.0f;
toon_texture_argb[i] = 0.0f;
}
}
int material_index;
uint8_t offset_operation;
float diffuse[4];
float specular[3];
float specularity;
float ambient[3];
float edge_color[4];
float edge_size;
float texture_argb[4];
float sphere_texture_argb[4];
float toon_texture_argb[4];
void Read(std::istream *stream, PmxSetting *setting) override;
};
class PmxMorphGroupOffset : public PmxMorphOffset
{
public:
PmxMorphGroupOffset()
: morph_index(0)
, morph_weight(0.0f)
{}
int morph_index;
float morph_weight;
void Read(std::istream *stream, PmxSetting *setting) override;
};
class PmxMorphFlipOffset : public PmxMorphOffset
{
public:
PmxMorphFlipOffset()
: morph_index(0)
, morph_value(0.0f)
{}
int morph_index;
float morph_value;
void Read(std::istream *stream, PmxSetting *setting) override;
};
class PmxMorphImplusOffset : public PmxMorphOffset
{
public:
PmxMorphImplusOffset()
: rigid_body_index(0)
, is_local(0)
{
for (int i = 0; i < 3; ++i) {
velocity[i] = 0.0f;
angular_torque[i] = 0.0f;
}
}
int rigid_body_index;
uint8_t is_local;
float velocity[3];
float angular_torque[3];
void Read(std::istream *stream, PmxSetting *setting) override;
};
/// モーフ
class PmxMorph
{
public:
PmxMorph()
: offset_count(0)
{
}
/// モーフ名
utfstring morph_name;
/// モーフ英名
utfstring morph_english_name;
/// カテゴリ
MorphCategory category;
/// モーフタイプ
MorphType morph_type;
/// オフセット数
int offset_count;
/// 頂点モーフ配列
std::unique_ptr<PmxMorphVertexOffset []> vertex_offsets;
/// UVモーフ配列
std::unique_ptr<PmxMorphUVOffset []> uv_offsets;
/// ボーンモーフ配列
std::unique_ptr<PmxMorphBoneOffset []> bone_offsets;
/// マテリアルモーフ配列
std::unique_ptr<PmxMorphMaterialOffset []> material_offsets;
/// グループモーフ配列
std::unique_ptr<PmxMorphGroupOffset []> group_offsets;
/// フリップモーフ配列
std::unique_ptr<PmxMorphFlipOffset []> flip_offsets;
/// インパルスモーフ配列
std::unique_ptr<PmxMorphImplusOffset []> implus_offsets;
void Read(std::istream *stream, PmxSetting *setting);
};
/// 枠内要素
class PmxFrameElement
{
public:
PmxFrameElement()
: element_target(0)
, index(0)
{
}
/// 要素対象
uint8_t element_target;
/// 要素対象インデックス
int index;
void Read(std::istream *stream, PmxSetting *setting);
};
/// 表示枠
class PmxFrame
{
public:
PmxFrame()
: frame_flag(0)
, element_count(0)
{
}
/// 枠名
utfstring frame_name;
/// 枠英名
utfstring frame_english_name;
/// 特殊枠フラグ
uint8_t frame_flag;
/// 枠内要素数
int element_count;
/// 枠内要素配列
std::unique_ptr<PmxFrameElement []> elements;
void Read(std::istream *stream, PmxSetting *setting);
};
class PmxRigidBody
{
public:
PmxRigidBody()
: target_bone(0)
, group(0)
, mask(0)
, shape(0)
, mass(0.0f)
, move_attenuation(0.0f)
, rotation_attenuation(0.0f)
, repulsion(0.0f)
, friction(0.0f)
, physics_calc_type(0)
{
for (int i = 0; i < 3; ++i) {
size[i] = 0.0f;
position[i] = 0.0f;
orientation[i] = 0.0f;
}
}
/// 剛体名
utfstring girid_body_name;
/// 剛体英名
utfstring girid_body_english_name;
/// 関連ボーンインデックス
int target_bone;
/// グループ
uint8_t group;
/// マスク
uint16_t mask;
/// 形状
uint8_t shape;
float size[3];
float position[3];
float orientation[3];
float mass;
float move_attenuation;
float rotation_attenuation;
float repulsion;
float friction;
uint8_t physics_calc_type;
void Read(std::istream *stream, PmxSetting *setting);
};
enum class PmxJointType : uint8_t
{
Generic6DofSpring = 0,
Generic6Dof = 1,
Point2Point = 2,
ConeTwist = 3,
Slider = 5,
Hinge = 6
};
class PmxJointParam
{
public:
PmxJointParam()
: rigid_body1(0)
, rigid_body2(0)
{
for (int i = 0; i < 3; ++i) {
position[i] = 0.0f;
orientaiton[i] = 0.0f;
move_limitation_min[i] = 0.0f;
move_limitation_max[i] = 0.0f;
rotation_limitation_min[i] = 0.0f;
rotation_limitation_max[i] = 0.0f;
spring_move_coefficient[i] = 0.0f;
spring_rotation_coefficient[i] = 0.0f;
}
}
int rigid_body1;
int rigid_body2;
float position[3];
float orientaiton[3];
float move_limitation_min[3];
float move_limitation_max[3];
float rotation_limitation_min[3];
float rotation_limitation_max[3];
float spring_move_coefficient[3];
float spring_rotation_coefficient[3];
void Read(std::istream *stream, PmxSetting *setting);
};
class PmxJoint
{
public:
utfstring joint_name;
utfstring joint_english_name;
PmxJointType joint_type;
PmxJointParam param;
void Read(std::istream *stream, PmxSetting *setting);
};
enum PmxSoftBodyFlag : uint8_t
{
BLink = 0x01,
Cluster = 0x02,
Link = 0x04
};
class PmxAncherRigidBody
{
public:
PmxAncherRigidBody()
: related_rigid_body(0)
, related_vertex(0)
, is_near(false)
{}
int related_rigid_body;
int related_vertex;
bool is_near;
void Read(std::istream *stream, PmxSetting *setting);
};
class PmxSoftBody
{
public:
PmxSoftBody()
: shape(0)
, target_material(0)
, group(0)
, mask(0)
, blink_distance(0)
, cluster_count(0)
, mass(0.0)
, collisioni_margin(0.0)
, aero_model(0)
, VCF(0.0f)
, DP(0.0f)
, DG(0.0f)
, LF(0.0f)
, PR(0.0f)
, VC(0.0f)
, DF(0.0f)
, MT(0.0f)
, CHR(0.0f)
, KHR(0.0f)
, SHR(0.0f)
, AHR(0.0f)
, SRHR_CL(0.0f)
, SKHR_CL(0.0f)
, SSHR_CL(0.0f)
, SR_SPLT_CL(0.0f)
, SK_SPLT_CL(0.0f)
, SS_SPLT_CL(0.0f)
, V_IT(0)
, P_IT(0)
, D_IT(0)
, C_IT(0)
, LST(0.0f)
, AST(0.0f)
, VST(0.0f)
, anchor_count(0)
, pin_vertex_count(0)
{}
utfstring soft_body_name;
utfstring soft_body_english_name;
uint8_t shape;
int target_material;
uint8_t group;
uint16_t mask;
PmxSoftBodyFlag flag;
int blink_distance;
int cluster_count;
float mass;
float collisioni_margin;
int aero_model;
float VCF;
float DP;
float DG;
float LF;
float PR;
float VC;
float DF;
float MT;
float CHR;
float KHR;
float SHR;
float AHR;
float SRHR_CL;
float SKHR_CL;
float SSHR_CL;
float SR_SPLT_CL;
float SK_SPLT_CL;
float SS_SPLT_CL;
int V_IT;
int P_IT;
int D_IT;
int C_IT;
float LST;
float AST;
float VST;
int anchor_count;
std::unique_ptr<PmxAncherRigidBody []> anchers;
int pin_vertex_count;
std::unique_ptr<int []> pin_vertices;
void Read(std::istream *stream, PmxSetting *setting);
};
/// PMXモデル
class PmxModel
{
public:
PmxModel()
: version(0.0f)
, vertex_count(0)
, index_count(0)
, texture_count(0)
, material_count(0)
, bone_count(0)
, morph_count(0)
, frame_count(0)
, rigid_body_count(0)
, joint_count(0)
, soft_body_count(0)
{}
/// バージョン
float version;
/// 設定
PmxSetting setting;
/// モデル名
utfstring model_name;
/// モデル英名
utfstring model_english_name;
/// コメント
utfstring model_comment;
/// 英語コメント
utfstring model_english_comment;
/// 頂点数
int vertex_count;
/// 頂点配列
std::unique_ptr<PmxVertex []> vertices;
/// インデックス数
int index_count;
/// インデックス配列
std::unique_ptr<int []> indices;
/// テクスチャ数
int texture_count;
/// テクスチャ配列
std::unique_ptr< utfstring []> textures;
/// マテリアル数
int material_count;
/// マテリアル
std::unique_ptr<PmxMaterial []> materials;
/// ボーン数
int bone_count;
/// ボーン配列
std::unique_ptr<PmxBone []> bones;
/// モーフ数
int morph_count;
/// モーフ配列
std::unique_ptr<PmxMorph []> morphs;
/// 表示枠数
int frame_count;
/// 表示枠配列
std::unique_ptr<PmxFrame [] > frames;
/// 剛体数
int rigid_body_count;
/// 剛体配列
std::unique_ptr<PmxRigidBody []> rigid_bodies;
/// ジョイント数
int joint_count;
/// ジョイント配列
std::unique_ptr<PmxJoint []> joints;
/// ソフトボディ数
int soft_body_count;
/// ソフトボディ配列
std::unique_ptr<PmxSoftBody []> soft_bodies;
/// モデル初期化
void Init();
/// モデル読み込み
void Read(std::istream *stream);
///// ファイルからモデルの読み込み
//static std::unique_ptr<PmxModel> ReadFromFile(const char *filename);
///// 入力ストリームからモデルの読み込み
//static std::unique_ptr<PmxModel> ReadFromStream(std::istream *stream);
};
}

367
code/MMDVmdParser.h 100644
View File

@ -0,0 +1,367 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <iostream>
#include <fstream>
#include <ostream>
#include "MMDCpp14.h"
namespace vmd
{
/// ボーンフレーム
class VmdBoneFrame
{
public:
/// ボーン名
std::string name;
/// フレーム番号
int frame;
/// 位置
float position[3];
/// 回転
float orientation[4];
/// 補間曲線
char interpolation[4][4][4];
void Read(std::istream* stream)
{
char buffer[15];
stream->read((char*) buffer, sizeof(char)*15);
name = std::string(buffer);
stream->read((char*) &frame, sizeof(int));
stream->read((char*) position, sizeof(float)*3);
stream->read((char*) orientation, sizeof(float)*4);
stream->read((char*) interpolation, sizeof(char) * 4 * 4 * 4);
}
void Write(std::ostream* stream)
{
stream->write((char*)name.c_str(), sizeof(char) * 15);
stream->write((char*)&frame, sizeof(int));
stream->write((char*)position, sizeof(float) * 3);
stream->write((char*)orientation, sizeof(float) * 4);
stream->write((char*)interpolation, sizeof(char) * 4 * 4 * 4);
}
};
/// 表情フレーム
class VmdFaceFrame
{
public:
/// 表情名
std::string face_name;
/// 表情の重み
float weight;
/// フレーム番号
uint32_t frame;
void Read(std::istream* stream)
{
char buffer[15];
stream->read((char*) &buffer, sizeof(char) * 15);
face_name = std::string(buffer);
stream->read((char*) &frame, sizeof(int));
stream->read((char*) &weight, sizeof(float));
}
void Write(std::ostream* stream)
{
stream->write((char*)face_name.c_str(), sizeof(char) * 15);
stream->write((char*)&frame, sizeof(int));
stream->write((char*)&weight, sizeof(float));
}
};
/// カメラフレーム
class VmdCameraFrame
{
public:
/// フレーム番号
int frame;
/// 距離
float distance;
/// 位置
float position[3];
/// 回転
float orientation[3];
/// 補間曲線
char interpolation[6][4];
/// 視野角
float angle;
/// 不明データ
char unknown[3];
void Read(std::istream *stream)
{
stream->read((char*) &frame, sizeof(int));
stream->read((char*) &distance, sizeof(float));
stream->read((char*) position, sizeof(float) * 3);
stream->read((char*) orientation, sizeof(float) * 3);
stream->read((char*) interpolation, sizeof(char) * 24);
stream->read((char*) &angle, sizeof(float));
stream->read((char*) unknown, sizeof(char) * 3);
}
void Write(std::ostream *stream)
{
stream->write((char*)&frame, sizeof(int));
stream->write((char*)&distance, sizeof(float));
stream->write((char*)position, sizeof(float) * 3);
stream->write((char*)orientation, sizeof(float) * 3);
stream->write((char*)interpolation, sizeof(char) * 24);
stream->write((char*)&angle, sizeof(float));
stream->write((char*)unknown, sizeof(char) * 3);
}
};
/// ライトフレーム
class VmdLightFrame
{
public:
/// フレーム番号
int frame;
/// 色
float color[3];
/// 位置
float position[3];
void Read(std::istream* stream)
{
stream->read((char*) &frame, sizeof(int));
stream->read((char*) color, sizeof(float) * 3);
stream->read((char*) position, sizeof(float) * 3);
}
void Write(std::ostream* stream)
{
stream->write((char*)&frame, sizeof(int));
stream->write((char*)color, sizeof(float) * 3);
stream->write((char*)position, sizeof(float) * 3);
}
};
/// IKの有効無効
class VmdIkEnable
{
public:
std::string ik_name;
bool enable;
};
/// IKフレーム
class VmdIkFrame
{
public:
int frame;
bool display;
std::vector<VmdIkEnable> ik_enable;
void Read(std::istream *stream)
{
char buffer[20];
stream->read((char*) &frame, sizeof(int));
stream->read((char*) &display, sizeof(uint8_t));
int ik_count;
stream->read((char*) &ik_count, sizeof(int));
ik_enable.resize(ik_count);
for (int i = 0; i < ik_count; i++)
{
stream->read(buffer, 20);
ik_enable[i].ik_name = std::string(buffer);
stream->read((char*) &ik_enable[i].enable, sizeof(uint8_t));
}
}
void Write(std::ostream *stream)
{
stream->write((char*)&frame, sizeof(int));
stream->write((char*)&display, sizeof(uint8_t));
int ik_count = static_cast<int>(ik_enable.size());
stream->write((char*)&ik_count, sizeof(int));
for (int i = 0; i < ik_count; i++)
{
const VmdIkEnable& ik_enable = this->ik_enable.at(i);
stream->write(ik_enable.ik_name.c_str(), 20);
stream->write((char*)&ik_enable.enable, sizeof(uint8_t));
}
}
};
/// VMDモーション
class VmdMotion
{
public:
/// モデル名
std::string model_name;
/// バージョン
int version;
/// ボーンフレーム
std::vector<VmdBoneFrame> bone_frames;
/// 表情フレーム
std::vector<VmdFaceFrame> face_frames;
/// カメラフレーム
std::vector<VmdCameraFrame> camera_frames;
/// ライトフレーム
std::vector<VmdLightFrame> light_frames;
/// IKフレーム
std::vector<VmdIkFrame> ik_frames;
static std::unique_ptr<VmdMotion> LoadFromFile(char const *filename)
{
std::ifstream stream(filename, std::ios::binary);
auto result = LoadFromStream(&stream);
stream.close();
return result;
}
static std::unique_ptr<VmdMotion> LoadFromStream(std::ifstream *stream)
{
char buffer[30];
auto result = std::make_unique<VmdMotion>();
// magic and version
stream->read((char*) buffer, 30);
if (strncmp(buffer, "Vocaloid Motion Data", 20))
{
std::cerr << "invalid vmd file." << std::endl;
return nullptr;
}
result->version = std::atoi(buffer + 20);
// name
stream->read(buffer, 20);
result->model_name = std::string(buffer);
// bone frames
int bone_frame_num;
stream->read((char*) &bone_frame_num, sizeof(int));
result->bone_frames.resize(bone_frame_num);
for (int i = 0; i < bone_frame_num; i++)
{
result->bone_frames[i].Read(stream);
}
// face frames
int face_frame_num;
stream->read((char*) &face_frame_num, sizeof(int));
result->face_frames.resize(face_frame_num);
for (int i = 0; i < face_frame_num; i++)
{
result->face_frames[i].Read(stream);
}
// camera frames
int camera_frame_num;
stream->read((char*) &camera_frame_num, sizeof(int));
result->camera_frames.resize(camera_frame_num);
for (int i = 0; i < camera_frame_num; i++)
{
result->camera_frames[i].Read(stream);
}
// light frames
int light_frame_num;
stream->read((char*) &light_frame_num, sizeof(int));
result->light_frames.resize(light_frame_num);
for (int i = 0; i < light_frame_num; i++)
{
result->light_frames[i].Read(stream);
}
// unknown2
stream->read(buffer, 4);
// ik frames
if (stream->peek() != std::ios::traits_type::eof())
{
int ik_num;
stream->read((char*) &ik_num, sizeof(int));
result->ik_frames.resize(ik_num);
for (int i = 0; i < ik_num; i++)
{
result->ik_frames[i].Read(stream);
}
}
if (stream->peek() != std::ios::traits_type::eof())
{
std::cerr << "vmd stream has unknown data." << std::endl;
}
return result;
}
bool SaveToFile(const std::u16string& filename)
{
// TODO: How to adapt u16string to string?
/*
std::ofstream stream(filename.c_str(), std::ios::binary);
auto result = SaveToStream(&stream);
stream.close();
return result;
*/
return false;
}
bool SaveToStream(std::ofstream *stream)
{
std::string magic = "Vocaloid Motion Data 0002\0";
magic.resize(30);
// magic and version
stream->write(magic.c_str(), 30);
// name
stream->write(model_name.c_str(), 20);
// bone frames
const int bone_frame_num = static_cast<int>(bone_frames.size());
stream->write(reinterpret_cast<const char*>(&bone_frame_num), sizeof(int));
for (int i = 0; i < bone_frame_num; i++)
{
bone_frames[i].Write(stream);
}
// face frames
const int face_frame_num = static_cast<int>(face_frames.size());
stream->write(reinterpret_cast<const char*>(&face_frame_num), sizeof(int));
for (int i = 0; i < face_frame_num; i++)
{
face_frames[i].Write(stream);
}
// camera frames
const int camera_frame_num = static_cast<int>(camera_frames.size());
stream->write(reinterpret_cast<const char*>(&camera_frame_num), sizeof(int));
for (int i = 0; i < camera_frame_num; i++)
{
camera_frames[i].Write(stream);
}
// light frames
const int light_frame_num = static_cast<int>(light_frames.size());
stream->write(reinterpret_cast<const char*>(&light_frame_num), sizeof(int));
for (int i = 0; i < light_frame_num; i++)
{
light_frames[i].Write(stream);
}
// self shadow datas
const int self_shadow_num = 0;
stream->write(reinterpret_cast<const char*>(&self_shadow_num), sizeof(int));
// ik frames
const int ik_num = static_cast<int>(ik_frames.size());
stream->write(reinterpret_cast<const char*>(&ik_num), sizeof(int));
for (int i = 0; i < ik_num; i++)
{
ik_frames[i].Write(stream);
}
return true;
}
};
}

View File

@ -105,6 +105,7 @@ SET( TEST_SRCS
unit/utObjImportExport.cpp
unit/utPretransformVertices.cpp
unit/utPLYImportExport.cpp
unit/utPMXImporter.cpp
unit/utRemoveComments.cpp
unit/utRemoveComponent.cpp
unit/utRemoveRedundantMaterials.cpp

View File

@ -0,0 +1,62 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2016, assimp team
All rights reserved.
Redistribution and use of this software 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.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
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.
---------------------------------------------------------------------------
*/
#include "UnitTestPCH.h"
#include "SceneDiffer.h"
#include "AbstractImportExportBase.h"
#include "MMDImporter.h"
#include <assimp/Importer.hpp>
using namespace ::Assimp;
class utPMXImporter : public AbstractImportExportBase {
public:
virtual bool importerTest() {
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/../models-nonbsd/MMD/kawakaze.pmx", 0 );
return nullptr != scene;
}
};
TEST_F( utPMXImporter, importTest ) {
EXPECT_TRUE( importerTest() );
}

View File

@ -1,5 +1,5 @@
project(assimp_qt_viewer)
set(PROJECT_VERSION "")
project(assimp_qt_viewer)
cmake_minimum_required(VERSION 2.6)