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

<?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;
}