├── .gitignore
├── .travis.yml
├── test
├── expected_unknown.txt
├── helper.sh
├── pack_unity_packager_exec_test.sh
├── expected_help.txt
├── runner
└── pack_unity_package_test.sh
├── TexturePacker
├── Editor.meta
├── Plugins.meta
├── Shaders.meta
├── Shaders
│ ├── OpaqueUnlit.shader.meta
│ ├── VertexColor.shader.meta
│ ├── TransparentUnlit.shader.meta
│ ├── VertexColor.shader
│ ├── OpaqueUnlit.shader
│ └── TransparentUnlit.shader
├── Plugins
│ ├── MiniJSON.cs.meta
│ ├── TexturePacker.cs.meta
│ ├── TexturePacker.cs
│ └── MiniJSON.cs
└── Editor
│ ├── MeshTweaker.cs.meta
│ ├── TexturePackerImport.cs.meta
│ ├── MeshTweaker.cs
│ └── TexturePackerImport.cs
├── Gemfile
├── Guardfile
├── LICENSE
├── README.md
└── pack_unity_package
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | /Gemfile.lock
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: c
2 | install:
3 | - sudo apt-get install shunit2
4 |
5 | script: ./test/runner
--------------------------------------------------------------------------------
/test/expected_unknown.txt:
--------------------------------------------------------------------------------
1 | Unknown flag - detected.
2 | Usage: ./pack_unity_package [-h] [-v] [-u unityPath] [-f folderPath] [-o outputFile]
3 |
--------------------------------------------------------------------------------
/TexturePacker/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 35797fecbc4077c48bede249369aa979
3 | folderAsset: yes
4 | DefaultImporter:
5 | userData:
6 |
--------------------------------------------------------------------------------
/TexturePacker/Plugins.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9e2bac7ba4091ca4cbabad46a64db30e
3 | folderAsset: yes
4 | DefaultImporter:
5 | userData:
6 |
--------------------------------------------------------------------------------
/TexturePacker/Shaders.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e7d35e47b5c230847b63dcaab2604648
3 | folderAsset: yes
4 | DefaultImporter:
5 | userData:
6 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | group :development do
4 | gem 'guard-shell'
5 | gem 'rb-fsevent', :require => false if RUBY_PLATFORM =~ /darwin/i
6 | end
--------------------------------------------------------------------------------
/TexturePacker/Shaders/OpaqueUnlit.shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 59bb2c52ea3e43543bc4008d78550355
3 | ShaderImporter:
4 | defaultTextures: []
5 | userData:
6 |
--------------------------------------------------------------------------------
/TexturePacker/Shaders/VertexColor.shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 82019b3dc63e18044875f19e7ae7ad51
3 | ShaderImporter:
4 | defaultTextures: []
5 | userData:
6 |
--------------------------------------------------------------------------------
/TexturePacker/Shaders/TransparentUnlit.shader.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d8f45406dc6b7444fba8ee3589b2fc82
3 | ShaderImporter:
4 | defaultTextures: []
5 | userData:
6 |
--------------------------------------------------------------------------------
/test/helper.sh:
--------------------------------------------------------------------------------
1 | SHUNIT2=/usr/bin/shunit2
2 |
3 | export PREFIX="$PWD/test"
4 | export PATH="$PWD/bin:$PATH"
5 |
6 | test_path="$PATH"
7 |
8 | setUp() { return; }
9 | tearDown() { return; }
10 | oneTimeTearDown() { return; }
--------------------------------------------------------------------------------
/TexturePacker/Plugins/MiniJSON.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 550c5564dbfbc9242b32721e623ec9f3
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/TexturePacker/Editor/MeshTweaker.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2df93da18054372419b7c4cc84774cd3
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/TexturePacker/Plugins/TexturePacker.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dc14a033102b02e4b8c66bb8b1e25f54
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/TexturePacker/Editor/TexturePackerImport.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6e8b6e08c141d294aacd0e4153efb95f
3 | MonoImporter:
4 | serializedVersion: 2
5 | defaultReferences: []
6 | executionOrder: 0
7 | icon: {instanceID: 0}
8 | userData:
9 |
--------------------------------------------------------------------------------
/test/pack_unity_packager_exec_test.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | . ./test/helper.sh
3 |
4 | testExecNoArguments()
5 | {
6 | ./pack_unity_package -d 2>/dev/null
7 | assertEquals "did not exit with 0" 0 $?
8 | }
9 |
10 | # run shunit2
11 | SHUNIT_PARENT=$0 . $SHUNIT2
--------------------------------------------------------------------------------
/Guardfile:
--------------------------------------------------------------------------------
1 | # A sample Guardfile
2 | # More info at https://github.com/guard/guard#readme
3 |
4 | # Add files and commands to this file, like the example:
5 | # watch(%r{file/path}) { `command(s)` }
6 | #
7 | guard :shell do
8 | watch(/(pack_unity_package)|(.*).sh/) { `sh test/runner` }
9 | end
10 |
--------------------------------------------------------------------------------
/test/expected_help.txt:
--------------------------------------------------------------------------------
1 | usage: pack_unity_package [-h] [-v] [-u unityPath] [-f folderPath] [-o outputFile]
2 |
3 | Options
4 | -v show version
5 | -f set folder to bundle
6 | -o set filename to output
7 | -u set unity command path
8 | (-h) show this help
9 |
--------------------------------------------------------------------------------
/test/runner:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | function log() {
4 | if [[ -t 1 ]]; then
5 | echo -e "\x1b[1m\x1b[32m>>>\x1b[0m \x1b[1m\x1b[37m$1\x1b[0m"
6 | else
7 | echo ">>> $1"
8 | fi
9 | }
10 |
11 | error=0
12 | for test in ${0%/*}/*_test.sh; do
13 | log "Running $test ..."
14 | $test || error=1
15 | echo
16 | done
17 |
--------------------------------------------------------------------------------
/TexturePacker/Shaders/VertexColor.shader:
--------------------------------------------------------------------------------
1 | Shader "Sprites/Transparent Vertex Color" {
2 | Properties {
3 | _MainTex ("Texture", 2D) = "white" {}
4 | }
5 |
6 | Category {
7 | Tags { "Queue"="Transparent" }
8 | Lighting Off
9 | ZWrite Off
10 |
11 | Blend SrcAlpha OneMinusSrcAlpha
12 |
13 | BindChannels {
14 | Bind "Color", color
15 | Bind "Vertex", vertex
16 | Bind "TexCoord", texcoord
17 | }
18 |
19 | SubShader {
20 | Pass {
21 | SetTexture [_MainTex] {
22 | Combine texture * primary DOUBLE
23 | }
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/TexturePacker/Shaders/OpaqueUnlit.shader:
--------------------------------------------------------------------------------
1 | Shader "Sprites/Opaque Unlit"
2 | {
3 | Properties
4 | {
5 | _Color ("Color Tint", Color) = (1,1,1,1)
6 | _MainTex ("Base (RGB)", 2D) = "white"
7 | }
8 |
9 | Category
10 | {
11 | Lighting Off
12 | ZWrite On
13 | Cull back
14 | Tags {Queue=Geometry}
15 |
16 | SubShader
17 | {
18 |
19 | Pass
20 | {
21 | SetTexture [_MainTex]
22 | {
23 | ConstantColor [_Color]
24 | Combine Texture * constant
25 | }
26 | }
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/TexturePacker/Shaders/TransparentUnlit.shader:
--------------------------------------------------------------------------------
1 | Shader "Sprites/Transparent Unlit"
2 | {
3 | Properties
4 | {
5 | _Color ("Color Tint", Color) = (1,1,1,1)
6 | _MainTex ("Base (RGB) Alpha (A)", 2D) = "white"
7 | }
8 |
9 | Category
10 | {
11 | Lighting Off
12 | //ZWrite Off
13 | ZWrite On // uncomment if you have problems like the sprite disappear in some rotations.
14 | Cull back
15 | Blend SrcAlpha OneMinusSrcAlpha
16 | //AlphaTest Greater 0.001 // uncomment if you have problems like the sprites or 3d text have white quads instead of alpha pixels.
17 | Tags {Queue=Transparent}
18 |
19 | SubShader
20 | {
21 |
22 | Pass
23 | {
24 | SetTexture [_MainTex]
25 | {
26 | ConstantColor [_Color]
27 | Combine Texture * constant
28 | }
29 | }
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (C) 2013 Mitch Thompson, Harald Lurger, Hays Clark
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Unity3D - Texture Packer Importer
2 | [](https://travis-ci.org/haysclark/unity3d-texturepackerimporter)
3 |
4 | Grab the latest Unity Package here!
5 | [TexturePackerImporter.unitypackage](http://haysclark.github.io/unity3d-texturepackerimporter/package/TexturePackerImporter.unitypackage)
6 |
7 | ## Authors
8 | * Mitch Thompson
9 | * Harald Lurger
10 | * Hays Clark
11 |
12 | ## Video Tutorial
13 | There is a tutorial for this plugin here:
14 | http://www.youtube.com/watch?v=CHQmvC1pqaY
15 |
16 | ## Instructions
17 | How to import texture sheets from Texture Packer
18 |
19 | ### TexturePacker settings:
20 | Data Format: Unity3D (or JSON Hashtable, then change extension from .json to .txt so Unity picks it up as a text asset)
21 | Allow rotation is OK
22 | Everything else at your discretion
23 | Power of 2 output textures are suggested.
24 |
25 | ### Unity process:
26 | Create a folder in your Assets/ directory for your imported sprites.
27 | Copy the TXT and Image file (PNG, TGA, etc) into that folder.
28 | Your paths should look something like:
29 | Assets/MySprite/MySprite.txt
30 | Assets/MySprite/MySprite.png
31 |
32 | ### Shaders:
33 | Transparent Unlit -
34 | The default shader for all imported sprite sheets.
35 | Opaque Unlit -
36 | nontransparent tintable shader great for drawing backgrounds that don't need alpha. Very efficient.
37 | Vertex Color -
38 | Does not have an inspector-tweakable color property. All colors must be set by altering the colors[] or colors32[] array of a given mesh.
39 | Supports both texture alpha and vertex color alpha.
40 |
41 | ## About Texture Packer
42 | http://www.texturepacker.com/
43 |
44 |
--------------------------------------------------------------------------------
/TexturePacker/Editor/MeshTweaker.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Mesh Tools - Mesh Tweaker
3 | Copyright (C) 2013 Mitch Thompson
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 | */
18 |
19 | using UnityEngine;
20 | using UnityEditor;
21 | using System.Collections;
22 | using System.Collections.Generic;
23 |
24 | public class MeshTweaker{
25 |
26 | [MenuItem("Assets/MeshTweaker/Rotate/X45")]
27 | static void RotateX45(){BatchRotate(45,0,0);}
28 | [MenuItem("Assets/MeshTweaker/Rotate/X90")]
29 | static void RotateX90(){BatchRotate(90,0,0);}
30 |
31 | [MenuItem("Assets/MeshTweaker/Rotate/Y45")]
32 | static void RotateY45(){BatchRotate(0,45,0);}
33 | [MenuItem("Assets/MeshTweaker/Rotate/Y90")]
34 | static void RotateY90(){BatchRotate(0,90,0);}
35 |
36 | [MenuItem("Assets/MeshTweaker/Rotate/Z45")]
37 | static void RotateZ45(){BatchRotate(0,0,45);}
38 | [MenuItem("Assets/MeshTweaker/Rotate/Z90")]
39 | static void RotateZ90(){BatchRotate(0,0,90);}
40 |
41 | static void BatchRotate(float x, float y, float z){
42 | Quaternion quat = Quaternion.Euler(x,y,z);
43 | foreach(Object o in Selection.objects){
44 | if(o is Mesh){
45 | RotateMesh(o as Mesh, quat);
46 | }
47 | }
48 | }
49 |
50 | static void RotateMesh(Mesh mesh, Quaternion quat){
51 | Vector3[] verts = mesh.vertices;
52 | for(int i = 0; i < verts.Length; i++){
53 | verts[i] = quat * verts[i];
54 | }
55 |
56 | mesh.vertices = verts;
57 |
58 | mesh.RecalculateNormals();
59 |
60 | EditorUtility.SetDirty(mesh);
61 | }
62 |
63 |
64 | [MenuItem("Assets/MeshTweaker/Align/Center")]
65 | static void BatchCenter(){
66 | foreach(Object o in Selection.objects){
67 | if(o is Mesh){
68 | CenterMesh(o as Mesh);
69 | }
70 | }
71 | }
72 |
73 | static void CenterMesh(Mesh mesh){
74 | Vector3[] verts = mesh.vertices;
75 |
76 | Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
77 | Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
78 |
79 | foreach(Vector3 v in verts){
80 | if(v.x < min.x) min.x = v.x;
81 | else if(v.x > max.x) max.x = v.x;
82 |
83 | if(v.y < min.y) min.y = v.y;
84 | else if(v.y > max.y) max.y = v.y;
85 |
86 | if(v.z < min.z) min.z = v.z;
87 | else if(v.z > max.z) max.z = v.z;
88 | }
89 |
90 | Vector3 average = (min + max) * 0.5f;
91 |
92 | for(int i = 0; i < verts.Length; i++){
93 | verts[i] = verts[i] + ( Vector3.zero - average );
94 | }
95 |
96 | mesh.vertices = verts;
97 | EditorUtility.SetDirty(mesh);
98 | }
99 | }
--------------------------------------------------------------------------------
/test/pack_unity_package_test.sh:
--------------------------------------------------------------------------------
1 | #! /bin/sh
2 | . ./test/helper.sh
3 |
4 | DEFAULT_EXPORT_FLAG="-exportPackage"
5 | DEFAULT_EXPORT_PATH="TexturePacker"
6 | DEFAULT_EXPORT_DST="Assets/TexturePacker"
7 | DEFAULT_OUTPUT="TexturePackerImporter.unitypackage"
8 |
9 | EXPECTED_CREATE_PROJECT="/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode -createProject .;"
10 | EXPECTED_COPY_CONTENTS="cp -r TexturePacker Assets/TexturePacker;"
11 |
12 | oneTimeTearDown()
13 | {
14 | rm ./results.txt
15 | }
16 |
17 | testScriptShouldOutputExpectedUnknown()
18 | {
19 | EXPECTED='Expected output differs.'
20 | ./pack_unity_package -b > ./results.txt
21 | diff ./test/expected_unknown.txt ./results.txt
22 | assertTrue "${EXPECTED}" $?
23 | }
24 |
25 | testHFlagShouldOutputHelp()
26 | {
27 | EXPECTED='Expected output differs.'
28 | ./pack_unity_package -h > ./results.txt
29 | diff ./test/expected_help.txt ./results.txt
30 | assertTrue "${EXPECTED}" $?
31 | }
32 |
33 | testScriptShouldOutputExpectedVersion()
34 | {
35 | EXPECTED="pack_unity_package version 1.0"
36 | ./pack_unity_package -d -v > ./results.txt
37 | firstline=`head -1 ./results.txt`
38 | assertEquals "${EXPECTED}" "${firstline}"
39 | }
40 |
41 | testScriptShouldWarnIfUnityIsMissing()
42 | {
43 | EXPECTED="Unity path is incorrect or missing."
44 | ./pack_unity_package -d -u "/fake" > ./results.txt
45 | firstline=`head -1 ./results.txt`
46 | assertEquals "${EXPECTED}" "${firstline}"
47 | }
48 |
49 | testScriptShouldOutputCmdOnDryRunFlag()
50 | {
51 | EXPECTED="$EXPECTED_CREATE_PROJECT$EXPECTED_COPY_CONTENTS/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode ${DEFAULT_EXPORT_FLAG} ${DEFAULT_EXPORT_DST} ${DEFAULT_OUTPUT};"
52 | ./pack_unity_package -d > ./results.txt
53 | firstline=`head -1 ./results.txt`
54 | assertEquals "${EXPECTED}" "${firstline}"
55 | }
56 |
57 | testScriptShouldWarnIfFolderIsMissing()
58 | {
59 | EXPECTED="Folder path is incorrect or missing."
60 | ./pack_unity_package -d -f "/fake" > ./results.txt
61 | firstline=`head -1 ./results.txt`
62 | assertEquals "${EXPECTED}" "${firstline}"
63 | }
64 |
65 | testScriptShouldUseCorrectFolderWhenFFlagIsSet()
66 | {
67 | mkdir "fake"
68 | EXPECTED_FILE="fake"
69 | EXPECTED_ASSETS_PATH=Assets/${EXPECTED_FILE}
70 | EXPECTED_COPY="cp -r ${EXPECTED_FILE} ${EXPECTED_ASSETS_PATH};"
71 | EXPECTED="$EXPECTED_CREATE_PROJECT$EXPECTED_COPY/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode ${DEFAULT_EXPORT_FLAG} ${EXPECTED_ASSETS_PATH} ${DEFAULT_OUTPUT};"
72 | ./pack_unity_package -d -f "${EXPECTED_FILE}" > ./results.txt
73 | firstline=`head -1 ./results.txt`
74 | assertEquals "${EXPECTED}" "${firstline}"
75 | rmdir "fake"
76 | }
77 |
78 | testScriptShouldUseCorrectUnityFlagWhenFFlagIsSet()
79 | {
80 | mkdir "fake"
81 | EXPECTED_FILE="fake"
82 | EXPECTED_ASSETS_PATH=Assets/${EXPECTED_FILE}
83 | EXPECTED_COPY="cp -r ${EXPECTED_FILE} ${EXPECTED_ASSETS_PATH};"
84 | EXPECTED_COMMAND="exportPackage"
85 | EXPECTED="$EXPECTED_CREATE_PROJECT$EXPECTED_COPY/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode -${EXPECTED_COMMAND} ${EXPECTED_ASSETS_PATH} ${DEFAULT_OUTPUT};"
86 | ./pack_unity_package -d -f "${EXPECTED_FILE}" > ./results.txt
87 | firstline=`head -1 ./results.txt`
88 | assertEquals "${EXPECTED}" "${firstline}"
89 | rmdir "fake"
90 | }
91 |
92 | testScriptShouldUseCorrectOutputPathWhenOFlagIsSet()
93 | {
94 | EXPECTED_PATH="expectedOutputPath"
95 | EXPECTED="$EXPECTED_CREATE_PROJECT$EXPECTED_COPY_CONTENTS/Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode ${DEFAULT_EXPORT_FLAG} ${DEFAULT_EXPORT_DST} ${EXPECTED_PATH};"
96 | ./pack_unity_package -d -o "${EXPECTED_PATH}" > ./results.txt
97 | firstline=`head -1 ./results.txt`
98 | assertEquals "${EXPECTED}" "${firstline}"
99 | }
100 |
101 | # run shunit2
102 | SHUNIT_PARENT=$0 . $SHUNIT2
--------------------------------------------------------------------------------
/pack_unity_package:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Export Unity3d-TexturePacker to Unity Bundle
4 | #
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | # this software and associated documentation files (the "Software"), to deal in
7 | # the Software without restriction, including without limitation the rights to
8 | # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | # of the Software, and to permit persons to whom the Software is furnished to do
10 | # so, subject to the following conditions:
11 | #
12 | # The above copyright notice and this permission notice shall be included in all
13 | # copies or substantial portions of the Software.
14 | #
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | # SOFTWARE.
22 | #
23 | # Latest version can be found at https://github.com/haysclark/unity3d-texturepackerimporter
24 | # Tested on OSX (10.9)
25 | #
26 | # Copyright (c) 2013 Hays Clark
27 | #
28 |
29 | UNITY_PATH="/Applications/Unity/Unity.app/Contents/MacOS/Unity"
30 | FOLDER_PATH="TexturePacker"
31 | OUTPUT_PATH="TexturePackerImporter.unitypackage"
32 |
33 | # vars
34 | NAME=`basename "$0"`
35 | VERSION=1.0
36 | DRY_RUN=0
37 | EXPECTED_FLAGS="[-h] [-v] [-u unityPath] [-f folderPath] [-o outputFile]"
38 | CMD=""
39 |
40 | PRINT_VERSION(){
41 | echo ${NAME} version ${VERSION}
42 | }
43 |
44 | PRINT_HELP(){
45 | echo usage: ${NAME} ${EXPECTED_FLAGS}
46 | echo
47 | echo "Options"
48 | echo " -v show version"
49 | echo " -f set folder to bundle"
50 | echo " -o set filename to output"
51 | echo " -u set unity command path"
52 | echo "(-h) show this help"
53 | }
54 |
55 | COPY_README(){
56 | if [ -d "Assets/" ]; then
57 | cp LICENSE Assets/LICENSE.txt
58 | fi
59 | }
60 |
61 | COPY_LICENSE(){
62 | if [ -d "Assets/" ]; then
63 | cp README.md Assets/README.txt
64 | fi
65 | }
66 |
67 | CLEAN_UP(){
68 | if [ -d "Assets/" ]; then
69 | rm -r Assets/
70 | fi
71 | if [ -d "ProjectSettings/" ]; then
72 | rm -r ProjectSettings/
73 | fi
74 | if [ -d "Library/" ]; then
75 | rm -r Library/
76 | fi
77 | if [ -d "Temp/" ]; then
78 | rm -r Temp/
79 | fi
80 | }
81 |
82 | while getopts "dvf:o:u:h" VALUE "${@}" ; do
83 | if [ "${VALUE}" = "h" ] ; then
84 | PRINT_HELP
85 | exit 0
86 | fi
87 | if [ "${VALUE}" = "v" ] ; then
88 | PRINT_VERSION
89 | fi
90 | if [ "${VALUE}" = "d" ] ; then
91 | DRY_RUN=1
92 | fi
93 | if [ "${VALUE}" = "f" ] ; then
94 | FOLDER_PATH="${OPTARG}"
95 | fi
96 | if [ "${VALUE}" = "o" ] ; then
97 | OUTPUT_PATH="${OPTARG}"
98 | fi
99 | if [ "${VALUE}" = "u" ] ; then
100 | UNITY_PATH="${OPTARG}"
101 | if ! [ -f "${UNITY_PATH}" ]; then
102 | echo "Unity path is incorrect or missing."
103 | exit 1
104 | fi
105 | fi
106 | if [ "${VALUE}" = ":" ] ; then
107 | echo "Flag -${OPTARG} requires an argument."
108 | echo "Usage: $0 ${EXPECTED_FLAGS}"
109 | exit 1
110 | fi
111 | if [ "${VALUE}" = "?" ] ; then
112 | echo "Unknown flag -${OPTARG} detected."
113 | echo "Usage: $0 ${EXPECTED_FLAGS}"
114 | exit 1
115 | fi
116 | done
117 |
118 | if ! [ -d "${FOLDER_PATH}" ]; then
119 | echo "Folder path is incorrect or missing."
120 | exit 1
121 | fi
122 |
123 | if [ -f "${OUTPUT_PATH}" ]; then
124 | rm ${OUTPUT_PATH};
125 | fi
126 |
127 | EXPORT_PATH="Assets/${FOLDER_PATH}"
128 |
129 | CMD+="${UNITY_PATH} -quit -batchmode -createProject .;"
130 | COPY_README
131 | COPY_LICENSE
132 | CMD+="cp -r ${FOLDER_PATH} $EXPORT_PATH;"
133 | CMD+="${UNITY_PATH} -quit -batchmode -exportPackage ${EXPORT_PATH} ${OUTPUT_PATH};"
134 |
135 | if [ "${DRY_RUN}" = 1 ] ; then
136 | echo "${CMD}"
137 | exit 0
138 | fi
139 |
140 | eval "${CMD}"
141 | CLEAN_UP
142 | exit 0
--------------------------------------------------------------------------------
/TexturePacker/Plugins/TexturePacker.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Mitch Thompson
3 | Extended by Harald Lurger (2013) (Process to Sprites)
4 |
5 | Standard MIT License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 | */
13 |
14 | #if UNITY_EDITOR
15 |
16 | using UnityEngine;
17 | using UnityEditor;
18 | using System.Collections;
19 | using System.Collections.Generic;
20 |
21 | public static class TexturePackerExtensions{
22 | public static Rect TPHashtableToRect(this Hashtable table){
23 | return new Rect((float)table["x"], (float)table["y"], (float)table["w"], (float)table["h"]);
24 | }
25 |
26 | public static Vector2 TPHashtableToVector2(this Hashtable table){
27 | if(table.ContainsKey("x") && table.ContainsKey("y")){
28 | return new Vector2((float)table["x"], (float)table["y"]);
29 | }
30 | else{
31 | return new Vector2((float)table["w"], (float)table["h"]);
32 | }
33 | }
34 |
35 | public static Vector2 TPVector3toVector2(this Vector3 vec){
36 | return new Vector2(vec.x, vec.y);
37 | }
38 |
39 | public static bool IsTexturePackerTable(this Hashtable table){
40 | if(table == null) return false;
41 |
42 | if(table.ContainsKey("meta")){
43 | Hashtable metaTable = (Hashtable)table["meta"];
44 | if(metaTable.ContainsKey("app")){
45 | return true;
46 | // if((string)metaTable["app"] == "http://www.texturepacker.com"){
47 | // return true;
48 | // }
49 | }
50 | }
51 |
52 | return false;
53 | }
54 | }
55 |
56 | public class TexturePacker{
57 |
58 | public class PackedFrame{
59 | public string name;
60 | public Rect frame;
61 | public Rect spriteSourceSize;
62 | public Vector2 sourceSize;
63 | public bool rotated;
64 | public bool trimmed;
65 | Vector2 atlasSize;
66 |
67 | public PackedFrame(string name, Vector2 atlasSize, Hashtable table){
68 | this.name = name;
69 | this.atlasSize = atlasSize;
70 |
71 | frame = ((Hashtable)table["frame"]).TPHashtableToRect();
72 | spriteSourceSize = ((Hashtable)table["spriteSourceSize"]).TPHashtableToRect();
73 | sourceSize = ((Hashtable)table["sourceSize"]).TPHashtableToVector2();
74 | rotated = (bool)table["rotated"];
75 | trimmed = (bool)table["trimmed"];
76 | }
77 |
78 | public Mesh BuildBasicMesh(float scale, Color32 defaultColor){
79 | return BuildBasicMesh(scale, defaultColor, Quaternion.identity);
80 | }
81 |
82 | public Mesh BuildBasicMesh(float scale, Color32 defaultColor, Quaternion rotation){
83 | Mesh m = new Mesh();
84 | Vector3[] verts = new Vector3[4];
85 | Vector2[] uvs = new Vector2[4];
86 | Color32[] colors = new Color32[4];
87 |
88 | if(!rotated){
89 | verts[0] = new Vector3(frame.x,frame.y,0);
90 | verts[1] = new Vector3(frame.x,frame.y+frame.height,0);
91 | verts[2] = new Vector3(frame.x+frame.width,frame.y+frame.height,0);
92 | verts[3] = new Vector3(frame.x+frame.width,frame.y,0);
93 | }
94 | else{
95 | verts[0] = new Vector3(frame.x,frame.y,0);
96 | verts[1] = new Vector3(frame.x,frame.y+frame.width,0);
97 | verts[2] = new Vector3(frame.x+frame.height,frame.y+frame.width,0);
98 | verts[3] = new Vector3(frame.x+frame.height,frame.y,0);
99 | }
100 |
101 | uvs[0] = verts[0].TPVector3toVector2();
102 | uvs[1] = verts[1].TPVector3toVector2();
103 | uvs[2] = verts[2].TPVector3toVector2();
104 | uvs[3] = verts[3].TPVector3toVector2();
105 |
106 | for(int i = 0; i < uvs.Length; i++){
107 | uvs[i].x /= atlasSize.x;
108 | uvs[i].y /= atlasSize.y;
109 | uvs[i].y = 1.0f - uvs[i].y;
110 | }
111 |
112 | if(rotated){
113 | verts[3] = new Vector3(frame.x,frame.y,0);
114 | verts[0] = new Vector3(frame.x,frame.y+frame.height,0);
115 | verts[1] = new Vector3(frame.x+frame.width,frame.y+frame.height,0);
116 | verts[2] = new Vector3(frame.x+frame.width,frame.y,0);
117 | }
118 |
119 | //v-flip
120 | for(int i = 0; i < verts.Length; i++){
121 | verts[i].y = atlasSize.y - verts[i].y;
122 | }
123 |
124 | //original origin
125 | for(int i = 0; i < verts.Length; i++){
126 | verts[i].x -= frame.x - spriteSourceSize.x + (sourceSize.x/2.0f);
127 | verts[i].y -= (atlasSize.y - frame.y) - (sourceSize.y - spriteSourceSize.y) + (sourceSize.y/2.0f);
128 | }
129 |
130 | //scaler
131 | for(int i = 0; i < verts.Length; i++){
132 | verts[i] *= scale;
133 | }
134 |
135 | //rotator
136 | if(rotation != Quaternion.identity){
137 | for(int i = 0; i < verts.Length; i++){
138 | verts[i] = rotation * verts[i];
139 | }
140 | }
141 |
142 | for(int i = 0; i < colors.Length; i++){
143 | colors[i] = defaultColor;
144 | }
145 |
146 | m.vertices = verts;
147 | m.uv = uvs;
148 | m.colors32 = colors;
149 | m.triangles = new int[6]{0,3,1,1,3,2};
150 |
151 | m.RecalculateNormals();
152 | m.RecalculateBounds();
153 | m.name = name;
154 |
155 | return m;
156 | }
157 |
158 | public SpriteMetaData BuildBasicSprite(float scale, Color32 defaultColor){
159 | SpriteMetaData smd = new SpriteMetaData();
160 | Rect rect;
161 |
162 | if(!rotated){
163 | rect = this.frame;
164 | }
165 | else
166 | {
167 | rect = new Rect(frame.x,frame.y,frame.height,frame.width);
168 | }
169 |
170 | /* Look if frame is outside from texture */
171 | if( (frame.x + frame.width) > atlasSize.x || (frame.y + frame.height) > atlasSize.y ||
172 | (frame.x < 0 || frame.y < 0))
173 | {
174 | Debug.Log(this.name + " is outside from texture! Sprite is ignored!");
175 | smd.name = "IGNORE_SPRITE";
176 | return smd;
177 | }
178 |
179 | //calculate Height
180 | /* Example: Texture: 1000 Width x 500 height
181 | * Sprite.Recht(0,0,100,100) --> Sprite is on the bottom left
182 | */
183 | rect.y = atlasSize.y - frame.y - rect.height;
184 |
185 | smd.rect = rect;
186 | smd.alignment = (int)SpriteAlignment.Center;
187 | smd.name = name;
188 | smd.pivot = new Vector2(frame.width/2, frame.height/2);
189 |
190 | return smd;
191 | }
192 | }
193 |
194 | public class MetaData{
195 | public string image;
196 | public string format;
197 | public Vector2 size;
198 | public float scale;
199 | public string smartUpdate;
200 |
201 | public MetaData(Hashtable table){
202 | image = (string)table["image"];
203 | format = (string)table["format"];
204 | size = ((Hashtable)table["size"]).TPHashtableToVector2();
205 | scale = float.Parse(table["scale"].ToString());
206 | smartUpdate = (string)table["smartUpdate"];
207 | }
208 | }
209 |
210 | public static List ProcessToSprites(string text) {
211 | Hashtable table = text.hashtableFromJson();
212 | MetaData meta = new MetaData((Hashtable)table["meta"]);
213 | Hashtable frameTable = (Hashtable)table["frames"];
214 |
215 | List frames = new List();
216 | foreach(DictionaryEntry entry in frameTable) {
217 | frames.Add(new PackedFrame((string)entry.Key, meta.size, (Hashtable)entry.Value));
218 | }
219 | alphabatizeFramesByName( frames );
220 |
221 | List sprites = new List();
222 | for(int i = 0; i < frames.Count; i++){
223 | SpriteMetaData smd = frames[i].BuildBasicSprite( 0.01f, new Color32(128,128,128,128));
224 | if(smd.name.Equals("IGNORE_SPRITE")) {
225 | continue;
226 | }
227 | sprites.Add(smd);
228 | }
229 | return sprites;
230 | }
231 |
232 | static void alphabatizeFramesByName(List frames)
233 | {
234 | frames.Sort(delegate(PackedFrame a, PackedFrame b) {
235 | if (a.name == null && b.name == null) {
236 | return 0;
237 | }else if (a.name == null) {
238 | return -1;
239 | }else if (b.name == null) {
240 | return 1;
241 | }else {
242 | return a.name.CompareTo(b.name);
243 | }
244 | });
245 | }
246 |
247 | public static Mesh[] ProcessToMeshes(string text){
248 | return ProcessToMeshes(text, Quaternion.identity);
249 | }
250 |
251 | public static Mesh[] ProcessToMeshes(string text, Quaternion rotation){
252 | Hashtable table = text.hashtableFromJson();
253 |
254 | MetaData meta = new MetaData((Hashtable)table["meta"]);
255 |
256 | List frames = new List();
257 | Hashtable frameTable = (Hashtable)table["frames"];
258 |
259 | foreach(DictionaryEntry entry in frameTable){
260 | frames.Add(new PackedFrame((string)entry.Key, meta.size, (Hashtable)entry.Value));
261 | }
262 |
263 | List meshes = new List();
264 | for(int i = 0; i < frames.Count; i++){
265 | meshes.Add(frames[i].BuildBasicMesh(0.01f, new Color32(128,128,128,128), rotation));
266 | }
267 |
268 | return meshes.ToArray();
269 | }
270 |
271 | public static MetaData GetMetaData(string text){
272 | Hashtable table = text.hashtableFromJson();
273 | MetaData meta = new MetaData((Hashtable)table["meta"]);
274 |
275 | return meta;
276 | }
277 | }
278 |
279 | #endif
280 |
--------------------------------------------------------------------------------
/TexturePacker/Editor/TexturePackerImport.cs:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2013 Mitch Thompson
3 | Extended by Harald Lurger (2013) (Process to Sprites)
4 |
5 | Standard MIT License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 | */
13 |
14 | using UnityEngine;
15 | using UnityEditor;
16 | using System.Collections;
17 | using System.Collections.Generic;
18 | using System.Text;
19 | using System.IO;
20 |
21 | public static class TexturePackerImport{
22 |
23 | [MenuItem("Assets/TexturePacker/Process to Sprites")]
24 | static void ProcessToSprite(){
25 | TextAsset txt = (TextAsset)Selection.activeObject;
26 |
27 | string rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(txt));
28 | TexturePacker.MetaData meta = TexturePacker.GetMetaData(txt.text);
29 |
30 | List sprites = TexturePacker.ProcessToSprites(txt.text);
31 |
32 | string path = rootPath + "/" + meta.image;
33 |
34 | sprites = MaintainSpriteOrder(path, sprites, meta.image);
35 |
36 | TextureImporter texImp = AssetImporter.GetAtPath(path) as TextureImporter;
37 | texImp.spritesheet = sprites.ToArray();
38 | texImp.textureType = TextureImporterType.Sprite;
39 | texImp.spriteImportMode = SpriteImportMode.Multiple;
40 |
41 | AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate );
42 | }
43 |
44 | static List MaintainSpriteOrder(string path, List sprites, string imageName)
45 | {
46 | sprites = new List(sprites); // Work on a copy, method shouldn't have side-effects
47 | List orderedSprites = new List();
48 |
49 | Object[] existing = AssetDatabase.LoadAllAssetsAtPath(path);
50 |
51 | for (int i = 0; i < existing.Length; ++i)
52 | {
53 | Sprite existingSprite = existing[i] as Sprite;
54 |
55 | if (null != existingSprite)
56 | {
57 | int pickedIndex = FindSpriteFromListByName(sprites, existingSprite.name);
58 | if (-1 != pickedIndex)
59 | {
60 | orderedSprites.Add(sprites[pickedIndex]);
61 | sprites.RemoveAt(pickedIndex);
62 | }
63 | else
64 | {
65 | if (existingSprite.name != imageName) // Make sure not to add the spritesheet image itself
66 | {
67 | SpriteMetaData placeholder = new SpriteMetaData();
68 | placeholder.name = existingSprite.name;
69 | orderedSprites.Add(placeholder);
70 | Debug.LogWarning(existingSprite.name + " removed from spritesheet. Adding blank placeholder.");
71 | }
72 | }
73 | }
74 | else
75 | {
76 | if (null == existing[i] as Texture2D)
77 | Debug.LogWarning("Unexpected type " + existing[i]);
78 | }
79 | }
80 |
81 | orderedSprites.AddRange(sprites);
82 |
83 | return orderedSprites;
84 | }
85 |
86 | static int FindSpriteFromListByName(List spriteList, string name)
87 | {
88 | int index = -1;
89 |
90 | for (int i = 0; i < spriteList.Count; ++i)
91 | {
92 | if (spriteList[i].name == name)
93 | {
94 | index = i;
95 | break;
96 | }
97 | }
98 |
99 | return index;
100 | }
101 |
102 | [MenuItem("Assets/TexturePacker/Process to Meshes")]
103 | static Mesh[] ProcessToMeshes(){
104 | TextAsset txt = (TextAsset)Selection.activeObject;
105 |
106 | Quaternion rotation = Quaternion.identity;
107 | string pref = EditorPrefs.GetString("TexturePackerImporterFacing", "back");
108 |
109 | switch(pref){
110 | case "back":
111 | rotation = Quaternion.identity;
112 | break;
113 | case "forward":
114 | rotation = Quaternion.LookRotation(Vector3.back);
115 | break;
116 | case "up":
117 | rotation = Quaternion.LookRotation(Vector3.down, Vector3.forward);
118 | break;
119 | case "down":
120 | rotation = Quaternion.LookRotation(Vector3.up, Vector3.back);
121 | break;
122 | case "right":
123 | rotation = Quaternion.LookRotation(Vector3.left);
124 | break;
125 | case "left":
126 | rotation = Quaternion.LookRotation(Vector3.right);
127 | break;
128 | }
129 |
130 | Mesh[] meshes = TexturePacker.ProcessToMeshes(txt.text, rotation);
131 |
132 | string rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(txt));
133 |
134 | Directory.CreateDirectory(Application.dataPath + "/" + rootPath.Substring(7, rootPath.Length-7) + "/Meshes");
135 |
136 | Mesh[] returnMeshes = new Mesh[meshes.Length];
137 |
138 | int i = 0;
139 | foreach(Mesh m in meshes){
140 | string assetPath = rootPath + "/Meshes/" + Path.GetFileNameWithoutExtension(m.name) + ".asset";
141 | Mesh existingMesh = (Mesh)AssetDatabase.LoadAssetAtPath(assetPath, typeof(Mesh));
142 | if(existingMesh == null){
143 | AssetDatabase.CreateAsset(m, assetPath);
144 | existingMesh = (Mesh)AssetDatabase.LoadAssetAtPath(assetPath, typeof(Mesh));
145 | }
146 | else{
147 | existingMesh.triangles = new int[0];
148 | existingMesh.colors32 = new Color32[0];
149 | existingMesh.uv = new Vector2[0];
150 | existingMesh.vertices = m.vertices;
151 | existingMesh.uv = m.uv;
152 | existingMesh.colors32 = m.colors32;
153 | existingMesh.triangles = m.triangles;
154 | existingMesh.RecalculateNormals();
155 | existingMesh.RecalculateBounds();
156 | EditorUtility.SetDirty(existingMesh);
157 | Mesh.DestroyImmediate(m);
158 | }
159 |
160 | returnMeshes[i] = existingMesh;
161 | i++;
162 | }
163 |
164 | return returnMeshes;
165 | }
166 |
167 | [MenuItem("Assets/TexturePacker/Process to Prefabs")]
168 | static void ProcessToPrefabs(){
169 | Mesh[] meshes = ProcessToMeshes();
170 |
171 | TextAsset txt = (TextAsset)Selection.activeObject;
172 | string rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(txt));
173 |
174 | string prefabPath = rootPath.Substring(7, rootPath.Length-7) + "/Prefabs";
175 | Directory.CreateDirectory(Application.dataPath + "/" + prefabPath);
176 |
177 | prefabPath = "Assets/" + prefabPath;
178 |
179 | //make material
180 | TexturePacker.MetaData meta = TexturePacker.GetMetaData(txt.text);
181 |
182 | string matPath = rootPath + "/" + (Path.GetFileNameWithoutExtension(meta.image) + ".mat");
183 | string texturePath = rootPath + "/" + meta.image;
184 | Material mat = (Material)AssetDatabase.LoadAssetAtPath(matPath, typeof(Material));
185 | if(mat == null){
186 | mat = new Material(Shader.Find("Sprites/Transparent Unlit"));
187 | Texture2D tex = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D));
188 | if(tex == null){
189 | EditorUtility.DisplayDialog("Error!", "Texture " + meta.image + " not found!", "Ok");
190 | }
191 | mat.mainTexture = tex;
192 | AssetDatabase.CreateAsset(mat, matPath);
193 | }
194 |
195 | AssetDatabase.Refresh();
196 |
197 | for(int i = 0; i < meshes.Length; i++){
198 | string prefabFilePath = prefabPath + "/" + meshes[i].name + ".prefab";
199 |
200 | bool createdNewPrefab = false;
201 | Object prefab = AssetDatabase.LoadAssetAtPath(prefabFilePath, typeof(Object));
202 |
203 | if(prefab == null){
204 | prefab = PrefabUtility.CreateEmptyPrefab(prefabFilePath);
205 | createdNewPrefab = true;
206 | }
207 |
208 | if(createdNewPrefab){
209 | GameObject go = new GameObject(meshes[i].name, typeof(MeshRenderer), typeof(MeshFilter));
210 | go.GetComponent().sharedMesh = meshes[i];
211 | go.renderer.sharedMaterial = mat;
212 |
213 | PrefabUtility.ReplacePrefab(go, prefab, ReplacePrefabOptions.ConnectToPrefab);
214 |
215 | GameObject.DestroyImmediate(go);
216 | }
217 | else{
218 | GameObject pgo = (GameObject)prefab;
219 | pgo.renderer.sharedMaterial = mat;
220 | pgo.GetComponent().sharedMesh = meshes[i];
221 | EditorUtility.SetDirty(pgo);
222 | }
223 | }
224 | }
225 |
226 | //Validators
227 | [MenuItem("Assets/TexturePacker/Process to Prefabs", true)]
228 | [MenuItem("Assets/TexturePacker/Process to Meshes", true)]
229 | [MenuItem("Assets/TexturePacker/Process to Sprites", true)]
230 | static bool ValidateProcessTexturePacker(){
231 | Object o = Selection.activeObject;
232 |
233 | if(o == null)
234 | return false;
235 |
236 | if(o.GetType() == typeof(TextAsset)){
237 | return (((TextAsset)o).text.hashtableFromJson()).IsTexturePackerTable();
238 | }
239 |
240 | return false;
241 | }
242 |
243 | //Attach 90 degree "Shadow" meshes
244 | [MenuItem("Assets/TexturePacker/Attach Shadow Mesh")]
245 | static void AttachShadowMesh(){
246 | List meshes = new List();
247 | foreach(Object o in Selection.objects){
248 | if(o is Mesh) meshes.Add(o as Mesh);
249 | }
250 |
251 | foreach(Mesh m in meshes){
252 | Vector3[] verts = new Vector3[m.vertexCount*2];
253 | Vector2[] uvs = new Vector2[m.vertexCount*2];
254 | Color32[] colors = new Color32[m.vertexCount*2];
255 | int[] triangles = new int[m.triangles.Length * 2];
256 |
257 | System.Array.Copy(m.vertices, 0, verts, m.vertexCount, m.vertexCount);
258 | System.Array.Copy(m.uv, 0, uvs, m.vertexCount, m.vertexCount);
259 | System.Array.Copy(m.colors32, 0, colors, m.vertexCount, m.vertexCount);
260 | System.Array.Copy(m.triangles, 0, triangles, m.triangles.Length, m.triangles.Length);
261 |
262 | for(int i = 0; i < m.vertexCount; i++){
263 | verts[i].x = verts[i+m.vertexCount].x;
264 | verts[i].y = verts[i+m.vertexCount].z;
265 | verts[i].z = verts[i+m.vertexCount].y;
266 |
267 | uvs[i] = uvs[i+m.vertexCount];
268 | colors[i] = new Color32(0,0,0,64);
269 |
270 |
271 | }
272 |
273 | for(int i = 0; i < m.triangles.Length; i++){
274 | triangles[i] = triangles[i + m.triangles.Length];
275 | triangles[i + m.triangles.Length] += m.vertexCount;
276 |
277 | }
278 |
279 | m.vertices = verts;
280 | m.uv = uvs;
281 | m.colors32 = colors;
282 | m.triangles = triangles;
283 |
284 | m.RecalculateNormals();
285 | m.RecalculateBounds();
286 | EditorUtility.SetDirty(m);
287 | }
288 | }
289 |
290 | //Validators
291 | [MenuItem("Assets/TexturePacker/Attach Shadow Mesh", true)]
292 | static bool ValidateAttachShadowMesh(){
293 | Object[] objs = Selection.objects;
294 | foreach(Object o in objs){
295 | if(!(o is Mesh)){
296 | return false;
297 | }
298 | }
299 |
300 | return true;
301 | }
302 |
303 | //Options
304 | [MenuItem("Assets/TexturePacker/Facing/Back")]
305 | static void SetFacingBack(){ EditorPrefs.SetString("TexturePackerImporterFacing", "back"); }
306 |
307 | [MenuItem("Assets/TexturePacker/Facing/Forward")]
308 | static void SetFacingForward(){ EditorPrefs.SetString("TexturePackerImporterFacing", "forward"); }
309 |
310 | [MenuItem("Assets/TexturePacker/Facing/Up")]
311 | static void SetFacingUp(){ EditorPrefs.SetString("TexturePackerImporterFacing", "up"); }
312 |
313 | [MenuItem("Assets/TexturePacker/Facing/Down")]
314 | static void SetFacingDown(){ EditorPrefs.SetString("TexturePackerImporterFacing", "down"); }
315 |
316 | [MenuItem("Assets/TexturePacker/Facing/Right")]
317 | static void SetFacingRight(){ EditorPrefs.SetString("TexturePackerImporterFacing", "right"); }
318 |
319 | [MenuItem("Assets/TexturePacker/Facing/Left")]
320 | static void SetFacingLeft(){ EditorPrefs.SetString("TexturePackerImporterFacing", "left"); }
321 | }
322 |
--------------------------------------------------------------------------------
/TexturePacker/Plugins/MiniJSON.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Text;
4 | using System.Collections.Generic;
5 | using UnityEngine;
6 |
7 | /* Based on the JSON parser from
8 | * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html
9 | *
10 | * I simplified it so that it doesn't throw exceptions
11 | * and can be used in Unity iPhone with maximum code stripping.
12 | *
13 | * Additional:
14 | * Modified by Mitch Thompson to output new-line formatting to make things more readable
15 | * Also modified to parse all numbers to float or single instead of double
16 | * Also modified to support float Infinity (defaults to Positive Infinity)
17 | */
18 | ///
19 | /// This class encodes and decodes JSON strings.
20 | /// Spec. details, see http://www.json.org/
21 | ///
22 | /// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable.
23 | /// All numbers are parsed to doubles.
24 | ///
25 | public class MiniJSON
26 | {
27 | private const int TOKEN_NONE = 0;
28 | private const int TOKEN_CURLY_OPEN = 1;
29 | private const int TOKEN_CURLY_CLOSE = 2;
30 | private const int TOKEN_SQUARED_OPEN = 3;
31 | private const int TOKEN_SQUARED_CLOSE = 4;
32 | private const int TOKEN_COLON = 5;
33 | private const int TOKEN_COMMA = 6;
34 | private const int TOKEN_STRING = 7;
35 | private const int TOKEN_NUMBER = 8;
36 | private const int TOKEN_TRUE = 9;
37 | private const int TOKEN_FALSE = 10;
38 | private const int TOKEN_NULL = 11;
39 | //added token for infinity
40 | private const int TOKEN_INFINITY = 12;
41 | private const int BUILDER_CAPACITY = 2000;
42 |
43 | ///
44 | /// On decoding, this value holds the position at which the parse failed (-1 = no error).
45 | ///
46 | protected static int lastErrorIndex = -1;
47 | protected static string lastDecode = "";
48 |
49 |
50 | ///
51 | /// Parses the string json into a value
52 | ///
53 | /// A JSON string.
54 | /// An ArrayList, a Hashtable, a double, a string, null, true, or false
55 | public static object jsonDecode( string json )
56 | {
57 | // save the string for debug information
58 | MiniJSON.lastDecode = json;
59 |
60 | if( json != null )
61 | {
62 | char[] charArray = json.ToCharArray();
63 | int index = 0;
64 | bool success = true;
65 | object value = MiniJSON.parseValue( charArray, ref index, ref success );
66 |
67 | if( success )
68 | MiniJSON.lastErrorIndex = -1;
69 | else
70 | MiniJSON.lastErrorIndex = index;
71 |
72 | return value;
73 | }
74 | else
75 | {
76 | return null;
77 | }
78 | }
79 |
80 |
81 | ///
82 | /// Converts a Hashtable / ArrayList / Dictionary(string,string) object into a JSON string
83 | ///
84 | /// A Hashtable / ArrayList
85 | /// A JSON encoded string, or null if object 'json' is not serializable
86 | public static string jsonEncode( object json )
87 | {
88 | indentLevel = 0;
89 | var builder = new StringBuilder( BUILDER_CAPACITY );
90 | var success = MiniJSON.serializeValue( json, builder );
91 |
92 | return ( success ? builder.ToString() : null );
93 | }
94 |
95 |
96 | ///
97 | /// On decoding, this function returns the position at which the parse failed (-1 = no error).
98 | ///
99 | ///
100 | public static bool lastDecodeSuccessful()
101 | {
102 | return ( MiniJSON.lastErrorIndex == -1 );
103 | }
104 |
105 |
106 | ///
107 | /// On decoding, this function returns the position at which the parse failed (-1 = no error).
108 | ///
109 | ///
110 | public static int getLastErrorIndex()
111 | {
112 | return MiniJSON.lastErrorIndex;
113 | }
114 |
115 |
116 | ///
117 | /// If a decoding error occurred, this function returns a piece of the JSON string
118 | /// at which the error took place. To ease debugging.
119 | ///
120 | ///
121 | public static string getLastErrorSnippet()
122 | {
123 | if( MiniJSON.lastErrorIndex == -1 )
124 | {
125 | return "";
126 | }
127 | else
128 | {
129 | int startIndex = MiniJSON.lastErrorIndex - 5;
130 | int endIndex = MiniJSON.lastErrorIndex + 15;
131 | if( startIndex < 0 )
132 | startIndex = 0;
133 |
134 | if( endIndex >= MiniJSON.lastDecode.Length )
135 | endIndex = MiniJSON.lastDecode.Length - 1;
136 |
137 | return MiniJSON.lastDecode.Substring( startIndex, endIndex - startIndex + 1 );
138 | }
139 | }
140 |
141 |
142 | #region Parsing
143 |
144 | protected static Hashtable parseObject( char[] json, ref int index )
145 | {
146 | Hashtable table = new Hashtable();
147 | int token;
148 |
149 | // {
150 | nextToken( json, ref index );
151 |
152 | bool done = false;
153 | while( !done )
154 | {
155 | token = lookAhead( json, index );
156 | if( token == MiniJSON.TOKEN_NONE )
157 | {
158 | return null;
159 | }
160 | else if( token == MiniJSON.TOKEN_COMMA )
161 | {
162 | nextToken( json, ref index );
163 | }
164 | else if( token == MiniJSON.TOKEN_CURLY_CLOSE )
165 | {
166 | nextToken( json, ref index );
167 | return table;
168 | }
169 | else
170 | {
171 | // name
172 | string name = parseString( json, ref index );
173 | if( name == null )
174 | {
175 | return null;
176 | }
177 |
178 | // :
179 | token = nextToken( json, ref index );
180 | if( token != MiniJSON.TOKEN_COLON )
181 | return null;
182 |
183 | // value
184 | bool success = true;
185 | object value = parseValue( json, ref index, ref success );
186 | if( !success )
187 | return null;
188 |
189 | table[name] = value;
190 | }
191 | }
192 |
193 | return table;
194 | }
195 |
196 |
197 | protected static ArrayList parseArray( char[] json, ref int index )
198 | {
199 | ArrayList array = new ArrayList();
200 |
201 | // [
202 | nextToken( json, ref index );
203 |
204 | bool done = false;
205 | while( !done )
206 | {
207 | int token = lookAhead( json, index );
208 | if( token == MiniJSON.TOKEN_NONE )
209 | {
210 | return null;
211 | }
212 | else if( token == MiniJSON.TOKEN_COMMA )
213 | {
214 | nextToken( json, ref index );
215 | }
216 | else if( token == MiniJSON.TOKEN_SQUARED_CLOSE )
217 | {
218 | nextToken( json, ref index );
219 | break;
220 | }
221 | else
222 | {
223 | bool success = true;
224 | object value = parseValue( json, ref index, ref success );
225 | if( !success )
226 | return null;
227 |
228 | array.Add( value );
229 | }
230 | }
231 |
232 | return array;
233 | }
234 |
235 |
236 | protected static object parseValue( char[] json, ref int index, ref bool success )
237 | {
238 | switch( lookAhead( json, index ) )
239 | {
240 | case MiniJSON.TOKEN_STRING:
241 | return parseString( json, ref index );
242 | case MiniJSON.TOKEN_NUMBER:
243 | return parseNumber( json, ref index );
244 | case MiniJSON.TOKEN_CURLY_OPEN:
245 | return parseObject( json, ref index );
246 | case MiniJSON.TOKEN_SQUARED_OPEN:
247 | return parseArray( json, ref index );
248 | case MiniJSON.TOKEN_TRUE:
249 | nextToken( json, ref index );
250 | return Boolean.Parse( "TRUE" );
251 | case MiniJSON.TOKEN_FALSE:
252 | nextToken( json, ref index );
253 | return Boolean.Parse( "FALSE" );
254 | case MiniJSON.TOKEN_NULL:
255 | nextToken( json, ref index );
256 | return null;
257 | case MiniJSON.TOKEN_INFINITY:
258 | nextToken( json, ref index );
259 | return float.PositiveInfinity;
260 | case MiniJSON.TOKEN_NONE:
261 | break;
262 | }
263 |
264 | success = false;
265 | return null;
266 | }
267 |
268 |
269 | protected static string parseString( char[] json, ref int index )
270 | {
271 | string s = "";
272 | char c;
273 |
274 | eatWhitespace( json, ref index );
275 |
276 | // "
277 | c = json[index++];
278 |
279 | bool complete = false;
280 | while( !complete )
281 | {
282 | if( index == json.Length )
283 | break;
284 |
285 | c = json[index++];
286 | if( c == '"' )
287 | {
288 | complete = true;
289 | break;
290 | }
291 | else if( c == '\\' )
292 | {
293 | if( index == json.Length )
294 | break;
295 |
296 | c = json[index++];
297 | if( c == '"' )
298 | {
299 | s += '"';
300 | }
301 | else if( c == '\\' )
302 | {
303 | s += '\\';
304 | }
305 | else if( c == '/' )
306 | {
307 | s += '/';
308 | }
309 | else if( c == 'b' )
310 | {
311 | s += '\b';
312 | }
313 | else if( c == 'f' )
314 | {
315 | s += '\f';
316 | }
317 | else if( c == 'n' )
318 | {
319 | s += '\n';
320 | }
321 | else if( c == 'r' )
322 | {
323 | s += '\r';
324 | }
325 | else if( c == 't' )
326 | {
327 | s += '\t';
328 | }
329 | else if( c == 'u' )
330 | {
331 | int remainingLength = json.Length - index;
332 | if( remainingLength >= 4 )
333 | {
334 | char[] unicodeCharArray = new char[4];
335 | Array.Copy( json, index, unicodeCharArray, 0, 4 );
336 |
337 | // Drop in the HTML markup for the unicode character
338 | s += "" + new string( unicodeCharArray ) + ";";
339 |
340 | /*
341 | uint codePoint = UInt32.Parse(new string(unicodeCharArray), NumberStyles.HexNumber);
342 | // convert the integer codepoint to a unicode char and add to string
343 | s += Char.ConvertFromUtf32((int)codePoint);
344 | */
345 |
346 | // skip 4 chars
347 | index += 4;
348 | }
349 | else
350 | {
351 | break;
352 | }
353 |
354 | }
355 | }
356 | else
357 | {
358 | s += c;
359 | }
360 |
361 | }
362 |
363 | if( !complete )
364 | return null;
365 |
366 | return s;
367 | }
368 |
369 |
370 | protected static float parseNumber( char[] json, ref int index )
371 | {
372 | eatWhitespace( json, ref index );
373 |
374 | int lastIndex = getLastIndexOfNumber( json, index );
375 | int charLength = ( lastIndex - index ) + 1;
376 | char[] numberCharArray = new char[charLength];
377 |
378 | Array.Copy( json, index, numberCharArray, 0, charLength );
379 | index = lastIndex + 1;
380 | return float.Parse( new string( numberCharArray ) ); // , CultureInfo.InvariantCulture);
381 | }
382 |
383 |
384 | protected static int getLastIndexOfNumber( char[] json, int index )
385 | {
386 | int lastIndex;
387 | for( lastIndex = index; lastIndex < json.Length; lastIndex++ )
388 | if( "0123456789+-.eE".IndexOf( json[lastIndex] ) == -1 )
389 | {
390 | break;
391 | }
392 | return lastIndex - 1;
393 | }
394 |
395 |
396 | protected static void eatWhitespace( char[] json, ref int index )
397 | {
398 | for( ; index < json.Length; index++ )
399 | if( " \t\n\r".IndexOf( json[index] ) == -1 )
400 | {
401 | break;
402 | }
403 | }
404 |
405 |
406 | protected static int lookAhead( char[] json, int index )
407 | {
408 | int saveIndex = index;
409 | return nextToken( json, ref saveIndex );
410 | }
411 |
412 |
413 | protected static int nextToken( char[] json, ref int index )
414 | {
415 | eatWhitespace( json, ref index );
416 |
417 | if( index == json.Length )
418 | {
419 | return MiniJSON.TOKEN_NONE;
420 | }
421 |
422 | char c = json[index];
423 | index++;
424 | switch( c )
425 | {
426 | case '{':
427 | return MiniJSON.TOKEN_CURLY_OPEN;
428 | case '}':
429 | return MiniJSON.TOKEN_CURLY_CLOSE;
430 | case '[':
431 | return MiniJSON.TOKEN_SQUARED_OPEN;
432 | case ']':
433 | return MiniJSON.TOKEN_SQUARED_CLOSE;
434 | case ',':
435 | return MiniJSON.TOKEN_COMMA;
436 | case '"':
437 | return MiniJSON.TOKEN_STRING;
438 | case '0':
439 | case '1':
440 | case '2':
441 | case '3':
442 | case '4':
443 | case '5':
444 | case '6':
445 | case '7':
446 | case '8':
447 | case '9':
448 | case '-':
449 | return MiniJSON.TOKEN_NUMBER;
450 | case ':':
451 | return MiniJSON.TOKEN_COLON;
452 | }
453 | index--;
454 |
455 | int remainingLength = json.Length - index;
456 |
457 | // Infinity
458 | if( remainingLength >= 8 )
459 | {
460 | if( json[index] == 'I' &&
461 | json[index + 1] == 'n' &&
462 | json[index + 2] == 'f' &&
463 | json[index + 3] == 'i' &&
464 | json[index + 4] == 'n' &&
465 | json[index + 5] == 'i' &&
466 | json[index + 6] == 't' &&
467 | json[index + 7] == 'y' )
468 | {
469 | index += 8;
470 | return MiniJSON.TOKEN_INFINITY;
471 | }
472 | }
473 |
474 | // false
475 | if( remainingLength >= 5 )
476 | {
477 | if( json[index] == 'f' &&
478 | json[index + 1] == 'a' &&
479 | json[index + 2] == 'l' &&
480 | json[index + 3] == 's' &&
481 | json[index + 4] == 'e' )
482 | {
483 | index += 5;
484 | return MiniJSON.TOKEN_FALSE;
485 | }
486 | }
487 |
488 | // true
489 | if( remainingLength >= 4 )
490 | {
491 | if( json[index] == 't' &&
492 | json[index + 1] == 'r' &&
493 | json[index + 2] == 'u' &&
494 | json[index + 3] == 'e' )
495 | {
496 | index += 4;
497 | return MiniJSON.TOKEN_TRUE;
498 | }
499 | }
500 |
501 | // null
502 | if( remainingLength >= 4 )
503 | {
504 | if( json[index] == 'n' &&
505 | json[index + 1] == 'u' &&
506 | json[index + 2] == 'l' &&
507 | json[index + 3] == 'l' )
508 | {
509 | index += 4;
510 | return MiniJSON.TOKEN_NULL;
511 | }
512 | }
513 |
514 | return MiniJSON.TOKEN_NONE;
515 | }
516 |
517 | #endregion
518 |
519 |
520 | #region Serialization
521 |
522 | protected static bool serializeObjectOrArray( object objectOrArray, StringBuilder builder )
523 | {
524 | if( objectOrArray is Hashtable )
525 | {
526 | return serializeObject( (Hashtable)objectOrArray, builder );
527 | }
528 | else if( objectOrArray is ArrayList )
529 | {
530 | return serializeArray( (ArrayList)objectOrArray, builder );
531 | }
532 | else
533 | {
534 | return false;
535 | }
536 | }
537 |
538 | protected static int indentLevel = 0;
539 | protected static bool serializeObject( Hashtable anObject, StringBuilder builder )
540 | {
541 |
542 | indentLevel++;
543 | string indentString = "";
544 | for(int i = 0; i < indentLevel; i++)
545 | indentString += "\t";
546 |
547 | builder.Append( "{\n" + indentString );
548 |
549 |
550 |
551 | IDictionaryEnumerator e = anObject.GetEnumerator();
552 | bool first = true;
553 | while( e.MoveNext() )
554 | {
555 | string key = e.Key.ToString();
556 | object value = e.Value;
557 |
558 | if( !first )
559 | {
560 | builder.Append( ", \n" + indentString );
561 | }
562 |
563 | serializeString( key, builder );
564 | builder.Append( ":" );
565 | if( !serializeValue( value, builder ) )
566 | {
567 | return false;
568 | }
569 |
570 | first = false;
571 | }
572 |
573 |
574 | indentString = "";
575 | for(int i = 0; i < indentLevel-1; i++)
576 | indentString += "\t";
577 |
578 | builder.Append( "\n" + indentString + "}");
579 |
580 | indentLevel--;
581 | return true;
582 | }
583 |
584 |
585 | protected static bool serializeDictionary( Dictionary dict, StringBuilder builder )
586 | {
587 | builder.Append( "{" );
588 |
589 | bool first = true;
590 | foreach( var kv in dict )
591 | {
592 | if( !first )
593 | builder.Append( ", " );
594 |
595 | serializeString( kv.Key, builder );
596 | builder.Append( ":" );
597 | serializeString( kv.Value, builder );
598 |
599 | first = false;
600 | }
601 |
602 | builder.Append( "}" );
603 | return true;
604 | }
605 |
606 |
607 | protected static bool serializeArray( ArrayList anArray, StringBuilder builder )
608 | {
609 | indentLevel++;
610 | string indentString = "";
611 | for(int i = 0; i < indentLevel; i++)
612 | indentString += "\t";
613 |
614 | builder.Append( "[\n" + indentString );
615 | // builder.Append( "[" );
616 |
617 |
618 |
619 |
620 |
621 | bool first = true;
622 | for( int i = 0; i < anArray.Count; i++ )
623 | {
624 | object value = anArray[i];
625 |
626 | if( !first )
627 | {
628 | builder.Append( ", \n" + indentString );
629 | }
630 |
631 | if( !serializeValue( value, builder ) )
632 | {
633 | return false;
634 | }
635 |
636 | first = false;
637 | }
638 |
639 |
640 |
641 | indentString = "";
642 | for(int i = 0; i < indentLevel-1; i++)
643 | indentString += "\t";
644 |
645 | builder.Append( "\n" + indentString + "]");
646 |
647 | indentLevel--;
648 |
649 | return true;
650 | }
651 |
652 |
653 | protected static bool serializeValue( object value, StringBuilder builder )
654 | {
655 | // Type t = value.GetType();
656 | // Debug.Log("type: " + t.ToString() + " isArray: " + t.IsArray);
657 |
658 | if( value == null )
659 | {
660 | builder.Append( "null" );
661 | }
662 | else if( value.GetType().IsArray )
663 | {
664 | serializeArray( new ArrayList( (ICollection)value ), builder );
665 | }
666 | else if( value is string )
667 | {
668 | serializeString( (string)value, builder );
669 | }
670 | else if( value is Char )
671 | {
672 | serializeString( Convert.ToString( (char)value ), builder );
673 | }
674 | else if( value is Hashtable )
675 | {
676 | serializeObject( (Hashtable)value, builder );
677 | }
678 | else if( value is Dictionary )
679 | {
680 | serializeDictionary( (Dictionary)value, builder );
681 | }
682 | else if( value is ArrayList )
683 | {
684 | serializeArray( (ArrayList)value, builder );
685 | }
686 | else if( ( value is Boolean ) && ( (Boolean)value == true ) )
687 | {
688 | builder.Append( "true" );
689 | }
690 | else if( ( value is Boolean ) && ( (Boolean)value == false ) )
691 | {
692 | builder.Append( "false" );
693 | }
694 | else if( value.GetType().IsPrimitive )
695 | {
696 | serializeNumber( Convert.ToSingle( value ), builder );
697 | }
698 | else
699 | {
700 | return false;
701 | }
702 |
703 | return true;
704 | }
705 |
706 |
707 | protected static void serializeString( string aString, StringBuilder builder )
708 | {
709 | builder.Append( "\"" );
710 |
711 | char[] charArray = aString.ToCharArray();
712 | for( int i = 0; i < charArray.Length; i++ )
713 | {
714 | char c = charArray[i];
715 | if( c == '"' )
716 | {
717 | builder.Append( "\\\"" );
718 | }
719 | else if( c == '\\' )
720 | {
721 | builder.Append( "\\\\" );
722 | }
723 | else if( c == '\b' )
724 | {
725 | builder.Append( "\\b" );
726 | }
727 | else if( c == '\f' )
728 | {
729 | builder.Append( "\\f" );
730 | }
731 | else if( c == '\n' )
732 | {
733 | builder.Append( "\\n" );
734 | }
735 | else if( c == '\r' )
736 | {
737 | builder.Append( "\\r" );
738 | }
739 | else if( c == '\t' )
740 | {
741 | builder.Append( "\\t" );
742 | }
743 | else
744 | {
745 | int codepoint = Convert.ToInt32( c );
746 | if( ( codepoint >= 32 ) && ( codepoint <= 126 ) )
747 | {
748 | builder.Append( c );
749 | }
750 | else
751 | {
752 | builder.Append( "\\u" + Convert.ToString( codepoint, 16 ).PadLeft( 4, '0' ) );
753 | }
754 | }
755 | }
756 |
757 | builder.Append( "\"" );
758 | }
759 |
760 |
761 | protected static void serializeNumber( float number, StringBuilder builder )
762 | {
763 | builder.Append( Convert.ToString( number ) ); // , CultureInfo.InvariantCulture));
764 | }
765 |
766 | #endregion
767 |
768 | }
769 |
770 |
771 |
772 | #region Extension methods
773 |
774 | public static class MiniJsonExtensions
775 | {
776 | public static string toJson( this Hashtable obj )
777 | {
778 | return MiniJSON.jsonEncode( obj );
779 | }
780 |
781 | public static string toJson( this Dictionary obj )
782 | {
783 | return MiniJSON.jsonEncode( obj );
784 | }
785 |
786 |
787 | public static ArrayList arrayListFromJson( this string json )
788 | {
789 | return MiniJSON.jsonDecode( json ) as ArrayList;
790 | }
791 |
792 |
793 | public static Hashtable hashtableFromJson( this string json )
794 | {
795 | return MiniJSON.jsonDecode( json ) as Hashtable;
796 | }
797 | }
798 |
799 | #endregion
800 |
--------------------------------------------------------------------------------