├── .gitignore ├── .gitmodules ├── Dockerfile ├── README.md ├── build_cube.sh ├── build_materials.sh ├── config.ld ├── control ├── doc ├── index.html ├── ldoc.css └── modules │ ├── LuaScene.html │ ├── sk_animation.html │ ├── sk_definition_writer.html │ ├── sk_input.html │ ├── sk_math.html │ ├── sk_mesh.html │ ├── sk_scene.html │ ├── sk_transform.html │ └── vector3.html ├── examples ├── cube.h ├── cube.obj ├── cube_geo.c ├── image.png ├── materials.h ├── materials.skm.yaml └── materials_mat.c ├── lua ├── sk_animation.lua ├── sk_definition_writer.lua ├── sk_math.lua └── sk_scene.lua ├── main.cpp ├── makefile ├── schema └── material-schema.json ├── schema_docs ├── index.html ├── schema_doc.css └── schema_doc.min.js ├── setup_dependencies.sh └── src ├── BoneHierarchy.cpp ├── BoneHierarchy.h ├── CFileDefinition.cpp ├── CFileDefinition.h ├── CommandLineParser.cpp ├── CommandLineParser.h ├── DisplayList.cpp ├── DisplayList.h ├── DisplayListGenerator.cpp ├── DisplayListGenerator.h ├── DisplayListSettings.cpp ├── DisplayListSettings.h ├── Enum.h ├── ErrorCode.h ├── ErrorResult.cpp ├── ErrorResult.h ├── ExtendedMesh.cpp ├── ExtendedMesh.h ├── FileUtils.cpp ├── FileUtils.h ├── MathUtil.cpp ├── MathUtl.h ├── MeshWriter.cpp ├── MeshWriter.h ├── RCPState.cpp ├── RCPState.h ├── RenderChunk.cpp ├── RenderChunk.h ├── RenderChunkOrder.cpp ├── RenderChunkOrder.h ├── SceneLoader.cpp ├── SceneLoader.h ├── SceneModification.cpp ├── SceneModification.h ├── SceneWriter.cpp ├── SceneWriter.h ├── StringUtils.h ├── StringUtls.cpp ├── definition_generator ├── AnimationGenerator.cpp ├── AnimationGenerator.h ├── CollisionGenerator.cpp ├── CollisionGenerator.h ├── CollisionQuad.cpp ├── CollisionQuad.h ├── DefinitionGenerator.cpp ├── DefinitionGenerator.h ├── MaterialGenerator.cpp ├── MaterialGenerator.h ├── MeshDefinitionGenerator.cpp └── MeshDefinitionGenerator.h ├── definitions ├── DataChunk.cpp ├── DataChunk.h ├── FileDefinition.cpp └── FileDefinition.h ├── lua_generator ├── LuaBasicTypes.cpp ├── LuaBasicTypes.h ├── LuaDefinitionWriter.cpp ├── LuaDefinitionWriter.h ├── LuaDisplayListSettings.cpp ├── LuaDisplayListSettings.h ├── LuaFiles.h ├── LuaGenerator.cpp ├── LuaGenerator.h ├── LuaGeometry.cpp ├── LuaGeometry.h ├── LuaMesh.cpp ├── LuaMesh.h ├── LuaNodeGroups.cpp ├── LuaNodeGroups.h ├── LuaScene.cpp ├── LuaScene.h ├── LuaTransform.cpp ├── LuaTransform.h ├── LuaUtils.cpp └── LuaUtils.h ├── materials ├── CImgu8.cpp ├── CImgu8.h ├── CombineMode.cpp ├── CombineMode.h ├── Material.cpp ├── Material.h ├── MaterialEnums.cpp ├── MaterialEnums.h ├── MaterialParser.cpp ├── MaterialParser.h ├── MaterialState.cpp ├── MaterialState.h ├── MaterialTransitionTiming.h ├── MaterialTranslator.cpp ├── MaterialTranslator.h ├── RenderMode.cpp ├── RenderMode.h ├── TextureCache.cpp ├── TextureCache.h ├── TextureDefinition.cpp ├── TextureDefinition.h ├── TextureFormats.cpp └── TextureFormats.h └── math ├── LeastSquares.cpp ├── LeastSquares.h ├── MES.cpp ├── MES.h ├── Vector4.cpp └── Vector4.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.d 3 | .vscode/ 4 | assimp/ 5 | cimg/ 6 | yaml-cpp/ 7 | output/ 8 | skeletool64 9 | dna.txt 10 | build/ 11 | images/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "yaml-cpp"] 2 | path = yaml-cpp 3 | url = https://github.com/jbeder/yaml-cpp.git 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:latest 2 | 3 | WORKDIR /usr/src/app 4 | 5 | RUN apt update 6 | RUN apt install -y libpng-dev libtiff-dev libassimp-dev git cmake build-essential wget unzip 7 | 8 | RUN git clone https://github.com/jbeder/yaml-cpp.git 9 | 10 | RUN cmake -S yaml-cpp -B yaml-cpp 11 | RUN make -C yaml-cpp 12 | 13 | RUN wget http://cimg.eu/files/CImg_latest.zip 14 | RUN unzip CImg_latest.zip 15 | RUN mv CImg-3.1.3_pre051622 cimg 16 | 17 | COPY src src 18 | COPY main.cpp main.cpp 19 | COPY makefile makefile 20 | 21 | CMD make -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Skeletool64 2 | 3 | Converts various 3d formats to a N64 display list. Will support skeletal animation 4 | 5 | # pre requisites to build 6 | 7 | libpng libtiff libassimp-dev 8 | 9 | # how to install with apt 10 | 11 | ``` 12 | echo "deb [trusted=yes] https://lambertjamesd.github.io/apt/ ./" | tee /etc/apt/sources.list.d/lambertjamesd.list 13 | sudo apt install skeletool64 14 | ``` 15 | 16 | ## how to use 17 | 18 | 'skeletool64 path/to/input/file.obj -o path/to/output.h` 19 | 20 | The file formats located here [https://assimp.sourceforge.net/main_features_formats.html](https://assimp.sourceforge.net/main_features_formats.html) are supported, though not all are tested 21 | 22 | will take the input model file and convert it to a header file with accompanying c file `path/to/ouptut_geo.c` 23 | 24 | Here some command line arguments 25 | 26 | | Argument | Argument Type | Description | 27 | |----------|--------|-------------| 28 | | -o | filename | where to write the output | 29 | | --name | string | The name to prefix all c definitions with | 30 | | --fixed-point-scale | number | Scales all geometry by the given number when converting from floating point to fixed point geometry defaults to 256 | 31 | | --model-scale | number | used to scale all geometry defaults to 1 | 32 | | -m | filename | used to add a materials yaml or json file more details about how materials works below. You can add mulitple material files. You can also specify a 3d model as a material source and all materials from the file will be included. | 33 | | --material-output | | if present only materials are generated instead of geometry | 34 | | -r | number,number,number | a set of euler angles used to rotate the model | 35 | | --default-material | string | the name of the material that is expected to be active when rendering this model. This is useful to reduce needed state changes between default state and the state needed to render the model defaults to `default` | 36 | | --force-material | string | if present all geometry uses the given material | 37 | 38 | ## materials 39 | 40 | skeletool64 will attempt to automatically create materials. You can override any material by name by adding them to a materials yaml file. You can find the schema for a material file here [schema/material-schema.json](schema/material-schema.json). When a material is specified by name in a materials file it will replace any materials in 3d files with the same name. An example of a materials file 41 | 42 | ``` 43 | materials: 44 | default: 45 | gDPSetRenderMode: G_RM_ZB_OPA_SURF 46 | gDPSetTextureFilter: G_TF_BILERP 47 | gDPSetTexturePersp: G_TP_PERSP 48 | gDPSetCycleType: G_CYC_1CYCLE 49 | gDPSetAlphaCompare: G_AC_NONE 50 | gSPGeometryMode: 51 | set: [G_CULL_BACK, G_ZBUFFER] 52 | clear: [G_CULL_FRONT, G_TEXTURE_GEN, G_TEXTURE_GEN_LINEAR] 53 | 54 | button_base_black: 55 | gDPSetPrimColor: 56 | r: 32 57 | g: 32 58 | b: 32 59 | gSPGeometryMode: 60 | set: [G_LIGHTING, G_SHADE] 61 | gDPSetCombineMode: 62 | color: ["PRIMITIVE", "0", "SHADE", "0"] 63 | 64 | awe_total: 65 | gDPSetTile: 66 | filename: ../../portal_pak_modified/materials/models/props_animsigns/awe_total.png 67 | siz: G_IM_SIZ_4b 68 | fmt: G_IM_FMT_I 69 | 70 | gDPSetRenderMode: G_RM_ZB_OPA_DECAL 71 | 72 | gSPGeometryMode: 73 | clear: [G_LIGHTING] 74 | set: [G_SHADE] 75 | gDPSetCombineMode: 76 | color: [SHADE, PRIMITIVE, TEXEL0, PRIMITIVE] 77 | gDPSetPrimColor: 78 | r: 242 79 | g: 245 80 | b: 247 81 | gDPSetCycleType: G_CYC_1CYCLE 82 | 83 | cube_fizzled: 84 | gDPSetTile: 85 | filename: 86 | ../images/cube.png 87 | siz: G_IM_SIZ_16b 88 | fmt: G_IM_FMT_RGBA 89 | s: 90 | mirror: true 91 | t: 92 | mirror: true 93 | 94 | gDPSetRenderMode: 95 | - blend: ["G_BL_CLR_IN", "G_BL_A_IN", "G_BL_CLR_FOG", "G_BL_1MA"] 96 | - G_RM_ZB_XLU_SURF 97 | 98 | gDPSetCycleType: G_CYC_2CYCLE 99 | gSPGeometryMode: 100 | set: [G_LIGHTING, G_SHADE] 101 | gDPSetCombineMode: 102 | - color: ["SHADE", "0", "TEXEL0", "0"] 103 | alpha: ["0", "0", "0", "PRIMITIVE"] 104 | - color: ["NOISE", "COMBINED", "PRIMITIVE", "COMBINED"] 105 | alpha: ["0", "0", "0", "PRIMITIVE"] 106 | 107 | gDPSetFogColor: 108 | r: 0 109 | g: 0 110 | b: 0 111 | 112 | gDPSetPrimColor: 113 | r: 100 114 | g: 100 115 | b: 200 116 | a: 128 117 | ``` 118 | 119 | there are 4 reserved material names `texture_lit`, `texture_unlit`, `solid_lit`, and `solid_unlit`. If you specify a material with one of these names then materials generated from 3d model files will use one of these 4 materials as a base. 120 | 121 | If you use the `--material-output` flag you can generate a list of materials with no geometry. Each material generated will only output the required state change to transition from the default material. 122 | 123 | ## examples 124 | 125 | See [./build_cube.sh](./build_cube.sh) and [./build_materials.sh](./build_materials.sh) as an example -------------------------------------------------------------------------------- /build_cube.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./skeletool64 examples/cube.obj -o examples/cube.h -------------------------------------------------------------------------------- /build_materials.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./skeletool64 --material-output -m examples/materials.skm.yaml -o examples/materials.h -------------------------------------------------------------------------------- /config.ld: -------------------------------------------------------------------------------- 1 | project = "skeletool64" 2 | file = {'./src/lua_generator', './lua'} -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: skeletool64 2 | Version: 0.3 3 | Architecture: amd64 4 | Depends: libassimp5 5 | Maintainer: James Lambert lambertjamesd@gmail.com 6 | Description: skeletool64 7 | Converts various 3d formats to a N64 display list 8 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Reference 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 44 | 45 |
46 | 47 | 48 | 49 |

Modules

50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
sk_input
sk_mesh
sk_transform
sk_animation
sk_definition_writer
sk_math
sk_scene
80 | 81 |
82 |
83 |
84 | generated by LDoc 1.4.6 85 | Last updated 2022-12-30 12:30:52 86 |
87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /doc/modules/LuaScene.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Reference 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 46 | 47 |
48 | 49 |

Module LuaScene

50 |

Scene functions

51 |

52 | 53 | 54 |

Functions

55 | 56 | 57 | 58 | 59 | 60 |
export_default_mesh ()Generates mesh and animation data from the current scene
61 | 62 |
63 |
64 | 65 | 66 |

Functions

67 | 68 |
69 |
70 | 71 | export_default_mesh () 72 |
73 |
74 | Generates mesh and animation data from the current scene 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 |
84 | 85 | 86 |
87 |
88 |
89 | generated by LDoc 1.4.6 90 | Last updated 2022-10-01 11:25:20 91 |
92 |
93 | 94 | 95 | -------------------------------------------------------------------------------- /doc/modules/sk_input.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Reference 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 51 | 52 |
53 | 54 |

Module sk_input

55 |

56 |

57 | 58 | 59 |

Tables

60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
settings
input_filename
70 | 71 |
72 |
73 | 74 | 75 |

Tables

76 | 77 |
78 |
79 | 80 | settings 81 |
82 |
83 | 84 | 85 | 86 |

Fields:

87 |
    88 |
  • model_transform 89 | sk_transform.Transform 90 | 91 |
  • 92 |
  • fixed_point_transform 93 | sk_transform.Transform 94 | 95 |
  • 96 |
  • model_scale 97 | number 98 | 99 |
  • 100 |
  • fixed_point_scale 101 | number 102 | 103 |
  • 104 |
105 | 106 | 107 | 108 | 109 | 110 |
111 |
112 | 113 | input_filename 114 |
115 |
116 | 117 | 118 | 119 |

Fields:

120 |
    121 |
  • bar 122 | foo 123 | 124 |
  • 125 |
126 | 127 | 128 | 129 | 130 | 131 |
132 |
133 | 134 | 135 |
136 |
137 |
138 | generated by LDoc 1.4.6 139 | Last updated 2022-12-30 12:30:52 140 |
141 |
142 | 143 | 144 | -------------------------------------------------------------------------------- /doc/modules/sk_transform.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Reference 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 52 | 53 |
54 | 55 |

Module sk_transform

56 |

57 |

58 | 59 | 60 |

Functions

61 | 62 | 63 | 64 | 65 | 66 |
from_pos_rot_scale (pos[, rot[, scale]])
67 |

Class Transform

68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
Transform:decompose ()
Transform:__mul (other)
78 | 79 |
80 |
81 | 82 | 83 |

Functions

84 | 85 |
86 |
87 | 88 | from_pos_rot_scale (pos[, rot[, scale]]) 89 |
90 |
91 | 92 | 93 | 94 |

Parameters:

95 |
    96 |
  • pos 97 | sk_math.Vector3 98 | 99 |
  • 100 |
  • rot 101 | sk_math.Quaternion 102 | 103 | (optional) 104 |
  • 105 |
  • scale 106 | sk_math.Scale 107 | 108 | (optional) 109 |
  • 110 |
111 | 112 |

Returns:

113 |
    114 | 115 | Transform 116 | 117 |
118 | 119 | 120 | 121 | 122 |
123 |
124 |

Class Transform

125 | 126 |
127 | A 4x4 matrix transform 128 |
129 |
130 |
131 | 132 | Transform:decompose () 133 |
134 |
135 | 136 | 137 | 138 | 139 |

Returns:

140 |
    141 |
  1. 142 | vector3.Vector3 143 | position
  2. 144 |
  3. 145 | quaternion.Quaternion 146 | rotation
  4. 147 |
  5. 148 | vector3.Vector3 149 | scale
  6. 150 |
151 | 152 | 153 | 154 | 155 |
156 |
157 | 158 | Transform:__mul (other) 159 |
160 |
161 | 162 | 163 | 164 |

Parameters:

165 |
    166 |
  • other 167 | Transform or sk_math.Vector3 168 | 169 |
  • 170 |
171 | 172 |

Returns:

173 |
    174 | 175 | Transform 176 | 177 |
178 | 179 | 180 | 181 | 182 |
183 |
184 | 185 | 186 |
187 |
188 |
189 | generated by LDoc 1.4.6 190 | Last updated 2022-12-30 12:30:52 191 |
192 |
193 | 194 | 195 | -------------------------------------------------------------------------------- /doc/modules/vector3.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Reference 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 |
16 |
17 |
18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 46 | 47 |
48 | 49 |

Module vector3

50 |

51 |

52 | 53 | 54 |

Functions

55 | 56 | 57 | 58 | 59 | 60 |
vector3 (x, y, z)creates a new 3d vector
61 | 62 |
63 |
64 | 65 | 66 |

Functions

67 | 68 |
69 |
70 | 71 | vector3 (x, y, z) 72 |
73 |
74 | creates a new 3d vector 75 | 76 | 77 |

Parameters:

78 |
    79 |
  • x 80 | the x value for the vector 81 |
  • 82 |
  • y 83 | the x value for the vector 84 |
  • 85 |
  • z 86 | the x value for the vector 87 |
  • 88 |
89 | 90 | 91 | 92 | 93 | 94 |
95 |
96 | 97 | 98 |
99 |
100 |
101 | generated by LDoc 1.4.6 102 | Last updated 2022-10-01 11:25:20 103 |
104 |
105 | 106 | 107 | -------------------------------------------------------------------------------- /examples/cube.h: -------------------------------------------------------------------------------- 1 | #ifndef __SKOUT_CUBE_H__ 2 | #define __SKOUT_CUBE_H__ 3 | 4 | #include 5 | 6 | #define OUTPUT_ATTACHMENT_COUNT 0 7 | 8 | extern Vtx output_Cube__normal[]; 9 | extern Gfx output_model_gfx[]; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /examples/cube.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.76 (sub 0) OBJ File: '' 2 | # www.blender.org 3 | mtllib cube.mtl 4 | o Cube 5 | v 1.000000 -1.000000 -1.000000 6 | v 1.000000 -1.000000 1.000000 7 | v -1.000000 -1.000000 1.000000 8 | v -1.000000 -1.000000 -1.000000 9 | v 1.000000 1.000000 -0.999999 10 | v 0.999999 1.000000 1.000001 11 | v -1.000000 1.000000 1.000000 12 | v -1.000000 1.000000 -1.000000 13 | vt 1.000000 0.333333 14 | vt 1.000000 0.666667 15 | vt 0.666667 0.666667 16 | vt 0.666667 0.333333 17 | vt 0.666667 0.000000 18 | vt 0.000000 0.333333 19 | vt 0.000000 0.000000 20 | vt 0.333333 0.000000 21 | vt 0.333333 1.000000 22 | vt 0.000000 1.000000 23 | vt 0.000000 0.666667 24 | vt 0.333333 0.333333 25 | vt 0.333333 0.666667 26 | vt 1.000000 0.000000 27 | vn 0.000000 -1.000000 0.000000 28 | vn 0.000000 1.000000 0.000000 29 | vn 1.000000 0.000000 0.000000 30 | vn -0.000000 0.000000 1.000000 31 | vn -1.000000 -0.000000 -0.000000 32 | vn 0.000000 0.000000 -1.000000 33 | usemtl Material 34 | s off 35 | f 2/1/1 3/2/1 4/3/1 36 | f 8/1/2 7/4/2 6/5/2 37 | f 5/6/3 6/7/3 2/8/3 38 | f 6/8/4 7/5/4 3/4/4 39 | f 3/9/5 7/10/5 8/11/5 40 | f 1/12/6 4/13/6 8/11/6 41 | f 1/4/1 2/1/1 4/3/1 42 | f 5/14/2 8/1/2 6/5/2 43 | f 1/12/3 5/6/3 2/8/3 44 | f 2/12/4 6/8/4 3/4/4 45 | f 4/13/5 3/9/5 8/11/5 46 | f 5/6/6 1/12/6 8/11/6 -------------------------------------------------------------------------------- /examples/cube_geo.c: -------------------------------------------------------------------------------- 1 | #include "cube.h" 2 | Vtx output_Cube__normal[] = { 3 | {{{256, -256, 256}, 0, {0, 0}, {0, -128, 0, 255}}}, 4 | {{{-256, -256, 256}, 0, {0, 0}, {0, -128, 0, 255}}}, 5 | {{{-256, -256, -256}, 0, {0, 0}, {0, -128, 0, 255}}}, 6 | {{{-256, 256, -256}, 0, {0, 0}, {0, 127, 0, 255}}}, 7 | {{{-256, 256, 256}, 0, {0, 0}, {0, 127, 0, 255}}}, 8 | {{{256, 256, 256}, 0, {0, 0}, {0, 127, 0, 255}}}, 9 | {{{256, 256, -256}, 0, {0, 0}, {127, 0, 0, 255}}}, 10 | {{{256, 256, 256}, 0, {0, 0}, {127, 0, 0, 255}}}, 11 | {{{256, -256, 256}, 0, {0, 0}, {127, 0, 0, 255}}}, 12 | {{{256, 256, 256}, 0, {0, 0}, {0, 0, 127, 255}}}, 13 | {{{-256, 256, 256}, 0, {0, 0}, {0, 0, 127, 255}}}, 14 | {{{-256, -256, 256}, 0, {0, 0}, {0, 0, 127, 255}}}, 15 | {{{-256, -256, 256}, 0, {0, 0}, {-128, 0, 0, 255}}}, 16 | {{{-256, 256, 256}, 0, {0, 0}, {-128, 0, 0, 255}}}, 17 | {{{-256, 256, -256}, 0, {0, 0}, {-128, 0, 0, 255}}}, 18 | {{{256, -256, -256}, 0, {0, 0}, {0, 0, -128, 255}}}, 19 | {{{-256, -256, -256}, 0, {0, 0}, {0, 0, -128, 255}}}, 20 | {{{-256, 256, -256}, 0, {0, 0}, {0, 0, -128, 255}}}, 21 | {{{256, -256, -256}, 0, {0, 0}, {0, -128, 0, 255}}}, 22 | {{{256, 256, -256}, 0, {0, 0}, {0, 127, 0, 255}}}, 23 | {{{256, -256, -256}, 0, {0, 0}, {127, 0, 0, 255}}}, 24 | {{{256, -256, 256}, 0, {0, 0}, {0, 0, 127, 255}}}, 25 | {{{-256, -256, -256}, 0, {0, 0}, {-128, 0, 0, 255}}}, 26 | {{{256, 256, -256}, 0, {0, 0}, {0, 0, -128, 255}}}, 27 | }; 28 | 29 | Gfx output_model_gfx[] = { 30 | /* Material Material */ 31 | gsDPPipeSync(), 32 | gsSPGeometryMode(0, G_SHADE | G_LIGHTING), 33 | gsDPSetCombineLERP(0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE), 34 | gsDPSetPrimColor(255, 255, 153, 153, 153, 255), 35 | /* End Material Material */ 36 | gsSPVertex(&output_Cube__normal[0], 24, 0), 37 | gsSP2Triangles(0, 1, 2, 0, 3, 4, 5, 0), 38 | gsSP2Triangles(6, 7, 8, 0, 9, 10, 11, 0), 39 | gsSP2Triangles(12, 13, 14, 0, 15, 16, 17, 0), 40 | gsSP2Triangles(18, 0, 2, 0, 19, 3, 5, 0), 41 | gsSP2Triangles(20, 6, 8, 0, 21, 9, 11, 0), 42 | gsSP2Triangles(22, 12, 14, 0, 23, 15, 17, 0), 43 | gsDPPipeSync(), 44 | gsSPEndDisplayList(), 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /examples/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambertjamesd/skelatool64/708cfcae7734dc3d3997286976bbf32f5009da01/examples/image.png -------------------------------------------------------------------------------- /examples/materials.h: -------------------------------------------------------------------------------- 1 | #ifndef __SKOUT_MATERIALS_H__ 2 | #define __SKOUT_MATERIALS_H__ 3 | 4 | #include 5 | 6 | #define TEST_MATERIAL_A_INDEX 0 7 | #define DEFAULT_INDEX 1 8 | #define OUTPUT_MATERIAL_COUNT 2 9 | #define OUTPUT_TRANSPARENT_START 3 10 | 11 | extern u64 output_image_i_8b[]; 12 | extern Gfx output_Test_Material_A[]; 13 | extern Gfx output_Test_Material_A_revert[]; 14 | extern Gfx output_default[]; 15 | extern Gfx output_default_revert[]; 16 | extern Gfx* output_material_list[]; 17 | extern Gfx* output_material_revert_list[]; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /examples/materials.skm.yaml: -------------------------------------------------------------------------------- 1 | 2 | materials: 3 | default: 4 | gDPSetRenderMode: G_RM_AA_ZB_OPA_SURF 5 | gDPSetCycleType: G_CYC_1CYCLE 6 | 7 | Test Material A: 8 | gDPSetTile: 9 | filename: ./image.png 10 | fmt: G_IM_FMT_I 11 | gDPSetRenderMode: G_RM_AA_ZB_OPA_SURF 12 | gDPSetCombineMode: 13 | color: ["0", "0", "0", "1"] 14 | alpha: ["0", "0", "0", "1"] 15 | gDPSetCycleType: G_CYC_1CYCLE 16 | gDPSetTextureLOD: G_TL_TILE 17 | gDPSetAlphaDither: G_AD_DISABLE 18 | gDPSetPrimColor: 19 | r: 255 20 | g: 0 21 | b: 0 22 | gDPSetEnvColor: 23 | r: 128 24 | g: 128 25 | b: 128 26 | gDPSetFogColor: 27 | r: 200 28 | g: 100 29 | b: 50 30 | gDPSetBlendColor: 31 | r: 180 32 | g: 120 33 | b: 100 -------------------------------------------------------------------------------- /examples/materials_mat.c: -------------------------------------------------------------------------------- 1 | #include "materials.h" 2 | u64 output_image_i_8b[] = { 3 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 4 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 5 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 6 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x9ba49b8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 7 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8cbd, 0xe9eed39b8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 8 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8cc4f9, 0xffffffd28c8c8c8c, 0x8c8c8c8c8c8c8c8c, 9 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8cb9f5ff, 0xfffffff8b98c8c8c, 0x8c8c8c8c8c8c8c8c, 10 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8cc1f4ffff, 0xfffffffff0b08c8c, 0x8c8c8c8c8c8c8c8c, 11 | 0x8c8c8c8c8c8c8c8c, 0x8c8c9bd2fbffffff, 0xffffffffffe6a48c, 0x8c8c8c8c8c8c8c8c, 12 | 0x8c8c8c8c8c8c8c8c, 0x8ca4deffffffffff, 0xf5f7ffffffffde9b, 0x8c8c8c8c8c8c8c8c, 13 | 0x8c8c8c8c8c8c8c8c, 0xb0e6fffffffffff0, 0xb9c1fbffffffffd2, 0x8c8c8c8c8c8c8c8c, 14 | 0x8c8c8c8c8c8c8cb9, 0xf0ffffffffffe4b0, 0x8c8cc8fcfffffffc, 0xc88c8c8c8c8c8c8c, 15 | 0x8c8c8c8c8c8cc1f4, 0xfffffffffcd29b8c, 0x8c8c8cd2ffffffff, 0xfbc18c8c8c8c8c8c, 16 | 0x8c8c8c8c8cc8fbff, 0xfffffffbc88c8c8c, 0x8c8c8c9bdeffffff, 0xfffacf8c8c8c8c8c, 17 | 0x8c8c8c8cdbfdffff, 0xfffff4c18c8c8c8c, 0x8c8c8c8ca4e6ffff, 0xffffffc68c8c8c8c, 18 | 0x8c8c8cd0ffffffff, 0xfff0b98c8c8c8c8c, 0x8c8c8c8c8cb0f2ff, 0xffffffe58c8c8c8c, 19 | 0x8c8c8cecffffffff, 0xeeb58c8c8c8c8c8c, 0x8c8c8c8c8c9beaff, 0xffffffd78c8c8c8c, 20 | 0x8c8c8cd0fffffffd, 0xfbeac29b8c8c8c8c, 0x8c8c8c8c8cc8fcff, 0xfffff4a98c8c8c8c, 21 | 0x8c8c8c8cd0f5ffff, 0xfffffceac29b8c8c, 0x8c8c8c8ca9f3ffff, 0xfffcc88c8c8c8c8c, 22 | 0x8c8c8c8c8cc1ffff, 0xfffffffffce4bb9b, 0x8c8c8c8cdbffffff, 0xffe29b8c8c8c8c8c, 23 | 0x8c8c8c8c8c9bd7fc, 0xfffffffffffff8e1, 0xbb9b8cc1fcffffff, 0xf6b08c8c8c8c8c8c, 24 | 0x8c8c8c8c8c8c9bc2, 0xeafcffffffffffff, 0xf8e0bdf2ffffffff, 0xcd8c8c8c8c8c8c8c, 25 | 0x8c8c8c8c8c8c8c8c, 0x9bc2eafdffffffff, 0xfffffbffffffffe4, 0x9b8c8c8c8c8c8c8c, 26 | 0x8c8c8c8c8c8c8c8c, 0x8c8c9bc8f2fdffff, 0xfffffffffffff6b0, 0x8c8c8c8c8c8c8c8c, 27 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8ca9d4f3fd, 0xffffffffffffd78c, 0x8c8c8c8c8c8c8c8c, 28 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8ca9d4, 0xf4fffffffff2a98c, 0x8c8c8c8c8c8c8c8c, 29 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0xa9d7f4f6edb98c8c, 0x8c8c8c8c8c8c8c8c, 30 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8ca9bba98c8c8c, 0x8c8c8c8c8c8c8c8c, 31 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 32 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 33 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 34 | 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 0x8c8c8c8c8c8c8c8c, 35 | }; 36 | 37 | Gfx output_Test_Material_A[] = { 38 | gsDPPipeSync(), 39 | gsDPSetTextureLOD(G_TL_TILE), 40 | gsDPSetAlphaDither(G_AD_DISABLE), 41 | gsDPSetCombineLERP(0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1), 42 | gsDPSetPrimColor(255, 255, 255, 0, 0, 255), 43 | gsDPSetEnvColor(128, 128, 128, 255), 44 | gsDPSetFogColor(200, 100, 50, 255), 45 | gsDPSetBlendColor(180, 120, 100, 255), 46 | gsSPTexture(65535, 65535, 0, 0, G_ON), 47 | gsDPTileSync(), 48 | gsDPSetTextureImage(G_IM_FMT_I, G_IM_SIZ_8b_LOAD_BLOCK, 1, output_image_i_8b), 49 | gsDPSetTile(G_IM_FMT_I, G_IM_SIZ_8b_LOAD_BLOCK, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0), 50 | gsDPLoadSync(), 51 | gsDPLoadBlock(G_TX_LOADTILE, 0, 0, 511, 512), 52 | gsDPPipeSync(), 53 | gsDPSetTile(G_IM_FMT_I, G_IM_SIZ_8b, 4, 0, 0, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0, G_TX_WRAP | G_TX_NOMIRROR, 5, 0), 54 | gsDPSetTileSize(0, 0, 0, 124, 124), 55 | gsSPEndDisplayList(), 56 | }; 57 | 58 | Gfx output_Test_Material_A_revert[] = {gsDPPipeSync(), gsSPEndDisplayList()}; 59 | 60 | Gfx output_default[] = { 61 | gsDPPipeSync(), 62 | gsDPSetCycleType(G_CYC_1CYCLE), 63 | gsDPSetRenderMode(G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2), 64 | gsSPEndDisplayList(), 65 | }; 66 | 67 | Gfx output_default_revert[] = {gsDPPipeSync(), gsSPEndDisplayList()}; 68 | 69 | Gfx* output_material_list[] = {output_Test_Material_A, output_default}; 70 | 71 | Gfx* output_material_revert_list[] = { 72 | output_Test_Material_A_revert, 73 | output_default_revert, 74 | }; 75 | 76 | -------------------------------------------------------------------------------- /lua/sk_scene.lua: -------------------------------------------------------------------------------- 1 | --- @module sk_scene 2 | 3 | local node_name_cache = nil 4 | 5 | local exports 6 | 7 | -- Defintions from LuaScene.cpp 8 | 9 | ---A scene node 10 | ---@table Node 11 | ---@tfield string name 12 | ---@tfield sk_transform.Transform transformation 13 | ---@tfield sk_transform.Transform full_transformation 14 | ---@tfield Node parent 15 | ---@tfield {Node,...} children 16 | ---@tfield {sk_mesh.Mesh,...} meshes 17 | 18 | --- Generates mesh and animation data from the current scene 19 | ---@function export_default_mesh 20 | ---@treturn sk_definition_writer.RawType model 21 | ---@treturn sk_definition_writer.RawType material 22 | local function export_default_mesh() 23 | -- implmentation overridden by LuaScene.cpp 24 | end 25 | 26 | -- Defintions from LuaNodeGroups.cpp 27 | 28 | ---A pairing of nodes and pre parsed node arguments 29 | ---@table NodeWithArguments 30 | ---@tfield Node node 31 | ---@tfield {string,...} arguments the list is strings produced by splitting the node name by spaces 32 | 33 | ---Returns a list of nodes with the given string prefix 34 | ---@function nodes_for_type 35 | ---@tparam string prefix the string prefix to search 36 | ---@treturn NodeWithArguments 37 | local function nodes_for_type(prefix) 38 | 39 | end 40 | 41 | ---Finds a named value in a list of arguments 42 | ---@function find_named_argument 43 | ---@tfield {string,...} arg_list 44 | ---@tfield string name 45 | ---@treturn string|nil 46 | local function find_named_argument(arg_list, name) 47 | for i = 1,#arg_list do 48 | if (arg_list[i] == name) then 49 | return arg_list[i + 1] 50 | end 51 | end 52 | 53 | return nil 54 | end 55 | 56 | ---Finds a named value in a list of arguments 57 | ---@function find_flag_argument 58 | ---@tfield {string,...} arg_list 59 | ---@tfield string name 60 | ---@treturn boolean 61 | local function find_flag_argument(arg_list, name) 62 | for i = 1,#arg_list do 63 | if (arg_list[i] == name) then 64 | return true 65 | end 66 | end 67 | 68 | return false 69 | end 70 | 71 | local function build_node_with_name_cache(node) 72 | node_name_cache[node.name] = node 73 | 74 | for _, child in pairs(node.children) do 75 | build_node_with_name_cache(child) 76 | end 77 | end 78 | 79 | --- Returns a node with the given name 80 | ---@function node_with_name 81 | ---@tparam string name 82 | ---@treturn Node result 83 | local function node_with_name(name) 84 | if (not node_name_cache) then 85 | node_name_cache = {} 86 | build_node_with_name_cache(exports.scene.root) 87 | end 88 | 89 | return node_name_cache[name] 90 | end 91 | 92 | local function for_each_node(node, callback) 93 | callback(node) 94 | 95 | for _, child in pairs(node.children) do 96 | for_each_node(child, callback) 97 | end 98 | end 99 | 100 | ---@table Vector3Key 101 | ---@tfield number time 102 | ---@tfield sk_math.Vector3 value 103 | 104 | ---@table QuaternionKey 105 | ---@tfield number time 106 | ---@tfield sk_math.Quaternion value 107 | 108 | ---@table Channel 109 | ---@tfield string node_name 110 | ---@tfield {Vector3Key,...} position_keys 111 | ---@tfield {QuaternionKey,...} rotation_keys 112 | ---@tfield {Vector3Key,...} scaling_keys 113 | 114 | ---@table Animation 115 | ---@tfield string name 116 | ---@tfield number duration 117 | ---@tfield number ticks_per_second 118 | ---@tfield {Channel,...} channels 119 | 120 | exports = { 121 | export_default_mesh = export_default_mesh, 122 | nodes_for_type = nodes_for_type, 123 | find_named_argument = find_named_argument, 124 | find_flag_argument = find_flag_argument, 125 | node_with_name = node_with_name, 126 | for_each_node = for_each_node, 127 | } 128 | 129 | return exports -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 2 | GCC_FLAGS = -Wall -Werror -g -rdynamic -I./yaml-cpp/include 3 | 4 | LINKER_FLAGS = -L./yaml-cpp -lassimp -lyaml-cpp -lpng -ltiff -llua5.4 -ldl 5 | 6 | SRC_FILES = main.cpp $(shell find src/ -type f -name '*.cpp') 7 | 8 | OBJ_FILES = $(patsubst %.cpp, build/%.o, $(SRC_FILES)) 9 | 10 | LUA_SRC_FILES = $(shell find lua/ -type f -name '*.lua') 11 | 12 | LUA_OBJ_FILES = $(patsubst %.lua, build/%.o, $(LUA_SRC_FILES)) 13 | 14 | DEPS = $(patsubst %.cpp, build/%.d, $(SRC_FILES)) 15 | 16 | .PHONY: default 17 | default: skeletool64 18 | 19 | -include $(DEPS) 20 | 21 | build/lua/%.o: lua/%.lua 22 | @mkdir -p $(@D) 23 | luac -o $(@:%.o=%.out) $< 24 | ld -r -b binary -o $@ $(@:%.o=%.out) 25 | 26 | build/%.o: %.cpp 27 | @mkdir -p $(@D) 28 | g++ $(GCC_FLAGS) -c $< -o $@ 29 | $(CC) $(GCC_FLAGS) -MM $^ -MF "$(@:.o=.d)" -MT"$@" 30 | 31 | skeletool64: $(OBJ_FILES) $(LUA_OBJ_FILES) 32 | g++ -g -o skeletool64 $(OBJ_FILES) $(LUA_OBJ_FILES) $(LINKER_FLAGS) 33 | 34 | clean: 35 | rm -r build/ 36 | 37 | init: 38 | 39 | 40 | install: skeletool64 41 | cp skeletool64 ~/.local/bin 42 | 43 | build/skeletool.deb: skeletool64 control 44 | mkdir build/skeletool/usr/local/bin -p 45 | cp skeletool64 build/skeletool/usr/local/bin 46 | mkdir build/skeletool/DEBIAN -p 47 | cp control build/skeletool/DEBIAN 48 | dpkg-deb --build build/skeletool 49 | 50 | docs: 51 | ldoc . 52 | 53 | schema_docs/index.html: schema/material-schema.json 54 | generate-schema-doc schema/ schema_docs/index.html 55 | -------------------------------------------------------------------------------- /schema_docs/schema_doc.css: -------------------------------------------------------------------------------- 1 | body { 2 | font: 16px/1.5em "Overpass", "Open Sans", Helvetica, sans-serif; 3 | color: #333; 4 | font-weight: 300; 5 | padding: 40px; 6 | } 7 | 8 | .btn.btn-link { 9 | font-size: 18px; 10 | } 11 | 12 | .jsfh-animated-property { 13 | animation: eclair; 14 | animation-iteration-count: 1; 15 | animation-fill-mode: forwards; 16 | animation-duration: .75s; 17 | 18 | } 19 | 20 | @keyframes eclair { 21 | 0%,100% { 22 | transform: scale(1); 23 | } 24 | 50% { 25 | transform: scale(1.03); 26 | } 27 | } 28 | 29 | .btn.btn-primary { 30 | margin: 10px; 31 | } 32 | 33 | .btn.example-show.collapsed:before { 34 | content: "show" 35 | } 36 | 37 | .btn.example-show:before { 38 | content: "hide" 39 | } 40 | 41 | .description.collapse:not(.show) { 42 | max-height: 100px !important; 43 | overflow: hidden; 44 | 45 | display: -webkit-box; 46 | -webkit-line-clamp: 2; 47 | -webkit-box-orient: vertical; 48 | } 49 | 50 | .description.collapsing { 51 | min-height: 100px !important; 52 | } 53 | 54 | .collapse-description-link.collapsed:after { 55 | content: '+ Read More'; 56 | } 57 | 58 | .collapse-description-link:not(.collapsed):after { 59 | content: '- Read Less'; 60 | } 61 | 62 | .badge { 63 | font-size: 100%; 64 | margin-bottom: 0.5rem; 65 | margin-top: 0.5rem; 66 | } 67 | 68 | .badge.value-type { 69 | font-size: 120%; 70 | margin-right: 5px; 71 | margin-bottom: 10px; 72 | } 73 | 74 | 75 | .badge.default-value { 76 | font-size: 120%; 77 | margin-left: 5px; 78 | margin-bottom: 10px; 79 | } 80 | 81 | .badge.restriction { 82 | display: inline-block; 83 | } 84 | 85 | .badge.required-property,.badge.deprecated-property,.badge.pattern-property,.badge.no-additional { 86 | font-size: 100%; 87 | margin-left: 10px; 88 | } 89 | 90 | .accordion div.card:only-child { 91 | border-bottom: 1px solid rgba(0, 0, 0, 0.125); 92 | } 93 | 94 | .examples { 95 | padding: 1rem !important; 96 | } 97 | 98 | .examples pre { 99 | margin-bottom: 0; 100 | } 101 | 102 | .highlight.jumbotron { 103 | padding: 1rem !important; 104 | } 105 | 106 | .generated-by-footer { 107 | margin-top: 1em; 108 | text-align: right; 109 | } 110 | 111 | /* From https://github.com/richleland/pygments-css/blob/master/friendly.css, see https://github.com/trentm/python-markdown2/wiki/fenced-code-blocks */ 112 | .highlight { background: #e9ecef; } /* Changed from #f0f0f0 in the original style to be the same as bootstrap's jumbotron */ 113 | .highlight .hll { background-color: #ffffcc } 114 | .highlight .c { color: #60a0b0; font-style: italic } /* Comment */ 115 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 116 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 117 | .highlight .o { color: #666666 } /* Operator */ 118 | .highlight .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */ 119 | .highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ 120 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 121 | .highlight .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */ 122 | .highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ 123 | .highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ 124 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 125 | .highlight .ge { font-style: italic } /* Generic.Emph */ 126 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 127 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 128 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 129 | .highlight .go { color: #888888 } /* Generic.Output */ 130 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 131 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 132 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 133 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 134 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 135 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 136 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 137 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 138 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 139 | .highlight .kt { color: #902000 } /* Keyword.Type */ 140 | .highlight .m { color: #40a070 } /* Literal.Number */ 141 | .highlight .s { color: #4070a0 } /* Literal.String */ 142 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 143 | .highlight .nb { color: #007020 } /* Name.Builtin */ 144 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 145 | .highlight .no { color: #60add5 } /* Name.Constant */ 146 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 147 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 148 | .highlight .ne { color: #007020 } /* Name.Exception */ 149 | .highlight .nf { color: #06287e } /* Name.Function */ 150 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 151 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 152 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 153 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 154 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 155 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 156 | .highlight .mb { color: #40a070 } /* Literal.Number.Bin */ 157 | .highlight .mf { color: #40a070 } /* Literal.Number.Float */ 158 | .highlight .mh { color: #40a070 } /* Literal.Number.Hex */ 159 | .highlight .mi { color: #40a070 } /* Literal.Number.Integer */ 160 | .highlight .mo { color: #40a070 } /* Literal.Number.Oct */ 161 | .highlight .sa { color: #4070a0 } /* Literal.String.Affix */ 162 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 163 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 164 | .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ 165 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 166 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 167 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 168 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 169 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 170 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 171 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 172 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 173 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 174 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 175 | .highlight .fm { color: #06287e } /* Name.Function.Magic */ 176 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 177 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 178 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 179 | .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ 180 | .highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /schema_docs/schema_doc.min.js: -------------------------------------------------------------------------------- 1 | function flashElement(t){myElement=document.getElementById(t),myElement.classList.add("jsfh-animated-property"),setTimeout(function(){myElement.classList.remove("jsfh-animated-property")},1e3)}function setAnchor(t){history.pushState({},"",t)}function anchorOnLoad(){let t=window.location.hash.split("?")[0].split("&")[0];"#"===t[0]&&(t=t.substr(1)),t.length>0&&anchorLink(t)}function anchorLink(t){$("#"+t).parents().addBack().filter(".collapse:not(.show), .tab-pane, [role='tab']").each(function(t){if($(this).hasClass("collapse"))$(this).collapse("show");else if($(this).hasClass("tab-pane")){const t=$("a[href='#"+$(this).attr("id")+"']");t&&t.tab("show")}else"tab"===$(this).attr("role")&&$(this).tab("show")}),setTimeout(function(){let e=document.getElementById(t);e&&(e.scrollIntoView({block:"center",behavior:"smooth"}),setTimeout(function(){flashElement(t)},500))},1e3)}$(document).on("click",'a[href^="#"]',function(t){t.preventDefault(),history.pushState({},"",this.href)}); -------------------------------------------------------------------------------- /setup_dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | sudo apt install -y libpng-dev libtiff-dev libassimp-dev g++ liblua5.4-dev cmake 4 | 5 | pushd $(dirname "$0") 6 | 7 | git clone https://github.com/jbeder/yaml-cpp.git 8 | 9 | cmake -S yaml-cpp -B yaml-cpp 10 | make -C yaml-cpp 11 | 12 | wget http://cimg.eu/files/CImg_3.1.3.zip 13 | unzip CImg_3.1.3.zip 14 | mv CImg-3.1.3 cimg 15 | 16 | popd 17 | -------------------------------------------------------------------------------- /src/BoneHierarchy.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "BoneHierarchy.h" 4 | #include "CFileDefinition.h" 5 | 6 | Bone::Bone(int index, std::string name, Bone* parent, const aiVector3D& restPosition, const aiQuaternion& restRotation, const aiVector3D& restScale): 7 | mIndex(index), 8 | mName(name), 9 | mParent(parent), 10 | mRestPosition(restPosition), 11 | mRestRotation(restRotation), 12 | mRestScale(restScale) { 13 | 14 | if (mParent) { 15 | mParent->mChildren.push_back(this); 16 | } 17 | } 18 | 19 | int Bone::GetIndex() { 20 | return mIndex; 21 | } 22 | 23 | const std::string& Bone::GetName() { 24 | return mName; 25 | } 26 | 27 | Bone* Bone::GetParent() { 28 | return mParent; 29 | } 30 | 31 | std::unique_ptr Bone::GenerateRestPosiitonData() { 32 | std::unique_ptr result(new StructureDataChunk()); 33 | 34 | result->Add(std::unique_ptr(new StructureDataChunk(mRestPosition))); 35 | result->Add(std::unique_ptr(new StructureDataChunk(mRestRotation))); 36 | result->Add(std::unique_ptr(new StructureDataChunk(mRestScale))); 37 | 38 | return std::move(result); 39 | } 40 | 41 | Bone* Bone::FindCommonAncestor(Bone* a, Bone* b) { 42 | std::set hierarchyDifference; 43 | 44 | Bone* curr = a; 45 | 46 | while (curr) { 47 | hierarchyDifference.insert(curr); 48 | curr = curr->mParent; 49 | } 50 | 51 | curr = b; 52 | 53 | while (curr) { 54 | hierarchyDifference.erase(curr); 55 | curr = curr->mParent; 56 | } 57 | 58 | curr = a; 59 | 60 | while (hierarchyDifference.find(curr) != hierarchyDifference.end()) { 61 | curr = curr->mParent; 62 | } 63 | 64 | return curr; 65 | } 66 | 67 | Bone* Bone::StepDownTowards(Bone* ancestor, Bone* decendant) { 68 | Bone* curr = decendant; 69 | 70 | while (curr && curr->mParent != ancestor) { 71 | curr = curr->mParent; 72 | } 73 | 74 | return curr; 75 | } 76 | 77 | bool Bone::CompareBones(Bone* a, Bone* b) { 78 | if (a == nullptr && b == nullptr) { 79 | return false; 80 | } else if (a == nullptr) { 81 | return true; 82 | } else if (b == nullptr) { 83 | return false; 84 | } else { 85 | return a->mIndex < b->mIndex; 86 | } 87 | } 88 | 89 | int Bone::GetBoneIndex(Bone* a) { 90 | if (a == nullptr) { 91 | return -1; 92 | } else { 93 | return a->mIndex; 94 | } 95 | } 96 | 97 | void BoneHierarchy::PopulateWithAnimationNodeInfo(const NodeAnimationInfo& animInfo, float fixedPointScale, aiQuaternion& rotation) { 98 | aiMatrix4x4 rotationMatrix(rotation.GetMatrix()); 99 | 100 | for (auto& node : animInfo.nodesWithAnimation) { 101 | Bone* parent = nullptr; 102 | 103 | if (node->parent) { 104 | auto parentFind = mBoneByName.find(node->parent->mName.C_Str()); 105 | 106 | if (parentFind != mBoneByName.end()) { 107 | parent = parentFind->second; 108 | } 109 | } 110 | 111 | std::string boneName = node->node->mName.C_Str(); 112 | 113 | aiVector3D restPosition; 114 | aiQuaternion restRotation; 115 | aiVector3D restScale; 116 | 117 | aiMatrix4x4 fullRestTransform = node->relativeTransform * node->node->mTransformation; 118 | 119 | if (parent == nullptr) { 120 | fullRestTransform = rotationMatrix * fullRestTransform; 121 | } 122 | 123 | fullRestTransform.Decompose(restScale, restRotation, restPosition); 124 | 125 | mBones.push_back(std::unique_ptr(new Bone( 126 | mBones.size(), 127 | boneName, 128 | parent, 129 | restPosition * fixedPointScale, 130 | restRotation, 131 | restScale 132 | ))); 133 | 134 | mBoneByName.insert(std::pair(boneName, mBones.back().get())); 135 | } 136 | } 137 | 138 | void BoneHierarchy::SearchForBones(aiNode* node, Bone* currentBoneParent, std::set& knownBones, bool parentIsBone, float fixedPointScale) { 139 | if (knownBones.find(node->mName.C_Str()) != knownBones.end()) { 140 | aiVector3D restPosition; 141 | aiQuaternion restRotation; 142 | aiVector3D restScale; 143 | node->mTransformation.Decompose(restScale, restRotation, restPosition); 144 | 145 | mBones.push_back(std::unique_ptr(new Bone( 146 | mBones.size(), 147 | node->mName.C_Str(), 148 | currentBoneParent, 149 | restPosition * fixedPointScale, 150 | restRotation, 151 | restScale 152 | ))); 153 | 154 | currentBoneParent = mBones[mBones.size() - 1].get(); 155 | mBoneByName.insert(std::pair(node->mName.C_Str(), currentBoneParent)); 156 | 157 | parentIsBone = true; 158 | } 159 | 160 | for (unsigned int i = 0; i < node->mNumChildren; ++i) { 161 | SearchForBones(node->mChildren[i], currentBoneParent, knownBones, parentIsBone, fixedPointScale); 162 | } 163 | } 164 | 165 | void BoneHierarchy::SearchForBonesInScene(const aiScene* scene, float fixedPointScale) { 166 | std::set knownBones; 167 | 168 | for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { 169 | aiMesh* mesh = scene->mMeshes[meshIndex]; 170 | 171 | for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) { 172 | knownBones.insert(mesh->mBones[boneIndex]->mName.C_Str()); 173 | } 174 | } 175 | 176 | SearchForBones(scene->mRootNode, nullptr, knownBones, false, fixedPointScale); 177 | } 178 | 179 | Bone* BoneHierarchy::BoneByIndex(unsigned index) { 180 | return mBones[index].get(); 181 | } 182 | 183 | Bone* BoneHierarchy::BoneForName(std::string name) { 184 | auto result = mBoneByName.find(name); 185 | 186 | if (result == mBoneByName.end()) { 187 | return nullptr; 188 | } else { 189 | return result->second; 190 | } 191 | } 192 | 193 | void BoneHierarchy::GenerateRestPosiitonData(CFileDefinition& fileDef, const std::string& variableName) { 194 | if (mBones.size() == 0) return; 195 | 196 | std::unique_ptr transformData(new StructureDataChunk()); 197 | 198 | for (unsigned int boneIndex = 0; boneIndex < mBones.size(); ++boneIndex) { 199 | transformData->Add(std::move(mBones[boneIndex]->GenerateRestPosiitonData())); 200 | 201 | std::string boneName = fileDef.GetUniqueName(mBones[boneIndex]->GetName() + "_BONE"); 202 | std::transform(boneName.begin(), boneName.end(), boneName.begin(), ::toupper); 203 | 204 | fileDef.AddMacro(boneName, std::to_string(boneIndex)); 205 | } 206 | 207 | std::unique_ptr restPosDef(new DataFileDefinition("struct Transform", variableName, true, "_geo", std::move(transformData))); 208 | restPosDef->AddTypeHeader("\"math/transform.h\""); 209 | fileDef.AddDefinition(std::move(restPosDef)); 210 | } 211 | 212 | bool BoneHierarchy::HasData() const { 213 | return mBones.size() > 0; 214 | } 215 | 216 | unsigned int BoneHierarchy::GetBoneCount() const { 217 | return mBones.size(); 218 | } -------------------------------------------------------------------------------- /src/BoneHierarchy.h: -------------------------------------------------------------------------------- 1 | #ifndef _BONE_HIERARCHY_H 2 | #define _BONE_HIERARCHY_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "ErrorCode.h" 16 | #include "./definitions/DataChunk.h" 17 | 18 | struct AnimationNodeInfo { 19 | const aiNode* node; 20 | // the ancestor of this node that is also a bone 21 | const aiNode* parent; 22 | aiMatrix4x4 relativeTransform; 23 | }; 24 | 25 | struct NodeAnimationInfo { 26 | std::vector> nodesWithAnimation; 27 | }; 28 | 29 | class CFileDefinition; 30 | 31 | class Bone { 32 | public: 33 | Bone(int index, std::string name, Bone* parent, const aiVector3D& restPosition, const aiQuaternion& restRotation, const aiVector3D& restScale); 34 | 35 | int GetIndex(); 36 | const std::string& GetName(); 37 | Bone* GetParent(); 38 | 39 | std::unique_ptr GenerateRestPosiitonData(); 40 | 41 | static Bone* FindCommonAncestor(Bone* a, Bone* b); 42 | /** 43 | * Assumes ancestor is an ancestor of decendant 44 | * Returns the child bone of ancestor that is an ancestor 45 | * of decendant or is decendant 46 | */ 47 | static Bone* StepDownTowards(Bone* ancestor, Bone* decendant); 48 | 49 | static bool CompareBones(Bone* a, Bone* b); 50 | // return -1 if a is null 51 | static int GetBoneIndex(Bone* a); 52 | private: 53 | int mIndex; 54 | std::string mName; 55 | Bone* mParent; 56 | aiVector3D mRestPosition; 57 | aiQuaternion mRestRotation; 58 | aiVector3D mRestScale; 59 | 60 | std::vector mChildren; 61 | }; 62 | 63 | class BoneHierarchy { 64 | public: 65 | void SearchForBones(aiNode* node, Bone* currentBoneParent, std::set& knownBones, bool parentIsBone, float fixedPointScale); 66 | void SearchForBonesInScene(const aiScene* scene, float fixedPointScale); 67 | 68 | void PopulateWithAnimationNodeInfo(const NodeAnimationInfo& animInfo, float fixedPointScale, aiQuaternion& rotation); 69 | 70 | Bone* BoneByIndex(unsigned index); 71 | Bone* BoneForName(std::string name); 72 | bool HasData() const; 73 | unsigned int GetBoneCount() const; 74 | 75 | void GenerateRestPosiitonData(CFileDefinition& fileDef, const std::string& variableName); 76 | private: 77 | std::vector> mBones; 78 | std::map mBoneByName; 79 | }; 80 | 81 | #endif -------------------------------------------------------------------------------- /src/CFileDefinition.h: -------------------------------------------------------------------------------- 1 | #ifndef _C_FILE_DEFINITION_H 2 | #define _C_FILE_DEFINITION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "./ErrorResult.h" 12 | #include "./ExtendedMesh.h" 13 | #include "./definitions/FileDefinition.h" 14 | #include "./materials/TextureDefinition.h" 15 | 16 | class VertexBufferDefinition { 17 | public: 18 | VertexBufferDefinition(std::shared_ptr targetMesh, std::string name, VertexType vertexType, int textureWidth, int textureHeight); 19 | 20 | std::shared_ptr mTargetMesh; 21 | std::string mName; 22 | VertexType mVertexType; 23 | int mTextureWidth; 24 | int mTextureHeight; 25 | 26 | ErrorResult Generate(float fixedPointScale, float modelScale, aiQuaternion rotate, std::unique_ptr& output, const std::string& fileSuffix, const PixelRGBAu8& defaultVertexColor); 27 | private: 28 | }; 29 | 30 | class CFileDefinition { 31 | public: 32 | CFileDefinition(std::string prefix, float fixedPointScale, float modelScale, aiQuaternion modelRotate); 33 | 34 | void AddDefinition(std::unique_ptr definition); 35 | std::string AddDataDefinition(const std::string& nameHint, const std::string& dataType, bool isArray, const std::string& location, std::unique_ptr data); 36 | void AddMacro(const std::string& name, const std::string& value); 37 | 38 | void AddHeader(const std::string& name); 39 | 40 | std::string GetVertexBuffer(std::shared_ptr mesh, VertexType vertexType, int textureWidth, int textureHeight, const std::string& modelSuffix, const PixelRGBAu8& defaultVertexColor); 41 | std::string GetCullingBuffer(const std::string& name, const aiVector3D& min, const aiVector3D& max, const std::string& modelSuffix); 42 | 43 | std::string GetUniqueName(std::string requestedName); 44 | 45 | std::string GetMacroName(std::string requestedName); 46 | 47 | std::set GetDefinitionTypes(); 48 | 49 | void GenerateAll(const std::string& headerFileLocation); 50 | 51 | void Generate(std::ostream& output, const std::string& location, const std::string& headerFileName); 52 | void GenerateHeader(std::ostream& output, const std::string& headerFileName); 53 | 54 | bool HasDefinitions(const std::string& location); 55 | 56 | bool GetResourceName(const void* resource, std::string& result) const; 57 | 58 | std::shared_ptr GetExtendedMesh(aiMesh* mesh); 59 | 60 | BoneHierarchy& GetBoneHierarchy(); 61 | private: 62 | std::string mPrefix; 63 | float mFixedPointScale; 64 | float mModelScale; 65 | aiQuaternion mModelRotate; 66 | std::set mHeaders; 67 | std::set mUsedNames; 68 | std::map mVertexBuffers; 69 | std::vector> mDefinitions; 70 | std::vector mMacros; 71 | std::map mResourceNames; 72 | std::map> mMeshes; 73 | BoneHierarchy mBoneHierarchy; 74 | }; 75 | 76 | #endif -------------------------------------------------------------------------------- /src/CommandLineParser.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "CommandLineParser.h" 3 | 4 | void parseEulerAngles(const std::string& input, aiVector3D& output) { 5 | std::size_t firstComma = input.find(','); 6 | std::size_t secondComma = input.find(',', firstComma + 1); 7 | output.x = (float)atof(input.substr(0, firstComma).c_str()); 8 | output.y = (float)atof(input.substr(firstComma + 1, secondComma - (firstComma + 1)).c_str()); 9 | output.z = (float)atof(input.substr(secondComma + 1).c_str()); 10 | } 11 | 12 | bool needsInput(FileOutputType type) { 13 | return type != FileOutputType::Materials; 14 | } 15 | 16 | bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArguments& output) { 17 | output.mInputFile = ""; 18 | output.mOutputFile = ""; 19 | output.mPrefix = "output"; 20 | output.mFixedPointScale = 256.0f; 21 | output.mModelScale = 1.0f; 22 | output.mExportAnimation = true; 23 | output.mExportGeometry = true; 24 | output.mBonesAsVertexGroups = false; 25 | output.mTargetCIBuffer = false; 26 | output.mOutputType = FileOutputType::Mesh; 27 | output.mEulerAngles = aiVector3D(0.0f, 0.0f, 0.0f); 28 | output.mDefaultMaterial = "default"; 29 | output.mForceMaterialName = ""; 30 | output.mProcessAsModel = false; 31 | output.mFPS = 30.0f; 32 | 33 | std::string lastParameter = ""; 34 | bool hasError = false; 35 | 36 | for (int i = 1; i < argc; ++i) { 37 | char* curr = argv[i]; 38 | 39 | if (lastParameter != "") { 40 | if (lastParameter == "output") { 41 | if (output.mOutputFile != "") { 42 | std::cerr << "You can only specify a single output file" << std::endl; 43 | hasError = true; 44 | } 45 | 46 | output.mOutputFile = curr; 47 | } else if (lastParameter == "name") { 48 | output.mPrefix = curr; 49 | } else if (lastParameter == "fixed-point-scale") { 50 | output.mFixedPointScale = (float)atof(curr); 51 | } else if (lastParameter == "model-scale") { 52 | output.mModelScale = (float)atof(curr); 53 | } else if (lastParameter == "materials") { 54 | output.mMaterialFiles.push_back(curr); 55 | } else if (lastParameter == "rotate") { 56 | parseEulerAngles(curr, output.mEulerAngles); 57 | } else if (lastParameter == "default-material") { 58 | output.mDefaultMaterial = curr; 59 | } else if (lastParameter == "force-material") { 60 | output.mForceMaterialName = curr; 61 | } else if (lastParameter == "pallete") { 62 | output.mForcePallete = curr; 63 | } else if (lastParameter == "script") { 64 | output.mScriptFiles.push_back(curr); 65 | } else if (lastParameter == "fps") { 66 | output.mFPS = (float)atof(curr); 67 | } 68 | 69 | lastParameter = ""; 70 | } else if ( 71 | strcmp(curr, "-o") == 0 || 72 | strcmp(curr, "--output") == 0) { 73 | lastParameter = "output"; 74 | } else if ( 75 | strcmp(curr, "-n") == 0 || 76 | strcmp(curr, "--name") == 0) { 77 | lastParameter = "name"; 78 | } else if (strcmp(curr, "--fixed-point-scale") == 0) { 79 | lastParameter = "fixed-point-scale"; 80 | } else if (strcmp(curr, "--model-scale") == 0) { 81 | lastParameter = "model-scale"; 82 | } else if ( 83 | strcmp(curr, "-m") == 0 || 84 | strcmp(curr, "--materials") == 0) { 85 | lastParameter = "materials"; 86 | } else if (strcmp(curr, "--material-output") == 0) { 87 | output.mOutputType = FileOutputType::Materials; 88 | } else if (strcmp(curr, "--mesh-collider") == 0) { 89 | output.mOutputType = FileOutputType::CollisionMesh; 90 | } else if ( 91 | strcmp(curr, "-r") == 0 || 92 | strcmp(curr, "--rotate") == 0) { 93 | lastParameter = "rotate"; 94 | } else if ( 95 | strcmp(curr, "--pallete") == 0) { 96 | lastParameter = "pallete"; 97 | } else if ( 98 | strcmp(curr, "-a") == 0 || 99 | strcmp(curr, "--animations-only") == 0) { 100 | output.mExportGeometry = false; 101 | } else if (strcmp(curr, "--boneless") == 0) { 102 | output.mBonesAsVertexGroups = true; 103 | } else if (strcmp(curr, "--default-material") == 0) { 104 | lastParameter = "default-material"; 105 | } else if (strcmp(curr, "--force-material") == 0) { 106 | lastParameter = "force-material"; 107 | } else if (strcmp(curr, "--script") == 0) { 108 | output.mOutputType = FileOutputType::Script; 109 | lastParameter = "script"; 110 | } else if (strcmp(curr, "--ci-buffer") == 0) { 111 | output.mTargetCIBuffer = true; 112 | } else if (strcmp(curr, "--model") == 0) { 113 | output.mProcessAsModel = true; 114 | } else if (strcmp(curr, "--fps") == 0) { 115 | lastParameter = "fps"; 116 | } else { 117 | if (curr[0] == '-') { 118 | hasError = true; 119 | std::cerr << "Unrecognized argument '" << curr << '"' << std::endl; 120 | } else if (output.mInputFile == "") { 121 | output.mInputFile = curr; 122 | } else { 123 | hasError = true; 124 | std::cerr << "Only one input file allowed. " << 125 | "Already gave '" << output.mInputFile << "'" << 126 | ". And then got '" << curr << "'" << std::endl; 127 | } 128 | } 129 | } 130 | 131 | if (output.mOutputFile == "") { 132 | std::cerr << "No output file specified" << std::endl; 133 | hasError = true; 134 | } 135 | 136 | if (output.mInputFile == "" && needsInput(output.mOutputType)) { 137 | std::cerr << "No input file specified" << std::endl; 138 | hasError = true; 139 | } 140 | 141 | if (hasError) { 142 | std::cerr << "usage " << argv[0] << " [ARGS] -o [output-file] [input-file]" << std::endl; 143 | } 144 | 145 | if (output.mOutputFile.length() > 2 && output.mOutputFile.substr(output.mOutputFile.length() - 2) == ".h") { 146 | output.mOutputFile = output.mOutputFile.substr(0, output.mOutputFile.length() - 2); 147 | } 148 | 149 | return !hasError; 150 | } -------------------------------------------------------------------------------- /src/CommandLineParser.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMAND_LINE_PARSER_H 2 | #define _COMMAND_LINE_PARSER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum class FileOutputType { 11 | Mesh, 12 | Materials, 13 | CollisionMesh, 14 | Script, 15 | }; 16 | 17 | struct CommandLineArguments { 18 | std::string mInputFile; 19 | std::string mOutputFile; 20 | FileOutputType mOutputType; 21 | std::string mPrefix; 22 | std::vector mMaterialFiles; 23 | std::vector mScriptFiles; 24 | std::string mDefaultMaterial; 25 | std::string mForceMaterialName; 26 | std::string mForcePallete; 27 | float mFixedPointScale; 28 | float mModelScale; 29 | float mFPS; 30 | bool mExportAnimation; 31 | bool mExportGeometry; 32 | bool mBonesAsVertexGroups; 33 | bool mTargetCIBuffer; 34 | bool mProcessAsModel; 35 | aiVector3D mEulerAngles; 36 | }; 37 | 38 | bool parseCommandLineArguments(int argc, char *argv[], struct CommandLineArguments& output); 39 | 40 | #endif -------------------------------------------------------------------------------- /src/DisplayList.h: -------------------------------------------------------------------------------- 1 | #ifndef _DISPLAY_LIST_H 2 | #define _DISPLAY_LIST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "./definitions/FileDefinition.h" 10 | #include "./materials/MaterialEnums.h" 11 | 12 | enum class DisplayListCommandType { 13 | COMMENT, 14 | RAW, 15 | G_VTX, 16 | G_TRI1, 17 | G_TRI2, 18 | G_MTX, 19 | G_POPMTX, 20 | G_DL, 21 | G_GEOMETRYMODE, 22 | G_CULLDL, 23 | }; 24 | 25 | class DisplayList; 26 | class CFileDefinition; 27 | 28 | struct DisplayListCommand { 29 | DisplayListCommand(DisplayListCommandType type); 30 | virtual ~DisplayListCommand(); 31 | 32 | DisplayListCommandType mType; 33 | 34 | virtual std::unique_ptr GenerateCommand() = 0; 35 | }; 36 | 37 | 38 | struct CommentCommand : DisplayListCommand { 39 | CommentCommand(std::string comment); 40 | 41 | std::string mComment; 42 | 43 | std::unique_ptr GenerateCommand(); 44 | }; 45 | 46 | struct RawContentCommand : DisplayListCommand { 47 | RawContentCommand(std::string content); 48 | 49 | std::string mContent; 50 | 51 | std::unique_ptr GenerateCommand(); 52 | }; 53 | 54 | struct VTXCommand : DisplayListCommand { 55 | VTXCommand( 56 | int numVerts, 57 | int indexBufferStart, 58 | std::string vertexBuffer, 59 | int vertexBufferOffset 60 | ); 61 | 62 | int mNumVerts; 63 | int mIndexBufferStart; 64 | std::string mVertexBuffer; 65 | int mVertexBufferOffset; 66 | 67 | std::unique_ptr GenerateCommand(); 68 | }; 69 | 70 | struct TRI1Command : DisplayListCommand { 71 | TRI1Command(int a, int b, int c); 72 | 73 | int mA; 74 | int mB; 75 | int mC; 76 | 77 | std::unique_ptr GenerateCommand(); 78 | }; 79 | 80 | struct TRI2Command : DisplayListCommand { 81 | TRI2Command(int a0, int b0, int c0, int a1, int b1, int c1); 82 | 83 | int mA0; 84 | int mB0; 85 | int mC0; 86 | 87 | int mA1; 88 | int mB1; 89 | int mC1; 90 | 91 | std::unique_ptr GenerateCommand(); 92 | }; 93 | 94 | struct CallDisplayListCommand { 95 | CallDisplayListCommand(int targetDL, int offset); 96 | 97 | int mTargetDL; 98 | int mOffset; 99 | 100 | std::unique_ptr GenerateCommand(); 101 | }; 102 | 103 | struct CallDisplayListByNameCommand : DisplayListCommand { 104 | CallDisplayListByNameCommand(const std::string& dlName); 105 | 106 | std::string mDLName; 107 | 108 | std::unique_ptr GenerateCommand(); 109 | }; 110 | 111 | struct PushMatrixCommand : DisplayListCommand { 112 | PushMatrixCommand(unsigned int matrixOffset, bool replace); 113 | std::unique_ptr GenerateCommand(); 114 | 115 | unsigned int mMatrixOffset; 116 | bool mReplace; 117 | }; 118 | 119 | struct PopMatrixCommand : DisplayListCommand { 120 | PopMatrixCommand(unsigned int popCount); 121 | std::unique_ptr GenerateCommand(); 122 | 123 | unsigned int mPopCount; 124 | }; 125 | 126 | struct ChangeGeometryMode : DisplayListCommand { 127 | ChangeGeometryMode(GeometryMode clear, GeometryMode set); 128 | std::unique_ptr GenerateCommand(); 129 | 130 | GeometryMode mClear; 131 | GeometryMode mSet; 132 | }; 133 | 134 | struct CullDisplayList : DisplayListCommand { 135 | CullDisplayList(unsigned int vertexCount); 136 | std::unique_ptr GenerateCommand(); 137 | unsigned int mVertexCount; 138 | }; 139 | 140 | class DisplayList { 141 | public: 142 | DisplayList(std::string name); 143 | void AddCommand(std::unique_ptr command); 144 | StructureDataChunk& GetDataChunk(); 145 | 146 | const std::string& GetName(); 147 | std::unique_ptr Generate(const std::string& fileSuffix); 148 | private: 149 | std::string mName; 150 | std::unique_ptr mDataChunk; 151 | }; 152 | 153 | #endif -------------------------------------------------------------------------------- /src/DisplayListGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "./DisplayListGenerator.h" 7 | 8 | bool doesFaceFit(std::set& indices, aiFace* face, unsigned int maxVertices) { 9 | unsigned int misses = 0; 10 | 11 | for (unsigned int i = 0; i < face->mNumIndices; ++i) { 12 | if (indices.find(face->mIndices[i]) == indices.end()) { 13 | ++misses; 14 | } 15 | } 16 | 17 | return indices.size() + misses <= maxVertices; 18 | } 19 | 20 | void flushVertices(RenderChunk& chunk, std::set& currentVertices, std::vector& currentFaces, RCPState& state, std::string vertexBuffer, DisplayList& output, bool hasTri2) { 21 | std::vector verticesAsVector(currentVertices.begin(), currentVertices.end()); 22 | 23 | std::sort(verticesAsVector.begin(), verticesAsVector.end(), 24 | [=](int a, int b) -> bool { 25 | Bone* boneA = chunk.mMesh->mVertexBones[a]; 26 | Bone* boneB = chunk.mMesh->mVertexBones[b]; 27 | 28 | if (boneA != boneB && (boneA == chunk.mBonePair.first || boneB == chunk.mBonePair.second)) { 29 | return true; 30 | } 31 | 32 | return a < b; 33 | }); 34 | 35 | VertexData vertexData[MAX_VERTEX_CACHE_SIZE]; 36 | 37 | for (unsigned int vertexIndex = 0; vertexIndex < verticesAsVector.size() && vertexIndex < MAX_VERTEX_CACHE_SIZE; ++vertexIndex) { 38 | vertexData[vertexIndex] = VertexData(vertexBuffer, verticesAsVector[vertexIndex], -1); 39 | } 40 | 41 | unsigned int cacheLocation[MAX_VERTEX_CACHE_SIZE]; 42 | 43 | state.AssignSlots(vertexData, cacheLocation, verticesAsVector.size()); 44 | int lastVertexIndex = -1; 45 | int lastCacheLocation = MAX_VERTEX_CACHE_SIZE; 46 | int vertexCount = 0; 47 | Bone* lastBone = nullptr; 48 | std::map vertexMapping; 49 | 50 | for (unsigned int index = 0; index <= verticesAsVector.size(); ++index) { 51 | int vertexIndex; 52 | int cacheIndex; 53 | Bone* bone = nullptr; 54 | 55 | if (index < verticesAsVector.size()) { 56 | vertexIndex = verticesAsVector[index]; 57 | cacheIndex = cacheLocation[index]; 58 | vertexMapping[vertexIndex] = cacheIndex; 59 | bone = chunk.mMesh->mVertexBones[vertexIndex]; 60 | } 61 | 62 | if (index == verticesAsVector.size() || 63 | (index != 0 && ( 64 | vertexIndex != lastVertexIndex + 1 || 65 | cacheIndex != lastCacheLocation + 1 || bone != lastBone 66 | ))) { 67 | state.TraverseToBone(lastBone, output); 68 | output.AddCommand(std::unique_ptr(new VTXCommand( 69 | vertexCount, 70 | lastCacheLocation + 1 - vertexCount, 71 | vertexBuffer, 72 | lastVertexIndex + 1 - vertexCount 73 | ))); 74 | 75 | vertexCount = 1; 76 | } else { 77 | ++vertexCount; 78 | } 79 | 80 | lastVertexIndex = vertexIndex; 81 | lastCacheLocation = cacheIndex; 82 | lastBone = bone; 83 | } 84 | 85 | for (unsigned int faceIndex = 0; faceIndex < currentFaces.size(); ++faceIndex) { 86 | if (hasTri2 && faceIndex + 1 < currentFaces.size()) { 87 | aiFace* currFace = currentFaces[faceIndex + 0]; 88 | aiFace* nextFace = currentFaces[faceIndex + 1]; 89 | 90 | output.AddCommand(std::unique_ptr(new TRI2Command( 91 | vertexMapping.at(currFace->mIndices[0]), vertexMapping.at(currFace->mIndices[1]), vertexMapping.at(currFace->mIndices[2]), 92 | vertexMapping.at(nextFace->mIndices[0]), vertexMapping.at(nextFace->mIndices[1]), vertexMapping.at(nextFace->mIndices[2]) 93 | ))); 94 | 95 | ++faceIndex; 96 | } else { 97 | aiFace* currFace = currentFaces[faceIndex + 0]; 98 | 99 | output.AddCommand(std::unique_ptr(new TRI1Command( 100 | vertexMapping.at(currFace->mIndices[0]), vertexMapping.at(currFace->mIndices[1]), vertexMapping.at(currFace->mIndices[2]) 101 | ))); 102 | } 103 | } 104 | } 105 | 106 | void generateCulling(DisplayList& output, std::string vertexBuffer, bool renableLighting) { 107 | output.AddCommand(std::unique_ptr(new ChangeGeometryMode(GeometryMode::G_LIGHTING, GeometryMode::None))); 108 | output.AddCommand(std::unique_ptr(new VTXCommand(8, 0, vertexBuffer, 0))); 109 | output.AddCommand(std::unique_ptr(new CullDisplayList(8))); 110 | if (renableLighting) { 111 | output.AddCommand(std::unique_ptr(new ChangeGeometryMode(GeometryMode::None, GeometryMode::G_LIGHTING))); 112 | } 113 | } 114 | 115 | void generateGeometry(RenderChunk& chunk, RCPState& state, std::string vertexBuffer, DisplayList& output, bool hasTri2) { 116 | std::set currentVertices; 117 | std::vector currentFaces; 118 | 119 | const std::vector& faces = chunk.GetFaces(); 120 | 121 | for (unsigned int faceIndex = 0; faceIndex <= faces.size(); ++faceIndex) { 122 | if (faceIndex == faces.size() || !doesFaceFit(currentVertices, faces[faceIndex], state.GetMaxVertices())) { 123 | flushVertices(chunk, currentVertices, currentFaces, state, vertexBuffer, output, hasTri2); 124 | 125 | currentVertices.clear(); 126 | currentFaces.clear(); 127 | 128 | if (faceIndex == faces.size()) { 129 | break; 130 | } 131 | } 132 | 133 | for (unsigned int vertexIndex = 0; vertexIndex < faces[faceIndex]->mNumIndices; ++vertexIndex) { 134 | currentVertices.insert(faces[faceIndex]->mIndices[vertexIndex]); 135 | } 136 | 137 | currentFaces.push_back(faces[faceIndex]); 138 | } 139 | } -------------------------------------------------------------------------------- /src/DisplayListGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef _DISPLAY_LIST_GENERATOR_H 2 | #define _DISPLAY_LIST_GENERATOR_H 3 | 4 | #include 5 | #include "./RCPState.h" 6 | #include "./DisplayList.h" 7 | #include "./CFileDefinition.h" 8 | #include "./RenderChunk.h" 9 | 10 | void generateCulling(DisplayList& output, std::string vertexBuffer, bool renableLighting); 11 | void generateGeometry(RenderChunk& mesh, RCPState& state, std::string vertexBuffer, DisplayList& output, bool hasTri2); 12 | 13 | #endif -------------------------------------------------------------------------------- /src/DisplayListSettings.cpp: -------------------------------------------------------------------------------- 1 | #include "DisplayListSettings.h" 2 | 3 | #include "RCPState.h" 4 | 5 | DisplayListSettings::DisplayListSettings(): 6 | mPrefix(""), 7 | mVertexCacheSize(MAX_VERTEX_CACHE_SIZE), 8 | mHasTri2(true), 9 | mFixedPointScale(256.0f), 10 | mModelScale(1.0f), 11 | mMaxMatrixDepth(10), 12 | mMaxOptimizationIterations(DEFAULT_MAX_OPTIMIZATION_ITERATIONS), 13 | mCanPopMultipleMatrices(true), 14 | mTicksPerSecond(30.0f), 15 | mExportAnimation(true), 16 | mExportGeometry(true), 17 | mIncludeCulling(true), 18 | mTargetCIBuffer(false) { 19 | } 20 | 21 | aiMatrix4x4 DisplayListSettings::CreateGlobalTransform() const { 22 | aiMatrix4x4 scale; 23 | aiMatrix4x4::Scaling(aiVector3D(1, 1, 1) * mFixedPointScale * mModelScale, scale); 24 | aiMatrix4x4 rotation(mRotateModel.GetMatrix()); 25 | 26 | return rotation * scale; 27 | } 28 | 29 | aiMatrix4x4 DisplayListSettings::CreateCollisionTransform() const { 30 | aiMatrix4x4 scale; 31 | aiMatrix4x4::Scaling(aiVector3D(1, 1, 1) * mModelScale, scale); 32 | aiMatrix4x4 rotation(mRotateModel.GetMatrix()); 33 | 34 | return rotation * scale; 35 | } 36 | 37 | bool DisplayListSettings::NeedsTangents() const { 38 | for (auto& material : mMaterials) { 39 | if (material.second->mNormalSource != NormalSource::Normal) { 40 | return true; 41 | } 42 | } 43 | 44 | return false; 45 | } -------------------------------------------------------------------------------- /src/DisplayListSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef _DISPLAY_LIST_SETTINGS_H 2 | #define _DISPLAY_LIST_SETTINGS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "./materials/Material.h" 9 | #include "./materials/MaterialState.h" 10 | 11 | #define DEFAULT_MAX_OPTIMIZATION_ITERATIONS 1000 12 | 13 | struct DisplayListSettings { 14 | DisplayListSettings(); 15 | std::string mPrefix; 16 | int mVertexCacheSize; 17 | bool mHasTri2; 18 | float mFixedPointScale; 19 | float mModelScale; 20 | int mMaxMatrixDepth; 21 | int mMaxOptimizationIterations; 22 | bool mCanPopMultipleMatrices; 23 | float mTicksPerSecond; 24 | std::map> mMaterials; 25 | std::string mDefaultMaterialName; 26 | std::string mForceMaterialName; 27 | std::string mForcePallete; 28 | MaterialState mDefaultMaterialState; 29 | aiQuaternion mRotateModel; 30 | bool mExportAnimation; 31 | bool mExportGeometry; 32 | bool mIncludeCulling; 33 | bool mBonesAsVertexGroups; 34 | bool mTargetCIBuffer; 35 | 36 | aiMatrix4x4 CreateGlobalTransform() const; 37 | aiMatrix4x4 CreateCollisionTransform() const; 38 | 39 | bool NeedsTangents() const; 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /src/Enum.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambertjamesd/skelatool64/708cfcae7734dc3d3997286976bbf32f5009da01/src/Enum.h -------------------------------------------------------------------------------- /src/ErrorCode.h: -------------------------------------------------------------------------------- 1 | #ifndef _ERROR_CODE_H 2 | #define _ERROR_CODE_H 3 | 4 | enum class ErrorCode { 5 | None, 6 | ModelTooLarge, 7 | MatrixStackOverflow, 8 | }; 9 | 10 | #endif -------------------------------------------------------------------------------- /src/ErrorResult.cpp: -------------------------------------------------------------------------------- 1 | #include "ErrorResult.h" 2 | 3 | ErrorResult::ErrorResult() : mMessage("") {} 4 | 5 | ErrorResult::ErrorResult(const std::string& message) : mMessage(message) {} 6 | 7 | bool ErrorResult::HasError() const { 8 | return mMessage.length() > 0; 9 | } 10 | 11 | const std::string& ErrorResult::GetMessage() const { 12 | return mMessage; 13 | } -------------------------------------------------------------------------------- /src/ErrorResult.h: -------------------------------------------------------------------------------- 1 | #ifndef __ERROR_RESULT_H__ 2 | #define __ERROR_RESULT_H__ 3 | 4 | #include 5 | 6 | class ErrorResult { 7 | public: 8 | ErrorResult(); 9 | ErrorResult(const std::string& message); 10 | 11 | bool HasError() const; 12 | const std::string& GetMessage() const; 13 | private: 14 | std::string mMessage; 15 | }; 16 | 17 | #endif -------------------------------------------------------------------------------- /src/ExtendedMesh.h: -------------------------------------------------------------------------------- 1 | #ifndef _EXTENDED_MESH_H 2 | #define _EXTENDED_MESH_H 3 | 4 | #include 5 | #include "BoneHierarchy.h" 6 | #include 7 | #include 8 | #include 9 | 10 | enum class VertexType { 11 | PosUVNormal, 12 | PosUVColor, 13 | POSUVTangent, 14 | POSUVMinusTangent, 15 | POSUVCotangent, 16 | POSUVMinusCotangent, 17 | }; 18 | 19 | class ExtendedMesh { 20 | public: 21 | ExtendedMesh(const ExtendedMesh& other); 22 | ExtendedMesh(aiMesh* mesh, BoneHierarchy& boneHierarchy); 23 | ~ExtendedMesh(); 24 | aiMesh* mMesh; 25 | std::vector mPointInverseTransform; 26 | std::vector mNormalInverseTransform; 27 | std::vector mVertexBones; 28 | std::map> mFacesForBone; 29 | // first bone in pair is always the parent of the second 30 | std::map, std::vector> mBoneSpanningFaces; 31 | aiVector3D bbMin; 32 | aiVector3D bbMax; 33 | 34 | void RecalcBB(); 35 | 36 | std::shared_ptr Transform(const aiMatrix4x4& transform) const; 37 | void ReplaceColor(const aiColor4D& color); 38 | void CubeProjectTex(double sTile, double tTile, aiQuaternion rotation, aiVector3D translation); 39 | 40 | bool isFaceOneBone(aiFace* face); 41 | std::pair findTransitionPairForFace(aiFace* face); 42 | 43 | static std::string GetMaterialName(aiMaterial* material, const std::string& forceMaterial); 44 | private: 45 | void PopulateFacesForBone(); 46 | }; 47 | 48 | aiMesh* copyMesh(aiMesh* mesh); 49 | 50 | void findAdjacentVertices(aiMesh* mesh, unsigned fromIndex, std::set& result); 51 | 52 | #endif -------------------------------------------------------------------------------- /src/FileUtils.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "FileUtils.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | std::string gCwd; 11 | 12 | #define MAX_PATH 256 13 | 14 | const std::string& GetCwd() { 15 | if (!gCwd.length()) { 16 | char buffer[MAX_PATH]; 17 | if (getcwd(buffer, MAX_PATH)) { 18 | gCwd = buffer; 19 | } 20 | } 21 | 22 | return gCwd; 23 | } 24 | 25 | bool isPathCharacter(char chr) { 26 | return chr == '\\' || chr == '/'; 27 | } 28 | 29 | std::string replaceExtension(const std::string& input, const std::string& newExt) { 30 | std::size_t extPos = input.rfind('.'); 31 | 32 | if (extPos == std::string::npos) { 33 | return input + newExt; 34 | } else { 35 | return input.substr(0, extPos) + newExt; 36 | } 37 | } 38 | 39 | std::string getBaseName(const std::string& input) { 40 | std::size_t pathPos = input.rfind('/'); 41 | std::size_t wrongPathPos = input.rfind('\\'); 42 | 43 | if (wrongPathPos != std::string::npos && pathPos != std::string::npos) { 44 | pathPos = std::max(pathPos, wrongPathPos); 45 | } else if (wrongPathPos != std::string::npos) { 46 | pathPos = wrongPathPos; 47 | } 48 | 49 | if (pathPos == std::string::npos) { 50 | return input; 51 | } else { 52 | return input.substr(pathPos + 1); 53 | } 54 | } 55 | 56 | std::string DirectoryName(const std::string& filename) { 57 | std::size_t correctSlash = filename.rfind('/'); 58 | std::size_t wrongSlash = filename.rfind('\\'); 59 | 60 | if (correctSlash != std::string::npos && wrongSlash != std::string::npos) { 61 | correctSlash = std::max(correctSlash, wrongSlash); 62 | } 63 | 64 | if (correctSlash == std::string::npos) { 65 | return ""; 66 | } 67 | 68 | return filename.substr(0, correctSlash); 69 | } 70 | 71 | std::size_t nextPathCharacter(const std::string& input, std::size_t curr) { 72 | std::size_t correctPath = input.find('/', curr); 73 | std::size_t wrongPath = input.find('\\', curr); 74 | 75 | if (correctPath != std::string::npos && wrongPath != std::string::npos) { 76 | return std::min(correctPath, wrongPath); 77 | } else if (correctPath != std::string::npos) { 78 | return correctPath; 79 | } else { 80 | return wrongPath; 81 | } 82 | } 83 | 84 | void separatePath(const std::string& input, std::vector& output) { 85 | std::size_t curr = 0; 86 | 87 | do { 88 | std::size_t next = nextPathCharacter(input, curr); 89 | 90 | if (next == std::string::npos) { 91 | output.push_back(input.substr(curr)); 92 | curr = std::string::npos; 93 | } else { 94 | output.push_back(input.substr(curr, next - curr)); 95 | curr = next + 1; 96 | } 97 | 98 | } while (curr != std::string::npos); 99 | } 100 | 101 | std::string Join(const std::string& a, const std::string& b) { 102 | if (b.length() == 0) { 103 | return a; 104 | } 105 | 106 | if (isPathCharacter(b[0])) { 107 | return b; 108 | } 109 | 110 | std::vector parts; 111 | 112 | separatePath(a, parts); 113 | separatePath(b, parts); 114 | 115 | std::vector normalizedParts; 116 | 117 | int skipCount = 0; 118 | 119 | for (int i = parts.size() - 1; i >= 0; --i) { 120 | if (parts[i] == "..") { 121 | ++skipCount; 122 | } else if (parts[i] == ".") { 123 | continue; 124 | } else if (skipCount) { 125 | --skipCount; 126 | } else if (parts[i] != ".") { 127 | normalizedParts.push_back(parts[i]); 128 | } 129 | } 130 | 131 | std::ostringstream result; 132 | 133 | for (int i = normalizedParts.size() - 1; i >= 0; --i) { 134 | if (i != (int)normalizedParts.size() - 1) { 135 | result << "/"; 136 | } 137 | 138 | result << normalizedParts[i]; 139 | } 140 | 141 | return result.str(); 142 | } 143 | 144 | std::vector SplitOnFirstPath(const std::string& path) { 145 | std::size_t lastStart = 0; 146 | 147 | std::vector result; 148 | 149 | bool hasMore = true; 150 | 151 | while (hasMore) { 152 | std::size_t pathPos = path.find('/', lastStart); 153 | std::size_t wrongPathPos = path.find('\\', lastStart); 154 | 155 | if (pathPos != std::string::npos && wrongPathPos != std::string::npos) { 156 | pathPos = std::min(pathPos, wrongPathPos); 157 | } 158 | 159 | if (pathPos == std::string::npos) { 160 | hasMore = false; 161 | result.push_back(path.substr(lastStart)); 162 | } else { 163 | if (pathPos != lastStart) { 164 | result.push_back(path.substr(lastStart, pathPos - lastStart)); 165 | } 166 | lastStart = pathPos + 1; 167 | } 168 | } 169 | 170 | return result; 171 | } 172 | 173 | std::string Relative(const std::string& from, const std::string& to) { 174 | std::vector fromPathSplit = SplitOnFirstPath(DirectoryName(from)); 175 | std::vector toPathSplit = SplitOnFirstPath(to); 176 | 177 | unsigned commonStart = 0; 178 | 179 | while (commonStart < fromPathSplit.size() && commonStart < toPathSplit.size() && fromPathSplit[commonStart] == toPathSplit[commonStart]) { 180 | ++commonStart; 181 | } 182 | 183 | std::ostringstream result; 184 | 185 | for (unsigned i = commonStart; i < fromPathSplit.size(); ++i) { 186 | result << "../"; 187 | } 188 | 189 | for (unsigned i = commonStart; i < toPathSplit.size(); ++i) { 190 | result << toPathSplit[i]; 191 | 192 | if (i+1 != toPathSplit.size()) { 193 | result << '/'; 194 | } 195 | } 196 | 197 | return result.str(); 198 | } 199 | 200 | std::string NormalizePath(const std::string& path) { 201 | return Join(GetCwd(), path); 202 | } 203 | 204 | bool FileExists(const std::string& path) { 205 | std::ifstream tmp; 206 | tmp.open(path); 207 | 208 | bool result = (bool)tmp; 209 | 210 | if (result) { 211 | tmp.close(); 212 | } 213 | 214 | return result; 215 | } -------------------------------------------------------------------------------- /src/FileUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef _FILE_UTILS_H 2 | #define _FILE_UTILS_H 3 | 4 | #include 5 | 6 | bool isPathCharacter(char chr); 7 | 8 | std::string replaceExtension(const std::string& input, const std::string& newExt); 9 | std::string getBaseName(const std::string& input); 10 | 11 | std::string DirectoryName(const std::string& filename); 12 | std::string Join(const std::string& a, const std::string& b); 13 | std::string Relative(const std::string& from, const std::string& to); 14 | 15 | std::string NormalizePath(const std::string& path); 16 | 17 | bool FileExists(const std::string& path); 18 | 19 | #endif -------------------------------------------------------------------------------- /src/MathUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "MathUtl.h" 2 | 3 | #include 4 | 5 | aiVector3D min(const aiVector3D& a, const aiVector3D& b) { 6 | return aiVector3D(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z)); 7 | } 8 | 9 | aiVector3D max(const aiVector3D& a, const aiVector3D& b) { 10 | return aiVector3D(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z)); 11 | } 12 | 13 | float distanceToAABB(const aiAABB& aabb, const aiVector3D& point) { 14 | aiVector3D closestPoint = max(aabb.mMin, min(aabb.mMax, point)); 15 | 16 | if (closestPoint == point) { 17 | // return negative penetration depth 18 | aiVector3D maxOffset = point - aabb.mMax; 19 | aiVector3D minOffset = aabb.mMin - point; 20 | 21 | return std::max( 22 | std::max( 23 | std::max(maxOffset.x, maxOffset.y), 24 | std::max(maxOffset.z, minOffset.x) 25 | ), 26 | std::max(minOffset.y, minOffset.z) 27 | ); 28 | } else { 29 | return (closestPoint - point).Length(); 30 | } 31 | } 32 | 33 | bool doesAABBOverlap(const aiAABB& a, const aiAABB& b) { 34 | return a.mMin.x < b.mMax.x && b.mMin.x < a.mMax.x && 35 | a.mMin.y < b.mMax.y && b.mMin.y < a.mMax.y && 36 | a.mMin.z < b.mMax.z && b.mMin.z < a.mMax.z; 37 | } -------------------------------------------------------------------------------- /src/MathUtl.h: -------------------------------------------------------------------------------- 1 | #ifndef MATH_UTIL_H 2 | #define MATH_UTIL_H 3 | 4 | #include 5 | 6 | aiVector3D min(const aiVector3D& a, const aiVector3D& b); 7 | aiVector3D max(const aiVector3D& a, const aiVector3D& b); 8 | 9 | float distanceToAABB(const aiAABB& aabb, const aiVector3D& point); 10 | bool doesAABBOverlap(const aiAABB& a, const aiAABB& b); 11 | 12 | #endif -------------------------------------------------------------------------------- /src/MeshWriter.h: -------------------------------------------------------------------------------- 1 | #ifndef _MESH_WRITER_H 2 | #define _MESH_WRITER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "RenderChunk.h" 11 | #include "DisplayListSettings.h" 12 | #include "CFileDefinition.h" 13 | #include "./materials/TextureDefinition.h" 14 | 15 | class MaterialCollector { 16 | public: 17 | MaterialCollector(); 18 | void UseMaterial(const std::string& material, DisplayListSettings& settings); 19 | void CollectMaterialResources(const aiScene* scene, std::vector& renderChunks, DisplayListSettings& settings); 20 | void GenerateMaterials(DisplayListSettings& settings, CFileDefinition& fileDefinition, const std::string& fileSuffix); 21 | 22 | unsigned mSceneCount; 23 | std::set> mUsedTextures; 24 | std::set> mUsedPalletes; 25 | std::map mMaterialUseCount; 26 | std::map mMaterialNameMapping; 27 | std::map mResourceNameMapping; 28 | 29 | private: 30 | }; 31 | 32 | void generateMeshIntoDLWithMaterials(const aiScene* scene, CFileDefinition& fileDefinition, MaterialCollector* materials, std::vector& renderChunks, DisplayListSettings& settings, DisplayList &displayList, const std::string& modelSuffix); 33 | void generateMeshIntoDL(const aiScene* scene, CFileDefinition& fileDefinition, std::vector& renderChunks, DisplayListSettings& settings, DisplayList &displayList, const std::string& fileSuffix); 34 | std::string generateMesh(const aiScene* scene, CFileDefinition& fileDefinition, std::vector& renderChunks, DisplayListSettings& settings, const std::string& fileSuffix); 35 | 36 | #endif -------------------------------------------------------------------------------- /src/RCPState.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "./RCPState.h" 3 | 4 | #include 5 | 6 | VertexData::VertexData() : 7 | mVertexBuffer("-1"), 8 | mVertexIndex(-1), 9 | mMatrixIndex(-1) { 10 | 11 | } 12 | 13 | VertexData::VertexData(std::string vertexBuffer, int vertexIndex, int matrixIndex) : 14 | mVertexBuffer(vertexBuffer), 15 | mVertexIndex(vertexIndex), 16 | mMatrixIndex(matrixIndex) { 17 | 18 | } 19 | 20 | const bool VertexData::operator==(const VertexData& other) { 21 | return mVertexBuffer == other.mVertexBuffer && 22 | mVertexIndex == other.mVertexIndex && 23 | mMatrixIndex == other.mMatrixIndex; 24 | } 25 | 26 | RCPState::RCPState(const MaterialState& materialState, unsigned int maxVertexCount, unsigned int maxMatrixDepth, bool canPopMultiple) : 27 | mMaterialState(materialState), 28 | mMaxVertices(maxVertexCount), 29 | mMaxMatrixDepth(maxMatrixDepth), 30 | mCanPopMultiple(canPopMultiple) { 31 | 32 | } 33 | 34 | ErrorCode RCPState::TraverseToBone(Bone* bone, DisplayList& output) { 35 | std::set bonesToPop(mBoneMatrixStack.begin(), mBoneMatrixStack.end()); 36 | 37 | Bone* curr = bone; 38 | 39 | while (curr) { 40 | bonesToPop.erase(curr); 41 | curr = curr->GetParent(); 42 | } 43 | 44 | if (mCanPopMultiple) { 45 | if (bonesToPop.size() != 0) { 46 | output.AddCommand(std::unique_ptr(new PopMatrixCommand(bonesToPop.size()))); 47 | } 48 | } else { 49 | for (unsigned int i = 0; i < bonesToPop.size(); ++i) { 50 | output.AddCommand(std::unique_ptr(new PopMatrixCommand(1))); 51 | } 52 | } 53 | 54 | mBoneMatrixStack.resize(mBoneMatrixStack.size() - bonesToPop.size()); 55 | 56 | std::vector bonesToAdd; 57 | 58 | curr = bone; 59 | 60 | while (curr != nullptr && (mBoneMatrixStack.size() == 0 || *mBoneMatrixStack.rbegin() != curr)) { 61 | bonesToAdd.push_back(curr); 62 | curr = curr->GetParent(); 63 | } 64 | 65 | for (auto curr = bonesToAdd.rbegin(); curr != bonesToAdd.rend(); ++curr) { 66 | if (mBoneMatrixStack.size() == mMaxMatrixDepth) { 67 | return ErrorCode::MatrixStackOverflow; 68 | } 69 | 70 | mBoneMatrixStack.push_back(*curr); 71 | output.AddCommand(std::unique_ptr(new CommentCommand((*curr)->GetName()))); 72 | output.AddCommand(std::unique_ptr(new PushMatrixCommand((*curr)->GetIndex(), false))); 73 | } 74 | 75 | return ErrorCode::None; 76 | } 77 | 78 | void RCPState::AssignSlots(VertexData* newVertices, unsigned int* slotIndex, unsigned int vertexCount) { 79 | bool usedSlots[MAX_VERTEX_CACHE_SIZE]; 80 | bool assignedVertices[MAX_VERTEX_CACHE_SIZE]; 81 | for (unsigned int i = 0; i < MAX_VERTEX_CACHE_SIZE; ++i) { 82 | usedSlots[i] = false; 83 | assignedVertices[i] = false; 84 | } 85 | 86 | for (unsigned int currentVertex = 0; currentVertex < mMaxVertices; ++currentVertex) { 87 | for (unsigned int newVertex = 0; newVertex < vertexCount; ++newVertex) { 88 | if (mVertices[currentVertex] == newVertices[newVertex]) { 89 | usedSlots[currentVertex] = true; 90 | assignedVertices[newVertex] = true; 91 | 92 | slotIndex[newVertex] = currentVertex; 93 | } 94 | } 95 | } 96 | 97 | unsigned int nextTarget = 0; 98 | unsigned int nextSource = 0; 99 | 100 | while (nextTarget < mMaxVertices && nextSource < vertexCount) { 101 | if (usedSlots[nextTarget]) { 102 | ++nextTarget; 103 | } else if (assignedVertices[nextSource]) { 104 | ++nextSource; 105 | } else { 106 | slotIndex[nextSource] = nextTarget; 107 | ++nextTarget; 108 | ++nextSource; 109 | } 110 | } 111 | } 112 | 113 | const unsigned int RCPState::GetMaxVertices() { 114 | return mMaxVertices; 115 | } 116 | 117 | MaterialState& RCPState::GetMaterialState() { 118 | return mMaterialState; 119 | } -------------------------------------------------------------------------------- /src/RCPState.h: -------------------------------------------------------------------------------- 1 | #ifndef _RCP_STATE_H 2 | #define _RCP_STATE_H 3 | 4 | #include 5 | 6 | #include "BoneHierarchy.h" 7 | #include "DisplayList.h" 8 | #include "ErrorCode.h" 9 | #include "materials/MaterialState.h" 10 | 11 | struct VertexData { 12 | VertexData(); 13 | VertexData(std::string vertexBuffer, int vertexIndex, int matrixIndex); 14 | 15 | std::string mVertexBuffer; 16 | int mVertexIndex; 17 | int mMatrixIndex; 18 | 19 | const bool operator==(const VertexData& other); 20 | }; 21 | 22 | #define MAX_VERTEX_CACHE_SIZE 32 23 | 24 | class RCPState { 25 | public: 26 | RCPState(const MaterialState& materialState, unsigned int maxVertexCount, unsigned int maxMatrixDepth, bool canPopMultiple); 27 | ErrorCode TraverseToBone(Bone* bone, DisplayList& output); 28 | void AssignSlots(VertexData* newVertices, unsigned int* slotIndex, unsigned int vertexCount); 29 | const unsigned int GetMaxVertices(); 30 | MaterialState& GetMaterialState(); 31 | private: 32 | MaterialState mMaterialState; 33 | unsigned int mMaxVertices; 34 | unsigned int mMaxMatrixDepth; 35 | bool mCanPopMultiple; 36 | VertexData mVertices[MAX_VERTEX_CACHE_SIZE]; 37 | std::vector mBoneMatrixStack; 38 | }; 39 | 40 | #endif -------------------------------------------------------------------------------- /src/RenderChunk.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "RenderChunk.h" 3 | #include 4 | 5 | 6 | RenderChunk::RenderChunk(): mBonePair(nullptr, nullptr), 7 | mMesh(nullptr), 8 | mMeshRoot(nullptr), 9 | mAttachedDLIndex(-1), 10 | mMaterial(nullptr) { 11 | 12 | } 13 | 14 | RenderChunk::RenderChunk(std::pair bonePair, std::shared_ptr mesh, aiNode* meshRoot, Material* material): 15 | mBonePair(bonePair), 16 | mMesh(mesh), 17 | mMeshRoot(meshRoot), 18 | mAttachedDLIndex(-1), 19 | mMaterial(material) { 20 | 21 | } 22 | 23 | RenderChunk::RenderChunk(std::pair bonePair, int attachedDLIndex, Material* material): 24 | mBonePair(bonePair), 25 | mMesh(NULL), 26 | mMeshRoot(nullptr), 27 | mAttachedDLIndex(attachedDLIndex), 28 | mMaterial(material) { 29 | 30 | } 31 | 32 | VertexType RenderChunk::GetVertexType() { 33 | return Material::GetVertexType(mMaterial); 34 | } 35 | 36 | int RenderChunk::GetTextureWidth() { 37 | return Material::TextureWidth(mMaterial); 38 | } 39 | 40 | int RenderChunk::GetTextureHeight() { 41 | return Material::TextureHeight(mMaterial); 42 | } 43 | 44 | const std::vector& RenderChunk::GetFaces() { 45 | if (mBonePair.first == mBonePair.second) { 46 | auto result = mMesh->mFacesForBone.find(mBonePair.first); 47 | return result->second; 48 | } else { 49 | auto result = mMesh->mBoneSpanningFaces.find(mBonePair); 50 | return result->second; 51 | } 52 | } 53 | 54 | void extractChunks(const aiScene* scene, std::vector>& meshes, std::vector& result, std::map>& materials, const std::string& forceMaterial) { 55 | for (auto it = meshes.begin(); it != meshes.end(); ++it) { 56 | Material* materialPtr = NULL; 57 | 58 | auto material = materials.find(ExtendedMesh::GetMaterialName(scene->mMaterials[(*it)->mMesh->mMaterialIndex], forceMaterial)); 59 | 60 | if (material != materials.end()) { 61 | materialPtr = material->second.get(); 62 | } 63 | 64 | for (auto boneSegment = (*it)->mFacesForBone.begin(); boneSegment != (*it)->mFacesForBone.end(); ++boneSegment) { 65 | result.push_back(RenderChunk( 66 | std::make_pair(boneSegment->first, boneSegment->first), 67 | *it, 68 | nullptr, 69 | materialPtr 70 | )); 71 | } 72 | 73 | for (auto pairSegment = (*it)->mBoneSpanningFaces.begin(); pairSegment != (*it)->mBoneSpanningFaces.end(); ++pairSegment) { 74 | result.push_back(RenderChunk(pairSegment->first, *it, nullptr, materialPtr)); 75 | } 76 | } 77 | } 78 | 79 | void orderChunks(std::vector& result) { 80 | // TODO solve the traveling salesman algorithm 81 | std::sort(result.begin(), result.end(), 82 | [](const RenderChunk& a, const RenderChunk& b) -> bool { 83 | int aSecondScore = Bone::GetBoneIndex(a.mBonePair.second); 84 | int bSecondScore = Bone::GetBoneIndex(b.mBonePair.second); 85 | 86 | if (aSecondScore == bSecondScore) { 87 | return Bone::GetBoneIndex(a.mBonePair.first) < Bone::GetBoneIndex(b.mBonePair.first); 88 | } 89 | 90 | return aSecondScore < bSecondScore; 91 | }); 92 | } -------------------------------------------------------------------------------- /src/RenderChunk.h: -------------------------------------------------------------------------------- 1 | #ifndef _RENDER_CHUNK_H 2 | #define _RENDER_CHUNK_H 3 | 4 | #include 5 | 6 | #include "ExtendedMesh.h" 7 | #include "BoneHierarchy.h" 8 | #include "materials/Material.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | class RenderChunk { 15 | public: 16 | RenderChunk(); 17 | RenderChunk(std::pair bonePair, std::shared_ptr mesh, aiNode* meshRoot, Material* material); 18 | RenderChunk(std::pair bonePair, int attachedDLIndex, Material* material); 19 | // if bones are the same, chunk cooresponds to a single bone 20 | // the bones can be null 21 | std::pair mBonePair; 22 | std::shared_ptr mMesh; 23 | aiNode* mMeshRoot; 24 | int mAttachedDLIndex; 25 | Material* mMaterial; 26 | 27 | VertexType GetVertexType(); 28 | int GetTextureWidth(); 29 | int GetTextureHeight(); 30 | 31 | const std::vector& GetFaces(); 32 | private: 33 | }; 34 | 35 | void extractChunks(const aiScene* scene, std::vector>& meshes, std::vector& result, std::map>& mMaterials, const std::string& forceMaterial); 36 | 37 | void orderChunks(std::vector& result); 38 | 39 | #endif -------------------------------------------------------------------------------- /src/RenderChunkOrder.h: -------------------------------------------------------------------------------- 1 | #ifndef __RENDER_CHUNK_ORDER_H__ 2 | #define __RENDER_CHUNK_ORDER_H__ 3 | 4 | #include 5 | #include "RenderChunk.h" 6 | #include "CFileDefinition.h" 7 | #include "DisplayListSettings.h" 8 | 9 | struct EstimatedTime { 10 | EstimatedTime(); 11 | EstimatedTime(double total, double materialSwitching, double matrixSwitching); 12 | 13 | double GetTotal() const; 14 | 15 | double materialSwitching; 16 | double matrixSwitching; 17 | }; 18 | 19 | void orderRenderChunks(std::vector& chunks, const DisplayListSettings& settings); 20 | 21 | #endif -------------------------------------------------------------------------------- /src/SceneLoader.cpp: -------------------------------------------------------------------------------- 1 | #include "SceneLoader.h" 2 | 3 | #include 4 | #include 5 | #include "SceneModification.h" 6 | #include 7 | 8 | aiScene* loadScene(const std::string& filename, bool isLevel, int vertexCacheSize, unsigned int additionalPFlags) { 9 | Assimp::Importer importer; 10 | 11 | importer.SetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS, 1); 12 | 13 | unsigned int pFlags = aiProcess_JoinIdenticalVertices | 14 | aiProcess_Triangulate | 15 | aiProcess_LimitBoneWeights | 16 | aiProcess_OptimizeMeshes | 17 | additionalPFlags; 18 | 19 | if (!isLevel) { 20 | importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE); 21 | pFlags |= aiProcess_OptimizeGraph | aiProcess_SortByPType; 22 | } 23 | 24 | const aiScene* scene = importer.ReadFile(filename, pFlags); 25 | 26 | if (scene == nullptr) { 27 | std::cerr << "Error loading input file: " << importer.GetErrorString() << std::endl; 28 | return 0; 29 | } 30 | 31 | if (!isLevel) { 32 | std::cout << "Splitting scenes by bones" << std::endl; 33 | splitSceneByBones(const_cast(scene)); 34 | } 35 | 36 | importer.SetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE, vertexCacheSize); 37 | importer.ApplyPostProcessing(aiProcess_ImproveCacheLocality); 38 | 39 | return importer.GetOrphanedScene(); 40 | } -------------------------------------------------------------------------------- /src/SceneLoader.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCENE_LOADER_H 2 | #define _SCENE_LOADER_H 3 | 4 | #include 5 | #include 6 | 7 | aiScene* loadScene(const std::string& filename, bool isLevel, int vertexCacheSize, unsigned int additionalPFlags); 8 | 9 | #endif -------------------------------------------------------------------------------- /src/SceneModification.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCENE_MODIFICAITON_H 2 | #define _SCENE_MODIFICAITON_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // Caller is responsible for freeing memory 9 | aiMesh* subMesh(aiMesh* mesh, std::vector faces, std::string name); 10 | 11 | void splitSceneByBones(aiScene* targetScene); 12 | 13 | #endif -------------------------------------------------------------------------------- /src/SceneWriter.cpp: -------------------------------------------------------------------------------- 1 | #include "SceneWriter.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "./DisplayList.h" 11 | #include "./DisplayListGenerator.h" 12 | #include "./BoneHierarchy.h" 13 | #include "./ExtendedMesh.h" 14 | #include "./RenderChunk.h" 15 | #include "MeshWriter.h" 16 | #include "FileUtils.h" 17 | #include "./definition_generator/AnimationGenerator.h" 18 | 19 | void generateMeshFromScene(const aiScene* scene, CFileDefinition& fileDefinition, DisplayListSettings& settings) { 20 | BoneHierarchy bones; 21 | bool shouldExportAnimations; 22 | 23 | if (settings.mExportAnimation) { 24 | bones.SearchForBonesInScene(scene, settings.mFixedPointScale); 25 | shouldExportAnimations = bones.HasData(); 26 | } else { 27 | shouldExportAnimations = false; 28 | } 29 | 30 | std::vector> extendedMeshes; 31 | 32 | for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { 33 | extendedMeshes.push_back(std::shared_ptr(new ExtendedMesh(scene->mMeshes[i], bones))); 34 | } 35 | 36 | std::vector renderChunks; 37 | 38 | extractChunks(scene, extendedMeshes, renderChunks, settings.mMaterials, settings.mForceMaterialName); 39 | orderChunks(renderChunks); 40 | 41 | std::string renderDLName; 42 | 43 | if (settings.mExportGeometry) { 44 | renderDLName = generateMesh(scene, fileDefinition, renderChunks, settings, ""); 45 | } 46 | 47 | if (shouldExportAnimations) { 48 | generateAnimationForScene(scene, fileDefinition, settings); 49 | } 50 | } 51 | 52 | void generateMeshFromSceneToFile(const aiScene* scene, std::string filename, DisplayListSettings& settings) { 53 | CFileDefinition fileDefinition(settings.mPrefix, settings.mFixedPointScale, settings.mModelScale, settings.mRotateModel); 54 | 55 | generateMeshFromScene(scene, fileDefinition, settings); 56 | 57 | std::string filenameBase = replaceExtension(getBaseName(filename), ""); 58 | 59 | if (settings.mExportGeometry) { 60 | std::ofstream outputFile; 61 | outputFile.open(filename + "_geo.inc.h", std::ios_base::out | std::ios_base::trunc); 62 | fileDefinition.Generate(outputFile, "", filenameBase + ".h"); 63 | outputFile.close(); 64 | } 65 | 66 | std::ofstream outputHeader; 67 | outputHeader.open(filename + ".h", std::ios_base::out | std::ios_base::trunc); 68 | fileDefinition.GenerateHeader(outputHeader, filenameBase); 69 | outputHeader.close(); 70 | 71 | if (fileDefinition.HasDefinitions("_anim")) { 72 | std::ofstream animOutput; 73 | animOutput.open(filename + "_anim.inc.h", std::ios_base::out | std::ios_base::trunc); 74 | fileDefinition.Generate(animOutput, "_anim", filenameBase + ".h"); 75 | animOutput.close(); 76 | } 77 | } -------------------------------------------------------------------------------- /src/SceneWriter.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCENE_WRITER_H 2 | #define _SCENE_WRITER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "./materials/Material.h" 10 | #include "./DisplayListSettings.h" 11 | #include "CFileDefinition.h" 12 | 13 | void generateMeshFromScene(const aiScene* scene, CFileDefinition& fileDefinition, DisplayListSettings& settings); 14 | void generateMeshFromSceneToFile(const aiScene* scene, std::string filename, DisplayListSettings& settings); 15 | 16 | #endif -------------------------------------------------------------------------------- /src/StringUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRING_UTILS_H 2 | #define _STRING_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | std::string FindAndReplace(const std::string& source, const std::string& searchString, const std::string& replaceString, bool wholeWord = false); 8 | 9 | std::string Indent(const std::string& input, const std::string& whitespace); 10 | 11 | std::string Trim(const std::string& input); 12 | 13 | void makeCCompatible(std::string& target); 14 | 15 | bool StartsWith(const std::string& input, const std::string& prefix); 16 | 17 | bool EndsWith(const std::string& input, const std::string& suffix); 18 | 19 | void SplitString(const std::string& input, char delimeter, std::vector& output); 20 | 21 | #endif -------------------------------------------------------------------------------- /src/StringUtls.cpp: -------------------------------------------------------------------------------- 1 | #include "StringUtils.h" 2 | 3 | #include 4 | 5 | bool IsWordCharacter(char input) { 6 | return isalnum(input) || input == '_'; 7 | } 8 | 9 | std::string FindAndReplace(const std::string& source, const std::string& searchString, const std::string& replaceString, bool wholeWord) { 10 | std::ostringstream result; 11 | 12 | unsigned next = source.find(searchString); 13 | unsigned last = 0; 14 | 15 | while (next < source.length()) { 16 | result << source.substr(last, next - last); 17 | 18 | bool shouldReplace = true; 19 | unsigned afterNext = next + searchString.length(); 20 | 21 | if (wholeWord) { 22 | if (next > 0 && IsWordCharacter(source[next - 1])) { 23 | shouldReplace = false; 24 | } 25 | 26 | if (afterNext < source.length() && IsWordCharacter(source[afterNext])) { 27 | shouldReplace = false; 28 | } 29 | } 30 | 31 | if (shouldReplace) { 32 | result << replaceString; 33 | } else { 34 | result << searchString; 35 | } 36 | 37 | last = afterNext; 38 | next = source.find(searchString, last); 39 | } 40 | 41 | result << source.substr(last, source.length() - last); 42 | 43 | return result.str(); 44 | } 45 | 46 | std::string Indent(const std::string& input, const std::string& whitespace) { 47 | std::ostringstream result; 48 | 49 | unsigned lineStart = 0; 50 | bool lookingForLineStart = true; 51 | 52 | for (unsigned curr = 0; curr <= input.length(); ++curr) { 53 | char currentChar = curr < input.length() ? input[curr] : '\0'; 54 | 55 | if (lookingForLineStart) { 56 | if (!isspace(currentChar)) { 57 | lineStart = curr; 58 | lookingForLineStart = false; 59 | result << whitespace; 60 | } 61 | } else { 62 | if (currentChar == '\n' || currentChar == '\r' || currentChar == '\0') { 63 | result << input.substr(lineStart, curr - lineStart) << std::endl; 64 | lookingForLineStart = true; 65 | } 66 | } 67 | } 68 | 69 | return result.str(); 70 | } 71 | 72 | std::string Trim(const std::string& input) { 73 | int start = 0; 74 | 75 | while (start < (int)input.length() && isspace(input[start])) { 76 | ++start; 77 | } 78 | 79 | int end = input.length() - 1; 80 | 81 | while (end >= 0 && isspace(input[end])) { 82 | --end; 83 | } 84 | 85 | ++end; 86 | 87 | if (start >= end) { 88 | return ""; 89 | } 90 | 91 | return input.substr(start, end - start); 92 | } 93 | 94 | void makeCCompatible(std::string& target) { 95 | for (unsigned int i = 0; i < target.length(); ++i) { 96 | char curr = target[i]; 97 | 98 | if (!(curr >= 'a' && curr <= 'z') && !(curr >= 'A' && curr <= 'Z') && !(curr >= '0' && curr <= '9') && curr != '_') { 99 | target[i] = '_'; 100 | } 101 | } 102 | 103 | if (target.length() > 0 && target[0] >= '0' && target[0] <= '9') { 104 | target = '_' + target; 105 | } 106 | } 107 | 108 | bool StartsWith(const std::string& input, const std::string& prefix) { 109 | if (prefix.length() > input.length()) { 110 | return false; 111 | } 112 | 113 | for (unsigned i = 0; i < prefix.length(); ++i) { 114 | if (input[i] != prefix[i]) { 115 | return false; 116 | } 117 | } 118 | 119 | return true; 120 | } 121 | 122 | bool EndsWith(const std::string& input, const std::string& suffix) { 123 | if (suffix.length() > input.length()) { 124 | return false; 125 | } 126 | 127 | unsigned indexOffset = input.size() - suffix.size(); 128 | 129 | for (unsigned i = 0; i < suffix.length(); ++i) { 130 | if (input[i + indexOffset] != suffix[i]) { 131 | return false; 132 | } 133 | } 134 | 135 | return true; 136 | } 137 | 138 | void SplitString(const std::string& input, char delimeter, std::vector& output) { 139 | std::size_t lastStart = 0; 140 | std::size_t curr = 0; 141 | 142 | while (curr < input.size()) { 143 | if (input[curr] == delimeter) { 144 | output.push_back(input.substr(lastStart, curr - lastStart)); 145 | lastStart = curr + 1; 146 | } 147 | 148 | ++curr; 149 | } 150 | 151 | output.push_back(input.substr(lastStart, curr - lastStart)); 152 | } -------------------------------------------------------------------------------- /src/definition_generator/AnimationGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef __ANIMATION_GENERATOR_H__ 2 | #define __ANIMATION_GENERATOR_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../CFileDefinition.h" 9 | #include "../DisplayListSettings.h" 10 | 11 | struct AnimationResults { 12 | std::string initialPoseReference; 13 | std::string boneParentReference; 14 | std::string boneCountMacro; 15 | std::string numberOfAttachmentMacros; 16 | }; 17 | 18 | std::shared_ptr findNodesForWithAnimation(const aiScene* scene, const std::vector& usedNodes, float modelScale); 19 | 20 | AnimationResults generateAnimationForScene(const aiScene* scene, CFileDefinition &fileDefinition, DisplayListSettings& settings); 21 | 22 | #endif -------------------------------------------------------------------------------- /src/definition_generator/CollisionGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef __COLLISION_GENERATOR_H__ 2 | #define __COLLISION_GENERATOR_H__ 3 | 4 | #include "DefinitionGenerator.h" 5 | #include "../DisplayListSettings.h" 6 | #include "CollisionQuad.h" 7 | 8 | #define COLLISION_GRID_CELL_SIZE 4 9 | 10 | struct CollisionGrid { 11 | CollisionGrid(const aiAABB& boundaries); 12 | 13 | short x; 14 | short z; 15 | short spanX; 16 | short spanZ; 17 | 18 | std::vector>> cells; 19 | 20 | void AddToCells(const aiAABB& box, short value); 21 | }; 22 | 23 | struct CollisionGeneratorOutput { 24 | std::string quadsName; 25 | std::vector quads; 26 | std::vector roomGrids; 27 | }; 28 | 29 | std::shared_ptr generateCollision(const aiScene* scene, CFileDefinition& fileDefinition, const DisplayListSettings& settings, NodeGroups& nodeGroups); 30 | 31 | void generateMeshCollider(CFileDefinition& fileDefinition, CollisionGeneratorOutput& collisionOutput); 32 | 33 | #endif -------------------------------------------------------------------------------- /src/definition_generator/CollisionQuad.cpp: -------------------------------------------------------------------------------- 1 | #include "CollisionQuad.h" 2 | 3 | #include "../MathUtl.h" 4 | 5 | #define SAME_TOLERANCE 0.00001f 6 | 7 | bool bottomRightMost(const aiVector3D& a, const aiVector3D& b) { 8 | if (fabs(a.x - b.x) > SAME_TOLERANCE) { 9 | return a.x < b.x; 10 | } 11 | 12 | if (fabs(a.y - b.y) > SAME_TOLERANCE) { 13 | return a.y < b.y; 14 | } 15 | 16 | return a.z < b.z; 17 | } 18 | 19 | const aiVector3D* findMostOppositeEdge(const aiVector3D& fromEdge, const std::vector& edges) { 20 | return std::min_element(edges.begin(), edges.end(), [=](const aiVector3D& a, const aiVector3D& b) { 21 | return (a * fromEdge) < (b * fromEdge); 22 | }).base(); 23 | } 24 | 25 | CollisionQuad::CollisionQuad(aiMesh* mesh, const aiMatrix4x4& transform): thickness(0.0f) { 26 | if (mesh->mVertices) { 27 | std::vector transformedPoints; 28 | 29 | for (unsigned index = 0; index < mesh->mNumVertices; ++index) { 30 | transformedPoints.push_back(transform * mesh->mVertices[index]); 31 | } 32 | 33 | auto cornerPointer = std::min_element(transformedPoints.begin(), transformedPoints.end(), bottomRightMost); 34 | unsigned cornerIndex = cornerPointer - transformedPoints.begin(); 35 | 36 | corner = *cornerPointer; 37 | 38 | std::set adjacentIndices; 39 | findAdjacentVertices(mesh, cornerIndex, adjacentIndices); 40 | 41 | std::vector edgesFromCorner; 42 | 43 | for (auto index : adjacentIndices) { 44 | edgesFromCorner.push_back(transformedPoints[index] - corner); 45 | } 46 | 47 | auto edgeAPoint = findMostOppositeEdge(edgesFromCorner[0], edgesFromCorner); 48 | 49 | edgeA = *edgeAPoint; 50 | edgeALength = edgeA.Length(); 51 | edgeA.Normalize(); 52 | 53 | auto edgeBPoint = findMostOppositeEdge(edgeA, edgesFromCorner); 54 | 55 | edgeB = *edgeBPoint; 56 | edgeBLength = edgeB.Length(); 57 | edgeB.Normalize(); 58 | 59 | aiMatrix3x3 rotation(transform); 60 | 61 | for (unsigned i = 0; i < mesh->mNumVertices; ++i) { 62 | normal += rotation * mesh->mNormals[i]; 63 | } 64 | 65 | normal.Normalize(); 66 | 67 | if ((edgeA ^ edgeB) * normal < 0.0f) { 68 | aiVector3D tmpEdge = edgeA; 69 | float tmpLength = edgeALength; 70 | 71 | edgeA = edgeB; 72 | edgeALength = edgeBLength; 73 | 74 | edgeB = tmpEdge; 75 | edgeBLength = tmpLength; 76 | } 77 | 78 | corner.x = 0.001f * round(1000.0f * corner.x); 79 | corner.y = 0.001f * round(1000.0f * corner.y); 80 | corner.z = 0.001f * round(1000.0f * corner.z); 81 | 82 | edgeA.x = 0.001f * round(1000.0f * edgeA.x); 83 | edgeA.y = 0.001f * round(1000.0f * edgeA.y); 84 | edgeA.z = 0.001f * round(1000.0f * edgeA.z); 85 | 86 | edgeALength = 0.001f * round(1000.0f * edgeALength); 87 | 88 | edgeB.x = 0.001f * round(1000.0f * edgeB.x); 89 | edgeB.y = 0.001f * round(1000.0f * edgeB.y); 90 | edgeB.z = 0.001f * round(1000.0f * edgeB.z); 91 | 92 | edgeBLength = 0.001f * round(1000.0f * edgeBLength); 93 | 94 | normal.x = 0.001f * round(1000.0f * normal.x); 95 | normal.y = 0.001f * round(1000.0f * normal.y); 96 | normal.z = 0.001f * round(1000.0f * normal.z); 97 | } else { 98 | corner = aiVector3D(); 99 | edgeA = aiVector3D(); 100 | edgeALength = 0.0f; 101 | edgeB = aiVector3D(); 102 | edgeBLength = 0.0f; 103 | normal = aiVector3D(); 104 | } 105 | } 106 | 107 | std::unique_ptr CollisionQuad::Generate() const { 108 | std::unique_ptr result(new StructureDataChunk()); 109 | 110 | result->Add(std::unique_ptr(new StructureDataChunk(corner))); 111 | result->Add(std::unique_ptr(new StructureDataChunk(edgeA))); 112 | result->AddPrimitive(edgeALength); 113 | result->Add(std::unique_ptr(new StructureDataChunk(edgeB))); 114 | result->AddPrimitive(edgeBLength); 115 | 116 | std::unique_ptr plane(new StructureDataChunk()); 117 | plane->Add(std::unique_ptr(new StructureDataChunk(normal))); 118 | plane->AddPrimitive(-(corner * normal)); 119 | result->Add(std::move(plane)); 120 | 121 | result->AddPrimitive(thickness); 122 | 123 | return result; 124 | } 125 | 126 | #define INSIDE_NORMAL_TOLERANCE 0.1f 127 | 128 | bool CollisionQuad::IsCoplanar(ExtendedMesh& mesh, float relativeScale) const { 129 | for (unsigned i = 0; i < mesh.mMesh->mNumVertices; ++i) { 130 | aiVector3D offset = mesh.mMesh->mVertices[i] * relativeScale - corner; 131 | 132 | float z = offset * normal; 133 | 134 | if (fabs(z) >= INSIDE_NORMAL_TOLERANCE) { 135 | return false; 136 | } 137 | } 138 | 139 | return true; 140 | } 141 | 142 | bool CollisionQuad::IsCoplanar(const aiVector3D& input) const { 143 | aiVector3D offset = input - corner; 144 | 145 | float z = offset * normal; 146 | 147 | if (fabs(z) >= INSIDE_NORMAL_TOLERANCE) { 148 | return false; 149 | } 150 | 151 | float x = offset * edgeA; 152 | 153 | if (x < -INSIDE_NORMAL_TOLERANCE || x > edgeALength + INSIDE_NORMAL_TOLERANCE) { 154 | return false; 155 | } 156 | 157 | float y = offset * edgeB; 158 | 159 | if (y < -INSIDE_NORMAL_TOLERANCE || y > edgeBLength + INSIDE_NORMAL_TOLERANCE) { 160 | return false; 161 | } 162 | 163 | return true; 164 | } 165 | 166 | aiAABB CollisionQuad::BoundingBox() const { 167 | aiAABB result; 168 | 169 | result.mMin = corner; 170 | result.mMax = corner; 171 | 172 | for (int x = 0; x < 2; ++x) { 173 | for (int y = 0; y < 2; ++y) { 174 | for (int z = 0; z < 2; ++z) { 175 | aiVector3D point = corner; 176 | 177 | if (x) { 178 | point = point + edgeA * edgeALength; 179 | } 180 | 181 | if (y) { 182 | point = point + edgeB * edgeBLength; 183 | } 184 | 185 | if (z) { 186 | point = point - normal * thickness; 187 | } 188 | 189 | result.mMin = min(result.mMin, point); 190 | result.mMax = max(result.mMax, point); 191 | } 192 | } 193 | } 194 | 195 | return result; 196 | } -------------------------------------------------------------------------------- /src/definition_generator/CollisionQuad.h: -------------------------------------------------------------------------------- 1 | #ifndef __COLLISION_QUAD_H__ 2 | #define __COLLISION_QUAD_H__ 3 | 4 | #include 5 | #include "../ExtendedMesh.h" 6 | 7 | struct CollisionQuad { 8 | CollisionQuad(aiMesh* mesh, const aiMatrix4x4& transform); 9 | 10 | aiVector3D corner; 11 | aiVector3D edgeA; 12 | float edgeALength; 13 | aiVector3D edgeB; 14 | float edgeBLength; 15 | aiVector3D normal; 16 | float thickness; 17 | 18 | std::unique_ptr Generate() const; 19 | 20 | bool IsCoplanar(ExtendedMesh& mesh, float relativeScale) const; 21 | bool IsCoplanar(const aiVector3D& input) const; 22 | 23 | aiAABB BoundingBox() const; 24 | }; 25 | 26 | #endif -------------------------------------------------------------------------------- /src/definition_generator/DefinitionGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "DefinitionGenerator.h" 2 | 3 | #include 4 | 5 | #include "../StringUtils.h" 6 | 7 | DefinitionGenerator::DefinitionGenerator() {} 8 | DefinitionGenerator::~DefinitionGenerator() {} 9 | 10 | void DefinitionGenerator::TraverseScene(const aiScene* scene) { 11 | if (!scene) { 12 | return; 13 | } 14 | 15 | BeforeTraversal(scene); 16 | 17 | forEachNode(scene->mRootNode, [&](aiNode* node) -> void { 18 | if (ShouldIncludeNode(node)) { 19 | mIncludedNodes.push_back(node); 20 | } 21 | }); 22 | } 23 | 24 | void DefinitionGenerator::BeforeTraversal(const aiScene* scene) {} 25 | 26 | NodeGroups::NodeGroups(const aiScene* scene) { 27 | RecurseAddNode(scene->mRootNode, false); 28 | } 29 | 30 | void NodeGroups::RecurseAddNode(aiNode* node, bool isSpecialNode) { 31 | if (!node) { 32 | return; 33 | } 34 | 35 | if (node->mName.data[0] == '@') { 36 | AddNode(node); 37 | isSpecialNode = true; 38 | } else if (!isSpecialNode) { 39 | AddNode(node); 40 | } 41 | 42 | 43 | for (unsigned int i = 0; i < node->mNumChildren; ++i) { 44 | RecurseAddNode(node->mChildren[i], isSpecialNode); 45 | } 46 | } 47 | 48 | std::vector& NodeGroups::NodesForType(const std::string& typeName) { 49 | mTypesReferenced.insert(typeName); 50 | return mNodesByType[typeName]; 51 | } 52 | 53 | void NodeGroups::PrintUnusedTypes() { 54 | for (auto& byType : mNodesByType) { 55 | if (mTypesReferenced.find(byType.first) == mTypesReferenced.end()) { 56 | std::cout << "The node type " << byType.first << " was never referenced." << std::endl; 57 | } 58 | } 59 | } 60 | 61 | void NodeGroups::AddNode(aiNode* node) { 62 | NodeWithArguments result; 63 | SplitString(node->mName.C_Str(), ' ', result.arguments); 64 | std::string typeName; 65 | result.node = node; 66 | 67 | if (result.arguments[0][0] == '@') { 68 | typeName = result.arguments[0]; 69 | result.arguments.erase(result.arguments.begin()); 70 | } 71 | 72 | mNodesByType[typeName].push_back(result); 73 | } 74 | 75 | std::string NodeWithArguments::ReadNamedArgument(const std::string& name) { 76 | auto parameterValue = std::find(arguments.begin(), arguments.end(), name); 77 | 78 | if (parameterValue == arguments.end() || parameterValue + 1 == arguments.end()) { 79 | return ""; 80 | } 81 | 82 | return *(parameterValue + 1); 83 | 84 | } 85 | 86 | void forEachNode(aiNode* node, const std::function& callback) { 87 | if (!node) { 88 | return; 89 | } 90 | 91 | callback(node); 92 | 93 | for (unsigned int i = 0; i < node->mNumChildren; ++i) { 94 | forEachNode(node->mChildren[i], callback); 95 | } 96 | } -------------------------------------------------------------------------------- /src/definition_generator/DefinitionGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEFINITION_GENERATOR_H__ 2 | #define __DEFINITION_GENERATOR_H__ 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "../CFileDefinition.h" 13 | 14 | class DefinitionGenerator { 15 | public: 16 | DefinitionGenerator(); 17 | virtual ~DefinitionGenerator(); 18 | 19 | void TraverseScene(const aiScene* scene); 20 | 21 | virtual void BeforeTraversal(const aiScene* scene); 22 | 23 | virtual bool ShouldIncludeNode(aiNode* node) = 0; 24 | virtual void GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition) = 0; 25 | protected: 26 | std::vector mIncludedNodes; 27 | }; 28 | 29 | struct NodeWithArguments { 30 | aiNode* node; 31 | std::vector arguments; 32 | 33 | std::string ReadNamedArgument(const std::string& name); 34 | }; 35 | 36 | class NodeGroups { 37 | public: 38 | NodeGroups(const aiScene* scene); 39 | 40 | std::vector& NodesForType(const std::string& typeName); 41 | void PrintUnusedTypes(); 42 | private: 43 | void AddNode(aiNode* node); 44 | 45 | void RecurseAddNode(aiNode* node, bool isSpecialNode); 46 | 47 | std::map> mNodesByType; 48 | std::set mTypesReferenced; 49 | }; 50 | 51 | void forEachNode(aiNode* node, const std::function& callback); 52 | 53 | #endif -------------------------------------------------------------------------------- /src/definition_generator/MaterialGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "MaterialGenerator.h" 2 | 3 | #include "../StringUtils.h" 4 | #include "../materials/RenderMode.h" 5 | 6 | MaterialGenerator::MaterialGenerator(const DisplayListSettings& settings): mSettings(settings) {} 7 | 8 | 9 | bool MaterialGenerator::ShouldIncludeNode(aiNode* node) { 10 | return false; 11 | } 12 | 13 | #define OPAQUE_ORDER 0 14 | #define DECAL_ORDER 1 15 | #define TRANSPARENT_ORDER 2 16 | 17 | int sortOrderForMaterial(const Material& material) { 18 | // assume opaque 19 | if (!material.mState.hasRenderMode) { 20 | return OPAQUE_ORDER; 21 | } 22 | 23 | if (material.mState.cycle1RenderMode.GetZMode() == ZMODE_DEC || 24 | material.mState.cycle2RenderMode.GetZMode() == ZMODE_DEC) { 25 | return DECAL_ORDER; 26 | } 27 | 28 | if ((material.mState.cycle1RenderMode.data | material.mState.cycle2RenderMode.data) & FORCE_BL) { 29 | return TRANSPARENT_ORDER; 30 | } 31 | 32 | return OPAQUE_ORDER; 33 | } 34 | 35 | void MaterialGenerator::GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition) { 36 | std::set> textures; 37 | std::set> palletes; 38 | 39 | for (auto& entry : mSettings.mMaterials) { 40 | if (entry.second->mExcludeFromOutut) { 41 | continue; 42 | } 43 | 44 | for (int i = 0; i < 8; ++i) { 45 | std::shared_ptr texture = entry.second->mState.tiles[i].texture; 46 | if (texture) { 47 | textures.insert(texture); 48 | 49 | if (texture->GetPallete()) { 50 | palletes.insert(texture->GetPallete()); 51 | } 52 | } 53 | } 54 | } 55 | 56 | for (auto& texture : textures) { 57 | fileDefinition.AddDefinition(std::move(texture->GenerateDefinition(fileDefinition.GetUniqueName(texture->Name()), "_mat"))); 58 | } 59 | 60 | for (auto& pallete : palletes) { 61 | fileDefinition.AddDefinition(std::move(pallete->GenerateDefinition(fileDefinition.GetUniqueName(pallete->Name()), "_mat"))); 62 | } 63 | 64 | int index = 0; 65 | 66 | std::unique_ptr materialList(new StructureDataChunk()); 67 | std::unique_ptr revertList(new StructureDataChunk()); 68 | 69 | std::vector> materialsAsVector; 70 | 71 | for (auto& entry : mSettings.mMaterials) { 72 | if (entry.second->mExcludeFromOutut) { 73 | continue; 74 | } 75 | 76 | materialsAsVector.push_back(entry.second); 77 | } 78 | 79 | std::sort(materialsAsVector.begin(), materialsAsVector.end(), [&](const std::shared_ptr& a, const std::shared_ptr& b) -> bool { 80 | int aOrder = sortOrderForMaterial(*a); 81 | int bOrder = sortOrderForMaterial(*b); 82 | 83 | if (aOrder != bOrder) { 84 | return aOrder < bOrder; 85 | } 86 | 87 | return a->mSortOrder < b->mSortOrder; 88 | }); 89 | 90 | for (auto& entry : materialsAsVector) { 91 | std::string name = fileDefinition.GetUniqueName(entry->mName); 92 | 93 | DisplayList dl(name); 94 | if (entry->mName == mSettings.mDefaultMaterialName) { 95 | entry->Write(fileDefinition, MaterialState(), dl.GetDataChunk(), mSettings.mTargetCIBuffer); 96 | } else { 97 | entry->Write(fileDefinition, mSettings.mDefaultMaterialState, dl.GetDataChunk(), mSettings.mTargetCIBuffer); 98 | } 99 | std::unique_ptr material = dl.Generate("_mat"); 100 | materialList->AddPrimitive(material->GetName()); 101 | fileDefinition.AddDefinition(std::move(material)); 102 | 103 | std::string revertName = fileDefinition.GetUniqueName(entry->mName + "_revert"); 104 | DisplayList revertDL(revertName); 105 | generateMaterial(fileDefinition, entry->mState, mSettings.mDefaultMaterialState, revertDL.GetDataChunk(), mSettings.mTargetCIBuffer); 106 | std::unique_ptr materialRevert = revertDL.Generate("_mat"); 107 | revertList->AddPrimitive(materialRevert->GetName()); 108 | fileDefinition.AddDefinition(std::move(materialRevert)); 109 | 110 | fileDefinition.AddMacro(MaterialIndexMacroName(entry->mName), std::to_string(index)); 111 | 112 | ++index; 113 | } 114 | 115 | unsigned transparentIndex = 0; 116 | 117 | while (transparentIndex < materialsAsVector.size() && sortOrderForMaterial(*materialsAsVector[transparentIndex]) != TRANSPARENT_ORDER) { 118 | ++transparentIndex; 119 | } 120 | 121 | fileDefinition.AddMacro(fileDefinition.GetMacroName("MATERIAL_COUNT"), std::to_string(index)); 122 | fileDefinition.AddMacro(fileDefinition.GetMacroName("TRANSPARENT_START"), std::to_string(transparentIndex + 1)); 123 | 124 | fileDefinition.AddDefinition(std::unique_ptr(new DataFileDefinition("Gfx*", fileDefinition.GetUniqueName("material_list"), true, "_mat", std::move(materialList)))); 125 | fileDefinition.AddDefinition(std::unique_ptr(new DataFileDefinition("Gfx*", fileDefinition.GetUniqueName("material_revert_list"), true, "_mat", std::move(revertList)))); 126 | } 127 | 128 | std::string MaterialGenerator::MaterialIndexMacroName(const std::string& materialName) { 129 | std::string result = materialName; 130 | std::transform(materialName.begin(), materialName.end(), result.begin(), ::toupper); 131 | makeCCompatible(result); 132 | return result + "_INDEX"; 133 | } -------------------------------------------------------------------------------- /src/definition_generator/MaterialGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATERIAL_GENERATOR_H__ 2 | #define __MATERIAL_GENERATOR_H__ 3 | 4 | #include "DefinitionGenerator.h" 5 | #include "../DisplayListSettings.h" 6 | 7 | class MaterialGenerator : public DefinitionGenerator { 8 | public: 9 | MaterialGenerator(const DisplayListSettings& settings); 10 | 11 | virtual bool ShouldIncludeNode(aiNode* node); 12 | virtual void GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition); 13 | 14 | static std::string MaterialIndexMacroName(const std::string& materialName); 15 | private: 16 | DisplayListSettings mSettings; 17 | }; 18 | 19 | #endif -------------------------------------------------------------------------------- /src/definition_generator/MeshDefinitionGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef __MESH_DEFINTION_GENERATOR_H__ 2 | #define __MESH_DEFINTION_GENERATOR_H__ 3 | 4 | #include "DefinitionGenerator.h" 5 | #include "../DisplayListSettings.h" 6 | #include "../RenderChunk.h" 7 | 8 | struct ArmatureDefinitionResults { 9 | std::string modelName; 10 | std::string initialPoseReference; 11 | std::string boneParentReference; 12 | std::string boneCountMacro; 13 | std::string numberOfAttachmentMacros; 14 | }; 15 | 16 | struct MeshDefinitionResults { 17 | public: 18 | std::string modelName; 19 | std::string materialMacro; 20 | }; 21 | 22 | class MeshDefinitionGenerator : public DefinitionGenerator { 23 | public: 24 | MeshDefinitionGenerator(const DisplayListSettings& settings); 25 | 26 | virtual bool ShouldIncludeNode(aiNode* node); 27 | virtual void GenerateDefinitions(const aiScene* scene, CFileDefinition& fileDefinition); 28 | 29 | void PopulateBones(const aiScene* scene, CFileDefinition& fileDefinition); 30 | 31 | MeshDefinitionResults GenerateDefinitionsWithResults(const aiScene* scene, CFileDefinition& fileDefinition); 32 | 33 | static void AppendRenderChunks(const aiScene* scene, aiNode* node, CFileDefinition& fileDefinition, const DisplayListSettings& settings, std::vector& renderChunks); 34 | private: 35 | DisplayListSettings mSettings; 36 | }; 37 | 38 | #endif -------------------------------------------------------------------------------- /src/definitions/DataChunk.h: -------------------------------------------------------------------------------- 1 | #ifndef __DATA_CHUNK_H__ 2 | #define __DATA_CHUNK_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | class DataChunk { 14 | public: 15 | DataChunk(); 16 | virtual ~DataChunk(); 17 | 18 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix) = 0; 19 | 20 | int GetEstimatedLength(); 21 | protected: 22 | virtual int CalculateEstimatedLength() = 0; 23 | private: 24 | int mCachedLength; 25 | }; 26 | 27 | class DataChunkNop : public DataChunk { 28 | public: 29 | DataChunkNop(); 30 | 31 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); 32 | protected: 33 | virtual int CalculateEstimatedLength(); 34 | }; 35 | 36 | template 37 | class PrimitiveDataChunk : public DataChunk { 38 | public: 39 | PrimitiveDataChunk(const T& value): DataChunk(), mValue(value) {} 40 | 41 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix) { 42 | output << mValue; 43 | return true; 44 | } 45 | protected: 46 | virtual int CalculateEstimatedLength() { 47 | std::ostringstream tmp; 48 | Output(tmp, 0, 0); 49 | return tmp.tellp(); 50 | } 51 | private: 52 | T mValue; 53 | }; 54 | 55 | class StringDataChunk : public PrimitiveDataChunk { 56 | public: 57 | StringDataChunk(const std::string& value); 58 | private: 59 | static char EscapeCharacter(char input); 60 | static std::string EscapeAndWrapString(const std::string& string); 61 | }; 62 | 63 | class StructureEntryDataChunk : public DataChunk { 64 | public: 65 | StructureEntryDataChunk(const std::string& name, std::unique_ptr entry); 66 | 67 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); 68 | protected: 69 | virtual int CalculateEstimatedLength(); 70 | private: 71 | std::string mName; 72 | std::unique_ptr mEntry; 73 | }; 74 | 75 | class StructureDataChunk : public DataChunk { 76 | public: 77 | StructureDataChunk(); 78 | StructureDataChunk(const aiVector3D& vector); 79 | StructureDataChunk(const aiQuaternion& quat); 80 | StructureDataChunk(const aiAABB& bb); 81 | 82 | void Add(std::unique_ptr entry); 83 | 84 | template 85 | void AddPrimitive(const T& primitive) { 86 | Add(std::unique_ptr(new PrimitiveDataChunk(primitive))); 87 | } 88 | 89 | void Add(const std::string& name, std::unique_ptr entry); 90 | 91 | template 92 | void AddPrimitive(const std::string& name, const T& primitive) { 93 | Add(std::unique_ptr(new StructureEntryDataChunk( 94 | name, 95 | std::unique_ptr(new PrimitiveDataChunk(primitive)) 96 | ))); 97 | } 98 | 99 | void AddNewlineHint(); 100 | 101 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); 102 | 103 | static void OutputIndent(std::ostream& output, int indentLevel); 104 | static void OutputChildren(std::vector>& children, std::ostream& output, int indentLevel, int totalLength, bool trailingComma, bool includeNewlines); 105 | protected: 106 | virtual int CalculateEstimatedLength(); 107 | private: 108 | std::vector> mChildren; 109 | bool mHasNewlineHints; 110 | }; 111 | 112 | class MacroDataChunk : public DataChunk { 113 | public: 114 | MacroDataChunk(const std::string& macroName); 115 | MacroDataChunk(const std::string& macroName, bool singleLine); 116 | 117 | void Add(std::unique_ptr entry); 118 | 119 | template 120 | void AddPrimitive(const T& primitive) { 121 | Add(std::unique_ptr(new PrimitiveDataChunk(primitive))); 122 | } 123 | 124 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); 125 | protected: 126 | virtual int CalculateEstimatedLength(); 127 | 128 | private: 129 | std::string mMacroName; 130 | std::vector> mParameters; 131 | bool mSingleLine; 132 | }; 133 | 134 | class CommentDataChunk : public DataChunk { 135 | public: 136 | CommentDataChunk(const std::string& comment); 137 | 138 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); 139 | protected: 140 | virtual int CalculateEstimatedLength(); 141 | private: 142 | std::string mComment; 143 | }; 144 | 145 | class NewlineHintChunk : public DataChunk { 146 | public: 147 | NewlineHintChunk(); 148 | virtual bool Output(std::ostream& output, int indentLevel, int linePrefix); 149 | protected: 150 | virtual int CalculateEstimatedLength(); 151 | }; 152 | 153 | #endif -------------------------------------------------------------------------------- /src/definitions/FileDefinition.cpp: -------------------------------------------------------------------------------- 1 | #include "FileDefinition.h" 2 | #include "../StringUtils.h" 3 | 4 | FileDefinition::FileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location) : 5 | mType(type), 6 | mName(name), 7 | mIsArray(isArray), 8 | mLocation(location), 9 | mForResource(NULL) { 10 | 11 | } 12 | 13 | FileDefinition::FileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, const void* forResource) : 14 | mType(type), 15 | mName(name), 16 | mIsArray(isArray), 17 | mLocation(location), 18 | mForResource(forResource) { 19 | 20 | } 21 | 22 | FileDefinition::~FileDefinition() { 23 | 24 | } 25 | 26 | void FileDefinition::GenerateDeclaration(std::ostream& output) { 27 | output << "extern " << mType << " " << mName; 28 | 29 | if (mIsArray) { 30 | output << "[]"; 31 | } 32 | } 33 | 34 | std::string FileDefinition::GetLocation() { 35 | return mLocation; 36 | } 37 | 38 | void FileDefinition::AddTypeHeader(const std::string& typeHeader) { 39 | mTypeHeaders.insert(typeHeader); 40 | } 41 | 42 | const std::set& FileDefinition::GetTypeHeaders() { 43 | return mTypeHeaders; 44 | } 45 | 46 | const void* FileDefinition::ForResource() const { 47 | return mForResource; 48 | } 49 | 50 | const std::string& FileDefinition::GetName() const { 51 | return mName; 52 | } 53 | 54 | DataFileDefinition::DataFileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, std::unique_ptr data): 55 | FileDefinition(type, name, isArray, location), 56 | mData(std::move(data)) { 57 | 58 | } 59 | 60 | DataFileDefinition::DataFileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, std::unique_ptr data, const void* forResource): 61 | FileDefinition(type, name, isArray, location, forResource), 62 | mData(std::move(data)) { 63 | 64 | } 65 | 66 | void DataFileDefinition::Generate(std::ostream& output) { 67 | int start = (int)output.tellp(); 68 | 69 | output << mType << " " << mName; 70 | 71 | if (mIsArray) { 72 | output << "[]"; 73 | } 74 | 75 | output << " = "; 76 | 77 | mData->Output(output, 0, (int)output.tellp() - start); 78 | } 79 | 80 | RawFileDefinition::RawFileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, const std::string& content) : FileDefinition(type, name, isArray, location), mContent(content) {} 81 | 82 | void RawFileDefinition::Generate(std::ostream& output) { 83 | output << mType << " " << mName; 84 | 85 | if (mIsArray) { 86 | output << "[] = {" << std::endl; 87 | output << Indent(mContent, " "); 88 | output << "};"; 89 | } else { 90 | output << " = " << mContent << ";"; 91 | } 92 | } -------------------------------------------------------------------------------- /src/definitions/FileDefinition.h: -------------------------------------------------------------------------------- 1 | #ifndef __FILE_DEFINITION_H__ 2 | #define __FILE_DEFINITION_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "DataChunk.h" 8 | 9 | class FileDefinition { 10 | public: 11 | FileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location); 12 | FileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, const void* forResource); 13 | 14 | virtual ~FileDefinition(); 15 | 16 | virtual void Generate(std::ostream& output) = 0; 17 | void GenerateDeclaration(std::ostream& output); 18 | 19 | std::string GetLocation(); 20 | 21 | void AddTypeHeader(const std::string& typeHeader); 22 | 23 | const std::set& GetTypeHeaders(); 24 | 25 | const void* ForResource() const; 26 | const std::string& GetName() const; 27 | protected: 28 | std::string mType; 29 | std::string mName; 30 | bool mIsArray; 31 | std::string mLocation; 32 | const void* mForResource; 33 | 34 | std::set mTypeHeaders; 35 | }; 36 | 37 | class DataFileDefinition : public FileDefinition { 38 | public: 39 | DataFileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, std::unique_ptr data); 40 | DataFileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, std::unique_ptr data, const void* forResource); 41 | 42 | virtual void Generate(std::ostream& output); 43 | private: 44 | std::unique_ptr mData; 45 | }; 46 | 47 | class RawFileDefinition : public FileDefinition { 48 | public: 49 | RawFileDefinition(const std::string& type, const std::string& name, bool isArray, std::string location, const std::string& content); 50 | 51 | virtual void Generate(std::ostream& output); 52 | private: 53 | std::string mContent; 54 | }; 55 | 56 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaBasicTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaBasicTypes.h" 2 | 3 | void toLua(lua_State* L, const std::string& string) { 4 | lua_pushlstring(L, string.c_str(), string.size()); 5 | } 6 | 7 | void fromLua(lua_State* L, std::string& string) { 8 | size_t len; 9 | const char* str = lua_tolstring(L, -1, &len); 10 | string.assign(str, len); 11 | lua_pop(L, 1); 12 | } 13 | 14 | void toLua(lua_State* L, int number) { 15 | lua_pushinteger(L, number); 16 | } 17 | 18 | 19 | void toLua(lua_State* L, unsigned int number) { 20 | lua_pushinteger(L, number); 21 | } 22 | 23 | void fromLua(lua_State* L, int& number) { 24 | number = lua_tointeger(L, -1); 25 | lua_pop(L, 1); 26 | } 27 | 28 | void toLua(lua_State* L, double number) { 29 | lua_pushnumber(L, number); 30 | } 31 | 32 | void fromLua(lua_State* L, double& number) { 33 | number = lua_tonumber(L, -1); 34 | lua_pop(L, 1); 35 | } 36 | 37 | void fromLua(lua_State* L, float& number) { 38 | number = (float)lua_tonumber(L, -1); 39 | lua_pop(L, 1); 40 | } -------------------------------------------------------------------------------- /src/lua_generator/LuaBasicTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_BASIC_TYPES_H__ 2 | #define __LUA_BASIC_TYPES_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void toLua(lua_State* L, const std::string& string); 12 | 13 | void fromLua(lua_State* L, std::string& string); 14 | 15 | void toLua(lua_State* L, int number); 16 | void toLua(lua_State* L, unsigned int number); 17 | 18 | void fromLua(lua_State* L, int& number); 19 | 20 | void toLua(lua_State* L, double number); 21 | 22 | void fromLua(lua_State* L, double& number); 23 | 24 | void fromLua(lua_State* L, float& number); 25 | 26 | template void toLua(lua_State* L, const std::vector vector) { 27 | lua_createtable(L, vector.size(), 0); 28 | 29 | int tableIndex = lua_gettop(L); 30 | 31 | int index = 1; 32 | 33 | for (const auto& element : vector) { 34 | toLua(L, element); 35 | lua_seti(L, tableIndex, index); 36 | ++index; 37 | } 38 | } 39 | 40 | template void fromLua(lua_State* L, std::vector& result) { 41 | lua_len(L, -1); 42 | 43 | int length; 44 | fromLua(L, length); 45 | result.resize(length); 46 | 47 | for (int i = 1; i <= length; ++i) { 48 | lua_geti(L, -1, i); 49 | fromLua(L, result[i-1]); 50 | } 51 | lua_pop(L, 1); 52 | } 53 | 54 | template void toLua(lua_State* L, const T* array, unsigned count) { 55 | lua_createtable(L, count, 0); 56 | 57 | int tableIndex = lua_gettop(L); 58 | 59 | for (unsigned i = 0; i < count; ++i) { 60 | toLua(L, array[i]); 61 | lua_seti(L, tableIndex, i + 1); 62 | } 63 | } 64 | 65 | template void toLua(lua_State* L, const std::pair& pair) { 66 | lua_createtable(L, 2, 0); 67 | 68 | int tableIndex = lua_gettop(L); 69 | 70 | toLua(L, pair.first); 71 | lua_seti(L, tableIndex, 1); 72 | 73 | toLua(L, pair.second); 74 | lua_seti(L, tableIndex, 2); 75 | } 76 | 77 | template void fromLua(lua_State* L, std::pair& pair) { 78 | lua_geti(L, -1, 1); 79 | fromLua(L, pair.first); 80 | lua_geti(L, -1, 2); 81 | fromLua(L, pair.second); 82 | lua_pop(L, 1); 83 | } 84 | 85 | template int luaSharedPtrGC(lua_State* L) { 86 | std::shared_ptr* ptr = (std::shared_ptr*)luaL_checkudata(L, 1, typeid(std::shared_ptr).name()); 87 | ptr->~shared_ptr(); 88 | return 0; 89 | } 90 | 91 | template void toLua(lua_State* L, std::shared_ptr ptr) { 92 | std::shared_ptr* result = (std::shared_ptr*)lua_newuserdata(L, sizeof(std::shared_ptr)); 93 | 94 | int resultIndex = lua_gettop(L); 95 | 96 | new(result) std::shared_ptr(ptr); 97 | 98 | if (luaL_newmetatable(L, typeid(std::shared_ptr).name())) { 99 | lua_pushcfunction(L, luaSharedPtrGC); 100 | lua_setfield(L, -2, "__gc"); 101 | } 102 | 103 | lua_setmetatable(L, resultIndex); 104 | } 105 | 106 | template void fromLua(lua_State* L, std::shared_ptr& output) { 107 | std::shared_ptr* ptr = (std::shared_ptr*)luaL_checkudata(L, -1, typeid(std::shared_ptr).name()); 108 | output = *ptr; 109 | lua_pop(L, 1); 110 | } 111 | 112 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaDefinitionWriter.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_DEFINITON_WRITER_H__ 2 | #define __LUA_DEFINITON_WRITER_H__ 3 | 4 | #include 5 | #include "../CFileDefinition.h" 6 | 7 | bool dumpDefinitions(lua_State* L, CFileDefinition& fileDef, const char* filename); 8 | 9 | void populateLuaDefinitionWrite(lua_State* L, CFileDefinition& fileDef); 10 | 11 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaDisplayListSettings.cpp: -------------------------------------------------------------------------------- 1 | /// @module sk_input 2 | 3 | #include "LuaDisplayListSettings.h" 4 | 5 | #include 6 | #include "./LuaMesh.h" 7 | #include "LuaTransform.h" 8 | #include "LuaBasicTypes.h" 9 | #include "LuaUtils.h" 10 | 11 | Material* luaGetMaterial(lua_State* L, const DisplayListSettings& defaults) { 12 | int materialType = lua_type(L, -1); 13 | 14 | if (materialType == LUA_TSTRING) { 15 | auto material = defaults.mMaterials.find(lua_tostring(L, -1)); 16 | 17 | if (material != defaults.mMaterials.end()) { 18 | return material->second.get(); 19 | } 20 | } 21 | 22 | if (materialType == LUA_TTABLE) { 23 | lua_pushnil(L); 24 | lua_copy(L, -2, -1); 25 | Material* result = nullptr; 26 | fromLua(L, result); 27 | return result; 28 | } 29 | 30 | return nullptr; 31 | } 32 | 33 | void fromLua(lua_State* L, DisplayListSettings& result, const DisplayListSettings& defaults) { 34 | result = defaults; 35 | 36 | int topStart = lua_gettop(L); 37 | 38 | lua_pushnil(L); /* first key */ 39 | while (lua_next(L, topStart) != 0) { 40 | int keyType = lua_type(L, -2); 41 | 42 | if (keyType == LUA_TSTRING) { 43 | const char* key = lua_tostring(L, -2); 44 | 45 | if (strcmp(key, "defaultMaterial") == 0) { 46 | Material* material = luaGetMaterial(L, defaults); 47 | 48 | if (!material) { 49 | luaL_error(L, "invlaid defaultMaterial"); 50 | } 51 | 52 | result.mDefaultMaterialState = material->mState; 53 | } 54 | } 55 | 56 | lua_pop(L, 1); 57 | } 58 | 59 | } 60 | 61 | /*** 62 | @table settings 63 | @tfield sk_transform.Transform model_transform 64 | @tfield sk_transform.Transform fixed_point_transform 65 | @tfield number model_scale 66 | @tfield number fixed_point_scale 67 | */ 68 | 69 | /*** 70 | @table input_filename 71 | @tfield foo bar 72 | */ 73 | 74 | int luaInputModuleLoader(lua_State* L) { 75 | lua_newtable(L); 76 | 77 | DisplayListSettings* defaults = (DisplayListSettings*)lua_touserdata(L, lua_upvalueindex(1)); 78 | const char* levelFilename = lua_tostring(L, lua_upvalueindex(2)); 79 | 80 | lua_newtable(L); 81 | toLua(L, defaults->CreateCollisionTransform()); 82 | lua_setfield(L, -2, "model_transform"); 83 | 84 | toLua(L, defaults->CreateGlobalTransform()); 85 | lua_setfield(L, -2, "fixed_point_transform"); 86 | 87 | toLua(L, defaults->mModelScale); 88 | lua_setfield(L, -2, "model_scale"); 89 | 90 | toLua(L, defaults->mFixedPointScale); 91 | lua_setfield(L, -2, "fixed_point_scale"); 92 | 93 | toLua(L, defaults->mTicksPerSecond); 94 | lua_setfield(L, -2, "ticks_per_second"); 95 | 96 | lua_setfield(L, -2, "settings"); 97 | 98 | lua_pushstring(L, levelFilename); 99 | lua_setfield(L, -2, "input_filename"); 100 | 101 | return 1; 102 | } 103 | 104 | void populateDisplayListSettings(lua_State* L, const DisplayListSettings& defaults, const std::string& levelFilename) { 105 | lua_pushlightuserdata(L, const_cast(&defaults)); 106 | lua_pushstring(L, levelFilename.c_str()); 107 | lua_pushcclosure(L, luaInputModuleLoader, 2); 108 | luaSetModuleLoader(L, "sk_input"); 109 | } -------------------------------------------------------------------------------- /src/lua_generator/LuaDisplayListSettings.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_DISPLAY_LIST_SETTINGS_H__ 2 | #define __LUA_DISPLAY_LIST_SETTINGS_H__ 3 | 4 | #include 5 | #include "../DisplayListSettings.h" 6 | 7 | void fromLua(lua_State* L, DisplayListSettings& result, const DisplayListSettings& defaults); 8 | 9 | void populateDisplayListSettings(lua_State* L, const DisplayListSettings& defaults, const std::string& levelFilename); 10 | 11 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaFiles.h: -------------------------------------------------------------------------------- 1 | EMIT(sk_definition_writer) 2 | EMIT(sk_math) 3 | EMIT(sk_scene) 4 | EMIT(sk_animation) -------------------------------------------------------------------------------- /src/lua_generator/LuaGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaGenerator.h" 2 | #include "../FileUtils.h" 3 | 4 | #include "LuaDefinitionWriter.h" 5 | #include "LuaTransform.h" 6 | #include "LuaNodeGroups.h" 7 | #include "LuaScene.h" 8 | #include "LuaMesh.h" 9 | #include "LuaDisplayListSettings.h" 10 | #include "LuaBasicTypes.h" 11 | 12 | #include 13 | #include 14 | 15 | #define EMIT(name) extern const char _binary_build_lua_##name##_out_start[]; extern const char _binary_build_lua_##name##_out_end[]; 16 | #include "LuaFiles.h" 17 | #undef EMIT 18 | 19 | struct LuaFile { 20 | const char* start; 21 | const char* end; 22 | const char* name; 23 | const char* moduleName; 24 | }; 25 | 26 | struct LuaFile luaFiles[] = { 27 | #define EMIT(name) {_binary_build_lua_##name##_out_start, _binary_build_lua_##name##_out_end, "lua/" #name ".lua", #name}, 28 | #include "LuaFiles.h" 29 | #undef EMIT 30 | }; 31 | 32 | bool checkLuaError(lua_State *L, int errCode, const char* filename) { 33 | if (errCode != LUA_OK) { 34 | const char* error = lua_tostring(L, -1); 35 | 36 | if (error) { 37 | std::cerr << "Error running " << filename << ":" << std::endl << error << std::endl; 38 | } else { 39 | std::cerr << "Unknown error running " << filename; 40 | } 41 | 42 | return true; 43 | } 44 | 45 | return false; 46 | } 47 | 48 | int loadPrecompiledModule(lua_State* L) { 49 | const char* moduleName = lua_tostring(L, lua_upvalueindex(1)); 50 | 51 | for (unsigned i = 0; i < sizeof(luaFiles) / sizeof(*luaFiles); ++i) { 52 | struct LuaFile* file = &luaFiles[i]; 53 | 54 | if (strcmp(moduleName, file->moduleName) != 0) { 55 | continue; 56 | } 57 | 58 | luaL_loadbuffer(L, file->start, file->end - file->start, file->name); 59 | 60 | int errCode = lua_pcall(L, 0, 1, 0); 61 | 62 | if (checkLuaError(L, errCode, file->name)) { 63 | lua_close(L); 64 | exit(1); 65 | return 0; 66 | } 67 | 68 | return 1; 69 | } 70 | 71 | return 0; 72 | } 73 | 74 | void generateFromLuaScript( 75 | const std::string& levelFilename, 76 | const std::string& filename, 77 | const aiScene* scene, 78 | CFileDefinition& fileDefinition, 79 | NodeGroups& nodeGroups, 80 | const DisplayListSettings& settings 81 | ) { 82 | lua_State *L = luaL_newstate(); 83 | luaL_openlibs(L); 84 | generateLuaTransform(L); 85 | populateLuaMesh(L, scene, fileDefinition, settings); 86 | 87 | lua_getglobal(L, "package"); 88 | lua_getfield(L, -1, "preload"); 89 | 90 | for (unsigned i = 0; i < sizeof(luaFiles) / sizeof(*luaFiles); ++i) { 91 | struct LuaFile* file = &luaFiles[i]; 92 | lua_pushstring(L, file->moduleName); 93 | lua_pushcclosure(L, loadPrecompiledModule, 1); 94 | lua_setfield(L, -2, file->moduleName); 95 | } 96 | 97 | // pop package and preload 98 | lua_pop(L, 2); 99 | 100 | populateDisplayListSettings(L, settings, levelFilename); 101 | populateLuaDefinitionWrite(L, fileDefinition); 102 | populateLuaScene(L, scene, fileDefinition, settings); 103 | populateLuaNodeGroups(L, nodeGroups); 104 | 105 | std::string directory = DirectoryName(filename) + "/?.lua;"; 106 | 107 | // set the directory of the script location as a search path 108 | lua_getglobal(L, "package"); 109 | int packageLocation = lua_gettop(L); 110 | lua_pushstring(L, directory.c_str()); 111 | lua_getfield(L, packageLocation, "path"); 112 | lua_concat(L, 2); 113 | lua_setfield(L, packageLocation, "path"); 114 | 115 | int errCode = luaL_dofile(L, filename.c_str()); 116 | if (checkLuaError(L, errCode, filename.c_str())) { 117 | lua_close(L); 118 | exit(1); 119 | return; 120 | } 121 | 122 | if (!dumpDefinitions(L, fileDefinition, filename.c_str())) { 123 | lua_close(L); 124 | exit(1); 125 | return; 126 | } 127 | 128 | lua_close(L); 129 | } -------------------------------------------------------------------------------- /src/lua_generator/LuaGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_GENERATOR_H__ 2 | #define __LUA_GENERATOR_H__ 3 | 4 | #include 5 | #include 6 | #include "../CFileDefinition.h" 7 | #include "../DisplayListSettings.h" 8 | #include "../definition_generator/DefinitionGenerator.h" 9 | 10 | bool checkLuaError(lua_State *L, int errCode, const char* filename); 11 | 12 | void generateFromLuaScript( 13 | const std::string& levelFilename, 14 | const std::string& filename, 15 | const aiScene* scene, 16 | CFileDefinition& fileDefinition, 17 | NodeGroups& nodeGroups, 18 | const DisplayListSettings& settings 19 | ); 20 | 21 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaGeometry.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaGeometry.h" 2 | 3 | #include "LuaBasicTypes.h" 4 | #include "LuaUtils.h" 5 | 6 | void toLua(lua_State* L, const aiVector3D& vector) { 7 | luaLoadModuleFunction(L, "sk_math", "vector3"); 8 | toLua(L, vector.x); 9 | toLua(L, vector.y); 10 | toLua(L, vector.z); 11 | lua_call(L, 3, 1); 12 | } 13 | 14 | void toLua(lua_State* L, const aiColor4D& color) { 15 | luaLoadModuleFunction(L, "sk_math", "color4"); 16 | toLua(L, color.r); 17 | toLua(L, color.g); 18 | toLua(L, color.b); 19 | toLua(L, color.a); 20 | lua_call(L, 4, 1); 21 | 22 | } 23 | 24 | void toLua(lua_State* L, const aiQuaternion& quaternion) { 25 | luaLoadModuleFunction(L, "sk_math", "quaternion"); 26 | toLua(L, quaternion.x); 27 | toLua(L, quaternion.y); 28 | toLua(L, quaternion.z); 29 | toLua(L, quaternion.w); 30 | lua_call(L, 4, 1); 31 | } 32 | 33 | void toLua(lua_State* L, const aiAABB& box) { 34 | luaLoadModuleFunction(L, "sk_math", "box3"); 35 | toLua(L, box.mMin); 36 | toLua(L, box.mMax); 37 | lua_call(L, 2, 1); 38 | } 39 | 40 | void fromLua(lua_State* L, aiVector3D& vector) { 41 | lua_getfield(L, -1, "x"); 42 | fromLua(L, vector.x); 43 | 44 | lua_getfield(L, -1, "y"); 45 | fromLua(L, vector.y); 46 | 47 | lua_getfield(L, -1, "z"); 48 | fromLua(L, vector.z); 49 | 50 | lua_pop(L, 1); 51 | } 52 | 53 | void fromLua(lua_State* L, aiQuaternion& quaternion) { 54 | lua_getfield(L, -1, "x"); 55 | fromLua(L, quaternion.x); 56 | 57 | lua_getfield(L, -1, "y"); 58 | fromLua(L, quaternion.y); 59 | 60 | lua_getfield(L, -1, "z"); 61 | fromLua(L, quaternion.z); 62 | 63 | lua_getfield(L, -1, "w"); 64 | fromLua(L, quaternion.w); 65 | 66 | lua_pop(L, 1); 67 | } 68 | 69 | void fromLua(lua_State* L, aiColor4D& color) { 70 | lua_getfield(L, -1, "r"); 71 | fromLua(L, color.r); 72 | 73 | lua_getfield(L, -1, "g"); 74 | fromLua(L, color.g); 75 | 76 | lua_getfield(L, -1, "b"); 77 | fromLua(L, color.b); 78 | 79 | lua_getfield(L, -1, "a"); 80 | fromLua(L, color.a); 81 | 82 | lua_pop(L, 1); 83 | } -------------------------------------------------------------------------------- /src/lua_generator/LuaGeometry.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_GEOMETRY_H__ 2 | #define __LUA_GEOMETRY_H__ 3 | 4 | #include 5 | #include 6 | 7 | void toLua(lua_State* L, const aiQuaternion& quaternion); 8 | void toLua(lua_State* L, const aiVector3D& vector); 9 | void toLua(lua_State* L, const aiColor4D& color); 10 | void toLua(lua_State* L, const aiAABB& box); 11 | 12 | void fromLua(lua_State* L, aiVector3D& vector); 13 | void fromLua(lua_State* L, aiQuaternion& quaternion); 14 | void fromLua(lua_State* L, aiColor4D& color); 15 | 16 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaMesh.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_MESH_H__ 2 | #define __LUA_MESH_H__ 3 | 4 | #include 5 | #include 6 | #include "../CFileDefinition.h" 7 | #include "../DisplayListSettings.h" 8 | 9 | template 10 | struct LazyVectorWithLength { 11 | T* vertices; 12 | int length; 13 | }; 14 | 15 | void fromLua(lua_State* L, Material *& material); 16 | void meshToLua(lua_State* L, std::shared_ptr mesh); 17 | void meshFromLua(lua_State* L, std::shared_ptr& mesh); 18 | 19 | template 20 | std::string luaGetVectorName() { 21 | return std::string("LazyVectorWithLength<") + typeid(T).name() + std::string(">"); 22 | } 23 | 24 | template 25 | bool luaIsLazyVector3DArray(lua_State* L, int index) { 26 | return luaL_testudata(L, index, luaGetVectorName().c_str()); 27 | } 28 | 29 | void populateLuaMesh(lua_State* L, const aiScene* scene, CFileDefinition& fileDefinition, const DisplayListSettings& settings); 30 | 31 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaNodeGroups.cpp: -------------------------------------------------------------------------------- 1 | // lua docs defined in sk_scene.lua 2 | 3 | #include "LuaNodeGroups.h" 4 | 5 | #include "LuaBasicTypes.h" 6 | #include "LuaScene.h" 7 | #include "LuaUtils.h" 8 | 9 | void toLua(lua_State* L, const NodeWithArguments& nodes) { 10 | lua_createtable(L, 0, 2); 11 | 12 | int tableIndex = lua_gettop(L); 13 | 14 | toLua(L, nodes.arguments); 15 | lua_setfield(L, tableIndex, "arguments"); 16 | 17 | toLua(L, nodes.node); 18 | lua_setfield(L, tableIndex, "node"); 19 | } 20 | 21 | int luaNodesForType(lua_State* L) { 22 | std::string prefix = luaL_checkstring(L, 1); 23 | NodeGroups* nodeGroups = (NodeGroups*)lua_touserdata(L, lua_upvalueindex(1)); 24 | 25 | std::vector result = nodeGroups->NodesForType(prefix); 26 | toLua(L, result); 27 | return 1; 28 | } 29 | 30 | int luaNodeGroupsAppendModule(lua_State* L) { 31 | int moduleIndex = luaGetPrevModuleLoader(L); 32 | 33 | NodeGroups* nodeGroups = (NodeGroups*)lua_touserdata(L, lua_upvalueindex(2)); 34 | 35 | lua_pushlightuserdata(L, nodeGroups); 36 | lua_pushcclosure(L, luaNodesForType, 1); 37 | lua_setfield(L, moduleIndex, "nodes_for_type"); 38 | 39 | return 1; 40 | } 41 | 42 | void populateLuaNodeGroups(lua_State* L, NodeGroups& nodeGroups) { 43 | lua_pushlightuserdata(L, (NodeGroups*)&nodeGroups); 44 | luaChainModuleLoader(L, "sk_scene", luaNodeGroupsAppendModule, 1); 45 | } -------------------------------------------------------------------------------- /src/lua_generator/LuaNodeGroups.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_NODE_GROUPS_H__ 2 | #define __LUA_NODE_GROUPS_H__ 3 | 4 | #include 5 | #include "../definition_generator/DefinitionGenerator.h" 6 | 7 | void populateLuaNodeGroups(lua_State* L, NodeGroups& nodeGroups); 8 | 9 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaScene.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_SCENE_H__ 2 | #define __LUA_SCENE_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "../DisplayListSettings.h" 8 | #include "../CFileDefinition.h" 9 | 10 | extern const aiScene* gLuaCurrentScene; 11 | extern const DisplayListSettings* gLuaCurrentSettings; 12 | 13 | void toLua(lua_State* L, const aiNode* node); 14 | 15 | void fromLua(lua_State* L, aiNode *& node); 16 | 17 | void populateLuaScene(lua_State* L, const aiScene* scene, CFileDefinition& fileDefinition, const DisplayListSettings& setting); 18 | 19 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaTransform.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_TRANSFORM_H__ 2 | #define __LUA_TRANSFORM_H__ 3 | 4 | #include 5 | #include 6 | 7 | #include "LuaGeometry.h" 8 | 9 | void toLua(lua_State* L, const aiMatrix4x4& matrix); 10 | void fromLua(lua_State* L, aiMatrix4x4& matrix); 11 | 12 | void generateLuaTransform(lua_State* L); 13 | 14 | #endif -------------------------------------------------------------------------------- /src/lua_generator/LuaUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaUtils.h" 2 | 3 | void luaLoadModuleFunction(lua_State* L, const char* moduleName, const char* functionName) { 4 | lua_getglobal(L, "require"); 5 | lua_pushstring(L, moduleName); 6 | lua_call(L, 1, 1); 7 | 8 | lua_getfield(L, -1, functionName); 9 | lua_remove(L, -2); 10 | } 11 | 12 | void luaSetModuleLoader(lua_State* L, const char* moduleName) { 13 | lua_getglobal(L, "package"); 14 | lua_getfield(L, -1, "preload"); 15 | lua_rotate(L, -3, -1); 16 | lua_setfield(L, -2, moduleName); 17 | lua_pop(L, 2); 18 | } 19 | 20 | void luaChainModuleLoader(lua_State* L, const char* moduleName, lua_CFunction function, int additionalClosure) { 21 | int startingTop = lua_gettop(L); 22 | 23 | lua_getglobal(L, "package"); 24 | lua_getfield(L, -1, "preload"); 25 | 26 | lua_getfield(L, -1, moduleName); 27 | 28 | if (additionalClosure) { 29 | lua_rotate(L, startingTop - additionalClosure + 1, -additionalClosure); 30 | } 31 | 32 | lua_pushcclosure(L, function, 1 + additionalClosure); 33 | lua_setfield(L, -2, moduleName); 34 | 35 | // pop package and preload 36 | lua_pop(L, 2); 37 | } 38 | 39 | int luaGetPrevModuleLoader(lua_State* L) { 40 | int nArgs = lua_gettop(L); 41 | 42 | lua_pushnil(L); 43 | lua_copy(L, lua_upvalueindex(1), -1); 44 | 45 | lua_insert(L, 1); 46 | lua_call(L, nArgs, 1); 47 | 48 | return lua_gettop(L); 49 | } -------------------------------------------------------------------------------- /src/lua_generator/LuaUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef __LUA_UTILS_H__ 2 | #define __LUA_UTILS_H__ 3 | 4 | #include 5 | 6 | void luaLoadModuleFunction(lua_State* L, const char* moduleName, const char* functionName); 7 | 8 | void luaSetModuleLoader(lua_State* L, const char* moduleName); 9 | 10 | void luaChainModuleLoader(lua_State* L, const char* moduleName, lua_CFunction function, int additionalClosure); 11 | 12 | int luaGetPrevModuleLoader(lua_State* L); 13 | 14 | #endif -------------------------------------------------------------------------------- /src/materials/CImgu8.cpp: -------------------------------------------------------------------------------- 1 | #include "CImgu8.h" 2 | 3 | 4 | CImgu8::CImgu8(const std::string& filename) : mImg(filename.c_str()) { 5 | 6 | } 7 | 8 | CImgu8::CImgu8(const cimg_library_suffixed::CImg& img) : mImg(img) { 9 | 10 | } -------------------------------------------------------------------------------- /src/materials/CImgu8.h: -------------------------------------------------------------------------------- 1 | #ifndef __CIMG_U8_H__ 2 | #define __CIMG_U8_H__ 3 | 4 | #define cimg_display 0 5 | #define cimg_use_png 6 | #define cimg_use_tiff 7 | // This is a massive header file and I don't 8 | // want it to drive my compile times up by being 9 | // included in every file. That is whey I created 10 | // The CImgu8 class. You should not include this header 11 | // file from other header files 12 | #include "../../cimg/CImg.h" 13 | 14 | #include 15 | 16 | class CImgu8 { 17 | public: 18 | CImgu8(const std::string& filename); 19 | CImgu8(const cimg_library_suffixed::CImg& img); 20 | cimg_library_suffixed::CImg mImg; 21 | }; 22 | 23 | #endif -------------------------------------------------------------------------------- /src/materials/CombineMode.cpp: -------------------------------------------------------------------------------- 1 | #include "CombineMode.h" 2 | 3 | #include 4 | 5 | #define DEFINE_NAMED_COMBINE_MODE(combineMode) {#combineMode, DEFINE_COMBINE_MODE_LERP(combineMode)} 6 | 7 | std::map gNamedCombineModes = { 8 | DEFINE_NAMED_COMBINE_MODE(G_CC_PRIMITIVE), 9 | DEFINE_NAMED_COMBINE_MODE(G_CC_SHADE), 10 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEI), 11 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEIA), 12 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEIDECALA), 13 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGB), 14 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGBA), 15 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGBDECALA), 16 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEI_PRIM), 17 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEIA_PRIM), 18 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEIDECALA_PRIM), 19 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGB_PRIM), 20 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGBA_PRIM), 21 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGBDECALA_PRIM), 22 | DEFINE_NAMED_COMBINE_MODE(G_CC_DECALRGB), 23 | DEFINE_NAMED_COMBINE_MODE(G_CC_DECALRGBA), 24 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDI), 25 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDIA), 26 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDIDECALA), 27 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDRGBA), 28 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDRGBDECALA), 29 | DEFINE_NAMED_COMBINE_MODE(G_CC_ADDRGB), 30 | DEFINE_NAMED_COMBINE_MODE(G_CC_ADDRGBDECALA), 31 | DEFINE_NAMED_COMBINE_MODE(G_CC_REFLECTRGB), 32 | DEFINE_NAMED_COMBINE_MODE(G_CC_REFLECTRGBDECALA), 33 | DEFINE_NAMED_COMBINE_MODE(G_CC_HILITERGB), 34 | DEFINE_NAMED_COMBINE_MODE(G_CC_HILITERGBA), 35 | DEFINE_NAMED_COMBINE_MODE(G_CC_HILITERGBDECALA), 36 | DEFINE_NAMED_COMBINE_MODE(G_CC_SHADEDECALA), 37 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDPE), 38 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDPEDECALA), 39 | 40 | /* oddball modes */ 41 | DEFINE_NAMED_COMBINE_MODE(_G_CC_BLENDPE), 42 | DEFINE_NAMED_COMBINE_MODE(_G_CC_BLENDPEDECALA), 43 | DEFINE_NAMED_COMBINE_MODE(_G_CC_TWOCOLORTEX), 44 | /* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */ 45 | DEFINE_NAMED_COMBINE_MODE(_G_CC_SPARSEST), 46 | DEFINE_NAMED_COMBINE_MODE(G_CC_TEMPLERP), 47 | 48 | /* typical CC cycle 1 modes, usually followed by other cycle 2 modes */ 49 | DEFINE_NAMED_COMBINE_MODE(G_CC_TRILERP), 50 | DEFINE_NAMED_COMBINE_MODE(G_CC_INTERFERENCE), 51 | 52 | /* 53 | * One-cycle color convert operation 54 | */ 55 | DEFINE_NAMED_COMBINE_MODE(G_CC_1CYUV2RGB), 56 | 57 | /* 58 | * NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock. 59 | * Therefore, CC looks for step1 results in TEXEL1 60 | */ 61 | DEFINE_NAMED_COMBINE_MODE(G_CC_YUV2RGB), 62 | 63 | /* typical CC cycle 2 modes */ 64 | DEFINE_NAMED_COMBINE_MODE(G_CC_PASS2), 65 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEI2), 66 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEIA2), 67 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGB2), 68 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGBA2), 69 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEI_PRIM2), 70 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATEIA_PRIM2), 71 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGB_PRIM2), 72 | DEFINE_NAMED_COMBINE_MODE(G_CC_MODULATERGBA_PRIM2), 73 | DEFINE_NAMED_COMBINE_MODE(G_CC_DECALRGB2), 74 | /* 75 | * ? 76 | DEFINE_NAMED_COMBINE_MODE(G_CC_DECALRGBA2), 77 | */ 78 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDI2), 79 | DEFINE_NAMED_COMBINE_MODE(G_CC_BLENDIA2), 80 | DEFINE_NAMED_COMBINE_MODE(G_CC_CHROMA_KEY2), 81 | DEFINE_NAMED_COMBINE_MODE(G_CC_HILITERGB2), 82 | DEFINE_NAMED_COMBINE_MODE(G_CC_HILITERGBA2), 83 | DEFINE_NAMED_COMBINE_MODE(G_CC_HILITERGBDECALA2), 84 | DEFINE_NAMED_COMBINE_MODE(G_CC_HILITERGBPASSA2), 85 | }; 86 | 87 | bool combineModeWithName(const std::string& name, ColorCombineMode& result) { 88 | auto it = gNamedCombineModes.find(name); 89 | 90 | if (it == gNamedCombineModes.end()) { 91 | return false; 92 | } 93 | 94 | result = it->second; 95 | 96 | return true; 97 | } -------------------------------------------------------------------------------- /src/materials/CombineMode.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMBINE_MODE_H__ 2 | #define __COMBINE_MODE_H__ 3 | 4 | #include "MaterialState.h" 5 | #include 6 | 7 | /* 8 | * G_SETCOMBINE: color combine modes 9 | */ 10 | /* Color combiner constants: */ 11 | #define G_CCMUX_COMBINED ColorCombineSource::Combined 12 | #define G_CCMUX_TEXEL0 ColorCombineSource::Texel0 13 | #define G_CCMUX_TEXEL1 ColorCombineSource::Texel1 14 | #define G_CCMUX_PRIMITIVE ColorCombineSource::PrimitiveColor 15 | #define G_CCMUX_SHADE ColorCombineSource::ShadeColor 16 | #define G_CCMUX_ENVIRONMENT ColorCombineSource::EnvironmentColor 17 | #define G_CCMUX_CENTER ColorCombineSource::KeyCenter 18 | #define G_CCMUX_SCALE ColorCombineSource::KeyScale 19 | #define G_CCMUX_COMBINED_ALPHA ColorCombineSource::CombinedAlpha 20 | #define G_CCMUX_TEXEL0_ALPHA ColorCombineSource::Texture0Alpha 21 | #define G_CCMUX_TEXEL1_ALPHA ColorCombineSource::Texture1Alpha 22 | #define G_CCMUX_PRIMITIVE_ALPHA ColorCombineSource::PrimitiveAlpha 23 | #define G_CCMUX_SHADE_ALPHA ColorCombineSource::ShadedAlpha 24 | #define G_CCMUX_ENV_ALPHA ColorCombineSource::EnvironmentAlpha 25 | #define G_CCMUX_LOD_FRACTION ColorCombineSource::LODFraction 26 | #define G_CCMUX_PRIM_LOD_FRAC ColorCombineSource::PrimitiveLODFraction 27 | #define G_CCMUX_NOISE ColorCombineSource::Noise 28 | #define G_CCMUX_K4 ColorCombineSource::ConvertK4 29 | #define G_CCMUX_K5 ColorCombineSource::ConvertK5 30 | #define G_CCMUX_1 ColorCombineSource::_1 31 | #define G_CCMUX_0 ColorCombineSource::_0 32 | 33 | /* Alpha combiner constants: */ 34 | #define G_ACMUX_COMBINED AlphaCombineSource::CombinedAlpha 35 | #define G_ACMUX_TEXEL0 AlphaCombineSource::Texture0Alpha 36 | #define G_ACMUX_TEXEL1 AlphaCombineSource::Texture1Alpha 37 | #define G_ACMUX_PRIMITIVE AlphaCombineSource::PrimitiveAlpha 38 | #define G_ACMUX_SHADE AlphaCombineSource::ShadedAlpha 39 | #define G_ACMUX_ENVIRONMENT AlphaCombineSource::EnvironmentAlpha 40 | #define G_ACMUX_LOD_FRACTION AlphaCombineSource::LODFraction 41 | #define G_ACMUX_PRIM_LOD_FRAC AlphaCombineSource::PrimitiveLODFraction 42 | #define G_ACMUX_1 AlphaCombineSource::_1 43 | #define G_ACMUX_0 AlphaCombineSource::_0 44 | 45 | /* typical CC cycle 1 modes */ 46 | #define G_CC_PRIMITIVE 0, 0, 0, PRIMITIVE, 0, 0, 0, PRIMITIVE 47 | #define G_CC_SHADE 0, 0, 0, SHADE, 0, 0, 0, SHADE 48 | #define G_CC_MODULATEI TEXEL0, 0, SHADE, 0, 0, 0, 0, SHADE 49 | #define G_CC_MODULATEIA TEXEL0, 0, SHADE, 0, TEXEL0, 0, SHADE, 0 50 | #define G_CC_MODULATEIDECALA TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0 51 | #define G_CC_MODULATERGB G_CC_MODULATEI 52 | #define G_CC_MODULATERGBA G_CC_MODULATEIA 53 | #define G_CC_MODULATERGBDECALA G_CC_MODULATEIDECALA 54 | #define G_CC_MODULATEI_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE 55 | #define G_CC_MODULATEIA_PRIM TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0 56 | #define G_CC_MODULATEIDECALA_PRIM TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0 57 | #define G_CC_MODULATERGB_PRIM G_CC_MODULATEI_PRIM 58 | #define G_CC_MODULATERGBA_PRIM G_CC_MODULATEIA_PRIM 59 | #define G_CC_MODULATERGBDECALA_PRIM G_CC_MODULATEIDECALA_PRIM 60 | #define G_CC_DECALRGB 0, 0, 0, TEXEL0, 0, 0, 0, SHADE 61 | #define G_CC_DECALRGBA 0, 0, 0, TEXEL0, 0, 0, 0, TEXEL0 62 | #define G_CC_BLENDI ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE 63 | #define G_CC_BLENDIA ENVIRONMENT, SHADE, TEXEL0, SHADE, TEXEL0, 0, SHADE, 0 64 | #define G_CC_BLENDIDECALA ENVIRONMENT, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 65 | #define G_CC_BLENDRGBA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, SHADE 66 | #define G_CC_BLENDRGBDECALA TEXEL0, SHADE, TEXEL0_ALPHA, SHADE, 0, 0, 0, TEXEL0 67 | #define G_CC_ADDRGB 1, 0, TEXEL0, SHADE, 0, 0, 0, SHADE 68 | #define G_CC_ADDRGBDECALA 1, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 69 | #define G_CC_REFLECTRGB ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, SHADE 70 | #define G_CC_REFLECTRGBDECALA ENVIRONMENT, 0, TEXEL0, SHADE, 0, 0, 0, TEXEL0 71 | #define G_CC_HILITERGB PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE 72 | #define G_CC_HILITERGBA PRIMITIVE, SHADE, TEXEL0, SHADE, PRIMITIVE, SHADE, TEXEL0, SHADE 73 | #define G_CC_HILITERGBDECALA PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, TEXEL0 74 | #define G_CC_SHADEDECALA 0, 0, 0, SHADE, 0, 0, 0, TEXEL0 75 | #define G_CC_BLENDPE PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, SHADE, 0 76 | #define G_CC_BLENDPEDECALA PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, 0, 0, 0, TEXEL0 77 | 78 | /* oddball modes */ 79 | #define _G_CC_BLENDPE ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, TEXEL0, 0, SHADE, 0 80 | #define _G_CC_BLENDPEDECALA ENVIRONMENT, PRIMITIVE, TEXEL0, PRIMITIVE, 0, 0, 0, TEXEL0 81 | #define _G_CC_TWOCOLORTEX PRIMITIVE, SHADE, TEXEL0, SHADE, 0, 0, 0, SHADE 82 | /* used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD */ 83 | #define _G_CC_SPARSEST PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0, PRIMITIVE, TEXEL0, LOD_FRACTION, TEXEL0 84 | #define G_CC_TEMPLERP TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0, TEXEL1, TEXEL0, PRIM_LOD_FRAC, TEXEL0 85 | 86 | /* typical CC cycle 1 modes, usually followed by other cycle 2 modes */ 87 | #define G_CC_TRILERP TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0, TEXEL1, TEXEL0, LOD_FRACTION, TEXEL0 88 | #define G_CC_INTERFERENCE TEXEL0, 0, TEXEL1, 0, TEXEL0, 0, TEXEL1, 0 89 | 90 | /* 91 | * One-cycle color convert operation 92 | */ 93 | #define G_CC_1CYUV2RGB TEXEL0, K4, K5, TEXEL0, 0, 0, 0, SHADE 94 | 95 | /* 96 | * NOTE: YUV2RGB expects TF step1 color conversion to occur in 2nd clock. 97 | * Therefore, CC looks for step1 results in TEXEL1 98 | */ 99 | #define G_CC_YUV2RGB TEXEL1, K4, K5, TEXEL1, 0, 0, 0, 0 100 | 101 | /* typical CC cycle 2 modes */ 102 | #define G_CC_PASS2 0, 0, 0, COMBINED, 0, 0, 0, COMBINED 103 | #define G_CC_MODULATEI2 COMBINED, 0, SHADE, 0, 0, 0, 0, SHADE 104 | #define G_CC_MODULATEIA2 COMBINED, 0, SHADE, 0, COMBINED, 0, SHADE, 0 105 | #define G_CC_MODULATERGB2 G_CC_MODULATEI2 106 | #define G_CC_MODULATERGBA2 G_CC_MODULATEIA2 107 | #define G_CC_MODULATEI_PRIM2 COMBINED, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE 108 | #define G_CC_MODULATEIA_PRIM2 COMBINED, 0, PRIMITIVE, 0, COMBINED, 0, PRIMITIVE, 0 109 | #define G_CC_MODULATERGB_PRIM2 G_CC_MODULATEI_PRIM2 110 | #define G_CC_MODULATERGBA_PRIM2 G_CC_MODULATEIA_PRIM2 111 | #define G_CC_DECALRGB2 0, 0, 0, COMBINED, 0, 0, 0, SHADE 112 | /* 113 | * ? 114 | #define G_CC_DECALRGBA2 COMBINED, SHADE, COMBINED_ALPHA, SHADE, 0, 0, 0, SHADE 115 | */ 116 | #define G_CC_BLENDI2 ENVIRONMENT, SHADE, COMBINED, SHADE, 0, 0, 0, SHADE 117 | #define G_CC_BLENDIA2 ENVIRONMENT, SHADE, COMBINED, SHADE, COMBINED, 0, SHADE, 0 118 | #define G_CC_CHROMA_KEY2 TEXEL0, CENTER, SCALE, 0, 0, 0, 0, 0 119 | #define G_CC_HILITERGB2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, SHADE 120 | #define G_CC_HILITERGBA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, ENVIRONMENT, COMBINED, TEXEL0, COMBINED 121 | #define G_CC_HILITERGBDECALA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, TEXEL0 122 | #define G_CC_HILITERGBPASSA2 ENVIRONMENT, COMBINED, TEXEL0, COMBINED, 0, 0, 0, COMBINED 123 | 124 | #define DEFINE_COMBINE_MODE_LERP(c0, c1, c2, c3, a0, a1, a2, a3) \ 125 | ColorCombineMode(G_CCMUX_##c0, G_CCMUX_##c1, G_CCMUX_##c2, G_CCMUX_##c3, G_ACMUX_##a0, G_ACMUX_##a1, G_ACMUX_##a2, G_ACMUX_##a3) 126 | 127 | #define DEFINE_COMBINE_MODE(terms) DEFINE_COMBINE_MODE_LERP(terms) 128 | 129 | bool combineModeWithName(const std::string& name, ColorCombineMode& result); 130 | 131 | #endif -------------------------------------------------------------------------------- /src/materials/Material.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Material.h" 3 | 4 | #include "../StringUtils.h" 5 | #include "../CFileDefinition.h" 6 | 7 | Material::Material(const std::string& name): mName(name), mNormalSource(NormalSource::Normal), mExcludeFromOutut(false), mSortOrder(0) {} 8 | 9 | void Material::Write(CFileDefinition& fileDef, const MaterialState& from, StructureDataChunk& output, bool targetCIBuffer) { 10 | generateMaterial(fileDef, from, mState, output, targetCIBuffer); 11 | } 12 | 13 | int Material::TextureWidth(Material* material) { 14 | if (!material) { 15 | return 0; 16 | } 17 | 18 | for (int i = 0; i < MAX_TILE_COUNT; ++i) { 19 | if (material->mState.tiles[i].isOn && material->mState.tiles[i].texture) { 20 | return material->mState.tiles[i].texture->Width(); 21 | } 22 | } 23 | 24 | return 0; 25 | } 26 | 27 | int Material::TextureHeight(Material* material) { 28 | if (!material) { 29 | return 0; 30 | } 31 | 32 | for (int i = 0; i < MAX_TILE_COUNT; ++i) { 33 | if (material->mState.tiles[i].isOn && material->mState.tiles[i].texture) { 34 | return material->mState.tiles[i].texture->Height(); 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | 41 | VertexType convertNormalSourceToVertexType(NormalSource normalSource) { 42 | switch (normalSource) { 43 | case NormalSource::Normal: 44 | return VertexType::PosUVNormal; 45 | 46 | case NormalSource::Tangent: 47 | return VertexType::POSUVTangent; 48 | case NormalSource::MinusTangent: 49 | return VertexType::POSUVMinusTangent; 50 | case NormalSource::Bitangent: 51 | return VertexType::POSUVMinusCotangent; 52 | case NormalSource::MinusCotangent: 53 | return VertexType::POSUVMinusCotangent; 54 | } 55 | 56 | return VertexType::PosUVNormal; 57 | } 58 | 59 | VertexType Material::GetVertexType(Material* material) { 60 | if (!material) { 61 | return VertexType::PosUVNormal; 62 | } 63 | 64 | if (material->mState.geometryModes.knownFlags & material->mState.geometryModes.flags & (int)GeometryMode::G_LIGHTING) { 65 | return convertNormalSourceToVertexType(material->mNormalSource); 66 | } 67 | 68 | return VertexType::PosUVColor; 69 | } -------------------------------------------------------------------------------- /src/materials/Material.h: -------------------------------------------------------------------------------- 1 | #ifndef _MATERIAL_H 2 | #define _MATERIAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "TextureDefinition.h" 11 | #include "../DisplayList.h" 12 | #include "../ExtendedMesh.h" 13 | #include "MaterialState.h" 14 | #include "../definitions/DataChunk.h" 15 | #include "../CFileDefinition.h" 16 | 17 | #include "MaterialEnums.h" 18 | 19 | enum class NormalSource { 20 | Normal, 21 | Tangent, 22 | MinusTangent, 23 | Bitangent, 24 | MinusCotangent, 25 | }; 26 | 27 | class Material { 28 | public: 29 | Material(const std::string& name); 30 | std::string mName; 31 | MaterialState mState; 32 | std::map mProperties; 33 | NormalSource mNormalSource; 34 | bool mExcludeFromOutut; 35 | int mSortOrder; 36 | PixelRGBAu8 mDefaultVertexColor; 37 | 38 | void Write(CFileDefinition& fileDef, const MaterialState& from, StructureDataChunk& output, bool targetCIBuffer); 39 | 40 | static int TextureWidth(Material* material); 41 | static int TextureHeight(Material* material); 42 | 43 | static VertexType GetVertexType(Material* material); 44 | }; 45 | 46 | #endif -------------------------------------------------------------------------------- /src/materials/MaterialEnums.cpp: -------------------------------------------------------------------------------- 1 | #include "MaterialEnums.h" 2 | 3 | const char* gGeometryModeNames[GEOMETRY_MODE_COUNT] = { 4 | "G_ZBUFFER", 5 | "G_SHADE", 6 | "G_TEXTURE_ENABLE", 7 | "G_SHADING_SMOOTH", 8 | "G_CULL_FRONT", 9 | "G_CULL_BACK", 10 | "G_FOG", 11 | "G_LIGHTING", 12 | "G_TEXTURE_GEN", 13 | "G_TEXTURE_GEN_LINEAR", 14 | "G_LOD", 15 | "G_CLIPPING", 16 | }; 17 | 18 | const char* gCycleTypeNames[(int)CycleType::Count] = { 19 | "Unknown", 20 | "G_CYC_1CYCLE", 21 | "G_CYC_2CYCLE", 22 | "G_CYC_COPY", 23 | "G_CYC_FILL", 24 | }; 25 | 26 | const char* gColorCombineSourceNames[(int)ColorCombineSource::Count] = { 27 | "COMBINED", 28 | "TEXEL0", 29 | "TEXEL1", 30 | "PRIMITIVE", 31 | "SHADE", 32 | "ENVIRONMENT", 33 | "CENTER", 34 | "SCALE", 35 | "COMBINED_ALPHA", 36 | "TEXEL0_ALPHA", 37 | "TEXEL1_ALPHA", 38 | "PRIMITIVE_ALPHA", 39 | "SHADE_ALPHA", 40 | "ENVIRONMENT_ALPHA", 41 | "LOD_FRACTION", 42 | "PRIM_LOD_FRAC", 43 | "NOISE", 44 | "K4", 45 | "K5", 46 | "1", 47 | "0", 48 | }; 49 | 50 | bool gCanUseColorCombineSource[4][(int)ColorCombineSource::Count] = { 51 | {true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, true, false, false, true, true}, 52 | {true, true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, true, false, false, true}, 53 | {true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, false, false, true, false, true}, 54 | {true, true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true}, 55 | }; 56 | 57 | bool canUseColorCombineSource(int offset, ColorCombineSource source) { 58 | return gCanUseColorCombineSource[offset][(int)source]; 59 | } 60 | 61 | 62 | const char* gAlphaCombineSourceNames[(int)AlphaCombineSource::Count] = { 63 | "COMBINED", 64 | "TEXEL0", 65 | "TEXEL1", 66 | "PRIMITIVE", 67 | "SHADE", 68 | "ENVIRONMENT", 69 | "LOD_FRACTION", 70 | "PRIM_LOD_FRAC", 71 | "1", 72 | "0", 73 | }; 74 | 75 | bool gCanUseAlphaCombineSources[4][(int)AlphaCombineSource::Count] = { 76 | {true, true, true, true, true, true, false, false, true, true}, 77 | {true, true, true, true, true, true, false, false, true, true}, 78 | {false, true, true, true, true, true, true, true, false, true}, 79 | {true, true, true, true, true, true, false, false, true, true}, 80 | }; 81 | 82 | bool canUseAlphaCombineSource(int offset, ColorCombineSource source) { 83 | return gCanUseAlphaCombineSources[offset][(int)source]; 84 | } 85 | 86 | const char* gPipelineModeNames[(int)PipelineMode::Count] = { 87 | "Unknown", 88 | "G_PM_1PRIMITIVE", 89 | "G_PM_NPRIMITIVE", 90 | }; 91 | 92 | const char* gPerspectiveModeNames[(int)PerspectiveMode::Count] = { 93 | "Unknown", 94 | "G_TP_NONE", 95 | "G_TP_PERSP", 96 | }; 97 | 98 | const char* gTextureDetailNames[(int)TextureDetail::Count] = { 99 | "Unknown", 100 | "G_TD_CLAMP", 101 | "G_TD_SHARPEN", 102 | "G_TD_DETAIL", 103 | }; 104 | 105 | const char* gTextureLODNames[] = { 106 | "Unknown", 107 | "G_TL_TILE", 108 | "G_TL_LOD", 109 | }; 110 | 111 | const char* gTextureLUTNames[] = { 112 | "Unknown", 113 | "G_TT_NONE", 114 | "G_TT_RGBA16", 115 | "G_TT_IA16", 116 | }; 117 | 118 | const char* gTextureFilterNames[] = { 119 | "Unknown", 120 | "G_TF_POINT", 121 | "G_TF_AVERAGE", 122 | "G_TF_BILERP", 123 | }; 124 | 125 | const char* gTextureConvertNames[] = { 126 | "Unknown", 127 | "G_TC_CONV", 128 | "G_TC_FILTCONV", 129 | "G_TC_FILT", 130 | }; 131 | 132 | const char* gCombineKeyNames[] = { 133 | "Unknown", 134 | "G_CK_NONE", 135 | "G_CK_KEY", 136 | }; 137 | 138 | const char* gCotherDitherNames[] = { 139 | "Unknown", 140 | "G_CD_MAGICSQ", 141 | "G_CD_BAYER", 142 | "G_CD_NOISE", 143 | "G_CD_DISABLE", 144 | }; 145 | 146 | const char* gAlphaDitherNames[] = { 147 | "Unknown", 148 | "G_AD_PATTERN", 149 | "G_AD_NOTPATTERN", 150 | "G_AD_NOISE", 151 | "G_AD_DISABLE", 152 | }; 153 | 154 | const char* gAlphaCompareNames[] = { 155 | "Unknown", 156 | "G_AC_NONE", 157 | "G_AC_THRESHOLD", 158 | "G_AC_DITHER", 159 | }; 160 | 161 | const char* gDepthSourceNames[] = { 162 | "Unknown", 163 | "G_ZS_PIXEL", 164 | "G_ZS_PRIM", 165 | }; 166 | 167 | bool gCanUseAlphaBlendSource[2][7] = { 168 | {false, false, true, true, true, false, true}, 169 | {true, true, false, false, false, true, true}, 170 | }; -------------------------------------------------------------------------------- /src/materials/MaterialEnums.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATERIAL_ENUMS_H__ 2 | #define __MATERIAL_ENUMS_H__ 3 | 4 | enum class GeometryMode { 5 | None = 0, 6 | G_ZBUFFER = (1 << 0), 7 | G_SHADE = (1 << 1), 8 | G_TEXTURE_ENABLE = (1 << 2), 9 | G_SHADING_SMOOTH = (1 << 3), 10 | G_CULL_FRONT = (1 << 4), 11 | G_CULL_BACK = (1 << 5), 12 | G_FOG = (1 << 6), 13 | G_LIGHTING = (1 << 7), 14 | G_TEXTURE_GEN = (1 << 8), 15 | G_TEXTURE_GEN_LINEAR = (1 << 9), 16 | G_LOD = (1 << 10), 17 | G_CLIPPING = (1 << 11), 18 | }; 19 | 20 | extern const char* gGeometryModeNames[]; 21 | 22 | #define GEOMETRY_MODE_COUNT 12 23 | 24 | enum class CycleType { 25 | Unknown, 26 | _1Cycle, 27 | _2Cycle, 28 | Copy, 29 | Fill, 30 | Count, 31 | }; 32 | 33 | extern const char* gCycleTypeNames[]; 34 | 35 | enum class ColorCombineSource { 36 | Combined, 37 | Texel0, 38 | Texel1, 39 | PrimitiveColor, 40 | ShadeColor, 41 | EnvironmentColor, 42 | KeyCenter, 43 | KeyScale, 44 | CombinedAlpha, 45 | Texture0Alpha, 46 | Texture1Alpha, 47 | PrimitiveAlpha, 48 | ShadedAlpha, 49 | EnvironmentAlpha, 50 | LODFraction, 51 | PrimitiveLODFraction, 52 | Noise, 53 | ConvertK4, 54 | ConvertK5, 55 | _1, 56 | _0, 57 | Count, 58 | }; 59 | 60 | extern const char* gColorCombineSourceNames[]; 61 | 62 | bool canUseColorCombineSource(int offset, ColorCombineSource source); 63 | 64 | enum class AlphaCombineSource { 65 | CombinedAlpha, 66 | Texture0Alpha, 67 | Texture1Alpha, 68 | PrimitiveAlpha, 69 | ShadedAlpha, 70 | EnvironmentAlpha, 71 | LODFraction, 72 | PrimitiveLODFraction, 73 | _1, 74 | _0, 75 | Count, 76 | }; 77 | 78 | extern const char* gAlphaCombineSourceNames[]; 79 | 80 | bool canUseAlphaCombineSource(int offset, AlphaCombineSource source); 81 | 82 | enum class PipelineMode { 83 | Unknown, 84 | _1Primitive, 85 | _NPrimitive, 86 | Count, 87 | }; 88 | 89 | extern const char* gPipelineModeNames[]; 90 | 91 | enum class PerspectiveMode { 92 | Unknown, 93 | None, 94 | Perspective, 95 | Count, 96 | }; 97 | 98 | extern const char* gPerspectiveModeNames[]; 99 | 100 | enum class TextureDetail { 101 | Unknown, 102 | Clamp, 103 | Sharpen, 104 | Detail, 105 | Count, 106 | }; 107 | 108 | extern const char* gTextureDetailNames[]; 109 | 110 | enum class TextureLOD { 111 | Unknown, 112 | Tile, 113 | LOD, 114 | Count, 115 | }; 116 | 117 | extern const char* gTextureLODNames[]; 118 | 119 | enum class TextureLUT { 120 | Unknown, 121 | None, 122 | RGBA16, 123 | IA16, 124 | Count, 125 | }; 126 | 127 | extern const char* gTextureLUTNames[]; 128 | 129 | enum class TextureFilter { 130 | Unknown, 131 | Point, 132 | Average, 133 | Bilerp, 134 | Count, 135 | }; 136 | 137 | extern const char* gTextureFilterNames[]; 138 | 139 | enum class TextureConvert { 140 | Unknown, 141 | Conv, 142 | FiltConv, 143 | Filt, 144 | Count, 145 | }; 146 | 147 | extern const char* gTextureConvertNames[]; 148 | 149 | enum class CombineKey { 150 | Unknown, 151 | None, 152 | Key, 153 | Count, 154 | }; 155 | 156 | extern const char* gCombineKeyNames[]; 157 | 158 | enum class ColorDither { 159 | Unknown, 160 | MagicSQ, 161 | Bayer, 162 | Noise, 163 | Disable, 164 | Count, 165 | }; 166 | 167 | extern const char* gCotherDitherNames[]; 168 | 169 | enum class AlphaDither { 170 | Unknown, 171 | Pattern, 172 | NotPattern, 173 | Noise, 174 | Disable, 175 | Count, 176 | }; 177 | 178 | extern const char* gAlphaDitherNames[]; 179 | 180 | enum class AlphaCompare { 181 | Unknown, 182 | None, 183 | Threshold, 184 | Dither, 185 | Count, 186 | }; 187 | 188 | extern const char* gAlphaCompareNames[]; 189 | 190 | enum class DepthSource { 191 | Unknown, 192 | Pixel, 193 | Primitive, 194 | Count, 195 | }; 196 | 197 | extern const char* gDepthSourceNames[]; 198 | 199 | #endif -------------------------------------------------------------------------------- /src/materials/MaterialParser.h: -------------------------------------------------------------------------------- 1 | #ifndef _MATERIAL_PARSER_H 2 | #define _MATERIAL_PARSER_H 3 | 4 | #include "Material.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct MaterialFile { 11 | public: 12 | std::map> mMaterials; 13 | }; 14 | 15 | struct ParseError { 16 | ParseError(const std::string& message); 17 | std::string mMessage; 18 | }; 19 | 20 | struct ParseResult { 21 | ParseResult(const std::string& insideFolder); 22 | std::string mInsideFolder; 23 | std::string mForcePallete; 24 | bool mTargetCIBuffer; 25 | MaterialFile mMaterialFile; 26 | std::vector mErrors; 27 | }; 28 | 29 | void parseMaterialFile(std::istream& input, ParseResult& output); 30 | 31 | #endif -------------------------------------------------------------------------------- /src/materials/MaterialState.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATERIAL_STATE_H__ 2 | #define __MATERIAL_STATE_H__ 3 | 4 | #include 5 | #include "TextureDefinition.h" 6 | #include "MaterialEnums.h" 7 | #include "../CFileDefinition.h" 8 | 9 | struct FlagList { 10 | FlagList(); 11 | uint64_t flags; 12 | uint64_t knownFlags; 13 | 14 | void SetFlag(int mask, bool value); 15 | void DeleteFlag(int mask); 16 | 17 | struct FlagList GetDeltaFrom(const struct FlagList& other) const; 18 | 19 | void ApplyFrom(const FlagList& other); 20 | }; 21 | 22 | struct TextureCoordinateState { 23 | public: 24 | TextureCoordinateState(); 25 | bool wrap; 26 | bool mirror; 27 | int mask; 28 | int shift; 29 | int offset; 30 | int limit; 31 | }; 32 | 33 | struct TileState { 34 | public: 35 | TileState(); 36 | 37 | bool IsTileStateEqual(const TileState& other) const; 38 | bool IsTileSizeEqual(const TileState& other) const; 39 | 40 | bool isOn; 41 | std::shared_ptr texture; 42 | G_IM_FMT format; 43 | G_IM_SIZ size; 44 | // 1 line is a 64 bit offset in TMEM 45 | int line; 46 | int tmem; 47 | int pallete; 48 | struct TextureCoordinateState sCoord; 49 | struct TextureCoordinateState tCoord; 50 | }; 51 | 52 | struct TextureState { 53 | public: 54 | TextureState(); 55 | uint16_t sc; 56 | uint16_t tc; 57 | 58 | int level; 59 | int tile; 60 | 61 | bool isOn; 62 | }; 63 | 64 | struct ColorCombineMode { 65 | ColorCombineMode(); 66 | ColorCombineMode(ColorCombineSource c0, ColorCombineSource c1, ColorCombineSource c2, ColorCombineSource c3, AlphaCombineSource a0, AlphaCombineSource a1, AlphaCombineSource a2, AlphaCombineSource a3); 67 | 68 | bool operator==(const ColorCombineMode& other) const; 69 | 70 | ColorCombineSource color[4]; 71 | AlphaCombineSource alpha[4]; 72 | }; 73 | 74 | struct RenderModeState { 75 | public: 76 | RenderModeState(); 77 | RenderModeState(int data); 78 | 79 | bool operator==(const RenderModeState& other) const; 80 | 81 | int GetZMode() const; 82 | 83 | int data; 84 | }; 85 | 86 | bool findRenderModeByName(const std::string& name, RenderModeState& output); 87 | 88 | #define MAX_TILE_COUNT 8 89 | 90 | struct MaterialState { 91 | public: 92 | MaterialState(); 93 | // state to keep track of 94 | // tiles 95 | // RDP tile cache 96 | struct TileState tiles[MAX_TILE_COUNT]; 97 | struct TextureState textureState; 98 | 99 | // geometry modes 100 | FlagList geometryModes; 101 | 102 | // G_SETOTHERMODE_H 103 | PipelineMode pipelineMode; 104 | CycleType cycleType; 105 | PerspectiveMode perspectiveMode; 106 | TextureDetail textureDetail; 107 | TextureLOD textureLOD; 108 | TextureLUT textureLUT; 109 | TextureFilter textureFilter; 110 | TextureConvert textureConvert; 111 | CombineKey combineKey; 112 | ColorDither colorDither; 113 | AlphaDither alphaDither; 114 | // G_SETOTHERMODE_L 115 | AlphaCompare alphaCompare; 116 | DepthSource depthSource; 117 | 118 | // combine mode 119 | bool hasCombineMode; 120 | ColorCombineMode cycle1Combine; 121 | ColorCombineMode cycle2Combine; 122 | 123 | bool hasRenderMode; 124 | RenderModeState cycle1RenderMode; 125 | RenderModeState cycle2RenderMode; 126 | 127 | // RDP colors 128 | bool usePrimitiveColor; 129 | PixelRGBAu8 primitiveColor; 130 | uint8_t primitiveM; 131 | uint8_t primitiveL; 132 | 133 | bool useEnvColor; 134 | PixelRGBAu8 envColor; 135 | 136 | bool useFillColor; 137 | PixelRGBAu8 fillColor; 138 | 139 | bool useFogColor; 140 | PixelRGBAu8 fogColor; 141 | 142 | bool useBlendColor; 143 | PixelRGBAu8 blendColor; 144 | 145 | bool IsTextureLoaded(std::shared_ptr texture, int tmem) const; 146 | }; 147 | 148 | void generateMaterial(CFileDefinition& fileDef, const MaterialState& from, const MaterialState& to, StructureDataChunk& output, bool targetCIBuffer); 149 | 150 | void applyMaterial(const MaterialState& from, MaterialState& to); 151 | double materialTransitionTime(const MaterialState& from, const MaterialState& to); 152 | 153 | #endif -------------------------------------------------------------------------------- /src/materials/MaterialTransitionTiming.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATERIALS_MATERIAL_TRANSITION_TIMING_H__ 2 | #define __MATERIALS_MATERIAL_TRANSITION_TIMING_H__ 3 | 4 | #define TIMING_SP_GEOMETRY_MODE 0.324 5 | #define TIMING_SP_OTHER_MODE_H 0.770 6 | #define TIMING_SP_OTHER_MODE_L 0.751 7 | #define TIMING_DP_COLOR 0.395 8 | 9 | #define TIMING_DP_TEXTURE 0.305 10 | #define TIMING_DP_TEXTURE_IMAGE 0.698 11 | #define TIMING_DP_SET_TILE 0.395 12 | #define TIMING_DP_SET_TILE_SIZE 0.394 13 | #define TIMING_DP_TILE_SYNC 0.385 14 | #define TIMING_DP_LOAD_SYNC 0.388 15 | #define TIMING_DP_PIPE_SYNC 0.388 16 | 17 | #define TIMING_DP_MATRIX_LOAD 1.880 18 | #define TIMING_DP_MATRIX_MUL 4.134 19 | #define TIMING_DP_MATRIX_POP 1.780 20 | 21 | #define TIMING_DP_LOAD_BLOCK(bytes) ((bytes) * 0.00772) 22 | 23 | #endif -------------------------------------------------------------------------------- /src/materials/MaterialTranslator.h: -------------------------------------------------------------------------------- 1 | #ifndef __MATERIAL_MATERIALTRANSLATOR_H__ 2 | #define __MATERIAL_MATERIALTRANSLATOR_H__ 3 | 4 | #include 5 | #include "./Material.h" 6 | #include "./TextureCache.h" 7 | #include "../DisplayListSettings.h" 8 | 9 | void fillMissingMaterials(TextureCache& cache, const aiScene* fromScene, DisplayListSettings& settings); 10 | 11 | #endif -------------------------------------------------------------------------------- /src/materials/RenderMode.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderMode.h" 2 | 3 | #include 4 | 5 | #define CREATE_RENDER_MODE_ENTRY(val) {std::string(#val), val} 6 | 7 | std::map gRenderModeFlags = { 8 | CREATE_RENDER_MODE_ENTRY(AA_EN), 9 | CREATE_RENDER_MODE_ENTRY(Z_CMP), 10 | CREATE_RENDER_MODE_ENTRY(Z_UPD), 11 | CREATE_RENDER_MODE_ENTRY(IM_RD), 12 | CREATE_RENDER_MODE_ENTRY(CLR_ON_CVG), 13 | 14 | CREATE_RENDER_MODE_ENTRY(CVG_X_ALPHA), 15 | CREATE_RENDER_MODE_ENTRY(ALPHA_CVG_SEL), 16 | CREATE_RENDER_MODE_ENTRY(FORCE_BL), 17 | }; 18 | 19 | std::map gCVG_DST_VALUES = { 20 | CREATE_RENDER_MODE_ENTRY(CVG_DST_CLAMP), 21 | CREATE_RENDER_MODE_ENTRY(CVG_DST_WRAP), 22 | CREATE_RENDER_MODE_ENTRY(CVG_DST_FULL), 23 | CREATE_RENDER_MODE_ENTRY(CVG_DST_SAVE), 24 | }; 25 | 26 | std::map gZMODE_VALUES = { 27 | CREATE_RENDER_MODE_ENTRY(ZMODE_OPA), 28 | CREATE_RENDER_MODE_ENTRY(ZMODE_INTER), 29 | CREATE_RENDER_MODE_ENTRY(ZMODE_XLU), 30 | CREATE_RENDER_MODE_ENTRY(ZMODE_DEC), 31 | }; 32 | 33 | void renderModeExtractFlags(int flags, std::vector& output) { 34 | for (auto& pair : gRenderModeFlags) { 35 | if (flags & pair.second) { 36 | output.push_back(pair.first); 37 | } 38 | } 39 | 40 | for (auto& pair : gCVG_DST_VALUES) { 41 | if ((flags & CVG_DST_MASK) == pair.second) { 42 | output.push_back(pair.first); 43 | break; 44 | } 45 | } 46 | 47 | for (auto& pair : gZMODE_VALUES) { 48 | if ((flags & ZMODE_MASK) == pair.second) { 49 | output.push_back(pair.first); 50 | break; 51 | } 52 | } 53 | } 54 | 55 | bool renderModeGetFlagValue(const std::string& name, int& output) { 56 | auto it = gRenderModeFlags.find(name); 57 | 58 | if (it != gRenderModeFlags.end()) { 59 | output = it->second; 60 | return true; 61 | } 62 | 63 | it = gCVG_DST_VALUES.find(name); 64 | 65 | if (it != gCVG_DST_VALUES.end()) { 66 | output = it->second; 67 | return true; 68 | } 69 | 70 | it = gZMODE_VALUES.find(name); 71 | 72 | if (it != gZMODE_VALUES.end()) { 73 | output = it->second; 74 | return true; 75 | } 76 | 77 | return false; 78 | } 79 | 80 | std::string gBlendModeNames[4][4] = { 81 | {std::string("G_BL_CLR_IN"), std::string("G_BL_CLR_MEM"), std::string("G_BL_CLR_BL"), std::string("G_BL_CLR_FOG")}, 82 | {std::string("G_BL_A_IN"), std::string("G_BL_A_FOG"), std::string("G_BL_A_SHADE"), std::string("G_BL_0")}, 83 | {std::string("G_BL_CLR_IN"), std::string("G_BL_CLR_MEM"), std::string("G_BL_CLR_BL"), std::string("G_BL_CLR_FOG")}, 84 | {std::string("G_BL_1MA"), std::string("G_BL_A_MEM"), std::string("G_BL_1"), std::string("G_BL_0")}, 85 | }; 86 | 87 | int gBlendModeShift[4] = {30, 26, 22, 18}; 88 | 89 | bool renderModeGetBlendModeValue(const std::string& name, int index, int& output) { 90 | if (index < 0 || index >= 4) { 91 | return false; 92 | } 93 | 94 | for (int i = 0; i < 4; ++i) { 95 | if (gBlendModeNames[index][i] == name) { 96 | output = i; 97 | return true; 98 | } 99 | } 100 | 101 | return false; 102 | } 103 | 104 | const std::string& renderModeGetBlendModeName(int blendMode, int index) { 105 | if (index < 0) { 106 | index = 0; 107 | } 108 | 109 | if (index >= 4) { 110 | index = 3; 111 | } 112 | 113 | int dataIndex = (blendMode >> gBlendModeShift[index]) & 0x3; 114 | return gBlendModeNames[index][dataIndex]; 115 | } -------------------------------------------------------------------------------- /src/materials/TextureCache.cpp: -------------------------------------------------------------------------------- 1 | #include "TextureCache.h" 2 | 3 | #include "../FileUtils.h" 4 | 5 | TextureCache gTextureCache; 6 | 7 | std::shared_ptr TextureCache::GetPallete(const std::string& filename) { 8 | auto check = mPalletes.find(filename); 9 | 10 | if (check != mPalletes.end()) { 11 | return check->second; 12 | } 13 | 14 | std::shared_ptr result(new PalleteDefinition(filename)); 15 | mPalletes[filename] = result; 16 | return result; 17 | } 18 | 19 | std::shared_ptr TextureCache::GetTexture(const std::string& filename, G_IM_FMT format, G_IM_SIZ size, TextureDefinitionEffect effects, const std::string& palleteFilename) { 20 | std::string normalizedPath = NormalizePath(filename) + 21 | "#" + nameForImageFormat(format) + 22 | ":" + nameForImageSize(size) + 23 | ":" + std::to_string((int)effects) + 24 | ":" + palleteFilename; 25 | 26 | auto check = mCache.find(normalizedPath); 27 | 28 | if (check != mCache.end()) { 29 | return check->second; 30 | } 31 | 32 | std::shared_ptr pallete; 33 | 34 | if (palleteFilename.length()) { 35 | pallete = GetPallete(palleteFilename); 36 | } 37 | 38 | if (pallete) { 39 | format = G_IM_FMT::G_IM_FMT_CI; 40 | 41 | if (pallete->ColorCount() <= 16) { 42 | size = G_IM_SIZ::G_IM_SIZ_4b; 43 | } else { 44 | size = G_IM_SIZ::G_IM_SIZ_8b; 45 | } 46 | } 47 | 48 | std::shared_ptr result(new TextureDefinition(filename, format, size, effects, pallete)); 49 | mCache[normalizedPath] = result; 50 | return result; 51 | } -------------------------------------------------------------------------------- /src/materials/TextureCache.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEXTURE_CACHE_H__ 2 | #define __TEXTURE_CACHE_H__ 3 | 4 | #include "TextureDefinition.h" 5 | #include 6 | #include 7 | #include 8 | 9 | class TextureCache { 10 | public: 11 | std::shared_ptr GetPallete(const std::string& filename); 12 | std::shared_ptr GetTexture(const std::string& filename, G_IM_FMT format, G_IM_SIZ size, TextureDefinitionEffect effects, const std::string& palleteFilename); 13 | private: 14 | std::map> mPalletes; 15 | std::map> mCache; 16 | }; 17 | 18 | extern TextureCache gTextureCache; 19 | 20 | #endif -------------------------------------------------------------------------------- /src/materials/TextureDefinition.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEXTURE_DEFINITION_H__ 2 | #define __TEXTURE_DEFINITION_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "TextureFormats.h" 9 | 10 | #include "../definitions/DataChunk.h" 11 | #include "../definitions/FileDefinition.h" 12 | 13 | class CImgu8; 14 | 15 | class DataChunkStream { 16 | public: 17 | DataChunkStream(); 18 | void WriteBytes(const char* data, int byteCount); 19 | void WriteBits(int from, int bitCount); 20 | 21 | const std::vector& GetData(); 22 | private: 23 | void FlushBuffer(); 24 | 25 | int mCurrentBufferPos; 26 | uint64_t mCurrentBuffer; 27 | std::vector mData; 28 | }; 29 | 30 | struct PixelRGBAu8 { 31 | PixelRGBAu8(); 32 | PixelRGBAu8(uint8_t rVal, uint8_t gVal, uint8_t bVal, uint8_t aVal); 33 | 34 | bool operator==(const PixelRGBAu8& other) const; 35 | 36 | uint8_t r; 37 | uint8_t g; 38 | uint8_t b; 39 | uint8_t a; 40 | 41 | bool WriteToStream(DataChunkStream& output, G_IM_SIZ size); 42 | }; 43 | 44 | struct PixelIu8 { 45 | PixelIu8(uint8_t i); 46 | uint8_t i; 47 | 48 | bool WriteToStream(DataChunkStream& output, G_IM_SIZ size); 49 | }; 50 | 51 | struct PixelIAu8 { 52 | PixelIAu8(uint8_t i, uint8_t a); 53 | uint8_t i; 54 | uint8_t a; 55 | 56 | bool WriteToStream(DataChunkStream& output, G_IM_SIZ size); 57 | }; 58 | 59 | enum class TextureDefinitionEffect { 60 | TwoToneGrayscale = (1 << 0), 61 | NormalMap = (1 << 1), 62 | Invert = (1 << 2), 63 | SelectR = (1 << 3), 64 | SelectG = (1 << 4), 65 | SelectB = (1 << 5), 66 | }; 67 | 68 | class PalleteDefinition { 69 | public: 70 | PalleteDefinition(const std::string& filename); 71 | 72 | PixelIu8 FindIndex(PixelRGBAu8 color) const; 73 | 74 | std::unique_ptr GenerateDefinition(const std::string& name, const std::string& location) const; 75 | 76 | const std::string& Name() const; 77 | 78 | int LoadBlockSize() const; 79 | int DTX() const; 80 | int NBytes() const; 81 | unsigned ColorCount() const; 82 | private: 83 | std::string mName; 84 | std::vector mColors; 85 | std::vector mData; 86 | }; 87 | 88 | class TextureDefinition { 89 | public: 90 | TextureDefinition(const std::string& filename, G_IM_FMT fmt, G_IM_SIZ siz, TextureDefinitionEffect effects, std::shared_ptr pallete); 91 | ~TextureDefinition(); 92 | 93 | static void DetermineIdealFormat(const std::string& filename, G_IM_FMT& fmt, G_IM_SIZ& siz); 94 | 95 | std::unique_ptr GenerateDefinition(const std::string& name, const std::string& location) const; 96 | 97 | int Width() const; 98 | int Height() const; 99 | 100 | G_IM_FMT Format() const; 101 | G_IM_SIZ Size() const; 102 | 103 | bool GetLine(int& line) const; 104 | bool GetLineForTile(int& line) const; 105 | int LoadBlockSize() const; 106 | int DTX() const; 107 | int NBytes() const; 108 | 109 | const std::vector& GetData() const; 110 | 111 | const std::string& Name() const; 112 | 113 | bool HasEffect(TextureDefinitionEffect effect) const; 114 | 115 | PixelRGBAu8 GetTwoToneMin() const; 116 | PixelRGBAu8 GetTwoToneMax() const; 117 | 118 | std::shared_ptr GetPallete() const; 119 | 120 | std::shared_ptr Crop(int x, int y, int w, int h) const; 121 | std::shared_ptr Resize(int w, int h) const; 122 | private: 123 | TextureDefinition( 124 | CImgu8* mImg, 125 | const std::string& name, 126 | G_IM_FMT fmt, 127 | G_IM_SIZ siz, 128 | std::shared_ptr pallete, 129 | TextureDefinitionEffect effects 130 | ); 131 | 132 | CImgu8* mImg; 133 | std::string mName; 134 | G_IM_FMT mFmt; 135 | G_IM_SIZ mSiz; 136 | int mWidth; 137 | int mHeight; 138 | std::vector mData; 139 | std::shared_ptr mPallete; 140 | TextureDefinitionEffect mEffects; 141 | 142 | PixelRGBAu8 mTwoToneMin; 143 | PixelRGBAu8 mTwoToneMax; 144 | }; 145 | 146 | #endif -------------------------------------------------------------------------------- /src/materials/TextureFormats.cpp: -------------------------------------------------------------------------------- 1 | #include "TextureFormats.h" 2 | 3 | const char* G_IM_FMT_NAMES[] = { 4 | "G_IM_FMT_RGBA", 5 | "G_IM_FMT_YUV", 6 | "G_IM_FMT_CI", 7 | "G_IM_FMT_I", 8 | "G_IM_FMT_IA", 9 | }; 10 | 11 | const char* nameForImageFormat(G_IM_FMT format) { 12 | return G_IM_FMT_NAMES[(int)format]; 13 | } 14 | 15 | const char* G_IM_SIZ_NAMES[] = { 16 | "G_IM_SIZ_4b", 17 | "G_IM_SIZ_8b", 18 | "G_IM_SIZ_16b", 19 | "G_IM_SIZ_32b", 20 | }; 21 | 22 | const char* nameForImageSize(G_IM_SIZ size) { 23 | return G_IM_SIZ_NAMES[(int)size]; 24 | } 25 | 26 | bool G_IM_SUPPORTED[5][4] = { 27 | {false, false, true, true}, 28 | {false, false, true, false}, 29 | {true, true, false, false}, 30 | {true, true, false, false}, 31 | {true, true, true, false}, 32 | }; 33 | 34 | bool isImageFormatSupported(G_IM_FMT format, G_IM_SIZ size) { 35 | return G_IM_SUPPORTED[(int)format][(int)size]; 36 | } 37 | 38 | const int G_IM_SIZ_SIZES[] = { 39 | 4, 40 | 8, 41 | 16, 42 | 32, 43 | }; 44 | 45 | int bitSizeforSiz(G_IM_SIZ input) { 46 | return G_IM_SIZ_SIZES[(int)input]; 47 | } 48 | 49 | const int G_IM_SIZ_LINE_BYTES[] = { 50 | 4, 51 | 8, 52 | 16, 53 | 16, 54 | }; 55 | 56 | int lineSizeForSize(G_IM_SIZ input) { 57 | return G_IM_SIZ_LINE_BYTES[(int)input]; 58 | } -------------------------------------------------------------------------------- /src/materials/TextureFormats.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEXTURE_FORMATS_H__ 2 | #define __TEXTURE_FORMATS_H__ 3 | 4 | enum class G_IM_FMT { 5 | G_IM_FMT_RGBA, 6 | G_IM_FMT_YUV, 7 | G_IM_FMT_CI, 8 | G_IM_FMT_I, 9 | G_IM_FMT_IA, 10 | }; 11 | 12 | const char* nameForImageFormat(G_IM_FMT format); 13 | 14 | enum class G_IM_SIZ { 15 | G_IM_SIZ_4b, 16 | G_IM_SIZ_8b, 17 | G_IM_SIZ_16b, 18 | G_IM_SIZ_32b, 19 | }; 20 | 21 | const char* nameForImageSize(G_IM_SIZ size); 22 | 23 | bool isImageFormatSupported(G_IM_FMT format, G_IM_SIZ size); 24 | 25 | int bitSizeforSiz(G_IM_SIZ input); 26 | int lineSizeForSize(G_IM_SIZ input); 27 | 28 | #endif -------------------------------------------------------------------------------- /src/math/LeastSquares.cpp: -------------------------------------------------------------------------------- 1 | #include "LeastSquares.h" 2 | 3 | #include 4 | 5 | LinearLeastSquares::LinearLeastSquares() : 6 | mXSum(0.0), 7 | mYSum(0.0), 8 | mXYSum(0.0), 9 | mXXSum(0.0), 10 | mCount(0.0), 11 | mIsDirty(false), 12 | mSlope(0.0), 13 | mYIntercept(0.0) { 14 | 15 | } 16 | 17 | void LinearLeastSquares::AddDataPoint(double x, double y) { 18 | mXSum += x; 19 | mYSum += y; 20 | mXYSum += x * y; 21 | mXXSum += x * x; 22 | mCount += 1.0; 23 | mIsDirty = true; 24 | } 25 | 26 | void LinearLeastSquares::Calculate() { 27 | if (!mIsDirty) { 28 | return; 29 | } 30 | 31 | mIsDirty = false; 32 | 33 | double denom = mCount * mXXSum - mXSum * mXSum; 34 | 35 | if (fabs(denom) < 0.00000001) { 36 | mSlope = 0.0f; 37 | } else { 38 | mSlope = (mCount * mXYSum - mXSum * mYSum) / denom; 39 | } 40 | 41 | mYIntercept = (mYSum - mSlope * mXSum) / mCount; 42 | } 43 | 44 | double LinearLeastSquares::PredictY(double x) { 45 | Calculate(); 46 | return mYIntercept + mSlope * x; 47 | } -------------------------------------------------------------------------------- /src/math/LeastSquares.h: -------------------------------------------------------------------------------- 1 | #ifndef __LEAST_SQUARES_H__ 2 | #define __LEAST_SQUARES_H__ 3 | 4 | class LinearLeastSquares { 5 | public: 6 | LinearLeastSquares(); 7 | void AddDataPoint(double x, double y); 8 | void Calculate(); 9 | double PredictY(double x); 10 | private: 11 | double mXSum; 12 | double mYSum; 13 | double mXYSum; 14 | double mXXSum; 15 | double mCount; 16 | 17 | bool mIsDirty; 18 | double mSlope; 19 | double mYIntercept; 20 | }; 21 | 22 | #endif -------------------------------------------------------------------------------- /src/math/MES.cpp: -------------------------------------------------------------------------------- 1 | #include "MES.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "Vector4.h" 8 | #include 9 | 10 | Sphere::Sphere() : radius(0.0f) {} 11 | 12 | Sphere::Sphere(const aiVector3D& center, float radius): center(center), radius(radius) {} 13 | 14 | bool Sphere::Contains(const aiVector3D& point) { 15 | return (point - center).SquareLength() <= radius * radius * 1.001f; 16 | } 17 | 18 | struct Sphere miniumEnclosingSphereTwoPoints(const aiVector3D& a, const aiVector3D& b) { 19 | return Sphere((a + b) * 0.5f, (a - b).Length() * 0.5); 20 | } 21 | 22 | bool miniumEnclosingSphereThreePoints(const aiVector3D& a, const aiVector3D& b, const aiVector3D& c, Sphere& output) { 23 | aiMatrix4x4 coef; 24 | 25 | aiVector3D edgeA = a - c; 26 | aiVector3D edgeB = b - c; 27 | 28 | aiVector3D normal = edgeA ^ edgeB; 29 | 30 | if (normal.SquareLength() < 0.00001f) { 31 | return false; 32 | } 33 | 34 | aiVector3D top = ((edgeB * edgeA.SquareLength()) - (edgeA * edgeB.SquareLength())) ^ normal; 35 | float bottom = 0.5f / normal.SquareLength(); 36 | aiVector3D center = top * bottom; 37 | 38 | output.center = c + center; 39 | output.radius = center.Length(); 40 | 41 | return true; 42 | } 43 | 44 | bool miniumEnclosingSphereFourPoints(const aiVector3D& a, const aiVector3D& b, const aiVector3D& c,const aiVector3D& d, Sphere& output) { 45 | 46 | aiVector3D edge1 = b - a; 47 | aiVector3D edge2 = c - a; 48 | aiVector3D edge3 = d - a; 49 | 50 | float sqLength1 = edge1.SquareLength(); 51 | float sqLength2 = edge2.SquareLength(); 52 | float sqLength3 = edge3.SquareLength(); 53 | 54 | float determinant = edge1.x * (edge2.y * edge3.z - edge3.y * edge2.z) 55 | - edge2.x * (edge1.y * edge3.z - edge3.y * edge1.z) 56 | + edge3.x * (edge1.y * edge2.z - edge2.y * edge1.z); 57 | 58 | if (fabs(determinant) < 0.000001f) { 59 | return false; 60 | } 61 | 62 | float scalar = 0.5f / determinant; 63 | 64 | aiVector3D offset( 65 | scalar * ((edge2.y * edge3.z - edge3.y * edge2.z) * sqLength1 - (edge1.y * edge3.z - edge3.y * edge1.z) * sqLength2 + (edge1.y * edge2.z - edge2.y * edge1.z) * sqLength3), 66 | scalar * (-(edge2.x * edge3.z - edge3.x * edge2.z) * sqLength1 + (edge1.x * edge3.z - edge3.x * edge1.z) * sqLength2 - (edge1.x * edge2.z - edge2.x * edge1.z) * sqLength3), 67 | scalar * ((edge2.x * edge3.y - edge3.x * edge2.y) * sqLength1 - (edge1.x * edge3.y - edge3.x * edge1.y) * sqLength2 + (edge1.x * edge2.y - edge2.x * edge1.y) * sqLength3) 68 | ); 69 | 70 | output.center = a + offset; 71 | output.radius = offset.Length(); 72 | 73 | return true; 74 | } 75 | 76 | struct Sphere miniumEnclosingSphereTrivial(const std::vector& points) { 77 | if (points.size() > 4) { 78 | // degenerate case 79 | return Sphere(aiVector3D(0.0f, 0.0f, 0.0f), 0.0f); 80 | } 81 | 82 | if (points.size() == 0) { 83 | return Sphere(aiVector3D(0.0f, 0.0f, 0.0f), 0.0f); 84 | } 85 | 86 | if (points.size() == 1) { 87 | return Sphere(points[0], 0.0f); 88 | } 89 | 90 | if (points.size() == 2) { 91 | return miniumEnclosingSphereTwoPoints(points[0], points[1]); 92 | } 93 | 94 | // see if two points is sufficient 95 | for (unsigned i = 0; i < points.size(); ++i) { 96 | for (unsigned j = i + 1; j < points.size(); ++j) { 97 | Sphere test = miniumEnclosingSphereTwoPoints(points[i], points[j]); 98 | 99 | unsigned otherIndex; 100 | 101 | for (otherIndex = 0; otherIndex < points.size(); ++otherIndex) { 102 | if (otherIndex == i || otherIndex == j) { 103 | continue; 104 | } 105 | 106 | if (!test.Contains(points[otherIndex])) { 107 | break; 108 | } 109 | } 110 | 111 | if (otherIndex == points.size()) { 112 | return test; 113 | } 114 | } 115 | } 116 | 117 | if (points.size() == 3) { 118 | Sphere result; 119 | 120 | if (miniumEnclosingSphereThreePoints(points[0], points[1], points[2], result)) { 121 | return result; 122 | } else { 123 | return miniumEnclosingSphereTwoPoints(points[0], points[1]); 124 | } 125 | } 126 | 127 | // see if 3 points are sufficent 128 | for (unsigned i = 0; i < 4; ++i) { 129 | Sphere result; 130 | 131 | if (miniumEnclosingSphereThreePoints(points[i == 0 ? 1 : 0], points[i <= 1 ? 2 : 1], points[i <= 2 ? 3 : 2], result) && result.Contains(points[i])) { 132 | return result; 133 | } 134 | } 135 | 136 | Sphere result; 137 | if (miniumEnclosingSphereFourPoints(points[0], points[1], points[2], points[3], result)) { 138 | return result; 139 | } 140 | 141 | return Sphere(aiVector3D(0.0f, 0.0f, 0.0f), 0.0f); 142 | } 143 | 144 | struct Sphere minimumEnclosingSphereMutateInput(std::vector& input) { 145 | std::shuffle(input.begin(), input.end(), std::default_random_engine(rand())); 146 | std::set edgeIndices; 147 | Sphere currentSphere; 148 | 149 | unsigned pointIndex = 0; 150 | 151 | while (pointIndex < input.size()) { 152 | if (edgeIndices.find(pointIndex) != edgeIndices.end() || currentSphere.Contains(input[pointIndex])) { 153 | ++pointIndex; 154 | } else { 155 | std::set setCopy; 156 | std::vector edgePoints; 157 | 158 | for (auto current : edgeIndices) { 159 | if (current > pointIndex) { 160 | setCopy.insert(current); 161 | edgePoints.push_back(input[current]); 162 | } 163 | } 164 | 165 | edgeIndices = setCopy; 166 | edgeIndices.insert(pointIndex); 167 | edgePoints.push_back(input[pointIndex]); 168 | 169 | currentSphere = miniumEnclosingSphereTrivial(edgePoints); 170 | 171 | if (edgePoints.size() > 1 && currentSphere.radius == 0.0f) { 172 | miniumEnclosingSphereTrivial(edgePoints); 173 | std::cout << "something wrong" << std::endl; 174 | } 175 | 176 | if (edgeIndices.size() < 4) { 177 | pointIndex = 0; 178 | } else { 179 | pointIndex = pointIndex + 1; 180 | } 181 | } 182 | } 183 | 184 | return currentSphere; 185 | } 186 | 187 | struct Sphere minimumEnclosingSphereForMeshes(const std::vector& input) { 188 | std::vector allPoints; 189 | 190 | for (auto mesh : input) { 191 | allPoints.insert(allPoints.end(), mesh->mVertices, mesh->mVertices + mesh->mNumVertices); 192 | } 193 | 194 | return minimumEnclosingSphereMutateInput(allPoints); 195 | } 196 | 197 | struct Sphere minimumEnclosingSphere(const std::vector& input) { 198 | std::vector copy = input; 199 | return minimumEnclosingSphereMutateInput(copy); 200 | } -------------------------------------------------------------------------------- /src/math/MES.h: -------------------------------------------------------------------------------- 1 | #ifndef __MES_H__ 2 | #define __MES_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct Sphere { 9 | Sphere(); 10 | Sphere(const aiVector3D& center, float radius); 11 | 12 | aiVector3D center; 13 | float radius; 14 | 15 | bool Contains(const aiVector3D& point); 16 | }; 17 | 18 | Sphere minimumEnclosingSphere(const std::vector& input); 19 | Sphere minimumEnclosingSphereForMeshes(const std::vector& input); 20 | 21 | #endif -------------------------------------------------------------------------------- /src/math/Vector4.cpp: -------------------------------------------------------------------------------- 1 | #include "Vector4.h" 2 | 3 | Vector4::Vector4(): x(0.0f), y(0.0f), z(0.0f), w(0.0f) {} 4 | Vector4::Vector4(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {} 5 | 6 | Vector4 operator * (const aiMatrix4x4& matrix, const Vector4& vector) { 7 | return Vector4( 8 | matrix.a1 * vector.x + matrix.a2 * vector.y + matrix.a3 * vector.z + matrix.a4 * vector.w, 9 | matrix.b1 * vector.x + matrix.b2 * vector.y + matrix.b3 * vector.z + matrix.b4 * vector.w, 10 | matrix.c1 * vector.x + matrix.c2 * vector.y + matrix.c3 * vector.z + matrix.c4 * vector.w, 11 | matrix.d1 * vector.x + matrix.d2 * vector.y + matrix.d3 * vector.z + matrix.d4 * vector.w 12 | ); 13 | } -------------------------------------------------------------------------------- /src/math/Vector4.h: -------------------------------------------------------------------------------- 1 | #ifndef __VECTOR4_H__ 2 | #define __VECTOR4_H__ 3 | 4 | #include 5 | 6 | struct Vector4 { 7 | Vector4(); 8 | Vector4(float x, float y, float z, float w); 9 | float x; 10 | float y; 11 | float z; 12 | float w; 13 | }; 14 | 15 | Vector4 operator * (const aiMatrix4x4& matrix, const Vector4& vector); 16 | 17 | #endif --------------------------------------------------------------------------------