Initial commit

main
eater 2 years ago
commit 1f3881bdc4
Signed by: eater
GPG Key ID: AD2560A0F84F0759

2
.gitignore vendored

@ -0,0 +1,2 @@
resources/gl.xml
vendor

@ -0,0 +1,5 @@
# Graphics Toolkit
A php library offering FFI "bindings" to OpenGL (GLX), GLFW, and Cairo.
work in progress and all

@ -0,0 +1,40 @@
<?php
if ( ! file_exists(__DIR__ . "/../resources/gl.xml")) {
copy("https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/gl.xml", __DIR__ . "/../resources/gl.xml");
}
$xml = new DOMDocument();
$xml->loadXML(file_get_contents(__DIR__ . "/../resources/gl.xml"));
$commands = $xml->getElementsByTagName("commands")->item(0);
$data = file_get_contents(__DIR__ . "/../headers/gl.h");
$data .= "// GENERATED DATA START\n\n";
/** @var DOMNode $node */
foreach ($commands->childNodes as $node) {
if ($node->nodeName !== "command") {
continue;
}
/** @var DOMElement $node */
$proto = $node->getElementsByTagName("proto")->item(0);
/** @var DOMElement $name */
$name = $proto->getElementsByTagName("name")[0];
$name->remove();
$returnType = trim($proto->textContent);
$functionName = trim($name->textContent);
$args = [];
foreach ($node->getElementsByTagName("param") as $param) {
$args[] = trim($param->textContent);
}
$data .= "typedef $returnType (* FUNC_$functionName) (" . implode(", ", $args) . ");\n";
}
file_put_contents(__DIR__ . "/../headers/gl_generated.h", $data);

@ -0,0 +1,313 @@
<?php
use Cijber\GraphicsToolkit\Cairo;
use Cijber\GraphicsToolkit\GL;
use Cijber\GraphicsToolkit\GLFW;
use Cijber\GraphicsToolkit\Utils;
include(__DIR__ . "/../vendor/autoload.php");
function main() {
GL::init();
GLFW::init();
GLFW::windowHint(GLFW::CONTEXT_VERSION_MAJOR, 3);
GLFW::windowHint(GLFW::CONTEXT_VERSION_MINOR, 3);
GLFW::windowHint(GLFW::OPENGL_PROFILE, GLFW::OPENGL_CORE_PROFILE);
$window = GLFW::createWindow(800, 600, "Ha it's PHP!", null, null);
if ($window === null || FFI::isNull($window)) {
die("Couldn't create Window");
}
GLFW::makeContextCurrent($window);
$viewportHeight = 0;
$viewportWidth = 0;
GLFW::setFramebufferSizeCallback(
$window,
function($window, $width, $height) use (&$viewportHeight, &$viewportWidth) {
echo "Size: $width x $height\n";
GL::viewport(0, 0, $viewportWidth = $width, $viewportHeight = $height);
}
);
GL::viewport(0, 0, 800, 600);
GL::debugMessageCallback(function($source, $type, $id, $severity, $length, $message, $user) {
$message = substr($message, 0, $length);
var_dump(["source" => $source, "type" => $type, "id" => $id, "severity" => $severity, "message" => $message, "gl" => GL::$lastCall]);
}, null);
// GL::debugMessageCallback($callback, null);
GL::enable(GL::DEBUG_OUTPUT);
GL::enable(GL::DEBUG_OUTPUT_SYNCHRONOUS);
GL::enable(GL::BLEND);
GL::blendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA);
$vertexShader = GL::createShader(GL::VERTEX_SHADER);
$vertexShaderSource = file_get_contents(__DIR__ . "/../shaders/vertex.glsl");
GL::shaderSource($vertexShader, 1, $vertexShaderSource, null);
GL::compileShader($vertexShader);
GL::getShaderiv($vertexShader, GL::COMPILE_STATUS, $success);
if ( ! $success) {
GL::getShaderiv($vertexShader, GL::INFO_LOG_LENGTH, $logLength);
GL::getShaderInfoLog($vertexShader, $infoLog, $logLength);
die("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n\t$infoLog");
}
$fragmentShader = GL::createShader(GL::FRAGMENT_SHADER);
$fragmentShaderSource = file_get_contents(
__DIR__ . "/../shaders/fragment.glsl"
);
GL::shaderSource($fragmentShader, 1, $fragmentShaderSource, null);
GL::compileShader($fragmentShader);
GL::getShaderiv($fragmentShader, GL::COMPILE_STATUS, $success);
if ( ! $success) {
GL::getShaderiv($fragmentShader, GL::INFO_LOG_LENGTH, $logLength);
GL::GetShaderInfoLog($fragmentShader, $infoLog, $logLength);
die("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n\t$infoLog");
}
$shaderProgram = GL::createProgram();
GL::attachShader($shaderProgram, $vertexShader);
GL::attachShader($shaderProgram, $fragmentShader);
GL::linkProgram($shaderProgram);
GL::deleteShader($vertexShader);
GL::deleteShader($fragmentShader);
$vertices = [
-0.5,
-0.5,
0.0,
0.5,
-0.5,
0.0,
0.0,
0.5,
0.0,
];
$float = Utils::arrayOf('float', $vertices);
GL::genVertexArrays(1, $VAO);
GL::genBuffers(1, $VBO);
GL::bindVertexArray($VAO);
GL::bindBuffer(GL::ARRAY_BUFFER, $VBO);
GL::bufferData(
GL::ARRAY_BUFFER,
FFI::sizeof($float),
$float,
GL::STATIC_DRAW
);
GL::vertexAttribPointer(
0,
3,
GL::FLOAT,
false,
12,
0
);
GL::enableVertexAttribArray(0);
GL::bindBuffer(GL::ARRAY_BUFFER, 0);
GL::bindVertexArray(0);
$textureRow = Cairo::format_stride_for_width(Cairo::FORMAT_RGB24, 400);
$textureData = FFI::new(FFI::arrayType(FFI::type("unsigned char"), [$textureRow * 400]));
$surface = Cairo::image_surface_create_for_data($textureData, Cairo::FORMAT_RGB24, 400, 400, $textureRow);
$cairo = Cairo::create($surface);
Cairo::select_font_face($cairo, "sans-serif", Cairo::FONT_SLANT_NORMAL, Cairo::FONT_SLANT_NORMAL);
Cairo::set_font_size($cairo, 50);
Cairo::move_to($cairo, 50, 50);
Cairo::show_text($cairo, "Hello PHP!");
Cairo::rectangle($cairo, 0, 0, 50, 50);
Cairo::fill($cairo);
Cairo::surface_flush($surface);
Gl::genTextures(1, $texture);
GL::bindTexture(GL::TEXTURE_2D, $texture);
gl::texParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_S, GL::REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
gl::texParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_T, GL::REPEAT);
// set texture filtering parameters
gl::texParameteri(GL::TEXTURE_2D, GL::TEXTURE_MIN_FILTER, GL::LINEAR);
gl::texParameteri(GL::TEXTURE_2D, GL::TEXTURE_MAG_FILTER, GL::LINEAR);
GL::texImage2D(GL::TEXTURE_2D, 0, GL::RGBA, 400, 400, 0, GL::BGRA, GL::UNSIGNED_BYTE, $textureData);
$vertexShader = GL::createShader(GL::VERTEX_SHADER);
$vertexShaderSource = file_get_contents(__DIR__ . "/../shaders/sq_vertex_shader.glsl");
GL::shaderSource(
$vertexShader,
1,
$vertexShaderSource,
null
);
GL::compileShader($vertexShader);
GL::getShaderiv($vertexShader, GL::COMPILE_STATUS, $success);
if ( ! $success) {
GL::getShaderiv($vertexShader, GL::INFO_LOG_LENGTH, $logLength);
GL::getShaderInfoLog($vertexShader, $infoLog, $logLength);
die("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n\t$infoLog");
}
$fragmentShader = GL::createShader(GL::FRAGMENT_SHADER);
$fragmentShaderSource = file_get_contents(
__DIR__ . "/../shaders/sq_fragment_shader.glsl"
);
GL::shaderSource(
$fragmentShader,
1,
$fragmentShaderSource,
null
);
GL::compileShader($fragmentShader);
GL::getShaderiv($fragmentShader, GL::COMPILE_STATUS, $success);
if ( ! $success) {
GL::getShaderiv($fragmentShader, GL::INFO_LOG_LENGTH, $logLength);
GL::GetShaderInfoLog($fragmentShader, $infoLog, $logLength);
die("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n\t$infoLog");
}
$squareProgram = GL::createProgram();
GL::attachShader($squareProgram, $vertexShader);
GL::attachShader($squareProgram, $fragmentShader);
GL::linkProgram($squareProgram);
GL::deleteShader($vertexShader);
GL::deleteShader($fragmentShader);
$sq = [
// positions // colors // texture coords
0.5,
0.5,
0.0,
1.0,
0.0,
0.0,
1.0,
1.0, // top right
0.5,
-0.5,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0, // bottom right
-0.5,
-0.5,
0.0,
0.0,
0.0,
1.0,
0.0,
0.0, // bottom left
-0.5,
0.5,
0.0,
1.0,
1.0,
0.0,
0.0,
1.0 // top left
];
$float = Utils::arrayOf('float', $sq);
GL::genVertexArrays(1, $SQUARE_VAO);
GL::genBuffers(1, $VBO);
GL::genBuffers(1, $EBO);
GL::bindVertexArray($SQUARE_VAO);
GL::bindBuffer(GL::ARRAY_BUFFER, $VBO);
GL::bufferData(
GL::ARRAY_BUFFER,
FFI::sizeof($float),
$float,
GL::STATIC_DRAW
);
$indices = Utils::arrayOf("unsigned int", [0, 1, 3, 1, 2, 3]);
GL::bindBuffer(GL::ELEMENT_ARRAY_BUFFER, $EBO);
GL::bufferData(
GL::ELEMENT_ARRAY_BUFFER,
FFI::sizeof($indices),
$indices,
GL::STATIC_DRAW,
);
GL::vertexAttribPointer(0, 3, GL::FLOAT, false, 8 * 4, 0);
GL::enableVertexAttribArray(0);
GL::vertexAttribPointer(1, 3, GL::FLOAT, false, 8 * 4, 3 * 4);
GL::enableVertexAttribArray(1);
GL::vertexAttribPointer(2, 2, GL::FLOAT, false, 8 * 4, 6 * 4);
GL::enableVertexAttribArray(2);
GL::useProgram($squareProgram);
$location = GL::getUniformLocation($squareProgram, "ourTexture");
GL::uniform1i($location, 0);
$viewportSizeLocation = GL::getUniformLocation($squareProgram, "viewportSize");
while ( ! GLFW::windowShouldClose($window)) {
processInput($window);
GL::clearColor(0.2, 0.3, 0.3, 1.0);
GL::clear(GL::COLOR_BUFFER_BIT);
GL::useProgram($shaderProgram);
GL::bindVertexArray($VAO);
GL::drawArrays(GL::TRIANGLES, 0, 3);
GL::activeTexture(GL::TEXTURE0);
GL::bindTexture(GL::TEXTURE_2D, $texture);
GL::useProgram($squareProgram);
GL::uniform2i($viewportSizeLocation, $viewportWidth, $viewportHeight);
GL::bindVertexArray($SQUARE_VAO);
$f = FFI::new("long long");
$f->cdata = 0;
GL::drawElements(GL::TRIANGLES, 6, GL::UNSIGNED_INT, FFI::cast('void *', $f));
GLFW::pollEvents();
GLFW::swapBuffers($window);
}
GLFW::terminate();
}
function processInput($window) {
if (GLFW::getKey($window, GLFW::KEY_ESCAPE) === GLFW::PRESS) {
GLFW::setWindowShouldClose($window, 1);
}
}
main();

@ -0,0 +1,23 @@
{
"name": "cijber/graphics-toolkit",
"type": "project",
"require": {
"php": "^8.0",
"ext-FFI": "*",
"ext-dom": "*"
},
"require-dev": {
},
"license": "GPLv3-or-later",
"autoload": {
"psr-4": {
"Cijber\\GraphicsToolkit\\": "src"
}
},
"authors": [
{
"name": "eater",
"email": "=@eater.me"
}
]
}

22
composer.lock generated

@ -0,0 +1,22 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "31d56ebb2757d377f4d691569ec53ea6",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^8.0",
"ext-ffi": "*",
"ext-dom": "*"
},
"platform-dev": [],
"plugin-api-version": "2.1.0"
}

@ -0,0 +1,30 @@
#define FFI_LIB "libcairo.so.2"
#define FFI_SCOPE "cairo"
typedef struct _cairo cairo_t;
typedef struct _cairo_surface cairo_surface_t;
typedef int cairo_format_t;
typedef int cairo_font_slant_t;
typedef int cairo_font_weight_t;
// Context
cairo_t *cairo_create(cairo_surface_t *target);
void cairo_set_source_rgba(cairo_t *cr, double red, double green, double blue, double alpha);
// Drawing
void cairo_move_to(cairo_t *cr, double x, double y);
void cairo_stroke(cairo_t *cr);
void cairo_fill(cairo_t *cr);
void cairo_rectangle(cairo_t *cr, double x, double y, double width, double height);
// Surface
cairo_surface_t *cairo_image_surface_create (cairo_format_t format, int width, int height);
cairo_surface_t *cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, int width, int height, int stride);
int cairo_format_stride_for_width (cairo_format_t format, int width);
void cairo_surface_flush (cairo_surface_t *surface);
// Text
void cairo_show_text (cairo_t *cr, const char *utf8);
void cairo_select_font_face (cairo_t *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight);
void cairo_set_font_size (cairo_t *cr, double size);

@ -0,0 +1,57 @@
#define FFI_LIB "libGL.so.1"
#define FFI_SCOPE "gl"
typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef unsigned int GLbitfield;
typedef void GLvoid;
typedef signed char GLbyte; /* 1-byte signed */
typedef short GLshort; /* 2-byte signed */
typedef int GLint; /* 4-byte signed */
typedef unsigned char GLubyte; /* 1-byte unsigned */
typedef unsigned short GLushort; /* 2-byte unsigned */
typedef unsigned int GLuint; /* 4-byte unsigned */
typedef int GLsizei; /* 4-byte signed */
typedef float GLfloat; /* single precision float */
typedef float GLclampf; /* single precision float in [0,1] */
typedef double GLdouble; /* double precision float */
typedef double GLclampd; /* double precision float in [0,1] */
typedef char GLchar;
typedef long GLsizeiptr;
typedef long GLintptr;
typedef long GLsync;
typedef long GLeglImageOES;
typedef void *GLeglClientBufferEXT;
typedef uint64_t GLuint64;
typedef int64_t GLint64;
typedef uint64_t GLuint64EXT;
typedef int64_t GLint64EXT;
typedef GLint GLfixed;
typedef unsigned short GLhalfNV;
typedef unsigned int GLhandleARB;
typedef char GLcharARB;
typedef long GLintptrARB;
typedef long GLsizeiptrARB;
typedef int32_t GLclampx;
typedef void (*__GLXextFuncPtr)(void);
typedef void ( *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
typedef void ( *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
typedef void ( *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
typedef void ( *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
typedef unsigned short GLhalfNV;
typedef GLintptr GLvdpauSurfaceNV;
__GLXextFuncPtr glXGetProcAddress (const GLubyte *procName);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,19 @@
#define FFI_LIB "libglfw.so.3"
#define FFI_SCOPE "glfw"
int glfwInit(void);
void glfwWindowHint(int hint, int value);
typedef struct GLFWmonitor GLFWmonitor;
typedef struct GLFWwindow GLFWwindow;
typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);
GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share);
void glfwMakeContextCurrent(GLFWwindow* window);
int glfwWindowShouldClose(GLFWwindow* window);
int glfwGetKey(GLFWwindow* window, int key);
void glfwSetWindowShouldClose(GLFWwindow* window, int shouldClose);
void glfwSwapBuffers(GLFWwindow* window);
void glfwPollEvents(void);
void glfwTerminate(void);
GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun callback);

@ -0,0 +1,7 @@
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0, 0.5, 0.2, 1.0);
}

@ -0,0 +1,17 @@
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
uniform ivec2 viewportSize;
void main()
{
ivec2 txtSize = textureSize(ourTexture, 0);
vec2 coord = vec2(gl_FragCoord.x / txtSize.x, -gl_FragCoord.y / txtSize.y);
float rest = coord.y - floor(coord.y);
FragColor = texture(ourTexture, coord);
}

@ -0,0 +1,14 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
TexCoord = aTexCoord;
}

@ -0,0 +1,7 @@
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}

@ -0,0 +1,37 @@
<?php
namespace Cijber\GraphicsToolkit;
use Cijber\GraphicsToolkit\Consts\CairoConsts;
use FFI;
/**
* @method static FFI\CData create(FFI\CData $surface)
* @method static FFI\CData image_surface_create(int $format, int $width, int $height)
* @method static FFI\CData image_surface_create_for_data(FFI\CData $data, int $format, int $width, int $height, int $stride)
* @method static int format_stride_for_width(int $format, int $width)
* @method static void show_text(FFI\CData $cr, string $text)
* @method static void surface_flush(FFI\CData $surface)
*/
class Cairo extends CairoConsts {
private static FFI $ffi;
private static bool $started = false;
static function init() {
if (static::$started) {
return;
}
static::$ffi = FFI::load(__DIR__ . "/../headers/cairo.h");
static::$started = true;
}
static function __callStatic($name, $arguments) {
if ( ! static::$started) {
static::init();
}
return static::$ffi->{"cairo_" . $name}(...$arguments);
}
}

@ -0,0 +1,20 @@
<?php
namespace Cijber\GraphicsToolkit\Consts;
class CairoConsts {
const FORMAT_INVALID = -1;
const FORMAT_ARGB32 = 0;
const FORMAT_RGB24 = 1;
const FORMAT_A8 = 2;
const FORMAT_A1 = 3;
const FORMAT_RGB16_565 = 4;
const FORMAT_RGB30 = 5;
const FONT_SLANT_NORMAL = 0;
const FONT_SLANT_ITALIC = 1;
const FONT_SLANT_OBLIQUE = 2;
const FONT_WEIGHT_NORMAL = 0;
const FONT_WEIGHT_BOLD = 1;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,315 @@
<?php
namespace Cijber\GraphicsToolkit\Consts;
class GLFWConsts
{
//region constants
const VERSION_MAJOR = 3;
const VERSION_MINOR = 3;
const VERSION_REVISION = 2;
const TRUE = 1;
const FALSE = 0;
const RELEASE = 0;
const PRESS = 1;
const REPEAT = 2;
const HAT_CENTERED = 0;
const HAT_UP = 1;
const HAT_RIGHT = 2;
const HAT_DOWN = 4;
const HAT_LEFT = 8;
const HAT_RIGHT_UP = (GLFWConsts::HAT_RIGHT | GLFWConsts::HAT_UP);
const HAT_RIGHT_DOWN = (GLFWConsts::HAT_RIGHT | GLFWConsts::HAT_DOWN);
const HAT_LEFT_UP = (GLFWConsts::HAT_LEFT | GLFWConsts::HAT_UP);
const HAT_LEFT_DOWN = (GLFWConsts::HAT_LEFT | GLFWConsts::HAT_DOWN);
const KEY_UNKNOWN = -1;
const KEY_SPACE = 32;
const KEY_APOSTROPHE = 39 /* ' */
;
const KEY_COMMA = 44 /* , */
;
const KEY_MINUS = 45 /* - */
;
const KEY_PERIOD = 46 /* . */
;
const KEY_SLASH = 47 /* / */
;
const KEY_0 = 48;
const KEY_1 = 49;
const KEY_2 = 50;
const KEY_3 = 51;
const KEY_4 = 52;
const KEY_5 = 53;
const KEY_6 = 54;
const KEY_7 = 55;
const KEY_8 = 56;
const KEY_9 = 57;
const KEY_SEMICOLON = 59 /* ; */
;
const KEY_EQUAL = 61 /* = */
;
const KEY_A = 65;
const KEY_B = 66;
const KEY_C = 67;
const KEY_D = 68;
const KEY_E = 69;
const KEY_F = 70;
const KEY_G = 71;
const KEY_H = 72;
const KEY_I = 73;
const KEY_J = 74;
const KEY_K = 75;
const KEY_L = 76;
const KEY_M = 77;
const KEY_N = 78;
const KEY_O = 79;
const KEY_P = 80;
const KEY_Q = 81;
const KEY_R = 82;
const KEY_S = 83;
const KEY_T = 84;
const KEY_U = 85;
const KEY_V = 86;
const KEY_W = 87;
const KEY_X = 88;
const KEY_Y = 89;
const KEY_Z = 90;
const KEY_LEFT_BRACKET = 91 /* [ */
;
const KEY_BACKSLASH = 92 /* \ */
;
const KEY_RIGHT_BRACKET = 93 /* ] */
;
const KEY_GRAVE_ACCENT = 96 /* ` */
;
const KEY_WORLD_1 = 161 /* non-US #1 */
;
const KEY_WORLD_2 = 162 /* non-US #2 */
;
const KEY_ESCAPE = 256;
const KEY_ENTER = 257;
const KEY_TAB = 258;
const KEY_BACKSPACE = 259;
const KEY_INSERT = 260;
const KEY_DELETE = 261;
const KEY_RIGHT = 262;
const KEY_LEFT = 263;
const KEY_DOWN = 264;
const KEY_UP = 265;
const KEY_PAGE_UP = 266;
const KEY_PAGE_DOWN = 267;
const KEY_HOME = 268;
const KEY_END = 269;
const KEY_CAPS_LOCK = 280;
const KEY_SCROLL_LOCK = 281;
const KEY_NUM_LOCK = 282;
const KEY_PRINT_SCREEN = 283;
const KEY_PAUSE = 284;
const KEY_F1 = 290;
const KEY_F2 = 291;
const KEY_F3 = 292;
const KEY_F4 = 293;
const KEY_F5 = 294;
const KEY_F6 = 295;
const KEY_F7 = 296;
const KEY_F8 = 297;
const KEY_F9 = 298;
const KEY_F10 = 299;
const KEY_F11 = 300;
const KEY_F12 = 301;
const KEY_F13 = 302;
const KEY_F14 = 303;
const KEY_F15 = 304;
const KEY_F16 = 305;
const KEY_F17 = 306;
const KEY_F18 = 307;
const KEY_F19 = 308;
const KEY_F20 = 309;
const KEY_F21 = 310;
const KEY_F22 = 311;
const KEY_F23 = 312;
const KEY_F24 = 313;
const KEY_F25 = 314;
const KEY_KP_0 = 320;
const KEY_KP_1 = 321;
const KEY_KP_2 = 322;
const KEY_KP_3 = 323;
const KEY_KP_4 = 324;
const KEY_KP_5 = 325;
const KEY_KP_6 = 326;
const KEY_KP_7 = 327;
const KEY_KP_8 = 328;
const KEY_KP_9 = 329;
const KEY_KP_DECIMAL = 330;
const KEY_KP_DIVIDE = 331;
const KEY_KP_MULTIPLY = 332;
const KEY_KP_SUBTRACT = 333;
const KEY_KP_ADD = 334;
const KEY_KP_ENTER = 335;
const KEY_KP_EQUAL = 336;
const KEY_LEFT_SHIFT = 340;
const KEY_LEFT_CONTROL = 341;
const KEY_LEFT_ALT = 342;
const KEY_LEFT_SUPER = 343;
const KEY_RIGHT_SHIFT = 344;
const KEY_RIGHT_CONTROL = 345;
const KEY_RIGHT_ALT = 346;
const KEY_RIGHT_SUPER = 347;
const KEY_MENU = 348;
const KEY_LAST = GLFWConsts::KEY_MENU;
const MOD_SHIFT = 0x0001;
const MOD_CONTROL = 0x0002;
const MOD_ALT = 0x0004;
const MOD_SUPER = 0x0008;
const MOD_CAPS_LOCK = 0x0010;
const MOD_NUM_LOCK = 0x0020;
const MOUSE_BUTTON_1 = 0;
const MOUSE_BUTTON_2 = 1;
const MOUSE_BUTTON_3 = 2;
const MOUSE_BUTTON_4 = 3;
const MOUSE_BUTTON_5 = 4;
const MOUSE_BUTTON_6 = 5;
const MOUSE_BUTTON_7 = 6;
const MOUSE_BUTTON_8 = 7;
const MOUSE_BUTTON_LAST = GLFWConsts::MOUSE_BUTTON_8;
const MOUSE_BUTTON_LEFT = GLFWConsts::MOUSE_BUTTON_1;
const MOUSE_BUTTON_RIGHT = GLFWConsts::MOUSE_BUTTON_2;
const MOUSE_BUTTON_MIDDLE = GLFWConsts::MOUSE_BUTTON_3;
const JOYSTICK_1 = 0;
const JOYSTICK_2 = 1;
const JOYSTICK_3 = 2;
const JOYSTICK_4 = 3;
const JOYSTICK_5 = 4;
const JOYSTICK_6 = 5;
const JOYSTICK_7 = 6;
const JOYSTICK_8 = 7;
const JOYSTICK_9 = 8;
const JOYSTICK_10 = 9;
const JOYSTICK_11 = 10;
const JOYSTICK_12 = 11;
const JOYSTICK_13 = 12;
const JOYSTICK_14 = 13;
const JOYSTICK_15 = 14;
const JOYSTICK_16 = 15;
const JOYSTICK_LAST = GLFWConsts::JOYSTICK_16;
const GAMEPAD_BUTTON_A = 0;
const GAMEPAD_BUTTON_B = 1;
const GAMEPAD_BUTTON_X = 2;
const GAMEPAD_BUTTON_Y = 3;
const GAMEPAD_BUTTON_LEFT_BUMPER = 4;
const GAMEPAD_BUTTON_RIGHT_BUMPER = 5;
const GAMEPAD_BUTTON_BACK = 6;
const GAMEPAD_BUTTON_START = 7;
const GAMEPAD_BUTTON_GUIDE = 8;
const GAMEPAD_BUTTON_LEFT_THUMB = 9;
const GAMEPAD_BUTTON_RIGHT_THUMB = 10;
const GAMEPAD_BUTTON_DPAD_UP = 11;
const GAMEPAD_BUTTON_DPAD_RIGHT = 12;
const GAMEPAD_BUTTON_DPAD_DOWN = 13;
const GAMEPAD_BUTTON_DPAD_LEFT = 14;
const GAMEPAD_BUTTON_LAST = GLFWConsts::GAMEPAD_BUTTON_DPAD_LEFT;
const GAMEPAD_BUTTON_CROSS = GLFWConsts::GAMEPAD_BUTTON_A;
const GAMEPAD_BUTTON_CIRCLE = GLFWConsts::GAMEPAD_BUTTON_B;
const GAMEPAD_BUTTON_SQUARE = GLFWConsts::GAMEPAD_BUTTON_X;
const GAMEPAD_BUTTON_TRIANGLE = GLFWConsts::GAMEPAD_BUTTON_Y;
const GAMEPAD_AXIS_LEFT_X = 0;
const GAMEPAD_AXIS_LEFT_Y = 1;
const GAMEPAD_AXIS_RIGHT_X = 2;
const GAMEPAD_AXIS_RIGHT_Y = 3;
const GAMEPAD_AXIS_LEFT_TRIGGER = 4;
const GAMEPAD_AXIS_RIGHT_TRIGGER = 5;
const GAMEPAD_AXIS_LAST = GLFWConsts::GAMEPAD_AXIS_RIGHT_TRIGGER;
const NO_ERROR = 0;
const NOT_INITIALIZED = 0x00010001;
const NO_CURRENT_CONTEXT = 0x00010002;
const INVALID_ENUM = 0x00010003;
const INVALID_VALUE = 0x00010004;
const OUT_OF_MEMORY = 0x00010005;
const API_UNAVAILABLE = 0x00010006;
const VERSION_UNAVAILABLE = 0x00010007;
const PLATFORM_ERROR = 0x00010008;
const FORMAT_UNAVAILABLE = 0x00010009;
const NO_WINDOW_CONTEXT = 0x0001000A;
const FOCUSED = 0x00020001;
const ICONIFIED = 0x00020002;
const RESIZABLE = 0x00020003;
const VISIBLE = 0x00020004;
const DECORATED = 0x00020005;
const AUTO_ICONIFY = 0x00020006;
const FLOATING = 0x00020007;
const MAXIMIZED = 0x00020008;
const CENTER_CURSOR = 0x00020009;
const TRANSPARENT_FRAMEBUFFER = 0x0002000A;
const HOVERED = 0x0002000B;
const FOCUS_ON_SHOW = 0x0002000C;
const RED_BITS = 0x00021001;
const GREEN_BITS = 0x00021002;
const BLUE_BITS = 0x00021003;
const ALPHA_BITS = 0x00021004;
const DEPTH_BITS = 0x00021005;
const STENCIL_BITS = 0x00021006;
const ACCUM_RED_BITS = 0x00021007;
const ACCUM_GREEN_BITS = 0x00021008;
const ACCUM_BLUE_BITS = 0x00021009;
const ACCUM_ALPHA_BITS = 0x0002100A;
const AUX_BUFFERS = 0x0002100B;
const STEREO = 0x0002100C;
const SAMPLES = 0x0002100D;
const SRGB_CAPABLE = 0x0002100E;
const REFRESH_RATE = 0x0002100F;
const DOUBLEBUFFER = 0x00021010;
const CLIENT_API = 0x00022001;
const CONTEXT_VERSION_MAJOR = 0x00022002;
const CONTEXT_VERSION_MINOR = 0x00022003;
const CONTEXT_REVISION = 0x00022004;
const CONTEXT_ROBUSTNESS = 0x00022005;
const OPENGL_FORWARD_COMPAT = 0x00022006;
const OPENGL_DEBUG_CONTEXT = 0x00022007;
const OPENGL_PROFILE = 0x00022008;
const CONTEXT_RELEASE_BEHAVIOR = 0x00022009;
const CONTEXT_NO_ERROR = 0x0002200A;
const CONTEXT_CREATION_API = 0x0002200B;
const SCALE_TO_MONITOR = 0x0002200C;
const COCOA_RETINA_FRAMEBUFFER = 0x00023001;
const COCOA_FRAME_NAME = 0x00023002;
const COCOA_GRAPHICS_SWITCHING = 0x00023003;
const X11_CLASS_NAME = 0x00024001;
const X11_INSTANCE_NAME = 0x00024002;
const NO_API = 0;
const OPENGL_API = 0x00030001;
const OPENGL_ES_API = 0x00030002;
const NO_ROBUSTNESS = 0;
const NO_RESET_NOTIFICATION = 0x00031001;
const LOSE_CONTEXT_ON_RESET = 0x00031002;
const OPENGL_ANY_PROFILE = 0;
const OPENGL_CORE_PROFILE = 0x00032001;
const OPENGL_COMPAT_PROFILE = 0x00032002;
const CURSOR = 0x00033001;
const STICKY_KEYS = 0x00033002;
const STICKY_MOUSE_BUTTONS = 0x00033003;
const LOCK_KEY_MODS = 0x00033004;
const RAW_MOUSE_MOTION = 0x00033005;
const CURSOR_NORMAL = 0x00034001;
const CURSOR_HIDDEN = 0x00034002;
const CURSOR_DISABLED = 0x00034003;
const ANY_RELEASE_BEHAVIOR = 0;
const RELEASE_BEHAVIOR_FLUSH = 0x00035001;
const RELEASE_BEHAVIOR_NONE = 0x00035002;
const NATIVE_CONTEXT_API = 0x00036001;
const EGL_CONTEXT_API = 0x00036002;
const OSMESA_CONTEXT_API = 0x00036003;
const ARROW_CURSOR = 0x00036001;
const IBEAM_CURSOR = 0x00036002;
const CROSSHAIR_CURSOR = 0x00036003;
const HAND_CURSOR = 0x00036004;
const HRESIZE_CURSOR = 0x00036005;
const VRESIZE_CURSOR = 0x00036006;
const CONNECTED = 0x00040001;
const DISCONNECTED = 0x00040002;
const JOYSTICK_HAT_BUTTONS = 0x00050001;
const COCOA_CHDIR_RESOURCES = 0x00051001;
const COCOA_MENUBAR = 0x00051002;
const DONT_CARE = -1;
//endregion
}

@ -0,0 +1,308 @@
<?php
/** @noinspection PhpUnused */
namespace Cijber\GraphicsToolkit;
use Cijber\GraphicsToolkit\Consts\GLConsts;
use FFI;
use FFI\CData;
use ReflectionClass;
use ReflectionMethod;
use RuntimeException;
/**
* @method static void bindVertexArray(int $VAO)
* @method static void bindBuffer(int $type, int $VBO)
* @method static void bufferData(int $type, int $size, $data, int $management)
* @method static void viewport(int $x, int $y, int $width, int $height)
* @method static void enableVertexAttribArray(int $VAO)
* @method static void drawArrays(int $type, int $index, int $count)
* @method static void useProgram($shaderProgram)
* @method static void clear(int $type)
* @method static void clearColor(float $red, float $green, float $blue, float $alpha)
* @method static int createShader(int $type)
* @method static void compileShader(int $shader)
* @method static void attachShader(int $program, int $shader)
* @method static int createProgram()
* @method static void linkProgram(int $program)
* @method static void deleteShader(int $shader)
* @method static int getError()
* @method static void enable(int $flag)
* @method static void debugMessageCallback(callable $callback, $userParam)
* @method static void debugMessageControl(int $source, int $type, int $severity, int $count, $null, bool $enabled)
* @method static void blendFunc(int $sfactor, int $bfactor)
*/
class GL extends GLConsts {
public static string $lastCall;
public static FFI $ffi;
/**
* @var array|callable[]
*/
public static array $calls;
/**
* @GLIgnore
*/
public static function init() {
static::$ffi = FFI::load(__DIR__ . "/../headers/gl_generated.h");
$reflection = new ReflectionClass(__CLASS__);
$methods = $reflection->getMethods(
ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_STATIC
);
foreach ($methods as $method) {
if (str_contains($method->getDocComment() ?: "", "@GLIgnore")) {
continue;
}
static::$calls[$method->name] = static::getProcAddress(
$method->name
);
}
preg_match_all(
":@method static [a-zA-Z]+ ([a-zA-Z0-9]+):",
$reflection->getDocComment(),
$matches
);
foreach ($matches[1] as $match) {
static::$calls[$match] = static::getProcAddress($match);
}
}
/**
* @GLIgnore
*/
private static function getProcAddress($name): CData {
$funcname = 'gl' . ucfirst($name);
$typename = 'FUNC_' . $funcname;
$funcstring = static::$ffi->new(FFI::arrayType(static::$ffi->type('GLubyte'), [strlen($funcname) + 1]));
FFI::memcpy($funcstring, $funcname, strlen($funcname));
$funcstring[strlen($funcname)] = "\0";
/** @var CData $proc */
/** @noinspection PhpUndefinedMethodInspection */
$proc = static::$ffi->glXGetProcAddress(
static::$ffi->cast("GLubyte*", $funcstring)
);
/** @noinspection PhpUndefinedMethodInspection */
if ($proc === null || FFI::isNull($proc)) {
throw new RuntimeException("GL function $name doesn't exist");
}
return static::$ffi->cast($typename, $proc);
}
public static function genBuffers(int $amount, &$ids) {
if ($amount > 1) {
$ids = array_fill(0, $amount, 0);
}
if (is_array($ids)) {
$arr = &$ids;
} else {
$arr = [&$ids];
}
$items = static::$ffi->new("GLuint[$amount]");
(static::$calls['genBuffers'])($amount, $items);
for ($i = 0; $i < $amount; $i++) {
$arr[$i] = $items[$i];
}
}
public static function genVertexArrays(int $amount, &$ids) {
if ($amount > 1) {
$ids = array_fill(0, $amount, 0);
}
if (is_array($ids)) {
$arr = &$ids;
} else {
$arr = [&$ids];
}
$items = static::$ffi->new("GLuint[$amount]");
(static::$calls['genVertexArrays'])($amount, $items);
for ($i = 0; $i < $amount; $i++) {
$arr[$i] = $items[$i];
}
}
public static function genTextures(int $amount, &$ids) {
if ($amount > 1) {
$ids = array_fill(0, $amount, 0);
}
if (is_array($ids)) {
$arr = &$ids;
} else {
$arr = [&$ids];
}
$items = static::$ffi->new("GLuint[$amount]");
(static::$calls['genTextures'])($amount, $items);
for ($i = 0; $i < $amount; $i++) {
$arr[$i] = $items[$i];
}
}
/**
* @GLIgnore
*/
public static function __callStatic($name, $arguments) {
if ( ! isset(static::$calls[$name])) {
static::$calls[$name] = static::getProcAddress($name);
}
static::$lastCall = $name;
return (static::$calls[$name])(...$arguments);
}
public static function vertexAttribPointer(
int $index,
int $size,
int $type,
bool $normalized,
int $stride,
int $pointer
) {
$pointerC = static::$ffi->new('long long');
$pointerC->cdata = $pointer;
$p = static::$ffi->cast(
'void*',
$pointerC
);
(static::$calls['vertexAttribPointer'])(
$index,
$size,
$type,
$normalized ? 1 : 0,
$stride,
$p,
);
}
public static function getShaderiv(
int $shader,
int $type,
&$params
) {
$paramsC = static::$ffi->new('GLint');
(static::$calls['getShaderiv'])(
$shader,
$type,
FFI::addr($paramsC)
);
$params = $paramsC->cdata;
}
public static function getProgramiv(
int $program,
int $type,
&$params
) {
$paramsC = static::$ffi->new('GLint');
(static::$calls['getProgramiv'])(
$program,
$type,
FFI::addr($paramsC)
);
$params = $paramsC->cdata;
}
public static function getProgramInfoLog(
int $program,
&$log,
int $maxLength = 512
) {
$logC = static::$ffi->new("char[$maxLength]");
$actualLength = static::$ffi->new("GLsizei");
(static::$calls['getProgramInfoLog'])(
$program,
$maxLength,
FFI::addr($actualLength),
$logC,
);
$log = FFI::string($logC, $actualLength->cdata);
}
public static function getShaderInfoLog(
int $shader,
null|string &$log = null,
int $maxLength = 512
) {
$logC = static::$ffi->new(FFI::arrayType(FFI::type("char"), [$maxLength]));
$actualLength = static::$ffi->new("GLsizei");
(static::$calls['getShaderInfoLog'])(
$shader,
$maxLength,
FFI::addr($actualLength),
$logC,
);
$log = FFI::string($logC, $actualLength->cdata);
}
public static function shaderSource(
int $shader,
int $count,
string $source,
?array $offsets
) {
$item = null;
if (is_array($offsets) && count($offsets) > 0) {
$item = static::$ffi->new('GLint[' . count($offsets) . ']');
for ($i = 0; $i < count($offsets); $i++) {
$item[$i] = $offsets[$i];
}
}
$sourceConst = Utils::constString($source . "\0");
(static::$calls['shaderSource'])(
$shader,
$count,
FFI::addr($sourceConst),
$item,
);
}
/**
* @GLIgnore
*/
public static function getInteger(int $item): int {
return static::getIntegerv($item)[0];
}
public static function getIntegerv(int $item, int $values = 1): array {
$t = static::$ffi->new(FFI::arrayType(static::$ffi->type("GLint"), [$values]));
(static::$calls['getIntegerv'])($item, $t);
$arr = [];
for ($i = 0; $i < $values; $i++) {
$arr[$i] = $t[$i];
}
return $arr;
}
}

@ -0,0 +1,43 @@
<?php
/** @noinspection PhpUnused */
namespace Cijber\GraphicsToolkit;
use Cijber\GraphicsToolkit\Consts\GLFWConsts;
use FFI;
/**
* @method static void windowHint(int $hint, int $hintValue)
* @method static FFI\CData createWindow(int $width, int $height, string $title, $window, $screen)
* @method static void makeContextCurrent($window)
* @method static int windowShouldClose($window)
* @method static void swapBuffers($window)
* @method static void pollEvents()
* @method static void terminate()
* @method static int setWindowShouldClose(FFI\CData $window, int $shouldClose)
* @method static int getKey(FFI\CData $window, int $key)
* @method static void setFramebufferSizeCallback(FFI\CData $window, \Closure $callback)
*/
class GLFW extends GLFWConsts
{
private static FFI $ffi;
private static bool $started = false;
static function init()
{
if (static::$started) {
return;
}
static::$ffi = FFI::load(__DIR__."/../headers/glfw.h");
/** @noinspection PhpUndefinedMethodInspection */
static::$ffi->glfwInit();
static::$started = true;
}
static function __callStatic($name, $arguments)
{
return static::$ffi->{"glfw".ucfirst($name)}(...$arguments);
}
}

@ -0,0 +1,80 @@
<?php
namespace Cijber\GraphicsToolkit;
use FFI;
class Utils {
static $ffi;
private static ?FFI\CData $null;
static function ffi(): FFI {
if (static::$ffi === null) {
static::$ffi = FFI::cdef("");
}
return static::$ffi;
}
static function arrayOf($type, $items): FFI\CData {
$ffi = static::ffi();
$items = array_values($items);
if (is_string($type)) {
$type = $ffi->type($type);
}
$arrType = FFI::arrayType($type, [count($items)]);
$arr = $ffi->new($arrType);
for ($i = 0; $i < count($items); $i++) {
$arr[$i] = $items[$i];
}
return $arr;
}
public static function string(string $input): FFI\CData {
$ffi = static::ffi();
$data = $ffi->new('char[' . strlen($input) . ']');
for ($i = 0; $i < strlen($input); $i++) {
$data[$i] = $input[$i];
}
return $data;
}
public static function constString(string $input): FFI\CData {
$ffi = static::ffi();
$data = $ffi->new('char[' . strlen($input) . ']', false);
for ($i = 0; $i < strlen($input); $i++) {
$data[$i] = $input[$i];
}
return $ffi->cast('const char*', $data);
}
public static function sizeOf($type): int {
$ffi = static::ffi();
if (is_string($type)) {
$type = $ffi->type($type);
}
return FFI::sizeof($type);
}
public static function null(): FFI\CData {
if (static::$null === null) {
$val = FFI::new("usize");
$val->cdata = 0;
static::$null = FFI::cast('void *', $val);
}
return static::$null;
}
}
Loading…
Cancel
Save