Example #1
0
func getShader(gl *webgl.Context, typ int, source string) (*js.Object, bool) {
	shader := gl.CreateShader(typ)

	gl.ShaderSource(shader, source)
	gl.CompileShader(shader)

	if !gl.GetShaderParameter(shader, gl.COMPILE_STATUS).Bool() {
		js.Global.Call("alert", gl.GetShaderInfoLog(shader))
		return nil, false
	}
	return shader, true
}
Example #2
0
func setResolution(
	gl *webgl.Context, canvas *js.Object, uResolution *js.Object) {
	width := canvas.Get("clientWidth").Int()
	height := canvas.Get("clientHeight").Int()

	if (canvas.Get("width").Int() != width) ||
		(canvas.Get("height").Int() != height) {
		canvas.Set("width", width)
		canvas.Set("height", height)
	}
	gl.Viewport(0, 0, width, height)
	gl.Uniform2f(uResolution, float32(width), float32(height))
}
Example #3
0
func setupConnection(gl *webgl.Context) {
	document := js.Global.Get("document")
	location := document.Get("location")

	ws, err := websocket.New(fmt.Sprintf("ws://%s/render", location.Get("host")))
	assert(err)

	renderer := make(chan struct{})

	onOpen := func(ev *js.Object) {
		setup := setupMessage{
			Resolution: imgCmResolution,
			ClearColor: [4]byte{127, 127, 127, 255},
		}

		msg, err := json.Marshal(setup)
		assert(err)

		assert(ws.Send(string(msg)))

		go updateCamera(ws, gl, renderer)
	}

	onMessage := func(ev *js.Object) {
		face := frameId % 6
		fmt.Println("Received face:", face)

		data := js.Global.Get("Uint8Array").New(ev.Get("data"))
		gl.Call("texImage2D", gl.TEXTURE_CUBE_MAP_POSITIVE_X+face, 0, gl.RGBA, imgCmResolution, imgCmResolution, 0, gl.RGBA, gl.UNSIGNED_BYTE, data)
		frameId++

		select {
		case renderer <- struct{}{}:
		default:
		}
	}

	ws.BinaryType = "arraybuffer"
	ws.AddEventListener("open", false, onOpen)
	ws.AddEventListener("message", false, onMessage)
}
Example #4
0
func initShader(gl *webgl.Context, canvas *js.Object) (*js.Object, bool) {
	shader := gl.CreateProgram()
	vertexShader, ok := getShader(gl, gl.VERTEX_SHADER, vertexShaderSource)
	if !ok {
		js.Global.Call("alert", "Error getting vertex shader")
		return nil, false
	}
	fragShader, ok := getShader(gl, gl.FRAGMENT_SHADER, fragShaderSource)
	if !ok {
		js.Global.Call("alert", "Error getting fragment shader")
		return nil, false
	}
	gl.AttachShader(shader, vertexShader)
	gl.AttachShader(shader, fragShader)
	gl.LinkProgram(shader)
	if !gl.GetProgramParameterb(shader, gl.LINK_STATUS) {
		js.Global.Call("alert", "couldnt init shaders :(")
		return nil, false
	}
	gl.UseProgram(shader)

	return shader, true
}
Example #5
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
}
Example #6
0
func setupShaders(gl *webgl.Context) *js.Object {
	vs := gl.CreateShader(gl.VERTEX_SHADER)
	gl.ShaderSource(vs, vsSource)
	gl.CompileShader(vs)

	if gl.GetShaderParameter(vs, gl.COMPILE_STATUS).Bool() == false {
		throw(errors.New(gl.GetShaderInfoLog(vs)))
	}

	ps := gl.CreateShader(gl.FRAGMENT_SHADER)
	gl.ShaderSource(ps, psSource)
	gl.CompileShader(ps)

	if gl.GetShaderParameter(ps, gl.COMPILE_STATUS).Bool() == false {
		throw(errors.New(gl.GetShaderInfoLog(ps)))
	}

	program := gl.CreateProgram()
	gl.AttachShader(program, vs)
	gl.AttachShader(program, ps)

	gl.LinkProgram(program)
	gl.UseProgram(program)
	return program
}
Example #7
0
func updateCamera(ws *websocket.WebSocket, gl *webgl.Context, renderer <-chan struct{}) {
	const tick30hz = (1000 / 30) * time.Millisecond

	var (
		camera    trace.FreeFlightCamera
		oldPos    [3]float32
		positions = make(chan [3]float32, 1)
	)

	positions <- oldPos

	go func() {
		for {
			pos := <-positions
			fmt.Println("New position:", pos)

			m, err := json.Marshal(updateMessage{Position: pos})
			assert(err)
			assert(ws.Send(string(m)))
			<-renderer
		}
	}()

	for _ = range time.Tick(tick30hz) {
		switch {
		case keys[38]: // Up
			camera.YRot += cameraSpeed
		case keys[40]: // Down
			camera.YRot -= cameraSpeed
		case keys[37]: // Left
			camera.XRot += cameraSpeed
		case keys[39]: // Right
			camera.XRot -= cameraSpeed
		case keys[87]: // W
			camera.Move(cameraSpeed)
		case keys[83]: // S
			camera.Move(-cameraSpeed)
		case keys[65]: // A
			camera.Strafe(cameraSpeed)
		case keys[68]: // D
			camera.Strafe(-cameraSpeed)
		case keys[69]: // E
			camera.Lift(cameraSpeed)
		case keys[81]: // Q
			camera.Lift(-cameraSpeed)
		}

		if oldPos != camera.Pos {
			select {
			case positions <- camera.Pos:
				oldPos = camera.Pos
			default:
			}
		}

		mat := mat4.Ident
		mat.AssignEulerRotation(camera.XRot, camera.YRot, 0)
		mat.Transpose()

		gl.UniformMatrix4fv(uniformViewLocation, false, mat.Slice())
		gl.DrawArrays(gl.TRIANGLES, 0, 6)
	}
}
Example #8
0
func setupTextures(gl *webgl.Context, program *js.Object) {
	gl.ActiveTexture(gl.TEXTURE0)
	gl.BindTexture(gl.TEXTURE_CUBE_MAP, gl.CreateTexture())

	for i := 0; i < 6; i++ {
		gl.Call("texImage2D", gl.TEXTURE_CUBE_MAP_POSITIVE_X+i, 0, gl.RGBA, imgCmResolution, imgCmResolution, 0, gl.RGBA, gl.UNSIGNED_BYTE, nil)
	}

	gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR)

	/*
		gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
		gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	*/

	gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
	gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)

	gl.Uniform1i(gl.GetUniformLocation(program, "s_texture"), 0)
}
Example #9
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)
}