Giter VIP home page Giter VIP logo

rswinkle / portablegl Goto Github PK

View Code? Open in Web Editor NEW
1.0K 18.0 48.0 28.13 MB

An implementation of OpenGL 3.x-ish in clean C

License: MIT License

C++ 20.15% C 78.99% Lua 0.09% Python 0.32% Makefile 0.43% Shell 0.03%
opengl graphics rendering software-renderer 3d single-header-library software-rendering 3d-graphics computer-graphics rasterization rasterizer rendering-pipeline shader shaders tutorial renderer

portablegl's Introduction

PortableGL

"Because of the nature of Moore's law, anything that an extremely clever graphics programmer can do at one point can be replicated by a merely competent programmer some number of years later." -John Carmack

In a nutshell, PortableGL is an implementation of OpenGL 3.x core (mostly; see GL Version) in clean C99 as a single header library (in the style of the stb libraries). This means it compiles cleanly as C++ and can be easily added to almost any codebase.

It can theoretically be used with anything that takes a framebuffer/texture as input (including just writing images to disk manually or using something like stb_image_write) but all the demos use SDL2 and it currently only supports 8-bits per channel RGBA as a target (and also for textures).

Its goals are, roughly in order of priority,

  1. Portability
  2. Matching the API within reason, at the least matching features/abilities
  3. Ease of Use
  4. Straightforward code
  5. Speed

Obviously there are trade-offs between several of those. An example where 4 trumps 2 (and arguably 3) is with shaders. Rather than write or include a GLSL parser and have a built in compiler or interpreter, shaders are special C/C++ functions that match a specific prototype. Uniforms are another example where 3 and 4 beat 2 because it made no sense to match the API because we can do things so much simpler by passing a pointer to a user defined struct (see the examples).

What PortableGL Is Not

It is not a drop in replacement for libGL the way Mesa and some other software rendering libraries are. Porting a real OpenGL program to PGL will require some code changes, though depending on the program that could be as little as a couple dozen lines or so. In many cases the biggest changes required have nothing to do with PGL vs OpenGL directly, but having to change the windowing system. If you want to use PGL for full window software rendering you need a system that supports blitting raw pixels to the screen. Libraries like GLFW which are designed to be used with real OpenGL do not have that capability because everything is done through the OpenGL context. There is some talk of adding some kind of support for real software rendering but I don't see it going anywhere because it just doesn't make sense for GLFW's goals. SDL is great but it is a rather large dependency that links dozens of external libraries. So what else is out there? I've seen many lighter windowing/input libraries out there that wrap platform specific toolkits that would work, most recently RGFW which recently added a PGL example.

Download

Get the source from Github.

You can also install it via Homebrew.

Gallery

gears sphereworld backpack craft

The last is a PortableGL port of Michael Fogleman's Craft.

See the demos README.md for more screenshots, or look in the screenshots directory.

History

PortableGL started as a very simple wireframe software renderer based on a tutorial in summer 2011. I kept playing with it, adding minor features over the next year, until in early 2013 I decided I should turn it into a software implementation of OpenGL. This would save me a huge amount of time and energy on API design since I'd just be implementing an existing good API (though some disagree) and also make the project more useful both to me and potentially others. Also, at the time Mesa3D was still years away from full 3.x support, not that I'm really competing, and the fact that there was no finished implementation was a little motivating. I made a lot of progress that year and had a few bursts here and there since, but once I got it mostly working, I was less motivated and when I did work on it I spent my time on creating new demos/examples and tweaking or fixing minor things. I could have released an MVP back in 2014 at the earliest but late 2016 would have been the best compromise. Anyway, after several thousand hours spread out over more than 10 years, it is as you see it today. Software is never finished, and I'll be the first to admit PortableGL could use more polish.

Why

Aside from the fact that I just wrote it for fun and because I thought it was cool (maybe others will too), I can think of a few semi-practical purposes.

Educational

I took a 400 level 3D Graphics course in college in fall 2010 months after OpenGL 3.3/4.0 was released. It was taught based on the original Red Book using OpenGL 1.1. Fortunately, the professor let me use OpenGL 3.3 as long as I met the assignment requirements. Sadly, college graphics professors still teach 1.x and 2.x OpenGL today in 2022 more commonly than 3.x/4.x (or Vulkan). A few are using WebGL 2.0 which I kind of consider 1 step forward, 2 steps back.

While Vulkan is the newest thing (already 5 years old time flies), it really is overkill for learning 3D graphics. There is rarely anything that students make in your standard intro to 3D graphics that remotely stresses the performance of any laptop built in the last decade plus. Using modern OpenGL (ie 3.3+ core profile) to introduce all the standard concepts, vertices, triangles, textures, shaders, fragments/pixels, the transformation pipeline etc. first is much better than trying to teach them Vulkan and graphics at the same time, and obviously better than teaching OpenGL API's that are decades old.

PortableGL could be a very convenient base for such a class. It's easy to walk through the code and see the pipeline and how all the steps flow together. For more advanced classes or graduate students in a shared class, modifying PortableGL in some way would be a good project. It could be some optimization or algorithm, maybe a new feature. Theoretically it could be used as starter code for actual research into new graphics algorithms or techniques because it's such a convenient small foundation to change and share, vs trying to modify a project the size and complexity of Mesa3D or create a software renderer from scratch.

Special Cases

It's hard to imagine any hardware today that has a CPU capable of running software rendered 3D graphics at any respectable speed (especially with full IEEE floating point) that doesn't also have some kind of dedicated GPU. The GPU might only support OpenGL 2.0 give or take but for performance it'd be better to stick to whatever the hardware supported than use PortableGL. However, theoretically, there could be some platform somewhere where the CPU is relatively powerful that doesn't have a GPU. Maybe some of the current and future RISC SoC's for example? In such a case PortableGL might be a useful alternative to Mesa3D or similar.

Another special case is hobby OS's. The hardware they run on might have a GPU but it might be impossible or more trouble than it's worth to get Mesa3D to run on some systems. If they have a C99 compliant compiler and standard library, they could use PortableGL to get at least some OpenGL-ish 3D support.

Why C

I recently came across a comment regarding PortableGL that essentially asked, "why implement a dead technology in a dying language?"

While I would argue that OpenGL is far from dead and C isn't even close to dying, there are many good reasons to write a library in C.

Here are a few libraries written in C, along with some links to their reasoning:

If you read through any of those you may have noticed a pattern. Choosing to write a library in the C++-clean subset of C gives you automatic C/C++ support, the most portability across platforms, the easiest integration into other projects, and the easiest bindings to other languages. Keeping the library small with few or no dependencies only enhances all those benefits and makes it even easier to use.

All that said, if I were ever going to actually write a real/large 3D application or game I would probably use C++ for the benefits like operator overloading, just like I do with the majority of the demos. Choosing a language for a large user level application is an entirely different animal from choosing one for a library. On the other hand, there are still reasons to use C, including objective reasons like compilation time and binary size, but most are more subjective/personal. On the other other hand, I don't think the "It Runs Doom" meme would exist if it were written in C++ and who doesn't want their application to run on toasters and oscilloscopes 3 decades after it was released?

Lastly, I just like C. It was my first language and is still my favorite for a host of reasons. Hey, if it's good enough for Bellard, it's certainly good enough for me.

Documentation

There is the documentation in the comments at the top of the file but there is currently no formal documentation. Looking at the examples and demos (and comparing them to opengl_reference) should be helpful.

I've also started porting the learnopengl tutorial code here which is or will be the best resource, combining his tutorials explaining the OpenGL aspects and my comments in the ported code explaining PortableGL's differences and limitations (at least in the first time they appear).

Honestly, the official OpenGL docs and reference pages are good for 90-95% of it as far as basic usage:

4.6 Core reference 4.5 comprehensive reference tutorials and guides

GL Version

You may have noticed that I link to OpenGL 4 references above, even though I describe PortableGL as "3.x-ish". There is a good reason for that.

When I first started PortableGL I originally wanted to target OpenGL 3.3 Core profile since that's what I knew, and for the history of this project I've described it as 3.x-ish core, but that's not entirely accurate. While I don't include any of the old fixed function stuff (no glBegin/glEnd or anything that goes with them), right away I found that I supported some things from the compatibility profile (like a default VAO) for free. Later I realized there was no reason not to add the 4.x DSA functions which are also simple to implement as everything is in RAM anyway. Mapping buffers is free for the same reason, and textures too (see pgl_ext.c).

In late 2023 I was working with OpenGL ES 2. I'd worked with it before but in the past it seemed so similar to what I already knew, I mostly skimmed the book, assuming most differences were just fewer formats and smaller limits. Obviously that's not quite true. In digging deeper, I learned about "client arrays" and they explain why the last parameter to VertexAttribPointer is GLVoid* pointer and not GLsizei offset. Of course the name should have given it away too. Turned out even OpenGL 3.3 (compatibility) and ES 3.0 still support client arrays, as long as the current VAO is 0. So now I technically match their spec but as a software renderer, there's really no downside to using client arrays if you prefer that. You can easily change the if statement.

And as of mid-2024 I just added support for the very useful GL debug output from OpenGL 4.3. It doesn't support everything because most is overkill/unecessary for PGL so far but by default PGL will print all errors to stdout and you can set your own message handler with just like normal.

So what version of OpenGL is PortableGL? Shrug, it's still mostly 3.x but I will add things outside of 3.x as long as it makes sense to me and is in line with the goals and priorities of the project.

Building

There are no dependencies for PortableGL itself, other than a compliant C99/C++ compiler. The examples, demos, and the performance test use SDL2 for the window/input/getting a framebuffer to the screen. If you just want to do a quick test that it compiles and runs:

cd testing
make run_tests
...
./run_tests
...
All tests passed

You can look in testing/test_output to see the png's generated by run_tests which are compared with those in testing/expected_output. For each test that fails, two files will be generated: testname_diff.png and testname_diff.txt. The first is a black image with any pixels that didn't match the expected output being white. The second lists the exact pixel values and their expected values in the format:

Diff from (195, 67) to (195, 67):
(252 253 248 255)
(251 253 248 255)
Diff from (330, 67) to (331, 67):
(253 254 249 255) (252 253 249 255)
(253 253 249 255) (253 253 249 255)

This format is subject to change but for now it lists runs of consecutive mismatching pixels with the produced output on the first line and the expected output on the second line. The coordinates are image coordinates, from the top left, not the bottom left like when PGL actually generated the image.

For the rest, on Debian/Ubuntu based distributions you can install SDL2 using the following command:

sudo apt install libsdl2-dev

On Mac you can download the DMG file from their releases page or install it through a package manager like Homebrew, MacPorts, or Fink. Note, I do not own a mac and have never tested PortableGL on one. Worst case, you can always just compile SDL2 from source but one of the above options should work.

Once you have SDL2 installed you should be able to cd into examples, demos, or testing, and just run make or make config=release for optimized builds.

On Windows you can grab the zip you want from the same releases page linked above.

I use premake generated makefiles that I include in the repo which I use on Linux. I have used these same Makefiles to build under MSYS2 on Windows. However, at least for now, even though PortableGL and all the examples and demos are cross platform, I don't officially support building them on other platforms. I've thought about removing the premake scripts from the repo entirely and just leaving the Makefiles to make that clearer but decided not to for the benefit of those who want to modify it for themselves to handle different platforms and build systems.

To sum up, the only thing that should be guaranteed to build and run anywhere out of the box with no extra effort on your part are the regression tests since they don't depend on anything.

Directory Structure

  • demos: More advanced open ended programs demonstrating a wide variety of features
  • examples: Very basic "hello triangle" type examples in C and C++
  • glcommon: Collection of helper libraries I use for graphics programming
  • media: Parent directory for all external resources
    • models: Models in my own simplified text format (created with demos/assimp_convert)
    • screenshots: All screenshots used in the various README files
    • textures: All textures used in any program in the repo
  • src: Contains the actual source files of portablegl.h which are amalgamated with generate_gl_h.py
  • testing: Contains a more formal regression and performance test suite
    • expected_output: The expected output frames for the regression tests (run_tests)
    • test_output: The output of the regression tests (see Building section)
  • portablegl.h : Current dev version of PortableGL

While I try not to introduce bugs, they do occasionally slip in, as well as (rarely) breaking changes. After the official 0.98.0 release I'll move to more frequent point releases for fixes and non-breaking changes and when I eventually reach 1.0 I'll make it 1.0.0 and be closer to semantic versioning.

Modifying

portablegl.h is generated in the src subdirectory with the python script generate_gl_h.py. You can see how it's put together and either modify the script to leave out or add files, or actually edit any of the code. Make sure if you add any actual gl functions that you add them to gl_function_list.c as it's used in the script for optionally wrapping all of them in a macro to allow user defined prexix/namespacing.

Additionally, there is a growing set of more formal tests in testing, one set of regression/feature tests, and one for performance. If you make any changes to core algorithms or data structures, you should definitely run those and make sure nothing broke or got drastically slower. The demos can also function as performance tests, so if one of those would be especially affected by a change, it might be worth comparing its before/after performance too.

On the other hand, if you're adding a function or feature that doesn't really affect anything else, it might be worth adding your own test if applicable. You can see how they work from looking at the code, but I'll add more details and documentation about the testing system later when it's more mature.

References

While I often used the official OpenGL documentation to make sure I was matching the spec as closely as realistically possible, what I used most, especially early on were a few textbooks.

The first was Fundamentals of Computer Graphics 3rd Edition which I used extensively early on to understand all the math involved, including the matrix transformation pipeline, barycentric coordinates and interpolation, texture mapping and more. There is now a 4th Edition and a soon to be released 5th Edition.

The second was the 5th edition of the OpenGL Superbible. I got this in 2010, right after OpenGL 3.3/4.0 was released, and used it for my college graphics course mentioned above. A lot of people didn't like this book because they thought it relied too much on the author`s helper libraries but I had no problems. It was my first exposure to any kind of OpenGL so I didn't have to unlearn the old stuff and all his code was free and available online so it was easy to look inside and not only see what actual OpenGL calls are used, but to then develop your own classes to your own preferences. I still use a class based on his GLFrame class for example.

In any case, that's the book I actually learned OpenGL from, and still use as a reference sometimes. I have a fork of the book repo too that I occasionally look at/update. Of course they've come out with a 6th and a 7th edition in the last decade.

Lastly, while I haven't used it as much since I got it years later, the OpenGL 4.0 Shading Language Cookbook has been useful in specific OpenGL topics occasionally. Once again, you can now get the expanded 3rd edition.

Bindings/Ports

pgl is a Go port using CXGO, and hand translating the individual examples/demos.

Sponsors

You can help support PortableGL development by becoming a Github Sponsor or via one of the other methods shown/linked to in the Sponsor popup.

Past Aeronix Sep-Oct 2023

Similar/Related Projects

I'll probably add others to this list as I find them.

TinyGL is Fabrice Bellard's implementation of a subset of OpenGL 1.x. If you want something like PortableGL but don't want to write shaders, just want old style glBegin/glEnd/glVertex etc. this is the closest I know of. Also I shamelessly copied his clipping code because I'm not 1/10th the programmer Bellard was even as an undergrad and I knew it would "just work".

TinyGL Updated: An updated and cleaned up version of TinyGL that adds several fixes and features, including performance tuning and limited multithreading.

Pixomatic is/was a software implementation of D3D 7 and 9 written in C and assembly by Michael Abrash and Mike Sartain. You can read a series of articles about it written by Abrash for Dr. Dobbs.

TTSIOD is an advanced software renderer written in C++.

As an aside, the way I handle interpolation in PortableGL works as a semi-rebuttal of this article. The answer is not the terrible strawman C approach he comes up with just to easily say "look how bad that is". The answer is that interpolation is an algorithm, a simple function, and it doesn't care what the data means or how many elements there are. Pass it data and let the algorithm do its job, same as graphics hardware does. While the inheritance + template functions method works ok if you only have a few "types" of data, every time you think of some new feature you want to interpolate, you need to define a new struct and a new template function specialization. Having a function/pipeline that just takes an arbitrary amount of float data to operate on takes less code and even has less runtime overhead since it's a single function that interpolates all the features at once rather than having to call a function for each feature. See lines ~1200-1250 of src/gl_internals. Obviously it looks more complicated with all the other openGL stuff going on but you can see a simpler version on line 308 that's used for interpolating between line endpoints instead of over a triangle. This is closer to his example but still longer because it has to support SMOOTH, PERSPECTIVE and FLAT. You can see the shape of a straightforward implementation even there though, and the benefits of decoupling the algorithm from the data it operates on.

Mesa3D is an open source implementation of OpenGL, Vulkan and other graphics APIs. It includes several different software renderers including the Gallium rasterizer (softpipe or llvmpipe depending on whether llvm is used) and Intel's OpenSWR.

libosmesa is an extraction and clean-up of the subset of Mesa3D 7.0.4 needed to support the old "swrast" software rasterizer and OSMesa offscreen renderer (both of which were removed from upstream Mesa3D in 2020.) libosmesa's intended purpose is to allow programs to offer a last-resort fallback renderer when system OpenGL capabilities are unavailable (or inadequate), while being fully self contained and buildable as simple C with no external dependencies (which is why the 7.0.4 version was chosen for ths purpose.) As that version of Mesa targets OpenGL v2.1, libosmesa may be a useful middle ground between PortableGL's OpenGL 3.x target and TinyGL's minimalist subset.

bbgl is just a very interesting concept. When I first saw it soon after it was published I was very frightened that it was exactly what PortableGL is but far more polished and from a better programmer. Fortunately, it is not.

pixman I feel like you could use them together or combine useful parts of pixman with PortableGL.

fauxgl "3D software rendering in pure Go. No OpenGL, no C extensions, no nothin'."

swGL A GPL2 multithreaded software implementation of OpenGL 1.3(ish) in C++. x86 and Windows only.

SoftGLRender A OpenGL renderer/rasterizer in modern C++. The very impressive demo lets you toggle and change various features and settings including switching seamlessly between the GPU and the software renderer. AFAIK, this is the only project that lets you write shaders in C++ like PortableGL, however the process is more complicated since it has to work with the same class/API structure as real OpenGL and can't take the shortcuts that PortableGL does. An advantage of all the extra plumbing and complexity is the actual C++ shader code is more standardized, looks a little cleaner, and more like GLSL. Besides supporting many more features (though I didn't see gl_FragDepth?), it is also optimized with threading, and SIMD on x86. Given all the abstraction and extra overhead necessary to do what it does, it's impressive it manages to still be as fast as it is. As best I can tell, disabling features to get vaguely close to an apples to apples comparison, it's about as fast as PortableGL. So if you want OpenGL, don't need to use C, like modern C++/OOP style, and want software rendering while still being able to write your own shaders and avoid the old fixed-function mess, this might be the best option on this list (or a generic C++ OpenGL wrapper library linked with modern Mesa+llvmpipe).

LICENSE

PortableGL is licensed under the MIT License (MIT)

The code used for clipping is copyright (c) Fabrice Bellard from TinyGL also under the MIT License, see LICENSE.

TODO/IDEAS

  • Render to texture; do I bother with FBOs/Renderbuffers/PixelBuffers etc.? See ch 8 of superbible 5
  • Multitexture (pointsprites and shadertoy) and texture array (Texturing) examples
  • Render to texture example program
  • Mapped buffers according to API (just wraps extensions; it's free and everything is really read/write)
  • Extension functions that avoid unecessary copying, ie user owns buffer/texture data and gl doesn't free
  • Unsafe mode (ie no gl error checking for speedup)
  • Finish duplicating NeHe style tutorial programs from learningwebgl to opengl_reference and then porting those to use PortableGL Port learnopengl instead, repo here WIP.
  • Port medium to large open source game project as correctness/performance/API coverage test (Craft done)
  • Fix bug in cubemap demo
  • More texture and render target formats
  • Logo
  • Update premake scripts to Premake5 and handle other platforms once 5 is out of beta
  • Formal regression testing (WIP)
  • Formal performance testing (WIP)
  • Formal/organized documentation
  • Integrated documentation, license etc. a la stb libraries

portablegl's People

Contributors

rswinkle avatar starseeker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

portablegl's Issues

Multithreaded Rasterization?

Hi! I just want to say that this project is excellent, and I plan on getting it running in my kernel as soon as I get the time

While it's quite easy for a hobby kernel to take advantage of multiple CPU cores, implementing (or porting) a GPU driver is quite the sisyphean task. I was wondering if there are plans to enable parallelized rasterization in a similar way to how GPUs do so, but in software w/ multiple CPU threads - pthreads, for example. I'm not super familiar with the codebase here, but would that be a considerable undertaking/refactor of the core renderer? I'd assume this feature would be hidden behind an opt-in flag to maintain support for systems without multiple cores, or even the pthread interface.

request a new release

๐Ÿ‘‹ while upgrading sdl2 to 2.30.3, I ran into some regression test failure with portablegl 0.97.1, and it is reproducible even with a rebuild. And then after I rebuild from the master, the regression tests run well again.

Can you cut a new release to help refresh the homebrew formula? Thanks!

cc @rswinkle

Looking to include PortableGL in LVGL - roadmap for v1.0?

I'm looking to include PortableGL as a widget in the embedded graphics/UI library LVGL. I'm not a maintainer there; will just make a pull request once I get it properly implemented. My initial proof-of-concept tests are looking pretty promising and I really appreciate how easy it's been using PortableGL for this.

I noticed that the version number being used for PGL is 0.96. Are there any additional features you are looking to implement in order to call it 1.0? If it's embedded in a toolkit such at LVGL, it might be nice to use a "feature complete" version as it will likely get updated less frequently than your source tree. Thanks again for your efforts on this project; it's been a lot of fun to play with.

This is a great project

Just wanted to let you know I think this is a really neat project.

I was stuck trying to compile a cross-architecture static mesa for DICOMautomaton and ... I just don't think it will work. PortableGL, in comparison, took a tiny number of changes to integrate and build. What a lifesaver!

I still haven't been able to test the binaries work (ripped out glew init code and have not yet replaced it), but the program seems so much more tractable at this point that I had to reach out and thank you!

glVertexAttribPointer parameter type

The OpenGL spec gives glVertexAttribPointer the following prototype:

void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);

However, the last parameter is "pointer is treated as a byte offset into the buffer object's data store." You can see the full description here.

What that means is that everyone has to cast the byte offset to a void pointer like so

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));

I've always thought this was a stupid design decision that didn't make any sense, so when I implemented it for PortableGL I gave it the following prototype

void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLsizei offset)

I've never really had cause to regret that but in the process of porting the LearningOpenGL code, having to delete the cast on every call is a bit of an irritation. It occurred to me that maybe I should have matched the stupid spec and had a pgl extension version or macro wrapper that took a regular int. So if I went the macro route it would look like this:

#define pglVertexAttribPointer(index, size, type, normalized, stride, offset) \
glVertexAttribPointer(index, size, type, normalized, stride, (void*)offset)

That way you could ignore it when porting if you wanted to, and still use the pgl version from scratch for simplicity.

It seems like it'd be an easy change, and it is logically, but unfortunately the offset member is currently a GLsizei which is in int32_t so you get a warning or error casting from a 64 bit pointer. There are several solutions to that, but I think the one that obeys the spec (or at least the spirit of it) the closest would be to add the missing GL types GLintptr and GLsizeiptr and define them as intptr_t and uintptr_t and use one of those for offset. This would work but it just feels a little wrong and maybe not worth the effort. It also would break backward compatibility but as a single header library designed to be statically compiled into projects and with a very small user base that probably shouldn't be a huge factor.

I'm on the fence about it, and I'm in no hurry either way so I figured I'd do an informal poll. I can't guarantee I'll end up deciding in favor of the majority, but I'd welcome any strong arguments for or against the change.

Thanks!

Cubemap demo bug

I mention it in both the main README TODO list and the demo README description. Basically the sky wobbles when you look around but is fine when you move. Most likely a bug in the demo not in PortableGL but anything's possible.

I'm putting this here to motivate me to fix it sometime this year hopefully.

ported to Go but ex1 doesn't work

This project is really cool. I have had a fascination with graphics for a long time but haven't found something that really interests me until this. I ported this project to the GO programming language using a tool called CXGO.

I then went ahead and converted by hand the ex1 c code found in main.go.

Everything runs without any errors but I don't get any triangle displayed. It appears that shaders are getting the vertex data but I don't know why nothing shows. I know my code is in Go and not C but since you understand the project better than I do maybe you'll spot something wrong in my code. Or give suggestions on what to look for if cxgo introduced a bug.

My project is here

Dozens of warnings when using strict rules

I was testing RGFW using stricter warning rules, this caused the PortableGL example to fail.

The flags I used were -Wall -Werror -Wstrict-prototypes -Wextra

Feel free to close this issue if you don't care if PortableGL can compile with those flags.

Need help in implementing in game.

Hello, congrats on this a cool project.
I would like to implement PortableGL in WipeOut 1 https://github.com/phoboslab/wipeout-rewrite
I have got game running, most gl function except anisotropy options links with PGL.

Added new renderer based on SOFTWARE and GL ones in platform_sdl.c :

#elif defined(RENDERER_PORTABLEGL) // ----------------------------------------------
	#define PLATFORM_WINDOW_FLAGS 0

	#define HEIGHT SYSTEM_WINDOW_HEIGHT
	#define WIDTH SYSTEM_WINDOW_WIDTH 
	static SDL_Texture *screenbuffer = NULL;
	static void *screenbuffer_pixels = NULL;
	static int screenbuffer_pitch;
	static vec2i_t screenbuffer_size = vec2i(0, 0);
	static vec2i_t screen_size = vec2i(0, 0);


	void platform_video_init(void) {
		SDL_GLContext platform_gl;
		platform_gl = SDL_GL_CreateContext(window);

		SDL_GL_SetSwapInterval(1);

		SDL_SetMainReady();
		renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
		if (!init_glContext(&the_context, &bbufpix, WIDTH, HEIGHT, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)) {
				puts("Failed to initialize glContext");
				exit(0);
			}
	}

	void platform_video_cleanup() {
		if (screenbuffer) {
			SDL_DestroyTexture(screenbuffer);
		}
		SDL_DestroyRenderer(renderer);
		free_glContext(&the_context);
	}

	void platform_prepare_frame() {
		SDL_GL_SwapWindow(window); //??
		if (screen_size.x != screenbuffer_size.x || screen_size.y != screenbuffer_size.y) {
			if (screenbuffer) {
				SDL_DestroyTexture(screenbuffer);
			}
			screenbuffer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, WIDTH, HEIGHT);
			screenbuffer_size = screen_size;

		}
		SDL_LockTexture(screenbuffer, NULL, &screenbuffer_pixels, &screenbuffer_pitch);
	}

	void platform_end_frame() {
		screenbuffer_pixels = NULL;
		SDL_UnlockTexture(screenbuffer);
		SDL_UpdateTexture(screenbuffer, NULL, bbufpix, WIDTH * sizeof(uint32_t));
		SDL_RenderCopy(renderer, screenbuffer, NULL, NULL);
		SDL_RenderPresent(renderer);
	}

	rgba_t *platform_get_screenbuffer(int32_t *pitch) {
		*pitch = screenbuffer_pitch;
		return screenbuffer_pixels;
	}

	vec2i_t platform_screen_size() {
		int width, height;
		SDL_GetWindowSize(window, &width, &height);

			screen_size = vec2i(width, height);
		return screen_size;
	}

and in render_gl.c commented out glewInit(); and replaced glCreateProgram() :

	//GLuint program = glCreateProgram();
	GLenum flat = PGL_FLAT; 
	GLuint program = pglCreateProgram(vs, fs, 1, &flat, GL_FALSE);

End result is just blue flashing rectangle.
obraz

Any help would be appreciated.

Using with sokol?

Hi! I just tried using portableGL with one of the examples in the sokol repository (app + gfx), but the compiler whines about missing functions:

Expand
/usr/bin/ld: /tmp/ccBE58hl.o: in function `_sg_gl_init_caps_glcore33':
triangle-sapp.c:(.text+0x3061d): undefined reference to `glGetStringi'
/usr/bin/ld: /tmp/ccBE58hl.o: in function `_sg_gl_reset_state_cache':
triangle-sapp.c:(.text+0x31259): undefined reference to `glColorMask'
/usr/bin/ld: /tmp/ccBE58hl.o: in function `_sg_gl_create_image':
triangle-sapp.c:(.text+0x31d0c): undefined reference to `glRenderbufferStorageMultisample'
/usr/bin/ld: triangle-sapp.c:(.text+0x31df1): undefined reference to `glRenderbufferStorageMultisample'
/usr/bin/ld: triangle-sapp.c:(.text+0x322bc): undefined reference to `glTexParameterf'
/usr/bin/ld: triangle-sapp.c:(.text+0x322ea): undefined reference to `glTexParameterf'
/usr/bin/ld: triangle-sapp.c:(.text+0x32445): undefined reference to `glCompressedTexImage2D'
/usr/bin/ld: triangle-sapp.c:(.text+0x32561): undefined reference to `glCompressedTexImage3D'
/usr/bin/ld: /tmp/ccBE58hl.o: in function `_sg_gl_create_pass':
triangle-sapp.c:(.text+0x33f40): undefined reference to `glFramebufferTextureLayer'
/usr/bin/ld: triangle-sapp.c:(.text+0x34067): undefined reference to `glDrawBuffers'
/usr/bin/ld: triangle-sapp.c:(.text+0x34212): undefined reference to `glFramebufferTextureLayer'
/usr/bin/ld: triangle-sapp.c:(.text+0x3426e): undefined reference to `glDrawBuffers'
/usr/bin/ld: /tmp/ccBE58hl.o: in function `_sg_gl_begin_pass':
triangle-sapp.c:(.text+0x34814): undefined reference to `glColorMask'
/usr/bin/ld: triangle-sapp.c:(.text+0x349fc): undefined reference to `glClearBufferfv'
/usr/bin/ld: triangle-sapp.c:(.text+0x34a62): undefined reference to `glClearBufferfi'
/usr/bin/ld: triangle-sapp.c:(.text+0x34a89): undefined reference to `glClearBufferfv'
/usr/bin/ld: triangle-sapp.c:(.text+0x34aba): undefined reference to `glClearBufferiv'
/usr/bin/ld: /tmp/ccBE58hl.o: in function `_sg_gl_end_pass':
triangle-sapp.c:(.text+0x34d29): undefined reference to `glReadBuffer'
/usr/bin/ld: triangle-sapp.c:(.text+0x34d65): undefined reference to `glBlitFramebuffer'
/usr/bin/ld: /tmp/ccBE58hl.o: in function `_sg_gl_apply_pipeline':
triangle-sapp.c:(.text+0x35738): undefined reference to `glColorMaski'
/usr/bin/ld: /tmp/ccBE58hl.o: in function `init':

That's with the SOKOL_GLCORE33 option. Using SOKOL_GLES2 gets us closer but still no workie:

Expand
/usr/bin/ld: /tmp/cc03flIg.o: in function `_sg_gl_reset_state_cache':
triangle-sapp.c:(.text+0x2ff93): undefined reference to `glColorMask'
/usr/bin/ld: /tmp/cc03flIg.o: in function `_sg_gl_create_image':
triangle-sapp.c:(.text+0x30c7c): undefined reference to `glCompressedTexImage2D'
/usr/bin/ld: /tmp/cc03flIg.o: in function `_sg_gl_begin_pass':
triangle-sapp.c:(.text+0x32dd0): undefined reference to `glColorMask'
/usr/bin/ld: triangle-sapp.c:(.text+0x32ef9): undefined reference to `glClearDepthf'
/usr/bin/ld: /tmp/cc03flIg.o: in function `_sg_gl_apply_pipeline':
triangle-sapp.c:(.text+0x33990): undefined reference to `glColorMask'
/usr/bin/ld: /tmp/cc03flIg.o: in function `init':

Am I missing some specific flag or #define, or is it simply because PortableGL doesn't implement those functions (yet)?

Thanks in advance!

RGBA8888 Byte Format

This is such an awesome project! Have OpenGL-esque API in software rendering opens up portability to embedded systems, which is huge.

I've put together a small software-rendering library which facilitates a number of different platforms. While using PortableGL in raylib, which uses an RGBA8888 pixel format, it ends up rendering like....

Screenshot from 2024-04-17 14-49-38

While I have been able to switch up the masks, I'm unsure why the alpha looks to be weird.

#ifdef PNTR_PIXELFORMAT_RGBA
    // TODO: raylib: Fix alpha mask
    u32 Rmask = 0x000000FF;
    u32 Gmask = 0x0000FF00;
    u32 Bmask = 0x00FF0000;
    u32 Amask = 0xFF000000;
#elif defined(PNTR_PIXELFORMAT_ARGB)
    #if defined(SDL_BYTEORDER) && SDL_BYTEORDER == SDL_BIG_ENDIAN
        u32 Rmask = 0xFF000000;
        u32 Gmask = 0x00FF0000;
        u32 Bmask = 0x0000FF00;
        u32 Amask = 0x000000FF;
    #else
        u32 Rmask = 0x00FF0000;
        u32 Gmask = 0x0000FF00;
        u32 Bmask = 0x000000FF;
        u32 Amask = 0xFF000000;
    #endif
#endif

https://github.com/RobLoach/pntr_portablegl/blob/master/examples/ex2.c

Would you happen to know what would be wrong? It works perfectly in SDL with ARGB

Supported Vector Font Libraries?

First of all, you're doing the net.gods' own work here, sir. Thank you for this project.

I'm wondering if you've had success using a font library such as freetype with this, and if so I'd greatly appreciate any information about which one(s) and how it went. I'm just trying to write something to render a background image with a calendar drawn on top of it and dump it into a png, so PortableGL looks perfect so long as I can draw text without reinventing the wheel.

Edit
Actually, now that I'm looking directly at FreeType for the first time in a decade or so, it looks like it's independent from the renderer, so I'm in business. Sorry to bug you, and thanks again for the project. ๐Ÿ˜

Function prefix

I'm looking into including PortableGL as a fallback (in my 8th programming language ) when running on e.g. an RPI or other Linux system which hasn't got OpenGL (or which has GL < 2).

To that end, it would be convenient if the glXXX functions could optionally be "prefixed", e..g #define PORTABLEGL_PREFIX "pgl_" would turn your implementation of say glEnable into pgl_glEnable.

I haven't yet done the integration, but finding your library was exciting, since it potentially makes it easy to support previously un- or under- supported systems in 8th.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.