From ad759e03fc75a456af484a6a472dd1e9df6c2df0 Mon Sep 17 00:00:00 2001 From: bloeys Date: Sat, 2 Jul 2022 07:11:40 +0400 Subject: [PATCH] Respect bearing,scaling and other metrics --- glyphs/font_atlas.go | 126 +++++++++++++++++++++++++++------- glyphs/glyphs.go | 131 +++++++++++++++++------------------- main.go | 90 ++++++++++++++++++++++--- res/shaders/glyph.frag.glsl | 9 ++- res/shaders/grid.frag.glsl | 12 ++++ res/shaders/grid.vert.glsl | 22 ++++++ 6 files changed, 288 insertions(+), 102 deletions(-) create mode 100755 res/shaders/grid.frag.glsl create mode 100755 res/shaders/grid.vert.glsl diff --git a/glyphs/font_atlas.go b/glyphs/font_atlas.go index ef435aa..dcd71f7 100755 --- a/glyphs/font_atlas.go +++ b/glyphs/font_atlas.go @@ -1,11 +1,13 @@ package glyphs import ( + "errors" "image" "image/draw" "image/png" "math" "os" + "unicode" "github.com/bloeys/nterm/assert" "github.com/golang/freetype/truetype" @@ -26,11 +28,17 @@ type FontAtlasGlyph struct { SizeU float32 SizeV float32 - Ascent float32 - Descent float32 - Advance float32 + Ascent float32 + Descent float32 + Advance float32 + BearingX float32 + Width float32 } +//NewFontAtlasFromFile reads a TTF or TTC file and produces a font texture atlas containing +//all its characters using the specified options. +// +//Only monospaced fonts are supported func NewFontAtlasFromFile(fontFile string, fontOptions *truetype.Options) (*FontAtlas, error) { fBytes, err := os.ReadFile(fontFile) @@ -44,25 +52,28 @@ func NewFontAtlasFromFile(fontFile string, fontOptions *truetype.Options) (*Font } face := truetype.NewFace(f, fontOptions) - atlas := NewFontAtlasFromFont(f, face, uint(fontOptions.Size)) - return atlas, nil + return NewFontAtlasFromFont(f, face, uint(fontOptions.Size)) } -func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) *FontAtlas { +//NewFontAtlasFromFile uses the passed font to produce a font texture atlas containing +//all its characters using the specified options. +// +//Only monospaced fonts are supported +func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) (*FontAtlas, error) { const maxAtlasSize = 8192 - glyphs := getGlyphsFromRanges(getGlyphRanges(f)) - + glyphs := getGlyphsFromRuneRanges(getGlyphRangesFromFont(f)) assert.T(len(glyphs) > 0, "no glyphs") //Choose atlas size atlasSizeX := 512 atlasSizeY := 512 - _, charWidthFixed, _ := face.GlyphBounds(glyphs[0]) - charWidth := charWidthFixed.Floor() - lineHeight := face.Metrics().Height.Floor() + charWidthFixed, _ := face.GlyphAdvance('L') + charWidth := charWidthFixed.Ceil() + + lineHeight := face.Metrics().Height.Ceil() maxLinesInAtlas := atlasSizeY/lineHeight - 1 charsPerLine := atlasSizeX / charWidth @@ -78,7 +89,10 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) *Fon charsPerLine = atlasSizeX / charWidth linesNeeded = int(math.Ceil(float64(len(glyphs)) / float64(charsPerLine))) } - assert.T(atlasSizeX <= maxAtlasSize, "Atlas size went beyond maximum") + + if atlasSizeX > maxAtlasSize { + return nil, errors.New("atlas size went beyond the maximum of 8192*8192") + } //Create atlas atlas := &FontAtlas{ @@ -102,28 +116,33 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) *Fon atlasSizeYF32 := float32(atlasSizeY) charsOnLine := 0 - lineDx := fixed.P(0, lineHeight) + lineHeightFixed := fixed.I(lineHeight) drawer.Dot = fixed.P(0, lineHeight) for _, g := range glyphs { gBounds, gAdvanceFixed, _ := face.GlyphBounds(g) + advanceCeilF32 := float32(gAdvanceFixed.Ceil()) - descent := gBounds.Max.Y - advanceRoundedF32 := float32(gAdvanceFixed.Floor()) - ascent := -gBounds.Min.Y + ascent := absFixedI26_6(gBounds.Min.Y) + descent := absFixedI26_6(gBounds.Max.Y) + bearingX := absFixedI26_6(gBounds.Min.X) - heightRounded := (ascent + descent).Floor() + glyphWidth := float32((absFixedI26_6(gBounds.Max.X - gBounds.Min.X)).Ceil()) + heightRounded := (ascent + descent).Ceil() atlas.Glyphs[g] = FontAtlasGlyph{ - U: float32(drawer.Dot.X.Floor()) / atlasSizeXF32, - V: (atlasSizeYF32 - float32((drawer.Dot.Y + descent).Floor())) / atlasSizeYF32, + U: float32((drawer.Dot.X + bearingX).Floor()) / atlasSizeXF32, + V: (atlasSizeYF32 - float32((drawer.Dot.Y + descent).Ceil())) / atlasSizeYF32, - SizeU: advanceRoundedF32 / atlasSizeXF32, + SizeU: glyphWidth / atlasSizeXF32, SizeV: float32(heightRounded) / atlasSizeYF32, - Ascent: float32(ascent.Floor()), - Descent: float32(descent.Floor()), - Advance: float32(advanceRoundedF32), + Ascent: float32(ascent.Ceil()), + Descent: float32(descent.Ceil()), + Advance: float32(advanceCeilF32), + + BearingX: float32(bearingX.Ceil()), + Width: glyphWidth, } drawer.DrawString(string(g)) @@ -132,11 +151,11 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) *Fon charsOnLine = 0 drawer.Dot.X = 0 - drawer.Dot = drawer.Dot.Add(lineDx) + drawer.Dot.Y += lineHeightFixed } } - return atlas + return atlas, nil } func SaveImgToPNG(img image.Image, file string) error { @@ -154,3 +173,60 @@ func SaveImgToPNG(img image.Image, file string) error { return nil } + +//getGlyphRangesFromFont returns a list of ranges, each range is: [i][0]<=range<[i][1] +func getGlyphRangesFromFont(f *truetype.Font) (ret [][2]rune) { + + isRuneInPrivateUseArea := func(r rune) bool { + return 0xe000 <= r && r <= 0xf8ff || + 0xf0000 <= r && r <= 0xffffd || + 0x100000 <= r && r <= 0x10fffd + } + + rr := [2]rune{-1, -1} + for r := rune(0); r <= unicode.MaxRune; r++ { + if isRuneInPrivateUseArea(r) { + continue + } + if f.Index(r) == 0 { + continue + } + if rr[1] == r { + rr[1] = r + 1 + continue + } + if rr[0] != -1 { + ret = append(ret, rr) + } + rr = [2]rune{r, r + 1} + } + if rr[0] != -1 { + ret = append(ret, rr) + } + return ret +} + +//getGlyphsFromRuneRanges takes ranges of runes and produces an array of all the runes in these ranges +func getGlyphsFromRuneRanges(ranges [][2]rune) []rune { + + out := make([]rune, 0) + for _, rr := range ranges { + + temp := make([]rune, 0, rr[1]-rr[0]) + for r := rr[0]; r < rr[1]; r++ { + temp = append(temp, r) + } + + out = append(out, temp...) + } + + return out +} + +func absFixedI26_6(x fixed.Int26_6) fixed.Int26_6 { + if x < 0 { + return -x + } + + return x +} diff --git a/glyphs/glyphs.go b/glyphs/glyphs.go index f21fa58..1a63b55 100755 --- a/glyphs/glyphs.go +++ b/glyphs/glyphs.go @@ -2,8 +2,8 @@ package glyphs import ( "errors" + "math" "os" - "unicode" "github.com/bloeys/gglm/gglm" "github.com/bloeys/nmage/assets" @@ -29,67 +29,24 @@ type GlyphRend struct { ScreenHeight int32 } -//getGlyphRanges returns a list of ranges, each range is: [i][0]<=range<[i][1] -func getGlyphRanges(f *truetype.Font) (ret [][2]rune) { - rr := [2]rune{-1, -1} - for r := rune(0); r <= unicode.MaxRune; r++ { - if privateUseArea(r) { - continue - } - if f.Index(r) == 0 { - continue - } - if rr[1] == r { - rr[1] = r + 1 - continue - } - if rr[0] != -1 { - ret = append(ret, rr) - } - rr = [2]rune{r, r + 1} - } - if rr[0] != -1 { - ret = append(ret, rr) - } - return ret -} - -func privateUseArea(r rune) bool { - return 0xe000 <= r && r <= 0xf8ff || - 0xf0000 <= r && r <= 0xffffd || - 0x100000 <= r && r <= 0x10fffd -} - -//getGlyphsFromRanges takes ranges of runes and produces an array of all the runes in these ranges -func getGlyphsFromRanges(ranges [][2]rune) []rune { - - out := make([]rune, 0) - for _, rr := range ranges { - - temp := make([]rune, 0, rr[1]-rr[0]) - for r := rr[0]; r < rr[1]; r++ { - temp = append(temp, r) - } - - out = append(out, temp...) - } - - return out -} - -//DrawTextOpenGL prepares text that will be drawn on the next GlyphRend.Draw call. +//DrawTextOpenGLAbs prepares text that will be drawn on the next GlyphRend.Draw call. //screenPos is in the range [0,1], where (0,0) is the bottom left. //Color is RGBA in the range [0,1]. -func (gr *GlyphRend) DrawTextOpenGL(text string, screenPos *gglm.Vec3, color *gglm.Vec4) { +func (gr *GlyphRend) DrawTextOpenGL01(text string, screenPos *gglm.Vec3, color *gglm.Vec4) { + screenPos.Set(screenPos.X()*float32(gr.ScreenWidth), screenPos.Y()*float32(gr.ScreenHeight), screenPos.Z()) + gr.DrawTextOpenGLAbs(text, screenPos, color) +} - screenWidthF32 := float32(gr.ScreenWidth) - screenHeightF32 := float32(gr.ScreenHeight) - screenPos.Set(screenPos.X()*screenWidthF32, screenPos.Y()*screenHeightF32, screenPos.Z()) +//DrawTextOpenGLAbs prepares text that will be drawn on the next GlyphRend.Draw call. +//screenPos is in the range ([0,ScreenWidth],[0,ScreenHeight]). +//Color is RGBA in the range [0,1]. +func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color *gglm.Vec4) { //Prepass to pre-allocate the buffer rs := []rune(text) const floatsPerGlyph = 18 + // startPos := screenPos.Clone() pos := screenPos.Clone() instancedData := make([]float32, 0, len(rs)*floatsPerGlyph) //This a larger approximation than needed because we don't count spaces etc for i := 0; i < len(rs); i++ { @@ -100,11 +57,15 @@ func (gr *GlyphRend) DrawTextOpenGL(text string, screenPos *gglm.Vec3, color *gg screenPos.SetY(screenPos.Y() - float32(gr.Atlas.LineHeight)) pos = screenPos.Clone() continue + } else if r == ' ' { + pos.SetX(pos.X() + g.Advance) + continue } gr.GlyphCount++ - height := float32(g.Ascent + g.Descent) - scale := gglm.NewVec3(g.Advance, height, 1) + glyphHeight := float32(g.Ascent + g.Descent) + scale := gglm.NewVec3(g.Width, glyphHeight, 1) + // scale := gglm.NewVec3(g.Advance, glyphHeight, 1) //See: https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png //Quads are drawn from the center and so that's our baseline. But chars shouldn't be centered, they should follow ascent/decent/advance. @@ -113,8 +74,8 @@ func (gr *GlyphRend) DrawTextOpenGL(text string, screenPos *gglm.Vec3, color *gg // //Horizontally the character should be drawn from the left edge not the center, so we just move it forward by advance/2 drawPos := *pos - drawPos.SetX(drawPos.X() + g.Advance*0.5) - drawPos.SetY(drawPos.Y() + height*0.5 - g.Descent) + drawPos.SetX(drawPos.X() + g.BearingX) + drawPos.SetY(drawPos.Y() - g.Descent) instancedData = append(instancedData, []float32{ g.U, g.V, @@ -123,13 +84,32 @@ func (gr *GlyphRend) DrawTextOpenGL(text string, screenPos *gglm.Vec3, color *gg g.U + g.SizeU, g.V + g.SizeV, color.R(), color.G(), color.B(), color.A(), //Color - drawPos.X(), drawPos.Y(), drawPos.Z(), //Model pos + roundF32(drawPos.X()), roundF32(drawPos.Y()), drawPos.Z(), //Model pos scale.X(), scale.Y(), scale.Z(), //Model scale }...) pos.SetX(pos.X() + g.Advance) } + //Draw baselines + // g := gr.Atlas.Glyphs['-'] + // lineData := []float32{ + // g.U, g.V, + // g.U + g.SizeU, g.V, + // g.U, g.V + g.SizeV, + // g.U + g.SizeU, g.V + g.SizeV, + + // 1, 0, 0, 1, //Color + // 0, startPos.Y(), 1, //Model pos + // float32(gr.ScreenWidth), 5, 1, //Model scale + // } + + // instancedData = append(instancedData, lineData...) + // lineData[13] -= float32(gr.Atlas.LineHeight) + // instancedData = append(instancedData, lineData...) + // gr.GlyphCount++ + // gr.GlyphCount++ + gr.GlyphVBO = append(gr.GlyphVBO, instancedData...) } @@ -149,10 +129,19 @@ func (gr *GlyphRend) Draw() { gr.GlyphVBO = []float32{} } -func (gr *GlyphRend) SetFace(fontOptions *truetype.Options) { +//SetFace updates the underlying font atlas used by the glyph renderer. +//The current atlas is unchanged if there is an error +func (gr *GlyphRend) SetFace(fontOptions *truetype.Options) error { + face := truetype.NewFace(gr.Atlas.Font, fontOptions) - gr.Atlas = NewFontAtlasFromFont(gr.Atlas.Font, face, uint(fontOptions.Size)) + newAtlas, err := NewFontAtlasFromFont(gr.Atlas.Font, face, uint(fontOptions.Size)) + if err != nil { + return err + } + + gr.Atlas = newAtlas gr.updateFontAtlasTexture("temp-atlas") + return nil } func (gr *GlyphRend) SetFontFromFile(fontFile string, fontOptions *truetype.Options) error { @@ -210,9 +199,9 @@ func (gr *GlyphRend) SetScreenSize(screenWidth, screenHeight int32) { gr.ScreenHeight = screenHeight //The projection matrix fits the screen size. This is needed so we can size and position characters correctly. - projMtx := gglm.Ortho(0, float32(screenWidth), float32(screenHeight), 0, 0.1, 10) - viewMtx := gglm.LookAt(gglm.NewVec3(0, 0, -1), gglm.NewVec3(0, 0, 0), gglm.NewVec3(0, 1, 0)) - projViewMtx := projMtx.Clone().Mul(viewMtx) + projMtx := gglm.Ortho(0, float32(screenWidth), float32(screenHeight), 0, 0.1, 20) + viewMtx := gglm.LookAt(gglm.NewVec3(0, 0, -10), gglm.NewVec3(0, 0, 0), gglm.NewVec3(0, 1, 0)) + projViewMtx := projMtx.Mul(viewMtx) gr.GlyphMat.DiffuseTex = gr.AtlasTex.TexID gr.GlyphMat.SetUnifMat4("projViewMat", &projViewMtx.Mat4) @@ -246,11 +235,12 @@ func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, s ), } + //The quad must be anchored at the bottom-left, not it's center (i.e. bottom-left vertex must be at 0,0) gr.GlyphMesh.Buf.SetData([]float32{ - -0.5, -0.5, 0, - 0.5, -0.5, 0, - -0.5, 0.5, 0, - 0.5, 0.5, 0, + 0, 0, 0, + 1, 0, 0, + 0, 1, 0, + 1, 1, 0, }) gr.GlyphMesh.Buf.SetIndexBufData([]uint32{ @@ -329,5 +319,10 @@ func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, s gr.InstancedBuf.UnBind() gr.SetScreenSize(screenWidth, screenHeight) + // fmt.Printf("lineHeight=%d, glyphInfo=%+v\n", gr.Atlas.LineHeight, gr.Atlas.Glyphs['A']) return gr, nil } + +func roundF32(x float32) float32 { + return float32(math.Round(float64(x))) +} diff --git a/main.go b/main.go index d05fb31..e9158d3 100755 --- a/main.go +++ b/main.go @@ -1,12 +1,17 @@ package main import ( + "fmt" + "github.com/bloeys/gglm/gglm" "github.com/bloeys/nmage/engine" "github.com/bloeys/nmage/input" + "github.com/bloeys/nmage/materials" + "github.com/bloeys/nmage/meshes" "github.com/bloeys/nmage/renderer/rend3dgl" nmageimgui "github.com/bloeys/nmage/ui/imgui" "github.com/bloeys/nterm/glyphs" + "github.com/go-gl/gl/v4.1-core/gl" "github.com/golang/freetype/truetype" "github.com/veandco/go-sdl2/sdl" ) @@ -32,6 +37,9 @@ type program struct { // * Allow texture loading without cache // * Reduce/remove Game interface +const subPixelX = 64 +const subPixelY = 64 + func main() { err := engine.Init() @@ -53,7 +61,7 @@ func main() { rend: rend, imguiInfo: nmageimgui.NewImGUI(), - FontSize: 32, + FontSize: 80, } p.win.EventCallbacks = append(p.win.EventCallbacks, func(e sdl.Event) { @@ -65,6 +73,10 @@ func main() { } }) + //Don't flash white + gl.ClearColor(0, 0, 0, 0) + p.win.SDLWin.GLSwap() + engine.Run(p) } @@ -74,17 +86,31 @@ func (p *program) Init() { if err != nil { panic("Failed to get display DPI. Err: " + err.Error()) } - println("DPI:", dpi) + fmt.Println("DPI:", dpi) w, h := p.win.SDLWin.GetSize() - p.GlyphRend, err = glyphs.NewGlyphRend("./res/fonts/Consolas.ttf", &truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi}, w, h) + p.GlyphRend, err = glyphs.NewGlyphRend("./res/fonts/Consolas.ttf", &truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi, SubPixelsX: subPixelX, SubPixelsY: subPixelY}, w, h) if err != nil { panic("Failed to create atlas from font file. Err: " + err.Error()) } + + glyphs.SaveImgToPNG(p.GlyphRend.Atlas.Img, "./debug-atlas.png") } +var gridMesh *meshes.Mesh +var gridMat *materials.Material + func (p *program) Start() { + var err error + gridMesh, err = meshes.NewMesh("grid", "./res/models/quad.obj", 0) + if err != nil { + panic(err.Error()) + } + + gridMat = materials.NewMaterial("grid", "./res/shaders/grid") + gridMat.SetAttribute(gridMesh.Buf) + p.handleWindowResize() } func (p *program) FrameStart() { @@ -100,6 +126,7 @@ func (p *program) Update() { p.handleWindowResize() } + oldFont := p.FontSize fontSizeChanged := false if input.KeyClicked(sdl.K_KP_PLUS) { p.FontSize += 2 @@ -110,16 +137,62 @@ func (p *program) Update() { } if fontSizeChanged { - p.GlyphRend.SetFace(&truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi}) + + err := p.GlyphRend.SetFace(&truetype.Options{Size: float64(p.FontSize), DPI: p.Dpi, SubPixelsX: subPixelX, SubPixelsY: subPixelY}) + if err != nil { + p.FontSize = oldFont + println("Failed to update font face. Err: " + err.Error()) + } else { + glyphs.SaveImgToPNG(p.GlyphRend.Atlas.Img, "./debug-atlas.png") + println("New font size:", p.FontSize) + } + } + + var speed float32 = 1 + if input.KeyDown(sdl.K_RIGHT) { + xOff += speed + } else if input.KeyDown(sdl.K_LEFT) { + xOff -= speed + } + + if input.KeyDown(sdl.K_UP) { + yOff += speed + } else if input.KeyDown(sdl.K_DOWN) { + yOff -= speed } } +var xOff float32 = 0 +var yOff float32 = 0 + func (p *program) Render() { defer p.GlyphRend.Draw() textColor := gglm.NewVec4(1, 1, 1, 1) - p.GlyphRend.DrawTextOpenGL("Hello there, friend.", gglm.NewVec3(0, 0.9, 0), textColor) + // p.GlyphRend.DrawTextOpenGL("y", gglm.NewVec3(0+xOff, 0+yOff, 0), textColor) + // p.GlyphRend.DrawTextOpenGL("A\np-+_; This is", gglm.NewVec3(0.3+xOff, 0.5+yOff, 0), textColor) + // p.GlyphRend.DrawTextOpenGLAbs("Hello there, friend.\nABCDEFGHIJKLMNOPQRSTUVWXYZ", gglm.NewVec3(0, 0, 0), textColor) + p.GlyphRend.DrawTextOpenGLAbs(" Hello there, friend|.\n ABCDEFGHIJKLMNOPQRSTUVWXYZ", gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*2+yOff, 0), textColor) + + // p.drawGrid() +} + +func (p *program) drawGrid() { + + sizeX := float32(p.GlyphRend.ScreenWidth) + sizeY := float32(p.GlyphRend.ScreenHeight) + + //columns + adv := p.GlyphRend.Atlas.Glyphs['A'].Advance + for i := int32(0); i < p.GlyphRend.ScreenWidth; i += int32(adv) { + p.rend.Draw(gridMesh, gglm.NewTrMatId().Translate(gglm.NewVec3(float32(i)+0.5, sizeY/2, 0)).Scale(gglm.NewVec3(1, sizeY, 1)), gridMat) + } + + //rows + for i := int32(0); i < p.GlyphRend.ScreenHeight; i += int32(p.GlyphRend.Atlas.LineHeight) { + p.rend.Draw(gridMesh, gglm.NewTrMatId().Translate(gglm.NewVec3(sizeX/2, float32(i), 0)).Scale(gglm.NewVec3(sizeX, 1, 1)), gridMat) + } } func (p *program) FrameEnd() { @@ -142,9 +215,10 @@ func (p *program) Deinit() { } func (p *program) handleWindowResize() { - - println("Old size:", p.GlyphRend.ScreenWidth, ",", p.GlyphRend.ScreenHeight) w, h := p.win.SDLWin.GetSize() p.GlyphRend.SetScreenSize(w, h) - println("New size:", w, ",", h, "\n") + + projMtx := gglm.Ortho(0, float32(w), float32(h), 0, 0.1, 20) + viewMtx := gglm.LookAt(gglm.NewVec3(0, 0, -10), gglm.NewVec3(0, 0, 0), gglm.NewVec3(0, 1, 0)) + gridMat.SetUnifMat4("projViewMat", &projMtx.Mul(viewMtx).Mat4) } diff --git a/res/shaders/glyph.frag.glsl b/res/shaders/glyph.frag.glsl index 1c347ab..cf46b5e 100755 --- a/res/shaders/glyph.frag.glsl +++ b/res/shaders/glyph.frag.glsl @@ -11,5 +11,12 @@ uniform sampler2D diffTex; void main() { vec4 texColor = texture(diffTex, vertUV0); - fragColor = vec4(vertColor.rgb, texColor.r*texColor.a); + // if (texColor.r == 0) + // { + // fragColor = vec4(0,1,0,0.25); + // } + // else + { + fragColor = vec4(vertColor.rgb, texColor.r); + } } diff --git a/res/shaders/grid.frag.glsl b/res/shaders/grid.frag.glsl new file mode 100755 index 0000000..34c6532 --- /dev/null +++ b/res/shaders/grid.frag.glsl @@ -0,0 +1,12 @@ +#version 410 + +in vec4 vertColor; +in vec2 vertUV0; +in vec3 fragPos; + +out vec4 fragColor; + +void main() +{ + fragColor = vec4(1, 1, 1, 1); +} diff --git a/res/shaders/grid.vert.glsl b/res/shaders/grid.vert.glsl new file mode 100755 index 0000000..d07825c --- /dev/null +++ b/res/shaders/grid.vert.glsl @@ -0,0 +1,22 @@ +#version 410 + +layout(location=0) in vec3 vertPosIn; +layout(location=1) in vec4 vertNormalIn; +layout(location=2) in vec2 vertUV0In; +layout(location=3) in vec4 vertColorIn; + +out vec2 vertUV0; +out vec4 vertColor; +out vec3 fragPos; + +uniform mat4 modelMat; +uniform mat4 projViewMat; + +void main() +{ + vertUV0 = vertUV0In; + vertColor = vertColorIn; + fragPos = vec3(modelMat * vec4(vertPosIn, 1.0)); + + gl_Position = projViewMat * modelMat * vec4(vertPosIn, 1.0); +} \ No newline at end of file