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