initial
This commit is contained in:
commit
61e2fb2c28
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__pycache__/
|
||||
*.pyc
|
42
generate.py
Normal file
42
generate.py
Normal file
@ -0,0 +1,42 @@
|
||||
import io
|
||||
|
||||
def should_autonewline(line):
|
||||
return (
|
||||
"static_assert" not in line
|
||||
and "extern" not in line
|
||||
and (len(line.split()) < 2 or line.split()[1] != '=') # hacky; meh
|
||||
)
|
||||
|
||||
def _render(out, lines, indent_length):
|
||||
indent = " "
|
||||
level = 0
|
||||
namespace = 0
|
||||
for l in lines:
|
||||
if l and (l[0] == "}" or l[0] == ")"):
|
||||
level -= indent_length
|
||||
if level < 0:
|
||||
assert namespace >= 0
|
||||
namespace -= 1
|
||||
level = 0
|
||||
|
||||
if len(l) == 0:
|
||||
out.write("\n")
|
||||
else:
|
||||
out.write(indent * level + l + "\n")
|
||||
|
||||
if l and (l[-1] == "{" or l[-1] == "("):
|
||||
if l.startswith("namespace"):
|
||||
namespace += 1
|
||||
else:
|
||||
level += indent_length
|
||||
|
||||
if level == 0 and l and l[-1] == ";":
|
||||
if should_autonewline(l):
|
||||
out.write("\n")
|
||||
return out
|
||||
|
||||
def renderer(indent_length=2):
|
||||
out = io.StringIO()
|
||||
def render(lines):
|
||||
return _render(out, lines, indent_length)
|
||||
return render, out
|
61
generate_cpp.py
Normal file
61
generate_cpp.py
Normal file
@ -0,0 +1,61 @@
|
||||
from generate import renderer
|
||||
from obj import parse_obj_file
|
||||
import sys
|
||||
|
||||
def generate_vec3(vs):
|
||||
for v in vs:
|
||||
yield f"{{{v.x}f, {v.y}f, {v.z}f}},"
|
||||
|
||||
def generate_vec2(vs):
|
||||
for v in vs:
|
||||
yield f"{{{v.x}f, {v.y}f}},"
|
||||
|
||||
def generate_vec(name, type, func, vs):
|
||||
yield f"vertex_{type} {name}_{type}[] = {{"
|
||||
yield from func(vs)
|
||||
yield "};"
|
||||
|
||||
def filter_n(l, n):
|
||||
for a in l:
|
||||
if len(a.ptn) == n:
|
||||
yield a
|
||||
|
||||
def generate_ptn(ptn):
|
||||
for p in ptn:
|
||||
yield f"{{{p.position}, {p.texture}, {p.normal}}},"
|
||||
|
||||
def generate_faces(group_name, model_name, faces, type, n):
|
||||
yield f"union {type} {group_name}_{model_name}_triangles = {{"
|
||||
for face in filter_n(faces, n):
|
||||
yield "{ .v = {"
|
||||
yield from generate_ptn(face.ptn)
|
||||
yield "}},"
|
||||
yield "};"
|
||||
|
||||
def generate_object(group_name, object):
|
||||
yield f"struct object {group_name}_{object.name} = {{"
|
||||
yield f".triangle = &{group_name}_{object.name}_triangle[0],"
|
||||
yield f".quadrilateral = &{group_name}_{object.name}_quadrilateral[0],"
|
||||
triangle_count = sum(1 for _ in filter_n(object.faces, 3))
|
||||
quadrilateral_count = sum(1 for _ in filter_n(object.faces, 4))
|
||||
yield f".triangle_count = {triangle_count},"
|
||||
yield f".quadrilateral_count = {quadrilateral_count},"
|
||||
yield ".material = 0,"
|
||||
yield "};"
|
||||
|
||||
def generate_obj_file(group_name, obj_file):
|
||||
yield from generate_vec(group_name, "position", generate_vec3, obj_file.position)
|
||||
yield from generate_vec(group_name, "texture", generate_vec2, obj_file.texture)
|
||||
yield from generate_vec(group_name, "normal", generate_vec3, obj_file.normal)
|
||||
|
||||
for object in obj_file.objects:
|
||||
assert all(len(face.ptn) in {3, 4} for face in object.faces), object.name
|
||||
yield from generate_faces(group_name, object.name, object.faces, "triangle", 3)
|
||||
yield from generate_faces(group_name, object.name, object.faces, "quadrilateral", 4)
|
||||
yield from generate_object(group_name, object)
|
||||
|
||||
if __name__ == "__main__":
|
||||
obj_file = parse_obj_file(sys.argv[1])
|
||||
render, out = renderer(indent_length=4)
|
||||
render(generate_obj_file(sys.argv[2], obj_file))
|
||||
sys.stdout.write(out.getvalue())
|
57
generate_java.py
Normal file
57
generate_java.py
Normal file
@ -0,0 +1,57 @@
|
||||
from generate import renderer
|
||||
from obj import parse_obj_file
|
||||
import sys
|
||||
|
||||
def generate_vec3(field, vs):
|
||||
for i, v in enumerate(vs):
|
||||
vec3_args = f"{v.x}f, {v.y}f, {v.z}f"
|
||||
yield f"{field}[{i}] = new Vec3({vec3_args});"
|
||||
|
||||
def generate_vec2(field, vs):
|
||||
for i, v in enumerate(vs):
|
||||
vec2_args = f"{v.x}f, {v.y}f"
|
||||
yield f"{field}[{i}] = new Vec2({vec2_args});"
|
||||
|
||||
def generate_face(length, i, j, face):
|
||||
assert len(face.ptn) == length, (face.ptn, length)
|
||||
for k, ptn in enumerate(face.ptn):
|
||||
ptn_args = f"{ptn.position}, {ptn.texture}, {ptn.normal}"
|
||||
yield f"objects[{i}].faces[{j}][{k}] = new FacePTN({ptn_args});"
|
||||
|
||||
def generate_model_objects(objects):
|
||||
face_length = len(objects[0].faces[0].ptn)
|
||||
for i, o in enumerate(objects):
|
||||
yield f"objects[{i}] = new ModelObject();"
|
||||
yield f"objects[{i}].faces = new FacePTN[{len(o.faces)}][{face_length}];"
|
||||
for j, face in enumerate(objects[i].faces):
|
||||
yield from generate_face(face_length, i, j, face)
|
||||
|
||||
def generate_model(name, obj_file):
|
||||
yield "package model;"
|
||||
yield f"public class {name} {{"
|
||||
yield "public static Vec3[] position;"
|
||||
yield "public static Vec3[] normal;"
|
||||
yield "public static Vec2[] texture;"
|
||||
yield "public static ModelObject[] objects;"
|
||||
yield f"private {name}() {{"
|
||||
yield "}"
|
||||
yield "static {"
|
||||
yield f"position = new Vec3[{len(obj_file.position)}];"
|
||||
yield f"normal = new Vec3[{len(obj_file.normal)}];"
|
||||
yield f"texture = new Vec2[{len(obj_file.texture)}];"
|
||||
yield f"objects = new ModelObject[{len(obj_file.objects)}];"
|
||||
|
||||
yield from generate_vec3("position", obj_file.position)
|
||||
yield from generate_vec3("normal", obj_file.normal)
|
||||
yield from generate_vec2("texture", obj_file.texture)
|
||||
|
||||
yield from generate_model_objects(obj_file.objects)
|
||||
|
||||
yield "}"
|
||||
yield "}"
|
||||
|
||||
if __name__ == "__main__":
|
||||
obj_file = parse_obj_file(sys.argv[1])
|
||||
render, out = renderer(indent_length=4)
|
||||
render(generate_model(sys.argv[2], obj_file))
|
||||
sys.stdout.write(out.getvalue())
|
13
java/model/FacePTN.java
Normal file
13
java/model/FacePTN.java
Normal file
@ -0,0 +1,13 @@
|
||||
package model;
|
||||
|
||||
public class FacePTN {
|
||||
public int position;
|
||||
public int texture;
|
||||
public int normal;
|
||||
|
||||
FacePTN(int position, int texture, int normal) {
|
||||
this.position = position;
|
||||
this.texture = texture;
|
||||
this.normal = normal;
|
||||
}
|
||||
}
|
5
java/model/ModelObject.java
Normal file
5
java/model/ModelObject.java
Normal file
@ -0,0 +1,5 @@
|
||||
package model;
|
||||
|
||||
public class ModelObject {
|
||||
public FacePTN[][] faces;
|
||||
}
|
11
java/model/Vec2.java
Normal file
11
java/model/Vec2.java
Normal file
@ -0,0 +1,11 @@
|
||||
package model;
|
||||
|
||||
public class Vec2 {
|
||||
public float x;
|
||||
public float y;
|
||||
|
||||
public Vec2(float x, float y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
13
java/model/Vec3.java
Normal file
13
java/model/Vec3.java
Normal file
@ -0,0 +1,13 @@
|
||||
package model;
|
||||
|
||||
public class Vec3 {
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
|
||||
public Vec3(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
}
|
161
obj.py
Normal file
161
obj.py
Normal file
@ -0,0 +1,161 @@
|
||||
from dataclasses import dataclass
|
||||
import sys
|
||||
|
||||
@dataclass
|
||||
class VertexPosition:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
|
||||
@dataclass
|
||||
class VertexNormal:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
|
||||
@dataclass
|
||||
class VertexTexture:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
|
||||
@dataclass
|
||||
class ObjectEvent:
|
||||
name: str
|
||||
|
||||
@dataclass
|
||||
class FacePTN:
|
||||
position: int
|
||||
texture: int
|
||||
normal: int
|
||||
|
||||
@dataclass
|
||||
class Face:
|
||||
ptn: list[FacePTN]
|
||||
|
||||
@dataclass
|
||||
class Object:
|
||||
name: str
|
||||
faces: list[Face]
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.faces = []
|
||||
|
||||
@dataclass
|
||||
class ObjFile:
|
||||
position: list[VertexPosition]
|
||||
normal: list[VertexNormal]
|
||||
texture: list[VertexTexture]
|
||||
objects: list[Object]
|
||||
|
||||
def __init__(self):
|
||||
self.position = []
|
||||
self.normal = []
|
||||
self.texture = []
|
||||
self.objects = []
|
||||
|
||||
def parse_float(s):
|
||||
if '.' not in s:
|
||||
return int(s, 10)
|
||||
i, f = s.split('.')
|
||||
f_digits = len(f)
|
||||
i = int(i, 10)
|
||||
f = int(f, 10)
|
||||
return i + (f / 10 ** f_digits)
|
||||
|
||||
def parse_vertex(line, n, type):
|
||||
assert len(line) == n
|
||||
vs = [parse_float(line[i]) for i in range(n)]
|
||||
if len(vs) < 3:
|
||||
vs.append(0)
|
||||
return type(*vs)
|
||||
|
||||
def parse_vertex_position(line):
|
||||
return parse_vertex(line, 3, VertexPosition)
|
||||
|
||||
def parse_vertex_normal(line):
|
||||
return parse_vertex(line, 3, VertexNormal)
|
||||
|
||||
def parse_vertex_texture(line):
|
||||
return parse_vertex(line, 2, VertexTexture)
|
||||
|
||||
def parse_face_indices(indices):
|
||||
assert "/" in indices
|
||||
indices = indices.split("/")
|
||||
assert len(indices) == 3, indices
|
||||
def face_ix(s):
|
||||
i = int(s, 10)
|
||||
assert i >= 1
|
||||
return i - 1
|
||||
return FacePTN(*(face_ix(i) for i in indices))
|
||||
|
||||
def parse_face(line):
|
||||
return Face([parse_face_indices(indices) for indices in line])
|
||||
|
||||
def parse_object_event(line):
|
||||
assert len(line) == 1
|
||||
name, = line
|
||||
return ObjectEvent(name)
|
||||
|
||||
def parse_line(line):
|
||||
t, *line = line.split(' ')
|
||||
if t == '#':
|
||||
return None
|
||||
if t == 'usemtl':
|
||||
return None
|
||||
if t == 'mtllib':
|
||||
return None
|
||||
if t == 'o':
|
||||
return parse_object_event(line)
|
||||
if t == 'v':
|
||||
return parse_vertex_position(line)
|
||||
if t == 'vn':
|
||||
return parse_vertex_normal(line)
|
||||
if t == 'vt':
|
||||
return parse_vertex_texture(line)
|
||||
if t == 'f':
|
||||
return parse_face(line)
|
||||
if t == 's':
|
||||
# smooth shading
|
||||
return None
|
||||
assert False, (t, line)
|
||||
|
||||
def parse_obj_lines(lines):
|
||||
file = ObjFile()
|
||||
object = Object(None)
|
||||
for line in lines:
|
||||
x = parse_line(line)
|
||||
if x is None:
|
||||
continue
|
||||
elif type(x) is VertexPosition:
|
||||
file.position.append(x)
|
||||
elif type(x) is VertexNormal:
|
||||
file.normal.append(x)
|
||||
elif type(x) is VertexTexture:
|
||||
file.texture.append(x)
|
||||
elif type(x) is ObjectEvent:
|
||||
if object.faces:
|
||||
assert object.name != None
|
||||
file.objects.append(object)
|
||||
object = Object(x.name)
|
||||
elif type(x) is Face:
|
||||
object.faces.append(x)
|
||||
else:
|
||||
assert False, x
|
||||
if object.faces:
|
||||
assert object.name != None
|
||||
file.objects.append(object)
|
||||
return file
|
||||
|
||||
|
||||
def parse_obj_file(filename):
|
||||
with open(filename, "r") as f:
|
||||
lines = f.read().strip().split("\n")
|
||||
file = parse_obj_lines(lines)
|
||||
return file
|
||||
|
||||
if __name__ == "__main__":
|
||||
file = parse_obj_file(sys.argv[1])
|
||||
from pprint import pprint
|
||||
pprint(file)
|
Loading…
x
Reference in New Issue
Block a user