2019-05-23 19:42:12 +02:00
|
|
|
# Python tool to convert a 3D model from the text obj format to C arrays to be
|
|
|
|
# used with small3dlib.
|
|
|
|
#
|
2019-05-25 19:57:05 +02:00
|
|
|
# by drummyfish
|
2019-05-23 19:42:12 +02:00
|
|
|
# released under CC0 1.0.
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
2019-05-25 13:34:43 +02:00
|
|
|
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)")
|
2019-05-25 19:57:05 +02:00
|
|
|
print(" -t use direct instead of indexed UV coords (off by default)")
|
2019-05-26 16:42:55 +02:00
|
|
|
print(" -h include header guards (for model per file)")
|
2019-05-25 19:57:05 +02:00
|
|
|
print(" -nS use the name S for the model (defaut: \"model\")")
|
2019-05-25 13:34:43 +02:00
|
|
|
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")
|
2019-05-23 19:42:12 +02:00
|
|
|
|
2019-05-25 13:34:43 +02:00
|
|
|
if len(sys.argv) < 2:
|
|
|
|
printHelp()
|
|
|
|
quit()
|
|
|
|
|
2019-05-25 19:57:05 +02:00
|
|
|
FILENAME = ""
|
2019-05-23 19:42:12 +02:00
|
|
|
VERTEX_SCALE = 512
|
|
|
|
U_SCALE = 512
|
|
|
|
V_SCALE = 512
|
|
|
|
NAME = "model"
|
2019-05-26 16:42:55 +02:00
|
|
|
GUARDS = False
|
2019-05-25 13:34:43 +02:00
|
|
|
COMPACT = False
|
|
|
|
INDEXED_UVS = True
|
|
|
|
|
|
|
|
for s in sys.argv:
|
|
|
|
if s == "-c":
|
|
|
|
COMPACT = True
|
2019-05-25 19:57:05 +02:00
|
|
|
elif s == "-t":
|
2019-05-25 13:34:43 +02:00
|
|
|
INDEXED_UVS = False
|
2019-05-26 16:42:55 +02:00
|
|
|
elif s == "-h":
|
|
|
|
GUARDS = True
|
2019-05-25 13:34:43 +02:00
|
|
|
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:])
|
2019-05-25 19:57:05 +02:00
|
|
|
elif s[:2] == "-n":
|
|
|
|
NAME = s[2:]
|
2019-05-25 13:34:43 +02:00
|
|
|
else:
|
2019-05-25 19:57:05 +02:00
|
|
|
FILENAME = s
|
2019-05-23 19:42:12 +02:00
|
|
|
|
2019-05-25 19:57:05 +02:00
|
|
|
objFile = open(FILENAME)
|
2019-05-23 19:42:12 +02:00
|
|
|
|
|
|
|
vertices = []
|
|
|
|
uvs = []
|
|
|
|
triangles = []
|
|
|
|
triangleUVs = []
|
|
|
|
|
|
|
|
# parse the file:
|
|
|
|
|
|
|
|
for line in objFile:
|
|
|
|
if line[:2] == "v ":
|
|
|
|
coords = line[2:].split()
|
|
|
|
vertex = [float(coords[i]) for i in range(3)]
|
|
|
|
vertices.append(vertex)
|
|
|
|
elif line[:3] == "vt ":
|
|
|
|
coords = line[3:].split()
|
|
|
|
vertex = [float(coords[i]) for i in range(2)]
|
2019-06-01 22:28:12 +02:00
|
|
|
vertex[1] = 1.0 - vertex[1]
|
2019-05-23 19:42:12 +02:00
|
|
|
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)
|
2019-06-01 22:28:12 +02:00
|
|
|
u.append(int(components[1]) - 1)
|
2019-05-23 19:42:12 +02:00
|
|
|
|
|
|
|
triangles.append(t)
|
2019-06-01 22:28:12 +02:00
|
|
|
triangleUVs.append(u)
|
2019-05-23 19:42:12 +02:00
|
|
|
|
|
|
|
# print the result:
|
|
|
|
|
2019-05-26 16:42:55 +02:00
|
|
|
def arrayString(name, array, components, scales, align, short, dataType):
|
|
|
|
result = "const " + dataType + " " + name + "[] = {\n"
|
2019-05-23 19:42:12 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-05-26 16:42:55 +02:00
|
|
|
result += "};\n"
|
2019-05-23 19:42:12 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2019-05-26 16:42:55 +02:00
|
|
|
result += "}; // " + name + "\n"
|
2019-05-23 19:42:12 +02:00
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
result = ""
|
|
|
|
|
2019-05-26 16:42:55 +02:00
|
|
|
if GUARDS:
|
2019-06-02 20:22:42 +02:00
|
|
|
print("#ifndef " + NAME.upper() + "_MODEL_H")
|
|
|
|
print("#define " + NAME.upper() + "_MODEL_H\n")
|
2019-05-26 16:42:55 +02:00
|
|
|
|
|
|
|
print(arrayString(NAME + "Vertices",vertices,3,[VERTEX_SCALE],5,False,"S3L_Unit"))
|
|
|
|
print(arrayString(NAME + "TriangleIndices",triangles,3,[1],5,True,"S3L_Index"))
|
2019-05-23 19:42:12 +02:00
|
|
|
|
|
|
|
if INDEXED_UVS:
|
2019-06-01 22:28:12 +02:00
|
|
|
print(arrayString(NAME + "UVs",uvs,2,[U_SCALE,V_SCALE],5,False,"S3L_Unit"))
|
2019-05-26 16:42:55 +02:00
|
|
|
print(arrayString(NAME + "UVIndices",triangleUVs,3,[1],5,True,"S3L_Index"))
|
2019-05-23 19:42:12 +02:00
|
|
|
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]])
|
|
|
|
|
2019-05-26 16:42:55 +02:00
|
|
|
print(arrayString(NAME + "TriangleUVs",uvs2,6,[U_SCALE,V_SCALE],5,False,"S3L_Unit"))
|
2019-05-23 19:42:12 +02:00
|
|
|
|
2019-06-02 20:22:42 +02:00
|
|
|
print("S3L_Model3D " + NAME + "Model = ")
|
2019-05-25 19:57:05 +02:00
|
|
|
|
|
|
|
if COMPACT:
|
|
|
|
print("{.vertices=" +
|
2019-05-26 16:42:55 +02:00
|
|
|
NAME + "Vertices,.vertexCount=" + str(len(vertices)) +
|
|
|
|
",.triangles=" + NAME + "TriangleIndices,\n.triangleCount=" +
|
2019-05-25 19:57:05 +02:00
|
|
|
str(len(triangles)) + "};");
|
|
|
|
else:
|
|
|
|
print("{")
|
|
|
|
print(" .vertices = " + NAME + "Vertices,")
|
|
|
|
print(" .vertexCount = " + str(len(vertices)) + ",")
|
2019-05-26 16:42:55 +02:00
|
|
|
print(" .triangles = " + NAME + "TriangleIndices,")
|
2019-05-25 19:57:05 +02:00
|
|
|
print(" .triangleCount = " + str(len(triangles)))
|
|
|
|
print("};")
|
2019-05-26 16:42:55 +02:00
|
|
|
|
|
|
|
if GUARDS:
|
|
|
|
print("\n#endif // guard")
|