VIF packet creator for Kingdom Hearts II models
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

345 lines
12 KiB

#include <fstream>
#include <iostream>
#include <limits>
#include <math.h>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <vector>
int max(int x, int y, int z) {
int flagx = x;
if (y > flagx) {
flagx = y;
}
if (z > flagx) {
flagx = z;
}
return flagx;
}
void help() { printf("Usage: kh2vif model.obj\n"); }
int main(int argc, char *argv[]) {
// max uv buffer, should be enough for an entire set of obj vertices
int uvs[8192];
int uv_count = 0;
int vertex_count = 0;
int face_count = 0;
int vertices_arg = 0;
int vertex_affiliation = 0;
int junk = 0;
int map = 0;
char *objname = argv[1];
printf("kh2vif\n-- If you don't know what a VIF packet be prepared to be "
"driven to insanity\n\n");
if (argc < 2) {
help();
return -1;
}
if ((strcmp(objname, "-m") == 0) || (strcmp(objname, "--map") == 0)) {
printf("\nSwitching to map mode\n");
map = 1;
objname = argv[2];
}
if (access(objname, F_OK) == -1) {
help();
return -1;
}
std::ifstream input(objname, std::ios::in);
std::string dsmname =
std::string(objname).substr(0, std::string(objname).find_last_of('.')) +
".dsm";
std::string kh2vname =
std::string(objname).substr(0, std::string(objname).find_last_of('.')) +
".kh2v";
std::ofstream dsm(dsmname);
std::string line;
std::vector<std::string> dsm_mem;
std::vector<int> bones;
dsm_mem.push_back(".align 0");
line = ";";
line += objname;
dsm_mem.push_back(line);
dsm_mem.push_back(";Automatically generated by kh2vif");
dsm_mem.push_back(";DO NOT EDIT IF YOU DON'T KNOW WHAT YOU ARE DOING");
dsm_mem.push_back("");
dsm_mem.push_back(
"stcycl 01, 01; We write code to memory without skips/overwrite");
dsm_mem.push_back("");
dsm_mem.push_back("unpack[r] V4_32, 0, * ;Model Part Header");
if (map) {
dsm_mem.push_back(".int 0, 0, 0, 0 ;type 0 Model");
} else {
dsm_mem.push_back(".int 1, 0, 0, 0 ;type 1 Model");
}
// 3 MPHeader lines we will fix at the end, Vector is 11 here
int tmpheader = dsm_mem.size();
dsm_mem.push_back("");
dsm_mem.push_back("");
dsm_mem.push_back("");
dsm_mem.push_back(".EndUnpack");
dsm_mem.push_back("");
dsm_mem.push_back(
"stcycl 01, 01; We write code to memory without skips/overwrite");
dsm_mem.push_back("");
dsm_mem.push_back("unpack[r] V2_16, 4, *; UV definition");
if (dsm.is_open()) {
while (getline(input, line)) {
if (line.substr(0, 2) == "v ") {
vertex_count++;
}
}
input.clear();
input.seekg(0, std::ios::beg);
while (getline(input, line)) {
if (line.substr(0, 2) == "f ") {
face_count++;
}
}
input.clear();
input.seekg(0, std::ios::beg);
while (getline(input, line)) {
if (line.substr(0, 3) == "vt ") {
std::istringstream s(line.substr(3));
float u, v;
s >> u;
s >> v;
printf("tx= %f, ty= %f, txr= %d, tyr=%d\n", u, v,
int(round(u * 4095)), int(round(v * 4095)));
uvs[uv_count] = int(round(u * 4095));
uvs[uv_count + 1] = int(round(v * 4095));
uv_count += 2;
}
}
input.clear();
input.seekg(0, std::ios::beg);
while (getline(input, line)) {
if (line.substr(0, 3) == "vb ") {
std::istringstream s(line.substr(2));
int v;
s >> v;
bones.push_back(v);
printf("bone= %d\n", v);
}
}
if (bones.size() == 0) {
bones.push_back(vertex_count);
}
input.clear();
input.seekg(0, std::ios::beg);
// making temporary entries for uvs to insert later on
int uv_pos = dsm_mem.size();
for (int i = 0; i < face_count; i++) {
dsm_mem.push_back("");
dsm_mem.push_back("");
dsm_mem.push_back("");
}
dsm_mem.push_back(".EndUnpack");
dsm_mem.push_back("");
dsm_mem.push_back(
"stmask 0xcfcfcfcf; Sets mask register(3303, check EEUSER_E)");
dsm_mem.push_back(
"stcycl 01, 01; We write code to memory without skips/overwrite");
dsm_mem.push_back("");
dsm_mem.push_back("unpack[mru] S_8, 4, *; Vertex indices");
while (getline(input, line)) {
if (line.substr(0, 2) == "f ") {
std::istringstream s(line.substr(2));
std::string i, n, u;
int ii, inn, iu;
s >> i;
s >> n;
s >> u;
ii = std::stoi(i.substr(0, i.find("/")));
inn = std::stoi(n.substr(0, n.find("/")));
iu = std::stoi(u.substr(0, u.find("/")));
// printf("i1: %d i2: %d i3: %d\n", ii, inn, iu);
line = ".byte " + std::to_string(ii - 1);
dsm_mem.push_back(line);
line = ".short " + std::to_string(uvs[(ii - 1) * 2]) + ", " +
std::to_string(uvs[((ii - 1) * 2) + 1]);
dsm_mem[uv_pos] = line;
uv_pos++;
line = ".byte " + std::to_string(inn - 1);
dsm_mem.push_back(line);
line = ".short " + std::to_string(uvs[(inn - 1) * 2]) + ", " +
std::to_string(uvs[((inn - 1) * 2) + 1]);
dsm_mem[uv_pos] = line;
uv_pos++;
line = ".byte " + std::to_string(iu - 1);
dsm_mem.push_back(line);
line = ".short " + std::to_string(uvs[(iu - 1) * 2]) + ", " +
std::to_string(uvs[((iu - 1) * 2) + 1]);
dsm_mem[uv_pos] = line;
uv_pos++;
// printf("bis i1: %d i2: %d i3: %d\n", (ii-1)*2, (inn-1)*2,
// (iu-1)*2);
}
}
input.clear();
input.seekg(0, std::ios::beg);
dsm_mem.push_back(".EndUnpack");
dsm_mem.push_back("");
dsm_mem.push_back(
"stmask 0x3f3f3f3f; Sets mask register(3330, check EEUSER_E)");
dsm_mem.push_back(
"stcycl 01, 01; We write code to memory without skips/overwrite");
dsm_mem.push_back("");
dsm_mem.push_back("unpack[mru] S_8, 4, *; Flags");
for (int i = 0; i < face_count; i++) {
dsm_mem.push_back(".byte 0x10; stock");
dsm_mem.push_back(".byte 0x10; stock");
dsm_mem.push_back(".byte 0x20; draw triangle");
}
dsm_mem.push_back(".EndUnpack");
dsm_mem.push_back("");
dsm_mem.push_back("stcol 0x3f800000, 0x3f800000, 0x3f800000, "
"0x3f800000; We set garbage data to 1(float) so even "
"if nothing is referenced game doesn't go crazy");
dsm_mem.push_back(
"stmask 0x80808080; Sets mask register(0002, check EEUSER_E)");
dsm_mem.push_back(
"stcycl 01, 01; We write code to memory without skips/overwrite");
dsm_mem.push_back("");
dsm_mem.push_back("unpack[mr] V3_32, , *; Vertex definition");
vertices_arg = dsm_mem.size() - 1;
while (getline(input, line)) {
if (line.substr(0, 2) == "v ") {
std::istringstream s(line.substr(2));
float x, y, z;
s >> x;
s >> y;
s >> z;
line = ".float " + std::to_string(x) + ", " +
std::to_string(y) + ", " + std::to_string(z);
dsm_mem.push_back(line);
}
}
dsm_mem.push_back(".EndUnpack");
dsm_mem.push_back("");
if (!map) {
dsm_mem.push_back("stcycl 01, 01; We write code to memory without "
"skips/overwrite");
dsm_mem.push_back("");
dsm_mem.push_back("unpack[r] V4_32, ,*; Vertex affiliation header");
// printf("%lu", bones.size());
vertex_affiliation = dsm_mem.size() - 1;
for (unsigned int i = 0; i < ceil(float(bones.size()) / 4); i++) {
line = ".int " + std::to_string(bones[(i * 4)]);
unsigned int z = 1;
while ((i * 4) + z < bones.size() && z < 4) {
line += ", " + std::to_string(bones[(i * 4) + z]);
z++;
}
for (; z < 4; z++) {
line += ", 0";
}
dsm_mem.push_back(line);
}
dsm_mem.push_back(".EndUnpack");
} else {
// For some reason this is only specified in maps, should look at
// how necessary this truly is later
dsm_mem.push_back(
"mscnt; We tell the game the microcode continues");
}
dsm_mem.push_back("vifnop");
dsm_mem.push_back("vifnop; We wait for data to be kicked in");
}
printf("h1: %i, h2: 4, h3: %i, h4: %i\nj1: %i, j2: %i, j3: 0, j4: 1\n", 0,
4 + (face_count * 3) + vertex_count,
int(4 + (face_count * 3) + vertex_count +
ceil(float(bones.size()) / 4)),
4 + (face_count * 3), int(bones.size()));
// TODO: Stop hardcode Header size(5type-line exist) and Vert/Array
// h3: 1 not because 1 value but 1 array of 4, padding needs to be
// checked!
if (!map) {
line = ".int " + std::to_string(face_count * 3) + ", 4, " +
std::to_string(4 + (face_count * 3) + vertex_count) + ", " +
std::to_string(int(4 + (face_count * 3) + vertex_count +
ceil(float(bones.size()) / 4))) +
"; Number of u+v+flag+index, their offset, offset of vertex "
"affiliation header, offset of mat definition(end)";
} else {
line = ".int " + std::to_string(face_count * 3) +
", 4, 0, 0; Number of u+v+flag+index, their offset, offset of "
"vertex "
"affiliation header, offset of mat definition(end)";
}
dsm_mem[tmpheader] = line;
dsm_mem[tmpheader + 1] =
".int 0, 0, 0, 0; Nobody care about vertices merging and colors";
if (!map) {
line =
".int " + std::to_string(vertex_count) + ", " +
std::to_string(4 + (face_count * 3)) + ", 0, " +
std::to_string(bones.size()) +
"; Number of vertices, their offset, reserved and number of array "
"attribution";
} else {
line = ".int " + std::to_string(vertex_count) + ", " +
std::to_string(4 + (face_count * 3)) +
", 0, 0; Number of vertices, their offset, reserved and number "
"of array "
"attribution";
}
dsm_mem[tmpheader + 2] = line;
line = "unpack[mr] V3_32, " + std::to_string(4 + (face_count * 3)) +
", *; Vertex definition";
dsm_mem[vertices_arg] = line;
if (!map) {
line = "unpack[r] V4_32, " +
std::to_string(4 + (face_count * 3) + vertex_count) +
" ,*; Vertex affiliation header";
dsm_mem[vertex_affiliation] = line;
}
for (unsigned int i = 0; i < dsm_mem.size(); i++) {
dsm << dsm_mem[i] << std::endl;
}
dsm.close();
if (system(("dvp-as \"" + dsmname + "\" -o junk.o").c_str()) != 0) {
printf("Could not proceed, please install the homebrew ps2 sdk!\n");
return -1;
}
if (system(("dvp-objcopy -O binary junk.o \"" + kh2vname + "\"").c_str()) !=
0) {
printf("Your homebrew ps2 sdk installation seems to be broken, please "
"reinstall\n");
return -1;
}
remove("junk.o");
if (!junk) {
remove(dsmname.c_str());
}
FILE *vifpkt = fopen(kh2vname.c_str(), "a");
char empty[] = { 0x00 };
while (ftell(vifpkt) % 16 != 0) {
fwrite(empty, 1, sizeof(empty), vifpkt);
}
fclose(vifpkt);
return 1;
}