123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- # Python tool to convert a 3D model from the text obj format to C arrays to be
- # used with small3dlib.
- #
- # by drummyfish
- # released under CC0 1.0.
- # NOTE: this script doesn't work with any OBJ file! If this doesn't work, the
- # format is probably wrong. If you're exporting the OBJ from Blender, you may
- # have to play around with the export options. Try this: unwrap model UVs
- # (the script expects UV coords to exist), check "selection only", "apply
- # modifiers", "include UVs", "triangulate faces", uncheck other things.
- #
- # Yes, I'll fix all this later :)
- import sys
- def printHelp():
- print("Convert 3D model in OBJ format (text, triangulated) to C array for small3dlib.")
- print("usage:\n")
- print(" python obj2array.py [-c -sX -uY -vZ -n] file\n")
- print(" -c compact format (off by default)")
- print(" -t use direct instead of indexed UV coords (off by default)")
- print(" -h include header guards (for model per file)")
- print(" -m include a material array (per-triangle)")
- print(" -nS use the name S for the model (defaut: \"model\")")
- print(" -sX scale the model by X (default: 512)")
- print(" -uY scale the U texture coord by Y (default: 512)")
- print(" -vZ scale the V texture coord by Z (default: 512)")
- print("");
- print("by Miloslav \"drummyfish\" Ciz")
- print("released under CC0 1.0")
- if len(sys.argv) < 2:
- printHelp()
- quit()
- FILENAME = ""
- VERTEX_SCALE = 512
- U_SCALE = 512
- V_SCALE = 512
- NAME = "model"
- GUARDS = False
- COMPACT = False
- INDEXED_UVS = True
- MATERIALS = False
- for s in sys.argv:
- if s == "-c":
- COMPACT = True
- elif s == "-t":
- INDEXED_UVS = False
- elif s == "-h":
- GUARDS = True
- elif s == "-m":
- MATERIALS = True
- elif s[:2] == "-s":
- VERTEX_SCALE = int(s[2:])
- elif s[:2] == "-u":
- U_SCALE = int(s[2:])
- elif s[:2] == "-v":
- V_SCALE = int(s[2:])
- elif s[:2] == "-n":
- NAME = s[2:]
- else:
- FILENAME = s
- objFile = open(FILENAME)
- vertices = []
- uvs = []
- triangles = []
- triangleUVs = []
- materials = []
- materialNames = []
- currentMatrial = 0
- def getMaterialIndex(materialName):
- try:
- return materialNames.index(materialName)
- except Exception:
- materialNames.append(materialName)
- return len(materialNames) - 1
- # parse the file:
- for line in objFile:
- if line[:2] == "v ":
- coords = line[2:].split()
- vertex = [float(coords[i]) for i in range(3)]
- vertex[2] *= -1
- vertices.append(vertex)
- elif line[:3] == "vt ":
- coords = line[3:].split()
- vertex = [float(coords[i]) for i in range(2)]
- vertex[1] = 1.0 - vertex[1]
- uvs.append(vertex)
- elif line[:2] == "f ":
- indices = line[2:].split()
- if len(indices) != 3:
- raise(Exception("The model is not triangulated!"))
- t = []
- u = []
-
- for i in indices:
- components = i.split("/")
- t.append(int(components[0]) - 1)
- try:
- u.append(int(components[1]) - 1)
- except Exception as e:
- u.append(int(components[2]) - 1)
- triangles.append(t)
- triangleUVs.append(u)
- materials.append([currentMatrial])
- elif line[:7] == "usemtl ":
- currentMatrial = getMaterialIndex(line[7:])
- # print the result:
- def arrayString(name, array, components, scales, align, short, dataType, sizeStr):
- result = "const " + dataType + " " + name + "[" + sizeStr + "] = {\n"
- if COMPACT:
- lineLen = 0
- first = True
- n = 0
- for v in array:
- for c in v:
- item = ""
- if first:
- first = False
- else:
- result += ","
- lineLen += 1
- if lineLen >= 80:
- result += "\n"
- lineLen = 0
- num = c * scales[n % len(scales)]
- if short:
- item += str(num)
- else:
- item += ("" if num >= 0 else "-") + "0x%x" % abs(num)
- if lineLen + len(item) >= 80:
- result += "\n"
- lineLen = 0
-
- result += item
- lineLen += len(item)
- n += 1
- result += "};\n"
- else: # non-compact
- n = 0
- endIndex = len(array) - 1
- for v in array:
- line = " " + ", ".join([str(int(v[c] * scales[c % len(scales)])).rjust(align) for c in range(components)])
- if n < endIndex:
- line += ","
- line = line.ljust((components + 2) * (align + 1)) + "// " + str(n * components) + "\n"
- result += line
- n += 1
- result += "}; // " + name + "\n"
- return result
- result = ""
- if GUARDS:
- print("#ifndef " + NAME.upper() + "_MODEL_H")
- print("#define " + NAME.upper() + "_MODEL_H\n")
- print("#define " + NAME.upper() + "_VERTEX_COUNT " + str(len(vertices)))
- print(arrayString(NAME + "Vertices",vertices,3,[VERTEX_SCALE],5,False,"S3L_Unit",NAME.upper() + "_VERTEX_COUNT * 3"))
- print("#define " + NAME.upper() + "_TRIANGLE_COUNT " + str(len(triangles)))
- print(arrayString(NAME + "TriangleIndices",triangles,3,[1],5,True,"S3L_Index",NAME.upper() + "_TRIANGLE_COUNT * 3"))
- if MATERIALS:
- print(arrayString(NAME + "Materials",materials,1,[1],5,True,"uint8_t",NAME.upper() + "_TRIANGLE_COUNT"))
- if INDEXED_UVS:
- print("#define " + NAME.upper() + "_UV_COUNT " + str(len(uvs)))
- print(arrayString(NAME + "UVs",uvs,2,[U_SCALE,V_SCALE],5,False,"S3L_Unit",NAME.upper() + "_UV_COUNT * 2"))
- print("#define " + NAME.upper() + "_UV_INDEX_COUNT " + str(len(triangleUVs)))
- print(arrayString(NAME + "UVIndices",triangleUVs,3,[1],5,True,"S3L_Index",NAME.upper() + "_UV_INDEX_COUNT * 3"))
- else:
- uvs2 = []
- for item in triangleUVs:
- uvs2.append([
- uvs[item[0]][0],
- uvs[item[0]][1],
- uvs[item[1]][0],
- uvs[item[1]][1],
- uvs[item[2]][0],
- uvs[item[2]][1]])
- print("#define " + NAME.upper() + "_DIRECT_UV_COUNT " + str(len(uvs2)))
- print(arrayString(NAME + "DirectUVs",uvs2,6,[U_SCALE,V_SCALE],5,False,"S3L_Unit",NAME.upper() + "_DIRECT_UV_COUNT * 6"))
- print("S3L_Model3D " + NAME + "Model;\n")
- print("void " + NAME + "ModelInit()")
- print("{")
- print(" S3L_model3DInit(")
- print(" " + NAME + "Vertices,")
- print(" " + NAME.upper() + "_VERTEX_COUNT,")
- print(" " + NAME + "TriangleIndices,")
- print(" " + NAME.upper() + "_TRIANGLE_COUNT,")
- print(" &" + NAME + "Model);")
- print("}")
- if GUARDS:
- print("\n#endif // guard")
|