2023-08-03 16:51:17 +02:00
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2023-07-07 19:15:47 +02:00
|
|
|
// SPDX-FileCopyrightText: 2012 The glfw3-go Authors
|
|
|
|
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors
|
|
|
|
|
2023-07-08 06:59:51 +02:00
|
|
|
//go:build darwin || freebsd || linux || netbsd || openbsd
|
2023-07-05 03:51:55 +02:00
|
|
|
|
2023-07-21 18:02:55 +02:00
|
|
|
package cglfw
|
2023-07-05 03:51:55 +02:00
|
|
|
|
2023-07-07 16:52:56 +02:00
|
|
|
// #define GLFW_INCLUDE_NONE
|
2023-07-10 16:29:25 +02:00
|
|
|
// #include "glfw3.h"
|
2023-07-07 16:52:56 +02:00
|
|
|
//
|
|
|
|
// void goErrorCB(int code, char* desc);
|
|
|
|
//
|
|
|
|
// static void glfwSetErrorCallbackCB() {
|
|
|
|
// glfwSetErrorCallback((GLFWerrorfun)goErrorCB);
|
|
|
|
// }
|
2023-07-05 03:51:55 +02:00
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ErrorCode corresponds to an error code.
|
|
|
|
type ErrorCode int
|
|
|
|
|
|
|
|
// Error codes that are translated to panics and the programmer should not
|
|
|
|
// expect to handle.
|
|
|
|
const (
|
|
|
|
notInitialized ErrorCode = C.GLFW_NOT_INITIALIZED // GLFW has not been initialized.
|
|
|
|
noCurrentContext ErrorCode = C.GLFW_NO_CURRENT_CONTEXT // No context is current.
|
|
|
|
invalidEnum ErrorCode = C.GLFW_INVALID_ENUM // One of the enum parameters for the function was given an invalid enum.
|
|
|
|
invalidValue ErrorCode = C.GLFW_INVALID_VALUE // One of the parameters for the function was given an invalid value.
|
|
|
|
outOfMemory ErrorCode = C.GLFW_OUT_OF_MEMORY // A memory allocation failed.
|
|
|
|
platformError ErrorCode = C.GLFW_PLATFORM_ERROR // A platform-specific error occurred that does not match any of the more specific categories.
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// APIUnavailable is the error code used when GLFW could not find support
|
|
|
|
// for the requested client API on the system.
|
|
|
|
//
|
|
|
|
// The installed graphics driver does not support the requested client API,
|
|
|
|
// or does not support it via the chosen context creation backend. Below
|
|
|
|
// are a few examples.
|
|
|
|
//
|
|
|
|
// Some pre-installed Windows graphics drivers do not support OpenGL. AMD
|
|
|
|
// only supports OpenGL ES via EGL, while Nvidia and Intel only supports it
|
|
|
|
// via a WGL or GLX extension. OS X does not provide OpenGL ES at all. The
|
|
|
|
// Mesa EGL, OpenGL and OpenGL ES libraries do not interface with the
|
|
|
|
// Nvidia binary driver.
|
|
|
|
APIUnavailable ErrorCode = C.GLFW_API_UNAVAILABLE
|
|
|
|
|
|
|
|
// VersionUnavailable is the error code used when the requested OpenGL or
|
|
|
|
// OpenGL ES (including any requested profile or context option) is not
|
|
|
|
// available on this machine.
|
|
|
|
//
|
|
|
|
// The machine does not support your requirements. If your application is
|
|
|
|
// sufficiently flexible, downgrade your requirements and try again.
|
|
|
|
// Otherwise, inform the user that their machine does not match your
|
|
|
|
// requirements.
|
|
|
|
//
|
|
|
|
// Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if
|
|
|
|
// 5.0 comes out before the 4.x series gets that far, also fail with this
|
|
|
|
// error and not GLFW_INVALID_VALUE, because GLFW cannot know what future
|
|
|
|
// versions will exist.
|
|
|
|
VersionUnavailable ErrorCode = C.GLFW_VERSION_UNAVAILABLE
|
|
|
|
|
|
|
|
// FormatUnavailable is the error code used for both window creation and
|
|
|
|
// clipboard querying format errors.
|
|
|
|
//
|
|
|
|
// If emitted during window creation, the requested pixel format is not
|
|
|
|
// supported. This means one or more hard constraints did not match any of
|
|
|
|
// the available pixel formats. If your application is sufficiently
|
|
|
|
// flexible, downgrade your requirements and try again. Otherwise, inform
|
|
|
|
// the user that their machine does not match your requirements.
|
|
|
|
//
|
|
|
|
// If emitted when querying the clipboard, the contents of the clipboard
|
|
|
|
// could not be converted to the requested format. You should ignore the
|
|
|
|
// error or report it to the user, as appropriate.
|
|
|
|
FormatUnavailable ErrorCode = C.GLFW_FORMAT_UNAVAILABLE
|
|
|
|
)
|
|
|
|
|
|
|
|
func (e ErrorCode) String() string {
|
|
|
|
switch e {
|
|
|
|
case notInitialized:
|
|
|
|
return "NotInitialized"
|
|
|
|
case noCurrentContext:
|
|
|
|
return "NoCurrentContext"
|
|
|
|
case invalidEnum:
|
|
|
|
return "InvalidEnum"
|
|
|
|
case invalidValue:
|
|
|
|
return "InvalidValue"
|
|
|
|
case outOfMemory:
|
|
|
|
return "OutOfMemory"
|
|
|
|
case platformError:
|
|
|
|
return "PlatformError"
|
|
|
|
case APIUnavailable:
|
|
|
|
return "APIUnavailable"
|
|
|
|
case VersionUnavailable:
|
|
|
|
return "VersionUnavailable"
|
|
|
|
case FormatUnavailable:
|
|
|
|
return "FormatUnavailable"
|
|
|
|
default:
|
|
|
|
return fmt.Sprintf("ErrorCode(%d)", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error holds error code and description.
|
|
|
|
type Error struct {
|
|
|
|
Code ErrorCode
|
|
|
|
Desc string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error prints the error code and description in a readable format.
|
|
|
|
func (e *Error) Error() string {
|
|
|
|
return fmt.Sprintf("%s: %s", e.Code.String(), e.Desc)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: There are many cryptic caveats to proper error handling here.
|
|
|
|
// See: https://github.com/go-gl/glfw3/pull/86
|
|
|
|
|
|
|
|
// Holds the value of the last error.
|
|
|
|
var lastError = make(chan *Error, 1)
|
|
|
|
|
|
|
|
//export goErrorCB
|
|
|
|
func goErrorCB(code C.int, desc *C.char) {
|
|
|
|
flushErrors()
|
|
|
|
err := &Error{ErrorCode(code), C.GoString(desc)}
|
|
|
|
select {
|
|
|
|
case lastError <- err:
|
|
|
|
default:
|
|
|
|
fmt.Println("GLFW: An uncaught error has occurred:", err)
|
|
|
|
fmt.Println("GLFW: Please report this bug in the Go package immediately.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the glfw callback internally
|
|
|
|
func init() {
|
|
|
|
C.glfwSetErrorCallbackCB()
|
|
|
|
}
|
|
|
|
|
|
|
|
// flushErrors is called by Terminate before it actually calls C.glfwTerminate,
|
|
|
|
// this ensures that any uncaught errors buffered in lastError are printed
|
|
|
|
// before the program exits.
|
|
|
|
func flushErrors() {
|
|
|
|
err := fetchError()
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("GLFW: An uncaught error has occurred:", err)
|
|
|
|
fmt.Println("GLFW: Please report this bug in the Go package immediately.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// acceptError fetches the next error from the error channel, it accepts only
|
|
|
|
// errors with one of the given error codes. If any other error is encountered,
|
|
|
|
// a panic will occur.
|
|
|
|
//
|
|
|
|
// Platform errors are always printed, for information why please see:
|
|
|
|
//
|
|
|
|
// https://github.com/go-gl/glfw/issues/127
|
|
|
|
func acceptError(codes ...ErrorCode) error {
|
|
|
|
// Grab the next error, if there is one.
|
|
|
|
err := fetchError()
|
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only if the error has the specific error code accepted by the caller, do
|
|
|
|
// we return the error.
|
|
|
|
for _, code := range codes {
|
|
|
|
if err.Code == code {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The error isn't accepted by the caller. If the error code is not a code
|
|
|
|
// defined in the GLFW C documentation as a programmer error, then the
|
|
|
|
// caller should have accepted it. This is effectively a bug in this
|
|
|
|
// package.
|
|
|
|
switch err.Code {
|
|
|
|
case platformError:
|
|
|
|
log.Println(err)
|
|
|
|
return nil
|
|
|
|
case notInitialized, noCurrentContext, invalidEnum, invalidValue, outOfMemory:
|
|
|
|
panic(err)
|
|
|
|
default:
|
|
|
|
fmt.Println("GLFW: An invalid error was not accepted by the caller:", err)
|
|
|
|
fmt.Println("GLFW: Please report this bug in the Go package immediately.")
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// panicError is a helper used by functions which expect no errors (except
|
|
|
|
// programmer errors) to occur. It will panic if it finds any such error.
|
|
|
|
func panicError() {
|
|
|
|
err := acceptError()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fetchError fetches the next error from the error channel, it does not block
|
|
|
|
// and returns nil if there is no error present.
|
|
|
|
func fetchError() *Error {
|
|
|
|
select {
|
|
|
|
case err := <-lastError:
|
|
|
|
return err
|
|
|
|
default:
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|