mirror of
https://github.com/libretro/ludo.git
synced 2026-11-12 18:42:17 -10:00
Compare commits
61
Commits
master
...
kivutar/gl41
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71dc28f4a5 | ||
|
|
16cd399681 | ||
|
|
3edf65f9fd | ||
|
|
e01cc6bb86 | ||
|
|
3e084bf7f1 | ||
|
|
2bcbb1d24c | ||
|
|
7d48bb840b | ||
|
|
cb8649a129 | ||
|
|
d74969f50e | ||
|
|
a95767339e | ||
|
|
346dbd8a33 | ||
|
|
c95a3a7a14 | ||
|
|
8647e6f893 | ||
|
|
a43843bab1 | ||
|
|
6097d396df | ||
|
|
e4c5845b57 | ||
|
|
da0092ef53 | ||
|
|
d8afc6031a | ||
|
|
1e0c4a0966 | ||
|
|
e01a76b08d | ||
|
|
73d70cb1f9 | ||
|
|
8b8d49eef4 | ||
|
|
008a70c851 | ||
|
|
1d8f8e8fac | ||
|
|
1146cb6f99 | ||
|
|
dbfbe3ace5 | ||
|
|
e35cba220c | ||
|
|
f32af42ba9 | ||
|
|
827ae5461d | ||
|
|
40396a4b86 | ||
|
|
ff9a3c8f4b | ||
|
|
b8144699f6 | ||
|
|
42d43d63c3 | ||
|
|
9c5c3f5962 | ||
|
|
2dd9150510 | ||
|
|
d127589d50 | ||
|
|
05adbe4f6a | ||
|
|
ab13ef0ebc | ||
|
|
8f51dd3b2d | ||
|
|
4618fb63bf | ||
|
|
2d55e97431 | ||
|
|
c7030756e3 | ||
|
|
614c5c2ed9 | ||
|
|
466c2ef696 | ||
|
|
4914b16606 | ||
|
|
341ad35519 | ||
|
|
933c86b852 | ||
|
|
681dfbc6ab | ||
|
|
f241ef4995 | ||
|
|
6e4b4b634e | ||
|
|
87175ca350 | ||
|
|
7eef38cf2e | ||
|
|
dc56ebfff9 | ||
|
|
d3fd407e77 | ||
|
|
a7cf8d1f99 | ||
|
|
a7da8f7cb9 | ||
|
|
967b0da04f | ||
|
|
c6c0c9c819 | ||
|
|
d41ab5d9d7 | ||
|
|
7e794694f5 | ||
|
|
d861e3d47d |
No files matched your search
@@ -3,7 +3,7 @@ ARCH ?= x86_64
|
||||
VERSION ?= dev
|
||||
BUNDLENAME = $(APP)-$(OS)-$(ARCH)-$(VERSION)
|
||||
|
||||
CORES = atari800 bluemsx swanstation fbneo fceumm gambatte gearsystem genesis_plus_gx handy lutro mednafen_ngp mednafen_pce mednafen_pce_fast mednafen_pcfx mednafen_psx mednafen_saturn mednafen_supergrafx mednafen_vb mednafen_wswan mgba melonds np2kai o2em pcsx_rearmed picodrive pokemini prosystem snes9x stella2014 vecx virtualjaguar
|
||||
CORES = ppsspp dolphin atari800 bluemsx swanstation fbneo fceumm gambatte gearsystem genesis_plus_gx handy lutro mednafen_ngp mednafen_pce mednafen_pce_fast mednafen_pcfx mednafen_psx mednafen_saturn mednafen_supergrafx mednafen_vb mednafen_wswan mgba melonds np2kai o2em pcsx_rearmed picodrive pokemini prosystem snes9x stella2014 vecx virtualjaguar
|
||||
|
||||
ifeq ($(ARCH), arm)
|
||||
CORES := $(filter-out swanstation,$(CORES))
|
||||
|
||||
@@ -201,6 +201,11 @@ func LoadGame(gamePath string) error {
|
||||
log.Println("[Core]: Game loaded: " + gamePath)
|
||||
savefiles.LoadSRAM()
|
||||
|
||||
if state.Core.HWRenderCallback != nil {
|
||||
vid.InitFramebuffer()
|
||||
state.Core.HWRenderCallback.ContextReset()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,13 @@ func environment(cmd uint32, data unsafe.Pointer) bool {
|
||||
state.Core.SetFrameTimeCallback(data)
|
||||
case libretro.EnvironmentSetAudioCallback:
|
||||
state.Core.SetAudioCallback(data)
|
||||
case libretro.EnvironmentSetHWRender:
|
||||
state.Core.HWRenderCallback = libretro.SetHWRenderCallback(
|
||||
data,
|
||||
vid.CurrentFramebuffer,
|
||||
vid.ProcAddress)
|
||||
log.Println("[Env]: HWContextType:", state.Core.HWRenderCallback.HWContextType)
|
||||
return true
|
||||
case libretro.EnvironmentGetCanDupe:
|
||||
libretro.SetBool(data, true)
|
||||
case libretro.EnvironmentSetPixelFormat:
|
||||
@@ -151,6 +158,9 @@ func environment(cmd uint32, data unsafe.Pointer) bool {
|
||||
return environmentGetSystemDirectory(data)
|
||||
case libretro.EnvironmentGetSaveDirectory:
|
||||
return environmentGetSaveDirectory(data)
|
||||
case libretro.EnvironmentGetPrefferedHWRender:
|
||||
log.Println("[Env]: EnvironmentGetPrefferedHWRenderer: 1")
|
||||
libretro.SetUint(data, uint(libretro.HWContextOpenGL))
|
||||
case libretro.EnvironmentShutdown:
|
||||
vid.SetShouldClose(true)
|
||||
case libretro.EnvironmentGetCoreOptionsVersion:
|
||||
|
||||
@@ -9,6 +9,7 @@ require (
|
||||
github.com/fatih/structs v1.1.0
|
||||
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec
|
||||
github.com/go-gl/mathgl v1.0.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
|
||||
@@ -21,6 +21,8 @@ github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8I
|
||||
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec h1:3FLiRYO6PlQFDpUU7OEFlWgjGD1jnBIVSJ5SYRWk+9c=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/mathgl v1.0.0 h1:t9DznWJlXxxjeeKLIdovCOVJQk/GzDEL7h/h+Ro2B68=
|
||||
github.com/go-gl/mathgl v1.0.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
@@ -83,6 +85,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
|
||||
@@ -22,6 +22,14 @@ void bridge_retro_frame_time_callback(retro_frame_time_callback_t f, retro_usec_
|
||||
f(usec);
|
||||
}
|
||||
|
||||
void bridge_retro_hw_context_reset(retro_hw_context_reset_t f) {
|
||||
f();
|
||||
}
|
||||
|
||||
void bridge_retro_hw_context_destroy(retro_hw_context_reset_t f) {
|
||||
f();
|
||||
}
|
||||
|
||||
void bridge_retro_audio_callback(retro_audio_callback_t f) {
|
||||
f();
|
||||
}
|
||||
@@ -168,5 +176,15 @@ int64_t coreGetTimeUsec_cgo() {
|
||||
return coreGetTimeUsec();
|
||||
}
|
||||
|
||||
uintptr_t coreGetCurrentFramebuffer_cgo() {
|
||||
uintptr_t coreGetCurrentFramebuffer();
|
||||
return coreGetCurrentFramebuffer();
|
||||
}
|
||||
|
||||
uintptr_t coreGetProcAddress_cgo(const char *sym) {
|
||||
uintptr_t coreGetProcAddress(const char *sym);
|
||||
return coreGetProcAddress(sym);
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
+100
-16
@@ -33,6 +33,8 @@ void bridge_retro_unload_game(void *f);
|
||||
void bridge_retro_run(void *f);
|
||||
void bridge_retro_reset(void *f);
|
||||
void bridge_retro_frame_time_callback(retro_frame_time_callback_t f, retro_usec_t usec);
|
||||
void bridge_retro_hw_context_reset(retro_hw_context_reset_t f);
|
||||
void bridge_retro_hw_context_destroy(retro_hw_context_reset_t f);
|
||||
void bridge_retro_audio_callback(retro_audio_callback_t f);
|
||||
void bridge_retro_audio_set_state(retro_audio_set_state_callback_t f, bool state);
|
||||
size_t bridge_retro_get_memory_size(void *f, unsigned id);
|
||||
@@ -51,6 +53,8 @@ size_t coreAudioSampleBatch_cgo(const int16_t *data, size_t frames);
|
||||
int16_t coreInputState_cgo(unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
void coreLog_cgo(enum retro_log_level level, const char *msg);
|
||||
int64_t coreGetTimeUsec_cgo();
|
||||
uintptr_t coreGetCurrentFramebuffer_cgo();
|
||||
uintptr_t coreGetProcAddress_cgo(const char *sym);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
@@ -216,6 +220,20 @@ type FrameTimeCallback struct {
|
||||
Reference int64
|
||||
}
|
||||
|
||||
// HWRenderCallback sets an interface to let a libretro core render with
|
||||
// hardware acceleration.
|
||||
type HWRenderCallback struct {
|
||||
HWContextType uint32
|
||||
ContextReset func()
|
||||
Depth bool
|
||||
Stencil bool
|
||||
BottomLeftOrigin bool
|
||||
VersionMajor, VersionMinor uint
|
||||
CacheContext bool
|
||||
ContextDestroy func()
|
||||
DebugContext bool
|
||||
}
|
||||
|
||||
// AudioCallback stores the audio callback itself and the SetState callback
|
||||
type AudioCallback struct {
|
||||
Callback func()
|
||||
@@ -409,26 +427,48 @@ const (
|
||||
MemoryVideoRAM = uint32(C.RETRO_MEMORY_VIDEO_RAM)
|
||||
)
|
||||
|
||||
// Hardware contexts
|
||||
const (
|
||||
HWContextNone = uint32(C.RETRO_HW_CONTEXT_NONE)
|
||||
HWContextOpenGL = uint32(C.RETRO_HW_CONTEXT_OPENGL)
|
||||
HWContextOpenGLES2 = uint32(C.RETRO_HW_CONTEXT_OPENGLES2)
|
||||
HWContextOpenGLCore = uint32(C.RETRO_HW_CONTEXT_OPENGL_CORE)
|
||||
HWContextOpenGLES3 = uint32(C.RETRO_HW_CONTEXT_OPENGLES3)
|
||||
HWContextOpenGLESVersion = uint32(C.RETRO_HW_CONTEXT_OPENGLES_VERSION)
|
||||
HWContextVulkan = uint32(C.RETRO_HW_CONTEXT_VULKAN)
|
||||
HWContextDummy = uint32(C.RETRO_HW_CONTEXT_DUMMY)
|
||||
)
|
||||
|
||||
// Pass this to retro_video_refresh_t if rendering to hardware.
|
||||
// Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
|
||||
var (
|
||||
HWFrameBufferValid = unsafe.Pointer(C.RETRO_HW_FRAME_BUFFER_VALID)
|
||||
)
|
||||
|
||||
type (
|
||||
environmentFunc func(uint32, unsafe.Pointer) bool
|
||||
videoRefreshFunc func(unsafe.Pointer, int32, int32, int32)
|
||||
audioSampleFunc func(int16, int16)
|
||||
audioSampleBatchFunc func([]byte, int32) int32
|
||||
inputPollFunc func()
|
||||
inputStateFunc func(uint, uint32, uint, uint) int16
|
||||
logFunc func(uint32, string)
|
||||
getTimeUsecFunc func() int64
|
||||
environmentFunc func(uint32, unsafe.Pointer) bool
|
||||
videoRefreshFunc func(unsafe.Pointer, int32, int32, int32)
|
||||
audioSampleFunc func(int16, int16)
|
||||
audioSampleBatchFunc func([]byte, int32) int32
|
||||
inputPollFunc func()
|
||||
inputStateFunc func(uint, uint32, uint, uint) int16
|
||||
logFunc func(uint32, string)
|
||||
getTimeUsecFunc func() int64
|
||||
getCurrentFramebufferFunc func() uintptr
|
||||
getProcAddressFunc func(string) uintptr
|
||||
)
|
||||
|
||||
var (
|
||||
environment environmentFunc
|
||||
videoRefresh videoRefreshFunc
|
||||
audioSample audioSampleFunc
|
||||
audioSampleBatch audioSampleBatchFunc
|
||||
inputPoll inputPollFunc
|
||||
inputState inputStateFunc
|
||||
log logFunc
|
||||
getTimeUsec getTimeUsecFunc
|
||||
environment environmentFunc
|
||||
videoRefresh videoRefreshFunc
|
||||
audioSample audioSampleFunc
|
||||
audioSampleBatch audioSampleBatchFunc
|
||||
inputPoll inputPollFunc
|
||||
inputState inputStateFunc
|
||||
log logFunc
|
||||
getTimeUsec getTimeUsecFunc
|
||||
getCurrentFramebuffer getCurrentFramebufferFunc
|
||||
getProcAddress getProcAddressFunc
|
||||
)
|
||||
|
||||
// Load dynamically loads a libretro core at the given path and returns a Core instance
|
||||
@@ -490,6 +530,8 @@ func (core *Core) Deinit() {
|
||||
inputState = nil
|
||||
log = nil
|
||||
getTimeUsec = nil
|
||||
getCurrentFramebuffer = nil
|
||||
getProcAddress = nil
|
||||
}
|
||||
|
||||
// Run runs the game for one video frame.
|
||||
@@ -721,6 +763,16 @@ func coreGetTimeUsec() C.uint64_t {
|
||||
return C.uint64_t(getTimeUsec())
|
||||
}
|
||||
|
||||
//export coreGetCurrentFramebuffer
|
||||
func coreGetCurrentFramebuffer() C.uintptr_t {
|
||||
return C.uintptr_t(getCurrentFramebuffer())
|
||||
}
|
||||
|
||||
//export coreGetProcAddress
|
||||
func coreGetProcAddress(sym *C.char) C.uintptr_t {
|
||||
return C.uintptr_t(getProcAddress(C.GoString(sym)))
|
||||
}
|
||||
|
||||
// SetData is a setter for the data of a GameInfo type
|
||||
func (gi *GameInfo) SetData(bytes []byte) {
|
||||
cstr := C.CString(string(bytes))
|
||||
@@ -883,6 +935,38 @@ func (core *Core) SetFrameTimeCallback(data unsafe.Pointer) {
|
||||
core.FrameTimeCallback = ftc
|
||||
}
|
||||
|
||||
// SetHWRenderCallback is an environment callback helper to set the HWRenderCallback
|
||||
func SetHWRenderCallback(
|
||||
data unsafe.Pointer,
|
||||
currentFramebuffer getCurrentFramebufferFunc,
|
||||
procAddress getProcAddressFunc,
|
||||
) *HWRenderCallback {
|
||||
c := (*C.struct_retro_hw_render_callback)(data)
|
||||
hwrc := HWRenderCallback{}
|
||||
hwrc.HWContextType = uint32(c.context_type)
|
||||
|
||||
getCurrentFramebuffer = currentFramebuffer
|
||||
getProcAddress = procAddress
|
||||
c.get_current_framebuffer = (C.retro_hw_get_current_framebuffer_t)(C.coreGetCurrentFramebuffer_cgo)
|
||||
c.get_proc_address = (C.retro_hw_get_proc_address_t)(C.coreGetProcAddress_cgo)
|
||||
|
||||
hwrc.ContextReset = func() {
|
||||
C.bridge_retro_hw_context_reset((C.retro_hw_context_reset_t)(c.context_reset))
|
||||
}
|
||||
|
||||
hwrc.Depth = bool(c.depth)
|
||||
hwrc.Stencil = bool(c.stencil)
|
||||
hwrc.BottomLeftOrigin = bool(c.bottom_left_origin)
|
||||
hwrc.VersionMajor = uint(c.version_major)
|
||||
hwrc.VersionMinor = uint(c.version_minor)
|
||||
hwrc.CacheContext = bool(c.cache_context)
|
||||
hwrc.ContextDestroy = func() {
|
||||
C.bridge_retro_hw_context_destroy((C.retro_hw_context_reset_t)(c.context_destroy))
|
||||
}
|
||||
hwrc.DebugContext = bool(c.debug_context)
|
||||
return &hwrc
|
||||
}
|
||||
|
||||
// SetAudioCallback is an environment callback helper to set the AudioCallback
|
||||
func (core *Core) SetAudioCallback(data unsafe.Pointer) {
|
||||
c := *(*C.struct_retro_audio_callback)(data)
|
||||
|
||||
@@ -31,6 +31,7 @@ type Core struct {
|
||||
AudioCallback *AudioCallback
|
||||
FrameTimeCallback *FrameTimeCallback
|
||||
DiskControlCallback *DiskControlCallback
|
||||
HWRenderCallback *HWRenderCallback
|
||||
|
||||
MemoryMap []MemoryDescriptor
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/libretro/ludo/settings"
|
||||
"github.com/libretro/ludo/video"
|
||||
)
|
||||
|
||||
@@ -19,8 +19,10 @@ COMPAT_ATTRIBUTE vec2 vertTexCoord;
|
||||
|
||||
COMPAT_VARYING vec2 fragTexCoord;
|
||||
|
||||
uniform mat4 MVP;
|
||||
|
||||
void main() {
|
||||
fragTexCoord = vertTexCoord;
|
||||
gl_Position = vec4(vert, 0.0, 1.0);
|
||||
gl_Position = vec4(vert, 0.0, 1.0) * MVP;
|
||||
}
|
||||
` + "\x00"
|
||||
+20
-24
@@ -8,7 +8,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/golang/freetype"
|
||||
"github.com/golang/freetype/truetype"
|
||||
"golang.org/x/image/font"
|
||||
@@ -174,22 +174,14 @@ func LoadTrueTypeFont(program uint32, r io.Reader, scale int32, low, high rune,
|
||||
f.fontChar = append(f.fontChar, char)
|
||||
}
|
||||
|
||||
// Generate texture
|
||||
gl.GenTextures(1, &f.textureID)
|
||||
gl.BindTexture(gl.TEXTURE_2D, f.textureID)
|
||||
gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(rgba.Rect.Dx()), int32(rgba.Rect.Dy()), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(rgba.Pix))
|
||||
|
||||
gl.GenerateMipmap(gl.TEXTURE_2D)
|
||||
gl.BindTexture(gl.TEXTURE_2D, 0)
|
||||
textureUniform := gl.GetUniformLocation(f.program, gl.Str("Texture\x00"))
|
||||
gl.Uniform1i(textureUniform, 0)
|
||||
|
||||
// Configure VAO/VBO for texture quads
|
||||
genVertexArrays(1, &f.vao)
|
||||
gl.GenBuffers(1, &f.vbo)
|
||||
bindVertexArray(f.vao)
|
||||
|
||||
gl.GenBuffers(1, &f.vbo)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, f.vbo)
|
||||
|
||||
vertAttrib := uint32(gl.GetAttribLocation(f.program, gl.Str("vert\x00")))
|
||||
@@ -200,6 +192,16 @@ func LoadTrueTypeFont(program uint32, r io.Reader, scale int32, low, high rune,
|
||||
gl.EnableVertexAttribArray(texCoordAttrib)
|
||||
gl.VertexAttribPointerWithOffset(texCoordAttrib, 2, gl.FLOAT, false, 4*4, 2*4)
|
||||
|
||||
// Generate texture
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.GenTextures(1, &f.textureID)
|
||||
gl.BindTexture(gl.TEXTURE_2D, f.textureID)
|
||||
gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(rgba.Rect.Dx()), int32(rgba.Rect.Dy()), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(rgba.Pix))
|
||||
gl.GenerateMipmap(gl.TEXTURE_2D)
|
||||
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
|
||||
bindVertexArray(0)
|
||||
|
||||
@@ -224,8 +226,7 @@ func LoadFont(file string, scale int32, windowWidth int, windowHeight int) (*Fon
|
||||
gl.UseProgram(program)
|
||||
|
||||
// Set screen resolution
|
||||
resUniform := gl.GetUniformLocation(program, gl.Str("resolution\x00"))
|
||||
gl.Uniform2f(resUniform, float32(windowWidth), float32(windowHeight))
|
||||
gl.Uniform2f(gl.GetUniformLocation(program, gl.Str("resolution\x00")), float32(windowWidth), float32(windowHeight))
|
||||
|
||||
return LoadTrueTypeFont(program, fd, scale, 32, 256, LeftToRight)
|
||||
}
|
||||
@@ -253,15 +254,6 @@ func (f *Font) Printf(x, y float32, scale float32, fs string, argv ...interface{
|
||||
|
||||
lowChar := rune(32)
|
||||
|
||||
// Setup blending mode
|
||||
gl.Enable(gl.BLEND)
|
||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
// Activate corresponding render state
|
||||
gl.UseProgram(f.program)
|
||||
// Set text color
|
||||
gl.Uniform4f(gl.GetUniformLocation(f.program, gl.Str("textColor\x00")), f.color.R, f.color.G, f.color.B, f.color.A)
|
||||
|
||||
var coords []point
|
||||
|
||||
// Iterate through all characters in string
|
||||
@@ -302,6 +294,10 @@ func (f *Font) Printf(x, y float32, scale float32, fs string, argv ...interface{
|
||||
x += float32((ch.advance >> 6)) * scale // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
|
||||
}
|
||||
|
||||
gl.UseProgram(f.program)
|
||||
gl.Uniform4f(gl.GetUniformLocation(f.program, gl.Str("color\x00")), f.color.R, f.color.G, f.color.B, f.color.A)
|
||||
gl.Enable(gl.BLEND)
|
||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
bindVertexArray(f.vao)
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, f.textureID)
|
||||
|
||||
@@ -6,7 +6,7 @@ var fontFragmentShader = `
|
||||
#define COMPAT_ATTRIBUTE in
|
||||
#define COMPAT_TEXTURE texture
|
||||
#define COMPAT_FRAGCOLOR FragColor
|
||||
out vec4 FragColor;
|
||||
out vec4 COMPAT_FRAGCOLOR;
|
||||
#else
|
||||
#define COMPAT_VARYING varying
|
||||
#define COMPAT_ATTRIBUTE attribute
|
||||
@@ -14,12 +14,13 @@ out vec4 FragColor;
|
||||
#define COMPAT_FRAGCOLOR gl_FragColor
|
||||
#endif
|
||||
|
||||
uniform sampler2D tex;
|
||||
uniform vec4 textColor;
|
||||
uniform sampler2D Texture;
|
||||
uniform vec4 color;
|
||||
|
||||
COMPAT_VARYING vec2 fragTexCoord;
|
||||
|
||||
void main() {
|
||||
vec4 sampled = vec4(1.0, 1.0, 1.0, COMPAT_TEXTURE(tex, fragTexCoord).r);
|
||||
COMPAT_FRAGCOLOR = min(textColor, vec4(1.0, 1.0, 1.0, 1.0)) * sampled;
|
||||
vec4 sampled = vec4(1.0, 1.0, 1.0, COMPAT_TEXTURE(Texture, fragTexCoord).r);
|
||||
COMPAT_FRAGCOLOR = min(color, vec4(1.0, 1.0, 1.0, 1.0)) * sampled;
|
||||
}
|
||||
` + "\x00"
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"image/draw"
|
||||
"os"
|
||||
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
)
|
||||
|
||||
// Color is an RGBA type that we use in the menu
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
|
||||
"github.com/libretro/ludo/settings"
|
||||
"github.com/libretro/ludo/state"
|
||||
|
||||
+15
-1
@@ -4,7 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
)
|
||||
|
||||
func newProgram(vertexShaderSource, fragmentShaderSource string) (uint32, error) {
|
||||
@@ -39,12 +40,25 @@ func newProgram(vertexShaderSource, fragmentShaderSource string) (uint32, error)
|
||||
gl.DeleteShader(vertexShader)
|
||||
gl.DeleteShader(fragmentShader)
|
||||
|
||||
// Only the core rendering code uses MVPs so we set it to identity
|
||||
// to avoid issues with other parts of the program
|
||||
gl.UseProgram(program)
|
||||
mvp := gl.GetUniformLocation(program, gl.Str("MVP\x00"))
|
||||
|
||||
if mvp != -1 {
|
||||
IdentityMatrix := mgl32.Ident4()
|
||||
gl.UniformMatrix4fv(mvp, 1, false, &IdentityMatrix[0])
|
||||
}
|
||||
gl.UseProgram(0)
|
||||
|
||||
return program, nil
|
||||
}
|
||||
|
||||
func compileShader(source string, shaderType uint32) (uint32, error) {
|
||||
shader := gl.CreateShader(shaderType)
|
||||
|
||||
source = "#version 410\n" + source
|
||||
|
||||
csources, free := gl.Strs(source)
|
||||
gl.ShaderSource(shader, 1, csources, nil)
|
||||
free()
|
||||
|
||||
+103
-18
@@ -4,12 +4,14 @@
|
||||
package video
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/go-gl/glfw/v3.3/glfw"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/libretro/ludo/libretro"
|
||||
"github.com/libretro/ludo/settings"
|
||||
"github.com/libretro/ludo/state"
|
||||
@@ -33,6 +35,10 @@ type Video struct {
|
||||
vao uint32
|
||||
vbo uint32
|
||||
texID uint32
|
||||
fboID uint32
|
||||
rboID uint32
|
||||
identityMat mgl32.Mat4 // just a cache
|
||||
orthoMat mgl32.Mat4
|
||||
|
||||
pitch int32 // pitch set by the refresh callback
|
||||
pixFmt uint32 // format set by the environment callback
|
||||
@@ -45,6 +51,7 @@ type Video struct {
|
||||
// Init instanciates the video package
|
||||
func Init(fullscreen bool) *Video {
|
||||
vid := &Video{}
|
||||
vid.identityMat = mgl32.Ident4()
|
||||
vid.Configure(fullscreen)
|
||||
return vid
|
||||
}
|
||||
@@ -52,6 +59,14 @@ func Init(fullscreen bool) *Video {
|
||||
// Reconfigure destroys and recreates the window with new attributes
|
||||
func (video *Video) Reconfigure(fullscreen bool) {
|
||||
if video.Window != nil {
|
||||
// This is the expected frontend behavior and Flycast requires this
|
||||
// for fullscreen toggling to work, but ppsspp breaks. OTOH, ppsspp
|
||||
// breaks in those situations even if we don't call context_destroy
|
||||
// so ignore it.
|
||||
hw := state.Core.HWRenderCallback
|
||||
if state.CoreRunning && hw != nil && hw.ContextDestroy != nil {
|
||||
state.Core.HWRenderCallback.ContextDestroy()
|
||||
}
|
||||
video.Window.Destroy()
|
||||
}
|
||||
video.Configure(fullscreen)
|
||||
@@ -97,6 +112,11 @@ func (video *Video) Configure(fullscreen bool) {
|
||||
height = 240 * 2
|
||||
}
|
||||
|
||||
glfw.WindowHint(glfw.ContextVersionMajor, 4)
|
||||
glfw.WindowHint(glfw.ContextVersionMinor, 1)
|
||||
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
|
||||
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
|
||||
|
||||
var err error
|
||||
video.Window, err = glfw.CreateWindow(width, height, "Ludo", m, nil)
|
||||
if err != nil {
|
||||
@@ -115,6 +135,12 @@ func (video *Video) Configure(fullscreen bool) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
fmt.Println("OpenGL version", version)
|
||||
|
||||
shversion := gl.GoStr(gl.GetString(gl.SHADING_LANGUAGE_VERSION))
|
||||
fmt.Println("OpenGL shading version", shversion)
|
||||
|
||||
fbw, fbh := video.Window.GetFramebufferSize()
|
||||
|
||||
// LoadFont (fontfile, font scale, window width, window height)
|
||||
@@ -167,6 +193,7 @@ func (video *Video) Configure(fullscreen bool) {
|
||||
|
||||
video.UpdateFilter(settings.Current.VideoFilter)
|
||||
|
||||
gl.UseProgram(video.program)
|
||||
textureUniform := gl.GetUniformLocation(video.program, gl.Str("Texture\x00"))
|
||||
gl.Uniform1i(textureUniform, 0)
|
||||
|
||||
@@ -193,20 +220,27 @@ func (video *Video) Configure(fullscreen bool) {
|
||||
video.bpp = 2
|
||||
}
|
||||
|
||||
gl.GenTextures(1, &video.texID)
|
||||
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
if video.texID == 0 && state.Verbose {
|
||||
log.Println("[Video]: Failed to create the vid texture")
|
||||
if video.Geom.MaxWidth == 0 || video.Geom.MaxHeight == 0 {
|
||||
video.Geom.MaxWidth = video.Geom.BaseWidth
|
||||
video.Geom.MaxHeight = video.Geom.BaseHeight
|
||||
}
|
||||
|
||||
gl.GenTextures(1, &video.texID)
|
||||
if video.texID == 0 && state.Verbose {
|
||||
log.Fatalln("[Video]: Failed to create the vid texture")
|
||||
}
|
||||
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, video.texID)
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(video.Geom.MaxWidth), int32(video.Geom.MaxHeight), 0, video.pixType, video.pixFmt, nil)
|
||||
|
||||
video.UpdateFilter(settings.Current.VideoFilter)
|
||||
|
||||
video.coreRatioViewport(fbw, fbh)
|
||||
video.coreRatioViewport(fbw, fbh, video.Geom.BaseWidth, video.Geom.BaseHeight)
|
||||
|
||||
if e := gl.GetError(); e != gl.NO_ERROR {
|
||||
bindVertexArray(0)
|
||||
|
||||
for e := gl.GetError(); e != gl.NO_ERROR; e = gl.NO_ERROR {
|
||||
log.Printf("[Video] OpenGL error: %d\n", e)
|
||||
}
|
||||
}
|
||||
@@ -219,6 +253,7 @@ func (video *Video) Configure(fullscreen bool) {
|
||||
// CRT: zfast-crt
|
||||
// LCD: zfast-lcd
|
||||
func (video *Video) UpdateFilter(filter string) {
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, video.texID)
|
||||
switch filter {
|
||||
case "Smooth":
|
||||
@@ -247,8 +282,9 @@ func (video *Video) UpdateFilter(filter string) {
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||
gl.UseProgram(video.program)
|
||||
gl.Uniform2f(gl.GetUniformLocation(video.program, gl.Str("TextureSize\x00")), float32(video.width), float32(video.height))
|
||||
gl.Uniform2f(gl.GetUniformLocation(video.program, gl.Str("TextureSize\x00")), float32(video.Geom.MaxWidth), float32(video.Geom.MaxHeight))
|
||||
gl.Uniform2f(gl.GetUniformLocation(video.program, gl.Str("InputSize\x00")), float32(video.width), float32(video.height))
|
||||
gl.UseProgram(0)
|
||||
}
|
||||
|
||||
// SetPixelFormat is a callback passed to the libretro implementation.
|
||||
@@ -298,7 +334,7 @@ func (video *Video) ResetRot() {
|
||||
|
||||
// coreRatioViewport configures the vertex array to display the game at the center of the window
|
||||
// while preserving the original ascpect ratio of the game or core
|
||||
func (video *Video) coreRatioViewport(fbWidth int, fbHeight int) (x, y, w, h float32) {
|
||||
func (video *Video) coreRatioViewport(fbWidth, fbHeight, clipWidth, clipHeight int) (x, y, w, h float32) {
|
||||
// Scale the content to fit in the viewport.
|
||||
fbw := float32(fbWidth)
|
||||
fbh := float32(fbHeight)
|
||||
@@ -321,6 +357,12 @@ func (video *Video) coreRatioViewport(fbWidth int, fbHeight int) (x, y, w, h flo
|
||||
y = (fbh - h) / 2
|
||||
|
||||
va := video.vertexArray(x, y, w, h, 1.0)
|
||||
|
||||
va[3] = float32(clipHeight) / float32(video.Geom.MaxHeight)
|
||||
va[10] = float32(clipWidth) / float32(video.Geom.MaxWidth)
|
||||
va[11] = va[3]
|
||||
va[14] = va[10]
|
||||
|
||||
va = rotateUV(va, video.rot)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, video.vbo)
|
||||
gl.BufferData(gl.ARRAY_BUFFER, len(va)*4, gl.Ptr(va), gl.STATIC_DRAW)
|
||||
@@ -336,36 +378,64 @@ func (video *Video) ResizeViewport() {
|
||||
|
||||
// Render the current frame
|
||||
func (video *Video) Render() {
|
||||
// Render directly to the screen
|
||||
bindBackbuffer()
|
||||
|
||||
// We can't trust the core to leave the OpenGL in the same state as
|
||||
// before retro_run() was called so we restore some state manually.
|
||||
gl.Disable(gl.DEPTH_TEST)
|
||||
gl.Disable(gl.CULL_FACE)
|
||||
gl.Disable(gl.DITHER)
|
||||
gl.Disable(gl.STENCIL_TEST)
|
||||
gl.Disable(gl.BLEND)
|
||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
gl.BlendEquation(gl.FUNC_ADD)
|
||||
gl.Enable(gl.TEXTURE_2D)
|
||||
|
||||
video.ResizeViewport()
|
||||
|
||||
if !state.CoreRunning {
|
||||
gl.ClearColor(1, 1, 1, 1)
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
||||
return
|
||||
}
|
||||
|
||||
gl.ClearColor(0, 0, 0, 1)
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
||||
|
||||
// Early return to not render the first frame of a newly loaded game with the
|
||||
// previous game pitch. A sane pitch must be set by video.Refresh first.
|
||||
if video.pitch == 0 {
|
||||
if state.Core.HWRenderCallback == nil && video.pitch == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
fbw, fbh := video.Window.GetFramebufferSize()
|
||||
_, _, w, h := video.coreRatioViewport(fbw, fbh)
|
||||
_, _, w, h := video.coreRatioViewport(fbw, fbh, int(video.width), int(video.height))
|
||||
|
||||
gl.UseProgram(video.program)
|
||||
gl.Uniform2f(gl.GetUniformLocation(video.program, gl.Str("OutputSize\x00")), w, h)
|
||||
|
||||
bindVertexArray(video.vao)
|
||||
if state.Core.HWRenderCallback != nil {
|
||||
gl.UniformMatrix4fv(gl.GetUniformLocation(video.program, gl.Str("MVP\x00")), 1, false, &video.orthoMat[0])
|
||||
}
|
||||
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, video.texID)
|
||||
gl.BindBuffer(gl.ARRAY_BUFFER, video.vbo)
|
||||
|
||||
bindVertexArray(video.vao)
|
||||
gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
|
||||
bindVertexArray(0)
|
||||
|
||||
// Reset MVP to identity to avoid menu issues
|
||||
gl.UniformMatrix4fv(gl.GetUniformLocation(video.program, gl.Str("MVP\x00")), 1, false, &video.identityMat[0])
|
||||
gl.UseProgram(0)
|
||||
}
|
||||
|
||||
// Refresh the texture framebuffer
|
||||
func (video *Video) Refresh(data unsafe.Pointer, width int32, height int32, pitch int32) {
|
||||
bindBackbuffer()
|
||||
|
||||
video.width = width
|
||||
video.height = height
|
||||
video.pitch = pitch
|
||||
@@ -374,13 +444,28 @@ func (video *Video) Refresh(data unsafe.Pointer, width int32, height int32, pitc
|
||||
gl.PixelStorei(gl.UNPACK_ROW_LENGTH, video.pitch/video.bpp)
|
||||
|
||||
gl.UseProgram(video.program)
|
||||
gl.Uniform2f(gl.GetUniformLocation(video.program, gl.Str("TextureSize\x00")), float32(width), float32(height))
|
||||
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, video.texID)
|
||||
|
||||
if data != nil && data != libretro.HWFrameBufferValid {
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(video.Geom.MaxWidth), int32(video.Geom.MaxHeight), 0, video.pixType, video.pixFmt, data)
|
||||
}
|
||||
|
||||
gl.Uniform2f(gl.GetUniformLocation(video.program, gl.Str("TextureSize\x00")), float32(video.Geom.MaxWidth), float32(video.Geom.MaxHeight))
|
||||
gl.Uniform2f(gl.GetUniformLocation(video.program, gl.Str("InputSize\x00")), float32(width), float32(height))
|
||||
|
||||
if data == nil {
|
||||
return
|
||||
}
|
||||
gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, video.pixType, video.pixFmt, data)
|
||||
gl.UseProgram(0)
|
||||
}
|
||||
|
||||
// CurrentFramebuffer returns the current FBO ID
|
||||
func (video *Video) CurrentFramebuffer() uintptr {
|
||||
return uintptr(video.fboID)
|
||||
}
|
||||
|
||||
// ProcAddress returns the address of the proc from GLFW
|
||||
func (video *Video) ProcAddress(procName string) uintptr {
|
||||
return uintptr(glfw.GetProcAddress(procName))
|
||||
}
|
||||
|
||||
// SetRotation rotates the game image as requested by the core
|
||||
|
||||
+68
-3
@@ -1,15 +1,80 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package video
|
||||
|
||||
import (
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"log"
|
||||
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/libretro/ludo/state"
|
||||
)
|
||||
|
||||
// InitFramebuffer initializes and configures the video frame buffer based on
|
||||
// informations from the HWRenderCallback of the libretro core.
|
||||
func (video *Video) InitFramebuffer() {
|
||||
width := int32(video.Geom.MaxWidth)
|
||||
height := int32(video.Geom.MaxHeight)
|
||||
|
||||
log.Printf("[Video]: Initializing HW render (%v x %v).\n", width, height)
|
||||
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, video.texID)
|
||||
gl.TexStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height)
|
||||
|
||||
gl.GenFramebuffers(1, &video.fboID)
|
||||
gl.BindFramebuffer(gl.FRAMEBUFFER, video.fboID)
|
||||
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, video.texID, 0)
|
||||
|
||||
hw := state.Core.HWRenderCallback
|
||||
if hw.Depth {
|
||||
gl.GenRenderbuffers(1, &video.rboID)
|
||||
gl.BindRenderbuffer(gl.RENDERBUFFER, video.rboID)
|
||||
format := gl.DEPTH_COMPONENT16
|
||||
if hw.Stencil {
|
||||
format = gl.DEPTH24_STENCIL8
|
||||
}
|
||||
gl.RenderbufferStorage(gl.RENDERBUFFER, uint32(format), width, height)
|
||||
gl.BindRenderbuffer(gl.RENDERBUFFER, 0)
|
||||
|
||||
if hw.Stencil {
|
||||
gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, video.rboID)
|
||||
} else {
|
||||
gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, video.rboID)
|
||||
}
|
||||
}
|
||||
|
||||
// Default origin is top left
|
||||
video.orthoMat = mgl32.Ortho2D(-1, 1, -1, 1)
|
||||
if hw.BottomLeftOrigin {
|
||||
video.orthoMat = mgl32.Ortho2D(-1, 1, 1, -1)
|
||||
}
|
||||
|
||||
if st := gl.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
|
||||
log.Fatalf("[Video] Framebuffer is not complete. Error: %v\n", st)
|
||||
}
|
||||
|
||||
bindBackbuffer()
|
||||
|
||||
gl.ClearColor(0, 0, 0, 1)
|
||||
if hw.Depth && hw.Stencil {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
|
||||
} else if hw.Depth {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
} else {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
||||
}
|
||||
}
|
||||
|
||||
func bindBackbuffer() {
|
||||
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
|
||||
}
|
||||
|
||||
func genVertexArrays(n int32, arrays *uint32) {
|
||||
gl.GenVertexArraysAPPLE(n, arrays)
|
||||
gl.GenVertexArrays(n, arrays)
|
||||
}
|
||||
|
||||
func bindVertexArray(array uint32) {
|
||||
gl.BindVertexArrayAPPLE(array)
|
||||
gl.BindVertexArray(array)
|
||||
}
|
||||
@@ -1,11 +1,76 @@
|
||||
//go:build !darwin
|
||||
// +build !darwin
|
||||
|
||||
package video
|
||||
|
||||
import (
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"log"
|
||||
|
||||
"github.com/go-gl/gl/v4.1-core/gl"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/libretro/ludo/state"
|
||||
)
|
||||
|
||||
// InitFramebuffer initializes and configures the video frame buffer based on
|
||||
// informations from the HWRenderCallback of the libretro core.
|
||||
func (video *Video) InitFramebuffer() {
|
||||
width := int32(video.Geom.MaxWidth)
|
||||
height := int32(video.Geom.MaxHeight)
|
||||
|
||||
log.Printf("[Video]: Initializing HW render (%v x %v).\n", width, height)
|
||||
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, video.texID)
|
||||
gl.TexStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height)
|
||||
|
||||
gl.GenFramebuffers(1, &video.fboID)
|
||||
gl.BindFramebuffer(gl.FRAMEBUFFER, video.fboID)
|
||||
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, video.texID, 0)
|
||||
|
||||
hw := state.Core.HWRenderCallback
|
||||
if hw.Depth {
|
||||
gl.GenRenderbuffers(1, &video.rboID)
|
||||
gl.BindRenderbuffer(gl.RENDERBUFFER, video.rboID)
|
||||
format := gl.DEPTH_COMPONENT16
|
||||
if hw.Stencil {
|
||||
format = gl.DEPTH24_STENCIL8
|
||||
}
|
||||
gl.RenderbufferStorage(gl.RENDERBUFFER, uint32(format), width, height)
|
||||
gl.BindRenderbuffer(gl.RENDERBUFFER, 0)
|
||||
|
||||
if hw.Stencil {
|
||||
gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, video.rboID)
|
||||
} else {
|
||||
gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, video.rboID)
|
||||
}
|
||||
}
|
||||
|
||||
// Default origin is top left
|
||||
video.orthoMat = mgl32.Ortho2D(-1, 1, -1, 1)
|
||||
if hw.BottomLeftOrigin {
|
||||
video.orthoMat = mgl32.Ortho2D(-1, 1, 1, -1)
|
||||
}
|
||||
|
||||
if st := gl.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
|
||||
log.Fatalf("[Video] Framebuffer is not complete. Error: %v\n", st)
|
||||
}
|
||||
|
||||
bindBackbuffer()
|
||||
|
||||
gl.ClearColor(0, 0, 0, 1)
|
||||
if hw.Depth && hw.Stencil {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
|
||||
} else if hw.Depth {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
} else {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT)
|
||||
}
|
||||
}
|
||||
|
||||
func bindBackbuffer() {
|
||||
gl.BindFramebuffer(gl.FRAMEBUFFER, 0)
|
||||
}
|
||||
|
||||
func genVertexArrays(n int32, arrays *uint32) {
|
||||
gl.GenVertexArrays(n, arrays)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user