mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-17 16:50:31 +00:00
Replace SDL2 with lightweight RGFW-like GL/Window helper lib
This commit is contained in:
parent
728b2a49f0
commit
dfb78c458d
10 changed files with 850 additions and 744 deletions
18
Dockerfile
18
Dockerfile
|
|
@ -1,9 +1,12 @@
|
|||
ARG BUILD_PATH=/tmp/cloud-game
|
||||
ARG VERSION=master
|
||||
|
||||
ARG GO_VERSION=1.26.4
|
||||
ARG GSTREAMER_VERSION=1.29.2
|
||||
|
||||
# gstreamer minimal build
|
||||
FROM ubuntu:resolute AS gst-builder
|
||||
ARG GST_VERSION=1.28.4
|
||||
ARG GSTREAMER_VERSION
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
|
|
@ -16,7 +19,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
|||
|
||||
WORKDIR /gst
|
||||
|
||||
RUN git clone --single-branch --depth 1 --branch ${GST_VERSION} \
|
||||
RUN git clone --single-branch --depth 1 --branch ${GSTREAMER_VERSION} \
|
||||
https://gitlab.freedesktop.org/gstreamer/gstreamer.git .
|
||||
|
||||
# fix meson build error
|
||||
|
|
@ -29,6 +32,8 @@ RUN meson setup builddir \
|
|||
-Doptimization=3 \
|
||||
-Db_lto=true \
|
||||
-Dauto_features=disabled \
|
||||
-Dextra-checks=disabled \
|
||||
-Dbenchmarks=disabled \
|
||||
-Dtools=disabled \
|
||||
-Dgstreamer:tools=disabled \
|
||||
-Dbase=enabled \
|
||||
|
|
@ -62,8 +67,8 @@ RUN meson setup builddir \
|
|||
# base build stage
|
||||
FROM ubuntu:resolute AS build0
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ARG GO=1.26.4
|
||||
ARG GO_DIST=go${GO}.linux-amd64.tar.gz
|
||||
ARG GO_VERSION
|
||||
ARG GO_DIST=go${GO_VERSION}.linux-amd64.tar.gz
|
||||
|
||||
ADD https://go.dev/dl/$GO_DIST ./
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
|
|
@ -107,9 +112,10 @@ COPY --from=gst-builder /usr/local /usr/local
|
|||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
apt-get -q update && apt-get -q install --no-install-recommends -y \
|
||||
build-essential \
|
||||
libsdl2-dev \
|
||||
pkg-config \
|
||||
build-essential \
|
||||
libx11-dev \
|
||||
libgl1-mesa-dev \
|
||||
libglib2.0-dev && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
|
|
|||
7
go.mod
7
go.mod
|
|
@ -12,14 +12,13 @@ require (
|
|||
github.com/klauspost/cpuid/v2 v2.3.0
|
||||
github.com/knadh/koanf/maps v0.1.2
|
||||
github.com/knadh/koanf/v2 v2.3.5
|
||||
github.com/minio/minio-go/v7 v7.2.0
|
||||
github.com/minio/minio-go/v7 v7.2.1
|
||||
github.com/pion/ice/v4 v4.2.7
|
||||
github.com/pion/interceptor v0.1.45
|
||||
github.com/pion/logging v0.2.4
|
||||
github.com/pion/webrtc/v4 v4.2.15
|
||||
github.com/pion/webrtc/v4 v4.2.16
|
||||
github.com/rs/xid v1.6.0
|
||||
github.com/rs/zerolog v1.35.1
|
||||
github.com/veandco/go-sdl2 v0.4.40
|
||||
golang.org/x/crypto v0.53.0
|
||||
golang.org/x/image v0.38.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
|
|
@ -47,7 +46,7 @@ require (
|
|||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.16 // indirect
|
||||
github.com/pion/rtp v1.10.2 // indirect
|
||||
github.com/pion/sctp v1.10.1 // indirect
|
||||
github.com/pion/sctp v1.10.3 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.19 // indirect
|
||||
github.com/pion/srtp/v3 v3.0.12 // indirect
|
||||
github.com/pion/stun/v3 v3.1.6 // indirect
|
||||
|
|
|
|||
14
go.sum
14
go.sum
|
|
@ -48,8 +48,8 @@ github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI
|
|||
github.com/minio/crc64nvme v1.1.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.2.0 h1:RCJM0R1XOsRs+A3x3UCaf3ZYbByDaLjFeAi+YCQEPhs=
|
||||
github.com/minio/minio-go/v7 v7.2.0/go.mod h1:EU9hENAStx/xXduNdrGO5e4X5vk19NtgB+RIPjZO8o0=
|
||||
github.com/minio/minio-go/v7 v7.2.1 h1:PfBfwvKB/MmqyN8Vb1G9voWisaM9OrLv+WwOvMwS9Dw=
|
||||
github.com/minio/minio-go/v7 v7.2.1/go.mod h1:EU9hENAStx/xXduNdrGO5e4X5vk19NtgB+RIPjZO8o0=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
|
|
@ -74,8 +74,8 @@ github.com/pion/rtcp v1.2.16 h1:fk1B1dNW4hsI78XUCljZJlC4kZOPk67mNRuQ0fcEkSo=
|
|||
github.com/pion/rtcp v1.2.16/go.mod h1:/as7VKfYbs5NIb4h6muQ35kQF/J0ZVNz2Z3xKoCBYOo=
|
||||
github.com/pion/rtp v1.10.2 h1:l+f6tTDcAH6xwepaAoW791ddhuYsJlqRATOzirO04Mo=
|
||||
github.com/pion/rtp v1.10.2/go.mod h1:Au8fc6cEByy8RLTwKTQTEeQqDB/SJDxwL4mZuxYA5Pk=
|
||||
github.com/pion/sctp v1.10.1 h1:IDwqRiteu1gqPnqYysDLxVTwIOMFR0zvwOS6cjhzX7k=
|
||||
github.com/pion/sctp v1.10.1/go.mod h1:N20Dq6LY+JvJDAh9VVh1JELngb2rQ8dPgds5yBWiPgw=
|
||||
github.com/pion/sctp v1.10.3 h1:1gBtLMA9lmwNuJkZSZJCdD5/Hz4yJs+7dAqi6ZY97QI=
|
||||
github.com/pion/sctp v1.10.3/go.mod h1:7KFmTwLcoYgJs/Z+99nJvsWL0qDpuyloSI0RbAqlrz0=
|
||||
github.com/pion/sdp/v3 v3.0.19 h1:1VMKs3gIkTQV5M3hNKfTAPrDXSNrYtOlmOD8+mSZUGQ=
|
||||
github.com/pion/sdp/v3 v3.0.19/go.mod h1:dE5WOSlzXrtiE/iuZqe9n+AcEbOjtAd3k5m5NtlV/qU=
|
||||
github.com/pion/srtp/v3 v3.0.12 h1:U7V17bckl7sI4mb3sepiojByDuBY0wNCqQE+6IlQBbc=
|
||||
|
|
@ -88,8 +88,8 @@ github.com/pion/transport/v4 v4.0.2 h1:ifYlPqNwsy6aKQ9y8yzxXlHae5431ZrH2avkD/Rn6
|
|||
github.com/pion/transport/v4 v4.0.2/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBPfviSVcjgM=
|
||||
github.com/pion/turn/v5 v5.0.10 h1:mOMZjudflXpte5OsCnXztpUKwNXcpXIAzMBnq9TXOSQ=
|
||||
github.com/pion/turn/v5 v5.0.10/go.mod h1:u3XjBqy2Z4+NhCUpDoOSsNuQDrPLvKStlCGWk6sTQ1E=
|
||||
github.com/pion/webrtc/v4 v4.2.15 h1:Ir/MauNFCfg+kgyBYPQLiGdVWFlzEcLxqtuzAkYkky0=
|
||||
github.com/pion/webrtc/v4 v4.2.15/go.mod h1:CPTcyLfIzC4scOkQ4UY4pj6WvbUGhcNLIpK28cP5h6M=
|
||||
github.com/pion/webrtc/v4 v4.2.16 h1:oK1GAg0TWJtZWYB8J/BgTgGWPoV2148gQWocH12vr3Q=
|
||||
github.com/pion/webrtc/v4 v4.2.16/go.mod h1:y4HjLAkX90LH+C/qPqGOUgz8RA8CbDj3Iar3d+2hdKQ=
|
||||
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/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
|
|
@ -113,8 +113,6 @@ github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G
|
|||
github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ=
|
||||
github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ=
|
||||
github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY=
|
||||
github.com/veandco/go-sdl2 v0.4.40 h1:fZv6wC3zz1Xt167P09gazawnpa0KY5LM7JAvKpX9d/U=
|
||||
github.com/veandco/go-sdl2 v0.4.40/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||
github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
|
||||
github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
|
|
|
|||
|
|
@ -522,7 +522,7 @@ func (f *Frontend) Load() error {
|
|||
}
|
||||
|
||||
func (f *Frontend) IsSupported() error {
|
||||
return graphics.TryInit()
|
||||
return graphics.RGFWTryInit()
|
||||
}
|
||||
|
||||
func (f *Frontend) autosave(periodSec int) {
|
||||
|
|
|
|||
|
|
@ -1,311 +0,0 @@
|
|||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
|
||||
# define KHRONOS_STATIC 1
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(KHRONOS_STATIC)
|
||||
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
|
||||
* header compatible with static linking. */
|
||||
# define KHRONOS_APICALL
|
||||
#elif defined(_WIN32)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
/*
|
||||
* To support platform where unsigned long cannot be used interchangeably with
|
||||
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
|
||||
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
|
||||
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
|
||||
* unsigned long long or similar (this results in different C++ name mangling).
|
||||
* To avoid changes for existing platforms, we restrict usage of intptr_t to
|
||||
* platforms where the size of a pointer is larger than the size of long.
|
||||
*/
|
||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
|
||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
|
||||
#define KHRONOS_USE_INTPTR_T
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef KHRONOS_USE_INTPTR_T
|
||||
typedef intptr_t khronos_intptr_t;
|
||||
typedef uintptr_t khronos_uintptr_t;
|
||||
#elif defined(_WIN64)
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
||||
|
|
@ -1,274 +0,0 @@
|
|||
package gl
|
||||
|
||||
// Custom OpenGL bindings
|
||||
// Based on https://github.com/go-gl/gl/tree/master/v2.1/gl
|
||||
|
||||
/*
|
||||
#cgo egl,windows LDFLAGS: -lEGL
|
||||
#cgo egl,darwin LDFLAGS: -lEGL
|
||||
#cgo !gles2,darwin LDFLAGS: -framework OpenGL
|
||||
#cgo gles2,darwin LDFLAGS: -lGLESv2
|
||||
#cgo !gles2,windows LDFLAGS: -lopengl32
|
||||
#cgo gles2,windows LDFLAGS: -lGLESv2
|
||||
#cgo !egl,linux !egl,freebsd !egl,openbsd pkg-config: gl
|
||||
#cgo egl,linux egl,freebsd egl,openbsd pkg-config: egl
|
||||
|
||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#endif
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY*
|
||||
#endif
|
||||
#ifndef GLAPI
|
||||
#define GLAPI extern
|
||||
#endif
|
||||
|
||||
#include <KHR/khrplatform.h>
|
||||
|
||||
typedef unsigned int GLenum;
|
||||
typedef unsigned char GLboolean;
|
||||
typedef unsigned int GLbitfield;
|
||||
typedef khronos_int8_t GLbyte;
|
||||
typedef khronos_uint8_t GLubyte;
|
||||
typedef khronos_int16_t GLshort;
|
||||
typedef khronos_uint16_t GLushort;
|
||||
typedef int GLint;
|
||||
typedef unsigned int GLuint;
|
||||
typedef khronos_int32_t GLclampx;
|
||||
typedef int GLsizei;
|
||||
typedef khronos_float_t GLfloat;
|
||||
typedef khronos_float_t GLclampf;
|
||||
typedef double GLdouble;
|
||||
typedef double GLclampd;
|
||||
typedef void *GLeglClientBufferEXT;
|
||||
typedef void *GLeglImageOES;
|
||||
typedef char GLchar;
|
||||
typedef char GLcharARB;
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
typedef void *GLhandleARB;
|
||||
#else
|
||||
typedef unsigned int GLhandleARB;
|
||||
#endif
|
||||
|
||||
typedef const GLubyte *(APIENTRYP GPGETSTRING)(GLenum name);
|
||||
typedef GLenum (APIENTRYP GPCHECKFRAMEBUFFERSTATUS)(GLenum target);
|
||||
typedef GLenum (APIENTRYP GPGETERROR)();
|
||||
typedef void (APIENTRYP GPBINDFRAMEBUFFER)(GLenum target, GLuint framebuffer);
|
||||
typedef void (APIENTRYP GPBINDRENDERBUFFER)(GLenum target, GLuint renderbuffer);
|
||||
typedef void (APIENTRYP GPBINDTEXTURE)(GLenum target, GLuint texture);
|
||||
typedef void (APIENTRYP GPDELETEFRAMEBUFFERS)(GLsizei n, const GLuint *framebuffers);
|
||||
typedef void (APIENTRYP GPDELETERENDERBUFFERS)(GLsizei n, const GLuint *renderbuffers);
|
||||
typedef void (APIENTRYP GPDELETETEXTURES)(GLsizei n, const GLuint* textures);
|
||||
typedef void (APIENTRYP GPFRAMEBUFFERRENDERBUFFER)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
typedef void (APIENTRYP GPFRAMEBUFFERTEXTURE2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
typedef void (APIENTRYP GPGENFRAMEBUFFERS)(GLsizei n, GLuint *framebuffers);
|
||||
typedef void (APIENTRYP GPGENRENDERBUFFERS)(GLsizei n, GLuint *renderbuffers);
|
||||
typedef void (APIENTRYP GPGENTEXTURES)(GLsizei n, GLuint *textures);
|
||||
typedef void (APIENTRYP GPREADPIXELS)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
|
||||
typedef void (APIENTRYP GPRENDERBUFFERSTORAGE)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
|
||||
typedef void (APIENTRYP GPTEXIMAGE2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels);
|
||||
typedef void (APIENTRYP GPTEXPARAMETERI)(GLenum target, GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP GPPIXELSTOREI)(GLenum pname, GLint param);
|
||||
|
||||
static const GLubyte *getString(GPGETSTRING ptr, GLenum name) { return (*ptr)(name); }
|
||||
static GLenum getError(GPGETERROR ptr) { return (*ptr)(); }
|
||||
static void bindTexture(GPBINDTEXTURE ptr, GLenum target, GLuint texture) { (*ptr)(target, texture); }
|
||||
static void bindFramebuffer(GPBINDFRAMEBUFFER ptr, GLenum target, GLuint framebuffer) { (*ptr)(target, framebuffer); }
|
||||
static void bindRenderbuffer(GPBINDRENDERBUFFER ptr, GLenum target, GLuint buf) { (*ptr)(target, buf); }
|
||||
static void texParameteri(GPTEXPARAMETERI ptr, GLenum target, GLenum pname, GLint param) {
|
||||
(*ptr)(target, pname, param);
|
||||
}
|
||||
static void texImage2D(GPTEXIMAGE2D ptr, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) {
|
||||
(*ptr)(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
}
|
||||
static void genFramebuffers(GPGENFRAMEBUFFERS ptr, GLsizei n, GLuint *framebuffers) { (*ptr)(n, framebuffers); }
|
||||
static void genTextures(GPGENTEXTURES ptr, GLsizei n, GLuint *textures) { (*ptr)(n, textures); }
|
||||
static void framebufferTexture2D(GPFRAMEBUFFERTEXTURE2D ptr, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
|
||||
(*ptr)(target, attachment, textarget, texture, level);
|
||||
}
|
||||
static void genRenderbuffers(GPGENRENDERBUFFERS ptr, GLsizei n, GLuint *renderbuffers) { (*ptr)(n, renderbuffers); }
|
||||
static void renderbufferStorage(GPRENDERBUFFERSTORAGE ptr, GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
|
||||
(*ptr)(target, internalformat, width, height);
|
||||
}
|
||||
static void framebufferRenderbuffer(GPFRAMEBUFFERRENDERBUFFER ptr, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
|
||||
(*ptr)(target, attachment, renderbuffertarget, renderbuffer);
|
||||
}
|
||||
static GLenum checkFramebufferStatus(GPCHECKFRAMEBUFFERSTATUS ptr, GLenum target) { return (*ptr)(target); }
|
||||
static void deleteRenderbuffers(GPDELETERENDERBUFFERS ptr, GLsizei n, const GLuint *renderbuffers) {
|
||||
(*ptr)(n, renderbuffers);
|
||||
}
|
||||
static void deleteFramebuffers(GPDELETEFRAMEBUFFERS ptr, GLsizei n, const GLuint *framebuffers) {
|
||||
(*ptr)(n, framebuffers);
|
||||
}
|
||||
static void deleteTextures(GPDELETETEXTURES ptr, GLsizei n, const GLuint *textures) { (*ptr)(n, textures); }
|
||||
static void readPixels(GPREADPIXELS ptr, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) {
|
||||
(*ptr)(x, y, width, height, format, type, pixels);
|
||||
}
|
||||
static void pixelStorei(GPPIXELSTOREI ptr, GLenum pname, GLint param) { (*ptr)(pname, param); }
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
VENDOR = 0x1F00
|
||||
VERSION = 0x1F02
|
||||
RENDERER = 0x1F01
|
||||
ShadingLanguageVersion = 0x8B8C
|
||||
Texture2d = 0x0DE1
|
||||
RENDERBUFFER = 0x8D41
|
||||
FRAMEBUFFER = 0x8D40
|
||||
TextureMinFilter = 0x2801
|
||||
TextureMagFilter = 0x2800
|
||||
NEAREST = 0x2600
|
||||
RGBA8 = 0x8058
|
||||
BGRA = 0x80E1
|
||||
RGB = 0x1907
|
||||
ColorAttachment0 = 0x8CE0
|
||||
Depth24Stencil8 = 0x88F0
|
||||
DepthStencilAttachment = 0x821A
|
||||
DepthComponent24 = 0x81A6
|
||||
DepthAttachment = 0x8D00
|
||||
FramebufferComplete = 0x8CD5
|
||||
|
||||
UnsignedShort5551 = 0x8034
|
||||
UnsignedShort565 = 0x8363
|
||||
UnsignedInt8888Rev = 0x8367
|
||||
|
||||
PackAlignment = 0x0D05
|
||||
)
|
||||
|
||||
var (
|
||||
gpGetString C.GPGETSTRING
|
||||
gpGenTextures C.GPGENTEXTURES
|
||||
gpGetError C.GPGETERROR
|
||||
gpBindTexture C.GPBINDTEXTURE
|
||||
gpBindFramebuffer C.GPBINDFRAMEBUFFER
|
||||
gpTexParameteri C.GPTEXPARAMETERI
|
||||
gpTexImage2D C.GPTEXIMAGE2D
|
||||
gpGenFramebuffers C.GPGENFRAMEBUFFERS
|
||||
gpFramebufferTexture2D C.GPFRAMEBUFFERTEXTURE2D
|
||||
gpGenRenderbuffers C.GPGENRENDERBUFFERS
|
||||
gpBindRenderbuffer C.GPBINDRENDERBUFFER
|
||||
gpRenderbufferStorage C.GPRENDERBUFFERSTORAGE
|
||||
gpFramebufferRenderbuffer C.GPFRAMEBUFFERRENDERBUFFER
|
||||
gpCheckFramebufferStatus C.GPCHECKFRAMEBUFFERSTATUS
|
||||
gpDeleteRenderbuffers C.GPDELETERENDERBUFFERS
|
||||
gpDeleteFramebuffers C.GPDELETEFRAMEBUFFERS
|
||||
gpDeleteTextures C.GPDELETETEXTURES
|
||||
gpReadPixels C.GPREADPIXELS
|
||||
gpPixelStorei C.GPPIXELSTOREI
|
||||
)
|
||||
|
||||
func InitWithProcAddrFunc(getProcAddr func(name string) unsafe.Pointer) error {
|
||||
if gpGetString = (C.GPGETSTRING)(getProcAddr("glGetString")); gpGetString == nil {
|
||||
return errors.New("glGetString")
|
||||
}
|
||||
if gpGenTextures = (C.GPGENTEXTURES)(getProcAddr("glGenTextures")); gpGenTextures == nil {
|
||||
return errors.New("glGenTextures")
|
||||
}
|
||||
if gpGetError = (C.GPGETERROR)(getProcAddr("glGetError")); gpGetError == nil {
|
||||
return errors.New("glGetError")
|
||||
}
|
||||
if gpBindTexture = (C.GPBINDTEXTURE)(getProcAddr("glBindTexture")); gpBindTexture == nil {
|
||||
return errors.New("glBindTexture")
|
||||
}
|
||||
if gpBindFramebuffer = (C.GPBINDFRAMEBUFFER)(getProcAddr("glBindFramebuffer")); gpBindFramebuffer == nil {
|
||||
return errors.New("glBindFramebuffer")
|
||||
}
|
||||
if gpTexParameteri = (C.GPTEXPARAMETERI)(getProcAddr("glTexParameteri")); gpTexParameteri == nil {
|
||||
return errors.New("glTexParameteri")
|
||||
}
|
||||
if gpTexImage2D = (C.GPTEXIMAGE2D)(getProcAddr("glTexImage2D")); gpTexImage2D == nil {
|
||||
return errors.New("glTexImage2D")
|
||||
}
|
||||
gpGenFramebuffers = (C.GPGENFRAMEBUFFERS)(getProcAddr("glGenFramebuffers"))
|
||||
gpFramebufferTexture2D = (C.GPFRAMEBUFFERTEXTURE2D)(getProcAddr("glFramebufferTexture2D"))
|
||||
gpGenRenderbuffers = (C.GPGENRENDERBUFFERS)(getProcAddr("glGenRenderbuffers"))
|
||||
gpBindRenderbuffer = (C.GPBINDRENDERBUFFER)(getProcAddr("glBindRenderbuffer"))
|
||||
gpRenderbufferStorage = (C.GPRENDERBUFFERSTORAGE)(getProcAddr("glRenderbufferStorage"))
|
||||
gpFramebufferRenderbuffer = (C.GPFRAMEBUFFERRENDERBUFFER)(getProcAddr("glFramebufferRenderbuffer"))
|
||||
gpCheckFramebufferStatus = (C.GPCHECKFRAMEBUFFERSTATUS)(getProcAddr("glCheckFramebufferStatus"))
|
||||
gpDeleteRenderbuffers = (C.GPDELETERENDERBUFFERS)(getProcAddr("glDeleteRenderbuffers"))
|
||||
gpDeleteFramebuffers = (C.GPDELETEFRAMEBUFFERS)(getProcAddr("glDeleteFramebuffers"))
|
||||
if gpDeleteTextures = (C.GPDELETETEXTURES)(getProcAddr("glDeleteTextures")); gpDeleteTextures == nil {
|
||||
return errors.New("glDeleteTextures")
|
||||
}
|
||||
gpReadPixels = (C.GPREADPIXELS)(getProcAddr("glReadPixels"))
|
||||
if gpReadPixels == nil {
|
||||
return errors.New("glReadPixels")
|
||||
}
|
||||
if gpPixelStorei = (C.GPPIXELSTOREI)(getProcAddr("glPixelStorei")); gpPixelStorei == nil {
|
||||
return errors.New("glPixelStorei")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetString(name uint32) *uint8 { return (*uint8)(C.getString(gpGetString, (C.GLenum)(name))) }
|
||||
func GenTextures(n int32, textures *uint32) {
|
||||
C.genTextures(gpGenTextures, (C.GLsizei)(n), (*C.GLuint)(unsafe.Pointer(textures)))
|
||||
}
|
||||
func BindTexture(target uint32, texture uint32) {
|
||||
C.bindTexture(gpBindTexture, (C.GLenum)(target), (C.GLuint)(texture))
|
||||
}
|
||||
func BindFramebuffer(target uint32, framebuffer uint32) {
|
||||
C.bindFramebuffer(gpBindFramebuffer, (C.GLenum)(target), (C.GLuint)(framebuffer))
|
||||
}
|
||||
func TexParameteri(target uint32, name uint32, param int32) {
|
||||
C.texParameteri(gpTexParameteri, (C.GLenum)(target), (C.GLenum)(name), (C.GLint)(param))
|
||||
}
|
||||
func TexImage2D(target uint32, level int32, internalformat int32, width int32, height int32, border int32, format uint32, xtype uint32, pixels unsafe.Pointer) {
|
||||
C.texImage2D(gpTexImage2D, (C.GLenum)(target), (C.GLint)(level), (C.GLint)(internalformat), (C.GLsizei)(width), (C.GLsizei)(height), (C.GLint)(border), (C.GLenum)(format), (C.GLenum)(xtype), pixels)
|
||||
}
|
||||
func GenFramebuffers(n int32, framebuffers *uint32) {
|
||||
C.genFramebuffers(gpGenFramebuffers, (C.GLsizei)(n), (*C.GLuint)(unsafe.Pointer(framebuffers)))
|
||||
}
|
||||
func FramebufferTexture2D(target uint32, attachment uint32, texTarget uint32, texture uint32, level int32) {
|
||||
C.framebufferTexture2D(gpFramebufferTexture2D, (C.GLenum)(target), (C.GLenum)(attachment), (C.GLenum)(texTarget), (C.GLuint)(texture), (C.GLint)(level))
|
||||
}
|
||||
func GenRenderbuffers(n int32, renderbuffers *uint32) {
|
||||
C.genRenderbuffers(gpGenRenderbuffers, (C.GLsizei)(n), (*C.GLuint)(unsafe.Pointer(renderbuffers)))
|
||||
}
|
||||
func BindRenderbuffer(target uint32, renderbuffer uint32) {
|
||||
C.bindRenderbuffer(gpBindRenderbuffer, (C.GLenum)(target), (C.GLuint)(renderbuffer))
|
||||
}
|
||||
func RenderbufferStorage(target uint32, internalformat uint32, width int32, height int32) {
|
||||
C.renderbufferStorage(gpRenderbufferStorage, (C.GLenum)(target), (C.GLenum)(internalformat), (C.GLsizei)(width), (C.GLsizei)(height))
|
||||
}
|
||||
func FramebufferRenderbuffer(target uint32, attachment uint32, renderbufferTarget uint32, renderbuffer uint32) {
|
||||
C.framebufferRenderbuffer(gpFramebufferRenderbuffer, (C.GLenum)(target), (C.GLenum)(attachment), (C.GLenum)(renderbufferTarget), (C.GLuint)(renderbuffer))
|
||||
}
|
||||
func CheckFramebufferStatus(target uint32) uint32 {
|
||||
return (uint32)(C.checkFramebufferStatus(gpCheckFramebufferStatus, (C.GLenum)(target)))
|
||||
}
|
||||
func DeleteRenderbuffers(n int32, renderbuffers *uint32) {
|
||||
C.deleteRenderbuffers(gpDeleteRenderbuffers, (C.GLsizei)(n), (*C.GLuint)(unsafe.Pointer(renderbuffers)))
|
||||
}
|
||||
func DeleteFramebuffers(n int32, framebuffers *uint32) {
|
||||
C.deleteFramebuffers(gpDeleteFramebuffers, (C.GLsizei)(n), (*C.GLuint)(unsafe.Pointer(framebuffers)))
|
||||
}
|
||||
func DeleteTextures(n int32, textures *uint32) {
|
||||
C.deleteTextures(gpDeleteTextures, (C.GLsizei)(n), (*C.GLuint)(unsafe.Pointer(textures)))
|
||||
}
|
||||
func ReadPixels(x int32, y int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer) {
|
||||
C.readPixels(gpReadPixels, (C.GLint)(x), (C.GLint)(y), (C.GLsizei)(width), (C.GLsizei)(height), (C.GLenum)(format), (C.GLenum)(xtype), pixels)
|
||||
}
|
||||
func PixelStorei(pname uint32, param int32) {
|
||||
C.pixelStorei(gpPixelStorei, (C.GLenum)(pname), (C.GLint)(param))
|
||||
}
|
||||
|
||||
func GetError() uint32 { return (uint32)(C.getError(gpGetError)) }
|
||||
|
||||
func GoStr(str *uint8) string { return C.GoString((*C.char)(unsafe.Pointer(str))) }
|
||||
|
|
@ -1,14 +1,147 @@
|
|||
package graphics
|
||||
|
||||
/*
|
||||
#cgo windows LDFLAGS: -lopengl32
|
||||
#cgo linux LDFLAGS: -lGL
|
||||
#cgo darwin LDFLAGS: -framework OpenGL
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef APIENTRY
|
||||
#define APIENTRY
|
||||
#endif
|
||||
#ifndef APIENTRYP
|
||||
#define APIENTRYP APIENTRY*
|
||||
#endif
|
||||
|
||||
typedef unsigned int GLenum;
|
||||
typedef int GLint;
|
||||
typedef unsigned int GLuint;
|
||||
typedef int GLsizei;
|
||||
typedef unsigned char GLubyte;
|
||||
|
||||
typedef const GLubyte *(APIENTRYP GPGETSTRING)(GLenum name);
|
||||
typedef GLenum (APIENTRYP GPCHECKFRAMEBUFFERSTATUS)(GLenum target);
|
||||
typedef GLenum (APIENTRYP GPGETERROR)();
|
||||
typedef void (APIENTRYP GPBINDFRAMEBUFFER)(GLenum target, GLuint framebuffer);
|
||||
typedef void (APIENTRYP GPBINDRENDERBUFFER)(GLenum target, GLuint renderbuffer);
|
||||
typedef void (APIENTRYP GPBINDTEXTURE)(GLenum target, GLuint texture);
|
||||
typedef void (APIENTRYP GPDELETEFRAMEBUFFERS)(GLsizei n, const GLuint *framebuffers);
|
||||
typedef void (APIENTRYP GPDELETERENDERBUFFERS)(GLsizei n, const GLuint *renderbuffers);
|
||||
typedef void (APIENTRYP GPDELETETEXTURES)(GLsizei n, const GLuint* textures);
|
||||
typedef void (APIENTRYP GPFRAMEBUFFERRENDERBUFFER)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
|
||||
typedef void (APIENTRYP GPFRAMEBUFFERTEXTURE2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
|
||||
typedef void (APIENTRYP GPGENFRAMEBUFFERS)(GLsizei n, GLuint *fb);
|
||||
typedef void (APIENTRYP GPGENRENDERBUFFERS)(GLsizei n, GLuint *rb);
|
||||
typedef void (APIENTRYP GPGENTEXTURES)(GLsizei n, GLuint *tex);
|
||||
typedef void (APIENTRYP GPREADPIXELS)(GLint x, GLint y, GLsizei w, GLsizei h, GLenum f, GLenum t, void *p);
|
||||
typedef void (APIENTRYP GPRENDERBUFFERSTORAGE)(GLenum t, GLenum i, GLsizei w, GLsizei h);
|
||||
typedef void (APIENTRYP GPTEXIMAGE2D)(GLenum t, GLint l, GLint i, GLsizei w, GLsizei h, GLint b, GLenum f, GLenum x, const void *px);
|
||||
typedef void (APIENTRYP GPTEXPARAMETERI)(GLenum t, GLenum n, GLint p);
|
||||
typedef void (APIENTRYP GPPIXELSTOREI)(GLenum n, GLint p);
|
||||
|
||||
// Generic C wrappers — one per signature pattern, called from Go via function pointers.
|
||||
static const GLubyte *gl_get_string(GPGETSTRING f, GLenum a) { return f(a); }
|
||||
static GLenum gl_get_error(GPGETERROR f) { return f(); }
|
||||
static GLenum gl_check_fb_status(GPCHECKFRAMEBUFFERSTATUS f, GLenum a) { return f(a); }
|
||||
static void gl_1u32(GPGENTEXTURES f, GLsizei a, GLuint *b) { f(a, b); }
|
||||
static void gl_bind_tex(GPBINDTEXTURE f, GLenum a, GLuint b) { f(a, b); }
|
||||
static void gl_bind_fb(GPBINDFRAMEBUFFER f, GLenum a, GLuint b) { f(a, b); }
|
||||
static void gl_bind_rb(GPBINDRENDERBUFFER f, GLenum a, GLuint b) { f(a, b); }
|
||||
static void gl_tex_param(GPTEXPARAMETERI f, GLenum a, GLenum b, GLint c) { f(a, b, c); }
|
||||
static void gl_tex_image(GPTEXIMAGE2D f, GLenum a, GLint b, GLint c, GLsizei d, GLsizei e, GLint g, GLenum h, GLenum i, const void *j) { f(a, b, c, d, e, g, h, i, j); }
|
||||
static void gl_fb_tex2d(GPFRAMEBUFFERTEXTURE2D f, GLenum a, GLenum b, GLenum c, GLuint d, GLint e) { f(a, b, c, d, e); }
|
||||
static void gl_fb_rb(GPFRAMEBUFFERRENDERBUFFER f, GLenum a, GLenum b, GLenum c, GLuint d) { f(a, b, c, d); }
|
||||
static void gl_rb_storage(GPRENDERBUFFERSTORAGE f, GLenum a, GLenum b, GLsizei c, GLsizei d) { f(a, b, c, d); }
|
||||
static void gl_delete_fb(GPDELETEFRAMEBUFFERS f, GLsizei a, const GLuint *b) { f(a, b); }
|
||||
static void gl_delete_rb(GPDELETERENDERBUFFERS f, GLsizei a, const GLuint *b) { f(a, b); }
|
||||
static void gl_delete_tex(GPDELETETEXTURES f, GLsizei a, const GLuint *b) { f(a, b); }
|
||||
static void gl_read_pixels(GPREADPIXELS f, GLint a, GLint b, GLsizei c, GLsizei d, GLenum e, GLenum g, void *h) { f(a, b, c, d, e, g, h); }
|
||||
static void gl_pixel_storei(GPPIXELSTOREI f, GLenum a, GLint b) { f(a, b); }
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"unsafe"
|
||||
|
||||
"github.com/giongto35/cloud-game/v3/pkg/worker/caged/libretro/graphics/gl"
|
||||
)
|
||||
|
||||
const (
|
||||
gl_VENDOR = 0x1F00
|
||||
gl_VERSION = 0x1F02
|
||||
gl_RENDERER = 0x1F01
|
||||
gl_SHADING_LANG_VERSION = 0x8B8C
|
||||
gl_TEXTURE_2D = 0x0DE1
|
||||
gl_RENDERBUFFER = 0x8D41
|
||||
gl_FRAMEBUFFER = 0x8D40
|
||||
gl_TEXTURE_MIN_FILTER = 0x2801
|
||||
gl_TEXTURE_MAG_FILTER = 0x2800
|
||||
gl_NEAREST = 0x2600
|
||||
gl_RGBA = 0x1908
|
||||
gl_RGB = 0x1907
|
||||
gl_BGRA = 0x80E1
|
||||
gl_RGBA8 = 0x8058
|
||||
gl_COLOR_ATTACHMENT0 = 0x8CE0
|
||||
gl_DEPTH_ATTACHMENT = 0x8D00
|
||||
gl_DEPTH_STENCIL_ATTACH = 0x821A
|
||||
gl_DEPTH_COMPONENT24 = 0x81A6
|
||||
gl_DEPTH24_STENCIL8 = 0x88F0
|
||||
gl_FRAMEBUFFER_COMPLETE = 0x8CD5
|
||||
gl_PACK_ALIGNMENT = 0x0D05
|
||||
)
|
||||
|
||||
// ---- GL function pointers ----
|
||||
|
||||
var (
|
||||
gpGetString,
|
||||
gpGetError,
|
||||
gpBindTexture,
|
||||
gpBindFramebuffer,
|
||||
gpBindRenderbuffer,
|
||||
gpTexParameteri,
|
||||
gpTexImage2D,
|
||||
gpGenTextures,
|
||||
gpGenFramebuffers,
|
||||
gpGenRenderbuffers,
|
||||
gpFramebufferTexture2D,
|
||||
gpFramebufferRenderbuffer,
|
||||
gpRenderbufferStorage,
|
||||
gpCheckFramebufferStatus,
|
||||
gpDeleteFramebuffers,
|
||||
gpDeleteRenderbuffers,
|
||||
gpDeleteTextures,
|
||||
gpReadPixels,
|
||||
gpPixelStorei unsafe.Pointer
|
||||
)
|
||||
|
||||
type glFunc struct {
|
||||
ptr *unsafe.Pointer
|
||||
name string
|
||||
}
|
||||
|
||||
var glFuncs = [...]glFunc{
|
||||
{&gpGetString, "glGetString"},
|
||||
{&gpGetError, "glGetError"},
|
||||
{&gpBindTexture, "glBindTexture"},
|
||||
{&gpBindFramebuffer, "glBindFramebuffer"},
|
||||
{&gpBindRenderbuffer, "glBindRenderbuffer"},
|
||||
{&gpTexParameteri, "glTexParameteri"},
|
||||
{&gpTexImage2D, "glTexImage2D"},
|
||||
{&gpGenTextures, "glGenTextures"},
|
||||
{&gpGenFramebuffers, "glGenFramebuffers"},
|
||||
{&gpGenRenderbuffers, "glGenRenderbuffers"},
|
||||
{&gpFramebufferTexture2D, "glFramebufferTexture2D"},
|
||||
{&gpFramebufferRenderbuffer, "glFramebufferRenderbuffer"},
|
||||
{&gpRenderbufferStorage, "glRenderbufferStorage"},
|
||||
{&gpCheckFramebufferStatus, "glCheckFramebufferStatus"},
|
||||
{&gpDeleteFramebuffers, "glDeleteFramebuffers"},
|
||||
{&gpDeleteRenderbuffers, "glDeleteRenderbuffers"},
|
||||
{&gpDeleteTextures, "glDeleteTextures"},
|
||||
{&gpReadPixels, "glReadPixels"},
|
||||
{&gpPixelStorei, "glPixelStorei"},
|
||||
}
|
||||
|
||||
type Context int
|
||||
|
||||
const (
|
||||
|
|
@ -31,6 +164,84 @@ const (
|
|||
UnsignedInt8888Rev
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Ctx Context
|
||||
W, H int
|
||||
GLAutoContext bool
|
||||
GLVersionMajor uint
|
||||
GLVersionMinor uint
|
||||
GLHasDepth bool
|
||||
GLHasStencil bool
|
||||
}
|
||||
|
||||
func initProcAddr(getProcAddr func(name string) unsafe.Pointer) error {
|
||||
for _, f := range glFuncs {
|
||||
p := getProcAddr(f.name)
|
||||
if p == nil {
|
||||
return errors.New(f.name)
|
||||
}
|
||||
*f.ptr = p
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func goStr(s *uint8) string { return C.GoString((*C.char)(unsafe.Pointer(s))) }
|
||||
|
||||
func getString(name uint32) *uint8 {
|
||||
return (*uint8)(C.gl_get_string((C.GPGETSTRING)(gpGetString), C.GLenum(name)))
|
||||
}
|
||||
func genTextures(n int32, textures *uint32) {
|
||||
C.gl_1u32((C.GPGENTEXTURES)(gpGenTextures), C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(textures)))
|
||||
}
|
||||
func bindTexture(target, texture uint32) {
|
||||
C.gl_bind_tex((C.GPBINDTEXTURE)(gpBindTexture), C.GLenum(target), C.GLuint(texture))
|
||||
}
|
||||
func bindFramebuffer(target, framebuffer uint32) {
|
||||
C.gl_bind_fb((C.GPBINDFRAMEBUFFER)(gpBindFramebuffer), C.GLenum(target), C.GLuint(framebuffer))
|
||||
}
|
||||
func bindRenderbuffer(target, renderbuffer uint32) {
|
||||
C.gl_bind_rb((C.GPBINDRENDERBUFFER)(gpBindRenderbuffer), C.GLenum(target), C.GLuint(renderbuffer))
|
||||
}
|
||||
func texParameteri(target, pname uint32, param int32) {
|
||||
C.gl_tex_param((C.GPTEXPARAMETERI)(gpTexParameteri), C.GLenum(target), C.GLenum(pname), C.GLint(param))
|
||||
}
|
||||
func texImage2D(target uint32, level, internalformat, width, height, border int32, format, xtype uint32, pixels unsafe.Pointer) {
|
||||
C.gl_tex_image((C.GPTEXIMAGE2D)(gpTexImage2D), C.GLenum(target), C.GLint(level), C.GLint(internalformat), C.GLsizei(width), C.GLsizei(height), C.GLint(border), C.GLenum(format), C.GLenum(xtype), pixels)
|
||||
}
|
||||
func genFramebuffers(n int32, framebuffers *uint32) {
|
||||
C.gl_1u32((C.GPGENTEXTURES)(gpGenFramebuffers), C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(framebuffers)))
|
||||
}
|
||||
func framebufferTexture2D(target, attachment, texTarget, texture uint32, level int32) {
|
||||
C.gl_fb_tex2d((C.GPFRAMEBUFFERTEXTURE2D)(gpFramebufferTexture2D), C.GLenum(target), C.GLenum(attachment), C.GLenum(texTarget), C.GLuint(texture), C.GLint(level))
|
||||
}
|
||||
func genRenderbuffers(n int32, renderbuffers *uint32) {
|
||||
C.gl_1u32((C.GPGENTEXTURES)(gpGenRenderbuffers), C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(renderbuffers)))
|
||||
}
|
||||
func renderbufferStorage(target, internalformat uint32, width, height int32) {
|
||||
C.gl_rb_storage((C.GPRENDERBUFFERSTORAGE)(gpRenderbufferStorage), C.GLenum(target), C.GLenum(internalformat), C.GLsizei(width), C.GLsizei(height))
|
||||
}
|
||||
func framebufferRenderbuffer(target, attachment, rbtarget, rb uint32) {
|
||||
C.gl_fb_rb((C.GPFRAMEBUFFERRENDERBUFFER)(gpFramebufferRenderbuffer), C.GLenum(target), C.GLenum(attachment), C.GLenum(rbtarget), C.GLuint(rb))
|
||||
}
|
||||
func checkFramebufferStatus(target uint32) uint32 {
|
||||
return uint32(C.gl_check_fb_status((C.GPCHECKFRAMEBUFFERSTATUS)(gpCheckFramebufferStatus), C.GLenum(target)))
|
||||
}
|
||||
func deleteRenderbuffers(n int32, renderbuffers *uint32) {
|
||||
C.gl_delete_rb((C.GPDELETERENDERBUFFERS)(gpDeleteRenderbuffers), C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(renderbuffers)))
|
||||
}
|
||||
func deleteFramebuffers(n int32, framebuffers *uint32) {
|
||||
C.gl_delete_fb((C.GPDELETEFRAMEBUFFERS)(gpDeleteFramebuffers), C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(framebuffers)))
|
||||
}
|
||||
func deleteTextures(n int32, textures *uint32) {
|
||||
C.gl_delete_tex((C.GPDELETETEXTURES)(gpDeleteTextures), C.GLsizei(n), (*C.GLuint)(unsafe.Pointer(textures)))
|
||||
}
|
||||
func readPixels(x, y, width, height int32, format, xtype uint32, pixels unsafe.Pointer) {
|
||||
C.gl_read_pixels((C.GPREADPIXELS)(gpReadPixels), C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(xtype), pixels)
|
||||
}
|
||||
func pixelStorei(pname uint32, param int32) {
|
||||
C.gl_pixel_storei((C.GPPIXELSTOREI)(gpPixelStorei), C.GLenum(pname), C.GLint(param))
|
||||
}
|
||||
|
||||
var (
|
||||
fbo, tex, rbo uint32
|
||||
hasDepth bool
|
||||
|
|
@ -40,40 +251,40 @@ var (
|
|||
)
|
||||
|
||||
func initContext(getProcAddr func(name string) unsafe.Pointer) {
|
||||
if err := gl.InitWithProcAddrFunc(getProcAddr); err != nil {
|
||||
if err := initProcAddr(getProcAddr); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gl.PixelStorei(gl.PackAlignment, 1)
|
||||
pixelStorei(gl_PACK_ALIGNMENT, 1)
|
||||
}
|
||||
|
||||
func initFramebuffer(width, height int, depth, stencil bool) error {
|
||||
w, h := int32(width), int32(height)
|
||||
hasDepth = depth
|
||||
|
||||
gl.GenTextures(1, &tex)
|
||||
gl.BindTexture(gl.Texture2d, tex)
|
||||
gl.TexParameteri(gl.Texture2d, gl.TextureMinFilter, gl.NEAREST)
|
||||
gl.TexParameteri(gl.Texture2d, gl.TextureMagFilter, gl.NEAREST)
|
||||
gl.TexImage2D(gl.Texture2d, 0, gl.RGBA8, w, h, 0, pixType, pixFormat, nil)
|
||||
gl.BindTexture(gl.Texture2d, 0)
|
||||
genTextures(1, &tex)
|
||||
bindTexture(gl_TEXTURE_2D, tex)
|
||||
texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, gl_NEAREST)
|
||||
texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, gl_NEAREST)
|
||||
texImage2D(gl_TEXTURE_2D, 0, gl_RGBA8, w, h, 0, pixType, pixFormat, nil)
|
||||
bindTexture(gl_TEXTURE_2D, 0)
|
||||
|
||||
gl.GenFramebuffers(1, &fbo)
|
||||
gl.BindFramebuffer(gl.FRAMEBUFFER, fbo)
|
||||
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.ColorAttachment0, gl.Texture2d, tex, 0)
|
||||
genFramebuffers(1, &fbo)
|
||||
bindFramebuffer(gl_FRAMEBUFFER, fbo)
|
||||
framebufferTexture2D(gl_FRAMEBUFFER, gl_COLOR_ATTACHMENT0, gl_TEXTURE_2D, tex, 0)
|
||||
|
||||
if depth {
|
||||
gl.GenRenderbuffers(1, &rbo)
|
||||
gl.BindRenderbuffer(gl.RENDERBUFFER, rbo)
|
||||
format, attachment := uint32(gl.DepthComponent24), uint32(gl.DepthAttachment)
|
||||
genRenderbuffers(1, &rbo)
|
||||
bindRenderbuffer(gl_RENDERBUFFER, rbo)
|
||||
format, attachment := uint32(gl_DEPTH_COMPONENT24), uint32(gl_DEPTH_ATTACHMENT)
|
||||
if stencil {
|
||||
format, attachment = gl.Depth24Stencil8, gl.DepthStencilAttachment
|
||||
format, attachment = gl_DEPTH24_STENCIL8, gl_DEPTH_STENCIL_ATTACH
|
||||
}
|
||||
gl.RenderbufferStorage(gl.RENDERBUFFER, format, w, h)
|
||||
gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, rbo)
|
||||
gl.BindRenderbuffer(gl.RENDERBUFFER, 0)
|
||||
renderbufferStorage(gl_RENDERBUFFER, format, w, h)
|
||||
framebufferRenderbuffer(gl_FRAMEBUFFER, attachment, gl_RENDERBUFFER, rbo)
|
||||
bindRenderbuffer(gl_RENDERBUFFER, 0)
|
||||
}
|
||||
|
||||
if status := gl.CheckFramebufferStatus(gl.FRAMEBUFFER); status != gl.FramebufferComplete {
|
||||
if status := checkFramebufferStatus(gl_FRAMEBUFFER); status != gl_FRAMEBUFFER_COMPLETE {
|
||||
return fmt.Errorf("framebuffer incomplete: 0x%X", status)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -81,15 +292,17 @@ func initFramebuffer(width, height int, depth, stencil bool) error {
|
|||
|
||||
func destroyFramebuffer() {
|
||||
if hasDepth {
|
||||
gl.DeleteRenderbuffers(1, &rbo)
|
||||
deleteRenderbuffers(1, &rbo)
|
||||
}
|
||||
gl.DeleteFramebuffers(1, &fbo)
|
||||
gl.DeleteTextures(1, &tex)
|
||||
deleteFramebuffers(1, &fbo)
|
||||
deleteTextures(1, &tex)
|
||||
}
|
||||
|
||||
// ReadFramebuffer reads the current FBO color attachment into the internal buffer.
|
||||
// Call SetBuffer first to size the buffer (w * h * 4).
|
||||
func ReadFramebuffer(size, w, h uint) []byte {
|
||||
gl.BindFramebuffer(gl.FRAMEBUFFER, fbo)
|
||||
gl.ReadPixels(0, 0, int32(w), int32(h), pixType, pixFormat, bufPtr)
|
||||
bindFramebuffer(gl_FRAMEBUFFER, fbo)
|
||||
readPixels(0, 0, int32(w), int32(h), pixType, pixFormat, bufPtr)
|
||||
return buf[:size]
|
||||
}
|
||||
|
||||
|
|
@ -101,11 +314,11 @@ func SetBuffer(size int) {
|
|||
func SetPixelFormat(format PixelFormat) error {
|
||||
switch format {
|
||||
case UnsignedShort5551:
|
||||
pixFormat, pixType = gl.UnsignedShort5551, gl.BGRA
|
||||
pixFormat, pixType = 0x8034, gl_BGRA // GL_UNSIGNED_SHORT_5_5_5_1
|
||||
case UnsignedShort565:
|
||||
pixFormat, pixType = gl.UnsignedShort565, gl.RGB
|
||||
pixFormat, pixType = 0x8363, gl_RGB // GL_UNSIGNED_SHORT_5_6_5
|
||||
case UnsignedInt8888Rev:
|
||||
pixFormat, pixType = gl.UnsignedInt8888Rev, gl.BGRA
|
||||
pixFormat, pixType = 0x8367, gl_BGRA // GL_UNSIGNED_INT_8_8_8_8_REV
|
||||
default:
|
||||
return errors.New("unknown pixel format")
|
||||
}
|
||||
|
|
@ -113,10 +326,10 @@ func SetPixelFormat(format PixelFormat) error {
|
|||
}
|
||||
|
||||
func GLInfo() (version, vendor, renderer, glsl string) {
|
||||
return gl.GoStr(gl.GetString(gl.VERSION)),
|
||||
gl.GoStr(gl.GetString(gl.VENDOR)),
|
||||
gl.GoStr(gl.GetString(gl.RENDERER)),
|
||||
gl.GoStr(gl.GetString(gl.ShadingLanguageVersion))
|
||||
return goStr(getString(gl_VERSION)),
|
||||
goStr(getString(gl_VENDOR)),
|
||||
goStr(getString(gl_RENDERER)),
|
||||
goStr(getString(gl_SHADING_LANG_VERSION))
|
||||
}
|
||||
|
||||
func GlFbo() uint32 { return fbo }
|
||||
|
|
|
|||
575
pkg/worker/caged/libretro/graphics/rgfw.go
Normal file
575
pkg/worker/caged/libretro/graphics/rgfw.go
Normal file
|
|
@ -0,0 +1,575 @@
|
|||
package graphics
|
||||
|
||||
/*
|
||||
#cgo windows LDFLAGS: -lgdi32 -lopengl32
|
||||
#cgo linux LDFLAGS: -lX11 -lGL
|
||||
#cgo darwin LDFLAGS: -framework OpenGL
|
||||
|
||||
// ==========================================================================
|
||||
// rgfw_nano — minimal window + GL context for cloud-game
|
||||
// Derived from RGFW 2.0.0-dev (libpng license)
|
||||
// Copyright (C) 2022-26 Riley Mabb (@ColleagueRiley)
|
||||
// Altered: stripped to ~540 lines from ~16,400
|
||||
// Original: https://github.com/ColleagueRiley/RGFW
|
||||
// ==========================================================================
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// ---- platform detection ----
|
||||
#if defined(_WIN32)
|
||||
#define RGFW_WINDOWS
|
||||
#include <windows.h>
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
#define RGFW_X11
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <GL/glx.h>
|
||||
#elif defined(__APPLE__)
|
||||
#define RGFW_MACOS
|
||||
#include <dlfcn.h>
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#include <OpenGL/CGLTypes.h>
|
||||
#endif
|
||||
|
||||
// ---- basic types ----
|
||||
typedef unsigned char u8;
|
||||
typedef signed char i8;
|
||||
typedef unsigned short u16;
|
||||
typedef signed short i16;
|
||||
typedef unsigned int u32;
|
||||
typedef signed int i32;
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long i64;
|
||||
typedef u8 RGFW_bool;
|
||||
#define RGFW_TRUE 1
|
||||
#define RGFW_FALSE 0
|
||||
|
||||
#define RGFW_ALLOC malloc
|
||||
#define RGFW_FREE free
|
||||
|
||||
// ---- window flags ----
|
||||
typedef u32 RGFW_windowFlags;
|
||||
#define RGFW_windowHide (1u << 9)
|
||||
|
||||
// ---- GL types ----
|
||||
typedef void (*RGFW_proc)(void);
|
||||
|
||||
typedef struct RGFW_glContext {
|
||||
#ifdef RGFW_WINDOWS
|
||||
HGLRC ctx;
|
||||
#elif defined(RGFW_MACOS)
|
||||
void* ctx;
|
||||
#else
|
||||
GLXContext ctx;
|
||||
#endif
|
||||
} RGFW_glContext;
|
||||
|
||||
typedef enum { RGFW_glCore = 0, RGFW_glForwardCompatibility, RGFW_glCompatibility, RGFW_glES } RGFW_glProfile;
|
||||
typedef enum { RGFW_glAccelerated = 0, RGFW_glSoftware } RGFW_glRenderer;
|
||||
typedef enum { RGFW_glReleaseNone = 0 } RGFW_glReleaseBehavior;
|
||||
|
||||
typedef struct RGFW_glHints {
|
||||
i32 stencil, samples, stereo, auxBuffers, doubleBuffer;
|
||||
i32 red, green, blue, alpha, depth;
|
||||
i32 accumRed, accumGreen, accumBlue, accumAlpha;
|
||||
RGFW_bool sRGB, robustness, debug, noError;
|
||||
RGFW_glReleaseBehavior releaseBehavior;
|
||||
RGFW_glProfile profile;
|
||||
i32 major, minor;
|
||||
RGFW_glContext* share;
|
||||
RGFW_glRenderer renderer;
|
||||
} RGFW_glHints;
|
||||
|
||||
typedef u32 RGFW_gfxContextType;
|
||||
#define RGFW_gfxNativeOpenGL (1u << 0)
|
||||
#define RGFW_gfxOwnedByRGFW (1u << 2)
|
||||
|
||||
// ---- window struct ----
|
||||
#ifdef RGFW_WINDOWS
|
||||
typedef struct RGFW_window_src {
|
||||
HWND window;
|
||||
HDC hdc;
|
||||
RGFW_glContext* ctx_native;
|
||||
RGFW_gfxContextType gfxType;
|
||||
} RGFW_window_src;
|
||||
#elif defined(RGFW_MACOS)
|
||||
typedef struct RGFW_window_src {
|
||||
void* window;
|
||||
void* view;
|
||||
RGFW_glContext* ctx_native;
|
||||
RGFW_gfxContextType gfxType;
|
||||
} RGFW_window_src;
|
||||
#else
|
||||
typedef struct RGFW_window_src {
|
||||
Window window;
|
||||
Display* display;
|
||||
Colormap cmap;
|
||||
GLXFBConfig fbconfig;
|
||||
RGFW_glContext* ctx_native;
|
||||
RGFW_gfxContextType gfxType;
|
||||
} RGFW_window_src;
|
||||
#endif
|
||||
|
||||
typedef struct RGFW_window {
|
||||
RGFW_window_src src;
|
||||
i32 x, y, w, h;
|
||||
} RGFW_window;
|
||||
|
||||
// ---- global hints ----
|
||||
static RGFW_glHints RGFW_nano_hints = {0,0,0,0,1, 8,8,8,8,24, 0,0,0,0, 0,0,0,0, RGFW_glReleaseNone, RGFW_glCore, 1,0, NULL, RGFW_glAccelerated};
|
||||
|
||||
static void RGFW_resetGlobalHints_OpenGL(void) {
|
||||
RGFW_glHints d = {0,0,0,0,1, 8,8,8,8,24, 0,0,0,0, 0,0,0,0, RGFW_glReleaseNone, RGFW_glCore, 1,0, NULL, RGFW_glAccelerated};
|
||||
RGFW_nano_hints = d;
|
||||
}
|
||||
static void RGFW_setGlobalHints_OpenGL(RGFW_glHints* h) { RGFW_nano_hints = *h; }
|
||||
static RGFW_glHints* RGFW_getGlobalHints_OpenGL(void) { return &RGFW_nano_hints; }
|
||||
|
||||
// ---- API prototypes ----
|
||||
static i32 RGFW_init(const char* name, u8 flags);
|
||||
static void RGFW_deinit(void);
|
||||
static RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags);
|
||||
static void RGFW_window_close(RGFW_window* win);
|
||||
static void RGFW_window_setName(RGFW_window* win, const char* name);
|
||||
static void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win);
|
||||
static RGFW_proc RGFW_getProcAddress_OpenGL(const char* name);
|
||||
static RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints);
|
||||
static RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints);
|
||||
|
||||
// ==========================================================================
|
||||
// Platform implementations
|
||||
// ==========================================================================
|
||||
|
||||
#ifdef RGFW_WINDOWS
|
||||
// -------------------------------------------------------------------
|
||||
// Windows (Win32 + WGL)
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
static LRESULT CALLBACK RGFW_nano_WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
|
||||
return DefWindowProcW(hwnd, msg, wp, lp);
|
||||
}
|
||||
|
||||
static i32 RGFW_init(const char* name, u8 flags) { (void)name; (void)flags; return 0; }
|
||||
static void RGFW_deinit(void) {}
|
||||
|
||||
static RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) {
|
||||
(void)x; (void)y;
|
||||
RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
|
||||
if (!win) return NULL;
|
||||
memset(win, 0, sizeof(*win));
|
||||
win->w = w; win->h = h;
|
||||
|
||||
HINSTANCE hi = GetModuleHandleW(NULL);
|
||||
WNDCLASSW wc = {0};
|
||||
wc.lpfnWndProc = RGFW_nano_WndProc;
|
||||
wc.hInstance = hi;
|
||||
wc.lpszClassName = L"rgfw_nano_wc";
|
||||
RegisterClassW(&wc);
|
||||
|
||||
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||||
RECT rect = {0, 0, (LONG)w, (LONG)h};
|
||||
AdjustWindowRect(&rect, style, FALSE);
|
||||
|
||||
win->src.window = CreateWindowExW(0, L"rgfw_nano_wc", L"",
|
||||
style, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
|
||||
NULL, NULL, hi, NULL);
|
||||
if (!win->src.window) { RGFW_FREE(win); return NULL; }
|
||||
|
||||
win->src.hdc = GetDC(win->src.window);
|
||||
return win;
|
||||
}
|
||||
|
||||
static void RGFW_window_close(RGFW_window* win) {
|
||||
if (!win) return;
|
||||
if (win->src.ctx_native && (win->src.gfxType & RGFW_gfxOwnedByRGFW))
|
||||
RGFW_FREE(win->src.ctx_native);
|
||||
if (win->src.hdc) { ReleaseDC(win->src.window, win->src.hdc); win->src.hdc = NULL; }
|
||||
if (win->src.window) { DestroyWindow(win->src.window); win->src.window = NULL; }
|
||||
RGFW_FREE(win);
|
||||
}
|
||||
|
||||
static void RGFW_window_setName(RGFW_window* win, const char* name) { (void)win; (void)name; }
|
||||
|
||||
static void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
|
||||
if (win && win->src.hdc && win->src.ctx_native && win->src.ctx_native->ctx)
|
||||
wglMakeCurrent(win->src.hdc, win->src.ctx_native->ctx);
|
||||
}
|
||||
|
||||
static RGFW_proc RGFW_getProcAddress_OpenGL(const char* name) {
|
||||
static HMODULE glModule;
|
||||
if (!glModule) glModule = LoadLibraryA("opengl32.dll");
|
||||
if (glModule) { RGFW_proc p = (RGFW_proc)GetProcAddress(glModule, name); if (p) return p; }
|
||||
return (RGFW_proc)wglGetProcAddress(name);
|
||||
}
|
||||
|
||||
static RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
|
||||
(void)hints;
|
||||
if (!win || !win->src.hdc || !ctx) return RGFW_FALSE;
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = {0};
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_GENERIC_FORMAT;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 32;
|
||||
pfd.cDepthBits = 24;
|
||||
pfd.cStencilBits = 8;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
|
||||
int pf = ChoosePixelFormat(win->src.hdc, &pfd);
|
||||
if (!pf || !SetPixelFormat(win->src.hdc, pf, &pfd)) return RGFW_FALSE;
|
||||
|
||||
ctx->ctx = wglCreateContext(win->src.hdc);
|
||||
if (!ctx->ctx) return RGFW_FALSE;
|
||||
|
||||
win->src.ctx_native = ctx;
|
||||
win->src.gfxType = RGFW_gfxNativeOpenGL;
|
||||
return RGFW_TRUE;
|
||||
}
|
||||
|
||||
static RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) {
|
||||
RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext));
|
||||
if (!ctx) return NULL;
|
||||
if (!RGFW_window_createContextPtr_OpenGL(win, ctx, hints)) { RGFW_FREE(ctx); return NULL; }
|
||||
win->src.gfxType |= RGFW_gfxOwnedByRGFW;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// macOS (CGL, offscreen)
|
||||
// -------------------------------------------------------------------
|
||||
#elif defined(RGFW_MACOS)
|
||||
|
||||
static i32 RGFW_init(const char* name, u8 flags) { (void)name; (void)flags; return 0; }
|
||||
static void RGFW_deinit(void) {}
|
||||
|
||||
static RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) {
|
||||
(void)x; (void)y; (void)flags; (void)name;
|
||||
RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
|
||||
if (!win) return NULL;
|
||||
memset(win, 0, sizeof(*win));
|
||||
win->w = w; win->h = h;
|
||||
return win;
|
||||
}
|
||||
|
||||
static void RGFW_window_close(RGFW_window* win) {
|
||||
if (!win) return;
|
||||
if (win->src.ctx_native && (win->src.gfxType & RGFW_gfxNativeOpenGL)) {
|
||||
if (win->src.ctx_native->ctx) CGLDestroyContext((CGLContextObj)win->src.ctx_native->ctx);
|
||||
if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(win->src.ctx_native);
|
||||
}
|
||||
RGFW_FREE(win);
|
||||
}
|
||||
|
||||
static void RGFW_window_setName(RGFW_window* win, const char* name) { (void)win; (void)name; }
|
||||
|
||||
static void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
|
||||
if (win && win->src.ctx_native && win->src.ctx_native->ctx)
|
||||
CGLSetCurrentContext((CGLContextObj)win->src.ctx_native->ctx);
|
||||
}
|
||||
|
||||
static RGFW_proc RGFW_getProcAddress_OpenGL(const char* name) {
|
||||
static void* gl_handle;
|
||||
if (!gl_handle) gl_handle = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY);
|
||||
if (gl_handle) { void* sym = dlsym(gl_handle, name); if (sym) return (RGFW_proc)sym; }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
|
||||
(void)win;
|
||||
if (!ctx) return RGFW_FALSE;
|
||||
|
||||
CGLPixelFormatAttribute attrs[32];
|
||||
int n = 0;
|
||||
attrs[n++] = kCGLPFAOpenGLProfile;
|
||||
attrs[n++] = (CGLPixelFormatAttribute)kCGLOGLPVersion_Legacy;
|
||||
if (hints && hints->renderer == RGFW_glAccelerated) attrs[n++] = kCGLPFAAccelerated;
|
||||
attrs[n++] = kCGLPFAColorSize; attrs[n++] = 32;
|
||||
attrs[n++] = kCGLPFADepthSize; attrs[n++] = hints ? hints->depth : 24;
|
||||
attrs[n++] = kCGLPFAStencilSize; attrs[n++] = hints ? hints->stencil : 8;
|
||||
if (hints && hints->doubleBuffer) attrs[n++] = kCGLPFADoubleBuffer;
|
||||
attrs[n++] = 0;
|
||||
|
||||
CGLPixelFormatObj pix = NULL; GLint npix = 0;
|
||||
if (CGLChoosePixelFormat(attrs, &pix, &npix) != kCGLNoError || !pix) return RGFW_FALSE;
|
||||
|
||||
CGLError err = CGLCreateContext(pix, NULL, (CGLContextObj*)&ctx->ctx);
|
||||
CGLDestroyPixelFormat(pix);
|
||||
if (err != kCGLNoError || !ctx->ctx) return RGFW_FALSE;
|
||||
|
||||
if (CGLSetCurrentContext((CGLContextObj)ctx->ctx) != kCGLNoError) {
|
||||
CGLDestroyContext((CGLContextObj)ctx->ctx); ctx->ctx = NULL; return RGFW_FALSE;
|
||||
}
|
||||
|
||||
win->src.ctx_native = ctx;
|
||||
win->src.gfxType = RGFW_gfxNativeOpenGL;
|
||||
return RGFW_TRUE;
|
||||
}
|
||||
|
||||
static RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) {
|
||||
RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext));
|
||||
if (!ctx) return NULL;
|
||||
if (!RGFW_window_createContextPtr_OpenGL(win, ctx, hints)) { RGFW_FREE(ctx); return NULL; }
|
||||
win->src.gfxType |= RGFW_gfxOwnedByRGFW;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// X11 (GLX)
|
||||
// -------------------------------------------------------------------
|
||||
#else
|
||||
|
||||
static Display* RGFW_nano_display = NULL;
|
||||
static Atom RGFW_nano_WM_DELETE_WINDOW;
|
||||
|
||||
static i32 RGFW_init(const char* name, u8 flags) {
|
||||
(void)name; (void)flags;
|
||||
RGFW_nano_display = XOpenDisplay(NULL);
|
||||
if (!RGFW_nano_display) return -1;
|
||||
RGFW_nano_WM_DELETE_WINDOW = XInternAtom(RGFW_nano_display, "WM_DELETE_WINDOW", False);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void RGFW_deinit(void) {
|
||||
if (RGFW_nano_display) { XCloseDisplay(RGFW_nano_display); RGFW_nano_display = NULL; }
|
||||
}
|
||||
|
||||
static RGFW_window* RGFW_createWindow(const char* name, i32 x, i32 y, i32 w, i32 h, RGFW_windowFlags flags) {
|
||||
(void)x; (void)y; (void)flags;
|
||||
if (!RGFW_nano_display) return NULL;
|
||||
|
||||
RGFW_window* win = (RGFW_window*)RGFW_ALLOC(sizeof(RGFW_window));
|
||||
if (!win) return NULL;
|
||||
memset(win, 0, sizeof(*win));
|
||||
win->w = w; win->h = h;
|
||||
win->src.display = RGFW_nano_display;
|
||||
|
||||
int scr = DefaultScreen(RGFW_nano_display);
|
||||
Window root = DefaultRootWindow(RGFW_nano_display);
|
||||
|
||||
XSetWindowAttributes swa;
|
||||
swa.event_mask = StructureNotifyMask | ExposureMask;
|
||||
swa.colormap = XCreateColormap(RGFW_nano_display, root, DefaultVisual(RGFW_nano_display, scr), AllocNone);
|
||||
win->src.cmap = swa.colormap;
|
||||
|
||||
win->src.window = XCreateWindow(RGFW_nano_display, root, 0, 0, w, h, 0,
|
||||
DefaultDepth(RGFW_nano_display, scr), InputOutput,
|
||||
DefaultVisual(RGFW_nano_display, scr), CWEventMask | CWColormap, &swa);
|
||||
if (!win->src.window) { RGFW_FREE(win); return NULL; }
|
||||
|
||||
XSetWMProtocols(RGFW_nano_display, win->src.window, &RGFW_nano_WM_DELETE_WINDOW, 1);
|
||||
RGFW_window_setName(win, name);
|
||||
XMapWindow(RGFW_nano_display, win->src.window);
|
||||
XFlush(RGFW_nano_display);
|
||||
return win;
|
||||
}
|
||||
|
||||
static void RGFW_window_close(RGFW_window* win) {
|
||||
if (!win) return;
|
||||
if (win->src.ctx_native && (win->src.gfxType & RGFW_gfxNativeOpenGL)) {
|
||||
glXMakeCurrent(win->src.display, None, NULL);
|
||||
if (win->src.ctx_native->ctx) glXDestroyContext(win->src.display, win->src.ctx_native->ctx);
|
||||
if (win->src.gfxType & RGFW_gfxOwnedByRGFW) RGFW_FREE(win->src.ctx_native);
|
||||
}
|
||||
if (win->src.window) { XDestroyWindow(win->src.display, win->src.window); win->src.window = 0; }
|
||||
if (win->src.cmap) { XFreeColormap(win->src.display, win->src.cmap); win->src.cmap = 0; }
|
||||
RGFW_FREE(win);
|
||||
}
|
||||
|
||||
static void RGFW_window_setName(RGFW_window* win, const char* name) {
|
||||
if (win && win->src.display && win->src.window) XStoreName(win->src.display, win->src.window, name);
|
||||
}
|
||||
|
||||
static void RGFW_window_makeCurrentContext_OpenGL(RGFW_window* win) {
|
||||
if (win && win->src.display && win->src.ctx_native && win->src.ctx_native->ctx)
|
||||
glXMakeCurrent(win->src.display, win->src.window, win->src.ctx_native->ctx);
|
||||
}
|
||||
|
||||
static RGFW_proc RGFW_getProcAddress_OpenGL(const char* name) {
|
||||
return (RGFW_proc)glXGetProcAddress((const GLubyte*)name);
|
||||
}
|
||||
|
||||
static int RGFW_nano_glx_attribs(int* attribs, int max, RGFW_glHints* hints) {
|
||||
int n = 0;
|
||||
(void)max;
|
||||
attribs[n++] = GLX_RENDER_TYPE; attribs[n++] = GLX_RGBA_BIT;
|
||||
attribs[n++] = GLX_DRAWABLE_TYPE; attribs[n++] = GLX_WINDOW_BIT;
|
||||
attribs[n++] = GLX_DOUBLEBUFFER; attribs[n++] = hints->doubleBuffer ? True : False;
|
||||
attribs[n++] = GLX_RED_SIZE; attribs[n++] = hints->red;
|
||||
attribs[n++] = GLX_GREEN_SIZE; attribs[n++] = hints->green;
|
||||
attribs[n++] = GLX_BLUE_SIZE; attribs[n++] = hints->blue;
|
||||
attribs[n++] = GLX_ALPHA_SIZE; attribs[n++] = hints->alpha;
|
||||
attribs[n++] = GLX_DEPTH_SIZE; attribs[n++] = hints->depth;
|
||||
attribs[n++] = GLX_STENCIL_SIZE; attribs[n++] = hints->stencil;
|
||||
attribs[n++] = None;
|
||||
return n;
|
||||
}
|
||||
|
||||
static RGFW_bool RGFW_window_createContextPtr_OpenGL(RGFW_window* win, RGFW_glContext* ctx, RGFW_glHints* hints) {
|
||||
if (!win || !win->src.display || !ctx) return RGFW_FALSE;
|
||||
|
||||
int attribs[64];
|
||||
RGFW_nano_glx_attribs(attribs, 64, hints);
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig* fbcs = glXChooseFBConfig(win->src.display, DefaultScreen(win->src.display), attribs, &fbcount);
|
||||
if (!fbcs || fbcount == 0) return RGFW_FALSE;
|
||||
|
||||
win->src.fbconfig = fbcs[0];
|
||||
XFree(fbcs);
|
||||
|
||||
GLXContext share = (hints && hints->share) ? hints->share->ctx : NULL;
|
||||
|
||||
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
|
||||
glXCreateContextAttribsARBProc glXCreateContextAttribsARB =
|
||||
(glXCreateContextAttribsARBProc)glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
|
||||
|
||||
if (glXCreateContextAttribsARB && hints && (hints->major > 0 || hints->minor > 0)) {
|
||||
int ctx_attribs[] = {
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, hints->major,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, hints->minor,
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB,
|
||||
hints->profile == RGFW_glCore ? GLX_CONTEXT_CORE_PROFILE_BIT_ARB :
|
||||
hints->profile == RGFW_glCompatibility ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :
|
||||
GLX_CONTEXT_ES_PROFILE_BIT_EXT,
|
||||
None
|
||||
};
|
||||
ctx->ctx = glXCreateContextAttribsARB(win->src.display, win->src.fbconfig, share, True, ctx_attribs);
|
||||
}
|
||||
if (!ctx->ctx) {
|
||||
ctx->ctx = glXCreateNewContext(win->src.display, win->src.fbconfig, GLX_RGBA_TYPE, share, True);
|
||||
}
|
||||
if (!ctx->ctx) return RGFW_FALSE;
|
||||
|
||||
win->src.ctx_native = ctx;
|
||||
win->src.gfxType = RGFW_gfxNativeOpenGL;
|
||||
return RGFW_TRUE;
|
||||
}
|
||||
|
||||
static RGFW_glContext* RGFW_window_createContext_OpenGL(RGFW_window* win, RGFW_glHints* hints) {
|
||||
RGFW_glContext* ctx = (RGFW_glContext*)RGFW_ALLOC(sizeof(RGFW_glContext));
|
||||
if (!ctx) return NULL;
|
||||
if (!RGFW_window_createContextPtr_OpenGL(win, ctx, hints)) { RGFW_FREE(ctx); return NULL; }
|
||||
win->src.gfxType |= RGFW_gfxOwnedByRGFW;
|
||||
return ctx;
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// RGFW is a graphics context backed by the inlined rgfw_nano C code.
|
||||
type RGFW struct {
|
||||
win *C.RGFW_window
|
||||
inited bool
|
||||
}
|
||||
|
||||
// NewRGFWContext creates a hidden window with an OpenGL context and an FBO.
|
||||
func NewRGFWContext(cfg Config) (*RGFW, error) {
|
||||
name := C.CString("cloud-retro")
|
||||
defer C.free(unsafe.Pointer(name))
|
||||
|
||||
if ret := C.RGFW_init(name, 0); ret < 0 {
|
||||
return nil, fmt.Errorf("rgfw init failed: %d", int(ret))
|
||||
}
|
||||
|
||||
if !cfg.GLAutoContext {
|
||||
var hints C.RGFW_glHints
|
||||
C.RGFW_resetGlobalHints_OpenGL()
|
||||
hints.major = C.i32(cfg.GLVersionMajor)
|
||||
hints.minor = C.i32(cfg.GLVersionMinor)
|
||||
if cfg.GLHasDepth {
|
||||
hints.depth = 24
|
||||
}
|
||||
if cfg.GLHasStencil {
|
||||
hints.stencil = 8
|
||||
}
|
||||
hints.doubleBuffer = 1
|
||||
hints.renderer = C.RGFW_glSoftware
|
||||
|
||||
switch cfg.Ctx {
|
||||
case CtxOpenGlCore:
|
||||
hints.profile = C.RGFW_glCore
|
||||
case CtxOpenGlEs2, CtxOpenGlEs3, CtxOpenGlEsVersion:
|
||||
hints.profile = C.RGFW_glES
|
||||
hints.major = 3
|
||||
hints.minor = 0
|
||||
case CtxOpenGl:
|
||||
hints.profile = C.RGFW_glCompatibility
|
||||
default:
|
||||
hints.profile = C.RGFW_glCompatibility
|
||||
}
|
||||
C.RGFW_setGlobalHints_OpenGL(&hints)
|
||||
}
|
||||
|
||||
wname := C.CString("cloud-retro")
|
||||
defer C.free(unsafe.Pointer(wname))
|
||||
win := C.RGFW_createWindow(wname, 0, 0, 1, 1, C.RGFW_windowHide)
|
||||
if win == nil {
|
||||
C.RGFW_deinit()
|
||||
return nil, fmt.Errorf("rgfw window creation failed")
|
||||
}
|
||||
|
||||
if C.RGFW_window_createContext_OpenGL(win, C.RGFW_getGlobalHints_OpenGL()) == nil {
|
||||
C.RGFW_window_close(win)
|
||||
C.RGFW_deinit()
|
||||
return nil, fmt.Errorf("rgfw GL context creation failed")
|
||||
}
|
||||
|
||||
C.RGFW_window_makeCurrentContext_OpenGL(win)
|
||||
|
||||
initContext(func(name string) unsafe.Pointer {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return unsafe.Pointer(C.RGFW_getProcAddress_OpenGL(cname))
|
||||
})
|
||||
|
||||
if err := initFramebuffer(cfg.W, cfg.H, cfg.GLHasDepth, cfg.GLHasStencil); err != nil {
|
||||
C.RGFW_window_close(win)
|
||||
C.RGFW_deinit()
|
||||
return nil, fmt.Errorf("rgfw fbo: %w", err)
|
||||
}
|
||||
|
||||
return &RGFW{win: win, inited: true}, nil
|
||||
}
|
||||
|
||||
func (r *RGFW) Deinit() error {
|
||||
if !r.inited {
|
||||
return nil
|
||||
}
|
||||
r.inited = false
|
||||
destroyFramebuffer()
|
||||
C.RGFW_window_close(r.win)
|
||||
r.win = nil
|
||||
C.RGFW_deinit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RGFW) BindContext() error {
|
||||
if !r.inited {
|
||||
return fmt.Errorf("rgfw: context not initialized")
|
||||
}
|
||||
C.RGFW_window_makeCurrentContext_OpenGL(r.win)
|
||||
return nil
|
||||
}
|
||||
|
||||
func RGFWGlProcAddress(proc string) unsafe.Pointer {
|
||||
cname := C.CString(proc)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
return unsafe.Pointer(C.RGFW_getProcAddress_OpenGL(cname))
|
||||
}
|
||||
|
||||
func RGFWTryInit() error {
|
||||
className := C.CString("cloud-retro-test")
|
||||
defer C.free(unsafe.Pointer(className))
|
||||
if ret := C.RGFW_init(className, 0); ret < 0 {
|
||||
return fmt.Errorf("rgfw init failed: %d", int(ret))
|
||||
}
|
||||
C.RGFW_deinit()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
package graphics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
type SDL struct {
|
||||
w *sdl.Window
|
||||
ctx sdl.GLContext
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Ctx Context
|
||||
W, H int
|
||||
GLAutoContext bool
|
||||
GLVersionMajor uint
|
||||
GLVersionMinor uint
|
||||
GLHasDepth bool
|
||||
GLHasStencil bool
|
||||
}
|
||||
|
||||
func NewSDLContext(cfg Config) (*SDL, error) {
|
||||
if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
|
||||
return nil, fmt.Errorf("sdl: %w", err)
|
||||
}
|
||||
|
||||
if !cfg.GLAutoContext {
|
||||
if err := setGLAttrs(cfg.Ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
w, err := sdl.CreateWindow("cloud-retro", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, 1, 1, sdl.WINDOW_OPENGL|sdl.WINDOW_HIDDEN)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("window: %w", err)
|
||||
}
|
||||
|
||||
ctx, err := w.GLCreateContext()
|
||||
if err != nil {
|
||||
err1 := w.Destroy()
|
||||
return nil, fmt.Errorf("gl context: %w, destroy err: %w", err, err1)
|
||||
}
|
||||
|
||||
if err = w.GLMakeCurrent(ctx); err != nil {
|
||||
return nil, fmt.Errorf("gl bind: %w", err)
|
||||
}
|
||||
|
||||
initContext(sdl.GLGetProcAddress)
|
||||
|
||||
if err = initFramebuffer(cfg.W, cfg.H, cfg.GLHasDepth, cfg.GLHasStencil); err != nil {
|
||||
return nil, fmt.Errorf("fbo: %w", err)
|
||||
}
|
||||
|
||||
return &SDL{w: w, ctx: ctx}, nil
|
||||
}
|
||||
|
||||
func setGLAttrs(ctx Context) error {
|
||||
set := sdl.GLSetAttribute
|
||||
switch ctx {
|
||||
case CtxOpenGlCore:
|
||||
return set(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_CORE)
|
||||
case CtxOpenGlEs2:
|
||||
for _, a := range [][2]int{
|
||||
{sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_ES},
|
||||
{sdl.GL_CONTEXT_MAJOR_VERSION, 3},
|
||||
{sdl.GL_CONTEXT_MINOR_VERSION, 0},
|
||||
} {
|
||||
if err := set(sdl.GLattr(a[0]), a[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case CtxOpenGl:
|
||||
return set(sdl.GL_CONTEXT_PROFILE_MASK, sdl.GL_CONTEXT_PROFILE_COMPATIBILITY)
|
||||
default:
|
||||
return fmt.Errorf("unsupported gl context: %v", ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SDL) Deinit() error {
|
||||
destroyFramebuffer()
|
||||
sdl.GLDeleteContext(s.ctx)
|
||||
err := s.w.Destroy()
|
||||
sdl.Quit()
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *SDL) BindContext() error { return s.w.GLMakeCurrent(s.ctx) }
|
||||
func GlProcAddress(proc string) unsafe.Pointer { return sdl.GLGetProcAddress(proc) }
|
||||
|
||||
func TryInit() error {
|
||||
if err := sdl.Init(sdl.INIT_VIDEO); err != nil {
|
||||
return err
|
||||
}
|
||||
sdl.Quit()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ type Nanoarch struct {
|
|||
}
|
||||
vfr bool
|
||||
Aspect bool
|
||||
sdlCtx *graphics.SDL
|
||||
glCtx *graphics.RGFW
|
||||
hackSkipHwContextDestroy bool
|
||||
hackSkipSameThreadSave bool
|
||||
limiter func(func())
|
||||
|
|
@ -373,7 +373,7 @@ func (n *Nanoarch) Shutdown() {
|
|||
thread.Main(func() {
|
||||
// running inside a go routine, lock the thread to make sure the OpenGL context stays current
|
||||
runtime.LockOSThread()
|
||||
if err := n.sdlCtx.BindContext(); err != nil {
|
||||
if err := n.glCtx.BindContext(); err != nil {
|
||||
n.log.Error().Err(err).Msg("ctx switch fail")
|
||||
}
|
||||
})
|
||||
|
|
@ -421,7 +421,7 @@ func (n *Nanoarch) Run() {
|
|||
} else {
|
||||
if n.Video.gl.enabled {
|
||||
runtime.LockOSThread()
|
||||
if err := n.sdlCtx.BindContext(); err != nil {
|
||||
if err := n.glCtx.BindContext(); err != nil {
|
||||
n.log.Error().Err(err).Msg("ctx bind fail")
|
||||
}
|
||||
}
|
||||
|
|
@ -432,7 +432,7 @@ func (n *Nanoarch) Run() {
|
|||
}
|
||||
}
|
||||
|
||||
func (n *Nanoarch) IsSupported() error { return graphics.TryInit() }
|
||||
func (n *Nanoarch) IsSupported() error { return graphics.RGFWTryInit() }
|
||||
func (n *Nanoarch) IsGL() bool { return n.Video.gl.enabled }
|
||||
func (n *Nanoarch) IsStopped() bool { return n.Stopped.Load() }
|
||||
func (n *Nanoarch) InputRetropad(port int, data []byte) { n.retropad.SetInput(port, data) }
|
||||
|
|
@ -744,7 +744,7 @@ func coreGetCurrentFramebuffer() C.uintptr_t { return (C.uintptr_t)(graphics.GlF
|
|||
|
||||
//export coreGetProcAddress
|
||||
func coreGetProcAddress(sym *C.char) C.retro_proc_address_t {
|
||||
return (C.retro_proc_address_t)(graphics.GlProcAddress(C.GoString(sym)))
|
||||
return (C.retro_proc_address_t)(graphics.RGFWGlProcAddress(C.GoString(sym)))
|
||||
}
|
||||
|
||||
//export coreEnvironment
|
||||
|
|
@ -903,7 +903,7 @@ func initVideo() {
|
|||
|
||||
thread.Main(func() {
|
||||
var err error
|
||||
Nan0.sdlCtx, err = graphics.NewSDLContext(graphics.Config{
|
||||
Nan0.glCtx, err = graphics.NewRGFWContext(graphics.Config{
|
||||
Ctx: context,
|
||||
W: int(Nan0.sys.av.geometry.max_width),
|
||||
H: int(Nan0.sys.av.geometry.max_height),
|
||||
|
|
@ -929,7 +929,7 @@ func deinitVideo() {
|
|||
C.bridge_context_reset(Nan0.Video.hw.context_destroy)
|
||||
}
|
||||
thread.Main(func() {
|
||||
if err := Nan0.sdlCtx.Deinit(); err != nil {
|
||||
if err := Nan0.glCtx.Deinit(); err != nil {
|
||||
Nan0.log.Error().Err(err).Msg("deinit fail")
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue