func (l *legacyShader) Pre() { Gl.Enable(Gl.BLEND) Gl.BlendFunc(Gl.SRC_ALPHA, Gl.ONE_MINUS_SRC_ALPHA) // Bind shader and buffer, enable attributes Gl.UseProgram(l.program) Gl.EnableVertexAttribArray(l.inPosition) Gl.EnableVertexAttribArray(l.inColor) if scaleOnResize { l.projectionMatrix[0] = 1 / (gameWidth / 2) l.projectionMatrix[4] = 1 / (-gameHeight / 2) } else { l.projectionMatrix[0] = 1 / (windowWidth / 2) // TODO: canvasWidth l.projectionMatrix[4] = 1 / (-windowHeight / 2) // TODO: canvasHeight } if l.cameraEnabled { l.viewMatrix[1], l.viewMatrix[0] = math.Sincos(cam.angle * math.Pi / 180) l.viewMatrix[3] = -l.viewMatrix[1] l.viewMatrix[4] = l.viewMatrix[0] l.viewMatrix[6] = -cam.x l.viewMatrix[7] = -cam.y l.viewMatrix[8] = cam.z } else { l.viewMatrix[6] = -1 / l.projectionMatrix[0] l.viewMatrix[7] = 1 / l.projectionMatrix[4] } Gl.UniformMatrix3fv(l.matrixProjection, false, l.projectionMatrix) Gl.UniformMatrix3fv(l.matrixView, false, l.viewMatrix) Gl.Uniform2f(l.inViewport, gameWidth, gameHeight) // TODO: canvasWidth/Height }
func (s *basicShader) Pre() { Gl.Enable(Gl.BLEND) Gl.BlendFunc(Gl.SRC_ALPHA, Gl.ONE_MINUS_SRC_ALPHA) // Enable shader and buffer, enable attributes in shader Gl.UseProgram(s.program) Gl.BindBuffer(Gl.ELEMENT_ARRAY_BUFFER, s.indexVBO) Gl.EnableVertexAttribArray(s.inPosition) Gl.EnableVertexAttribArray(s.inTexCoords) Gl.EnableVertexAttribArray(s.inColor) if scaleOnResize { s.projectionMatrix[0] = 1 / (gameWidth / 2) s.projectionMatrix[4] = 1 / (-gameHeight / 2) } else { s.projectionMatrix[0] = 1 / (windowWidth / 2) s.projectionMatrix[4] = 1 / (-windowHeight / 2) } if s.cameraEnabled { s.viewMatrix[1], s.viewMatrix[0] = math.Sincos(cam.angle * math.Pi / 180) s.viewMatrix[3] = -s.viewMatrix[1] s.viewMatrix[4] = s.viewMatrix[0] s.viewMatrix[6] = -cam.x s.viewMatrix[7] = -cam.y s.viewMatrix[8] = cam.z } else { s.viewMatrix[6] = -1 / s.projectionMatrix[0] s.viewMatrix[7] = 1 / s.projectionMatrix[4] } Gl.UniformMatrix3fv(s.matrixProjection, false, s.projectionMatrix) Gl.UniformMatrix3fv(s.matrixView, false, s.viewMatrix) }
func (s *basicShader) Draw(ren *RenderComponent, space *SpaceComponent) { if s.lastBuffer != ren.buffer || ren.buffer == nil { s.updateBuffer(ren) Gl.BindBuffer(Gl.ARRAY_BUFFER, ren.buffer) Gl.VertexAttribPointer(s.inPosition, 2, Gl.FLOAT, false, 20, 0) Gl.VertexAttribPointer(s.inTexCoords, 2, Gl.FLOAT, false, 20, 8) Gl.VertexAttribPointer(s.inColor, 4, Gl.UNSIGNED_BYTE, true, 20, 16) s.lastBuffer = ren.buffer } if s.lastTexture != ren.Drawable.Texture() { Gl.BindTexture(Gl.TEXTURE_2D, ren.Drawable.Texture()) s.lastTexture = ren.Drawable.Texture() } if s.lastRepeating != ren.Repeat { var val int switch ren.Repeat { case CLAMP_TO_EDGE: val = Gl.CLAMP_TO_EDGE case CLAMP_TO_BORDER: val = Gl.CLAMP_TO_EDGE case REPEAT: val = Gl.REPEAT case MIRRORED_REPEAT: val = Gl.MIRRORED_REPEAT } Gl.TexParameteri(Gl.TEXTURE_2D, Gl.TEXTURE_WRAP_S, val) Gl.TexParameteri(Gl.TEXTURE_2D, Gl.TEXTURE_WRAP_T, val) } if space.Rotation != 0 { sin, cos := math.Sincos(space.Rotation * math.Pi / 180) s.modelMatrix[0] = ren.Scale.X * cos s.modelMatrix[1] = ren.Scale.X * sin s.modelMatrix[3] = ren.Scale.Y * -sin s.modelMatrix[4] = ren.Scale.Y * cos } else { s.modelMatrix[0] = ren.Scale.X s.modelMatrix[1] = 0 s.modelMatrix[3] = 0 s.modelMatrix[4] = ren.Scale.Y } s.modelMatrix[6] = space.Position.X s.modelMatrix[7] = space.Position.Y Gl.UniformMatrix3fv(s.matrixModel, false, s.modelMatrix) Gl.DrawElements(Gl.TRIANGLES, 6, Gl.UNSIGNED_SHORT, 0) }
// AABB returns the minimum and maximum point for the given SpaceComponent. It hereby takes into account the // rotation of the Component - it may very well be that the Minimum as given by AABB, is smaller than the Position // of the object (i.e. when rotated). As this method takes into account the rotation, it should be used only when // required. func (sc SpaceComponent) AABB() AABB { if sc.Rotation == 0 { return AABB{ Min: sc.Position, Max: Point{sc.Position.X + sc.Width, sc.Position.Y + sc.Height}, } } sin, cos := math.Sincos(sc.Rotation * math.Pi / 180) xmin := sc.Position.X xmax := sc.Position.X + sc.Width*cos - sc.Height*sin ymin := sc.Position.Y ymax := sc.Position.Y + sc.Height*cos + sc.Width*sin var ( X_MIN, X_MAX, Y_MIN, Y_MAX float32 ) if xmin < xmax { X_MIN = xmin X_MAX = xmax } else { X_MIN = xmax X_MAX = xmin } if ymin < ymax { Y_MIN = ymin Y_MAX = ymax } else { Y_MIN = ymax Y_MAX = ymin } return AABB{Point{X_MIN, Y_MIN}, Point{X_MAX, Y_MAX}} }
func (l *legacyShader) Draw(ren *RenderComponent, space *SpaceComponent) { if l.lastBuffer != ren.buffer || ren.buffer == nil { l.updateBuffer(ren, space) Gl.BindBuffer(Gl.ARRAY_BUFFER, ren.buffer) Gl.VertexAttribPointer(l.inPosition, 2, Gl.FLOAT, false, 12, 0) Gl.VertexAttribPointer(l.inColor, 4, Gl.UNSIGNED_BYTE, true, 12, 8) l.lastBuffer = ren.buffer } if space.Rotation != 0 { sin, cos := math.Sincos(space.Rotation * math.Pi / 180) l.modelMatrix[0] = ren.Scale.X * cos l.modelMatrix[1] = ren.Scale.X * sin l.modelMatrix[3] = ren.Scale.Y * -sin l.modelMatrix[4] = ren.Scale.Y * cos } else { l.modelMatrix[0] = ren.Scale.X l.modelMatrix[1] = 0 l.modelMatrix[3] = 0 l.modelMatrix[4] = ren.Scale.Y } l.modelMatrix[6] = space.Position.X l.modelMatrix[7] = space.Position.Y Gl.UniformMatrix3fv(l.matrixModel, false, l.modelMatrix) switch shape := ren.Drawable.(type) { case Triangle: Gl.Uniform2f(l.inRadius, 0, 0) Gl.DrawArrays(Gl.TRIANGLES, 0, 3) if shape.BorderWidth > 0 { borderWidth := shape.BorderWidth if l.cameraEnabled { borderWidth /= cam.z } Gl.LineWidth(borderWidth) Gl.DrawArrays(Gl.LINE_LOOP, 3, 3) } case Rectangle: Gl.Uniform2f(l.inRadius, 0, 0) Gl.BindBuffer(Gl.ELEMENT_ARRAY_BUFFER, l.indicesRectanglesVBO) Gl.DrawElements(Gl.TRIANGLES, 6, Gl.UNSIGNED_SHORT, 0) if shape.BorderWidth > 0 { borderWidth := shape.BorderWidth if l.cameraEnabled { borderWidth /= cam.z } Gl.LineWidth(borderWidth) Gl.DrawArrays(Gl.LINE_LOOP, 4, 4) } case Circle: Gl.Uniform1f(l.inBorderWidth, shape.BorderWidth/cam.z) if shape.BorderWidth > 0 { r, g, b, a := shape.BorderColor.RGBA() Gl.Uniform4f(l.inBorderColor, float32(r>>8), float32(g>>8), float32(b>>8), float32(a>>8)) } Gl.Uniform2f(l.inRadius, (space.Width/2)/cam.z, (space.Height/2)/cam.z) Gl.Uniform2f(l.inCenter, space.Width/2, space.Height/2) Gl.BindBuffer(Gl.ELEMENT_ARRAY_BUFFER, l.indicesRectanglesVBO) Gl.DrawElements(Gl.TRIANGLES, 6, Gl.UNSIGNED_SHORT, 0) case ComplexTriangles: Gl.Uniform2f(l.inRadius, 0, 0) Gl.DrawArrays(Gl.TRIANGLES, 0, len(shape.Points)) if shape.BorderWidth > 0 { borderWidth := shape.BorderWidth if l.cameraEnabled { borderWidth /= cam.z } Gl.LineWidth(borderWidth) Gl.DrawArrays(Gl.LINE_LOOP, len(shape.Points), len(shape.Points)) } default: unsupportedType() } }
func (m *MouseSystem) Update(dt float32) { // Translate Mouse.X and Mouse.Y into "game coordinates" m.mouseX = Mouse.X*cam.z*(gameWidth/windowWidth) + cam.x - (gameWidth/2)*cam.z m.mouseY = Mouse.Y*cam.z*(gameHeight/windowHeight) + cam.y - (gameHeight/2)*cam.z // TODO maybe other width/height? // Rotate if needed if cam.angle != 0 { sin, cos := math.Sincos(cam.angle * math.Pi / 180) m.mouseX, m.mouseY = m.mouseX*cos+m.mouseY*sin, m.mouseY*cos-m.mouseX*sin } for _, e := range m.entities { // Reset all values except these *e.MouseComponent = MouseComponent{ Track: e.MouseComponent.Track, Hovered: e.MouseComponent.Hovered, startedDragging: e.MouseComponent.startedDragging, } if e.MouseComponent.Track { // track mouse position so that systems that need to stay on the mouse // position can do it (think an RTS when placing a new building and // you get a ghost building following your mouse until you click to // place it somewhere in your world. e.MouseComponent.MouseX = m.mouseX e.MouseComponent.MouseY = m.mouseY } mx := m.mouseX my := m.mouseY if e.SpaceComponent == nil { continue // with other entities } if e.RenderComponent != nil { // Hardcoded special case for the HUD | TODO: make generic instead of hardcoding if e.RenderComponent.shader == HUDShader { mx = Mouse.X my = Mouse.Y } } // if the Mouse component is a tracker we always update it // Check if the X-value is within range // and if the Y-value is within range pos := e.SpaceComponent.AABB() if e.MouseComponent.Track || e.MouseComponent.startedDragging || mx > pos.Min.X && mx < pos.Max.X && my > pos.Min.Y && my < pos.Max.Y { e.MouseComponent.Enter = !e.MouseComponent.Hovered e.MouseComponent.Hovered = true e.MouseComponent.Released = false if !e.MouseComponent.Track { // If we're tracking, we've already set these e.MouseComponent.MouseX = mx e.MouseComponent.MouseY = my } switch Mouse.Action { case PRESS: switch Mouse.Button { case MouseButtonLeft: e.MouseComponent.startedDragging = true e.MouseComponent.Clicked = true case MouseButtonRight: e.MouseComponent.RightClicked = true } m.mouseDown = true case RELEASE: switch Mouse.Button { case MouseButtonLeft: e.MouseComponent.Released = true case MouseButtonRight: e.MouseComponent.RightReleased = true } case MOVE: if m.mouseDown && e.MouseComponent.startedDragging { e.MouseComponent.Dragged = true } } } else { if e.MouseComponent.Hovered { e.MouseComponent.Leave = true } e.MouseComponent.Hovered = false } if Mouse.Action == RELEASE { // dragging stops as soon as one of the currently pressed buttons // is released e.MouseComponent.Dragged = false e.MouseComponent.startedDragging = false // mouseDown goes false as soon as one of the pressed buttons is // released. Effectively ending any dragging m.mouseDown = false } // propagate the modifiers to the mouse component so that game // implementers can take different decisions based on those e.MouseComponent.Modifier = Mouse.Modifer } }