Example #1
0
func setupGeometry(gl *webgl.Context, program *js.Object) {
	gl.BindBuffer(gl.ARRAY_BUFFER, gl.CreateBuffer())
	gl.BufferData(gl.ARRAY_BUFFER, buildArray(), gl.STATIC_DRAW)

	positionLocation := gl.GetAttribLocation(program, "a_position")
	gl.EnableVertexAttribArray(positionLocation)
	gl.VertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0)
}
Example #2
0
func (o *Obj) Read(reader io.Reader, gl *webgl.Context) error {
	var group *ObjGroup
	var materialName string
	var positions []float32
	var normals []float32
	var texcoords []float32

	var float2 [2]float32 = [2]float32{0, 0}
	var float3 [3]float32 = [3]float32{0, 0, 0}

	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") {
			// Blank line or comment, ignore it
			continue
		}

		// Split line into fields on whitespace
		fields := strings.Fields(line)
		switch strings.ToLower(fields[0]) {
		// Vertex position.
		case "v":
			if err := parseFloat3(fields[1:4], &float3); err != nil {
				return err
			}
			positions = append(positions, float3[0], float3[1], float3[2])

		// Vertex normal.
		case "vn":
			if err := parseFloat3(fields[1:4], &float3); err != nil {
				return err
			}
			normals = append(normals, float3[0], float3[1], float3[2])

		// Vertex texture coordinates.
		case "vt":
			if err := parseFloat2(fields[1:3], &float2); err != nil {
				return err
			}
			texcoords = append(texcoords, float2[0], 1.0-float2[1])

		// Face indices, specified in sets of "position/uv/normal".
		case "f":
			faces := fields[1:len(fields)]
			if group == nil {
				group = &ObjGroup{MaterialName: materialName}
				o.Groups = append(o.Groups, group)
			}
			group.faces = append(group.faces, faces)

		// New group, with a name.
		case "g":
			group = &ObjGroup{Name: fields[1], MaterialName: materialName}
			o.Groups = append(o.Groups, group)

		// Object name. The obj will only have one object statement.
		case "o":
			o.Name = fields[1]

		// Material library. I'm not handling this for now. Instead, call
		// SetMaterial() for each of the named materials.
		// case "mtllib":

		// Specifies the material for the current group (and any future groups
		// that don't have their own usemtl statement).
		case "usemtl":
			materialName = fields[1]
			if group != nil {
				group.MaterialName = materialName
			}
		}
	}
	if err := scanner.Err(); err != nil {
		return err
	}

	// Normalize the vertices. OBJ does two things that cause problems for
	// modern renderers: it allows faces to be polygons, instead of only
	// triangles; and it allows each face vertex to have a different index
	// for each stream (position, normal, uv).
	//
	// This code creates triangle fans out of any faces that have more than
	// three vertexes, and merges distinct groupings of pos/normal/uv into
	// a single vertex stream.
	var faceIndices [3]uint16 = [3]uint16{0, 0, 0}
	o.tupleIndex = 0
	for _, g := range o.Groups {
		for _, f := range g.faces {
			for i := 1; i < len(f)-1; i++ {
				var err error
				if faceIndices[0], err = o.mergeTuple(f[i], positions, normals, texcoords); err != nil {
					return err
				}
				if faceIndices[1], err = o.mergeTuple(f[0], positions, normals, texcoords); err != nil {
					return err
				}
				if faceIndices[2], err = o.mergeTuple(f[i+1], positions, normals, texcoords); err != nil {
					return err
				}
				g.indices = append(g.indices, faceIndices[0], faceIndices[1], faceIndices[2])
			}
		}
		g.IndexBuffer = gl.CreateBuffer()
		gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, g.IndexBuffer)
		gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, g.indices, gl.STATIC_DRAW)
		g.NumIndices = len(g.indices)
	}

	o.VertexBuffer = gl.CreateBuffer()
	gl.BindBuffer(gl.ARRAY_BUFFER, o.VertexBuffer)
	gl.BufferData(gl.ARRAY_BUFFER, o.vertices, gl.STATIC_DRAW)

	return nil
}