--- /dev/null
+/*
+ * PMD nothing handler
+ *
+ * License : The MIT License
+ * Copyright(c) 2013 MikuToga Partners
+ */
+
+package jp.sourceforge.mikutoga.pmd.parser;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * 何もしない統合ハンドラを提供する。
+ */
+public final class NullHandler{
+
+ /** 何もしない統合ハンドラ。 */
+ public static final PmdUnifiedHandler HANDLER;
+
+ static{
+ Class types[] = { PmdUnifiedHandler.class };
+ ClassLoader loader = types[0].getClassLoader();
+ InvocationHandler nothing = new Nothing();
+
+ Object proxy = Proxy.newProxyInstance(loader, types, nothing);
+ assert proxy instanceof PmdUnifiedHandler;
+
+ HANDLER = (PmdUnifiedHandler) proxy;
+ }
+
+
+ /**
+ * ダミーコンストラクタ。
+ */
+ private NullHandler(){
+ assert false;
+ throw new AssertionError();
+ }
+
+
+ /**
+ * 何もしないInvoker実装。
+ */
+ private static class Nothing implements InvocationHandler{
+
+ /**
+ * コンストラクタ。
+ */
+ Nothing(){
+ super();
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ * NOTHING...
+ * @param proxy {@inheritDoc}
+ * @param method {@inheritDoc}
+ * @param args {@inheritDoc}
+ * @return {@inheritDoc}
+ */
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args){
+ return null;
+ }
+
+ }
+
+}
/**
* ボーン定義情報の通知を受け取る。
- * {@link #BONE_LIST}ループの構成要素。
+ * <p>{@link #BONE_LIST}ループの構成要素。
* @param boneName ボーン名
* @param boneKind ボーン種別。
* <ul>
/**
* ボーン間接続情報の通知を受け取る。
- * {@link #BONE_LIST}ループの構成要素。
+ * <p>{@link #BONE_LIST}ループの構成要素。
* @param parentId 親(前)ボーンID。無い場合は0xffff。
* @param tailId 子(次)ボーンID。末端の場合は0。
* 捩りボーンの場合は軸方向のボーンID、
/**
* ボーン位置情報の通知を受け取る。
- * {@link #BONE_LIST}ループの構成要素。
+ * <p>{@link #BONE_LIST}ループの構成要素。
* @param xPos X座標
* @param yPos Y座標
* @param zPos Z座標
/**
* IKボーン情報の通知を受け取る。
- * {@link #IK_LIST}ループの構成要素。
+ * <p>{@link #IK_LIST}ループの構成要素。
* @param boneId IKボーンID
* @param targetId IKボーンが最初に接続するIK接続先ボーンID
* @param depth 再帰演算の深さ
/**
* IKチェイン要素の通知を受け取る。
- * {@link #IK_LIST}ループの下位{@link #IKCHAIN_LIST}ループの構成要素。
+ * <p>{@link #IK_LIST}ループの下位{@link #IKCHAIN_LIST}ループの構成要素。
* @param childId IK影響下ボーンID
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
/**
* ボーングループ名定義の通知を受け取る。
- * {@link #BONEGROUP_LIST}ループの構成要素。
+ * <p>{@link #BONEGROUP_LIST}ループの構成要素。
* @param groupName ボーングループ名。末尾のLF(0x0a)は削除される。
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
/**
* ボーングループ内訳の通知を受け取る。
- * {@link #GROUPEDBONE_LIST}ループの構成要素。
+ * <p>{@link #GROUPEDBONE_LIST}ループの構成要素。
* @param boneId グループに所属するボーンのID
* @param groupId ボーンが所属するボーングループIDに1を足した数
* @throws MmdFormatException 不正フォーマットによる
/** モーフ英語名抽出ループ。 */
ParseStage ENGMORPH_LIST = new ParseStage();
- /** ã\83\9cã\83¼ã\83³ã\82°ã\83«ã\83¼ã\83\97è\8b±èª\9eå\90\8dæ\8a½å\87ºã\82°ã\83«ã\83¼ã\83\97ã\80\82 */
+ /** ボーングループ英語名抽出ループ。 */
ParseStage ENGBONEGROUP_LIST = new ParseStage();
/**
/**
* 英語ボーン名の通知を受け取る。
- * {@link #ENGBONE_LIST}ループの構成要素
+ * <p>{@link #ENGBONE_LIST}ループの構成要素
* @param boneName 英語ボーン名
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
/**
* 英語モーフ名の通知を受け取る。
- * モーフ名「base」に対応する英語名は通知されない。
- * {@link #ENGMORPH_LIST}ループの構成要素
+ * 特殊モーフ名「base」に対応する英語名は通知されない。
+ * <p>{@link #ENGMORPH_LIST}ループの構成要素
* @param morphName 英語モーフ名
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
/**
* 英語ボーングループ名の通知を受け取る。
- * {@link #ENGBONEGROUP_LIST}ループの構成要素
+ * <p>{@link #ENGBONEGROUP_LIST}ループの構成要素
* @param groupName 英語ボーングループ名
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
/**
* ジョイント名の通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
+ * <p>{@link #JOINT_LIST}ループの構成要素。
* @param jointName ジョイント名
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示。
/**
* ジョイントが繋ぐ接続剛体IDの通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
+ * <p>{@link #JOINT_LIST}ループの構成要素。
* @param rigidIdA 接続剛体AのID
* @param rigidIdB 接続剛体BのID
* @throws MmdFormatException 不正フォーマットによる
/**
* ジョイント位置の通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
+ * <p>{@link #JOINT_LIST}ループの構成要素。
* @param posX X座標
* @param posY Y座標
* @param posZ Z座標
/**
* ジョイント回転姿勢の通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
+ * <p>{@link #JOINT_LIST}ループの構成要素。
* @param radX X軸回転量(radian)
* @param radY Y軸回転量(radian)
* @param radZ Z軸回転量(radian)
/**
* ジョイント移動制限の通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
- * ※(制限端その1<=その2)条件を満たす必要はあるか?
+ * <p>{@link #JOINT_LIST}ループの構成要素。
+ * <p>※ [制限端 その1 <= その2] 条件を満たす必要はあるか?
* @param posXlim1 X座標制限端その1
* @param posXlim2 X座標制限端その2
* @param posYlim1 Y座標制限端その1
/**
* ジョイント回転制限の通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
- * ※(制限端その1<=その2)条件を満たす必要はあるか?
+ * <p>{@link #JOINT_LIST}ループの構成要素。
+ * <p>※ [制限端 その1 <= その2] 条件を満たす必要はあるか?
* @param radXlim1 X軸制限端その1(radian)
* @param radXlim2 X軸制限端その2(radian)
* @param radYlim1 Y軸制限端その1(radian)
/**
* ジョイントのばね移動情報の通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
+ * <p>{@link #JOINT_LIST}ループの構成要素。
* @param elasticPosX X座標
* @param elasticPosY Y座標
* @param elasticPosZ Z座標
/**
* ジョイントのばね回転情報の通知を受け取る。
- * {@link #JOINT_LIST}ループの構成要素。
+ * <p>{@link #JOINT_LIST}ループの構成要素。
* @param elasticDegX X軸変量(degree)
* @param elasticDegY Y軸変量(degree)
* @param elasticDegZ Z軸変量(degree)
/**
* ボーン最大数。
* (Id : 0 - 0xfffe)
- * MMDがいくつまで受け入れるかはまた別の話だよ。
+ * <p>MMDがいくつまで受け入れるかはまた別の話だよ。
*/
public static final int MAX_BONE = 65535;
/**
* 材質の拡散光成分の通知を受け取る。
- * {@link #MATERIAL_LIST}ループの構成要素。
+ * <p>{@link #MATERIAL_LIST}ループの構成要素。
* @param red 0.0~1.0の範囲の赤成分
* @param green 0.0~1.0の範囲の緑成分
* @param blue 0.0~1.0の範囲の青成分
/**
* 材質の反射光成分の通知を受け取る。
- * {@link #MATERIAL_LIST}ループの構成要素。
+ * <p>{@link #MATERIAL_LIST}ループの構成要素。
* @param red 0.0~1.0の範囲の赤成分
* @param green 0.0~1.0の範囲の緑成分
* @param blue 0.0~1.0の範囲の青成分
/**
* 材質の環境色成分の通知を受け取る。
- * {@link #MATERIAL_LIST}ループの構成要素。
+ * <p>{@link #MATERIAL_LIST}ループの構成要素。
* @param red 0.0~1.0の範囲の赤成分
* @param green 0.0~1.0の範囲の緑成分
* @param blue 0.0~1.0の範囲の青成分
/**
* シェーディング情報の通知を受け取る。
- * {@link #MATERIAL_LIST}ループの構成要素。
+ * <p>{@link #MATERIAL_LIST}ループの構成要素。
* @param toonIdx トゥーンファイル番号。
* 0ならtoon01.bmp。9ならtoon10.bmp。0xffならtoon0.bmp。
* @param textureFile テクスチャファイル名。
/**
* 材質情報の通知を受け取る。
- * {@link #MATERIAL_LIST}ループの構成要素。
+ * <p>{@link #MATERIAL_LIST}ループの構成要素。
* @param hasEdge エッジを表示するならtrue
* @param vertexNum 面頂点数。
* 3の倍数のはず。
- * 3で割ると積算で表される面IDの範囲を表す。
+ * 3で割ると、材質に属する面の数を表す。
+ * <p>通算した面数を面情報通知順と突き合わせることにより、
+ * 材質に属する面の集合を得ることが可能。
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
+ * @see PmdShapeHandler#pmdSurfaceTriangle(int, int, int)
*/
void pmdMaterialInfo(boolean hasEdge, int vertexNum)
throws MmdFormatException;
/**
* モーフ情報の通知を受け取る。
- * {@link #MORPH_LIST}ループの構成要素
+ * <p>{@link #MORPH_LIST}ループの構成要素
* @param morphName モーフ名
* @param morphType モーフ種別。
* <ul>
/**
* モーフ形状の通知を受け取る。
- * {@link #MORPH_LIST}ループの下位{@link #MORPHVERTEX_LIST}の構成要素
+ * <p>{@link #MORPH_LIST}ループの下位{@link #MORPHVERTEX_LIST}の構成要素。
+ * <p>※ base型頂点IDの出現順がモーフ頂点IDとなる。
* @param serialId base型の場合は頂点ID、それ以外はモーフ頂点ID
* @param xPos base型の場合はX座標、それ以外はX軸変位
* @param yPos base型の場合はY座標、それ以外はY軸変位
/**
* 各モーフ種別内のGUI表示順の通知を受け取る。
- * {@link #MORPHORDER_LIST}ループの構成要素
- * @param morphId モーフ通し番号。同一種別内の大小関係のみ意味がある。
+ * <p>{@link #MORPHORDER_LIST}ループの構成要素
+ * @param morphId モーフ通し番号。同一モーフ種別内の大小関係のみ意味がある。
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
*/
/**
* PMDモデルファイルのパーサ最新版。
- * 将来のリリースにおいて、
+ * <p>将来のリリースにおいて、
* 常に最新のPMDモデルファイルフォーマットに対応したパーサの
* 別名であることが保証される。つもり。
*/
/** 改行文字列 CRLF。 */
protected static final String CRLF = CR + LF; // 0x0d, 0x0a
- private static final int HEADER_LENGTH = 7;
+ /** 3角ポリゴン頂点数。 */
+ private static final int TRIVTX = 3;
+ private static final int HEADER_LENGTH = 7;
private static final byte[] MAGIC_BYTES = {
(byte)0x50, (byte)0x6d, (byte)0x64, // "Pmd"
(byte)0x00, (byte)0x00, (byte)0x80, (byte)0x3f, // 1.0f
};
- private static final int VERTEX_DATA_SZ = 38;
- private static final int SURFACE_DATA_SZ = 6;
- private static final int MATERIAL_DATA_SZ = 70;
- private static final int BONE_DATA_SZ = 39;
- private static final int MORPHVERTEX_DATA_SZ = 16;
- private static final int MORPHORDER_DATA_SZ = 2;
- private static final int BONEGROUP_DATA_SZ = 50;
- private static final int GROUPEDBONE_DATA_SZ = 3;
-
static{
assert MAGIC_BYTES.length == HEADER_LENGTH;
private final TextDecoder decoderWin31j = new TextDecoder(CS_WIN31J);
- private PmdBasicHandler basicHandler = null;
- private PmdShapeHandler shapeHandler = null;
- private PmdMaterialHandler materialHandler = null;
- private PmdBoneHandler boneHandler = null;
- private PmdMorphHandler morphHandler = null;
+ private PmdBasicHandler basicHandler = NullHandler.HANDLER;
+ private PmdShapeHandler shapeHandler = NullHandler.HANDLER;
+ private PmdMaterialHandler materialHandler = NullHandler.HANDLER;
+ private PmdBoneHandler boneHandler = NullHandler.HANDLER;
+ private PmdMorphHandler morphHandler = NullHandler.HANDLER;
private int boneCount = -1;
private int morphCount = -1;
return;
}
+
/**
* 文字列の最後がLF(0x0a)の場合削除する。
+ * <p>ボーングループ名対策。
* @param name 文字列
* @return 末尾LFが削除された文字列
*/
* @param handler ハンドラ
*/
public void setBasicHandler(PmdBasicHandler handler){
- this.basicHandler = handler;
+ if(handler == null){
+ this.basicHandler = NullHandler.HANDLER;
+ }else{
+ this.basicHandler = handler;
+ }
return;
}
* @param handler ハンドラ
*/
public void setShapeHandler(PmdShapeHandler handler){
- this.shapeHandler = handler;
+ if(handler == null){
+ this.shapeHandler = NullHandler.HANDLER;
+ }else{
+ this.shapeHandler = handler;
+ }
return;
}
* @param handler ハンドラ
*/
public void setMaterialHandler(PmdMaterialHandler handler){
- this.materialHandler = handler;
+ if(handler == null){
+ this.materialHandler = NullHandler.HANDLER;
+ }else{
+ this.materialHandler = handler;
+ }
return;
}
* @param handler ハンドラ
*/
public void setBoneHandler(PmdBoneHandler handler){
- this.boneHandler = handler;
+ if(handler == null){
+ this.boneHandler = NullHandler.HANDLER;
+ }else{
+ this.boneHandler = handler;
+ }
return;
}
* @param handler ハンドラ
*/
public void setMorphHandler(PmdMorphHandler handler){
- this.morphHandler = handler;
+ if(handler == null){
+ this.morphHandler = NullHandler.HANDLER;
+ }else{
+ this.morphHandler = handler;
+ }
return;
}
/**
* 指定されたバイト長に収まるゼロ終端(0x00)文字列を読み込む。
- * 入力バイト列はwindows-31jエンコーディングとして解釈される。
- * ゼロ終端以降のデータは無視されるが、
+ * <p>入力バイト列はwindows-31jエンコーディングとして解釈される。
+ * <p>ゼロ終端以降のデータは無視されるが、
* IO入力は指定バイト数だけ読み進められる。
* ゼロ終端が見つからないまま指定バイト数が読み込み終わった場合、
* そこまでのデータから文字列を構成する。
*/
public void parsePmd()
throws IOException, MmdFormatException {
- if(this.basicHandler != null){
- this.basicHandler.pmdParseStart();
- }
+ this.basicHandler.pmdParseStart();
parseBody();
boolean hasMoreData = hasMore();
- if(this.basicHandler != null){
- this.basicHandler.pmdParseEnd(hasMoreData);
- }
+ this.basicHandler.pmdParseEnd(hasMoreData);
return;
}
throw new MmdFormatException("unknown PMD-header type");
}
- String modelName =
+ String modelName =
parsePmdText(PmdLimits.MAXBYTES_MODELNAME);
String description =
parsePmdText(PmdLimits.MAXBYTES_MODELDESC);
description = description.replace(CRLF, LF);
- if(this.basicHandler != null){
- this.basicHandler.pmdHeaderInfo(header);
- this.basicHandler.pmdModelInfo(modelName, description);
- }
+ this.basicHandler.pmdHeaderInfo(header);
+ this.basicHandler.pmdModelInfo(modelName, description);
return;
}
private void parseVertexList() throws IOException, MmdFormatException{
int vertexNum = parseLeInt();
- if(this.shapeHandler == null){
- skip(VERTEX_DATA_SZ * vertexNum);
- return;
- }
-
this.shapeHandler.loopStart(PmdShapeHandler.VERTEX_LIST, vertexNum);
for(int ct = 0; ct < vertexNum; ct++){
*/
private void parseSurfaceList() throws IOException, MmdFormatException{
int vertexNum = parseLeInt();
- if(vertexNum % 3 != 0) throw new MmdFormatException();
- int surfaceNum = vertexNum / 3;
-
- if(this.shapeHandler == null){
- skip(SURFACE_DATA_SZ * surfaceNum);
- return;
- }
+ if(vertexNum % TRIVTX != 0) throw new MmdFormatException();
+ int surfaceNum = vertexNum / TRIVTX;
this.shapeHandler.loopStart(PmdShapeHandler.SURFACE_LIST, surfaceNum);
private void parseMaterialList() throws IOException, MmdFormatException{
int materialNum = parseLeInt();
- if(this.materialHandler == null){
- skip(MATERIAL_DATA_SZ * materialNum);
- return;
- }
-
this.materialHandler.loopStart(PmdMaterialHandler.MATERIAL_LIST,
materialNum );
for(int ct = 0; ct < materialNum; ct++){
- float red;
- float green;
- float blue;
-
- red = parseLeFloat();
- green = parseLeFloat();
- blue = parseLeFloat();
- float alpha = parseLeFloat();
- this.materialHandler.pmdMaterialDiffuse(red, green, blue, alpha);
-
- float shininess = parseLeFloat();
- red = parseLeFloat();
- green = parseLeFloat();
- blue = parseLeFloat();
- this.materialHandler.pmdMaterialSpecular(red, green, blue,
- shininess);
-
- red = parseLeFloat();
- green = parseLeFloat();
- blue = parseLeFloat();
- this.materialHandler.pmdMaterialAmbient(red, green, blue);
+ parseColor();
int toonidx = parseUByteAsInt();
boolean hasEdge = parseBoolean();
int surfaceCount = parseLeInt();
+
String shadingFile =
parsePmdText(PmdLimits.MAXBYTES_TEXTUREFILENAME);
String[] splitted = splitShadingFileInfo(shadingFile);
String textureFile = splitted[0];
- String sphereFile = splitted[1];
+ String sphereFile = splitted[1];
this.materialHandler.pmdMaterialShading(toonidx,
textureFile, sphereFile );
}
/**
+ * 色情報のパースと通知。
+ * @throws IOException IOエラー
+ * @throws MmdFormatException フォーマットエラー
+ */
+ private void parseColor() throws IOException, MmdFormatException{
+ float red;
+ float green;
+ float blue;
+
+ red = parseLeFloat();
+ green = parseLeFloat();
+ blue = parseLeFloat();
+ float alpha = parseLeFloat();
+
+ this.materialHandler.pmdMaterialDiffuse(red, green, blue, alpha);
+
+ float shininess = parseLeFloat();
+ red = parseLeFloat();
+ green = parseLeFloat();
+ blue = parseLeFloat();
+
+ this.materialHandler.pmdMaterialSpecular(red, green, blue,
+ shininess);
+
+ red = parseLeFloat();
+ green = parseLeFloat();
+ blue = parseLeFloat();
+
+ this.materialHandler.pmdMaterialAmbient(red, green, blue);
+
+ return;
+ }
+
+ /**
* ボーン情報のパースと通知。
* @throws IOException IOエラー
* @throws MmdFormatException フォーマットエラー
private void parseBoneList() throws IOException, MmdFormatException{
this.boneCount = parseLeUShortAsInt();
- if(this.boneHandler == null){
- skip(BONE_DATA_SZ * this.boneCount);
- return;
- }
-
this.boneHandler.loopStart(PmdBoneHandler.BONE_LIST, this.boneCount);
for(int ct = 0; ct < this.boneCount; ct++){
private void parseIKList() throws IOException, MmdFormatException{
int ikCount = parseLeUShortAsInt();
- if(this.boneHandler != null){
- this.boneHandler.loopStart(PmdBoneHandler.IK_LIST, ikCount);
- }
+ this.boneHandler.loopStart(PmdBoneHandler.IK_LIST, ikCount);
for(int ct = 0; ct < ikCount; ct++){
int boneId = parseLeUShortAsInt();
parseIKChainList(chainLength);
- if(this.boneHandler != null){
- this.boneHandler.pmdIKInfo(boneId, targetId, depth, weight);
- this.boneHandler.loopNext(PmdBoneHandler.IK_LIST);
- }
- }
+ this.boneHandler.pmdIKInfo(boneId, targetId, depth, weight);
- if(this.boneHandler != null){
- this.boneHandler.loopEnd(PmdBoneHandler.IK_LIST);
+ this.boneHandler.loopNext(PmdBoneHandler.IK_LIST);
}
+ this.boneHandler.loopEnd(PmdBoneHandler.IK_LIST);
+
return;
}
*/
private void parseIKChainList(int chainLength)
throws IOException, MmdFormatException{
- if(this.boneHandler != null){
- this.boneHandler.loopStart(PmdBoneHandler.IKCHAIN_LIST,
- chainLength);
- }
+ this.boneHandler.loopStart(PmdBoneHandler.IKCHAIN_LIST,
+ chainLength);
for(int ct = 0; ct < chainLength; ct++){
int childId = parseLeUShortAsInt();
- if(this.boneHandler != null){
- this.boneHandler.pmdIKChainInfo(childId);
- this.boneHandler.loopNext(PmdBoneHandler.IKCHAIN_LIST);
- }
- }
+ this.boneHandler.pmdIKChainInfo(childId);
- if(this.boneHandler != null){
- this.boneHandler.loopEnd(PmdBoneHandler.IKCHAIN_LIST);
+ this.boneHandler.loopNext(PmdBoneHandler.IKCHAIN_LIST);
}
+ this.boneHandler.loopEnd(PmdBoneHandler.IKCHAIN_LIST);
+
return;
}
private void parseMorphList() throws IOException, MmdFormatException{
this.morphCount = parseLeUShortAsInt();
- if(this.morphHandler != null){
- this.morphHandler.loopStart(PmdMorphHandler.MORPH_LIST,
- this.morphCount );
- }
+ this.morphHandler.loopStart(PmdMorphHandler.MORPH_LIST,
+ this.morphCount );
for(int ct = 0; ct < this.morphCount; ct++){
String morphName =
int vertexCount = parseLeInt();
byte morphType = parseByte();
- if(this.morphHandler != null){
- this.morphHandler.pmdMorphInfo(morphName, morphType);
- }
+ this.morphHandler.pmdMorphInfo(morphName, morphType);
parseMorphVertexList(vertexCount);
- if(this.morphHandler != null){
- this.morphHandler.loopNext(PmdMorphHandler.MORPH_LIST);
- }
+ this.morphHandler.loopNext(PmdMorphHandler.MORPH_LIST);
}
- if(this.morphHandler != null){
- this.morphHandler.loopEnd(PmdMorphHandler.MORPH_LIST);
- }
+ this.morphHandler.loopEnd(PmdMorphHandler.MORPH_LIST);
return;
}
*/
private void parseMorphVertexList(int vertexCount)
throws IOException, MmdFormatException{
- if(this.morphHandler == null){
- skip(MORPHVERTEX_DATA_SZ * vertexCount);
- return;
- }
-
this.morphHandler.loopStart(PmdMorphHandler.MORPHVERTEX_LIST,
vertexCount );
float yPos = parseLeFloat();
float zPos = parseLeFloat();
this.morphHandler.pmdMorphVertexInfo(vertexId, xPos, yPos, zPos);
+
this.morphHandler.loopNext(PmdMorphHandler.MORPHVERTEX_LIST);
}
throws IOException, MmdFormatException{
int morphOrderCount = parseUByteAsInt();
- if(this.morphHandler == null){
- skip(MORPHORDER_DATA_SZ * morphOrderCount);
- return;
- }
-
this.morphHandler.loopStart(PmdMorphHandler.MORPHORDER_LIST,
morphOrderCount );
throws IOException, MmdFormatException{
this.boneGroupCount = parseUByteAsInt();
- if(this.boneHandler == null){
- skip(BONEGROUP_DATA_SZ * this.boneGroupCount);
- return;
- }
-
this.boneHandler.loopStart(PmdBoneHandler.BONEGROUP_LIST,
this.boneGroupCount);
throws IOException, MmdFormatException{
int groupedBoneCount = parseLeInt();
- if(this.boneHandler == null){
- skip(GROUPEDBONE_DATA_SZ * groupedBoneCount);
- return;
- }
-
this.boneHandler.loopStart(PmdBoneHandler.GROUPEDBONE_LIST,
groupedBoneCount);
/**
* PMDモデルファイルのパーサ拡張その1。
- * ※英名対応
+ * <p>※ 英名対応
*/
public class PmdParserExt1 extends PmdParserBase {
- private PmdEngHandler engHandler = null;
+ private PmdEngHandler engHandler = NullHandler.HANDLER;
private boolean hasEnglishInfo = true;
/**
* @param handler ハンドラ
*/
public void setEngHandler(PmdEngHandler handler){
- this.engHandler = handler;
+ if(handler == null){
+ this.engHandler = NullHandler.HANDLER;
+ }else{
+ this.engHandler = handler;
+ }
return;
}
throws IOException, MmdFormatException{
this.hasEnglishInfo = parseBoolean();
- if(this.engHandler != null){
- this.engHandler.pmdEngEnabled(this.hasEnglishInfo);
- }
+ this.engHandler.pmdEngEnabled(this.hasEnglishInfo);
if( ! this.hasEnglishInfo ) return;
String modelName =
parsePmdText(PmdLimits.MAXBYTES_MODELDESC);
description = description.replace(CRLF, LF);
- if(this.engHandler != null){
- this.engHandler.pmdEngModelInfo(modelName, description);
- }
+ this.engHandler.pmdEngModelInfo(modelName, description);
return;
}
throws IOException, MmdFormatException{
int boneNum = getBoneCount();
- if(this.engHandler == null){
- skip(PmdLimits.MAXBYTES_BONENAME * boneNum);
- return;
- }
-
this.engHandler.loopStart(PmdEngHandler.ENGBONE_LIST, boneNum);
for(int ct = 0; ct < boneNum; ct++){
throws IOException, MmdFormatException{
int morphNum = getMorphCount() - 1; // base は英名なし
- if(this.engHandler == null){
- skip(PmdLimits.MAXBYTES_MORPHNAME * morphNum);
- return;
- }
-
this.engHandler.loopStart(PmdEngHandler.ENGMORPH_LIST, morphNum);
for(int ct = 0; ct < morphNum; ct++){
throws IOException, MmdFormatException{
int groupNum = getBoneGroupCount();
- if(this.engHandler == null){
- skip(PmdLimits.MAXBYTES_BONEGROUPNAME * groupNum);
- return;
- }
-
this.engHandler.loopStart(PmdEngHandler.ENGBONEGROUP_LIST, groupNum);
for(int ct = 0; ct < groupNum; ct++){
/**
* PMDモデルファイルのパーサ拡張その2。
- * ※独自トゥーンテクスチャファイル名対応
+ * <p>※ 独自トゥーンテクスチャファイル名対応
*/
public class PmdParserExt2 extends PmdParserExt1 {
- private PmdToonHandler toonHandler = null;
+ private PmdToonHandler toonHandler = NullHandler.HANDLER;
/**
* コンストラクタ。
* @param handler ハンドラ
*/
public void setToonHandler(PmdToonHandler handler){
- this.toonHandler = handler;
+ if(handler == null){
+ this.toonHandler = NullHandler.HANDLER;
+ }else{
+ this.toonHandler = handler;
+ }
return;
}
* @throws MmdFormatException フォーマットエラー
*/
private void parseToonName() throws IOException, MmdFormatException{
- if(this.toonHandler == null){
- skip(PmdLimits.MAXBYTES_TOONFILENAME * PmdLimits.TOON_FIXEDNUM);
- return;
- }
-
this.toonHandler.loopStart(PmdToonHandler.TOON_LIST,
PmdLimits.TOON_FIXEDNUM );
/**
* PMDモデルファイルのパーサ拡張その3。
- * ※剛体情報対応
+ * <p>※ 剛体情報対応
*/
public class PmdParserExt3 extends PmdParserExt2 {
- private static final int RIGID_DATA_SZ = 83;
- private static final int JOINT_DATA_SZ = 124;
-
- private PmdRigidHandler rigidHandler = null;
- private PmdJointHandler jointHandler = null;
+ private PmdRigidHandler rigidHandler = NullHandler.HANDLER;
+ private PmdJointHandler jointHandler = NullHandler.HANDLER;
/**
* コンストラクタ。
* @param handler 剛体ハンドラ
*/
public void setRigidHandler(PmdRigidHandler handler){
- this.rigidHandler = handler;
+ if(handler == null){
+ this.rigidHandler = NullHandler.HANDLER;
+ }else{
+ this.rigidHandler = handler;
+ }
return;
}
* @param handler ジョイントハンドラ
*/
public void setJointHandler(PmdJointHandler handler){
- this.jointHandler = handler;
+ if(handler == null){
+ this.jointHandler = NullHandler.HANDLER;
+ }else{
+ this.jointHandler = handler;
+ }
return;
}
private void parseRigidList() throws IOException, MmdFormatException{
int rigidNum = parseLeInt();
- if(this.rigidHandler == null){
- skip(RIGID_DATA_SZ * rigidNum);
- return;
- }
-
this.rigidHandler.loopStart(PmdRigidHandler.RIGID_LIST, rigidNum);
for(int ct = 0; ct < rigidNum; ct++){
parsePmdText(PmdLimits.MAXBYTES_RIGIDNAME);
this.rigidHandler.pmdRigidName(rigidName);
- int linkedBoneId = parseLeUShortAsInt();
- int rigidGroupId = parseUByteAsInt();
+ int linkedBoneId = parseLeUShortAsInt();
+ int rigidGroupId = parseUByteAsInt();
short collisionMap = parseLeShort();
this.rigidHandler.pmdRigidInfo(rigidGroupId, linkedBoneId);
- byte shapeType = parseByte();
- float width = parseLeFloat();
- float height = parseLeFloat();
- float depth = parseLeFloat();
- this.rigidHandler.pmdRigidShape(shapeType, width, height, depth);
-
- float posX = parseLeFloat();
- float posY = parseLeFloat();
- float posZ = parseLeFloat();
- this.rigidHandler.pmdRigidPosition(posX, posY, posZ);
-
- float rotX = parseLeFloat();
- float rotY = parseLeFloat();
- float rotZ = parseLeFloat();
- this.rigidHandler.pmdRigidRotation(rotX, rotY, rotZ);
-
- float mass = parseLeFloat();
- float dampingPos = parseLeFloat();
- float dampingRot = parseLeFloat();
- float restitution = parseLeFloat();
- float friction = parseLeFloat();
- this.rigidHandler.pmdRigidPhysics(mass,
- dampingPos, dampingRot,
- restitution, friction );
+ parseRigidGeom();
+ parseRigidDynamics();
byte behaveType = parseByte();
this.rigidHandler.pmdRigidBehavior(behaveType, collisionMap);
}
/**
+ * 剛体ジオメトリのパースと通知。
+ * @throws IOException IOエラー
+ * @throws MmdFormatException フォーマットエラー
+ */
+ private void parseRigidGeom() throws IOException, MmdFormatException{
+ byte shapeType = parseByte();
+ float width = parseLeFloat();
+ float height = parseLeFloat();
+ float depth = parseLeFloat();
+
+ this.rigidHandler.pmdRigidShape(shapeType, width, height, depth);
+
+ float posX = parseLeFloat();
+ float posY = parseLeFloat();
+ float posZ = parseLeFloat();
+
+ this.rigidHandler.pmdRigidPosition(posX, posY, posZ);
+
+ float rotX = parseLeFloat();
+ float rotY = parseLeFloat();
+ float rotZ = parseLeFloat();
+
+ this.rigidHandler.pmdRigidRotation(rotX, rotY, rotZ);
+
+ return;
+ }
+
+ /**
+ * 剛体力学のパースと通知。
+ * @throws IOException IOエラー
+ * @throws MmdFormatException フォーマットエラー
+ */
+ private void parseRigidDynamics()
+ throws IOException, MmdFormatException{
+ float mass = parseLeFloat();
+ float dampingPos = parseLeFloat();
+ float dampingRot = parseLeFloat();
+ float restitution = parseLeFloat();
+ float friction = parseLeFloat();
+
+ this.rigidHandler.pmdRigidPhysics(
+ mass, dampingPos, dampingRot, restitution, friction
+ );
+
+ return;
+ }
+
+ /**
* ジョイント情報のパースと通知。
* @throws IOException IOエラー
* @throws MmdFormatException フォーマットエラー
private void parseJointList() throws IOException, MmdFormatException{
int jointNum = parseLeInt();
- if(this.jointHandler == null){
- skip(JOINT_DATA_SZ * jointNum);
- return;
- }
-
this.jointHandler.loopStart(PmdJointHandler.JOINT_LIST, jointNum);
for(int ct = 0; ct < jointNum; ct++){
int rigidIdB = parseLeInt();
this.jointHandler.pmdJointLink(rigidIdA, rigidIdB);
- float posX = parseLeFloat();
- float posY = parseLeFloat();
- float posZ = parseLeFloat();
- this.jointHandler.pmdJointPosition(posX, posY, posZ);
-
- float rotX = parseLeFloat();
- float rotY = parseLeFloat();
- float rotZ = parseLeFloat();
- this.jointHandler.pmdJointRotation(rotX, rotY, rotZ);
-
- float posXlim1 = parseLeFloat();
- float posYlim1 = parseLeFloat();
- float posZlim1 = parseLeFloat();
- float posXlim2 = parseLeFloat();
- float posYlim2 = parseLeFloat();
- float posZlim2 = parseLeFloat();
- this.jointHandler.pmdPositionLimit(posXlim1, posXlim2,
- posYlim1, posYlim2,
- posZlim1, posZlim2 );
-
- float rotXlim1 = parseLeFloat();
- float rotYlim1 = parseLeFloat();
- float rotZlim1 = parseLeFloat();
- float rotXlim2 = parseLeFloat();
- float rotYlim2 = parseLeFloat();
- float rotZlim2 = parseLeFloat();
- this.jointHandler.pmdRotationLimit(rotXlim1, rotXlim2,
- rotYlim1, rotYlim2,
- rotZlim1, rotZlim2 );
-
- float elasticPosX = parseLeFloat();
- float elasticPosY = parseLeFloat();
- float elasticPosZ = parseLeFloat();
- this.jointHandler.pmdElasticPosition(elasticPosX,
- elasticPosY,
- elasticPosZ );
-
- float elasticRotX = parseLeFloat();
- float elasticRotY = parseLeFloat();
- float elasticRotZ = parseLeFloat();
- this.jointHandler.pmdElasticRotation(elasticRotX,
- elasticRotY,
- elasticRotZ );
+ parseJointGeom();
+ parseJointLimit();
+ parseJointElastic();
this.jointHandler.loopNext(PmdJointHandler.JOINT_LIST);
}
return;
}
+ /**
+ * ジョイントジオメトリのパースと通知。
+ * @throws IOException IOエラー
+ * @throws MmdFormatException フォーマットエラー
+ */
+ private void parseJointGeom() throws IOException, MmdFormatException{
+ float posX = parseLeFloat();
+ float posY = parseLeFloat();
+ float posZ = parseLeFloat();
+
+ this.jointHandler.pmdJointPosition(posX, posY, posZ);
+
+ float rotX = parseLeFloat();
+ float rotY = parseLeFloat();
+ float rotZ = parseLeFloat();
+
+ this.jointHandler.pmdJointRotation(rotX, rotY, rotZ);
+
+ return;
+ }
+
+ /**
+ * ジョイント制約のパースと通知。
+ * @throws IOException IOエラー
+ * @throws MmdFormatException フォーマットエラー
+ */
+ private void parseJointLimit() throws IOException, MmdFormatException{
+ float posXlim1 = parseLeFloat();
+ float posYlim1 = parseLeFloat();
+ float posZlim1 = parseLeFloat();
+ float posXlim2 = parseLeFloat();
+ float posYlim2 = parseLeFloat();
+ float posZlim2 = parseLeFloat();
+
+ this.jointHandler.pmdPositionLimit(
+ posXlim1, posXlim2,
+ posYlim1, posYlim2,
+ posZlim1, posZlim2
+ );
+
+ float rotXlim1 = parseLeFloat();
+ float rotYlim1 = parseLeFloat();
+ float rotZlim1 = parseLeFloat();
+ float rotXlim2 = parseLeFloat();
+ float rotYlim2 = parseLeFloat();
+ float rotZlim2 = parseLeFloat();
+
+ this.jointHandler.pmdRotationLimit(
+ rotXlim1, rotXlim2,
+ rotYlim1, rotYlim2,
+ rotZlim1, rotZlim2
+ );
+
+ return;
+ }
+
+ /**
+ * ジョイント弾性のパースと通知。
+ * @throws IOException IOエラー
+ * @throws MmdFormatException フォーマットエラー
+ */
+ private void parseJointElastic()
+ throws IOException, MmdFormatException{
+ float elasticPosX = parseLeFloat();
+ float elasticPosY = parseLeFloat();
+ float elasticPosZ = parseLeFloat();
+
+ this.jointHandler.pmdElasticPosition(
+ elasticPosX,
+ elasticPosY,
+ elasticPosZ
+ );
+
+ float elasticRotX = parseLeFloat();
+ float elasticRotY = parseLeFloat();
+ float elasticRotZ = parseLeFloat();
+
+ this.jointHandler.pmdElasticRotation(
+ elasticRotX,
+ elasticRotY,
+ elasticRotZ
+ );
+
+ return;
+ }
+
}
/**
* PMDモデルの各種剛体情報の通知用ハンドラ。
+ * <p>MMDでの剛体力学では「Bullet Physics Library」が用いられる。
+ * @see <a href="http://www.bulletphysics.org/">Bullet Physics Library</a>
*/
public interface PmdRigidHandler extends LoopHandler {
/**
* 剛体名の通知を受け取る。
- * {@link #RIGID_LIST}ループの構成要素。
+ * <p>{@link #RIGID_LIST}ループの構成要素。
* @param rigidName 剛体名
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
/**
* 剛体基本情報の通知を受け取る。
- * {@link #RIGID_LIST}ループの構成要素。
+ * <p>{@link #RIGID_LIST}ループの構成要素。
* @param rigidGroupId 剛体グループ番号から1引いた数。(0-15)
- * @param linkedBoneId 接続先ボーンID
+ * @param linkedBoneId 接続先ボーンID。
+ * [ 0x0000 - 0xfffe ] に収まらない場合は接続先ボーン無し。
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
*/
/**
* 剛体形状の通知を受け取る。
- * {@link #RIGID_LIST}ループの構成要素。
+ * <p>{@link #RIGID_LIST}ループの構成要素。
* @param shapeType 形状種別。
* <ul>
* <li>0x00:球
/**
* 剛体位置の通知を受け取る。
- * {@link #RIGID_LIST}ループの構成要素。
+ * <p>{@link #RIGID_LIST}ループの構成要素。
* @param posX X座標
* @param posY Y座標
* @param posZ Z座標
/**
* 剛体姿勢の通知を受け取る。
- * {@link #RIGID_LIST}ループの構成要素。
+ * <p>{@link #RIGID_LIST}ループの構成要素。
* @param radX X軸回転量(radian)
* @param radY Y軸回転量(radian)
* @param radZ Z軸回転量(radian)
/**
* 剛体物理系数の通知を受け取る。
- * {@link #RIGID_LIST}ループの構成要素。
+ * <p>{@link #RIGID_LIST}ループの構成要素。
* @param mass 質量
* @param dampingPos 移動減衰率
* @param dampingRot 回転減衰率
/**
* 剛体の振る舞い情報の通知を受け取る。
- * {@link #RIGID_LIST}ループの構成要素。
+ * <p>{@link #RIGID_LIST}ループの構成要素。
* @param behaveType 剛体タイプ。
* <ul>
* <li>0:ボーン追従
* <li>2:物理演算+ボーン位置合わせ
* </ul>
* @param collisionMap 非衝突剛体グループビットマップ。
+ * <p>
* (衝突グループ番号-1)位置のビット位置は1に、
* (非衝突グループ番号-1)位置のビット位置は0になる。
* 例)グループ1と8のみが非衝突指定の場合、0xff7eになる。
/**
* PMDモデルの各種形状(頂点、面)の通知用ハンドラ。
- * 0から始まる頂点ID順に頂点は出現する。
- * 0から始まる面ID順に面は出現する。
+ * <p>0から始まる頂点ID順に頂点は出現する。
+ * <p>0から始まる面ID順に面は出現する。
*/
public interface PmdShapeHandler extends LoopHandler {
/**
* 頂点の座標の通知を受け取る。
- * {@link #VERTEX_LIST}ループの構成要素
+ * <p>{@link #VERTEX_LIST}ループの構成要素
* @param xPos X座標
* @param yPos Y座標
* @param zPos Z座標
/**
* 頂点の法線情報の通知を受け取る。
- * {@link #VERTEX_LIST}ループの構成要素
- * ※単位ベクトル化必須?
+ * <p>{@link #VERTEX_LIST}ループの構成要素
+ * <p>※単位ベクトル化必須?
* @param xVec 法線ベクトルX成分
* @param yVec 法線ベクトルY成分
* @param zVec 法線ベクトルZ成分
/**
* 頂点のUVマッピング情報の通知を受け取る。
* (頂点UV)
- * {@link #VERTEX_LIST}ループの構成要素
+ * <p>{@link #VERTEX_LIST}ループの構成要素
* @param uVal テクスチャのU座標
* @param vVal テクスチャのV座標
* @throws MmdFormatException 不正フォーマットによる
/**
* 頂点のボーン間ウェイトバランス情報の通知を受け取る。
- * {@link #VERTEX_LIST}ループの構成要素
+ * <p>{@link #VERTEX_LIST}ループの構成要素
* @param boneId1 ボーンその1識別ID
* @param boneId2 ボーンその2識別ID
* @param weightForB1 ボーンその1への影響度。0(min)~100(max)
/**
* 頂点のエッジ表現情報の通知を受け取る。
* 材質単位でのエッジ表現指定に優先される。
- * {@link #VERTEX_LIST}ループの構成要素
+ * <p>{@link #VERTEX_LIST}ループの構成要素
* @param hideEdge エッジ無効ならtrue
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
/**
* 3つの頂点から構成される面情報の通知を受け取る。
- * {@link #SURFACE_LIST}ループの構成要素
+ * <p>{@link #SURFACE_LIST}ループの構成要素。
+ * <p>3頂点の指定順は、面カリングにおいて意味を持つ。
* @param vertexId1 頂点IDその1
* @param vertexId2 頂点IDその1
* @param vertexId3 頂点IDその1
/**
* 独自トゥーンテクスチャファイル名の通知を受け取る。
- * {@link #TOON_LIST}ループの構成要素
+ * <p>{@link #TOON_LIST}ループの構成要素
* @param toonName 独自トゥーンテクスチャファイル名
* @throws MmdFormatException 不正フォーマットによる
* パース処理の中断をパーサに指示
--- /dev/null
+/*
+ * PMD unified handler
+ *
+ * License : The MIT License
+ * Copyright(c) 2013 MikuToga Partners
+ */
+
+package jp.sourceforge.mikutoga.pmd.parser;
+
+/**
+ * PMDパーサ用の統合ハンドラ。
+ */
+public interface PmdUnifiedHandler
+ extends PmdBasicHandler,
+ PmdShapeHandler,
+ PmdMaterialHandler,
+ PmdBoneHandler,
+ PmdMorphHandler,
+ PmdEngHandler,
+ PmdToonHandler,
+ PmdRigidHandler,
+ PmdJointHandler {
+}
package sample.pmd;
import jp.sfjp.mikutoga.bin.parser.ParseStage;
-import jp.sourceforge.mikutoga.pmd.parser.PmdBasicHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdBoneHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdEngHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdJointHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdMaterialHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdMorphHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdRigidHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdShapeHandler;
-import jp.sourceforge.mikutoga.pmd.parser.PmdToonHandler;
+import jp.sourceforge.mikutoga.pmd.parser.PmdUnifiedHandler;
/**
* サンプルのハンドラ。
* これはユニットテストではない。
* 必要に応じて要所でデバッガのブレークポイントを設定しておくと便利。
*/
-public class DummyHandler
- implements PmdBasicHandler,
- PmdBoneHandler,
- PmdShapeHandler,
- PmdMorphHandler,
- PmdMaterialHandler,
- PmdEngHandler,
- PmdToonHandler,
- PmdRigidHandler,
- PmdJointHandler {
+public class DummyHandler implements PmdUnifiedHandler {
public DummyHandler(){
super();