Skip to content

Instantly share code, notes, and snippets.

@ousttrue
Created August 4, 2010 16:18
Show Gist options
  • Save ousttrue/508377 to your computer and use it in GitHub Desktop.
Save ousttrue/508377 to your computer and use it in GitHub Desktop.
package mqo
import java.io.File
import scala.io.Source
import scala.collection.mutable.ArrayBuffer
class Vector2(val x :Float, val y :Float)
object Vector2 {
def apply(x :Float, y :Float) :Vector2=new Vector2(x, y)
def apply(
x :{def toFloat:Float},
y :{def toFloat:Float}
) :Vector2=new Vector2(x toFloat, y toFloat)
}
class Vector3(val x :Float, val y :Float, val z :Float)
object Vector3 {
def apply(x :Float, y :Float, z :Float) :Vector3=new Vector3(x, y, z)
def apply(
x :{def toFloat:Float},
y :{def toFloat:Float},
z :{def toFloat:Float}
) :Vector3=new Vector3(x toFloat, y toFloat, z toFloat)
}
class RGBA(val r :Float, val g :Float, val b :Float, val a :Float)
object RGBA {
def apply(r :Float, g :Float, b :Float, a :Float) :RGBA=new RGBA(r, g, b, a)
def apply(
r :{def toFloat:Float},
g :{def toFloat:Float},
b :{def toFloat:Float},
a :{def toFloat:Float}
) :RGBA=new RGBA(r toFloat, g toFloat, b toFloat, a toFloat)
}
///////////////////////////////////////////////////////////////////////////////
// Material
///////////////////////////////////////////////////////////////////////////////
class Material(var name :String) {
var shader=3
var color=new RGBA(0.5f, 0.5f, 0.5f, 1.0f)
var diffuse=1.0
var ambient=0.25
var emit=0.25
var specular=0.0
var power=5.0
var useVertexColor=0
var diffuseTexture=""
var alphaTexture=""
override def toString() :String={
"<Material"+
color+
">"
}
}
object Material {
val materialLine="""^\s*"([^"]+)"(.*)$""".r
val paramsPattern="""\s*(\w+)\(([^)]+)\)""".r
def parse(line: String) :Material={
line match {
case materialLine(name, params) =>
val material=new Material(name)
paramsPattern.findAllIn(params).matchData.foreach(m => {
m.group(1) match {
case "col" =>
val t=m.group(2).split(" ")
material.color=RGBA(t(0), t(1), t(2), t(3))
case "shader" => material.shader=m.group(2) toInt
case "dif" => material.diffuse=m.group(2) toFloat
case "amb" => material.ambient=m.group(2) toFloat
case "emi" => material.emit=m.group(2) toFloat
case "spc" => material.specular=m.group(2) toFloat
case "power" => material.power=m.group(2) toFloat
case "vcol" => material.useVertexColor=m.group(2) toInt
case "aplane" => material.alphaTexture=m.group(2)
case "tex" => material.diffuseTexture=m.group(2)
}
})
return material
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Face
///////////////////////////////////////////////////////////////////////////////
case class Face(val num :Int) {
val indices=new Array[Int](num)
val uv=new Array[Vector2](num)
var material=0
def setIndices(src :Seq[Int]){
val it=src.iterator
var i=0
while(it.hasNext){
indices(i)=it.next()
i+=1
}
}
def setUV(src :Seq[Float]){
val it=src.iterator
var i=0
while(it.hasNext){
uv(i)=Vector2(it.next(), it.next())
i+=1
}
}
}
object Face {
val faceLine="""^\s*(\d+)(.*)$""".r
private def parseParams_(count :Int, params :String)
:(Seq[Int], Int, Seq[Float])={
var indices :Seq[Int]=new Array[Int](count)
var material=0
var uvs :Seq[Float]=new Array[Float](count*2)
for(param <- params.split(')')){
val tokens=param.trim.split(Array('(', ' '))
tokens match {
case Array("M", m@_*)=> material=m(0) toInt
case Array("V", i@_*)=> indices=i.map(_ toInt)
case Array("UV", uv@_*)=> uvs=uv.map(_ toFloat)
case Array("COL", c@_*)=> 0
case _=> 0
}
}
return (indices, material, uvs)
}
def parse(line: String) :Face={
line match {
case faceLine(count, params) =>
val (indices, material, uv)=parseParams_(count toInt, params)
var face=new Face(count toInt)
face.setIndices(indices)
face.setUV(uv)
face.material=material
return face
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Object
///////////////////////////////////////////////////////////////////////////////
class Object(var name :String) {
var depth=0
var folding=1
var scale=Vector3(0, 0, 0)
var rotation=Vector3(0, 0, 0)
var translation=Vector3(0, 0, 0)
var visible=0
var locking=0
var shading=0
var facet=0.0f
var color=RGBA(0.5f, 0.5f, 0.5f, 1.0f)
var color_type=0
val vertices=new ArrayBuffer[Vector3]
val faces=new ArrayBuffer[Face]
override def toString() :String={
"["+name+
" vertices: "+vertices.size+
", faces: "+faces.size+
"]"
}
}
object Object{
def parse(name: String, iter :Iterator[String]) :Object={
val obj=new Object(name)
for(line <- iter){
val l=line.trim
if(l=="}"){
return obj
}
val tokens=l.split(" ")
//println(tokens(0))
tokens match {
case Array("depth", value) => obj.depth=value toInt
case Array("folding", value) => obj.folding=value toInt
case Array("scale", x, y, z) => obj.scale=Vector3(x, y, z)
case Array("rotation", x, y, z) => obj.rotation=Vector3(x, y, z)
case Array("translation", x, y, z) =>
obj.translation=Vector3(x, y, z)
case Array("visible", value)=> obj.visible=value toInt
case Array("locking", value)=> obj.locking=value toInt
case Array("shading", value)=> obj.shading=value toInt
case Array("facet", value)=> obj.facet=value toFloat
case Array("color", r, g, b)=> obj.color=RGBA(r, g, b, "1")
case Array("color_type", value)=> obj.color_type=value toInt
case Array("vertex", count, "{")=>
Object.parseVertices(obj, iter, count toInt)
case Array("face", count, "{")=>
Object.parseFaces(obj, iter, count toInt)
case _ => println("unknown key:", tokens(0))
}
}
return null
}
def parseVertices(obj :Object, iter :Iterator[String], count :Int){
for(line <- iter){
val l=line.trim
if(l=="}"){
return
}
l.split(" ") match {
case Array(x, y, z)=> obj.vertices.append(Vector3(x, y, z))
}
}
}
def parseFaces(obj :Object, iter :Iterator[String], count :Int){
for(line <- iter){
val l=line.trim
if(l=="}"){
return
}
obj.faces.append(Face.parse(l))
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Mqo Loader
///////////////////////////////////////////////////////////////////////////////
class Loader {
var path=""
var pos=Vector3(0, 0, 0)
var lookat=Vector3(0, 0, 0)
var head=0.0
var pitch=0.0
var orthogonal=false
var zoom2=0.0
var amb=Vector3(0, 0, 0)
val materials=new ArrayBuffer[Material]
val objects=new ArrayBuffer[Object]
override def toString() :String={
"<mqo.Loader"+
" materials: "+materials.size+
", objects: "+objects.size+"\n"+
(for(o <- objects)yield o.toString).mkString("\n") +
">"
}
private def _parseScene(iter :Iterator[String]) {
for(line <- iter){
if(line=="}"){
return true;
}
val tokens=line.trim.split(" ")
tokens match {
case Array("pos", x, y, z)=> pos=Vector3(x, y, z)
case Array("lookat", x, y, z)=> lookat=Vector3(x, y, z)
case Array("head", value)=> head=value toFloat
case Array("pich", value)=> pitch=value toFloat
case Array("ortho", value)=> orthogonal=(value.toInt != 0)
case Array("zoom2", value)=> zoom2=value toFloat
case Array("amb", x, y, z)=> amb=Vector3(x, y, z)
case _ => println("unknown key:", tokens(0))
}
}
}
private def _parseMaterials(iter :Iterator[String], count: Int){
for(line <- iter){
if(line=="}"){
return true
}
materials.append(Material.parse(line));
}
}
def load(src :java.io.File):Boolean=load(src toString)
def load(src :String):Boolean={
path=src
try{
val iter=Source.fromFile(path, "shift-jis").getLines
// check first line
if(iter.next!="Metasequoia Document"){
return false
}
// check second line
if(iter.next!="Format Text Ver 1.0"){
return false;
}
// each line
val materialChunk="""Material (\d+) \{""".r
val objectChunk="""^Object "([^"]+)" \{""".r
while(iter.hasNext){
iter.next match {
case "" => 0
case "Eof" => return true
case "Scene {" => _parseScene(iter)
case materialChunk(count) => _parseMaterials(
iter, count toInt)
case objectChunk(name) =>
objects.append(Object.parse(name, iter))
case default => println("unknown chunk:", default)
}
}
return false;
}
catch {
case ex :java.io.FileNotFoundException =>
println(ex toString)
return false;
}
}
}
object Loader {
def main(args :Array[String]){
for(arg <- args){
println("load: "+arg)
val loader=new Loader
if(loader.load(arg)){
println(loader)
}
else{
println("failed!")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment