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.
329 lines
9.8 KiB
PHP
329 lines
9.8 KiB
PHP
<?php
|
|
|
|
use Cijber\GraphicsToolkit\Cairo;
|
|
use Cijber\GraphicsToolkit\GL;
|
|
use Cijber\GraphicsToolkit\GLFW;
|
|
use Cijber\GraphicsToolkit\Utils;
|
|
|
|
|
|
set_error_handler(function($severity, $message, $file, $line) {
|
|
global $error;
|
|
$error = new RuntimeException("$severity: $message [$file($line)]");
|
|
Fiber::suspend();
|
|
});
|
|
|
|
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";
|
|
glViewport(0, 0, $viewportWidth = $width, $viewportHeight = $height);
|
|
}
|
|
);
|
|
|
|
glViewport(0, 0, 800, 600);
|
|
|
|
glDebugMessageCallback(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, "call" => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)[2]]);
|
|
}, null);
|
|
|
|
// glDebugMessageCallback($callback, null);
|
|
|
|
glEnable(GL::DEBUG_OUTPUT);
|
|
glEnable(GL::DEBUG_OUTPUT_SYNCHRONOUS);
|
|
|
|
glEnable(GL::BLEND);
|
|
|
|
// glEnable(GL::BLEND);
|
|
glBlendFunc(GL::SRC_ALPHA, GL::ONE_MINUS_SRC_ALPHA);
|
|
|
|
$vertexShader = \glCreateShader(GL::VERTEX_SHADER);
|
|
$vertexShaderSource = file_get_contents(__DIR__ . "/../shaders/vertex.glsl");
|
|
|
|
GL::shaderSource($vertexShader, [$vertexShaderSource]);
|
|
|
|
glCompileShader($vertexShader);
|
|
glGetShaderiv($vertexShader, GL::COMPILE_STATUS, Utils::pointer($success, "int32_t"));
|
|
|
|
if ( ! $success->cdata) {
|
|
glGetShaderiv($vertexShader, GL::INFO_LOG_LENGTH, Utils::pointer($logLength, "int32_t"));
|
|
glGetShaderInfoLog($vertexShader, $logLength, Utils::null(), Utils::stringBuffer($infoLog, $logLength->cdata));
|
|
die("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n\t$infoLog");
|
|
}
|
|
|
|
|
|
$fragmentShader = glCreateShader(GL::FRAGMENT_SHADER);
|
|
$fragmentShaderSource = file_get_contents(
|
|
__DIR__ . "/../shaders/fragment.glsl"
|
|
);
|
|
|
|
GL::shaderSource($fragmentShader, [$fragmentShaderSource]);
|
|
glCompileShader($fragmentShader);
|
|
glGetShaderiv($fragmentShader, GL::COMPILE_STATUS, FFI::addr($success));
|
|
|
|
if ( ! $success->cdata) {
|
|
glGetShaderiv($fragmentShader, GL::INFO_LOG_LENGTH, Utils::pointer($logLength, "int32_t"));
|
|
glGetShaderInfoLog($fragmentShader, $logLength->cdata, Utils::pointer($result, 'int32_t'), Utils::stringBuffer($infoLog, $logLength->cdata));
|
|
$infoLog = FFI::string($infoLog, $result->cdata);
|
|
die("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n\t{$infoLog}");
|
|
}
|
|
|
|
$shaderProgram = glCreateProgram();
|
|
glAttachShader($shaderProgram, $vertexShader);
|
|
glAttachShader($shaderProgram, $fragmentShader);
|
|
glLinkProgram($shaderProgram);
|
|
|
|
glDeleteShader($vertexShader);
|
|
glDeleteShader($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);
|
|
glGenVertexArrays(1, Utils::pointer($VAO, 'uint32_t'));
|
|
glGenBuffers(1, Utils::pointer($VBO, 'uint32_t'));
|
|
$VAO = $VAO->cdata;
|
|
$VBO = $VBO->cdata;
|
|
|
|
glBindVertexArray($VAO);
|
|
glBindBuffer(GL::ARRAY_BUFFER, $VBO);
|
|
glBufferData(
|
|
GL::ARRAY_BUFFER,
|
|
FFI::sizeof($float),
|
|
$float,
|
|
GL::STATIC_DRAW
|
|
);
|
|
|
|
glVertexAttribPointer(
|
|
0,
|
|
3,
|
|
GL::FLOAT,
|
|
false,
|
|
12,
|
|
0
|
|
);
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
glBindBuffer(GL::ARRAY_BUFFER, 0);
|
|
glBindVertexArray(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);
|
|
|
|
glGenTextures(1, Utils::pointer($texture, "uint32_t"));
|
|
$texture = $texture->cdata;
|
|
glBindTexture(GL::TEXTURE_2D, $texture);
|
|
|
|
glTexParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_S, GL::REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)
|
|
glTexParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_T, GL::REPEAT);
|
|
// set texture filtering parameters
|
|
glTexParameteri(GL::TEXTURE_2D, GL::TEXTURE_MIN_FILTER, GL::LINEAR);
|
|
glTexParameteri(GL::TEXTURE_2D, GL::TEXTURE_MAG_FILTER, GL::LINEAR);
|
|
|
|
glTexImage2D(GL::TEXTURE_2D, 0, GL::RGBA, 400, 400, 0, GL::BGRA, GL::UNSIGNED_BYTE, $textureData);
|
|
|
|
$vertexShader = glCreateShader(GL::VERTEX_SHADER);
|
|
$vertexShaderSource = file_get_contents(__DIR__ . "/../shaders/sq_vertex_shader.glsl");
|
|
|
|
GL::shaderSource($vertexShader, [$vertexShaderSource]);
|
|
|
|
glCompileShader($vertexShader);
|
|
glGetShaderiv($vertexShader, GL::COMPILE_STATUS, Utils::pointer($success, 'int32_t'));
|
|
|
|
if ( ! $success->cdata) {
|
|
glGetShaderiv($vertexShader, GL::INFO_LOG_LENGTH, Utils::pointer($logLength, "int32_t"));
|
|
glGetShaderInfoLog($vertexShader, $logLength, Utils::null(), Utils::stringBuffer($infoLog, $logLength->cdata));
|
|
die("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n\t$infoLog");
|
|
}
|
|
|
|
|
|
$fragmentShader = glCreateShader(GL::FRAGMENT_SHADER);
|
|
$fragmentShaderSource = file_get_contents(
|
|
__DIR__ . "/../shaders/sq_fragment_shader.glsl"
|
|
);
|
|
|
|
GL::shaderSource($fragmentShader, [$fragmentShaderSource]);
|
|
glCompileShader($fragmentShader);
|
|
glGetShaderiv($fragmentShader, GL::COMPILE_STATUS, FFI::addr($success));
|
|
|
|
|
|
if ( ! $success->cdata) {
|
|
glGetShaderiv($fragmentShader, GL::INFO_LOG_LENGTH, Utils::pointer($logLength, "int32_t"));
|
|
glGetShaderInfoLog($fragmentShader, $logLength->cdata, Utils::pointer($result, 'int32_t'), Utils::stringBuffer($infoLog, $logLength->cdata));
|
|
$infoLog = FFI::string($infoLog, $result->cdata);
|
|
die("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n\t{$infoLog}");
|
|
}
|
|
|
|
$squareProgram = glCreateProgram();
|
|
glAttachShader($squareProgram, $vertexShader);
|
|
glAttachShader($squareProgram, $fragmentShader);
|
|
glLinkProgram($squareProgram);
|
|
|
|
glDeleteShader($vertexShader);
|
|
glDeleteShader($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);
|
|
glGenVertexArrays(1, Utils::pointer($SQUARE_VAO, 'uint32_t'));
|
|
$SQUARE_VAO = $SQUARE_VAO->cdata;
|
|
glGenBuffers(1, Utils::pointer($VBO, 'uint32_t'));
|
|
$VBO = $VBO->cdata;
|
|
glGenBuffers(1, Utils::pointer($EBO, 'uint32_t'));
|
|
$EBO = $EBO->cdata;
|
|
|
|
glBindVertexArray($SQUARE_VAO);
|
|
|
|
|
|
glBindBuffer(GL::ARRAY_BUFFER, $VBO);
|
|
glBufferData(
|
|
GL::ARRAY_BUFFER,
|
|
FFI::sizeof($float),
|
|
$float,
|
|
GL::STATIC_DRAW
|
|
);
|
|
|
|
$indices = Utils::arrayOf("unsigned int", [0, 1, 3, 1, 2, 3]);
|
|
glBindBuffer(GL::ELEMENT_ARRAY_BUFFER, $EBO);
|
|
glBufferData(
|
|
GL::ELEMENT_ARRAY_BUFFER,
|
|
FFI::sizeof($indices),
|
|
$indices,
|
|
GL::STATIC_DRAW,
|
|
);
|
|
|
|
glVertexAttribPointer(0, 3, GL::FLOAT, 0, 8 * 4, 0);
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(1, 3, GL::FLOAT, 0, 8 * 4, 3 * 4);
|
|
glEnableVertexAttribArray(1);
|
|
glVertexAttribPointer(2, 2, GL::FLOAT, 0, 8 * 4, 6 * 4);
|
|
glEnableVertexAttribArray(2);
|
|
|
|
glUseProgram($squareProgram);
|
|
$location = glGetUniformLocation($squareProgram, "ourTexture");
|
|
glUniform1i($location, 0);
|
|
$viewportSizeLocation = glGetUniformLocation($squareProgram, "viewportSize");
|
|
|
|
while ( ! GLFW::windowShouldClose($window)) {
|
|
processInput($window);
|
|
|
|
glClearColor(0.2, 0.3, 0.3, 1.0);
|
|
glClear(GL::COLOR_BUFFER_BIT);
|
|
|
|
glUseProgram($squareProgram);
|
|
|
|
glActiveTexture(GL::TEXTURE0);
|
|
glBindTexture(GL::TEXTURE_2D, $texture);
|
|
|
|
glBindVertexArray($VAO);
|
|
glDrawArrays(GL::TRIANGLES, 0, 3);
|
|
|
|
glActiveTexture(GL::TEXTURE0);
|
|
glBindTexture(GL::TEXTURE_2D, $texture);
|
|
|
|
glUseProgram($squareProgram);
|
|
glUniform2i($viewportSizeLocation, $viewportWidth, $viewportHeight);
|
|
glBindVertexArray($SQUARE_VAO);
|
|
|
|
glDrawElements(GL::TRIANGLES, 6, GL::UNSIGNED_INT, 0);
|
|
|
|
GLFW::pollEvents();
|
|
GLFW::swapBuffers($window);
|
|
}
|
|
|
|
GLFW::terminate();
|
|
}
|
|
|
|
function processInput($window) {
|
|
if (GLFW::getKey($window, GLFW::KEY_ESCAPE) === GLFW::PRESS) {
|
|
GLFW::setWindowShouldClose($window, 1);
|
|
}
|
|
}
|
|
|
|
global $error;
|
|
$error = null;
|
|
$fiber = new Fiber(fn() => main());
|
|
$fiber->start();
|
|
|
|
if ($error !== null) {
|
|
throw $error;
|
|
}
|