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