You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
8.1 KiB
PHP
309 lines
8.1 KiB
PHP
<?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;
|
|
}
|
|
}
|