// Sets up anything that wouldn't have been loaded from disk, including // all opengl data, and sets up finalizers for that data. func (d *Dictionary) setupGlStuff() { d.dlists = make(map[string]uint32) d.strs = make(map[string]strBuffer) d.pars = make(map[string]strBuffer) // TODO: This finalizer is untested runtime.SetFinalizer(d, func(d *Dictionary) { render.Queue(func() { for _, v := range d.dlists { gl.DeleteLists(gl.Uint(v), 1) } }) }) render.Queue(func() { gl.Enable(gl.TEXTURE_2D) gl.GenTextures(1, (*gl.Uint)(&d.texture)) gl.BindTexture(gl.TEXTURE_2D, gl.Uint(d.texture)) gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) glu.Build2DMipmaps(gl.TEXTURE_2D, 4, d.data.Dx, d.data.Dy, gl.RGBA, d.data.Pix) gl.Disable(gl.TEXTURE_2D) }) }
func EnableShader(name string) { prog_obj, ok := shader_progs[name] if ok { gl.UseProgram(gl.Uint(prog_obj)) } else { gl.UseProgram(0) if name != "" && !warned_names[name] { Warn().Printf("Tried to use unknown shader '%s'", name) warned_names[name] = true } } }
func SetUniformF(shader, variable string, f float32) { prog, ok := shader_progs[shader] if !ok { if !warned_names[shader] { Warn().Printf("Tried to set a uniform in an unknown shader '%s'", shader) warned_names[shader] = true } return } bvariable := []byte(fmt.Sprintf("%s\x00", variable)) loc := gl.GetUniformLocation(gl.Uint(prog), (*gl.Char)(unsafe.Pointer(&bvariable[0]))) gl.Uniform1f(loc, gl.Float(f)) }
func (d *Dictionary) RenderString(s string, x, y, z, height float64, just Justification) { if len(s) == 0 { return } strbuf, ok := d.strs[s] if !ok { defer d.RenderString(s, x, y, z, height, just) } size := unsafe.Sizeof(dictVert{}) scale := height / float64(d.data.Maxy-d.data.Miny) width := float32(d.figureWidth(s) * scale) x_pos := float32(x) switch just { case Center: x_pos -= width / 2 case Right: x_pos -= width } if ok { gl.PushMatrix() defer gl.PopMatrix() gl.Translated(gl.Double(x_pos), gl.Double(y), gl.Double(z)) gl.Scaled(gl.Double(scale), gl.Double(scale), 1) gl.PushAttrib(gl.COLOR_BUFFER_BIT) defer gl.PopAttrib() gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Enable(gl.TEXTURE_2D) gl.BindTexture(gl.TEXTURE_2D, gl.Uint(d.texture)) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(strbuf.vbuffer)) gl.EnableClientState(gl.VERTEX_ARRAY) gl.VertexPointer(2, gl.FLOAT, gl.Sizei(size), nil) gl.EnableClientState(gl.TEXTURE_COORD_ARRAY) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(size), gl.Pointer(unsafe.Offsetof(strbuf.vs[0].u))) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(strbuf.ibuffer)) gl.DrawElements(gl.TRIANGLES, gl.Sizei(len(strbuf.is)), gl.UNSIGNED_SHORT, nil) gl.DisableClientState(gl.VERTEX_ARRAY) gl.DisableClientState(gl.TEXTURE_COORD_ARRAY) return } x_pos = 0 for _, r := range s { info := d.getInfo(r) xleft := x_pos + float32(info.Bounds.Min.X) xright := x_pos + float32(info.Bounds.Max.X) ytop := float32(d.data.Maxy - info.Bounds.Min.Y) ybot := float32(height) + float32(d.data.Miny-info.Bounds.Max.Y) start := uint16(len(strbuf.vs)) strbuf.is = append(strbuf.is, start+0) strbuf.is = append(strbuf.is, start+1) strbuf.is = append(strbuf.is, start+2) strbuf.is = append(strbuf.is, start+0) strbuf.is = append(strbuf.is, start+2) strbuf.is = append(strbuf.is, start+3) strbuf.vs = append(strbuf.vs, dictVert{ x: xleft, y: ybot, u: float32(info.Pos.Min.X) / float32(d.data.Dx), v: float32(info.Pos.Max.Y) / float32(d.data.Dy), }) strbuf.vs = append(strbuf.vs, dictVert{ x: xleft, y: ytop, u: float32(info.Pos.Min.X) / float32(d.data.Dx), v: float32(info.Pos.Min.Y) / float32(d.data.Dy), }) strbuf.vs = append(strbuf.vs, dictVert{ x: xright, y: ytop, u: float32(info.Pos.Max.X) / float32(d.data.Dx), v: float32(info.Pos.Min.Y) / float32(d.data.Dy), }) strbuf.vs = append(strbuf.vs, dictVert{ x: xright, y: ybot, u: float32(info.Pos.Max.X) / float32(d.data.Dx), v: float32(info.Pos.Max.Y) / float32(d.data.Dy), }) x_pos += float32(info.Advance) } gl.GenBuffers(1, (*gl.Uint)(&strbuf.vbuffer)) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(strbuf.vbuffer)) gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(int(size)*len(strbuf.vs)), gl.Pointer(&strbuf.vs[0].x), gl.STATIC_DRAW) gl.GenBuffers(1, (*gl.Uint)(&strbuf.ibuffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(strbuf.ibuffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(strbuf.is[0]))*len(strbuf.is)), gl.Pointer(&strbuf.is[0]), gl.STATIC_DRAW) d.strs[s] = strbuf }
func (room *Room) setupGlStuff() { if room.X == room.gl.x && room.Y == room.gl.y && room.Size.Dx == room.gl.dx && room.Size.Dy == room.gl.dy && room.Wall.Data().Dx() == room.gl.wall_tex_dx && room.Wall.Data().Dy() == room.gl.wall_tex_dy { return } room.gl.x = room.X room.gl.y = room.Y room.gl.dx = room.Size.Dx room.gl.dy = room.Size.Dy room.gl.wall_tex_dx = room.Wall.Data().Dx() room.gl.wall_tex_dy = room.Wall.Data().Dy() if room.vbuffer != 0 { gl.DeleteBuffers(1, (*gl.Uint)(&room.vbuffer)) gl.DeleteBuffers(1, (*gl.Uint)(&room.left_buffer)) gl.DeleteBuffers(1, (*gl.Uint)(&room.right_buffer)) gl.DeleteBuffers(1, (*gl.Uint)(&room.floor_buffer)) } dx := float32(room.Size.Dx) dy := float32(room.Size.Dy) var dz float32 if room.Wall.Data().Dx() > 0 { dz = -float32(room.Wall.Data().Dy()*(room.Size.Dx+room.Size.Dy)) / float32(room.Wall.Data().Dx()) } // Conveniently casted values frx := float32(room.X) fry := float32(room.Y) frdx := float32(room.Size.Dx) frdy := float32(room.Size.Dy) // c is the u-texcoord of the corner of the room c := frdx / (frdx + frdy) // lt_llx := frx / LosTextureSize // lt_lly := fry / LosTextureSize // lt_urx := (frx + frdx) / LosTextureSize // lt_ury := (fry + frdy) / LosTextureSize lt_llx_ep := (frx + 0.5) / LosTextureSize lt_lly_ep := (fry + 0.5) / LosTextureSize lt_urx_ep := (frx + frdx - 0.5) / LosTextureSize lt_ury_ep := (fry + frdy - 0.5) / LosTextureSize vs := []roomVertex{ // Walls {0, dy, 0, 0, 1, lt_ury_ep, lt_llx_ep}, {dx, dy, 0, c, 1, lt_ury_ep, lt_urx_ep}, {dx, 0, 0, 1, 1, lt_lly_ep, lt_urx_ep}, {0, dy, dz, 0, 0, lt_ury_ep, lt_llx_ep}, {dx, dy, dz, c, 0, lt_ury_ep, lt_urx_ep}, {dx, 0, dz, 1, 0, lt_lly_ep, lt_urx_ep}, // Floor // This is the bulk of the floor, containing all but the outer edges of // the room. los_tex can map directly onto this so we don't need to do // anything weird here. {0.5, 0.5, 0, 0.5 / dx, 1 - 0.5/dy, lt_lly_ep, lt_llx_ep}, {0.5, dy - 0.5, 0, 0.5 / dx, 0.5 / dy, lt_ury_ep, lt_llx_ep}, {dx - 0.5, dy - 0.5, 0, 1 - 0.5/dx, 0.5 / dy, lt_ury_ep, lt_urx_ep}, {dx - 0.5, 0.5, 0, 1 - 0.5/dx, 1 - 0.5/dy, lt_lly_ep, lt_urx_ep}, {0, 0.5, 0, 0, 1 - 0.5/dy, lt_lly_ep, lt_llx_ep}, {0, dy - 0.5, 0, 0, 0.5 / dy, lt_ury_ep, lt_llx_ep}, {0.5, dy - 0.5, 0, 0.5 / dx, 0.5 / dy, lt_ury_ep, lt_llx_ep}, {0.5, 0.5, 0, 0.5 / dx, 1 - 0.5/dy, lt_lly_ep, lt_llx_ep}, {0.5, 0, 0, 0.5 / dx, 1, lt_lly_ep, lt_llx_ep}, {0.5, 0.5, 0, 0.5 / dx, 1 - 0.5/dy, lt_lly_ep, lt_llx_ep}, {dx - 0.5, 0.5, 0, 1 - 0.5/dx, 1 - 0.5/dy, lt_lly_ep, lt_urx_ep}, {dx - 0.5, 0, 0, 1 - 0.5/dx, 1, lt_lly_ep, lt_urx_ep}, {dx - 0.5, 0.5, 0, 1 - 0.5/dx, 1 - 0.5/dy, lt_lly_ep, lt_urx_ep}, {dx - 0.5, dy - 0.5, 0, 1 - 0.5/dx, 0.5 / dy, lt_ury_ep, lt_urx_ep}, {dx, dy - 0.5, 0, 1, 0.5 / dy, lt_ury_ep, lt_urx_ep}, {dx, 0.5, 0, 1, 1 - 0.5/dy, lt_lly_ep, lt_urx_ep}, {0.5, dy - 0.5, 0, 0.5 / dx, 0.5 / dy, lt_ury_ep, lt_llx_ep}, {0.5, dy, 0, 0.5 / dx, 0, lt_ury_ep, lt_llx_ep}, {dx - 0.5, dy, 0, 1 - 0.5/dx, 0, lt_ury_ep, lt_urx_ep}, {dx - 0.5, dy - 0.5, 0, 1 - 0.5/dx, 0.5 / dy, lt_ury_ep, lt_urx_ep}, {0, 0, 0, 0, 1, lt_lly_ep, lt_llx_ep}, {0, 0.5, 0, 0, 1 - 0.5/dy, lt_lly_ep, lt_llx_ep}, {0.5, 0.5, 0, 0.5 / dx, 1 - 0.5/dy, lt_lly_ep, lt_llx_ep}, {0.5, 0, 0, 0.5 / dx, 1, lt_lly_ep, lt_llx_ep}, {0, dy - 0.5, 0, 0, 0.5 / dy, lt_ury_ep, lt_llx_ep}, {0, dy, 0, 0, 0, lt_ury_ep, lt_llx_ep}, {0.5, dy, 0, 0.5 / dx, 0, lt_ury_ep, lt_llx_ep}, {0.5, dy - 0.5, 0, 0.5 / dx, 0.5 / dy, lt_ury_ep, lt_llx_ep}, {dx - 0.5, dy - 0.5, 0, 1 - 0.5/dx, 0.5 / dy, lt_ury_ep, lt_urx_ep}, {dx - 0.5, dy, 0, 1 - 0.5/dx, 0, lt_ury_ep, lt_urx_ep}, {dx, dy, 0, 1, 0, lt_ury_ep, lt_urx_ep}, {dx, dy - 0.5, 0, 1, 0.5 / dy, lt_ury_ep, lt_urx_ep}, {dx - 0.5, 0, 0, 1 - 0.5/dx, 1, lt_lly_ep, lt_urx_ep}, {dx - 0.5, 0.5, 0, 1 - 0.5/dx, 1 - 0.5/dy, lt_lly_ep, lt_urx_ep}, {dx, 0.5, 0, 1, 1 - 0.5/dy, lt_lly_ep, lt_urx_ep}, {dx, 0, 0, 1, 1, lt_lly_ep, lt_urx_ep}, } gl.GenBuffers(1, (*gl.Uint)(&room.vbuffer)) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(room.vbuffer)) size := int(unsafe.Sizeof(roomVertex{})) gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(size*len(vs)), gl.Pointer(&vs[0].x), gl.STATIC_DRAW) // left wall indices is := []uint16{0, 3, 4, 0, 4, 1} gl.GenBuffers(1, (*gl.Uint)(&room.left_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(room.left_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is)), gl.Pointer(&is[0]), gl.STATIC_DRAW) // right wall indices is = []uint16{1, 4, 5, 1, 5, 2} gl.GenBuffers(1, (*gl.Uint)(&room.right_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(room.right_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is)), gl.Pointer(&is[0]), gl.STATIC_DRAW) // floor indices is = []uint16{ 6, 7, 8, 6, 8, 9, // middle 10, 11, 12, 10, 12, 13, // left side 14, 15, 16, 14, 16, 17, // bottom side 18, 19, 20, 18, 20, 21, // right side 22, 23, 24, 22, 24, 25, // top side 26, 27, 28, 26, 28, 29, // bottom left corner 30, 31, 32, 30, 32, 33, // upper left corner 34, 35, 36, 34, 36, 37, // upper right corner 38, 39, 40, 38, 40, 41, // lower right corner } gl.GenBuffers(1, (*gl.Uint)(&room.floor_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(room.floor_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is)), gl.Pointer(&is[0]), gl.STATIC_DRAW) room.floor_count = len(is) }
// Need floor, right wall, and left wall matrices to draw the details func (room *Room) render(floor, left, right mathgl.Mat4, zoom float32, base_alpha byte, drawables []Drawable, los_tex *LosTexture, floor_drawers []FloorDrawer) { do_color := func(r, g, b, a byte) { R, G, B, A := room.Color() A = alphaMult(A, base_alpha) gl.Color4ub(gl.Ubyte(alphaMult(R, r)), gl.Ubyte(alphaMult(G, g)), gl.Ubyte(alphaMult(B, b)), gl.Ubyte(alphaMult(A, a))) } gl.Enable(gl.TEXTURE_2D) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.Enable(gl.STENCIL_TEST) gl.ClearStencil(0) gl.Clear(gl.STENCIL_BUFFER_BIT) gl.EnableClientState(gl.VERTEX_ARRAY) gl.EnableClientState(gl.TEXTURE_COORD_ARRAY) defer gl.DisableClientState(gl.VERTEX_ARRAY) defer gl.DisableClientState(gl.TEXTURE_COORD_ARRAY) var vert roomVertex planes := []plane{ {room.left_buffer, room.Wall, &left}, {room.right_buffer, room.Wall, &right}, {room.floor_buffer, room.Floor, &floor}, } gl.PushMatrix() defer gl.PopMatrix() if los_tex != nil { gl.LoadMatrixf((*gl.Float)(&floor[0])) gl.ClientActiveTexture(gl.TEXTURE1) gl.ActiveTexture(gl.TEXTURE1) gl.Enable(gl.TEXTURE_2D) gl.EnableClientState(gl.TEXTURE_COORD_ARRAY) los_tex.Bind() gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(room.vbuffer)) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.los_u))) gl.ClientActiveTexture(gl.TEXTURE0) gl.ActiveTexture(gl.TEXTURE0) base.EnableShader("los") base.SetUniformI("los", "tex2", 1) } var mul, run mathgl.Mat4 for _, plane := range planes { gl.LoadMatrixf((*gl.Float)(&floor[0])) run.Assign(&floor) // Render the doors and cut out the stencil buffer so we leave them empty // if they're open switch plane.mat { case &left: gl.StencilFunc(gl.ALWAYS, 1, 1) gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) for _, door := range room.Doors { if door.Facing != FarLeft { continue } door.TextureData().Bind() R, G, B, A := door.Color() do_color(R, G, B, alphaMult(A, room.far_left.wall_alpha)) gl.ClientActiveTexture(gl.TEXTURE0) door.TextureData().Bind() if door.door_glids.floor_buffer != 0 { gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(door.threshold_glids.vbuffer)) gl.VertexPointer(3, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.x))) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(door.door_glids.floor_buffer)) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.u))) gl.ClientActiveTexture(gl.TEXTURE1) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.los_u))) gl.DrawElements(gl.TRIANGLES, door.door_glids.floor_count, gl.UNSIGNED_SHORT, nil) } } gl.StencilFunc(gl.NOTEQUAL, 1, 1) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) do_color(255, 255, 255, room.far_left.wall_alpha) case &right: gl.StencilFunc(gl.ALWAYS, 1, 1) gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) for _, door := range room.Doors { if door.Facing != FarRight { continue } door.TextureData().Bind() R, G, B, A := door.Color() do_color(R, G, B, alphaMult(A, room.far_right.wall_alpha)) gl.ClientActiveTexture(gl.TEXTURE0) door.TextureData().Bind() if door.door_glids.floor_buffer != 0 { gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(door.threshold_glids.vbuffer)) gl.VertexPointer(3, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.x))) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(door.door_glids.floor_buffer)) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.u))) gl.ClientActiveTexture(gl.TEXTURE1) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.los_u))) gl.DrawElements(gl.TRIANGLES, door.door_glids.floor_count, gl.UNSIGNED_SHORT, nil) } } gl.StencilFunc(gl.NOTEQUAL, 1, 1) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) do_color(255, 255, 255, room.far_right.wall_alpha) case &floor: gl.StencilFunc(gl.ALWAYS, 2, 2) gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE) do_color(255, 255, 255, 255) } gl.ClientActiveTexture(gl.TEXTURE0) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(room.vbuffer)) gl.VertexPointer(3, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.x))) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.u))) gl.ClientActiveTexture(gl.TEXTURE1) if los_tex != nil { los_tex.Bind() } gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(room.vbuffer)) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.los_u))) // Now draw the walls gl.LoadMatrixf((*gl.Float)(&floor[0])) plane.texture.Data().Bind() gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(plane.index_buffer)) if (plane.mat == &left || plane.mat == &right) && strings.Contains(string(room.Wall.Path), "gradient.png") { base.EnableShader("gorey") base.SetUniformI("gorey", "tex", 0) base.SetUniformI("gorey", "foo", Foo) base.SetUniformF("gorey", "num_rows", Num_rows) base.SetUniformF("gorey", "noise_rate", Noise_rate) base.SetUniformF("gorey", "num_steps", Num_steps) } if plane.mat == &floor && strings.Contains(string(room.Floor.Path), "gradient.png") { base.EnableShader("gorey") base.SetUniformI("gorey", "tex", 0) base.SetUniformI("gorey", "foo", Foo) base.SetUniformF("gorey", "num_rows", Num_rows) base.SetUniformF("gorey", "noise_rate", Noise_rate) base.SetUniformF("gorey", "num_steps", Num_steps) zexp := math.Log(float64(zoom)) frac := 1 - 1/zexp frac = (frac - 0.6) * 5.0 switch { case frac > 0.7: base.SetUniformI("gorey", "range", 1) case frac > 0.3: base.SetUniformI("gorey", "range", 2) default: base.SetUniformI("gorey", "range", 3) } } if plane.mat == &floor { R, G, B, _ := room.Color() gl.Color4ub(gl.Ubyte(R), gl.Ubyte(G), gl.Ubyte(B), 255) } gl.DrawElements(gl.TRIANGLES, gl.Sizei(room.floor_count), gl.UNSIGNED_SHORT, nil) if los_tex != nil { base.EnableShader("los") } else { base.EnableShader("") } } for _, wt := range room.WallTextures { if room.wall_texture_gl_map == nil { room.wall_texture_gl_map = make(map[*WallTexture]wallTextureGlIds) room.wall_texture_state_map = make(map[*WallTexture]wallTextureState) } ids := room.wall_texture_gl_map[wt] state := room.wall_texture_state_map[wt] var new_state wallTextureState new_state.flip = wt.Flip new_state.rot = wt.Rot new_state.x = wt.X new_state.y = wt.Y new_state.room.x = room.X new_state.room.y = room.Y new_state.room.dx = room.Size.Dx new_state.room.dy = room.Size.Dy if new_state != state { wt.setupGlStuff(room.X, room.Y, room.Size.Dx, room.Size.Dy, &ids) room.wall_texture_gl_map[wt] = ids room.wall_texture_state_map[wt] = new_state } gl.LoadMatrixf((*gl.Float)(&floor[0])) if ids.vbuffer != 0 { wt.Texture.Data().Bind() R, G, B, A := wt.Color() gl.ClientActiveTexture(gl.TEXTURE0) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(ids.vbuffer)) gl.VertexPointer(3, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.x))) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.u))) gl.ClientActiveTexture(gl.TEXTURE1) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.los_u))) gl.ClientActiveTexture(gl.TEXTURE0) if ids.floor_buffer != 0 { gl.StencilFunc(gl.ALWAYS, 2, 2) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(ids.floor_buffer)) gl.Color4ub(gl.Ubyte(R), gl.Ubyte(G), gl.Ubyte(B), gl.Ubyte(A)) gl.DrawElements(gl.TRIANGLES, ids.floor_count, gl.UNSIGNED_SHORT, nil) } if ids.left_buffer != 0 { gl.StencilFunc(gl.ALWAYS, 1, 1) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(ids.left_buffer)) do_color(R, G, B, alphaMult(A, room.far_left.wall_alpha)) gl.DrawElements(gl.TRIANGLES, ids.left_count, gl.UNSIGNED_SHORT, nil) } if ids.right_buffer != 0 { gl.StencilFunc(gl.ALWAYS, 1, 1) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(ids.right_buffer)) do_color(R, G, B, alphaMult(A, room.far_right.wall_alpha)) gl.DrawElements(gl.TRIANGLES, ids.right_count, gl.UNSIGNED_SHORT, nil) } } } base.EnableShader("marble") base.SetUniformI("marble", "tex2", 1) base.SetUniformF("marble", "room_x", float32(room.X)) base.SetUniformF("marble", "room_y", float32(room.Y)) for _, door := range room.Doors { door.setupGlStuff(room) if door.threshold_glids.vbuffer == 0 { continue } if door.AlwaysOpen() { continue } if door.highlight_threshold { gl.Color4ub(255, 255, 255, 255) } else { gl.Color4ub(128, 128, 128, 255) } gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(door.threshold_glids.vbuffer)) gl.VertexPointer(3, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.x))) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.u))) gl.ClientActiveTexture(gl.TEXTURE1) gl.TexCoordPointer(2, gl.FLOAT, gl.Sizei(unsafe.Sizeof(vert)), gl.Pointer(unsafe.Offsetof(vert.los_u))) gl.ClientActiveTexture(gl.TEXTURE0) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(door.threshold_glids.floor_buffer)) gl.DrawElements(gl.TRIANGLES, door.threshold_glids.floor_count, gl.UNSIGNED_SHORT, nil) } base.EnableShader("") if los_tex != nil { base.EnableShader("") gl.ActiveTexture(gl.TEXTURE1) gl.Disable(gl.TEXTURE_2D) gl.ActiveTexture(gl.TEXTURE0) gl.ClientActiveTexture(gl.TEXTURE1) gl.DisableClientState(gl.TEXTURE_COORD_ARRAY) gl.ClientActiveTexture(gl.TEXTURE0) } run.Assign(&floor) mul.Translation(float32(-room.X), float32(-room.Y), 0) run.Multiply(&mul) gl.LoadMatrixf((*gl.Float)(&run[0])) gl.StencilFunc(gl.EQUAL, 2, 3) gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP) room_rect := image.Rect(room.X, room.Y, room.X+room.Size.Dx, room.Y+room.Size.Dy) for _, fd := range floor_drawers { x, y := fd.Pos() dx, dy := fd.Dims() if room_rect.Overlaps(image.Rect(x, y, x+dx, y+dy)) { fd.RenderOnFloor() } } do_color(255, 255, 255, 255) gl.LoadIdentity() gl.Disable(gl.STENCIL_TEST) room.renderFurniture(floor, 255, drawables, los_tex) gl.ClientActiveTexture(gl.TEXTURE1) gl.Disable(gl.TEXTURE_2D) gl.ClientActiveTexture(gl.TEXTURE0) base.EnableShader("") }
func (d *Door) setupGlStuff(room *Room) { var state doorState state.facing = d.Facing state.pos = d.Pos state.room.x = room.X state.room.y = room.Y state.room.dx = room.roomDef.Size.Dx state.room.dy = room.roomDef.Size.Dy if state == d.state { return } if d.TextureData().Dy() == 0 { // Can't build this data until the texture is loaded, so we'll have to try // again later. return } d.state = state if d.threshold_glids.vbuffer != 0 { gl.DeleteBuffers(1, (*gl.Uint)(&d.threshold_glids.vbuffer)) gl.DeleteBuffers(1, (*gl.Uint)(&d.threshold_glids.floor_buffer)) d.threshold_glids.vbuffer = 0 d.threshold_glids.floor_buffer = 0 } if d.door_glids.vbuffer != 0 { gl.DeleteBuffers(1, (*gl.Uint)(&d.door_glids.vbuffer)) gl.DeleteBuffers(1, (*gl.Uint)(&d.door_glids.floor_buffer)) d.door_glids.vbuffer = 0 d.door_glids.floor_buffer = 0 } // far left, near right, do threshold // near left, far right, do threshold // far left, far right, do door var vs []roomVertex if d.Facing == FarLeft || d.Facing == NearRight { x1 := float32(d.Pos) x2 := float32(d.Pos + d.Width) var y1 float32 = -0.25 var y2 float32 = 0.25 if d.Facing == FarLeft { y1 = float32(room.roomDef.Size.Dy) y2 = float32(room.roomDef.Size.Dy) - 0.25 } // los_x1 := (x1 + float32(room.X)) / LosTextureSize vs = append(vs, roomVertex{x: x1, y: y1}) vs = append(vs, roomVertex{x: x1, y: y2}) vs = append(vs, roomVertex{x: x2, y: y2}) vs = append(vs, roomVertex{x: x2, y: y1}) for i := 0; i < 4; i++ { vs[i].los_u = (y2 + float32(room.Y)) / LosTextureSize vs[i].los_v = (vs[i].x + float32(room.X)) / LosTextureSize } } if d.Facing == FarRight || d.Facing == NearLeft { y1 := float32(d.Pos) y2 := float32(d.Pos + d.Width) var x1 float32 = -0.25 var x2 float32 = 0.25 if d.Facing == FarRight { x1 = float32(room.roomDef.Size.Dx) x2 = float32(room.roomDef.Size.Dx) - 0.25 } // los_y1 := (y1 + float32(room.Y)) / LosTextureSize vs = append(vs, roomVertex{x: x1, y: y1}) vs = append(vs, roomVertex{x: x1, y: y2}) vs = append(vs, roomVertex{x: x2, y: y2}) vs = append(vs, roomVertex{x: x2, y: y1}) for i := 0; i < 4; i++ { vs[i].los_u = (vs[i].y + float32(room.Y)) / LosTextureSize vs[i].los_v = (x2 + float32(room.X)) / LosTextureSize } } dz := -float32(d.Width*d.TextureData().Dy()) / float32(d.TextureData().Dx()) if d.Facing == FarRight { x := float32(room.roomDef.Size.Dx) y1 := float32(d.Pos + d.Width) y2 := float32(d.Pos) los_v := (float32(room.X) + x - 0.5) / LosTextureSize los_u1 := (float32(room.Y) + y1) / LosTextureSize los_u2 := (float32(room.Y) + y2) / LosTextureSize vs = append(vs, roomVertex{ x: x, y: y1, z: 0, u: 0, v: 1, los_u: los_u1, los_v: los_v, }) vs = append(vs, roomVertex{ x: x, y: y1, z: dz, u: 0, v: 0, los_u: los_u1, los_v: los_v, }) vs = append(vs, roomVertex{ x: x, y: y2, z: dz, u: 1, v: 0, los_u: los_u2, los_v: los_v, }) vs = append(vs, roomVertex{ x: x, y: y2, z: 0, u: 1, v: 1, los_u: los_u2, los_v: los_v, }) } if d.Facing == FarLeft { x1 := float32(d.Pos) x2 := float32(d.Pos + d.Width) y := float32(room.roomDef.Size.Dy) los_v1 := (float32(room.X) + x1) / LosTextureSize los_v2 := (float32(room.X) + x2) / LosTextureSize los_u := (float32(room.Y) + y - 0.5) / LosTextureSize vs = append(vs, roomVertex{ x: x1, y: y, z: 0, u: 0, v: 1, los_u: los_u, los_v: los_v1, }) vs = append(vs, roomVertex{ x: x1, y: y, z: dz, u: 0, v: 0, los_u: los_u, los_v: los_v1, }) vs = append(vs, roomVertex{ x: x2, y: y, z: dz, u: 1, v: 0, los_u: los_u, los_v: los_v2, }) vs = append(vs, roomVertex{ x: x2, y: y, z: 0, u: 1, v: 1, los_u: los_u, los_v: los_v2, }) } gl.GenBuffers(1, (*gl.Uint)(&d.threshold_glids.vbuffer)) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(d.threshold_glids.vbuffer)) size := int(unsafe.Sizeof(roomVertex{})) gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(size*len(vs)), gl.Pointer(&vs[0].x), gl.STATIC_DRAW) is := []uint16{0, 1, 2, 0, 2, 3} gl.GenBuffers(1, (*gl.Uint)(&d.threshold_glids.floor_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(d.threshold_glids.floor_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is)), gl.Pointer(&is[0]), gl.STATIC_DRAW) d.threshold_glids.floor_count = 6 if d.Facing == FarLeft || d.Facing == FarRight { is2 := []uint16{4, 5, 6, 4, 6, 7} gl.GenBuffers(1, (*gl.Uint)(&d.door_glids.floor_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(d.door_glids.floor_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is2)), gl.Pointer(&is2[0]), gl.STATIC_DRAW) d.door_glids.floor_count = 6 } }
func (wt *WallTexture) setupGlStuff(x, y, dx, dy int, gl_ids *wallTextureGlIds) { if gl_ids.vbuffer != 0 { gl.DeleteBuffers(1, (*gl.Uint)(&gl_ids.vbuffer)) gl.DeleteBuffers(1, (*gl.Uint)(&gl_ids.left_buffer)) gl.DeleteBuffers(1, (*gl.Uint)(&gl_ids.right_buffer)) gl.DeleteBuffers(1, (*gl.Uint)(&gl_ids.floor_buffer)) gl_ids.vbuffer = 0 gl_ids.left_buffer = 0 gl_ids.right_buffer = 0 gl_ids.floor_buffer = 0 } // All vertices for both walls and the floor will go here and get sent to // opengl all at once var vs []roomVertex // Conveniently casted values frx := float32(x) fry := float32(y) frdx := float32(dx) frdy := float32(dy) tdx := float32(wt.Texture.Data().Dx()) / 100 tdy := float32(wt.Texture.Data().Dy()) / 100 wtx := wt.X wty := wt.Y wtr := wt.Rot if wtx > frdx { wtr -= 3.1415926535 / 2 } // Floor verts := []mathgl.Vec2{ {-tdx / 2, -tdy / 2}, {-tdx / 2, tdy / 2}, {tdx / 2, tdy / 2}, {tdx / 2, -tdy / 2}, } var m, run mathgl.Mat3 run.Identity() m.Translation(wtx, wty) run.Multiply(&m) m.RotationZ(wtr) run.Multiply(&m) if wt.Flip { m.Scaling(-1, 1) run.Multiply(&m) } for i := range verts { verts[i].Transform(&run) } p := mathgl.Poly(verts) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{0, 0}, B: mathgl.Vec2{0, frdy}}) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{0, frdy}, B: mathgl.Vec2{frdx, frdy}}) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{frdx, frdy}, B: mathgl.Vec2{frdx, 0}}) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{frdx, 0}, B: mathgl.Vec2{0, 0}}) if len(p) >= 3 { // floor indices var is []uint16 for i := 1; i < len(p)-1; i++ { is = append(is, uint16(len(vs)+0)) is = append(is, uint16(len(vs)+i)) is = append(is, uint16(len(vs)+i+1)) } gl.GenBuffers(1, (*gl.Uint)(&gl_ids.floor_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(gl_ids.floor_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is)), gl.Pointer(&is[0]), gl.STATIC_DRAW) gl_ids.floor_count = gl.Sizei(len(is)) run.Inverse() for i := range p { v := mathgl.Vec2{p[i].X, p[i].Y} v.Transform(&run) vs = append(vs, roomVertex{ x: p[i].X, y: p[i].Y, u: v.X/tdx + 0.5, v: -(v.Y/tdy + 0.5), los_u: (fry + p[i].Y) / LosTextureSize, los_v: (frx + p[i].X) / LosTextureSize, }) } } // Left Wall verts = []mathgl.Vec2{ {-tdx / 2, -tdy / 2}, {-tdx / 2, tdy / 2}, {tdx / 2, tdy / 2}, {tdx / 2, -tdy / 2}, } run.Identity() m.Translation(wtx, wty) run.Multiply(&m) m.RotationZ(wtr) run.Multiply(&m) if wt.Flip { m.Scaling(-1, 1) run.Multiply(&m) } for i := range verts { verts[i].Transform(&run) } p = mathgl.Poly(verts) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{0, 0}, B: mathgl.Vec2{0, frdy}}) p.Clip(&mathgl.Seg2{B: mathgl.Vec2{0, frdy}, A: mathgl.Vec2{frdx, frdy}}) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{frdx, frdy}, B: mathgl.Vec2{frdx, 0}}) if len(p) >= 3 { // floor indices var is []uint16 for i := 1; i < len(p)-1; i++ { is = append(is, uint16(len(vs)+0)) is = append(is, uint16(len(vs)+i)) is = append(is, uint16(len(vs)+i+1)) } gl.GenBuffers(1, (*gl.Uint)(&gl_ids.left_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(gl_ids.left_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is)), gl.Pointer(&is[0]), gl.STATIC_DRAW) gl_ids.left_count = gl.Sizei(len(is)) run.Inverse() for i := range p { v := mathgl.Vec2{p[i].X, p[i].Y} v.Transform(&run) vs = append(vs, roomVertex{ x: p[i].X, y: frdy, z: frdy - p[i].Y, u: v.X/tdx + 0.5, v: -(v.Y/tdy + 0.5), los_u: (fry + frdy - 0.5) / LosTextureSize, los_v: (frx + p[i].X) / LosTextureSize, }) } } // Right Wall verts = []mathgl.Vec2{ {-tdx / 2, -tdy / 2}, {-tdx / 2, tdy / 2}, {tdx / 2, tdy / 2}, {tdx / 2, -tdy / 2}, } run.Identity() m.Translation(wtx, wty) run.Multiply(&m) m.RotationZ(wtr) run.Multiply(&m) if wt.Flip { m.Scaling(-1, 1) run.Multiply(&m) } for i := range verts { verts[i].Transform(&run) } p = mathgl.Poly(verts) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{0, frdy}, B: mathgl.Vec2{frdx, frdy}}) p.Clip(&mathgl.Seg2{B: mathgl.Vec2{frdx, frdy}, A: mathgl.Vec2{frdx, 0}}) p.Clip(&mathgl.Seg2{A: mathgl.Vec2{frdx, 0}, B: mathgl.Vec2{0, 0}}) if len(p) >= 3 { // floor indices var is []uint16 for i := 1; i < len(p)-1; i++ { is = append(is, uint16(len(vs)+0)) is = append(is, uint16(len(vs)+i)) is = append(is, uint16(len(vs)+i+1)) } gl.GenBuffers(1, (*gl.Uint)(&gl_ids.right_buffer)) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.Uint(gl_ids.right_buffer)) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, gl.Sizeiptr(int(unsafe.Sizeof(is[0]))*len(is)), gl.Pointer(&is[0]), gl.STATIC_DRAW) gl_ids.right_count = gl.Sizei(len(is)) run.Inverse() for i := range p { v := mathgl.Vec2{p[i].X, p[i].Y} v.Transform(&run) vs = append(vs, roomVertex{ x: frdx, y: p[i].Y, z: frdx - p[i].X, u: v.X/tdx + 0.5, v: -(v.Y/tdy + 0.5), los_u: (fry + p[i].Y) / LosTextureSize, los_v: (frx + frdx - 0.5) / LosTextureSize, }) } } if len(vs) > 0 { gl.GenBuffers(1, (*gl.Uint)(&gl_ids.vbuffer)) gl.BindBuffer(gl.ARRAY_BUFFER, gl.Uint(gl_ids.vbuffer)) size := int(unsafe.Sizeof(roomVertex{})) gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(size*len(vs)), gl.Pointer(&vs[0].x), gl.STATIC_DRAW) } }
func InitShaders() { render.Queue(func() { vertex_shaders = make(map[string]uint32) fragment_shaders = make(map[string]uint32) shader_progs = make(map[string]uint32) warned_names = make(map[string]bool) RemoveRegistry("shaders") RegisterRegistry("shaders", make(map[string]*shaderDef)) RegisterAllObjectsInDir("shaders", filepath.Join(GetDataDir(), "shaders"), ".json", "json") names := GetAllNamesInRegistry("shaders") for _, name := range names { // Load the shader files shader := Shader{Defname: name} GetObject("shaders", &shader) vdata, err := ioutil.ReadFile(filepath.Join(GetDataDir(), shader.Vertex_path)) if err != nil { Error().Printf("Unable to load vertex shader '%s': %v", shader.Vertex_path, err) continue } fdata, err := ioutil.ReadFile(filepath.Join(GetDataDir(), shader.Fragment_path)) if err != nil { Error().Printf("Unable to load fragment shader '%s': %v", shader.Fragment_path, err) continue } // Create the vertex shader vertex_id, ok := vertex_shaders[shader.Vertex_path] if !ok { vertex_id = uint32(gl.CreateShader(gl.VERTEX_SHADER)) pointer := &vdata[0] length := int32(len(vdata)) gl.ShaderSource(gl.Uint(vertex_id), 1, (**gl.Char)(unsafe.Pointer(&pointer)), (*gl.Int)(&length)) gl.CompileShader(gl.Uint(vertex_id)) var param int32 gl.GetShaderiv(gl.Uint(vertex_id), gl.COMPILE_STATUS, (*gl.Int)(¶m)) if param == 0 { Error().Printf("Failed to compile vertex shader '%s': %v", shader.Vertex_path, param) continue } } // Create the fragment shader fragment_id, ok := fragment_shaders[shader.Fragment_path] if !ok { fragment_id = uint32(gl.CreateShader(gl.FRAGMENT_SHADER)) pointer := &fdata[0] length := int32(len(fdata)) gl.ShaderSource(gl.Uint(fragment_id), 1, (**gl.Char)(unsafe.Pointer(&pointer)), (*gl.Int)(&length)) gl.CompileShader(gl.Uint(fragment_id)) var param int32 gl.GetShaderiv(gl.Uint(fragment_id), gl.COMPILE_STATUS, (*gl.Int)(¶m)) if param == 0 { Error().Printf("Failed to compile fragment shader '%s': %v", shader.Fragment_path, param) continue } } // shader successfully compiled - now link program_id := gl.CreateProgram() gl.AttachShader(program_id, gl.Uint(vertex_id)) gl.AttachShader(program_id, gl.Uint(fragment_id)) gl.LinkProgram(program_id) var param int32 gl.GetProgramiv(program_id, gl.LINK_STATUS, (*gl.Int)(¶m)) if param == 0 { Error().Printf("Failed to link shader '%s': %v", shader.Name, param) continue } vertex_shaders[shader.Vertex_path] = vertex_id fragment_shaders[shader.Fragment_path] = fragment_id shader_progs[shader.Name] = uint32(program_id) } }) }