Initial commit
commit
1f3881bdc4
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
@ -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…
Reference in New Issue