/*
League of Legends Custom Skin Tool-Kit
by Jahrain
This is a simple tool that can be used to compile and decompile .skn and .skl files
in order to create custom skin models for League of Legends
*/
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
using namespace std;
struct Header {
//Structure for header on skl files
char fileType[8];
int numObjects;
int skeletonHash;
int numElements;
};
struct Bone {
//Structure for a bone in skl files
char name[32];
int parent;
float scale;
float matrix[3][4];
};
struct SkinModelHeader {
//Structure for the Header in skn files
int magic;
short numMaterials;
short numObjects;
};
struct SkinModelMaterial {
//Structure for a material block in skn files
int matIndex;
char name[64];
int startVertex;
int numVertices;
int startIndex;
int numIndices;
};
struct SkinModelVertex {
//Vertex block in skn files
float position[3];
char boneIndex[4];
float weights[4];
float normal[3];
float texcoords[2];
};
struct SkinModelData {
//data block in skn files
int numIndices;
int numVertices;
vector<short> indices;
vector<SkinModelVertex> verteces;
};
struct SkinModel {
//Skin model data structure
SkinModelHeader header;
vector<SkinModelMaterial> materials;
SkinModelData modelData;
void exportObj(string fileName) {
//exports this skin model as a .obj file
ofstream fout(fileName.c_str());
for (int i = 0; i < modelData.verteces.size(); i++) {
fout << "v " << modelData.verteces[i].position[0] << " " << modelData.verteces[i].position[1] << " " << modelData.verteces[i].position[2] << endl;
fout << "vn " << modelData.verteces[i].normal[0] << " " << modelData.verteces[i].normal[1] << " " << modelData.verteces[i].normal[2] << endl;
fout << "vt " << modelData.verteces[i].texcoords[0] << " " << 1-modelData.verteces[i].texcoords[1] << endl;
}
if (materials.size()) {
fout << "g mat_" << materials[0].name << endl;
}
for (int i = 0; i < modelData.numIndices/3; i++) {
int a = modelData.indices[i*3] + 1;
int b = modelData.indices[i*3 + 1] + 1;
int c = modelData.indices[i*3 + 2] + 1;
fout << "f " << a << '/' << a << '/' << a << " " << b << '/' << b << '/' << b << " " << c << '/' << c << '/' << c << endl;
}
}
void exportSkn(string fileName) {
//export this SkinModel as .skn which can be used by league of legends
ofstream fout;
fout.open(fileName.c_str(), ios::binary);
fout.write((char*)(void*)&header,sizeof(SkinModelHeader));
for (int i = 0; i < header.numMaterials; i++) {
fout.write((char*)(void*)&materials[i], sizeof(SkinModelMaterial));
}
fout.write((char*)(void*)&modelData.numIndices,4);
fout.write((char*)(void*)&modelData.numVertices,4);
for (int i = 0; i < modelData.numIndices; i++) {
fout.write((char*)(void*)&modelData.indices[i], 2);
}
for (int i = 0; i < modelData.numVertices; i++) {
fout.write((char*)(void*)&modelData.verteces[i],sizeof(SkinModelVertex));
}
}
void importSkn(string infile) {
//import from .skn file
ifstream fin;
fin.open(infile.c_str(), ios::binary);
if (fin.fail()) {
cout << "ERROR: could not open " << infile << endl;
exit(1);
}
fin.read((char*)(void*)&header,sizeof(SkinModelHeader));
for (int i = 0; i < header.numMaterials; i++) {
SkinModelMaterial mat;
fin.read((char*)(void*)&mat, sizeof(SkinModelMaterial));
materials.push_back(mat);
}
fin.read((char*)(void*)&modelData.numIndices,4);
fin.read((char*)(void*)&modelData.numVertices,4);
for (int i = 0; i < modelData.numIndices; i++) {
short idx;
fin.read((char*)(void*)&idx, 2);
modelData.indices.push_back(idx);
}
for (int i = 0; i < modelData.numVertices; i++) {
SkinModelVertex vtx;
fin.read((char*)(void*)&vtx,sizeof(SkinModelVertex));
modelData.verteces.push_back(vtx);
}
}
void importMesh(string infile) {
//import from ASCII mesh output from Maya Script
//cout << "Compiling skin file: " << infile << " to binary file: " << outfile << endl;
ifstream fin(infile.c_str());
if (fin.fail()) {
cout << "ERROR: could not open " << infile << endl;
exit(1);
}
int numVerts;
fin >> numVerts;
modelData.numVertices = numVerts;
for (int i = 0; i < numVerts; i++) {
SkinModelVertex vtx;
fin >> vtx.position[0] >> vtx.position[1] >> vtx.position[2];
for (int j = 0; j < 3; j++) {
int boneIdx = 0;
string boneIdxStr;
fin >> boneIdxStr;
if (boneIdxStr != "#NULL") {
string tmp;
for (int k = boneIdxStr.length() - 1; k >= 0; k--) {
if (boneIdxStr[k] == '_') {
boneIdxStr[k] = ' ';
break;
}
}
}
char name[32];
sscanf(boneIdxStr.c_str(), "%s %d",name,&boneIdx);
vtx.boneIndex[j] = boneIdx;
}
vtx.boneIndex[3] = 0;
fin >> vtx.weights[0] >> vtx.weights[1] >> vtx.weights[2];
vtx.weights[3] = 0;
//normalize weights
float weightSum = vtx.weights[0] + vtx.weights[1] + vtx.weights[2];
vtx.weights[0] *= 1.0f/weightSum;
vtx.weights[1] *= 1.0f/weightSum;
vtx.weights[2] *= 1.0f/weightSum;
fin >> vtx.normal[0] >> vtx.normal[1] >> vtx.normal[2];
fin >> vtx.texcoords[0] >> vtx.texcoords[1];
vtx.texcoords[1] = 1 - vtx.texcoords[1]; //flip the UVs
modelData.verteces.push_back(vtx);
}
SkinModelMaterial mat;
memset((void*)&mat,0,sizeof(SkinModelMaterial));
fin >> mat.name;
int numFaces;
fin >> numFaces;
string nameStr = string(mat.name);
if (nameStr != "lambert1") {
cout << "NOTE: The material name is " << nameStr << ". Make sure this matches the same material as the original skin file!!!" << endl;
header.numMaterials = 1;
mat.matIndex = 1;
mat.numIndices = numFaces*3;
mat.numVertices = numVerts;
mat.startIndex = 0;
mat.startVertex = 0;
materials.push_back(mat);
} else {
cout << "WARNING: The default material was used because this model used the default material lambert1. Only do this if the original .skn file has no materials." << endl;
header.numMaterials = 0;
}
header.magic = 1122867;
header.numObjects = 1;
modelData.numIndices = numFaces*3;
for (int i = 0; i < numFaces; i++) {
for (int j = 0; j < 3; j++) {
short face;
fin >> face;
modelData.indices.push_back(face);
}
}
}
};
void dumpSkeleton(string infile, string outfile) {
//dump out the contents of a .skl file as ASCII for importing into Maya or some other 3d Application.
ifstream fin;
fin.open(infile.c_str(), ios::binary);
if (fin.fail()) {
cout << "ERROR: could not open " << infile << endl;
exit(1);
}
ofstream fout(outfile.c_str());
Header header;
fin.read((char*)(void*)&header, sizeof(header));
cout << "Found " << header.numElements << " bones" << endl;
fout << header.fileType << endl;
fout << header.numObjects << endl;
fout << header.skeletonHash << endl;
fout << header.numElements << endl;
for (int i = 0; i < header.numElements; i++) {
Bone bone;
fin.read((char*)(void*)&bone, sizeof(Bone));
fout << bone.name << endl;
fout << bone.parent << endl;
fout << bone.scale << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
fout << bone.matrix[i][j] << " ";
}
fout << endl;
}
}
}
void compileSkeleton(string infile, string outfile) {
//Compile the ASCII skeleton file back into a .skl file
ifstream fin;
fin.open(infile.c_str());
if (fin.fail()) {
cout << "ERROR: could not open " << infile << endl;
exit(1);
}
ofstream fout;
fout.open(outfile.c_str(), ios::binary);
Header header;
fin >> header.fileType;
fin >> header.numObjects;
fin >> header.skeletonHash;
fin >> header.numElements;
fout.write((const char*)&header,sizeof(Header));
for (int i = 0; i < header.numElements; i++) {
Bone bone;
memset(bone.name,0,32);
fin >> bone.name;
fin >> bone.parent;
fin >> bone.scale;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
fin >> bone.matrix[i][j];
}
}
fout.write((const char*)&bone, sizeof(Bone));
}
}
int main(int argc, char *argv[]) {
if (argc != 5) {
cout << "Usage: lolskintool <command> <type> <inputFile> <outputFile>" << endl;
cout << "Valid commands are: c (compile), d (decompile)" << endl;
cout << "Supported types are: skl (skeleton), skn (skin)" << endl;
return 2;
}
string cmd = string(argv[1]);
string type = string(argv[2]);
string inputFile = string(argv[3]);
string outputFile = string(argv[4]);
if (cmd == "compile" || cmd == "c") {
if (type == "skl" || type == "skeleton") {
cout << "Compiling ASCII skeleton file: " << inputFile << " to binary .skl file: " << outputFile << endl;
compileSkeleton(inputFile, outputFile);
cout << "Done!" << endl;
} else if (type == "skn" || type == "skin") {
SkinModel model;
cout << "Compiling ASCII skin mesh file: " << inputFile << " to binary .skn file: " << outputFile << endl;
model.importMesh(inputFile);
model.exportSkn(outputFile);
cout << "Done!" << endl;
} else {
cout << "Unsupported file type" << endl;
return 2;
}
} else if (cmd == "decompile" || cmd == "d") {
if (type == "skl" || type == "skeleton") {
cout << "Decompiling binary .skl file: " << inputFile << " to ASCII file: " << outputFile << endl;
dumpSkeleton(inputFile, outputFile);
cout << "Done!" << endl;
} else if (type == "skn" || type == "skin") {
cout << "Decompiling binary .skn file: " << inputFile << " to .obj file: " << outputFile << endl;
SkinModel model;
model.importSkn(inputFile);
model.exportObj(outputFile);
cout << "Done!" << endl;
} else {
cout << "Unsupported file type" << endl;
return 2;
}
} else {
cout << "Unsupported command" << endl;
return 2;
}
return 0;
}
转载于:https://my.oschina.net/lyr/blog/128006