Skip to content

Instantly share code, notes, and snippets.

@RobotixBC
Created March 8, 2023 10:18
Show Gist options
  • Save RobotixBC/91d68aea6a6557f04ace1ef335df9e74 to your computer and use it in GitHub Desktop.
Save RobotixBC/91d68aea6a6557f04ace1ef335df9e74 to your computer and use it in GitHub Desktop.
EGL + RLGL standalone
// EGL based off https://gist.github.com/dcommander/ee1247362201552b2532/
/*
* Copyright (C)2015, 2019 D. R. Commander. All Rights Reserved.
* Copyright (C)2002 Brian Paul. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <EGL/egl.h>
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/eglext.h>
#include <GL/gl.h>
#include "math.h"
namespace rl
{
#include "raylib.h"
#include "rlgl.h"
#include "raymath.h"
}
static const char *eglErrorString(EGLint error)
{
switch (error)
{
case EGL_SUCCESS:
return "Success";
case EGL_NOT_INITIALIZED:
return "EGL is not or could not be initialized";
case EGL_BAD_ACCESS:
return "EGL cannot access a requested resource";
case EGL_BAD_ALLOC:
return "EGL failed to allocate resources for the requested operation";
case EGL_BAD_ATTRIBUTE:
return "An unrecognized attribute or attribute value was passed in the attribute list";
case EGL_BAD_CONTEXT:
return "An EGLContext argument does not name a valid EGL rendering context";
case EGL_BAD_CONFIG:
return "An EGLConfig argument does not name a valid EGL frame buffer configuration";
case EGL_BAD_CURRENT_SURFACE:
return "The current surface of the calling thread is a window, pixel buffer or pixmap that is no longer valid";
case EGL_BAD_DISPLAY:
return "An EGLDisplay argument does not name a valid EGL display connection";
case EGL_BAD_SURFACE:
return "An EGLSurface argument does not name a valid surface configured for GL rendering";
case EGL_BAD_MATCH:
return "Arguments are inconsistent";
case EGL_BAD_PARAMETER:
return "One or more argument values are invalid";
case EGL_BAD_NATIVE_PIXMAP:
return "A NativePixmapType argument does not refer to a valid native pixmap";
case EGL_BAD_NATIVE_WINDOW:
return "A NativeWindowType argument does not refer to a valid native window";
case EGL_CONTEXT_LOST:
return "The application must destroy all contexts and reinitialise";
}
return "UNKNOWN EGL ERROR";
}
#define THROW(m) \
{ \
ret = -1; \
fprintf(stderr, "ERROR in line %d: %s\n", __LINE__, m); \
return -1; \
}
#define THROWEGL() THROW(eglErrorString(eglGetError()))
PFNEGLQUERYDEVICESEXTPROC _eglQueryDevicesEXT = NULL;
PFNEGLQUERYDEVICESTRINGEXTPROC _eglQueryDeviceStringEXT = NULL;
PFNEGLGETPLATFORMDISPLAYEXTPROC _eglGetPlatformDisplayEXT = NULL;
#define MAX_INSTANCES 1000
int main(void)
{
int width = 640;
int height = 480;
int num_devices = 0, i;
EGLDeviceEXT *devices = NULL;
EGLDisplay dpy = NULL;
EGLConfig *configs = NULL;
int major, minor, ret = 0, nc = 0;
EGLSurface pb = 0;
EGLContext ctx = 0;
unsigned char *pixels = NULL;
if ((_eglQueryDevicesEXT =
(PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT")) == NULL)
THROW("eglQueryDevicesEXT() could not be loaded");
if ((_eglQueryDeviceStringEXT =
(PFNEGLQUERYDEVICESTRINGEXTPROC)eglGetProcAddress("eglQueryDeviceStringEXT")) == NULL)
THROW("eglQueryDeviceStringEXT() could not be loaded");
if ((_eglGetPlatformDisplayEXT =
(PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT")) == NULL)
THROW("eglGetPlatformDisplayEXT() could not be loaded");
if (!_eglQueryDevicesEXT(0, NULL, &num_devices) || num_devices < 1)
THROWEGL();
if ((devices = (EGLDeviceEXT *)malloc(sizeof(EGLDeviceEXT) * num_devices)) == NULL)
THROW("Memory allocation failure");
if (!_eglQueryDevicesEXT(num_devices, devices, &num_devices) || num_devices < 1)
THROWEGL();
for (i = 0; i < num_devices; i++)
{
const char *devstr = _eglQueryDeviceStringEXT(devices[i], EGL_DRM_DEVICE_FILE_EXT);
printf("Device 0x%.8lx: %s\n", (unsigned long)devices[i], devstr ? devstr : "NULL");
}
// PICK DEVICE HERE ------------------------------------------------------------- DEVICE
if ((dpy = _eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, devices[0], NULL)) == NULL)
THROWEGL();
if (!eglInitialize(dpy, &major, &minor))
THROWEGL();
printf("EGL version %d.%d\n", major, minor);
int attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_NONE};
if (!eglChooseConfig(dpy, attribs, NULL, 0, &nc) || nc < 1)
THROWEGL();
if ((configs = (EGLConfig *)malloc(sizeof(EGLConfig) * nc)) == NULL)
THROW("Memory allocation failure");
if (!eglChooseConfig(dpy, attribs, configs, nc, &nc) || nc < 1)
THROWEGL();
int pbattribs[] = {
EGL_WIDTH, width,
EGL_HEIGHT, height,
EGL_NONE};
if ((pb = eglCreatePbufferSurface(dpy, configs[0], pbattribs)) == NULL)
THROWEGL();
if (!eglBindAPI(EGL_OPENGL_API))
THROWEGL();
EGLint ctx_attr[] = {
EGL_CONTEXT_MAJOR_VERSION, 3,
EGL_CONTEXT_MINOR_VERSION, 3,
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
EGL_NONE};
if ((ctx = eglCreateContext(dpy, configs[0], NULL, ctx_attr)) == NULL)
THROWEGL();
if (!eglMakeCurrent(dpy, pb, pb, ctx))
THROWEGL();
rl::rlLoadExtensions((void *)eglGetProcAddress);
rl::rlglInit(width, height);
rl::rlClearColor(200, 200, 200, 255);
rl::rlEnableDepthTest();
rl::Camera camera;
camera.position = (rl::Vector3){10.0f, 10.0f, 10.0f}; // Camera position
camera.target = (rl::Vector3){0.0f, 0.0f, 0.0f}; // Camera looking at point
camera.up = (rl::Vector3){0.0f, 1.0f, 0.0f}; // Camera up vector (rotation towards target)
camera.fovy = 45.0f;
rl::Model test_model;
rl::Matrix test_trans[4];
// Define transforms to be uploaded to GPU for instances
rl::Matrix *transforms = new rl::Matrix[MAX_INSTANCES]; // Pre-multiplied transformations passed to rlgl
rl::rlClearScreenBuffers();
// load default model / mat
test_model = rl::LoadModel("bs/path.obj");
test_model.materials[0].maps[rl::MATERIAL_MAP_DIFFUSE].color = rl::GOLD;
// Translate and rotate cubes randomly
for (int i = 0; i < MAX_INSTANCES; i++)
{
rl::Matrix translation = rl::MatrixTranslate((float)rl::GetRandomValue(-50, 50), (float)rl::GetRandomValue(-50, 50), (float)rl::GetRandomValue(-50, 50));
rl::Vector3 axis = rl::Vector3Normalize((rl::Vector3){(float)rl::GetRandomValue(0, 360), (float)rl::GetRandomValue(0, 360), (float)rl::GetRandomValue(0, 360)});
float angle = (float)rl::GetRandomValue(0, 10) * DEG2RAD;
rl::Matrix rotation = rl::MatrixRotate(axis, angle);
transforms[i] = rl::MatrixMultiply(rotation, translation);
}
test_trans[0] = rl::MatrixIdentity();
test_trans[1] = rl::MatrixTranslate(3, 0, 0);
test_trans[2] = rl::MatrixTranslate(6, 0, 0);
test_trans[3] = rl::MatrixTranslate(9, 0, 0);
{ // draw 3D stuff
rl::Matrix matProj = rl::MatrixPerspective((double)(camera.fovy * DEG2RAD), (double)width / (double)height, 0.01, 1000.0);
rl::Matrix matView = rl::MatrixLookAt(camera.position, camera.target, camera.up);
rl::rlSetMatrixModelview(matView); // Set internal modelview matrix (default shader)
rl::rlSetMatrixProjection(matProj); // Set internal projection matrix (default shader)
rl::DrawGrid(10, 1);
// rl::DrawCube({0, 2, 0}, 1, 1, 1, rl::PURPLE);
rl::DrawCube({0, 0, 0}, 0.5, 0.2, 2, rl::RED);
rl::DrawCube({1, 0, 0}, 0.6, 0.5, 0.5, rl::GREEN);
rl::DrawCube({2, 0, 0}, 0.7, 0.3, 0.3, rl::BLUE);
// rl::DrawCircle3D({3, 0, 0}, 0.5, {0, 1, 0}, 0, rl::PURPLE);
rl::DrawCircle3D({3, 0, 0}, 0.5, {0, 1, 0}, 90, rl::BLACK);
// OK
rl::DrawModel(test_model, {2,0,2}, 0.5, rl::WHITE);
// rl::DrawMesh(test_model.meshes[0], test_model.materials[0], test_trans[0]);
// rl::DrawMesh(test_model.meshes[0], test_model.materials[0], test_trans[1]);
// rl::DrawMesh(test_model.meshes[0], test_model.materials[0], test_trans[2]);
// rl::DrawMesh(test_model.meshes[0], test_model.materials[0], test_trans[3]);
// NOK
rl::DrawMeshInstanced(test_model.meshes[0], test_model.materials[0], test_trans, 4);
// rl::DrawMeshInstanced(test_model.meshes[0], test_model.materials[0], transforms, MAX_INSTANCES);
rl::rlDrawRenderBatchActive();
}
{ // draw 2D stuff
rlSetMatrixModelview(rl::MatrixIdentity()); // Set internal modelview matrix (default shader)
rlSetMatrixProjection(rl::MatrixOrtho(0.0, width, height, 0.0, 0.0, 1.0)); // Set internal projection matrix (default shader)
rl::DrawRectangle(0, 0, 30, 30, rl::RED);
rl::DrawRectangle(0, 50, 30, 30, rl::BLUE);
rl::rlDrawRenderBatchActive();
}
pixels = (unsigned char *)malloc(width * height * 4);
pixels = rl::rlReadScreenPixels(width, height);
rl::Image tmp;
tmp.data = pixels;
tmp.width = width;
tmp.height = height;
tmp.format = rl::PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
rl::ExportImage(tmp, "texture_export.png");
// bailout:
if (pixels)
free(pixels);
if (ctx && dpy)
eglDestroyContext(dpy, ctx);
if (pb && dpy)
eglDestroySurface(dpy, pb);
if (dpy)
eglTerminate(dpy);
if (configs)
free(configs);
if (devices)
free(devices);
return ret;
}
all: egltest
egltest: egltest.cpp
g++ -Wno-unused-variable -DDEBUG -g -O3 -Wall -Werror -I. -I../raylib-4.2.0/src -I/usr/include/libdrm -o $@ $^ -lOpenGL -lEGL -ldrm -lgbm -L../raylib-4.2.0/src -lraylib -lGL -lopenal -lm -lpthread -ldl -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor -lGLEW -lGLU
clean:
rm -f *.o egltest
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment