mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3574318552 | |||
| 05ccf3e158 | |||
| 4f5fd50660 | |||
| aaea27b543 | |||
| 039d09f888 | |||
| 1b83d7f9a7 | |||
| 201d9546b2 | |||
| c1d5033eb0 | |||
| 6f646540f9 | |||
| a99dd304ed | |||
| 4e45995ed0 | |||
| a735e01a77 | |||
| abb45e4c4a | |||
| 78ea3ae747 | |||
| b44b00d7e2 |
@ -7,10 +7,13 @@ import (
|
|||||||
|
|
||||||
type Buffer struct {
|
type Buffer struct {
|
||||||
VAOID uint32
|
VAOID uint32
|
||||||
//BufID is the ID of the VBO
|
// BufID is the ID of the VBO
|
||||||
BufID uint32
|
BufID uint32
|
||||||
//IndexBufID is the ID of the index/element buffer
|
// IndexBufID is the ID of the index/element buffer
|
||||||
IndexBufID uint32
|
IndexBufID uint32
|
||||||
|
// IndexBufCount is the number of elements in the index buffer
|
||||||
|
// Updated on SetIndexBufData
|
||||||
|
IndexBufCount int32
|
||||||
// IndexBufCount int32
|
// IndexBufCount int32
|
||||||
Stride int32
|
Stride int32
|
||||||
|
|
||||||
@ -59,7 +62,7 @@ func (b *Buffer) SetDataWithUsage(values []float32, usage BufUsage) {
|
|||||||
|
|
||||||
func (b *Buffer) SetIndexBufData(values []uint32) {
|
func (b *Buffer) SetIndexBufData(values []uint32) {
|
||||||
|
|
||||||
// b.IndexBufCount = int32(len(values))
|
b.IndexBufCount = int32(len(values))
|
||||||
gl.BindVertexArray(b.VAOID)
|
gl.BindVertexArray(b.VAOID)
|
||||||
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, b.IndexBufID)
|
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, b.IndexBufID)
|
||||||
|
|
||||||
@ -80,8 +83,8 @@ func (b *Buffer) GetLayout() []Element {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetLayout updates the layout object and the corresponding vertex attributes.
|
// SetLayout updates the layout object and the corresponding vertex attributes.
|
||||||
//Vertex attributes are also enabled.
|
// Vertex attributes are also enabled.
|
||||||
func (b *Buffer) SetLayout(layout ...Element) {
|
func (b *Buffer) SetLayout(layout ...Element) {
|
||||||
|
|
||||||
b.layout = layout
|
b.layout = layout
|
||||||
|
|||||||
@ -3,12 +3,13 @@ package engine
|
|||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
|
imgui "github.com/AllenDang/cimgui-go"
|
||||||
"github.com/bloeys/nmage/assert"
|
"github.com/bloeys/nmage/assert"
|
||||||
"github.com/bloeys/nmage/input"
|
"github.com/bloeys/nmage/input"
|
||||||
"github.com/bloeys/nmage/renderer"
|
"github.com/bloeys/nmage/renderer"
|
||||||
"github.com/bloeys/nmage/timing"
|
"github.com/bloeys/nmage/timing"
|
||||||
|
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
||||||
"github.com/go-gl/gl/v4.1-core/gl"
|
"github.com/go-gl/gl/v4.1-core/gl"
|
||||||
"github.com/inkyblackness/imgui-go/v4"
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,8 +27,9 @@ type Window struct {
|
|||||||
func (w *Window) handleInputs() {
|
func (w *Window) handleInputs() {
|
||||||
|
|
||||||
input.EventLoopStart()
|
input.EventLoopStart()
|
||||||
imIO := imgui.CurrentIO()
|
imIo := imgui.CurrentIO()
|
||||||
|
|
||||||
|
// @TODO: Would be nice to have imgui package process its own events via a callback instead of it being part of engine code
|
||||||
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||||
|
|
||||||
//Fire callbacks
|
//Fire callbacks
|
||||||
@ -43,19 +45,32 @@ func (w *Window) handleInputs() {
|
|||||||
input.HandleMouseWheelEvent(e)
|
input.HandleMouseWheelEvent(e)
|
||||||
|
|
||||||
xDelta, yDelta := input.GetMouseWheelMotion()
|
xDelta, yDelta := input.GetMouseWheelMotion()
|
||||||
imIO.AddMouseWheelDelta(float32(xDelta), float32(yDelta))
|
imIo.AddMouseWheelDelta(float32(xDelta), float32(yDelta))
|
||||||
|
|
||||||
case *sdl.KeyboardEvent:
|
case *sdl.KeyboardEvent:
|
||||||
input.HandleKeyboardEvent(e)
|
|
||||||
|
|
||||||
if e.Type == sdl.KEYDOWN {
|
input.HandleKeyboardEvent(e)
|
||||||
imIO.KeyPress(int(e.Keysym.Scancode))
|
imIo.AddKeyEvent(nmageimgui.SdlScancodeToImGuiKey(e.Keysym.Scancode), e.Type == sdl.KEYDOWN)
|
||||||
} else if e.Type == sdl.KEYUP {
|
|
||||||
imIO.KeyRelease(int(e.Keysym.Scancode))
|
// Send modifier key updates to imgui
|
||||||
|
if e.Keysym.Sym == sdl.K_LCTRL || e.Keysym.Sym == sdl.K_RCTRL {
|
||||||
|
imIo.SetKeyCtrl(e.Type == sdl.KEYDOWN)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Keysym.Sym == sdl.K_LSHIFT || e.Keysym.Sym == sdl.K_RSHIFT {
|
||||||
|
imIo.SetKeyShift(e.Type == sdl.KEYDOWN)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Keysym.Sym == sdl.K_LALT || e.Keysym.Sym == sdl.K_RALT {
|
||||||
|
imIo.SetKeyAlt(e.Type == sdl.KEYDOWN)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Keysym.Sym == sdl.K_LGUI || e.Keysym.Sym == sdl.K_RGUI {
|
||||||
|
imIo.SetKeySuper(e.Type == sdl.KEYDOWN)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *sdl.TextInputEvent:
|
case *sdl.TextInputEvent:
|
||||||
imIO.AddInputCharacters(string(e.Text[:]))
|
imIo.AddInputCharactersUTF8(e.GetText())
|
||||||
|
|
||||||
case *sdl.MouseButtonEvent:
|
case *sdl.MouseButtonEvent:
|
||||||
input.HandleMouseBtnEvent(e)
|
input.HandleMouseBtnEvent(e)
|
||||||
@ -75,15 +90,11 @@ func (w *Window) handleInputs() {
|
|||||||
|
|
||||||
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||||
x, y, _ := sdl.GetMouseState()
|
x, y, _ := sdl.GetMouseState()
|
||||||
imIO.SetMousePosition(imgui.Vec2{X: float32(x), Y: float32(y)})
|
imIo.SetMousePos(imgui.Vec2{X: float32(x), Y: float32(y)})
|
||||||
|
|
||||||
imIO.SetMouseButtonDown(0, input.MouseDown(sdl.BUTTON_LEFT))
|
imIo.SetMouseButtonDown(0, input.MouseDown(sdl.BUTTON_LEFT))
|
||||||
imIO.SetMouseButtonDown(1, input.MouseDown(sdl.BUTTON_RIGHT))
|
imIo.SetMouseButtonDown(1, input.MouseDown(sdl.BUTTON_RIGHT))
|
||||||
imIO.SetMouseButtonDown(2, input.MouseDown(sdl.BUTTON_MIDDLE))
|
imIo.SetMouseButtonDown(2, input.MouseDown(sdl.BUTTON_MIDDLE))
|
||||||
|
|
||||||
imIO.KeyShift(sdl.SCANCODE_LSHIFT, sdl.SCANCODE_RSHIFT)
|
|
||||||
imIO.KeyCtrl(sdl.SCANCODE_LCTRL, sdl.SCANCODE_RCTRL)
|
|
||||||
imIO.KeyAlt(sdl.SCANCODE_LALT, sdl.SCANCODE_RALT)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) handleWindowResize() {
|
func (w *Window) handleWindowResize() {
|
||||||
|
|||||||
@ -1,27 +1,26 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import "github.com/bloeys/nmage/assert"
|
import "github.com/bloeys/nmage/registry"
|
||||||
|
|
||||||
var _ Comp = &BaseComp{}
|
var _ Comp = &BaseComp{}
|
||||||
|
|
||||||
type BaseComp struct {
|
type BaseComp struct {
|
||||||
Entity *Entity
|
Handle registry.Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseComp) base() {
|
func (b BaseComp) baseComp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseComp) Init(parent *Entity) {
|
func (b *BaseComp) Init(parentHandle registry.Handle) {
|
||||||
assert.T(parent != nil, "Component was initialized with a nil parent. That is not allowed.")
|
b.Handle = parentHandle
|
||||||
b.Entity = parent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseComp) Name() string {
|
func (b BaseComp) Name() string {
|
||||||
return "Base Component"
|
return "Base Component"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseComp) Update() {
|
func (b BaseComp) Update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseComp) Destroy() {
|
func (b BaseComp) Destroy() {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,27 +1,38 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import "github.com/bloeys/nmage/assert"
|
import (
|
||||||
|
"github.com/bloeys/nmage/assert"
|
||||||
|
"github.com/bloeys/nmage/registry"
|
||||||
|
)
|
||||||
|
|
||||||
type Comp interface {
|
type Comp interface {
|
||||||
// This ensures that implementors of the Comp interface
|
// This ensures that implementors of the Comp interface
|
||||||
// always embed BaseComp
|
// always embed BaseComp
|
||||||
base()
|
baseComp()
|
||||||
|
|
||||||
Name() string
|
Name() string
|
||||||
Init(parent *Entity)
|
Init(parentHandle registry.Handle)
|
||||||
Update()
|
Update()
|
||||||
Destroy()
|
Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddComp[T Comp](e *Entity, c T) {
|
func NewCompContainer() CompContainer {
|
||||||
|
return CompContainer{Comps: []Comp{}}
|
||||||
assert.T(!HasComp[T](e), "Entity with id '%v' already has component of type '%T'", e.ID, c)
|
|
||||||
|
|
||||||
e.Comps = append(e.Comps, c)
|
|
||||||
c.Init(e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HasComp[T Comp](e *Entity) bool {
|
type CompContainer struct {
|
||||||
|
Comps []Comp
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddComp[T Comp](entityHandle registry.Handle, cc *CompContainer, c T) {
|
||||||
|
|
||||||
|
assert.T(!HasComp[T](cc), "Entity with id '%v' already has component of type '%T'", entityHandle, c)
|
||||||
|
|
||||||
|
cc.Comps = append(cc.Comps, c)
|
||||||
|
c.Init(entityHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HasComp[T Comp](e *CompContainer) bool {
|
||||||
|
|
||||||
for i := 0; i < len(e.Comps); i++ {
|
for i := 0; i < len(e.Comps); i++ {
|
||||||
|
|
||||||
@ -34,7 +45,7 @@ func HasComp[T Comp](e *Entity) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetComp[T Comp](e *Entity) (out T) {
|
func GetComp[T Comp](e *CompContainer) (out T) {
|
||||||
|
|
||||||
for i := 0; i < len(e.Comps); i++ {
|
for i := 0; i < len(e.Comps); i++ {
|
||||||
|
|
||||||
@ -48,7 +59,7 @@ func GetComp[T Comp](e *Entity) (out T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DestroyComp calls Destroy on the component and then removes it from the entities component list
|
// DestroyComp calls Destroy on the component and then removes it from the entities component list
|
||||||
func DestroyComp[T Comp](e *Entity) {
|
func DestroyComp[T Comp](e *CompContainer) {
|
||||||
|
|
||||||
for i := 0; i < len(e.Comps); i++ {
|
for i := 0; i < len(e.Comps); i++ {
|
||||||
|
|
||||||
|
|||||||
@ -1,49 +1,7 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
type EntityFlag byte
|
import "github.com/bloeys/nmage/registry"
|
||||||
|
|
||||||
const (
|
type Entity interface {
|
||||||
EntityFlag_None EntityFlag = 0
|
GetHandle() registry.Handle
|
||||||
EntityFlag_Alive EntityFlag = 1 << (iota - 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
GenerationShiftBits = 64 - 8
|
|
||||||
FlagsShiftBits = 64 - 16
|
|
||||||
IndexBitMask = 0x00_00_FFFF_FFFF_FFFF
|
|
||||||
)
|
|
||||||
|
|
||||||
type EntityHandle uint64
|
|
||||||
|
|
||||||
type Entity struct {
|
|
||||||
|
|
||||||
// Byte 1: Generation; Byte 2: Flags; Bytes 3-8: Index
|
|
||||||
ID EntityHandle
|
|
||||||
Comps []Comp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Entity) HasFlag(ef EntityFlag) bool {
|
|
||||||
return GetFlags(e.ID)&ef > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Entity) UpdateAllComps() {
|
|
||||||
for i := 0; i < len(e.Comps); i++ {
|
|
||||||
e.Comps[i].Update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGeneration(id EntityHandle) byte {
|
|
||||||
return byte(id >> GenerationShiftBits)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFlags(id EntityHandle) EntityFlag {
|
|
||||||
return EntityFlag(id >> FlagsShiftBits)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetIndex(id EntityHandle) uint64 {
|
|
||||||
return uint64(id & IndexBitMask)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEntityId(generation byte, flags EntityFlag, index uint64) EntityHandle {
|
|
||||||
return EntityHandle(index | (uint64(generation) << GenerationShiftBits) | (uint64(flags) << FlagsShiftBits))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,109 +0,0 @@
|
|||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/bloeys/nmage/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// The number of slots required to be in the free list before the free list
|
|
||||||
// is used for creating new entries
|
|
||||||
FreeListUsageThreshold uint32 = 20
|
|
||||||
)
|
|
||||||
|
|
||||||
type freeListitem struct {
|
|
||||||
EntityIndex uint64
|
|
||||||
nextFree *freeListitem
|
|
||||||
}
|
|
||||||
|
|
||||||
type Registry struct {
|
|
||||||
EntityCount uint64
|
|
||||||
Entities []Entity
|
|
||||||
|
|
||||||
FreeList *freeListitem
|
|
||||||
FreeListSize uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Registry) NewEntity() *Entity {
|
|
||||||
|
|
||||||
assert.T(r.EntityCount < uint64(len(r.Entities)), "Can not add more entities to registry because it is full")
|
|
||||||
|
|
||||||
entityToUseIndex := uint64(0)
|
|
||||||
var entityToUse *Entity = nil
|
|
||||||
|
|
||||||
if r.FreeList != nil && r.FreeListSize > FreeListUsageThreshold {
|
|
||||||
|
|
||||||
entityToUseIndex = r.FreeList.EntityIndex
|
|
||||||
entityToUse = &r.Entities[entityToUseIndex]
|
|
||||||
r.FreeList = r.FreeList.nextFree
|
|
||||||
r.FreeListSize--
|
|
||||||
} else {
|
|
||||||
|
|
||||||
for i := 0; i < len(r.Entities); i++ {
|
|
||||||
|
|
||||||
e := &r.Entities[i]
|
|
||||||
if e.HasFlag(EntityFlag_Alive) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
entityToUse = e
|
|
||||||
entityToUseIndex = uint64(i)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if entityToUse == nil {
|
|
||||||
panic("failed to create new entity because we did not find a free spot in the registry. Why did the assert not go off?")
|
|
||||||
}
|
|
||||||
|
|
||||||
r.EntityCount++
|
|
||||||
entityToUse.ID = NewEntityId(GetGeneration(entityToUse.ID)+1, EntityFlag_Alive, entityToUseIndex)
|
|
||||||
assert.T(entityToUse.ID != 0, "Entity ID must not be zero")
|
|
||||||
return entityToUse
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Registry) GetEntity(id EntityHandle) *Entity {
|
|
||||||
|
|
||||||
index := GetIndex(id)
|
|
||||||
gen := GetGeneration(id)
|
|
||||||
|
|
||||||
e := &r.Entities[index]
|
|
||||||
eGen := GetGeneration(e.ID)
|
|
||||||
|
|
||||||
if gen != eGen {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// FreeEntity calls Destroy on all the entities components, resets the component list, resets the entity flags, then ads this entity to the free list
|
|
||||||
func (r *Registry) FreeEntity(id EntityHandle) {
|
|
||||||
|
|
||||||
e := r.GetEntity(id)
|
|
||||||
if e == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(e.Comps); i++ {
|
|
||||||
e.Comps[i].Destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
r.EntityCount--
|
|
||||||
eIndex := GetIndex(e.ID)
|
|
||||||
|
|
||||||
e.Comps = []Comp{}
|
|
||||||
e.ID = NewEntityId(GetGeneration(e.ID), EntityFlag_None, eIndex)
|
|
||||||
|
|
||||||
r.FreeList = &freeListitem{
|
|
||||||
EntityIndex: eIndex,
|
|
||||||
nextFree: r.FreeList,
|
|
||||||
}
|
|
||||||
r.FreeListSize++
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRegistry(size uint32) *Registry {
|
|
||||||
assert.T(size > 0, "Registry size must be more than zero")
|
|
||||||
return &Registry{
|
|
||||||
Entities: make([]Entity, size),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
5
go.mod
5
go.mod
@ -2,12 +2,13 @@ module github.com/bloeys/nmage
|
|||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require github.com/veandco/go-sdl2 v0.4.25
|
require github.com/veandco/go-sdl2 v0.4.35
|
||||||
|
|
||||||
require github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6
|
require github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bloeys/assimp-go v0.4.4
|
github.com/bloeys/assimp-go v0.4.4
|
||||||
github.com/bloeys/gglm v0.43.0
|
github.com/bloeys/gglm v0.43.0
|
||||||
github.com/inkyblackness/imgui-go/v4 v4.6.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2
|
||||||
|
|||||||
15
go.sum
15
go.sum
@ -1,17 +1,10 @@
|
|||||||
|
github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2 h1:3HA/5qD8Rimxz/y1sLyVaM7ws1dzjXzMt4hOBiwHggo=
|
||||||
|
github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2/go.mod h1:iNfbIyOBN8k3XScMxULbrwYbPsXEAUD0Jb6UwrspQb8=
|
||||||
github.com/bloeys/assimp-go v0.4.4 h1:Yn5e/RpE0Oes0YMBy8O7KkwAO4R/RpgrZPJCt08dVIU=
|
github.com/bloeys/assimp-go v0.4.4 h1:Yn5e/RpE0Oes0YMBy8O7KkwAO4R/RpgrZPJCt08dVIU=
|
||||||
github.com/bloeys/assimp-go v0.4.4/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0=
|
github.com/bloeys/assimp-go v0.4.4/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0=
|
||||||
github.com/bloeys/gglm v0.43.0 h1:ZpOghR3PHfpkigTDh+FqxLsF0gN8CD6s/bWoei6LyxI=
|
github.com/bloeys/gglm v0.43.0 h1:ZpOghR3PHfpkigTDh+FqxLsF0gN8CD6s/bWoei6LyxI=
|
||||||
github.com/bloeys/gglm v0.43.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk=
|
github.com/bloeys/gglm v0.43.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
|
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk=
|
||||||
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||||
github.com/inkyblackness/imgui-go/v4 v4.6.0 h1:ShcnXEYl80+xREGBY9OpGWePA6FfJChY9Varsm+3jjE=
|
github.com/veandco/go-sdl2 v0.4.35 h1:NohzsfageDWGtCd9nf7Pc3sokMK/MOK+UA2QMJARWzQ=
|
||||||
github.com/inkyblackness/imgui-go/v4 v4.6.0/go.mod h1:g8SAGtOYUP7rYaOB2AsVKCEHmPMDmJKgt4z6d+flhb0=
|
github.com/veandco/go-sdl2 v0.4.35/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/veandco/go-sdl2 v0.4.25 h1:J5ac3KKOccp/0xGJA1PaNYKPUcZm19IxhDGs8lJofPI=
|
|
||||||
github.com/veandco/go-sdl2 v0.4.25/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
|
||||||
|
|||||||
@ -2,19 +2,16 @@ package level
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/bloeys/nmage/assert"
|
"github.com/bloeys/nmage/assert"
|
||||||
"github.com/bloeys/nmage/entity"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Level struct {
|
type Level struct {
|
||||||
*entity.Registry
|
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLevel(name string, maxEntities uint32) *Level {
|
func NewLevel(name string) *Level {
|
||||||
|
|
||||||
assert.T(name != "", "Level name can not be empty")
|
assert.T(name != "", "Level name can not be empty")
|
||||||
return &Level{
|
return &Level{
|
||||||
Name: name,
|
Name: name,
|
||||||
Registry: entity.NewRegistry(maxEntities),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
89
main.go
89
main.go
@ -2,22 +2,23 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
imgui "github.com/AllenDang/cimgui-go"
|
||||||
"github.com/bloeys/gglm/gglm"
|
"github.com/bloeys/gglm/gglm"
|
||||||
"github.com/bloeys/nmage/assets"
|
"github.com/bloeys/nmage/assets"
|
||||||
"github.com/bloeys/nmage/camera"
|
"github.com/bloeys/nmage/camera"
|
||||||
"github.com/bloeys/nmage/engine"
|
"github.com/bloeys/nmage/engine"
|
||||||
"github.com/bloeys/nmage/entity"
|
"github.com/bloeys/nmage/entity"
|
||||||
"github.com/bloeys/nmage/input"
|
"github.com/bloeys/nmage/input"
|
||||||
"github.com/bloeys/nmage/level"
|
|
||||||
"github.com/bloeys/nmage/logging"
|
"github.com/bloeys/nmage/logging"
|
||||||
"github.com/bloeys/nmage/materials"
|
"github.com/bloeys/nmage/materials"
|
||||||
"github.com/bloeys/nmage/meshes"
|
"github.com/bloeys/nmage/meshes"
|
||||||
|
"github.com/bloeys/nmage/registry"
|
||||||
"github.com/bloeys/nmage/renderer/rend3dgl"
|
"github.com/bloeys/nmage/renderer/rend3dgl"
|
||||||
"github.com/bloeys/nmage/timing"
|
"github.com/bloeys/nmage/timing"
|
||||||
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
||||||
"github.com/go-gl/gl/v4.1-core/gl"
|
"github.com/go-gl/gl/v4.1-core/gl"
|
||||||
"github.com/inkyblackness/imgui-go/v4"
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,6 +36,9 @@ import (
|
|||||||
const (
|
const (
|
||||||
camSpeed = 15
|
camSpeed = 15
|
||||||
mouseSensitivity = 0.5
|
mouseSensitivity = 0.5
|
||||||
|
|
||||||
|
unscaledWindowWidth = 1280
|
||||||
|
unscaledWindowHeight = 720
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -60,6 +64,8 @@ var (
|
|||||||
debugDrawDepthBuffer bool
|
debugDrawDepthBuffer bool
|
||||||
|
|
||||||
skyboxCmap assets.Cubemap
|
skyboxCmap assets.Cubemap
|
||||||
|
|
||||||
|
dpiScaling float32
|
||||||
)
|
)
|
||||||
|
|
||||||
type OurGame struct {
|
type OurGame struct {
|
||||||
@ -81,24 +87,39 @@ func (t *TransformComp) Name() string {
|
|||||||
|
|
||||||
func Test() {
|
func Test() {
|
||||||
|
|
||||||
lvl := level.NewLevel("test level", 1000)
|
// lvl := level.NewLevel("test level")
|
||||||
e1 := lvl.Registry.NewEntity()
|
testRegistry := registry.NewRegistry[int](100)
|
||||||
|
|
||||||
trComp := entity.GetComp[*TransformComp](e1)
|
e1, e1Handle := testRegistry.New()
|
||||||
|
e1CompContainer := entity.NewCompContainer()
|
||||||
|
fmt.Printf("Entity 1: %+v; Handle: %+v; Index: %+v; Gen: %+v; Flags: %+v\n", e1, e1Handle, e1Handle.Index(), e1Handle.Generation(), e1Handle.Flags())
|
||||||
|
|
||||||
|
trComp := entity.GetComp[*TransformComp](&e1CompContainer)
|
||||||
fmt.Println("Get comp before adding any:", trComp)
|
fmt.Println("Get comp before adding any:", trComp)
|
||||||
|
|
||||||
entity.AddComp(e1, &TransformComp{
|
entity.AddComp(e1Handle, &e1CompContainer, &TransformComp{
|
||||||
Pos: gglm.NewVec3(0, 0, 0),
|
Pos: gglm.NewVec3(0, 0, 0),
|
||||||
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||||
Scale: gglm.NewVec3(0, 0, 0),
|
Scale: gglm.NewVec3(0, 0, 0),
|
||||||
})
|
})
|
||||||
trComp = entity.GetComp[*TransformComp](e1)
|
trComp = entity.GetComp[*TransformComp](&e1CompContainer)
|
||||||
fmt.Println("Get transform comp:", trComp)
|
fmt.Println("Get transform comp:", trComp)
|
||||||
|
|
||||||
fmt.Printf("Entity: %+v\n", e1)
|
e2, e2Handle := testRegistry.New()
|
||||||
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
e3, e3Handle := testRegistry.New()
|
||||||
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
e4, e4Handle := testRegistry.New()
|
||||||
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
fmt.Printf("Entity 2: %+v; Handle: %+v; Index: %+v; Gen: %+v; Flags: %+v\n", e2, e2Handle, e2Handle.Index(), e2Handle.Generation(), e2Handle.Flags())
|
||||||
|
fmt.Printf("Entity 3: %+v; Handle: %+v; Index: %+v; Gen: %+v; Flags: %+v\n", e3, e3Handle, e3Handle.Index(), e3Handle.Generation(), e3Handle.Flags())
|
||||||
|
fmt.Printf("Entity 4: %+v; Handle: %+v; Index: %+v; Gen: %+v; Flags: %+v\n", e4, e4Handle, e4Handle.Index(), e4Handle.Generation(), e4Handle.Flags())
|
||||||
|
|
||||||
|
*e2 = 1000
|
||||||
|
fmt.Printf("Entity 2 value after registry get: %+v\n", *testRegistry.Get(e2Handle))
|
||||||
|
|
||||||
|
testRegistry.Free(e2Handle)
|
||||||
|
fmt.Printf("Entity 2 value after free: %+v\n", testRegistry.Get(e2Handle))
|
||||||
|
|
||||||
|
e5, e5Handle := testRegistry.New()
|
||||||
|
fmt.Printf("Entity 5: %+v; Handle: %+v; Index: %+v; Gen: %+v; Flags: %+v\n", e5, e5Handle, e5Handle.Index(), e5Handle.Generation(), e5Handle.Flags())
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -113,7 +134,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Create window
|
//Create window
|
||||||
window, err = engine.CreateOpenGLWindowCentered("nMage", 1280, 720, engine.WindowFlags_RESIZABLE, rend3dgl.NewRend3DGL())
|
dpiScaling = getDpiScaling(unscaledWindowWidth, unscaledWindowHeight)
|
||||||
|
window, err = engine.CreateOpenGLWindowCentered("nMage", int32(unscaledWindowWidth*dpiScaling), int32(unscaledWindowHeight*dpiScaling), engine.WindowFlags_RESIZABLE, rend3dgl.NewRend3DGL())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.ErrLog.Fatalln("Failed to create window. Err: ", err)
|
logging.ErrLog.Fatalln("Failed to create window. Err: ", err)
|
||||||
}
|
}
|
||||||
@ -123,7 +145,7 @@ func main() {
|
|||||||
|
|
||||||
game := &OurGame{
|
game := &OurGame{
|
||||||
Win: window,
|
Win: window,
|
||||||
ImGUIInfo: nmageimgui.NewImGUI(),
|
ImGUIInfo: nmageimgui.NewImGui(),
|
||||||
}
|
}
|
||||||
window.EventCallbacks = append(window.EventCallbacks, game.handleWindowEvents)
|
window.EventCallbacks = append(window.EventCallbacks, game.handleWindowEvents)
|
||||||
|
|
||||||
@ -147,6 +169,40 @@ func (g *OurGame) handleWindowEvents(e sdl.Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDpiScaling(unscaledWindowWidth, unscaledWindowHeight int32) float32 {
|
||||||
|
|
||||||
|
// Great read on DPI here: https://nlguillemot.wordpress.com/2016/12/11/high-dpi-rendering/
|
||||||
|
|
||||||
|
// The no-scaling DPI on different platforms (e.g. when scale=100% on windows)
|
||||||
|
var defaultDpi float32 = 96
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
defaultDpi = 96
|
||||||
|
} else if runtime.GOOS == "darwin" {
|
||||||
|
defaultDpi = 72
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current DPI of the monitor
|
||||||
|
_, dpiHorizontal, _, err := sdl.GetDisplayDPI(0)
|
||||||
|
if err != nil {
|
||||||
|
dpiHorizontal = defaultDpi
|
||||||
|
fmt.Printf("Failed to get DPI with error '%s'. Using default DPI of '%f'\n", err.Error(), defaultDpi)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scaling factor (e.g. will be 1.25 for 125% scaling on windows)
|
||||||
|
dpiScaling := dpiHorizontal / defaultDpi
|
||||||
|
|
||||||
|
fmt.Printf(
|
||||||
|
"Default DPI=%f\nHorizontal DPI=%f\nDPI scaling=%f\nUnscaled window size (width, height)=(%d, %d)\nScaled window size (width, height)=(%d, %d)\n\n",
|
||||||
|
defaultDpi,
|
||||||
|
dpiHorizontal,
|
||||||
|
dpiScaling,
|
||||||
|
unscaledWindowWidth, unscaledWindowHeight,
|
||||||
|
int32(float32(unscaledWindowWidth)*dpiScaling), int32(float32(unscaledWindowHeight)*dpiScaling),
|
||||||
|
)
|
||||||
|
|
||||||
|
return dpiScaling
|
||||||
|
}
|
||||||
|
|
||||||
func (g *OurGame) Init() {
|
func (g *OurGame) Init() {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -226,11 +282,14 @@ func (g *OurGame) Update() {
|
|||||||
g.updateCameraLookAround()
|
g.updateCameraLookAround()
|
||||||
g.updateCameraPos()
|
g.updateCameraPos()
|
||||||
|
|
||||||
|
imgui.ShowDemoWindow()
|
||||||
|
|
||||||
//Rotating cubes
|
//Rotating cubes
|
||||||
if input.KeyDown(sdl.K_SPACE) {
|
if input.KeyDown(sdl.K_SPACE) {
|
||||||
cubeModelMat.Rotate(10*timing.DT()*gglm.Deg2Rad, gglm.NewVec3(1, 1, 1).Normalize())
|
cubeModelMat.Rotate(10*timing.DT()*gglm.Deg2Rad, gglm.NewVec3(1, 1, 1).Normalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui.Begin("Debug controls")
|
||||||
if imgui.DragFloat3("Cam Pos", &cam.Pos.Data) {
|
if imgui.DragFloat3("Cam Pos", &cam.Pos.Data) {
|
||||||
updateViewMat()
|
updateViewMat()
|
||||||
}
|
}
|
||||||
@ -246,6 +305,9 @@ func (g *OurGame) Update() {
|
|||||||
simpleMat.SetUnifVec3("lightColor1", lightColor1)
|
simpleMat.SetUnifVec3("lightColor1", lightColor1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui.Checkbox("Debug depth buffer", &debugDrawDepthBuffer)
|
||||||
|
imgui.End()
|
||||||
|
|
||||||
if input.KeyClicked(sdl.K_F4) {
|
if input.KeyClicked(sdl.K_F4) {
|
||||||
fmt.Printf("Pos: %s; Forward: %s; |Forward|: %f\n", cam.Pos.String(), cam.Forward.String(), cam.Forward.Mag())
|
fmt.Printf("Pos: %s; Forward: %s; |Forward|: %f\n", cam.Pos.String(), cam.Forward.String(), cam.Forward.Mag())
|
||||||
}
|
}
|
||||||
@ -314,7 +376,6 @@ func (g *OurGame) updateCameraPos() {
|
|||||||
func (g *OurGame) Render() {
|
func (g *OurGame) Render() {
|
||||||
|
|
||||||
matToUse := simpleMat
|
matToUse := simpleMat
|
||||||
imgui.Checkbox("Debug depth buffer", &debugDrawDepthBuffer)
|
|
||||||
if debugDrawDepthBuffer {
|
if debugDrawDepthBuffer {
|
||||||
matToUse = debugDepthMat
|
matToUse = debugDepthMat
|
||||||
}
|
}
|
||||||
|
|||||||
73
registry/iterator.go
Executable file
73
registry/iterator.go
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
package registry
|
||||||
|
|
||||||
|
// Iterator goes through the entire registry it was created from and
|
||||||
|
// returns all alive items, and nil after its done.
|
||||||
|
//
|
||||||
|
// The iterator will still work if items are added/removed to the registry
|
||||||
|
// after it was created, but the following conditions apply:
|
||||||
|
// - If items are removed, iterator will not show the removed items (assuming it didn't return them before their removal)
|
||||||
|
// - If items are added, the iterator will either only return older items (i.e. is not affected), or only return newer items (i.e. items that were going to be returned before will now not get returned in favor of newly inserted items), or a mix of old and new items.
|
||||||
|
// However, in all cases the iterator will *never* returns more items than were alive at the time of the iterator's creation.
|
||||||
|
// - If items were both added and removed, the iterator might follow either of the previous 2 cases or a combination of them
|
||||||
|
//
|
||||||
|
// To summarize: The iterator will *never* return more items than were alive at the time of its creation, and will *never* return freed items
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
//
|
||||||
|
// for item, handle := it.Next(); !it.IsDone(); item, handle = it.Next() {
|
||||||
|
// // Do stuff
|
||||||
|
// }
|
||||||
|
type Iterator[T any] struct {
|
||||||
|
registry *Registry[T]
|
||||||
|
remainingItems uint
|
||||||
|
currIndex int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *Iterator[T]) Next() (*T, Handle) {
|
||||||
|
|
||||||
|
if it.IsDone() {
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// If IsDone() only checked 'remainingItems', then when Next() returns the last item IsDone() will immediately be true which will cause loops to exit before processing the last item!
|
||||||
|
// However, with this check IsDone will remain false until Next() is called at least one more time after returning the last item which ensures the last item is processed in the loop.
|
||||||
|
//
|
||||||
|
// In cases where iterator is created on an empty registry, IsDone() will report true and the above check will return early
|
||||||
|
if it.remainingItems == 0 {
|
||||||
|
it.currIndex = -1
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; it.currIndex < len(it.registry.Handles); it.currIndex++ {
|
||||||
|
|
||||||
|
handle := it.registry.Handles[it.currIndex]
|
||||||
|
if !handle.HasFlag(HandleFlag_Alive) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
item := &it.registry.Items[it.currIndex]
|
||||||
|
it.currIndex++
|
||||||
|
it.remainingItems--
|
||||||
|
return item, handle
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reached here means we iterated to the end and didn't find anything, which probably
|
||||||
|
// means that the registry changed since we were created, and that remainingItems is not accurate.
|
||||||
|
//
|
||||||
|
// As such, we zero remaining items so that this iterator is considered done
|
||||||
|
it.currIndex = -1
|
||||||
|
it.remainingItems = 0
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (it *Iterator[T]) IsDone() bool {
|
||||||
|
|
||||||
|
if it.remainingItems != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have two cases here:
|
||||||
|
// 1. Index of zero means Next() never returned an item. Remaining items of zero without returning anything means we have an empty registry and so its safe to report done
|
||||||
|
// 2. Negative index means Next() has detected we reached the end and that its safe to report being done
|
||||||
|
return it.currIndex <= 0
|
||||||
|
}
|
||||||
131
registry/registry.go
Executable file
131
registry/registry.go
Executable file
@ -0,0 +1,131 @@
|
|||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/bloeys/nmage/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type freeListitem struct {
|
||||||
|
ItemIndex uint64
|
||||||
|
nextFree *freeListitem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registry is a storage data structure that can efficiently create/get/free items using generational indices.
|
||||||
|
// Each item stored in the registry is associated with a 'handle' object that is used to get and free objects
|
||||||
|
//
|
||||||
|
// The registry 'owns' all items it stores and returns pointers to items in its array. All items are allocated upfront.
|
||||||
|
//
|
||||||
|
// It is NOT safe to concurrently create or free items. However, it is SAFE to concurrently get items
|
||||||
|
type Registry[T any] struct {
|
||||||
|
ItemCount uint
|
||||||
|
Handles []Handle
|
||||||
|
Items []T
|
||||||
|
|
||||||
|
FreeList *freeListitem
|
||||||
|
FreeListSize uint32
|
||||||
|
|
||||||
|
// The number of slots required to be in the free list before the free list
|
||||||
|
// is used for creating new entries
|
||||||
|
FreeListUsageThreshold uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry[T]) New() (*T, Handle) {
|
||||||
|
|
||||||
|
assert.T(r.ItemCount < uint(len(r.Handles)), "Can not add more entities to registry because it is full")
|
||||||
|
|
||||||
|
var index uint64 = math.MaxUint64
|
||||||
|
|
||||||
|
// Find index to use for the new item
|
||||||
|
if r.FreeList != nil && r.FreeListSize > r.FreeListUsageThreshold {
|
||||||
|
|
||||||
|
index = r.FreeList.ItemIndex
|
||||||
|
|
||||||
|
r.FreeList = r.FreeList.nextFree
|
||||||
|
r.FreeListSize--
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for i := 0; i < len(r.Handles); i++ {
|
||||||
|
|
||||||
|
handle := r.Handles[i]
|
||||||
|
|
||||||
|
if handle.HasFlag(HandleFlag_Alive) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
index = uint64(i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if index == math.MaxUint64 {
|
||||||
|
panic("failed to create new entity because we did not find a free spot in the registry. Why did the item count assert not go off?")
|
||||||
|
}
|
||||||
|
|
||||||
|
var newItem T
|
||||||
|
newHandle := NewHandle(r.Handles[index].Generation()+1, HandleFlag_Alive, index)
|
||||||
|
assert.T(newHandle != 0, "Entity handle must not be zero")
|
||||||
|
|
||||||
|
r.ItemCount++
|
||||||
|
r.Handles[index] = newHandle
|
||||||
|
r.Items[index] = newItem
|
||||||
|
|
||||||
|
// It is very important we return directly from the items array, because if we return
|
||||||
|
// a pointer to newItem, and T is a value not a pointer, then newItem and what's stored in items will be different
|
||||||
|
return &r.Items[index], newHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry[T]) Get(id Handle) *T {
|
||||||
|
|
||||||
|
index := id.Index()
|
||||||
|
assert.T(index < uint64(len(r.Handles)), "Failed to get entity because of invalid entity handle. Handle index is %d while registry only has %d slots. Handle: %+v", index, r.ItemCount, id)
|
||||||
|
|
||||||
|
handle := r.Handles[index]
|
||||||
|
if handle.Generation() != id.Generation() || !handle.HasFlag(HandleFlag_Alive) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
item := &r.Items[index]
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free resets the entity flags then adds this entity to the free list
|
||||||
|
func (r *Registry[T]) Free(id Handle) {
|
||||||
|
|
||||||
|
index := id.Index()
|
||||||
|
assert.T(index < uint64(len(r.Handles)), "Failed to free entity because of invalid entity handle. Handle index is %d while registry only has %d slots. Handle: %+v", index, r.ItemCount, id)
|
||||||
|
|
||||||
|
// Nothing to do if already free
|
||||||
|
handle := r.Handles[index]
|
||||||
|
if handle.Generation() != id.Generation() || !handle.HasFlag(HandleFlag_Alive) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generation is incremented on aquire, so here we just reset flags
|
||||||
|
r.ItemCount--
|
||||||
|
r.Handles[index] = NewHandle(id.Generation(), HandleFlag_None, index)
|
||||||
|
|
||||||
|
// Add to free list
|
||||||
|
r.FreeList = &freeListitem{
|
||||||
|
ItemIndex: index,
|
||||||
|
nextFree: r.FreeList,
|
||||||
|
}
|
||||||
|
r.FreeListSize++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry[T]) NewIterator() Iterator[T] {
|
||||||
|
return Iterator[T]{
|
||||||
|
registry: r,
|
||||||
|
remainingItems: r.ItemCount,
|
||||||
|
currIndex: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRegistry[T any](size uint32) *Registry[T] {
|
||||||
|
assert.T(size > 0, "Registry size must be more than zero")
|
||||||
|
return &Registry[T]{
|
||||||
|
Handles: make([]Handle, size),
|
||||||
|
Items: make([]T, size),
|
||||||
|
FreeListUsageThreshold: 30,
|
||||||
|
}
|
||||||
|
}
|
||||||
37
registry/registry_handle.go
Executable file
37
registry/registry_handle.go
Executable file
@ -0,0 +1,37 @@
|
|||||||
|
package registry
|
||||||
|
|
||||||
|
type HandleFlag byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
HandleFlag_None HandleFlag = 0
|
||||||
|
HandleFlag_Alive HandleFlag = 1 << (iota - 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GenerationShiftBits = 64 - 8
|
||||||
|
FlagsShiftBits = 64 - 16
|
||||||
|
IndexBitMask = 0x00_00_FFFF_FFFF_FFFF
|
||||||
|
)
|
||||||
|
|
||||||
|
// Byte 1: Generation; Byte 2: Flags; Bytes 3-8: Index
|
||||||
|
type Handle uint64
|
||||||
|
|
||||||
|
func (h Handle) HasFlag(ef HandleFlag) bool {
|
||||||
|
return h.Flags()&ef > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) Generation() byte {
|
||||||
|
return byte(h >> GenerationShiftBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) Flags() HandleFlag {
|
||||||
|
return HandleFlag(h >> FlagsShiftBits)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Handle) Index() uint64 {
|
||||||
|
return uint64(h & IndexBitMask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHandle(generation byte, flags HandleFlag, index uint64) Handle {
|
||||||
|
return Handle(index | (uint64(generation) << GenerationShiftBits) | (uint64(flags) << FlagsShiftBits))
|
||||||
|
}
|
||||||
BIN
rsrc_windows_386.syso
Executable file
BIN
rsrc_windows_386.syso
Executable file
Binary file not shown.
BIN
rsrc_windows_amd64.syso
Executable file
BIN
rsrc_windows_amd64.syso
Executable file
Binary file not shown.
@ -1,17 +1,16 @@
|
|||||||
package nmageimgui
|
package nmageimgui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
imgui "github.com/AllenDang/cimgui-go"
|
||||||
"github.com/bloeys/gglm/gglm"
|
"github.com/bloeys/gglm/gglm"
|
||||||
"github.com/bloeys/nmage/assert"
|
|
||||||
"github.com/bloeys/nmage/materials"
|
"github.com/bloeys/nmage/materials"
|
||||||
"github.com/bloeys/nmage/timing"
|
"github.com/bloeys/nmage/timing"
|
||||||
"github.com/go-gl/gl/v4.1-core/gl"
|
"github.com/go-gl/gl/v4.1-core/gl"
|
||||||
"github.com/inkyblackness/imgui-go/v4"
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ImguiInfo struct {
|
type ImguiInfo struct {
|
||||||
ImCtx *imgui.Context
|
ImCtx imgui.Context
|
||||||
|
|
||||||
Mat *materials.Material
|
Mat *materials.Material
|
||||||
VaoID uint32
|
VaoID uint32
|
||||||
@ -22,9 +21,9 @@ type ImguiInfo struct {
|
|||||||
|
|
||||||
func (i *ImguiInfo) FrameStart(winWidth, winHeight float32) {
|
func (i *ImguiInfo) FrameStart(winWidth, winHeight float32) {
|
||||||
|
|
||||||
if err := i.ImCtx.SetCurrent(); err != nil {
|
// if err := i.ImCtx.SetCurrent(); err != nil {
|
||||||
assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
// assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
imIO := imgui.CurrentIO()
|
imIO := imgui.CurrentIO()
|
||||||
imIO.SetDisplaySize(imgui.Vec2{X: float32(winWidth), Y: float32(winHeight)})
|
imIO.SetDisplaySize(imgui.Vec2{X: float32(winWidth), Y: float32(winHeight)})
|
||||||
@ -35,9 +34,9 @@ func (i *ImguiInfo) FrameStart(winWidth, winHeight float32) {
|
|||||||
|
|
||||||
func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32) {
|
func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32) {
|
||||||
|
|
||||||
if err := i.ImCtx.SetCurrent(); err != nil {
|
// if err := i.ImCtx.SetCurrent(); err != nil {
|
||||||
assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
// assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
imgui.Render()
|
imgui.Render()
|
||||||
|
|
||||||
@ -46,7 +45,7 @@ func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
drawData := imgui.RenderedDrawData()
|
drawData := imgui.CurrentDrawData()
|
||||||
drawData.ScaleClipRects(imgui.Vec2{
|
drawData.ScaleClipRects(imgui.Vec2{
|
||||||
X: float32(fbWidth) / float32(winWidth),
|
X: float32(fbWidth) / float32(winWidth),
|
||||||
Y: float32(fbHeight) / float32(winHeight),
|
Y: float32(fbHeight) / float32(winHeight),
|
||||||
@ -96,11 +95,11 @@ func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32)
|
|||||||
// Draw
|
// Draw
|
||||||
for _, list := range drawData.CommandLists() {
|
for _, list := range drawData.CommandLists() {
|
||||||
|
|
||||||
vertexBuffer, vertexBufferSize := list.VertexBuffer()
|
vertexBuffer, vertexBufferSize := list.GetVertexBuffer()
|
||||||
gl.BindBuffer(gl.ARRAY_BUFFER, i.VboID)
|
gl.BindBuffer(gl.ARRAY_BUFFER, i.VboID)
|
||||||
gl.BufferData(gl.ARRAY_BUFFER, vertexBufferSize, vertexBuffer, gl.STREAM_DRAW)
|
gl.BufferData(gl.ARRAY_BUFFER, vertexBufferSize, vertexBuffer, gl.STREAM_DRAW)
|
||||||
|
|
||||||
indexBuffer, indexBufferSize := list.IndexBuffer()
|
indexBuffer, indexBufferSize := list.GetIndexBuffer()
|
||||||
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, i.IndexBufID)
|
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, i.IndexBufID)
|
||||||
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, indexBufferSize, indexBuffer, gl.STREAM_DRAW)
|
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, indexBufferSize, indexBuffer, gl.STREAM_DRAW)
|
||||||
|
|
||||||
@ -113,7 +112,7 @@ func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32)
|
|||||||
clipRect := cmd.ClipRect()
|
clipRect := cmd.ClipRect()
|
||||||
gl.Scissor(int32(clipRect.X), int32(fbHeight)-int32(clipRect.W), int32(clipRect.Z-clipRect.X), int32(clipRect.W-clipRect.Y))
|
gl.Scissor(int32(clipRect.X), int32(fbHeight)-int32(clipRect.W), int32(clipRect.Z-clipRect.X), int32(clipRect.W-clipRect.Y))
|
||||||
|
|
||||||
gl.DrawElementsBaseVertex(gl.TRIANGLES, int32(cmd.ElementCount()), uint32(drawType), gl.PtrOffset(cmd.IndexOffset()*indexSize), int32(cmd.VertexOffset()))
|
gl.DrawElementsBaseVertex(gl.TRIANGLES, int32(cmd.ElemCount()), uint32(drawType), gl.PtrOffset(int(cmd.IdxOffset())*indexSize), int32(cmd.VtxOffset()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,14 +123,14 @@ func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32)
|
|||||||
gl.Enable(gl.DEPTH_TEST)
|
gl.Enable(gl.DEPTH_TEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *ImguiInfo) AddFontTTF(fontPath string, fontSize float32, fontConfig *imgui.FontConfig, glyphRanges *imgui.GlyphRanges) imgui.Font {
|
func (i *ImguiInfo) AddFontTTF(fontPath string, fontSize float32, fontConfig *imgui.FontConfig, glyphRanges *imgui.GlyphRange) imgui.Font {
|
||||||
|
|
||||||
fontConfigToUse := imgui.DefaultFontConfig
|
fontConfigToUse := imgui.NewFontConfig()
|
||||||
if fontConfig != nil {
|
if fontConfig != nil {
|
||||||
fontConfigToUse = *fontConfig
|
fontConfigToUse = *fontConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
glyphRangesToUse := imgui.EmptyGlyphRanges
|
glyphRangesToUse := imgui.NewGlyphRange()
|
||||||
if glyphRanges != nil {
|
if glyphRanges != nil {
|
||||||
glyphRangesToUse = *glyphRanges
|
glyphRangesToUse = *glyphRanges
|
||||||
}
|
}
|
||||||
@ -139,11 +138,11 @@ func (i *ImguiInfo) AddFontTTF(fontPath string, fontSize float32, fontConfig *im
|
|||||||
imIO := imgui.CurrentIO()
|
imIO := imgui.CurrentIO()
|
||||||
|
|
||||||
a := imIO.Fonts()
|
a := imIO.Fonts()
|
||||||
f := a.AddFontFromFileTTFV(fontPath, fontSize, fontConfigToUse, glyphRangesToUse)
|
f := a.AddFontFromFileTTFV(fontPath, fontSize, fontConfigToUse, glyphRangesToUse.Data())
|
||||||
image := a.TextureDataAlpha8()
|
pixels, width, height, _ := a.GetTextureDataAsAlpha8()
|
||||||
|
|
||||||
gl.BindTexture(gl.TEXTURE_2D, i.TexID)
|
gl.BindTexture(gl.TEXTURE_2D, i.TexID)
|
||||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(image.Width), int32(image.Height), 0, gl.RED, gl.UNSIGNED_BYTE, image.Pixels)
|
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(width), int32(height), 0, gl.RED, gl.UNSIGNED_BYTE, pixels)
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
@ -184,15 +183,16 @@ void main()
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
func NewImGUI() ImguiInfo {
|
func NewImGui() ImguiInfo {
|
||||||
|
|
||||||
imguiInfo := ImguiInfo{
|
imguiInfo := ImguiInfo{
|
||||||
ImCtx: imgui.CreateContext(nil),
|
ImCtx: imgui.CreateContext(),
|
||||||
Mat: materials.NewMaterialSrc("ImGUI Mat", []byte(imguiShdrSrc)),
|
Mat: materials.NewMaterialSrc("ImGUI Mat", []byte(imguiShdrSrc)),
|
||||||
}
|
}
|
||||||
|
|
||||||
imIO := imgui.CurrentIO()
|
io := imgui.CurrentIO()
|
||||||
imIO.SetBackendFlags(imIO.GetBackendFlags() | imgui.BackendFlagsRendererHasVtxOffset)
|
io.SetConfigFlags(io.ConfigFlags() | imgui.ConfigFlagsDockingEnable)
|
||||||
|
io.SetBackendFlags(io.BackendFlags() | imgui.BackendFlagsRendererHasVtxOffset)
|
||||||
|
|
||||||
gl.GenVertexArrays(1, &imguiInfo.VaoID)
|
gl.GenVertexArrays(1, &imguiInfo.VaoID)
|
||||||
gl.GenBuffers(1, &imguiInfo.VboID)
|
gl.GenBuffers(1, &imguiInfo.VboID)
|
||||||
@ -205,11 +205,11 @@ func NewImGUI() ImguiInfo {
|
|||||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||||
gl.PixelStorei(gl.UNPACK_ROW_LENGTH, 0)
|
gl.PixelStorei(gl.UNPACK_ROW_LENGTH, 0)
|
||||||
|
|
||||||
image := imIO.Fonts().TextureDataAlpha8()
|
pixels, width, height, _ := io.Fonts().GetTextureDataAsAlpha8()
|
||||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(image.Width), int32(image.Height), 0, gl.RED, gl.UNSIGNED_BYTE, image.Pixels)
|
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(width), int32(height), 0, gl.RED, gl.UNSIGNED_BYTE, pixels)
|
||||||
|
|
||||||
// Store our identifier
|
// Store our identifier
|
||||||
imIO.Fonts().SetTextureID(imgui.TextureID(imguiInfo.TexID))
|
io.Fonts().SetTexID(imgui.TextureID(uintptr(imguiInfo.TexID)))
|
||||||
|
|
||||||
//Shader attributes
|
//Shader attributes
|
||||||
imguiInfo.Mat.Bind()
|
imguiInfo.Mat.Bind()
|
||||||
@ -218,35 +218,223 @@ func NewImGUI() ImguiInfo {
|
|||||||
imguiInfo.Mat.EnableAttribute("Color")
|
imguiInfo.Mat.EnableAttribute("Color")
|
||||||
imguiInfo.Mat.UnBind()
|
imguiInfo.Mat.UnBind()
|
||||||
|
|
||||||
//Init imgui input mapping
|
|
||||||
keys := map[int]int{
|
|
||||||
imgui.KeyTab: sdl.SCANCODE_TAB,
|
|
||||||
imgui.KeyLeftArrow: sdl.SCANCODE_LEFT,
|
|
||||||
imgui.KeyRightArrow: sdl.SCANCODE_RIGHT,
|
|
||||||
imgui.KeyUpArrow: sdl.SCANCODE_UP,
|
|
||||||
imgui.KeyDownArrow: sdl.SCANCODE_DOWN,
|
|
||||||
imgui.KeyPageUp: sdl.SCANCODE_PAGEUP,
|
|
||||||
imgui.KeyPageDown: sdl.SCANCODE_PAGEDOWN,
|
|
||||||
imgui.KeyHome: sdl.SCANCODE_HOME,
|
|
||||||
imgui.KeyEnd: sdl.SCANCODE_END,
|
|
||||||
imgui.KeyInsert: sdl.SCANCODE_INSERT,
|
|
||||||
imgui.KeyDelete: sdl.SCANCODE_DELETE,
|
|
||||||
imgui.KeyBackspace: sdl.SCANCODE_BACKSPACE,
|
|
||||||
imgui.KeySpace: sdl.SCANCODE_BACKSPACE,
|
|
||||||
imgui.KeyEnter: sdl.SCANCODE_RETURN,
|
|
||||||
imgui.KeyEscape: sdl.SCANCODE_ESCAPE,
|
|
||||||
imgui.KeyA: sdl.SCANCODE_A,
|
|
||||||
imgui.KeyC: sdl.SCANCODE_C,
|
|
||||||
imgui.KeyV: sdl.SCANCODE_V,
|
|
||||||
imgui.KeyX: sdl.SCANCODE_X,
|
|
||||||
imgui.KeyY: sdl.SCANCODE_Y,
|
|
||||||
imgui.KeyZ: sdl.SCANCODE_Z,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
|
||||||
for imguiKey, nativeKey := range keys {
|
|
||||||
imIO.KeyMap(imguiKey, nativeKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
return imguiInfo
|
return imguiInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SdlScancodeToImGuiKey(scancode sdl.Scancode) imgui.Key {
|
||||||
|
|
||||||
|
switch scancode {
|
||||||
|
case sdl.SCANCODE_TAB:
|
||||||
|
return imgui.KeyTab
|
||||||
|
case sdl.SCANCODE_LEFT:
|
||||||
|
return imgui.KeyLeftArrow
|
||||||
|
case sdl.SCANCODE_RIGHT:
|
||||||
|
return imgui.KeyRightArrow
|
||||||
|
case sdl.SCANCODE_UP:
|
||||||
|
return imgui.KeyUpArrow
|
||||||
|
case sdl.SCANCODE_DOWN:
|
||||||
|
return imgui.KeyDownArrow
|
||||||
|
case sdl.SCANCODE_PAGEUP:
|
||||||
|
return imgui.KeyPageUp
|
||||||
|
case sdl.SCANCODE_PAGEDOWN:
|
||||||
|
return imgui.KeyPageDown
|
||||||
|
case sdl.SCANCODE_HOME:
|
||||||
|
return imgui.KeyHome
|
||||||
|
case sdl.SCANCODE_END:
|
||||||
|
return imgui.KeyEnd
|
||||||
|
case sdl.SCANCODE_INSERT:
|
||||||
|
return imgui.KeyInsert
|
||||||
|
case sdl.SCANCODE_DELETE:
|
||||||
|
return imgui.KeyDelete
|
||||||
|
case sdl.SCANCODE_BACKSPACE:
|
||||||
|
return imgui.KeyBackspace
|
||||||
|
case sdl.SCANCODE_SPACE:
|
||||||
|
return imgui.KeySpace
|
||||||
|
case sdl.SCANCODE_RETURN:
|
||||||
|
return imgui.KeyEnter
|
||||||
|
case sdl.SCANCODE_ESCAPE:
|
||||||
|
return imgui.KeyEscape
|
||||||
|
case sdl.SCANCODE_APOSTROPHE:
|
||||||
|
return imgui.KeyApostrophe
|
||||||
|
case sdl.SCANCODE_COMMA:
|
||||||
|
return imgui.KeyComma
|
||||||
|
case sdl.SCANCODE_MINUS:
|
||||||
|
return imgui.KeyMinus
|
||||||
|
case sdl.SCANCODE_PERIOD:
|
||||||
|
return imgui.KeyPeriod
|
||||||
|
case sdl.SCANCODE_SLASH:
|
||||||
|
return imgui.KeySlash
|
||||||
|
case sdl.SCANCODE_SEMICOLON:
|
||||||
|
return imgui.KeySemicolon
|
||||||
|
case sdl.SCANCODE_EQUALS:
|
||||||
|
return imgui.KeyEqual
|
||||||
|
case sdl.SCANCODE_LEFTBRACKET:
|
||||||
|
return imgui.KeyLeftBracket
|
||||||
|
case sdl.SCANCODE_BACKSLASH:
|
||||||
|
return imgui.KeyBackslash
|
||||||
|
case sdl.SCANCODE_RIGHTBRACKET:
|
||||||
|
return imgui.KeyRightBracket
|
||||||
|
case sdl.SCANCODE_GRAVE:
|
||||||
|
return imgui.KeyGraveAccent
|
||||||
|
case sdl.SCANCODE_CAPSLOCK:
|
||||||
|
return imgui.KeyCapsLock
|
||||||
|
case sdl.SCANCODE_SCROLLLOCK:
|
||||||
|
return imgui.KeyScrollLock
|
||||||
|
case sdl.SCANCODE_NUMLOCKCLEAR:
|
||||||
|
return imgui.KeyNumLock
|
||||||
|
case sdl.SCANCODE_PRINTSCREEN:
|
||||||
|
return imgui.KeyPrintScreen
|
||||||
|
case sdl.SCANCODE_PAUSE:
|
||||||
|
return imgui.KeyPause
|
||||||
|
case sdl.SCANCODE_KP_0:
|
||||||
|
return imgui.KeyKeypad0
|
||||||
|
case sdl.SCANCODE_KP_1:
|
||||||
|
return imgui.KeyKeypad1
|
||||||
|
case sdl.SCANCODE_KP_2:
|
||||||
|
return imgui.KeyKeypad2
|
||||||
|
case sdl.SCANCODE_KP_3:
|
||||||
|
return imgui.KeyKeypad3
|
||||||
|
case sdl.SCANCODE_KP_4:
|
||||||
|
return imgui.KeyKeypad4
|
||||||
|
case sdl.SCANCODE_KP_5:
|
||||||
|
return imgui.KeyKeypad5
|
||||||
|
case sdl.SCANCODE_KP_6:
|
||||||
|
return imgui.KeyKeypad6
|
||||||
|
case sdl.SCANCODE_KP_7:
|
||||||
|
return imgui.KeyKeypad7
|
||||||
|
case sdl.SCANCODE_KP_8:
|
||||||
|
return imgui.KeyKeypad8
|
||||||
|
case sdl.SCANCODE_KP_9:
|
||||||
|
return imgui.KeyKeypad9
|
||||||
|
case sdl.SCANCODE_KP_PERIOD:
|
||||||
|
return imgui.KeyKeypadDecimal
|
||||||
|
case sdl.SCANCODE_KP_DIVIDE:
|
||||||
|
return imgui.KeyKeypadDivide
|
||||||
|
case sdl.SCANCODE_KP_MULTIPLY:
|
||||||
|
return imgui.KeyKeypadMultiply
|
||||||
|
case sdl.SCANCODE_KP_MINUS:
|
||||||
|
return imgui.KeyKeypadSubtract
|
||||||
|
case sdl.SCANCODE_KP_PLUS:
|
||||||
|
return imgui.KeyKeypadAdd
|
||||||
|
case sdl.SCANCODE_KP_ENTER:
|
||||||
|
return imgui.KeyKeypadEnter
|
||||||
|
case sdl.SCANCODE_KP_EQUALS:
|
||||||
|
return imgui.KeyKeypadEqual
|
||||||
|
case sdl.SCANCODE_LSHIFT:
|
||||||
|
return imgui.KeyLeftShift
|
||||||
|
case sdl.SCANCODE_LCTRL:
|
||||||
|
return imgui.KeyLeftCtrl
|
||||||
|
case sdl.SCANCODE_LALT:
|
||||||
|
return imgui.KeyLeftAlt
|
||||||
|
case sdl.SCANCODE_LGUI:
|
||||||
|
return imgui.KeyLeftSuper
|
||||||
|
case sdl.SCANCODE_RSHIFT:
|
||||||
|
return imgui.KeyRightShift
|
||||||
|
case sdl.SCANCODE_RCTRL:
|
||||||
|
return imgui.KeyRightCtrl
|
||||||
|
case sdl.SCANCODE_RALT:
|
||||||
|
return imgui.KeyRightAlt
|
||||||
|
case sdl.SCANCODE_RGUI:
|
||||||
|
return imgui.KeyRightSuper
|
||||||
|
case sdl.SCANCODE_MENU:
|
||||||
|
return imgui.KeyMenu
|
||||||
|
case sdl.SCANCODE_0:
|
||||||
|
return imgui.Key0
|
||||||
|
case sdl.SCANCODE_1:
|
||||||
|
return imgui.Key1
|
||||||
|
case sdl.SCANCODE_2:
|
||||||
|
return imgui.Key2
|
||||||
|
case sdl.SCANCODE_3:
|
||||||
|
return imgui.Key3
|
||||||
|
case sdl.SCANCODE_4:
|
||||||
|
return imgui.Key4
|
||||||
|
case sdl.SCANCODE_5:
|
||||||
|
return imgui.Key5
|
||||||
|
case sdl.SCANCODE_6:
|
||||||
|
return imgui.Key6
|
||||||
|
case sdl.SCANCODE_7:
|
||||||
|
return imgui.Key7
|
||||||
|
case sdl.SCANCODE_8:
|
||||||
|
return imgui.Key8
|
||||||
|
case sdl.SCANCODE_9:
|
||||||
|
return imgui.Key9
|
||||||
|
case sdl.SCANCODE_A:
|
||||||
|
return imgui.KeyA
|
||||||
|
case sdl.SCANCODE_B:
|
||||||
|
return imgui.KeyB
|
||||||
|
case sdl.SCANCODE_C:
|
||||||
|
return imgui.KeyC
|
||||||
|
case sdl.SCANCODE_D:
|
||||||
|
return imgui.KeyD
|
||||||
|
case sdl.SCANCODE_E:
|
||||||
|
return imgui.KeyE
|
||||||
|
case sdl.SCANCODE_F:
|
||||||
|
return imgui.KeyF
|
||||||
|
case sdl.SCANCODE_G:
|
||||||
|
return imgui.KeyG
|
||||||
|
case sdl.SCANCODE_H:
|
||||||
|
return imgui.KeyH
|
||||||
|
case sdl.SCANCODE_I:
|
||||||
|
return imgui.KeyI
|
||||||
|
case sdl.SCANCODE_J:
|
||||||
|
return imgui.KeyJ
|
||||||
|
case sdl.SCANCODE_K:
|
||||||
|
return imgui.KeyK
|
||||||
|
case sdl.SCANCODE_L:
|
||||||
|
return imgui.KeyL
|
||||||
|
case sdl.SCANCODE_M:
|
||||||
|
return imgui.KeyM
|
||||||
|
case sdl.SCANCODE_N:
|
||||||
|
return imgui.KeyN
|
||||||
|
case sdl.SCANCODE_O:
|
||||||
|
return imgui.KeyO
|
||||||
|
case sdl.SCANCODE_P:
|
||||||
|
return imgui.KeyP
|
||||||
|
case sdl.SCANCODE_Q:
|
||||||
|
return imgui.KeyQ
|
||||||
|
case sdl.SCANCODE_R:
|
||||||
|
return imgui.KeyR
|
||||||
|
case sdl.SCANCODE_S:
|
||||||
|
return imgui.KeyS
|
||||||
|
case sdl.SCANCODE_T:
|
||||||
|
return imgui.KeyT
|
||||||
|
case sdl.SCANCODE_U:
|
||||||
|
return imgui.KeyU
|
||||||
|
case sdl.SCANCODE_V:
|
||||||
|
return imgui.KeyV
|
||||||
|
case sdl.SCANCODE_W:
|
||||||
|
return imgui.KeyW
|
||||||
|
case sdl.SCANCODE_X:
|
||||||
|
return imgui.KeyX
|
||||||
|
case sdl.SCANCODE_Y:
|
||||||
|
return imgui.KeyY
|
||||||
|
case sdl.SCANCODE_Z:
|
||||||
|
return imgui.KeyZ
|
||||||
|
case sdl.SCANCODE_F1:
|
||||||
|
return imgui.KeyF1
|
||||||
|
case sdl.SCANCODE_F2:
|
||||||
|
return imgui.KeyF2
|
||||||
|
case sdl.SCANCODE_F3:
|
||||||
|
return imgui.KeyF3
|
||||||
|
case sdl.SCANCODE_F4:
|
||||||
|
return imgui.KeyF4
|
||||||
|
case sdl.SCANCODE_F5:
|
||||||
|
return imgui.KeyF5
|
||||||
|
case sdl.SCANCODE_F6:
|
||||||
|
return imgui.KeyF6
|
||||||
|
case sdl.SCANCODE_F7:
|
||||||
|
return imgui.KeyF7
|
||||||
|
case sdl.SCANCODE_F8:
|
||||||
|
return imgui.KeyF8
|
||||||
|
case sdl.SCANCODE_F9:
|
||||||
|
return imgui.KeyF9
|
||||||
|
case sdl.SCANCODE_F10:
|
||||||
|
return imgui.KeyF10
|
||||||
|
case sdl.SCANCODE_F11:
|
||||||
|
return imgui.KeyF11
|
||||||
|
case sdl.SCANCODE_F12:
|
||||||
|
return imgui.KeyF12
|
||||||
|
default:
|
||||||
|
return imgui.KeyNone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user