Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f646540f9 | |||
| a99dd304ed | |||
| 4e45995ed0 | |||
| a735e01a77 | |||
| abb45e4c4a | |||
| 78ea3ae747 | |||
| b44b00d7e2 | |||
| 70dccd757e | |||
| d7cd5bfc8d | |||
| 3b8e5c06de | |||
| 8e9dbee002 | |||
| 7b2fb19618 | |||
| 9651f77348 | |||
| a16654107b | |||
| 855cbfaba3 | |||
| b025afe1b4 | |||
| 84cd8c28c8 | |||
| 7d5e3e2d82 | |||
| 23a6689346 | |||
| 36488ead04 | |||
| de77d5464e | |||
| 305982deca | |||
| 653a315631 | |||
| c971324b5a | |||
| b5a2479c16 | |||
| 6f54aecb5f | |||
| 7a25aea6ba | |||
| 3071b52c85 | |||
| 1b858bd4ac | |||
| d550767cb6 |
@ -1,22 +1,28 @@
|
||||
name: build-nmage
|
||||
|
||||
on:
|
||||
create:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-nmage-macos:
|
||||
runs-on: macos-10.15
|
||||
runs-on: macos-12
|
||||
steps:
|
||||
- name: Install golang 1.17
|
||||
uses: actions/setup-go@v2
|
||||
|
||||
- name: Install golang 1.18
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
go-version: '^1.18'
|
||||
|
||||
- name: Install assimp-go dylib
|
||||
run: sudo mkdir -p /usr/local/lib && sudo wget https://github.com/bloeys/assimp-go/releases/download/v0.4.2/libassimp_darwin_amd64.dylib -O /usr/local/lib/libassimp.5.dylib
|
||||
|
||||
- name: Install SDL2
|
||||
run: brew install sdl2{,_image,_mixer,_ttf,_gfx} pkg-config
|
||||
|
||||
- name: Clone nmage
|
||||
run: git clone https://github.com/bloeys/nmage
|
||||
|
||||
- name: build nmage
|
||||
working-directory: nmage
|
||||
run: go build .
|
||||
@ -1,6 +1,6 @@
|
||||
# nMage
|
||||
|
||||
[](https://github.com/bloeys/nmage/actions/workflows/run-nmage.yml)
|
||||
[](https://github.com/bloeys/nmage/actions/workflows/build-nmage.yml)
|
||||
|
||||
nMage is a (hopefully!) high performance 3D Game Engine written in Go being developed [live](https://twitch.tv/bloeys), with recordings posted on [YouTube](https://www.youtube.com/channel/UCCf4qyNGPVwpj1HYFGahs_A).
|
||||
|
||||
|
||||
@ -5,8 +5,9 @@ import (
|
||||
"github.com/bloeys/nmage/logging"
|
||||
)
|
||||
|
||||
func T(check bool, msg string) {
|
||||
func T(check bool, msg string, args ...any) {
|
||||
|
||||
if consts.Debug && !check {
|
||||
logging.ErrLog.Panicln("Assert failed:", msg)
|
||||
logging.ErrLog.Panicf("Assert failed: "+msg, args...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package assets
|
||||
|
||||
var (
|
||||
Textures map[uint32]Texture = make(map[uint32]Texture)
|
||||
TexturePaths map[string]uint32 = make(map[string]uint32)
|
||||
Textures = make(map[uint32]Texture)
|
||||
TexturePaths = make(map[string]uint32)
|
||||
)
|
||||
|
||||
func AddTextureToCache(t Texture) {
|
||||
|
||||
@ -2,10 +2,15 @@ package assets
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
@ -30,6 +35,18 @@ type TextureLoadOptions struct {
|
||||
TryLoadFromCache bool
|
||||
WriteToCache bool
|
||||
GenMipMaps bool
|
||||
KeepPixelsInMem bool
|
||||
}
|
||||
|
||||
type Cubemap struct {
|
||||
// These only exists for textures loaded from disk
|
||||
RightPath string
|
||||
LeftPath string
|
||||
TopPath string
|
||||
BotPath string
|
||||
FrontPath string
|
||||
BackPath string
|
||||
TexID uint32
|
||||
}
|
||||
|
||||
func LoadTexturePNG(file string, loadOptions *TextureLoadOptions) (Texture, error) {
|
||||
@ -56,28 +73,10 @@ func LoadTexturePNG(file string, loadOptions *TextureLoadOptions) (Texture, erro
|
||||
}
|
||||
|
||||
tex := Texture{
|
||||
Path: file,
|
||||
Width: int32(img.Bounds().Dx()),
|
||||
Height: int32(img.Bounds().Dy()),
|
||||
Pixels: make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4),
|
||||
Path: file,
|
||||
}
|
||||
|
||||
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
||||
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
||||
i := 0
|
||||
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
||||
for x := 0; x < img.Bounds().Dx(); x++ {
|
||||
|
||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||
|
||||
tex.Pixels[i] = c.R
|
||||
tex.Pixels[i+1] = c.G
|
||||
tex.Pixels[i+2] = c.B
|
||||
tex.Pixels[i+3] = c.A
|
||||
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
tex.Pixels, tex.Width, tex.Height = pixelsFromNrgbaPng(img)
|
||||
|
||||
//Prepare opengl stuff
|
||||
gl.GenTextures(1, &tex.TexID)
|
||||
@ -100,37 +99,21 @@ func LoadTexturePNG(file string, loadOptions *TextureLoadOptions) (Texture, erro
|
||||
AddTextureToCache(tex)
|
||||
}
|
||||
|
||||
if !loadOptions.KeepPixelsInMem {
|
||||
tex.Pixels = nil
|
||||
}
|
||||
|
||||
return tex, nil
|
||||
}
|
||||
|
||||
func LoadTextureInMemImg(img image.Image, loadOptions *TextureLoadOptions) (Texture, error) {
|
||||
func LoadTextureInMemPngImg(img image.Image, loadOptions *TextureLoadOptions) (Texture, error) {
|
||||
|
||||
if loadOptions == nil {
|
||||
loadOptions = &TextureLoadOptions{}
|
||||
}
|
||||
|
||||
tex := Texture{
|
||||
Width: int32(img.Bounds().Dx()),
|
||||
Height: int32(img.Bounds().Dy()),
|
||||
Pixels: make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4),
|
||||
}
|
||||
|
||||
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
||||
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
||||
i := 0
|
||||
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
||||
for x := 0; x < img.Bounds().Dx(); x++ {
|
||||
|
||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||
|
||||
tex.Pixels[i] = c.R
|
||||
tex.Pixels[i+1] = c.G
|
||||
tex.Pixels[i+2] = c.B
|
||||
tex.Pixels[i+3] = c.A
|
||||
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
tex := Texture{}
|
||||
tex.Pixels, tex.Width, tex.Height = pixelsFromNrgbaPng(img)
|
||||
|
||||
//Prepare opengl stuff
|
||||
gl.GenTextures(1, &tex.TexID)
|
||||
@ -153,5 +136,173 @@ func LoadTextureInMemImg(img image.Image, loadOptions *TextureLoadOptions) (Text
|
||||
AddTextureToCache(tex)
|
||||
}
|
||||
|
||||
if !loadOptions.KeepPixelsInMem {
|
||||
tex.Pixels = nil
|
||||
}
|
||||
|
||||
return tex, nil
|
||||
}
|
||||
|
||||
func LoadTextureJpeg(file string, loadOptions *TextureLoadOptions) (Texture, error) {
|
||||
|
||||
if loadOptions == nil {
|
||||
loadOptions = &TextureLoadOptions{}
|
||||
}
|
||||
|
||||
if loadOptions.TryLoadFromCache {
|
||||
if tex, ok := GetTextureFromCachePath(file); ok {
|
||||
return tex, nil
|
||||
}
|
||||
}
|
||||
|
||||
//Load from disk
|
||||
fileBytes, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return Texture{}, err
|
||||
}
|
||||
|
||||
img, err := jpeg.Decode(bytes.NewReader(fileBytes))
|
||||
if err != nil {
|
||||
return Texture{}, err
|
||||
}
|
||||
|
||||
tex := Texture{
|
||||
Path: file,
|
||||
}
|
||||
|
||||
tex.Pixels, tex.Width, tex.Height = pixelsFromNrgbaPng(img)
|
||||
|
||||
//Prepare opengl stuff
|
||||
gl.GenTextures(1, &tex.TexID)
|
||||
gl.BindTexture(gl.TEXTURE_2D, tex.TexID)
|
||||
|
||||
// set the texture wrapping/filtering options (on the currently bound texture object)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||
|
||||
// load and generate the texture
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, tex.Width, tex.Height, 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&tex.Pixels[0]))
|
||||
|
||||
if loadOptions.GenMipMaps {
|
||||
gl.GenerateMipmap(tex.TexID)
|
||||
}
|
||||
|
||||
if loadOptions.WriteToCache {
|
||||
AddTextureToCache(tex)
|
||||
}
|
||||
|
||||
if !loadOptions.KeepPixelsInMem {
|
||||
tex.Pixels = nil
|
||||
}
|
||||
|
||||
return tex, nil
|
||||
}
|
||||
|
||||
func pixelsFromNrgbaPng(img image.Image) (pixels []byte, width, height int32) {
|
||||
|
||||
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
||||
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
||||
i := 0
|
||||
width, height = int32(img.Bounds().Dx()), int32(img.Bounds().Dy())
|
||||
pixels = make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4)
|
||||
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
||||
for x := 0; x < img.Bounds().Dx(); x++ {
|
||||
|
||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||
|
||||
pixels[i] = c.R
|
||||
pixels[i+1] = c.G
|
||||
pixels[i+2] = c.B
|
||||
pixels[i+3] = c.A
|
||||
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
|
||||
return pixels, width, height
|
||||
}
|
||||
|
||||
func pixelsFromNrgbaJpg(img image.Image) (pixels []byte, width, height int32) {
|
||||
|
||||
//NOTE: Load bottom left to top right because this is the texture coordinate system used by OpenGL
|
||||
//NOTE: We only support 8-bit channels (32-bit colors) for now
|
||||
i := 0
|
||||
width, height = int32(img.Bounds().Dx()), int32(img.Bounds().Dy())
|
||||
pixels = make([]byte, img.Bounds().Dx()*img.Bounds().Dy()*4)
|
||||
for y := img.Bounds().Dy() - 1; y >= 0; y-- {
|
||||
for x := 0; x < img.Bounds().Dx(); x++ {
|
||||
|
||||
c := color.NRGBAModel.Convert(img.At(x, y)).(color.NRGBA)
|
||||
|
||||
pixels[i] = c.R
|
||||
pixels[i+1] = c.G
|
||||
pixels[i+2] = c.B
|
||||
pixels[i+3] = c.A
|
||||
|
||||
i += 4
|
||||
}
|
||||
}
|
||||
|
||||
return pixels, width, height
|
||||
}
|
||||
|
||||
func LoadCubemapTextures(rightTex, leftTex, topTex, botTex, frontTex, backTex string) (Cubemap, error) {
|
||||
|
||||
var imgDecoder func(r io.Reader) (image.Image, error)
|
||||
var pixelDecoder func(image.Image) ([]byte, int32, int32)
|
||||
ext := strings.ToLower(path.Ext(rightTex))
|
||||
if ext == ".jpg" || ext == ".jpeg" {
|
||||
imgDecoder = jpeg.Decode
|
||||
pixelDecoder = pixelsFromNrgbaJpg
|
||||
} else if ext == ".png" {
|
||||
imgDecoder = png.Decode
|
||||
pixelDecoder = pixelsFromNrgbaPng
|
||||
} else {
|
||||
return Cubemap{}, fmt.Errorf("unknown image extension: %s. Expected one of: .jpg, .jpeg, .png", ext)
|
||||
}
|
||||
|
||||
cmap := Cubemap{
|
||||
RightPath: rightTex,
|
||||
LeftPath: leftTex,
|
||||
TopPath: topTex,
|
||||
BotPath: botTex,
|
||||
FrontPath: frontTex,
|
||||
BackPath: backTex,
|
||||
}
|
||||
|
||||
gl.GenTextures(1, &cmap.TexID)
|
||||
gl.BindTexture(gl.TEXTURE_CUBE_MAP, cmap.TexID)
|
||||
|
||||
// The order here matters
|
||||
texturePaths := []string{rightTex, leftTex, topTex, botTex, frontTex, backTex}
|
||||
for i := uint32(0); i < uint32(len(texturePaths)); i++ {
|
||||
|
||||
fPath := texturePaths[i]
|
||||
|
||||
//Load from disk
|
||||
fileBytes, err := os.ReadFile(fPath)
|
||||
if err != nil {
|
||||
return Cubemap{}, err
|
||||
}
|
||||
|
||||
img, err := imgDecoder(bytes.NewReader(fileBytes))
|
||||
if err != nil {
|
||||
return Cubemap{}, err
|
||||
}
|
||||
|
||||
pixels, width, height := pixelDecoder(img)
|
||||
|
||||
gl.TexImage2D(uint32(gl.TEXTURE_CUBE_MAP_POSITIVE_X)+i, 0, gl.RGBA8, int32(width), int32(height), 0, gl.RGBA, gl.UNSIGNED_BYTE, unsafe.Pointer(&pixels[0]))
|
||||
}
|
||||
|
||||
// set the texture wrapping/filtering options (on the currently bound texture object)
|
||||
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||
gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE)
|
||||
|
||||
return cmap, nil
|
||||
}
|
||||
|
||||
@ -7,12 +7,15 @@ import (
|
||||
|
||||
type Buffer struct {
|
||||
VAOID uint32
|
||||
//BufID is the ID of the VBO
|
||||
// BufID is the ID of the VBO
|
||||
BufID uint32
|
||||
//IndexBufID is the ID of the index/element buffer
|
||||
IndexBufID uint32
|
||||
// IndexBufID is the ID of the index/element buffer
|
||||
IndexBufID uint32
|
||||
// IndexBufCount is the number of elements in the index buffer
|
||||
// Updated on SetIndexBufData
|
||||
IndexBufCount int32
|
||||
Stride int32
|
||||
// IndexBufCount int32
|
||||
Stride int32
|
||||
|
||||
layout []Element
|
||||
}
|
||||
@ -80,8 +83,8 @@ func (b *Buffer) GetLayout() []Element {
|
||||
return e
|
||||
}
|
||||
|
||||
//SetLayout updates the layout object and the corresponding vertex attributes.
|
||||
//Vertex attributes are also enabled.
|
||||
// SetLayout updates the layout object and the corresponding vertex attributes.
|
||||
// Vertex attributes are also enabled.
|
||||
func (b *Buffer) SetLayout(layout ...Element) {
|
||||
|
||||
b.layout = layout
|
||||
@ -101,7 +104,7 @@ func (b *Buffer) SetLayout(layout ...Element) {
|
||||
|
||||
for i := 0; i < len(layout); i++ {
|
||||
gl.EnableVertexAttribArray(uint32(i))
|
||||
gl.VertexAttribPointer(uint32(i), layout[i].ElementType.CompCount(), layout[i].ElementType.GLType(), false, b.Stride, gl.PtrOffset(layout[i].Offset))
|
||||
gl.VertexAttribPointerWithOffset(uint32(i), layout[i].ElementType.CompCount(), layout[i].ElementType.GLType(), false, b.Stride, uintptr(layout[i].Offset))
|
||||
}
|
||||
|
||||
b.UnBind()
|
||||
|
||||
@ -3,12 +3,13 @@ package engine
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
imgui "github.com/AllenDang/cimgui-go"
|
||||
"github.com/bloeys/nmage/assert"
|
||||
"github.com/bloeys/nmage/input"
|
||||
"github.com/bloeys/nmage/renderer"
|
||||
"github.com/bloeys/nmage/timing"
|
||||
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/inkyblackness/imgui-go/v4"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
@ -26,8 +27,9 @@ type Window struct {
|
||||
func (w *Window) handleInputs() {
|
||||
|
||||
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() {
|
||||
|
||||
//Fire callbacks
|
||||
@ -43,19 +45,32 @@ func (w *Window) handleInputs() {
|
||||
input.HandleMouseWheelEvent(e)
|
||||
|
||||
xDelta, yDelta := input.GetMouseWheelMotion()
|
||||
imIO.AddMouseWheelDelta(float32(xDelta), float32(yDelta))
|
||||
imIo.AddMouseWheelDelta(float32(xDelta), float32(yDelta))
|
||||
|
||||
case *sdl.KeyboardEvent:
|
||||
input.HandleKeyboardEvent(e)
|
||||
|
||||
if e.Type == sdl.KEYDOWN {
|
||||
imIO.KeyPress(int(e.Keysym.Scancode))
|
||||
} else if e.Type == sdl.KEYUP {
|
||||
imIO.KeyRelease(int(e.Keysym.Scancode))
|
||||
input.HandleKeyboardEvent(e)
|
||||
imIo.AddKeyEvent(nmageimgui.SdlScancodeToImGuiKey(e.Keysym.Scancode), e.Type == sdl.KEYDOWN)
|
||||
|
||||
// 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:
|
||||
imIO.AddInputCharacters(string(e.Text[:]))
|
||||
imIo.AddInputCharactersUTF8(e.GetText())
|
||||
|
||||
case *sdl.MouseButtonEvent:
|
||||
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.
|
||||
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(1, input.MouseDown(sdl.BUTTON_RIGHT))
|
||||
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)
|
||||
imIo.SetMouseButtonDown(0, input.MouseDown(sdl.BUTTON_LEFT))
|
||||
imIo.SetMouseButtonDown(1, input.MouseDown(sdl.BUTTON_RIGHT))
|
||||
imIo.SetMouseButtonDown(2, input.MouseDown(sdl.BUTTON_MIDDLE))
|
||||
}
|
||||
|
||||
func (w *Window) handleWindowResize() {
|
||||
@ -112,7 +123,7 @@ func Init() error {
|
||||
|
||||
func initSDL() error {
|
||||
|
||||
err := sdl.Init(sdl.INIT_EVERYTHING)
|
||||
err := sdl.Init(sdl.INIT_TIMER | sdl.INIT_VIDEO)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -23,19 +23,26 @@ type Game interface {
|
||||
func Run(g Game, w *Window, ui nmageimgui.ImguiInfo) {
|
||||
|
||||
isRunning = true
|
||||
|
||||
// Run init with an active Imgui frame to allow init full imgui access
|
||||
timing.FrameStarted()
|
||||
w.handleInputs()
|
||||
|
||||
width, height := w.SDLWin.GetSize()
|
||||
ui.FrameStart(float32(width), float32(height))
|
||||
|
||||
g.Init()
|
||||
|
||||
//Simulate an imgui frame during init so any imgui calls are allowed within init
|
||||
tempWidth, tempHeight := w.SDLWin.GetSize()
|
||||
tempFBWidth, tempFBHeight := w.SDLWin.GLGetDrawableSize()
|
||||
ui.FrameStart(float32(tempWidth), float32(tempHeight))
|
||||
ui.Render(float32(tempWidth), float32(tempHeight), tempFBWidth, tempFBHeight)
|
||||
fbWidth, fbHeight := w.SDLWin.GLGetDrawableSize()
|
||||
ui.Render(float32(width), float32(height), fbWidth, fbHeight)
|
||||
|
||||
timing.FrameEnded()
|
||||
|
||||
for isRunning {
|
||||
|
||||
//PERF: Cache these
|
||||
width, height := w.SDLWin.GetSize()
|
||||
fbWidth, fbHeight := w.SDLWin.GLGetDrawableSize()
|
||||
width, height = w.SDLWin.GetSize()
|
||||
fbWidth, fbHeight = w.SDLWin.GLGetDrawableSize()
|
||||
|
||||
timing.FrameStarted()
|
||||
w.handleInputs()
|
||||
@ -43,7 +50,7 @@ func Run(g Game, w *Window, ui nmageimgui.ImguiInfo) {
|
||||
|
||||
g.Update()
|
||||
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
|
||||
g.Render()
|
||||
ui.Render(float32(width), float32(height), fbWidth, fbHeight)
|
||||
w.SDLWin.GLSwap()
|
||||
|
||||
27
entity/base_comp.go
Executable file
@ -0,0 +1,27 @@
|
||||
package entity
|
||||
|
||||
import "github.com/bloeys/nmage/assert"
|
||||
|
||||
var _ Comp = &BaseComp{}
|
||||
|
||||
type BaseComp struct {
|
||||
Entity *Entity
|
||||
}
|
||||
|
||||
func (b *BaseComp) base() {
|
||||
}
|
||||
|
||||
func (b *BaseComp) Init(parent *Entity) {
|
||||
assert.T(parent != nil, "Component was initialized with a nil parent. That is not allowed.")
|
||||
b.Entity = parent
|
||||
}
|
||||
|
||||
func (b *BaseComp) Name() string {
|
||||
return "Base Component"
|
||||
}
|
||||
|
||||
func (b *BaseComp) Update() {
|
||||
}
|
||||
|
||||
func (b *BaseComp) Destroy() {
|
||||
}
|
||||
62
entity/comp.go
Executable file
@ -0,0 +1,62 @@
|
||||
package entity
|
||||
|
||||
import "github.com/bloeys/nmage/assert"
|
||||
|
||||
type Comp interface {
|
||||
// This ensures that implementors of the Comp interface
|
||||
// always embed BaseComp
|
||||
base()
|
||||
|
||||
Name() string
|
||||
Init(parent *Entity)
|
||||
Update()
|
||||
Destroy()
|
||||
}
|
||||
|
||||
func AddComp[T Comp](e *Entity, c T) {
|
||||
|
||||
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 {
|
||||
|
||||
for i := 0; i < len(e.Comps); i++ {
|
||||
|
||||
_, ok := e.Comps[i].(T)
|
||||
if ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GetComp[T Comp](e *Entity) (out T) {
|
||||
|
||||
for i := 0; i < len(e.Comps); i++ {
|
||||
|
||||
comp, ok := e.Comps[i].(T)
|
||||
if ok {
|
||||
return comp
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// DestroyComp calls Destroy on the component and then removes it from the entities component list
|
||||
func DestroyComp[T Comp](e *Entity) {
|
||||
|
||||
for i := 0; i < len(e.Comps); i++ {
|
||||
|
||||
comp, ok := e.Comps[i].(T)
|
||||
if ok {
|
||||
comp.Destroy()
|
||||
e.Comps = append(e.Comps[:i], e.Comps[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,9 +3,8 @@ package entity
|
||||
type EntityFlag byte
|
||||
|
||||
const (
|
||||
EntityFlag_Unknown EntityFlag = 0
|
||||
EntityFlag_Dead EntityFlag = 1 << (iota - 1)
|
||||
EntityFlag_Alive
|
||||
EntityFlag_None EntityFlag = 0
|
||||
EntityFlag_Alive EntityFlag = 1 << (iota - 1)
|
||||
)
|
||||
|
||||
const (
|
||||
@ -14,64 +13,37 @@ const (
|
||||
IndexBitMask = 0x00_00_FFFF_FFFF_FFFF
|
||||
)
|
||||
|
||||
type EntityHandle uint64
|
||||
|
||||
type Entity struct {
|
||||
|
||||
// Byte 1: Generation; Byte 2: Flags; Bytes 3-8: Index
|
||||
ID uint64
|
||||
ID EntityHandle
|
||||
Comps []Comp
|
||||
}
|
||||
|
||||
func GetGeneration(id uint64) byte {
|
||||
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 uint64) byte {
|
||||
return byte(id >> FlagsShiftBits)
|
||||
func GetFlags(id EntityHandle) EntityFlag {
|
||||
return EntityFlag(id >> FlagsShiftBits)
|
||||
}
|
||||
|
||||
func GetIndex(id uint64) uint64 {
|
||||
return id & IndexBitMask
|
||||
func GetIndex(id EntityHandle) uint64 {
|
||||
return uint64(id & IndexBitMask)
|
||||
}
|
||||
|
||||
func (e *Entity) HasFlag(ef EntityFlag) bool {
|
||||
return GetFlags(e.ID)&byte(ef) > 0
|
||||
}
|
||||
|
||||
func NewEntityId(generation, flags byte, index uint64) uint64 {
|
||||
return index | (uint64(generation) << GenerationShiftBits) | (uint64(flags) << FlagsShiftBits)
|
||||
}
|
||||
|
||||
type Comp interface {
|
||||
Name() string
|
||||
}
|
||||
|
||||
func AddComp(e *Entity, c Comp) {
|
||||
e.Comps = append(e.Comps, c)
|
||||
}
|
||||
|
||||
func GetComp[T Comp](e *Entity) (out T) {
|
||||
|
||||
for i := 0; i < len(e.Comps); i++ {
|
||||
|
||||
comp, ok := e.Comps[i].(T)
|
||||
if ok {
|
||||
return comp
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func GetAllCompOfType[T Comp](e *Entity) (out []T) {
|
||||
|
||||
out = []T{}
|
||||
for i := 0; i < len(e.Comps); i++ {
|
||||
|
||||
comp, ok := e.Comps[i].(T)
|
||||
if ok {
|
||||
out = append(out, comp)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
func NewEntityId(generation byte, flags EntityFlag, index uint64) EntityHandle {
|
||||
return EntityHandle(index | (uint64(generation) << GenerationShiftBits) | (uint64(flags) << FlagsShiftBits))
|
||||
}
|
||||
|
||||
@ -4,6 +4,12 @@ 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
|
||||
@ -12,7 +18,9 @@ type freeListitem struct {
|
||||
type Registry struct {
|
||||
EntityCount uint64
|
||||
Entities []Entity
|
||||
FreeList *freeListitem
|
||||
|
||||
FreeList *freeListitem
|
||||
FreeListSize uint32
|
||||
}
|
||||
|
||||
func (r *Registry) NewEntity() *Entity {
|
||||
@ -22,17 +30,18 @@ func (r *Registry) NewEntity() *Entity {
|
||||
entityToUseIndex := uint64(0)
|
||||
var entityToUse *Entity = nil
|
||||
|
||||
if r.FreeList != 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 GetFlags(e.ID) != byte(EntityFlag_Unknown) && !e.HasFlag(EntityFlag_Dead) {
|
||||
if e.HasFlag(EntityFlag_Alive) {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -47,12 +56,12 @@ func (r *Registry) NewEntity() *Entity {
|
||||
}
|
||||
|
||||
r.EntityCount++
|
||||
entityToUse.ID = NewEntityId(GetGeneration(entityToUse.ID)+1, byte(EntityFlag_Alive), entityToUseIndex)
|
||||
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 uint64) *Entity {
|
||||
func (r *Registry) GetEntity(id EntityHandle) *Entity {
|
||||
|
||||
index := GetIndex(id)
|
||||
gen := GetGeneration(id)
|
||||
@ -67,23 +76,29 @@ func (r *Registry) GetEntity(id uint64) *Entity {
|
||||
return e
|
||||
}
|
||||
|
||||
func (r *Registry) FreeEntity(id uint64) {
|
||||
// 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), byte(EntityFlag_Dead), eIndex)
|
||||
e.ID = NewEntityId(GetGeneration(e.ID), EntityFlag_None, eIndex)
|
||||
|
||||
r.FreeList = &freeListitem{
|
||||
EntityIndex: eIndex,
|
||||
nextFree: r.FreeList,
|
||||
}
|
||||
r.FreeListSize++
|
||||
}
|
||||
|
||||
func NewRegistry(size uint32) *Registry {
|
||||
|
||||
9
go.mod
@ -2,12 +2,13 @@ module github.com/bloeys/nmage
|
||||
|
||||
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/bloeys/assimp-go v0.4.2
|
||||
github.com/bloeys/gglm v0.42.0
|
||||
github.com/inkyblackness/imgui-go/v4 v4.6.0
|
||||
github.com/bloeys/assimp-go v0.4.4
|
||||
github.com/bloeys/gglm v0.43.0
|
||||
)
|
||||
|
||||
require github.com/AllenDang/cimgui-go v0.0.0-20230720025235-f2ff398a66b2
|
||||
|
||||
23
go.sum
@ -1,17 +1,10 @@
|
||||
github.com/bloeys/assimp-go v0.4.2 h1:ArVK74BCFcTO/rCGj2NgZG9xtbjnJdEn5npIeJx1Z04=
|
||||
github.com/bloeys/assimp-go v0.4.2/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0=
|
||||
github.com/bloeys/gglm v0.42.0 h1:UAUFGTaZv3dpZ0YSIQVum3bdeCZgNmx965VLnD2v11k=
|
||||
github.com/bloeys/gglm v0.42.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/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/go.mod h1:my3yRxT7CfOztmvi+0svmwbaqw0KFrxaHxncoyaEIP0=
|
||||
github.com/bloeys/gglm v0.43.0 h1:ZpOghR3PHfpkigTDh+FqxLsF0gN8CD6s/bWoei6LyxI=
|
||||
github.com/bloeys/gglm v0.43.0/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk=
|
||||
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/inkyblackness/imgui-go/v4 v4.6.0 h1:ShcnXEYl80+xREGBY9OpGWePA6FfJChY9Varsm+3jjE=
|
||||
github.com/inkyblackness/imgui-go/v4 v4.6.0/go.mod h1:g8SAGtOYUP7rYaOB2AsVKCEHmPMDmJKgt4z6d+flhb0=
|
||||
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=
|
||||
github.com/veandco/go-sdl2 v0.4.35 h1:NohzsfageDWGtCd9nf7Pc3sokMK/MOK+UA2QMJARWzQ=
|
||||
github.com/veandco/go-sdl2 v0.4.35/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||
|
||||
229
main.go
@ -2,8 +2,9 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/bloeys/assimp-go/asig"
|
||||
imgui "github.com/AllenDang/cimgui-go"
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
"github.com/bloeys/nmage/assets"
|
||||
"github.com/bloeys/nmage/camera"
|
||||
@ -17,14 +18,11 @@ import (
|
||||
"github.com/bloeys/nmage/renderer/rend3dgl"
|
||||
"github.com/bloeys/nmage/timing"
|
||||
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
||||
"github.com/inkyblackness/imgui-go/v4"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
// @Todo:
|
||||
// Complete entity registry (e.g. HasEntity, GetEntity, Generational Indices etc...)
|
||||
// Helper functions to update active entities
|
||||
|
||||
// Integrate physx
|
||||
// Create VAO struct independent from VBO to support multi-VBO use cases (e.g. instancing)
|
||||
// Renderer batching
|
||||
@ -38,6 +36,9 @@ import (
|
||||
const (
|
||||
camSpeed = 15
|
||||
mouseSensitivity = 0.5
|
||||
|
||||
unscaledWindowWidth = 1280
|
||||
unscaledWindowHeight = 720
|
||||
)
|
||||
|
||||
var (
|
||||
@ -48,12 +49,23 @@ var (
|
||||
cam *camera.Camera
|
||||
|
||||
simpleMat *materials.Material
|
||||
cubeMesh *meshes.Mesh
|
||||
skyboxMat *materials.Material
|
||||
|
||||
chairMesh *meshes.Mesh
|
||||
cubeMesh *meshes.Mesh
|
||||
skyboxMesh *meshes.Mesh
|
||||
|
||||
cubeModelMat = gglm.NewTrMatId()
|
||||
|
||||
lightPos1 = gglm.NewVec3(-2, 0, 2)
|
||||
lightColor1 = gglm.NewVec3(1, 1, 1)
|
||||
|
||||
debugDepthMat *materials.Material
|
||||
debugDrawDepthBuffer bool
|
||||
|
||||
skyboxCmap assets.Cubemap
|
||||
|
||||
dpiScaling float32
|
||||
)
|
||||
|
||||
type OurGame struct {
|
||||
@ -62,12 +74,14 @@ type OurGame struct {
|
||||
}
|
||||
|
||||
type TransformComp struct {
|
||||
entity.BaseComp
|
||||
|
||||
Pos *gglm.Vec3
|
||||
Rot *gglm.Quat
|
||||
Scale *gglm.Vec3
|
||||
}
|
||||
|
||||
func (t TransformComp) Name() string {
|
||||
func (t *TransformComp) Name() string {
|
||||
return "Transform Component"
|
||||
}
|
||||
|
||||
@ -77,23 +91,15 @@ func Test() {
|
||||
e1 := lvl.Registry.NewEntity()
|
||||
|
||||
trComp := entity.GetComp[*TransformComp](e1)
|
||||
fmt.Println("Got comp 1:", trComp)
|
||||
fmt.Println("Get comp before adding any:", trComp)
|
||||
|
||||
e1.Comps = append(e1.Comps, &TransformComp{
|
||||
entity.AddComp(e1, &TransformComp{
|
||||
Pos: gglm.NewVec3(0, 0, 0),
|
||||
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||
Scale: gglm.NewVec3(0, 0, 0),
|
||||
}, &TransformComp{
|
||||
Pos: gglm.NewVec3(0, 0, 0),
|
||||
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||
Scale: gglm.NewVec3(1, 1, 1),
|
||||
})
|
||||
|
||||
trComp = entity.GetComp[*TransformComp](e1)
|
||||
fmt.Println("Got comp 2:", trComp)
|
||||
|
||||
trComps := entity.GetAllCompOfType[*TransformComp](e1)
|
||||
fmt.Printf("Got comp 3: %+v, %+v\n", trComps[0], trComps[1])
|
||||
fmt.Println("Get transform comp:", trComp)
|
||||
|
||||
fmt.Printf("Entity: %+v\n", e1)
|
||||
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
||||
@ -113,7 +119,8 @@ func main() {
|
||||
}
|
||||
|
||||
//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 {
|
||||
logging.ErrLog.Fatalln("Failed to create window. Err: ", err)
|
||||
}
|
||||
@ -123,7 +130,7 @@ func main() {
|
||||
|
||||
game := &OurGame{
|
||||
Win: window,
|
||||
ImGUIInfo: nmageimgui.NewImGUI(),
|
||||
ImGUIInfo: nmageimgui.NewImGui(),
|
||||
}
|
||||
window.EventCallbacks = append(window.EventCallbacks, game.handleWindowEvents)
|
||||
|
||||
@ -142,38 +149,94 @@ func (g *OurGame) handleWindowEvents(e sdl.Event) {
|
||||
cam.Update()
|
||||
|
||||
simpleMat.SetUnifMat4("projMat", &cam.ProjMat)
|
||||
debugDepthMat.SetUnifMat4("projMat", &cam.ProjMat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
|
||||
var err error
|
||||
|
||||
//Create materials
|
||||
simpleMat = materials.NewMaterial("Simple Mat", "./res/shaders/simple.glsl")
|
||||
simpleMat = materials.NewMaterial("Simple mat", "./res/shaders/simple.glsl")
|
||||
debugDepthMat = materials.NewMaterial("Debug depth mat", "./res/shaders/debug-depth.glsl")
|
||||
skyboxMat = materials.NewMaterial("Skybox mat", "./res/shaders/skybox.glsl")
|
||||
|
||||
//Load meshes
|
||||
var err error
|
||||
cubeMesh, err = meshes.NewMesh("Cube", "./res/models/tex-cube.fbx", asig.PostProcess(0))
|
||||
cubeMesh, err = meshes.NewMesh("Cube", "./res/models/tex-cube.fbx", 0)
|
||||
if err != nil {
|
||||
logging.ErrLog.Fatalln("Failed to load cube mesh. Err: ", err)
|
||||
logging.ErrLog.Fatalln("Failed to load mesh. Err: ", err)
|
||||
}
|
||||
|
||||
chairMesh, err = meshes.NewMesh("Chair", "./res/models/chair.fbx", 0)
|
||||
if err != nil {
|
||||
logging.ErrLog.Fatalln("Failed to load mesh. Err: ", err)
|
||||
}
|
||||
|
||||
skyboxMesh, err = meshes.NewMesh("Skybox", "./res/models/skybox-cube.obj", 0)
|
||||
if err != nil {
|
||||
logging.ErrLog.Fatalln("Failed to load mesh. Err: ", err)
|
||||
}
|
||||
|
||||
//Load textures
|
||||
tex, err := assets.LoadTexturePNG("./res/textures/Low poly planet.png", nil)
|
||||
tex, err := assets.LoadTexturePNG("./res/textures/pallete-endesga-64-1x.png", nil)
|
||||
if err != nil {
|
||||
logging.ErrLog.Fatalln("Failed to load texture. Err: ", err)
|
||||
}
|
||||
|
||||
//Configure material
|
||||
skyboxCmap, err = assets.LoadCubemapTextures(
|
||||
"./res/textures/sb-right.jpg", "./res/textures/sb-left.jpg",
|
||||
"./res/textures/sb-top.jpg", "./res/textures/sb-bottom.jpg",
|
||||
"./res/textures/sb-front.jpg", "./res/textures/sb-back.jpg",
|
||||
)
|
||||
if err != nil {
|
||||
logging.ErrLog.Fatalln("Failed to load cubemap. Err: ", err)
|
||||
}
|
||||
|
||||
// Configure materials
|
||||
simpleMat.DiffuseTex = tex.TexID
|
||||
|
||||
//Movement, scale and rotation
|
||||
translationMat := gglm.NewTranslationMat(gglm.NewVec3(0, 0, 0))
|
||||
scaleMat := gglm.NewScaleMat(gglm.NewVec3(0.25, 0.25, 0.25))
|
||||
rotMat := gglm.NewRotMat(gglm.NewQuatEuler(gglm.NewVec3(0, 0, 0).AsRad()))
|
||||
scaleMat := gglm.NewScaleMat(gglm.NewVec3(1, 1, 1))
|
||||
rotMat := gglm.NewRotMat(gglm.NewQuatEuler(gglm.NewVec3(-90, -90, 0).AsRad()))
|
||||
|
||||
cubeModelMat.Mul(translationMat.Mul(rotMat.Mul(scaleMat)))
|
||||
simpleMat.SetUnifMat4("modelMat", &cubeModelMat.Mat4)
|
||||
|
||||
// Camera
|
||||
winWidth, winHeight := g.Win.SDLWin.GetSize()
|
||||
@ -181,11 +244,12 @@ func (g *OurGame) Init() {
|
||||
gglm.NewVec3(0, 0, 10),
|
||||
gglm.NewVec3(0, 0, -1),
|
||||
gglm.NewVec3(0, 1, 0),
|
||||
0.1, 20,
|
||||
0.1, 200,
|
||||
45*gglm.Deg2Rad,
|
||||
float32(winWidth)/float32(winHeight),
|
||||
)
|
||||
simpleMat.SetUnifMat4("projMat", &cam.ProjMat)
|
||||
debugDepthMat.SetUnifMat4("projMat", &cam.ProjMat)
|
||||
|
||||
updateViewMat()
|
||||
|
||||
@ -194,21 +258,6 @@ func (g *OurGame) Init() {
|
||||
simpleMat.SetUnifVec3("lightColor1", lightColor1)
|
||||
}
|
||||
|
||||
// @TODO: Add this to gglm
|
||||
// func vecRotByQuat(v *gglm.Vec3, q *gglm.Quat) *gglm.Vec3 {
|
||||
|
||||
// // Reference: https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion
|
||||
// qVec := gglm.NewVec3(q.X(), q.Y(), q.Z())
|
||||
|
||||
// rotatedVec := qVec.Clone().Scale(2 * gglm.DotVec3(v, qVec))
|
||||
|
||||
// t1 := q.W()*q.W() - gglm.DotVec3(qVec, qVec)
|
||||
// rotatedVec.Add(v.Clone().Scale(t1))
|
||||
|
||||
// rotatedVec.Add(gglm.Cross(qVec, v).Scale(2 * q.W()))
|
||||
// return rotatedVec
|
||||
// }
|
||||
|
||||
func (g *OurGame) Update() {
|
||||
|
||||
if input.IsQuitClicked() || input.KeyClicked(sdl.K_ESCAPE) {
|
||||
@ -218,12 +267,14 @@ func (g *OurGame) Update() {
|
||||
g.updateCameraLookAround()
|
||||
g.updateCameraPos()
|
||||
|
||||
imgui.ShowDemoWindow()
|
||||
|
||||
//Rotating cubes
|
||||
if input.KeyDown(sdl.K_SPACE) {
|
||||
cubeModelMat.Rotate(10*timing.DT()*gglm.Deg2Rad, gglm.NewVec3(1, 1, 1).Normalize())
|
||||
simpleMat.SetUnifMat4("modelMat", &cubeModelMat.Mat4)
|
||||
}
|
||||
|
||||
imgui.Begin("Debug controls")
|
||||
if imgui.DragFloat3("Cam Pos", &cam.Pos.Data) {
|
||||
updateViewMat()
|
||||
}
|
||||
@ -231,15 +282,30 @@ func (g *OurGame) Update() {
|
||||
updateViewMat()
|
||||
}
|
||||
|
||||
if imgui.DragFloat3("Light Pos 1", &lightPos1.Data) {
|
||||
simpleMat.SetUnifVec3("lightPos1", lightPos1)
|
||||
}
|
||||
|
||||
if imgui.DragFloat3("Light Color 1", &lightColor1.Data) {
|
||||
simpleMat.SetUnifVec3("lightColor1", lightColor1)
|
||||
}
|
||||
|
||||
imgui.Checkbox("Debug depth buffer", &debugDrawDepthBuffer)
|
||||
imgui.End()
|
||||
|
||||
if input.KeyClicked(sdl.K_F4) {
|
||||
fmt.Printf("Pos: %s; Forward: %s; |Forward|: %f\n", cam.Pos.String(), cam.Forward.String(), cam.Forward.Mag())
|
||||
}
|
||||
|
||||
g.Win.SDLWin.SetTitle(fmt.Sprint("nMage (", timing.GetAvgFPS(), " fps)"))
|
||||
}
|
||||
|
||||
var testString string
|
||||
|
||||
func (g *OurGame) updateCameraLookAround() {
|
||||
|
||||
mouseX, mouseY := input.GetMouseMotion()
|
||||
if mouseX == 0 && mouseY == 0 {
|
||||
if (mouseX == 0 && mouseY == 0) || !input.MouseDown(sdl.BUTTON_RIGHT) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -266,21 +332,26 @@ func (g *OurGame) updateCameraPos() {
|
||||
|
||||
update := false
|
||||
|
||||
var camSpeedScale float32 = 1.0
|
||||
if input.KeyDown(sdl.K_LSHIFT) {
|
||||
camSpeedScale = 2
|
||||
}
|
||||
|
||||
// Forward and backward
|
||||
if input.KeyDown(sdl.K_w) {
|
||||
cam.Pos.Add(cam.Forward.Clone().Scale(camSpeed * timing.DT()))
|
||||
cam.Pos.Add(cam.Forward.Clone().Scale(camSpeed * camSpeedScale * timing.DT()))
|
||||
update = true
|
||||
} else if input.KeyDown(sdl.K_s) {
|
||||
cam.Pos.Add(cam.Forward.Clone().Scale(-camSpeed * timing.DT()))
|
||||
cam.Pos.Add(cam.Forward.Clone().Scale(-camSpeed * camSpeedScale * timing.DT()))
|
||||
update = true
|
||||
}
|
||||
|
||||
// Left and right
|
||||
if input.KeyDown(sdl.K_d) {
|
||||
cam.Pos.Add(gglm.Cross(&cam.Forward, &cam.WorldUp).Normalize().Scale(camSpeed * timing.DT()))
|
||||
cam.Pos.Add(gglm.Cross(&cam.Forward, &cam.WorldUp).Normalize().Scale(camSpeed * camSpeedScale * timing.DT()))
|
||||
update = true
|
||||
} else if input.KeyDown(sdl.K_a) {
|
||||
cam.Pos.Add(gglm.Cross(&cam.Forward, &cam.WorldUp).Normalize().Scale(-camSpeed * timing.DT()))
|
||||
cam.Pos.Add(gglm.Cross(&cam.Forward, &cam.WorldUp).Normalize().Scale(-camSpeed * camSpeedScale * timing.DT()))
|
||||
update = true
|
||||
}
|
||||
|
||||
@ -291,18 +362,53 @@ func (g *OurGame) updateCameraPos() {
|
||||
|
||||
func (g *OurGame) Render() {
|
||||
|
||||
tempModelMat := cubeModelMat.Clone()
|
||||
|
||||
rowSize := 100
|
||||
for y := 0; y < rowSize; y++ {
|
||||
for x := 0; x < rowSize; x++ {
|
||||
tempModelMat.Translate(gglm.NewVec3(-1, 0, 0))
|
||||
window.Rend.Draw(cubeMesh, tempModelMat, simpleMat)
|
||||
}
|
||||
tempModelMat.Translate(gglm.NewVec3(float32(rowSize), -1, 0))
|
||||
matToUse := simpleMat
|
||||
if debugDrawDepthBuffer {
|
||||
matToUse = debugDepthMat
|
||||
}
|
||||
|
||||
g.Win.SDLWin.SetTitle(fmt.Sprint("nMage (", timing.GetAvgFPS(), " fps)"))
|
||||
tempModelMatrix := cubeModelMat.Clone()
|
||||
window.Rend.Draw(chairMesh, tempModelMatrix, matToUse)
|
||||
|
||||
rowSize := 1
|
||||
for y := 0; y < rowSize; y++ {
|
||||
for x := 0; x < rowSize; x++ {
|
||||
tempModelMatrix.Translate(gglm.NewVec3(-6, 0, 0))
|
||||
window.Rend.Draw(cubeMesh, tempModelMatrix, matToUse)
|
||||
}
|
||||
tempModelMatrix.Translate(gglm.NewVec3(float32(rowSize), -1, 0))
|
||||
}
|
||||
|
||||
g.DrawSkybox()
|
||||
}
|
||||
|
||||
func (g *OurGame) DrawSkybox() {
|
||||
|
||||
gl.Disable(gl.CULL_FACE)
|
||||
gl.DepthFunc(gl.LEQUAL)
|
||||
skyboxMesh.Buf.Bind()
|
||||
skyboxMat.Bind()
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_CUBE_MAP, skyboxCmap.TexID)
|
||||
|
||||
viewMat := cam.ViewMat.Clone()
|
||||
viewMat.Set(0, 3, 0)
|
||||
viewMat.Set(1, 3, 0)
|
||||
viewMat.Set(2, 3, 0)
|
||||
viewMat.Set(3, 0, 0)
|
||||
viewMat.Set(3, 1, 0)
|
||||
viewMat.Set(3, 2, 0)
|
||||
viewMat.Set(3, 3, 0)
|
||||
|
||||
skyboxMat.SetUnifMat4("viewMat", viewMat)
|
||||
skyboxMat.SetUnifMat4("projMat", &cam.ProjMat)
|
||||
// window.Rend.Draw(cubeMesh, gglm.NewTrMatId(), skyboxMat)
|
||||
for i := 0; i < len(skyboxMesh.SubMeshes); i++ {
|
||||
gl.DrawElementsBaseVertexWithOffset(gl.TRIANGLES, skyboxMesh.SubMeshes[i].IndexCount, gl.UNSIGNED_INT, uintptr(skyboxMesh.SubMeshes[i].BaseIndex), skyboxMesh.SubMeshes[i].BaseVertex)
|
||||
}
|
||||
|
||||
gl.DepthFunc(gl.LESS)
|
||||
gl.Enable(gl.CULL_FACE)
|
||||
}
|
||||
|
||||
func (g *OurGame) FrameEnd() {
|
||||
@ -315,4 +421,5 @@ func (g *OurGame) DeInit() {
|
||||
func updateViewMat() {
|
||||
cam.Update()
|
||||
simpleMat.SetUnifMat4("viewMat", &cam.ViewMat)
|
||||
debugDepthMat.SetUnifMat4("viewMat", &cam.ViewMat)
|
||||
}
|
||||
|
||||
115
meshes/mesh.go
@ -10,9 +10,16 @@ import (
|
||||
"github.com/bloeys/nmage/buffers"
|
||||
)
|
||||
|
||||
type SubMesh struct {
|
||||
BaseVertex int32
|
||||
BaseIndex uint32
|
||||
IndexCount int32
|
||||
}
|
||||
|
||||
type Mesh struct {
|
||||
Name string
|
||||
Buf buffers.Buffer
|
||||
Name string
|
||||
Buf buffers.Buffer
|
||||
SubMeshes []SubMesh
|
||||
}
|
||||
|
||||
func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (*Mesh, error) {
|
||||
@ -27,29 +34,68 @@ func NewMesh(name, modelPath string, postProcessFlags asig.PostProcess) (*Mesh,
|
||||
return nil, errors.New("No meshes found in file: " + modelPath)
|
||||
}
|
||||
|
||||
mesh := &Mesh{Name: name}
|
||||
sceneMesh := scene.Meshes[0]
|
||||
mesh.Buf = buffers.NewBuffer()
|
||||
|
||||
assert.T(len(sceneMesh.TexCoords[0]) > 0, "Mesh has no UV0")
|
||||
layoutToUse := []buffers.Element{{ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec2}}
|
||||
|
||||
if len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 {
|
||||
layoutToUse = append(layoutToUse, buffers.Element{ElementType: buffers.DataTypeVec4})
|
||||
}
|
||||
mesh.Buf.SetLayout(layoutToUse...)
|
||||
|
||||
var values []float32
|
||||
arrs := []arrToInterleave{{V3s: sceneMesh.Vertices}, {V3s: sceneMesh.Normals}, {V2s: v3sToV2s(sceneMesh.TexCoords[0])}}
|
||||
|
||||
if len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 {
|
||||
arrs = append(arrs, arrToInterleave{V4s: sceneMesh.ColorSets[0]})
|
||||
mesh := &Mesh{
|
||||
Name: name,
|
||||
Buf: buffers.NewBuffer(),
|
||||
SubMeshes: make([]SubMesh, 0, 1),
|
||||
}
|
||||
|
||||
values = interleave(arrs...)
|
||||
// Initial sizes assuming one submesh that has vertex pos+normals+texCoords, and 3 indices per face
|
||||
var vertexBufData []float32 = make([]float32, 0, len(scene.Meshes[0].Vertices)*3*3*2)
|
||||
var indexBufData []uint32 = make([]uint32, 0, len(scene.Meshes[0].Faces)*3)
|
||||
|
||||
mesh.Buf.SetData(values)
|
||||
mesh.Buf.SetIndexBufData(flattenFaces(sceneMesh.Faces))
|
||||
for i := 0; i < len(scene.Meshes); i++ {
|
||||
|
||||
sceneMesh := scene.Meshes[i]
|
||||
|
||||
if len(sceneMesh.TexCoords[0]) == 0 {
|
||||
sceneMesh.TexCoords[0] = make([]gglm.Vec3, len(sceneMesh.Vertices))
|
||||
println("Zeroing tex coords for submesh", i)
|
||||
}
|
||||
|
||||
layoutToUse := []buffers.Element{{ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec3}, {ElementType: buffers.DataTypeVec2}}
|
||||
if len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 {
|
||||
layoutToUse = append(layoutToUse, buffers.Element{ElementType: buffers.DataTypeVec4})
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
mesh.Buf.SetLayout(layoutToUse...)
|
||||
} else {
|
||||
|
||||
// @NOTE: Require that all submeshes have the same vertex buffer layout
|
||||
firstSubmeshLayout := mesh.Buf.GetLayout()
|
||||
assert.T(len(firstSubmeshLayout) == len(layoutToUse), fmt.Sprintf("Vertex layout of submesh %d does not equal vertex layout of the first submesh. Original layout: %v; This layout: %v", i, firstSubmeshLayout, layoutToUse))
|
||||
|
||||
for i := 0; i < len(firstSubmeshLayout); i++ {
|
||||
if firstSubmeshLayout[i].ElementType != layoutToUse[i].ElementType {
|
||||
panic(fmt.Sprintf("Vertex layout of submesh %d does not equal vertex layout of the first submesh. Original layout: %v; This layout: %v", i, firstSubmeshLayout, layoutToUse))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
arrs := []arrToInterleave{{V3s: sceneMesh.Vertices}, {V3s: sceneMesh.Normals}, {V2s: v3sToV2s(sceneMesh.TexCoords[0])}}
|
||||
if len(sceneMesh.ColorSets) > 0 && len(sceneMesh.ColorSets[0]) > 0 {
|
||||
arrs = append(arrs, arrToInterleave{V4s: sceneMesh.ColorSets[0]})
|
||||
}
|
||||
|
||||
indices := flattenFaces(sceneMesh.Faces)
|
||||
mesh.SubMeshes = append(mesh.SubMeshes, SubMesh{
|
||||
|
||||
// Index of the vertex to start from (e.g. if index buffer says use vertex 5, and BaseVertex=3, the vertex used will be vertex 8)
|
||||
BaseVertex: int32(len(vertexBufData)*4) / mesh.Buf.Stride,
|
||||
// Which index (in the index buffer) to start from
|
||||
BaseIndex: uint32(len(indexBufData)),
|
||||
// How many indices in this submesh
|
||||
IndexCount: int32(len(indices)),
|
||||
})
|
||||
|
||||
vertexBufData = append(vertexBufData, interleave(arrs...)...)
|
||||
indexBufData = append(indexBufData, indices...)
|
||||
}
|
||||
|
||||
// fmt.Printf("!!! Vertex count: %d; Submeshes: %+v\n", len(vertexBufData)*4/int(mesh.Buf.Stride), mesh.SubMeshes)
|
||||
mesh.Buf.SetData(vertexBufData)
|
||||
mesh.Buf.SetIndexBufData(indexBufData)
|
||||
return mesh, nil
|
||||
}
|
||||
|
||||
@ -125,31 +171,6 @@ func interleave(arrs ...arrToInterleave) []float32 {
|
||||
return out
|
||||
}
|
||||
|
||||
func flattenVec3(vec3s []gglm.Vec3) []float32 {
|
||||
|
||||
floats := make([]float32, len(vec3s)*3)
|
||||
for i := 0; i < len(vec3s); i++ {
|
||||
floats[i*3+0] = vec3s[i].X()
|
||||
floats[i*3+1] = vec3s[i].Y()
|
||||
floats[i*3+2] = vec3s[i].Z()
|
||||
}
|
||||
|
||||
return floats
|
||||
}
|
||||
|
||||
func flattenVec4(vec4s []gglm.Vec4) []float32 {
|
||||
|
||||
floats := make([]float32, len(vec4s)*4)
|
||||
for i := 0; i < len(vec4s); i++ {
|
||||
floats[i*4+0] = vec4s[i].X()
|
||||
floats[i*4+1] = vec4s[i].Y()
|
||||
floats[i*4+2] = vec4s[i].Z()
|
||||
floats[i*4+3] = vec4s[i].W()
|
||||
}
|
||||
|
||||
return floats
|
||||
}
|
||||
|
||||
func flattenFaces(faces []asig.Face) []uint32 {
|
||||
|
||||
assert.T(len(faces[0].Indices) == 3, fmt.Sprintf("Face doesn't have 3 indices. Index count: %v\n", len(faces[0].Indices)))
|
||||
|
||||
@ -28,7 +28,10 @@ func (r3d *Rend3DGL) Draw(mesh *meshes.Mesh, trMat *gglm.TrMat, mat *materials.M
|
||||
}
|
||||
|
||||
mat.SetUnifMat4("modelMat", &trMat.Mat4)
|
||||
gl.DrawElements(gl.TRIANGLES, mesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0))
|
||||
|
||||
for i := 0; i < len(mesh.SubMeshes); i++ {
|
||||
gl.DrawElementsBaseVertexWithOffset(gl.TRIANGLES, mesh.SubMeshes[i].IndexCount, gl.UNSIGNED_INT, uintptr(mesh.SubMeshes[i].BaseIndex), mesh.SubMeshes[i].BaseVertex)
|
||||
}
|
||||
}
|
||||
|
||||
func (r3d *Rend3DGL) FrameEnd() {
|
||||
|
||||
BIN
res/models/chair.fbx
Executable file
@ -1,46 +0,0 @@
|
||||
# Blender v2.92.0 OBJ File: ''
|
||||
# www.blender.org
|
||||
mtllib obj.mtl
|
||||
o Cube
|
||||
v 2.275618 1.000000 0.349413
|
||||
v 3.520138 -1.000000 0.102233
|
||||
v 2.275618 1.000000 0.752820
|
||||
v 3.520138 -1.000000 1.000000
|
||||
v 0.244520 1.000000 0.349413
|
||||
v -1.000000 -1.000000 0.102233
|
||||
v 0.244520 1.000000 0.752820
|
||||
v -1.000000 -1.000000 1.000000
|
||||
vt 0.806168 0.568832
|
||||
vt 0.693832 0.681168
|
||||
vt 0.693832 0.568832
|
||||
vt 0.375000 1.000000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.375000 0.000000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.125000 0.750000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.806168 0.681168
|
||||
vt 0.625000 0.931168
|
||||
vt 0.625000 0.068832
|
||||
vn 0.0000 1.0000 0.0000
|
||||
vn 0.0000 0.1227 0.9924
|
||||
vn -0.8490 0.5283 0.0000
|
||||
vn 0.0000 -1.0000 0.0000
|
||||
vn 0.8490 0.5283 0.0000
|
||||
vn 0.0000 0.1227 -0.9924
|
||||
usemtl Material
|
||||
s off
|
||||
f 5/1/1 3/2/1 1/3/1
|
||||
f 3/2/2 8/4/2 4/5/2
|
||||
f 8/6/3 5/7/3 6/8/3
|
||||
f 2/9/4 8/10/4 6/11/4
|
||||
f 1/3/5 4/5/5 2/9/5
|
||||
f 5/7/6 2/9/6 6/8/6
|
||||
f 5/1/1 7/12/1 3/2/1
|
||||
f 3/2/2 7/13/2 8/4/2
|
||||
f 8/6/3 7/14/3 5/7/3
|
||||
f 2/9/4 4/5/4 8/10/4
|
||||
f 1/3/5 3/2/5 4/5/5
|
||||
f 5/7/6 1/3/6 2/9/6
|
||||
38
res/models/skybox-cube.obj
Executable file
@ -0,0 +1,38 @@
|
||||
# Blender v2.92.0 OBJ File: 'chair.blend'
|
||||
# www.blender.org
|
||||
o Cube.002_Cube.005
|
||||
v -1.000000 -1.000000 1.000000
|
||||
v -1.000000 1.000000 1.000000
|
||||
v -1.000000 -1.000000 -1.000000
|
||||
v -1.000000 1.000000 -1.000000
|
||||
v 1.000000 -1.000000 1.000000
|
||||
v 1.000000 1.000000 1.000000
|
||||
v 1.000000 -1.000000 -1.000000
|
||||
v 1.000000 1.000000 -1.000000
|
||||
vt 0.375000 0.000000
|
||||
vt 0.625000 0.000000
|
||||
vt 0.625000 0.250000
|
||||
vt 0.375000 0.250000
|
||||
vt 0.625000 0.500000
|
||||
vt 0.375000 0.500000
|
||||
vt 0.625000 0.750000
|
||||
vt 0.375000 0.750000
|
||||
vt 0.625000 1.000000
|
||||
vt 0.375000 1.000000
|
||||
vt 0.125000 0.500000
|
||||
vt 0.125000 0.750000
|
||||
vt 0.875000 0.500000
|
||||
vt 0.875000 0.750000
|
||||
vn -1.0000 0.0000 0.0000
|
||||
vn 0.0000 0.0000 -1.0000
|
||||
vn 1.0000 0.0000 0.0000
|
||||
vn 0.0000 0.0000 1.0000
|
||||
vn 0.0000 -1.0000 0.0000
|
||||
vn 0.0000 1.0000 0.0000
|
||||
s off
|
||||
f 1/1/1 2/2/1 4/3/1 3/4/1
|
||||
f 3/4/2 4/3/2 8/5/2 7/6/2
|
||||
f 7/6/3 8/5/3 6/7/3 5/8/3
|
||||
f 5/8/4 6/7/4 2/9/4 1/10/4
|
||||
f 3/11/5 7/6/5 5/8/5 1/12/5
|
||||
f 8/5/6 4/13/6 2/14/6 6/7/6
|
||||
52
res/shaders/debug-depth.glsl
Executable file
@ -0,0 +1,52 @@
|
||||
//shader:vertex
|
||||
#version 410
|
||||
|
||||
layout(location=0) in vec3 vertPosIn;
|
||||
layout(location=1) in vec3 vertNormalIn;
|
||||
layout(location=2) in vec2 vertUV0In;
|
||||
layout(location=3) in vec3 vertColorIn;
|
||||
|
||||
out vec3 vertNormal;
|
||||
out vec2 vertUV0;
|
||||
out vec3 vertColor;
|
||||
out vec3 fragPos;
|
||||
|
||||
//MVP = Model View Projection
|
||||
uniform mat4 modelMat;
|
||||
uniform mat4 viewMat;
|
||||
uniform mat4 projMat;
|
||||
|
||||
void main()
|
||||
{
|
||||
vertNormal = mat3(transpose(inverse(modelMat))) * vertNormalIn;
|
||||
vertUV0 = vertUV0In;
|
||||
vertColor = vertColorIn;
|
||||
fragPos = vec3(modelMat * vec4(vertPosIn, 1.0));
|
||||
|
||||
gl_Position = projMat * viewMat * modelMat * vec4(vertPosIn, 1.0);
|
||||
}
|
||||
|
||||
//shader:fragment
|
||||
#version 410
|
||||
|
||||
in vec3 vertColor;
|
||||
in vec3 vertNormal;
|
||||
in vec2 vertUV0;
|
||||
in vec3 fragPos;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform float near = 0.1;
|
||||
uniform float far = 200.0;
|
||||
|
||||
float LinearizeDepth(float depth)
|
||||
{
|
||||
float z = depth * 2.0 - 1.0; // back to NDC
|
||||
return (2.0 * near * far) / (far + near - z * (far - near));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
float depth = LinearizeDepth(gl_FragCoord.z) / far;
|
||||
fragColor = vec4(vec3(depth), 1.0);
|
||||
}
|
||||
@ -29,7 +29,7 @@ void main()
|
||||
//shader:fragment
|
||||
#version 410
|
||||
|
||||
uniform float ambientStrength = 0.1;
|
||||
uniform float ambientStrength = 0;
|
||||
uniform vec3 ambientLightColor = vec3(1, 1, 1);
|
||||
|
||||
uniform vec3 lightPos1;
|
||||
|
||||
33
res/shaders/skybox.glsl
Executable file
@ -0,0 +1,33 @@
|
||||
//shader:vertex
|
||||
#version 410
|
||||
|
||||
layout(location=0) in vec3 vertPosIn;
|
||||
layout(location=1) in vec3 vertNormalIn;
|
||||
layout(location=2) in vec2 vertUV0In;
|
||||
layout(location=3) in vec3 vertColorIn;
|
||||
|
||||
out vec3 vertUV0;
|
||||
|
||||
uniform mat4 viewMat;
|
||||
uniform mat4 projMat;
|
||||
|
||||
void main()
|
||||
{
|
||||
vertUV0 = vec3(vertPosIn.x, vertPosIn.y, -vertPosIn.z);
|
||||
vec4 pos = projMat * viewMat * vec4(vertPosIn, 1.0);
|
||||
gl_Position = pos.xyww;
|
||||
}
|
||||
|
||||
//shader:fragment
|
||||
#version 410
|
||||
|
||||
in vec3 vertUV0;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform samplerCube skybox;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = texture(skybox, vertUV0);
|
||||
}
|
||||
BIN
res/textures/pallete-endesga-64-1x.png
Executable file
|
After Width: | Height: | Size: 355 B |
BIN
res/textures/sb-back.jpg
Executable file
|
After Width: | Height: | Size: 1008 KiB |
BIN
res/textures/sb-bottom.jpg
Executable file
|
After Width: | Height: | Size: 274 KiB |
BIN
res/textures/sb-front.jpg
Executable file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
res/textures/sb-left.jpg
Executable file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
res/textures/sb-right.jpg
Executable file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
res/textures/sb-top.jpg
Executable file
|
After Width: | Height: | Size: 338 KiB |
BIN
rsrc_windows_386.syso
Executable file
BIN
rsrc_windows_amd64.syso
Executable file
@ -1,17 +1,16 @@
|
||||
package nmageimgui
|
||||
|
||||
import (
|
||||
imgui "github.com/AllenDang/cimgui-go"
|
||||
"github.com/bloeys/gglm/gglm"
|
||||
"github.com/bloeys/nmage/assert"
|
||||
"github.com/bloeys/nmage/materials"
|
||||
"github.com/bloeys/nmage/timing"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/inkyblackness/imgui-go/v4"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
type ImguiInfo struct {
|
||||
ImCtx *imgui.Context
|
||||
ImCtx imgui.Context
|
||||
|
||||
Mat *materials.Material
|
||||
VaoID uint32
|
||||
@ -22,9 +21,9 @@ type ImguiInfo struct {
|
||||
|
||||
func (i *ImguiInfo) FrameStart(winWidth, winHeight float32) {
|
||||
|
||||
if err := i.ImCtx.SetCurrent(); err != nil {
|
||||
assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
||||
}
|
||||
// if err := i.ImCtx.SetCurrent(); err != nil {
|
||||
// assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
||||
// }
|
||||
|
||||
imIO := imgui.CurrentIO()
|
||||
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) {
|
||||
|
||||
if err := i.ImCtx.SetCurrent(); err != nil {
|
||||
assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
||||
}
|
||||
// if err := i.ImCtx.SetCurrent(); err != nil {
|
||||
// assert.T(false, "Setting imgui ctx as current failed. Err: "+err.Error())
|
||||
// }
|
||||
|
||||
imgui.Render()
|
||||
|
||||
@ -46,7 +45,7 @@ func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32)
|
||||
return
|
||||
}
|
||||
|
||||
drawData := imgui.RenderedDrawData()
|
||||
drawData := imgui.CurrentDrawData()
|
||||
drawData.ScaleClipRects(imgui.Vec2{
|
||||
X: float32(fbWidth) / float32(winWidth),
|
||||
Y: float32(fbHeight) / float32(winHeight),
|
||||
@ -96,11 +95,11 @@ func (i *ImguiInfo) Render(winWidth, winHeight float32, fbWidth, fbHeight int32)
|
||||
// Draw
|
||||
for _, list := range drawData.CommandLists() {
|
||||
|
||||
vertexBuffer, vertexBufferSize := list.VertexBuffer()
|
||||
vertexBuffer, vertexBufferSize := list.GetVertexBuffer()
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, i.VboID)
|
||||
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.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()
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
fontConfigToUse = *fontConfig
|
||||
}
|
||||
|
||||
glyphRangesToUse := imgui.EmptyGlyphRanges
|
||||
glyphRangesToUse := imgui.NewGlyphRange()
|
||||
if glyphRanges != nil {
|
||||
glyphRangesToUse = *glyphRanges
|
||||
}
|
||||
@ -139,11 +138,11 @@ func (i *ImguiInfo) AddFontTTF(fontPath string, fontSize float32, fontConfig *im
|
||||
imIO := imgui.CurrentIO()
|
||||
|
||||
a := imIO.Fonts()
|
||||
f := a.AddFontFromFileTTFV(fontPath, fontSize, fontConfigToUse, glyphRangesToUse)
|
||||
image := a.TextureDataAlpha8()
|
||||
f := a.AddFontFromFileTTFV(fontPath, fontSize, fontConfigToUse, glyphRangesToUse.Data())
|
||||
pixels, width, height, _ := a.GetTextureDataAsAlpha8()
|
||||
|
||||
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
|
||||
}
|
||||
@ -184,15 +183,16 @@ void main()
|
||||
}
|
||||
`
|
||||
|
||||
func NewImGUI() ImguiInfo {
|
||||
func NewImGui() ImguiInfo {
|
||||
|
||||
imguiInfo := ImguiInfo{
|
||||
ImCtx: imgui.CreateContext(nil),
|
||||
ImCtx: imgui.CreateContext(),
|
||||
Mat: materials.NewMaterialSrc("ImGUI Mat", []byte(imguiShdrSrc)),
|
||||
}
|
||||
|
||||
imIO := imgui.CurrentIO()
|
||||
imIO.SetBackendFlags(imIO.GetBackendFlags() | imgui.BackendFlagsRendererHasVtxOffset)
|
||||
io := imgui.CurrentIO()
|
||||
io.SetConfigFlags(io.ConfigFlags() | imgui.ConfigFlagsDockingEnable)
|
||||
io.SetBackendFlags(io.BackendFlags() | imgui.BackendFlagsRendererHasVtxOffset)
|
||||
|
||||
gl.GenVertexArrays(1, &imguiInfo.VaoID)
|
||||
gl.GenBuffers(1, &imguiInfo.VboID)
|
||||
@ -205,11 +205,11 @@ func NewImGUI() ImguiInfo {
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||
gl.PixelStorei(gl.UNPACK_ROW_LENGTH, 0)
|
||||
|
||||
image := imIO.Fonts().TextureDataAlpha8()
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(image.Width), int32(image.Height), 0, gl.RED, gl.UNSIGNED_BYTE, image.Pixels)
|
||||
pixels, width, height, _ := io.Fonts().GetTextureDataAsAlpha8()
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RED, int32(width), int32(height), 0, gl.RED, gl.UNSIGNED_BYTE, pixels)
|
||||
|
||||
// Store our identifier
|
||||
imIO.Fonts().SetTextureID(imgui.TextureID(imguiInfo.TexID))
|
||||
io.Fonts().SetTexID(imgui.TextureID(uintptr(imguiInfo.TexID)))
|
||||
|
||||
//Shader attributes
|
||||
imguiInfo.Mat.Bind()
|
||||
@ -218,35 +218,223 @@ func NewImGUI() ImguiInfo {
|
||||
imguiInfo.Mat.EnableAttribute("Color")
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||