func (r *Gopher) Paint(p *qml.Painter) { width := gl.Float(r.Int("width")) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.ShadeModel(gl.SMOOTH) gl.Enable(gl.DEPTH_TEST) gl.DepthMask(gl.TRUE) gl.Enable(gl.NORMALIZE) gl.Clear(gl.DEPTH_BUFFER_BIT) gl.Scalef(width/3, width/3, width/3) lka := []gl.Float{0.3, 0.3, 0.3, 1.0} lkd := []gl.Float{1.0, 1.0, 1.0, 0.0} lks := []gl.Float{1.0, 1.0, 1.0, 1.0} lpos := []gl.Float{-2, 6, 3, 1.0} gl.Enable(gl.LIGHTING) gl.Lightfv(gl.LIGHT0, gl.AMBIENT, lka) gl.Lightfv(gl.LIGHT0, gl.DIFFUSE, lkd) gl.Lightfv(gl.LIGHT0, gl.SPECULAR, lks) gl.Lightfv(gl.LIGHT0, gl.POSITION, lpos) gl.Enable(gl.LIGHT0) gl.EnableClientState(gl.NORMAL_ARRAY) gl.EnableClientState(gl.VERTEX_ARRAY) gl.Translatef(1.5, 1.5, 0) gl.Rotatef(-90, 0, 0, 1) gl.Rotatef(gl.Float(90+((36000+r.Rotation)%360)), 1, 0, 0) gl.Disable(gl.COLOR_MATERIAL) for _, obj := range r.model { for _, group := range obj.Groups { gl.Materialfv(gl.FRONT, gl.AMBIENT, group.Material.Ambient) gl.Materialfv(gl.FRONT, gl.DIFFUSE, group.Material.Diffuse) gl.Materialfv(gl.FRONT, gl.SPECULAR, group.Material.Specular) gl.Materialf(gl.FRONT, gl.SHININESS, group.Material.Shininess) gl.VertexPointer(3, gl.FLOAT, 0, group.Vertexes) gl.NormalPointer(gl.FLOAT, 0, group.Normals) gl.DrawArrays(gl.TRIANGLES, 0, gl.Sizei(len(group.Vertexes)/3)) } } gl.Enable(gl.COLOR_MATERIAL) gl.DisableClientState(gl.NORMAL_ARRAY) gl.DisableClientState(gl.VERTEX_ARRAY) }
func (r *GoRect) Paint(p *qml.Painter) { r.PaintCount++ obj := p.Object() width := gl.Float(obj.Int("width")) height := gl.Float(obj.Int("height")) gl.Color3f(1.0, 0.0, 0.0) gl.Begin(gl.QUADS) gl.Vertex2f(0, 0) gl.Vertex2f(width, 0) gl.Vertex2f(width, height) gl.Vertex2f(0, height) gl.End() }
func (r *GoRect) Paint(p *qml.Painter) { width := gl.Float(r.Int("width")) height := gl.Float(r.Int("height")) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Color4f(1.0, 1.0, 1.0, 0.8) gl.Begin(gl.QUADS) gl.Vertex2f(0, 0) gl.Vertex2f(width, 0) gl.Vertex2f(width, height) gl.Vertex2f(0, height) gl.End() gl.LineWidth(2.5) gl.Color4f(0.0, 0.0, 0.0, 1.0) gl.Begin(gl.LINES) gl.Vertex2f(0, 0) gl.Vertex2f(width, height) gl.Vertex2f(width, 0) gl.Vertex2f(0, height) gl.End() }
func Read(filename string) (map[string]*Object, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() var materials map[string]*Material var objects = make(map[string]*Object) var object *Object var group *Group var vertex []gl.Float var normal []gl.Float lno := 0 line := "" scanner := bufio.NewScanner(file) fail := func(msg string) error { return fmt.Errorf(msg+" at %s:%d: %s", filename, lno, line) } for scanner.Scan() { lno++ line = scanner.Text() if strings.HasPrefix(line, "#") { continue } fields := strings.Fields(line) if len(fields) == 0 { continue } if fields[0] == "mtllib" { if len(fields) != 2 { return nil, fail("unsupported materials library line") } materials, err = readMaterials(filepath.Join(filepath.Dir(filename), fields[1])) if err != nil { return nil, err } continue } if fields[0] == "o" { if len(fields) != 2 { return nil, fail("unsupported object line") } object = &Object{Name: fields[1]} objects[object.Name] = object group = nil continue } if object == nil { return nil, fail("found data before object") } if fields[0] == "usemtl" { group = &Group{} object.Groups = append(object.Groups, group) } switch fields[0] { case "usemtl": if len(fields) != 2 { return nil, fail("unsupported material usage line") } group.Material = materials[fields[1]] if group.Material == nil { return nil, fmt.Errorf("material %q not defined", fields[1]) } case "v": if len(fields) != 4 { return nil, fail("unsupported vertex line") } for i := 0; i < 3; i++ { f, err := strconv.ParseFloat(fields[i+1], 32) if err != nil { return nil, fail("cannot parse float") } vertex = append(vertex, gl.Float(f)) } case "vn": if len(fields) != 4 { return nil, fail("unsupported vertex normal line") } for i := 0; i < 3; i++ { f, err := strconv.ParseFloat(fields[i+1], 32) if err != nil { return nil, fail("cannot parse float") } normal = append(normal, gl.Float(f)) } case "f": if len(fields) != 4 { return nil, fail("unsupported face line") } for i := 0; i < 3; i++ { face := strings.Split(fields[i+1], "/") if len(face) != 3 { return nil, fail("unsupported face shape (not a triangle)") } vi, err := strconv.Atoi(face[0]) if err != nil { return nil, fail("unsupported face vertex index") } ni, err := strconv.Atoi(face[2]) if err != nil { return nil, fail("unsupported face normal index") } vi = (vi - 1) * 3 ni = (ni - 1) * 3 group.Vertexes = append(group.Vertexes, vertex[vi], vertex[vi+1], vertex[vi+2]) group.Normals = append(group.Normals, normal[ni], normal[ni+1], normal[ni+2]) } } } if err := scanner.Err(); err != nil { return nil, err } return objects, nil }
func readMaterials(filename string) (map[string]*Material, error) { file, err := os.Open(filename) if err != nil { return nil, fmt.Errorf("cannot read referenced material library: %v", err) } defer file.Close() var materials = make(map[string]*Material) var material *Material lno := 0 line := "" scanner := bufio.NewScanner(file) fail := func(msg string) error { return fmt.Errorf(msg+" at %s:%d: %s", filename, lno, line) } for scanner.Scan() { lno++ line = scanner.Text() if strings.HasPrefix(line, "#") { continue } fields := strings.Fields(line) if len(fields) == 0 { continue } if fields[0] == "newmtl" { if len(fields) != 2 { return nil, fail("unsupported material definition") } material = &Material{Name: fields[1]} material.Ambient = []gl.Float{0.2, 0.2, 0.2, 1.0} material.Diffuse = []gl.Float{0.8, 0.8, 0.8, 1.0} material.Specular = []gl.Float{0.0, 0.0, 0.0, 1.0} materials[material.Name] = material continue } if material == nil { return nil, fail("found data before material") } switch fields[0] { case "Ka": if len(fields) != 4 { return nil, fail("unsupported ambient color line") } for i := 0; i < 3; i++ { f, err := strconv.ParseFloat(fields[i+1], 32) if err != nil { return nil, fail("cannot parse float") } material.Ambient[i] = gl.Float(f) } case "Kd": if len(fields) != 4 { return nil, fail("unsupported diffuse color line") } for i := 0; i < 3; i++ { f, err := strconv.ParseFloat(fields[i+1], 32) if err != nil { return nil, fail("cannot parse float") } material.Diffuse[i] = gl.Float(f) } case "Ks": if len(fields) != 4 { return nil, fail("unsupported specular color line") } for i := 0; i < 3; i++ { f, err := strconv.ParseFloat(fields[i+1], 32) if err != nil { return nil, fail("cannot parse float") } material.Specular[i] = gl.Float(f) } case "Ns": if len(fields) != 2 { return nil, fail("unsupported shininess line") } f, err := strconv.ParseFloat(fields[1], 32) if err != nil { return nil, fail("cannot parse float") } material.Shininess = gl.Float(f / 1000 * 128) case "d": if len(fields) != 2 { return nil, fail("unsupported transparency line") } f, err := strconv.ParseFloat(fields[1], 32) if err != nil { return nil, fail("cannot parse float") } material.Ambient[3] = gl.Float(f) material.Diffuse[3] = gl.Float(f) material.Specular[3] = gl.Float(f) } } if err := scanner.Err(); err != nil { return nil, err } // Exporting from blender seems to show everything too dark in // practice, so hack colors to look closer to what we see there. // TODO This needs more real world checking. for _, material := range materials { if material.Ambient[0] == 0 && material.Ambient[1] == 0 && material.Ambient[2] == 0 && material.Ambient[3] == 1 { material.Ambient[0] = material.Diffuse[0] * 0.7 material.Ambient[1] = material.Diffuse[1] * 0.7 material.Ambient[2] = material.Diffuse[2] * 0.7 } for i := 0; i < 3; i++ { material.Diffuse[i] *= 1.3 if material.Diffuse[i] > 1 { material.Diffuse[i] = 1 } } } return materials, nil }