Aros/Developer/OpenGL

Introduction
The Amiga's first introduction to hardware enhanced 3D was Warp3D. This was followed by an open source(software based) equivalent called Wazp3D A Wazp3D adaptation to AROS from Matthias Rustler appeared on December 2007.

During 2009 Krzysztof "Deadwood" Smiechowicz ported version 7.5 of MESA 3D to AROS. MESA 3D provides a generic OpenGL implementation. Then he added hardware 3D acceleration capabilities to AROS with his port of Gallium3D for MESA 3D. Then on September 2011 Wazp3D was linked to Mesa 3D for hardware enhanced 3D.

in -> vertex -> fragment -> out


 * Framebuffer  – alpha, stencil, depth


 * Vertex       – transform and lighting
 * Fragment     – texturing, fog,


 * Geometry     – primitives (dots, lines, polygons triangle/quad), clipping
 * Compute      -
 * Tessellation -

Far better using SDL's 1.2.x GL additions for up to and including OpenGL 2 or consider SDL 1.3 / 2.x for OpenGL 3 and above


 * Web GL 1.0 – OpenGL ES 2.0 – OpenGL 2 but complete support in OpenGL 4.1
 * Web GL 2.0 – Open GL ES 3.0 – OpenGL 4.3

There is no backwards compatibility from OpenGL 2 to OpenGL 1 as well as OpenGL ES 2 to OpenGL ES 1. But all later OpenGL and ES versions are retrospectively support.

Considered deprecated (ie not advised using or missing/removed)

GL1.1 – OpenGL ES 1 with Fixed Functions – glNormalPointer, glColorPointer and glVertexPointer were introduced. Nearly all of the old ID software are OpenGL 1.1 + extensions

GL1.3 -

GL1.4 – fragment support added

GL1.5 – VBOs added – OpenGL ES 1.1 – added features such as mandatory support for multitexture, better multitexture support (including combiners and dot product texture operations), automatic mipmap generation, vertex buffer objects, state queries, user clip planes, and greater control over point rendering

GL2.0 – OpenGL es 2 – Vertex / Fragment shaders introduced – WebGL minimum – GLSL shading language -

deprecated = glMatrixMode glMult/LoadMatrix glRotate/Translate/Scale glPush/PopMatrix glBegin/End glVertex glTexCoords glLight glMaterial glPush/PopAttrib

GL2.1 – 2006 – last appearance of some matrix functions/stacks – PBOs Pixel buffer objects -

If you want to be able to run on hardware incapable of OpenGL 3.0, then suggest that you not write applications for OpenGL 3.0. Many of the features of 3.0 that can be used on older hardware are backported via extensions. So instead of writing a 3.x application, you could be writing a 2.1 application that is able to use certain extensions. So just code to the GL 2.1 spec instead. You can always research the calls and features that have been since deprecated and just avoid using them in a pure 2.1 program

general method is to have different rendering paths for different features. You detect the version number. If it's one thing, you use one rendering path. If it's lower, you use another. Etc. You can do fine-grained checking by checking for the presence of certain extensions.

Minimum advised starting point for new apps which arrived with Mesa 12 ported to AROS which opened access to the following (hardware support permitting)

Gl3.0 – 2008 – Geometry shaders – Vertex Array Objects (VAOs) ie GL_ARB_vertex_array_object. Older versions need to do more vertex setup work when drawing an object, rather than setting them up once and just binding the VAO. Modern OpenGL enforces you to write your own matrices and pass those manually into shader programs. use programmable function pipelines

GL3.1 – eliminates most of the fixed-function rendering pipeline in favor of a programmable one

GL3.3

GL4.0 – 2010 – Tesselation shaders – Image load/store and atomic counters are probably the biggest ones (this includes shader storage buffers too), though simultaneously the least advertised. Shaders get to write/read from images and buffers directly, though there are a lot of caveats and synchronization issues to understand about doing this. introduces an additional pair of shader stages: one that decides how much to tessellate a primitive, and the other to decide how to generate the new values from the tessellated primitive.

GL4.1 – 2010 – incompatibilities between the desktop version of OpenGL and OpenGL ES 2.0 persisted until OpenGL 4.1, which added the GL_ARB_ES2_compatibility extension. Subroutines are an interesting but often overlooked feature. Basically, you can attach subroutines to shader programs like uniforms. So you could use the same basic program that will run a lighting function, but you can swap lighting functions without changing the program. The basic program would fetch textures, figure out what the diffuse/specular/etc material parameters are, determine the normal and lighting parameters, and pass that to the subroutine. allows you to dynamically piece together different fragments of shaders. You can more or less attach a function to a specific bind point in a program.

GL4.2 – 2011 -

GL4.3 – 2012 – Compute shaders – openGL ES 3 compatibility -

GL4.4

GL4.5

WARP3D
Recompiling a program that use Warp3D.library is quite simple. You just need to link it to Warp3D

So compiling cow3d for Aros x86 was as simple as gcc -c -O3 CoW3D-3.c -o Cow3D-Aros -lWarp3D

Wazp3D-Prefs is a little tool for selecting how Wazp3D works (fast or nice).

Aros version is included with Aminet/Cow3D (see Wazp3D homepage for documentation) Option "Renderer:Soft to Image" is safer if your Aros system dont support LockBitmapTags else "Renderer:Soft to Bitmap" If your Aros support "Native Graphics Aros" then you can try "Renderer:hard overlay" or "Renderer:hard" but the display is not perfect as Mesa dont support rendering to bitmap as Warp3D

You need to use W3D_DrawTriFan, W3D_DrawTriSttrip or better still, W3D_DrawArray with their corresponding data structures. Suggest the latter since you have much more control over how the vertex data is organised.

You create a triangle strip or a triangle fan. In a strip, alternate triangles share two points along an edge. In a fan, all triangles share one common vertex and adjacent triangles also share an edge. The simplest to illustrate is the strip. A rectangle is simply a 2 triangle strip, something like this:

V[0]--V[1] V[2]--V[3]

Using one of the strip drawing methods, the same texture is applied to all polygons in the strip. If you use the old single triangle routines, you have to either enable global texture environment or specify the texture in each polygon separately.

Warp3D is a rasterizer only. That means that it draws primitives in screen space. Strictly, the axes are defined as X=left to right in pixels, Y top to botton in pixels, Z is plane of the screen into the distance. The valid range for Z is 0.0 – 1.0.

You need to calculate your vertices in screen space directly or write your own transformation pipeline.

See Starship3D

MESA 12
This is a work in progress

Creating a window in SDL and binding an OpenGL 3.2 context to it uses these steps

Initialize the SDL video subsystem using SDL_Init or SDL_VideoInit Set the parameters we require for opengl using SDL_GL_SetAttribute Create a window using SDL_CreateWindow Bind an OpenGL context to the window using SDL_GL_CreateContext

MESA 7
From client perspective using mesa.library is quite simple:

1) For programs that simply use OpenGL and Glut (like Aminet/starship) then just compile them

gcc starship.c -lglut -lgl – o starshiparos

2) For programs that use OpenGL and Amiga windowing system

[...]
 * Create a window
 * Call AROSMesaCreateContext passing it the window and some other stuff -> you get rendering context in return
 * Call AROSMesaMakeCurrent passing it the context so that AROSMesa knows what to render on
 * Render some stuff using glXXX functions
 * Call AROSMesaSwapBuffers to have the content of render buffer painted onto your window
 * Loop to glXXX functions
 * Call AROSMesaDestroyContext(context);
 * Call CloseWindow(window);

OpenGL API has been changed in ABI V1, just rename 'glA' to 'AROSMesa' The VBO functions are still there, but you need to access them via glaGetProcAddress.

3D Voxel C, 3D Voxel C++, voxel space c, Minecr*ft simple terrain, Voxel C++, [], [],

TD C++, 2D Tiles Sprite Sheet Game C++, 2D Tile Youtube, [], [],

GLSL openGL Shader Language
Shaders are written in the C-like language GLSL which has no pointers and is not object-oriented.

GLSL is tailored for use with graphics and contains useful features specifically targeted at vector and matrix manipulation.

GLSL 1.0 to 1.2 (OpenGL 2.x)
Shaders always begin with a version declaration, followed by a list of input and output variables, uniforms and its main function. Each shader's entry point is at its main function where we process any input variables and output the results in its output variables.

uniform type uniform_name; void main { // process input(s) and do_something ... // output did_somethings to output variable out_variable_name = something_done; }
 * 1) version version_number

Each input variable is also known as a vertex attribute. There is a maximum number of vertex attributes we're allowed to declare limited by the hardware. OpenGL guarantees there are always at least 16 4-component vertex attributes available, but some hardware may allow for more which you can retrieve by querying GL_MAX_VERTEX_ATTRIBS:

Types

GLSL has, like any other programming language, data types for specifying what kind of variable we want to work with. GLSL has most of the default basic types we know from languages like C: int, float, double, uint and bool. GLSL also features two container types that we'll be using a lot, namely vectors and matrices.

Vectors

A vector in GLSL is a 2,3 or 4 component container for any of the basic types just mentioned. They can take the following form (n represents the number of components):


 * vecn: the default vector of n floats.
 * bvecn: a vector of n booleans.
 * ivecn: a vector of n integers.
 * uvecn: a vector of n unsigned integers.
 * dvecn: a vector of n double components.

Most of the time we will be using the basic vecn since floats are sufficient for most of our purposes.

Components of a vector can be accessed via vec.x where x is the first component of the vector. You can use .x, .y, .z and .w to access their first, second, third and fourth component respectively. GLSL also allows you to use rgba for colors or stpq for texture coordinates, accessing the same components.

The vector datatype allows for some interesting and flexible component selection called swizzling. Swizzling allows us to use syntax like this:

vec2 someVec; vec4 differentVec = someVec.xyxx; vec3 anotherVec = differentVec.zyw; vec4 otherVec = someVec.xxxx + anotherVec.yxzy;

You can use any combination of up to 4 letters to create a new vector (of the same type) as long as the original vector has those components; it is not allowed to access the .z component of a vec2 for example. We can also pass vectors as arguments to different vector constructor calls, reducing the number of arguments required:

vec2 vect = vec2(0.5, 0.7); vec4 result = vec4(vect, 0.0, 0.0); vec4 otherResult = vec4(result.xyz, 1.0);

Vectors are thus a flexible datatype that we can use for all kinds of input and output.

Uniforms are another way to pass data from our application on the CPU to the shaders on the GPU. Uniforms are global so is unique per shader program object, and can be accessed from any shader at any stage in the shader program. Uniforms also will keep their values until they're either reset or updated.

To declare a uniform in GLSL we simply add the uniform keyword to a shader with a type and a name. From that point on we can use the newly declared uniform in the shader.

out vec4 FragColor; uniform vec4 ourColor; // we set this variable in the OpenGL code.
 * 1) version 330 core

void main {   FragColor = ourColor; }

Vertex - attributes

Vectors - swizzling

worldspace (position) transformed matrix to screenspace (projection, modelview, position)

Fragment - vectors

R, G, B, A

sdf (signed distance function) 2d and 3d shapes in shaders

Tut, [], [],

SDL2

snake c++, Snake C++, [],

Game starter, Game start, [], [],

simple c++ platformer, [], [],

Simple C 3D engine, [], [],

[], [], [],

SDL1

[], [], [],

[], [], [],

GLSL tut, [], [], []

load a vertex shader file and fragment shader file and store each in a separate C string call glCreateShader twice; for 1 vertex and 1 fragment shader index call glShaderSource to copy code from a string for each of the above call glCompileShader for both shader indices call glCreateProgram to create an index to a new program call glAttachShader twice, to attach both shader indices to the program call glLinkProgram call glGetUniformLocation to get the unique location of the variable called "inputColour" call glUseProgram to switch to your shader before calling...   glUniform4f(location, r,g,b,a) to assign an initial colour to your fragment shader (e.g. glUniform4f(colour_loc, 1.0f, 0.0f, 0.0f, 1.0f) for red)

For a complete list of OpenGL shader functions see the Quick Reference Card. The most useful functions are below

OpenGL "Shader" (Separate Shader Code) Functions Function Name 	Description glCreateShader 	create a variable for storing a shader's code in OpenGL. returns unsigned int index to it. glShaderSource 	copy shader code from C string into an OpenGL shader variable glCompileShader 	compile an OpenGL shader variable that has code in it glGetShaderiv 	can be used to check if compile found errors glGetShaderInfoLog 	creates a string with any error information glDeleteShader 	free memory used by an OpenGL shader variable

OpenGL "Program" (Combined Shader Programme) Functions Function Name 	Description glCreateProgram 	create a variable for storing a combined shader programme in OpenGL. returns unsigned int index to it. glAttachShader 	attach a compiled OpenGL shader variable to a shader programme variable glLinkProgram 	after all shaders are attached, link the parts into a complete shader programme glValidateProgram 	check if a program is ready to execute. information stored in a log glGetProgramiv 	can be used to check for link and validate errors glGetProgramInfoLog 	writes any information from link and validate to a C string glUseProgram 	switch to drawing with a specified shader programme glGetActiveAttrib 	get details of a numbered per-vertex attribute used in the shader glGetAttribLocation 	get the unique "location" identifier of a named per-vertex attribute glGetUniformLocation 	get the unique "location" identifier of a named uniform variable glGetActiveUniform 	get details of a named uniform variable used in the shader glUniform{1234}{ifd} 	set the value of a uniform variable of a given shader (function name varies by dimensionality and data type) glUniform{1234}{ifd}v 	same as above, but with a whole array of values glUniformMatrix{234}{fd}v 	same as above, but for matrices of dimensions 2x2,3x3, or 4x4

tut, examples, [],

GLSL 1.3 to 1.5 (OpenGL 3.x) GLSL 4.x (OpenGL 4.x)
Some changes occurred with later OpenGL specs compared to OpenGL 2 and so

in type in_variable_name; in type in_variable_name; out type out_variable_name; uniform type uniform_name; void main { // process input(s) and do_something ... // output did_somethings to output variable out_variable_name = something_done; }
 * 1) version version_number

Want to have inputs and outputs on the individual shaders so that we can move stuff around. GLSL defined the in and out keywords specifically for that purpose. Each shader can specify inputs and outputs using those keywords and wherever an output variable matches with an input variable of the next shader stage they're passed along. The vertex and fragment shader differ

raylib

 * 2013 1.0
 * 2016 2.0
 * 2019 3.0
 * 2021 3.7
 * 2023 5.0

highly inspired by XNA framework and by Borland BGI graphics lib


 * Made for games and animations
 * Input polled
 * every frame starts from fresh empty screen, you are tracking any state entity data per refresh
 * nothing happens until EndDrawing is called

Game loop - Quit -> Handle Input -> Update Game -> begin Drawing -> Draw Game -> End Drawing -> to Quit

DrawFPS, SetTargetFPS,

DrawTexturePro (tex2d, src, dest, origin, rot, color) Flexible Materials system, supporting classic maps and PBR maps

Camera2d, beginMode2D , EndMode2D, GetworldToScreen2D (pos, camera) for HUD, health etc, GetScreenToWorld2D (pos, camera) what World items clicked,

Animations, your code covers all motions, use time functions GetFrameTime iqm model and animation support -> binary file -> resource package Animated 3D models supported (skeletal bones animation) (raylib supports several 3d model formats (obj, gltf/glb, iqm, m3d, vox), some formats support must be enabled in raylib/src/config.h file!)

A* (A star) pathfinding, [], [], Dijkstra, BreadthFirstS and DepthFirstS

2D Physics engines like Box2D, Velocity Raptor, Torque2D, Chipmunk2D, [], [], Fluids,

3D Physics like Torque6,, ODE, Jolt, , Cu, Vehicle, Physics3D, qu3e, Newton,

gcc -o game main.c -lraylib


 * 1)   raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5
 * 2)   Copyright (c) 2013-2024 Ramon Santamaria (@raysan5)
 * 3)   This software is provided "as-is", without any express or implied warranty. In no event
 * 4)   will the authors be held liable for any damages arising from the use of this software.
 * 5)   Permission is granted to anyone to use this software for any purpose, including commercial
 * 6)   applications, and to alter it and redistribute it freely, subject to the following restrictions:
 * 7)     1. The origin of this software must not be misrepresented; you must not claim that you
 * 8)     wrote the original software. If you use this software in a product, an acknowledgment
 * 9)     in the product documentation would be appreciated but is not required.
 * 10)     2. Altered source versions must be plainly marked as such, and must not be misrepresented
 * 11)     as being the original software.
 * 12)     3. This notice may not be removed or altered from any source distribution.
 * 1)     1. The origin of this software must not be misrepresented; you must not claim that you
 * 2)     wrote the original software. If you use this software in a product, an acknowledgment
 * 3)     in the product documentation would be appreciated but is not required.
 * 4)     2. Altered source versions must be plainly marked as such, and must not be misrepresented
 * 5)     as being the original software.
 * 6)     3. This notice may not be removed or altered from any source distribution.
 * 1)     3. This notice may not be removed or altered from any source distribution.
 * 1)     3. This notice may not be removed or altered from any source distribution.

.PHONY: all clean run

PLATFORM             ?= PLATFORM_DESKTOP
 * 1) Define required environment variables
 * 2) Define target platform: PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB
 * 1) Define target platform: PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB

PROJECT_NAME         ?= raylib_game PROJECT_VERSION      ?= 1.0 PROJECT_BUILD_PATH   ?=.
 * 1) Define project variables

RAYLIB_PATH          ?= ../../raylib

RAYLIB_INCLUDE_PATH  ?= /usr/local/include RAYLIB_LIB_PATH      ?= /usr/local/lib
 * 1) Locations of raylib.h and libraylib.a/libraylib.so
 * 2) NOTE: Those variables are only used for PLATFORM_OS: LINUX, BSD

RAYLIB_LIBTYPE       ?= STATIC
 * 1) Library type compilation: STATIC (.a) or SHARED (.so/.dll)

BUILD_MODE           ?= RELEASE
 * 1) Build mode for project: DEBUG or RELEASE

USE_WAYLAND_DISPLAY  ?= FALSE
 * 1) Use Wayland display server protocol on Linux desktop (by default it uses X11 windowing system)
 * 2) NOTE: This variable is only used for PLATFORM_OS: LINUX

BUILD_WEB_ASYNCIFY   ?= FALSE BUILD_WEB_SHELL      ?= minshell.html BUILD_WEB_HEAP_SIZE  ?= 134217728 BUILD_WEB_RESOURCES  ?= TRUE BUILD_WEB_RESOURCES_PATH ?= resources
 * 1) PLATFORM_WEB: Default properties

ifeq ($(PLATFORM),PLATFORM_RPI) USE_RPI_CROSS_COMPILER ?= FALSE ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) RPI_TOOLCHAIN ?= C:/SysGCC/Raspberry RPI_TOOLCHAIN_SYSROOT ?= $(RPI_TOOLCHAIN)/arm-linux-gnueabihf/sysroot endif endif
 * 1) Use cross-compiler for PLATFORM_RPI

ifeq ($(PLATFORM),PLATFORM_DESKTOP) # No uname.exe on MinGW!, but OS=Windows_NT on Windows! # ifeq ($(UNAME),Msys) -> Windows ifeq ($(OS),Windows_NT) PLATFORM_OS = WINDOWS ifndef PLATFORM_SHELL PLATFORM_SHELL = cmd endif else UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS = LINUX endif ifeq ($(UNAMEOS),FreeBSD) PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),OpenBSD) PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),NetBSD) PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),DragonFly) PLATFORM_OS = BSD endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS = OSX endif ifndef PLATFORM_SHELL PLATFORM_SHELL = sh       endif endif endif ifeq ($(PLATFORM),PLATFORM_RPI) UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS = LINUX endif ifndef PLATFORM_SHELL PLATFORM_SHELL = sh   endif endif ifeq ($(PLATFORM),PLATFORM_DRM) UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS = LINUX endif ifndef PLATFORM_SHELL PLATFORM_SHELL = sh   endif endif ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(OS),Windows_NT) PLATFORM_OS = WINDOWS ifndef PLATFORM_SHELL PLATFORM_SHELL = cmd endif else UNAMEOS = $(shell uname) ifeq ($(UNAMEOS),Linux) PLATFORM_OS = LINUX endif ifeq ($(UNAMEOS),Darwin) PLATFORM_OS = OSX endif ifndef PLATFORM_SHELL PLATFORM_SHELL = sh       endif endif endif
 * 1) Determine PLATFORM_OS in case PLATFORM_DESKTOP selected

ifeq ($(PLATFORM),PLATFORM_RPI) RAYLIB_PATH       ?= /home/pi/raylib endif ifeq ($(PLATFORM),PLATFORM_DRM) RAYLIB_PATH       ?= /home/pi/raylib endif
 * 1) Default path for raylib on Raspberry Pi

RAYLIB_RELEASE_PATH 	?= $(RAYLIB_PATH)/src
 * 1) Define raylib release directory for compiled library

ifeq ($(OS),Windows_NT) ifeq ($(PLATFORM),PLATFORM_WEB) # Emscripten required variables EMSDK_PATH        ?= C:/emsdk EMSCRIPTEN_PATH   ?= $(EMSDK_PATH)/upstream/emscripten CLANG_PATH         = $(EMSDK_PATH)/upstream/bin PYTHON_PATH        = $(EMSDK_PATH)/python/3.9.2-nuget_64bit NODE_PATH          = $(EMSDK_PATH)/node/14.15.5_64bit/bin export PATH        = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH):$$(PATH) endif endif

CC = gcc
 * 1) Define default C compiler: CC

ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),OSX) # OSX default compiler CC = clang endif ifeq ($(PLATFORM_OS),BSD) # FreeBSD, OpenBSD, NetBSD, DragonFly default compiler CC = clang endif endif ifeq ($(PLATFORM),PLATFORM_RPI) ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) # Define RPI cross-compiler #CC = armv6j-hardfloat-linux-gnueabi-gcc CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc endif endif ifeq ($(PLATFORM),PLATFORM_WEB) # HTML5 emscripten compiler # WARNING: To compile to HTML5, code must be redesigned # to use emscripten.h and emscripten_set_main_loop CC = emcc endif

MAKE ?= make
 * 1) Define default make program: MAKE

ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) MAKE = mingw32-make endif endif ifeq ($(PLATFORM),PLATFORM_ANDROID) MAKE = mingw32-make endif

CFLAGS = -std=c99 -Wall -Wno-missing-braces -Wunused-result -D_DEFAULT_SOURCE
 * 1) Define compiler flags: CFLAGS
 * 2)  -O1                  defines optimization level
 * 3)  -g                   include debug information on compilation
 * 4)  -s                   strip unnecessary data from build
 * 5)  -Wall                turns on most, but not all, compiler warnings
 * 6)  -std=c99             defines C language mode (standard C from 1999 revision)
 * 7)  -std=gnu99           defines C language mode (GNU C from 1999 revision)
 * 8)  -Wno-missing-braces  ignore invalid warning (GCC bug 53119)
 * 9)  -Wno-unused-value    ignore unused return values of some functions (i.e. fread)
 * 10)  -D_DEFAULT_SOURCE    use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
 * 1)  -D_DEFAULT_SOURCE    use with -std=c99 on Linux and PLATFORM_WEB, required for timespec

ifeq ($(BUILD_MODE),DEBUG) CFLAGS += -g -D_DEBUG else ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(BUILD_WEB_ASYNCIFY),TRUE) CFLAGS += -O3 else CFLAGS += -Os endif else CFLAGS += -s -O2 endif endif

ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),LINUX) ifeq ($(RAYLIB_LIBTYPE),STATIC) CFLAGS += -D_DEFAULT_SOURCE endif ifeq ($(RAYLIB_LIBTYPE),SHARED) # Explicitly enable runtime link to libraylib.so           CFLAGS += -Wl,-rpath,$(RAYLIB_RELEASE_PATH) endif endif endif ifeq ($(PLATFORM),PLATFORM_RPI) CFLAGS += -std=gnu99 endif ifeq ($(PLATFORM),PLATFORM_DRM) CFLAGS += -std=gnu99 -DEGL_NO_X11 endif
 * 1) Additional flags for compiler (if desired)
 * 2) CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes

INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external -I$(RAYLIB_PATH)/src/extras
 * 1) Define include paths for required headers: INCLUDE_PATHS
 * 2) NOTE: Some external/extras libraries could be required (stb, physac, easings...)

ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),BSD) INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) endif ifeq ($(PLATFORM_OS),LINUX) INCLUDE_PATHS += -I$(RAYLIB_INCLUDE_PATH) endif endif ifeq ($(PLATFORM),PLATFORM_RPI) INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vmcs_host/linux INCLUDE_PATHS += -I$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/include/interface/vcos/pthreads endif ifeq ($(PLATFORM),PLATFORM_DRM) INCLUDE_PATHS += -I/usr/include/libdrm endif ifeq ($(PLATFORM),PLATFORM_WEB) INCLUDE_PATHS += -I$(EMSCRIPTEN_PATH)/cache/sysroot/include endif
 * 1) Define additional directories containing required header files

LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src
 * 1) Define library paths containing required libs: LDFLAGS

ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) # NOTE: The resource .rc file contains windows executable icon and properties LDFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data # -Wl,--subsystem,windows hides the console window ifeq ($(BUILD_MODE), RELEASE) LDFLAGS += -Wl,--subsystem,windows endif endif ifeq ($(PLATFORM_OS),LINUX) LDFLAGS += -L$(RAYLIB_LIB_PATH) endif ifeq ($(PLATFORM_OS),BSD) LDFLAGS += -Lsrc -L$(RAYLIB_LIB_PATH) endif endif ifeq ($(PLATFORM),PLATFORM_WEB) # -Os                       # size optimization # -O2                       # optimization level 2, if used, also set --memory-init-file 0 # -s USE_GLFW=3             # Use glfw3 library (context/input management) # -s ALLOW_MEMORY_GROWTH=1  # to allow memory resizing -> WARNING: Audio buffers could FAIL! # -s TOTAL_MEMORY=16777216  # to specify heap memory size (default = 16MB) (67108864 = 64MB) # -s USE_PTHREADS=1         # multithreading support # -s WASM=0                 # disable Web Assembly, emitted by default # -s ASYNCIFY               # lets synchronous C/C++ code interact with asynchronous JS    # -s FORCE_FILESYSTEM=1      # force filesystem to load/save files data # -s ASSERTIONS=1           # enable runtime checks for common memory allocation errors (-O1 and above turn it off) # --profiling               # include information for code profiling # --memory-init-file 0      # to avoid an external memory initialization code file (.mem) # --preload-file resources  # specify a resources folder for data compilation # --source-map-base         # allow debugging in browser with source map LDFLAGS += -s USE_GLFW=3 -s TOTAL_MEMORY=$(BUILD_WEB_HEAP_SIZE) -s FORCE_FILESYSTEM=1 # Build using asyncify ifeq ($(BUILD_WEB_ASYNCIFY),TRUE) LDFLAGS += -s ASYNCIFY endif # Add resources building if required ifeq ($(BUILD_WEB_RESOURCES),TRUE) LDFLAGS += --preload-file $(BUILD_WEB_RESOURCES_PATH) endif # Add debug mode flags if required ifeq ($(BUILD_MODE),DEBUG) LDFLAGS += -s ASSERTIONS=1 --profiling endif

# Define a custom shell .html and output extension LDFLAGS += --shell-file $(BUILD_WEB_SHELL) EXT = .html endif ifeq ($(PLATFORM),PLATFORM_RPI) LDFLAGS += -L$(RPI_TOOLCHAIN_SYSROOT)/opt/vc/lib endif

ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) # Libraries for Windows desktop compilation # NOTE: WinMM library required to set high-res timer resolution LDLIBS = -lraylib -lopengl32 -lgdi32 -lwinmm # Required for physac examples LDLIBS += -static -lpthread endif ifeq ($(PLATFORM_OS),LINUX) # Libraries for Debian GNU/Linux desktop compiling # NOTE: Required packages: libegl1-mesa-dev LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt
 * 1) Define libraries required on linking: LDLIBS
 * 2) NOTE: To link libraries (lib .so or lib .a), use -l

# On X11 requires also below libraries LDLIBS += -lX11 # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor

# On Wayland windowing system, additional libraries requires ifeq ($(USE_WAYLAND_DISPLAY),TRUE) LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon endif # Explicit link to libc ifeq ($(RAYLIB_LIBTYPE),SHARED) LDLIBS += -lc endif endif ifeq ($(PLATFORM_OS),OSX) # Libraries for OSX 10.9 desktop compiling # NOTE: Required packages: libopenal-dev libegl1-mesa-dev LDLIBS = -lraylib -framework OpenGL -framework Cocoa -framework IOKit -framework CoreAudio -framework CoreVideo endif ifeq ($(PLATFORM_OS),BSD) # Libraries for FreeBSD, OpenBSD, NetBSD, DragonFly desktop compiling # NOTE: Required packages: mesa-libs LDLIBS = -lraylib -lGL -lpthread -lm

# On XWindow requires also below libraries LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor endif endif ifeq ($(PLATFORM),PLATFORM_RPI) # Libraries for Raspberry Pi compiling # NOTE: Required packages: libasound2-dev (ALSA) LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) LDLIBS += -lvchiq_arm -lvcos endif endif ifeq ($(PLATFORM),PLATFORM_DRM) # Libraries for DRM compiling # NOTE: Required packages: libasound2-dev (ALSA) LDLIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lgbm -ldrm -ldl endif ifeq ($(PLATFORM),PLATFORM_WEB) # Libraries for web (HTML5) compiling LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.a endif

PROJECT_SOURCE_FILES ?= \ raylib_game.c \ screen_logo.c \ screen_title.c \ screen_options.c \ screen_gameplay.c \ screen_ending.c
 * 1) Define source code object files required

OBJS = $(patsubst %.c, %.o, $(PROJECT_SOURCE_FILES))
 * 1) Define all object files from source files

ifeq ($(PLATFORM),PLATFORM_ANDROID) MAKEFILE_PARAMS = -f Makefile.Android export PROJECT_NAME export PROJECT_SOURCE_FILES else MAKEFILE_PARAMS = $(PROJECT_NAME) endif
 * 1) Define processes to execute
 * 2) For Android platform we call a custom Makefile.Android
 * 1) For Android platform we call a custom Makefile.Android

all: $(MAKE) $(MAKEFILE_PARAMS)
 * 1) Default target entry
 * 2) NOTE: We call this Makefile target or Makefile.Android target

$(PROJECT_NAME): $(OBJS) $(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM)
 * 1) Project target defined by PROJECT_NAME

%.o: %.c	$(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM)
 * 1) Compile source files
 * 2) NOTE: This pattern will compile every module defined on $(OBJS)

run: $(MAKE) $(MAKEFILE_PARAMS)

ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),WINDOWS) $(PROJECT_NAME) endif ifeq ($(PLATFORM_OS),LINUX) ./$(PROJECT_NAME) endif ifeq ($(PLATFORM_OS),OSX) ./$(PROJECT_NAME) endif endif

.PHONY: clean_shell_cmd clean_shell_sh

clean:	clean_shell_$(PLATFORM_SHELL) @echo Cleaning done
 * 1) Clean everything

clean_shell_sh: ifeq ($(PLATFORM),PLATFORM_DESKTOP) ifeq ($(PLATFORM_OS),LINUX) find. -type f -executable -delete rm -fv *.o   endif ifeq ($(PLATFORM_OS),OSX) find. -type f -perm +ugo+x -delete rm -f *.o   endif endif ifeq ($(PLATFORM),PLATFORM_RPI) find. -type f -executable -delete rm -fv *.o endif ifeq ($(PLATFORM),PLATFORM_DRM) find. -type f -executable -delete rm -fv *.o endif ifeq ($(PLATFORM),PLATFORM_WEB) ifeq ($(PLATFORM_OS),LINUX) rm -fv *.o $(PROJECT_NAME).data $(PROJECT_NAME).html $(PROJECT_NAME).js $(PROJECT_NAME).wasm endif ifeq ($(PLATFORM_OS),OSX) rm -f *.o $(PROJECT_NAME).data $(PROJECT_NAME).html $(PROJECT_NAME).js $(PROJECT_NAME).wasm endif endif

clean_shell_cmd: SHELL=cmd clean_shell_cmd: del *.o *.exe $(PROJECT_NAME).data $(PROJECT_NAME).html $(PROJECT_NAME).js $(PROJECT_NAME).wasm /s
 * 1) Set specific target variable

module: rcore

module: rshapes

module: rtextures

module: rtext

module: rmodels

module: raudio

structs

colors

module: raymath

rlgl5.h
Midless 3D Voxel, Simple M*necraft, [],

Misc
slowdown when running multiple 3d apps: this happens because of the GL semaphore "ping pong" between the tasks which can cause like >10000 task switches (and GL context switches) per second.

Semaphores are evil! It you have two or more tasks (3d apps) competing for sem then they get into ping pong state when a task is preempted while he owns the sem which is very likely. From then on (until a task switch happens while the sem is *not* locked) what will happen is that only one (GL) call can be made by task #1, then task switch to task #2 happens, which also can only make one (GL) call, then task switch to task #1 happens, which can only make one (GL) call, then task switch to task #2 happens, etc.

One solution to prevent this would be to have some GrabGL/UngrabGL (or ObtainGL,ReleaseGL if that sounds better) functions to be used in 3D apps and then enclose big parts of GL rendering function calls with it. GrabGL would lock the GL sem and make sure context is correct. ReleaseGL would unlock the GL sem. Even better would be if GrabGL switched all the GL functions (through function table) to versions which which don't use semlock/contextcheck/semunlock at all.

you must pass SDL_OPENGL to SDL_SetVideoMode, you must specify several GL attributes (depth buffer size, framebuffer sizes) using SDL_GL_SetAttribute and finally, if you wish to use double buffering you must specify it as a GL attribute, not by passing the SDL_DOUBLEBUF flag to SDL_SetVideoMode

using a double-buffered display, then you must use SDL_GL_SwapBuffers to swap the buffers and update the display. To request double-buffering with OpenGL, use SDL_GL_SetAttribute with SDL_GL_DOUBLEBUFFER, and use SDL_GL_GetAttribute to see if you actually got

Loaders may be required to help with different versions needs Lua based loading libraries with extensions, extensions,

Open Scene Graph claims OGL 3.x and 4.x support, but has some kind of weird LGPL based hybrid license. It's C++ based and they consider subclassing to be outside of the scope of the license. The hybrid LGPL-derived license has an exception which allows the shipment of statically linked binaries, so that eliminates one of the major objections to using the LGPL in commercial work.

Ogre has a new 3.3 renderer that seems to be a work in progress. Forum entries seem to indicate that "modern" shader architecture stuff for both OpenGL and DX11 are WIP. MIT license.

G3D has OpenGL 3.3 but only for Windows and OS X. They used to have Linux support but discontinued it due to too many distros to deal with. A recent mailing list post says they want to reinstate the support. BSD license.

ClanLib seems to support 3.3..4.3 but may not build. Zlib license.

Irrlicht claims OpenGL 3.x on their features page. Zlib license.

Cube 2 looks like OpenGL 2.x. Someone's working on something called Tesseract which might have more "dynamic lighting" capabilities, but it's unclear that this means 3.x+. Zlib license.

3D Physics – Qu3e, [ Bullet],

3D Game Engine – List of,

the bare minimum of a "modernized" engine are

Conditional rendering support (if the engine relies on occlusion queries, which many engines do, it should use conditional rendering as much as possible to avoid CPU-GPU sync points)

GPU based skeletal animation (many engines still use CPU side skinning, despite the technology for GPU based animation is there for a decade now)

Instancing support (especially for particles, vegetation and other similar stuff)

Uniform buffer support (remove all glUniform* calls, despite they are still in core, allows also for batching)

Texture array support (use them as much as possible, batch draw commands together)

The most important take away here is to batch. GL 3.x+ provides dozens of different tech to support this, unfortunately they go unused 99% of the time.

procedural map generation principles
Simple room placement, BSP room placement, BSP interiors, cellular automata, drunkard's walk, mazes, diffusion-limited aggregation, voronoi, wave function collapse wfc (e.g 2D sprite sheets, tiles placed in terrain maps to 3d objects into 3d spaces) with valid path placed beforehand to save backtracking, and prefabs

Symmetry, layering/combining generators, different corridor algorithms, and doors placement

Domain warping with perturb


 * 1) pragma once


 * 1) include "util/types.hpp"
 * 2) include "util/std.hpp"
 * 3) include "util/ndarray.hpp"
 * 4) include "util/collections.hpp"
 * 5) include "util/rand.hpp"
 * 6) include "util/hash.hpp"
 * 7) include "util/assert.hpp"
 * 8) include "util/bitset.hpp"
 * 9) include "util/result.hpp"
 * 10) include "util/omp.hpp"

namespace wfc { enum Flags { // add rotations of default patterns to pattern set FLAGS_ROTATE = 1 << 0,

// add reflections of default patterns to pattern set FLAGS_REFLECT = 1 << 1 };

// which pattern selection function to use enum class PatternFunction { WEIGHTED };

// which cell selection function to use enum class NextCellFunction { MIN_ENTROPY };

// behavior of borders for pattern calculation // EXCLUDE: any pattern which would include a border is not used // ZERO: borders have the value T(0) // CLAMP: borders are clamped to their nearest defined value // WRAP: borders are wrapped around the input data enum BorderBehavior { EXCLUDE, ZERO, CLAMP, WRAP };

// permute n-dimensional rotations of an array template  struct Rotator {};

template <> struct Rotator<2> { using V = ivec2;

// permutes rotations of src template    static inline std::array, 4> permute(        const std::array &src) { std::array, 4> dst; dst[0] = src; dst[1] = rotate_ccw(dst[0]); dst[2] = rotate_ccw(dst[1]); dst[3] = rotate_ccw(dst[2]); return dst; }

private: template    static inline std::array rotate(        const std::array &src) { std::array dst; for (usize i = 0; i < S; i++) { for (usize j = 0; j < S; j++) { ndarray::at(V(S), &dst[0], { i, j }) = ndarray::at(V(S), &src[0], { S - j - 1, i }); }       }        return dst; } };

// permutes n-dimensional reflections of an array template  struct Reflector { using V = math::vec;

template  static inline auto permute(       const std::array &src) { std::array<std::array<T, VOL>, math::cexp::pow(2, N)> dst;

// iterate over possible permutations of axes usize i = 0; ndarray::each(           V(2),            [&](const V &v) {                const auto which = math::vec<N, bool, math::defaultp>(v);                dst[i] = src;                for (usize j = 0; j < N; j++) {                    if (which[j]) {                        dst[i] = reflect_axis<T, S>(dst[i], j);                    }                }                i++;            });

return dst; }

private: template <typename T, usize S, usize VOL = math::cexp::pow(S, N)> static inline auto reflect_axis(       const std::array<T, VOL> &src, usize axis) { std::array<T, VOL> dst; ndarray::each(           V(S),            [&](const V &v) {                V u = v;                u[axis] = S - u[axis] - 1;                ndarray::at(V(S), &dst[0], v) =                    ndarray::at(V(S), &src[0], u);            }); return dst; } };

// neighbors in N dimensions template <usize N> struct Neighbors {};

template <> struct Neighbors<2> { static constexpr std::array<ivec2, 4> neighbors = {           ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1), }; };

template <> struct Neighbors<3> { static constexpr std::array<ivec3, 9> neighbors = {           ivec3(-1, 0, 0), ivec3(1, 0, 0), ivec3(0, -1, 0), ivec3(0, 1, 0), ivec3(0, 0, -1), ivec3(0, 0, 1), }; };

// implements n-dimensional wave function collapse with the "overlapping model" // T: pattern data type // N: number of dimension // S: size of patterns (MUST BE ODD!) // D: bitset size // V (defaulted): ivecN template < typename T,   usize N,    usize S,    usize D,    typename V = math::vec<N, int, math::defaultp>> requires ((S % 2) == 1) struct WFC { // forward declarations struct Pattern; struct Element; struct Wave;

// function which takes current wave and returns next cell to collapse using NextCellFn = std::function<Element&(Wave&)>;

// function which chooses the pattern to collapse a cell to   using PatternFn = std::function<usize(Wave&, Element&)>;

// function used for optional callbacks during collapse process using CallbackFn = std::function<void(const Wave&)>;

// S ** N (volume of one pattern) static constexpr auto VOL = math::cexp::pow(S, N);

// pattern derived from input data struct Pattern { // unique pattern ID       usize id;

// normalized frequency of this pattern in input data f32 frequency;

// value at the center of this pattern T value;

// pattern data std::array<T, VOL> data;

// valid neighbors on each side of this pattern std::array<Bitset<D>, 2 * N> valid;

explicit Pattern(const std::array<T, VOL> &data) : data(data), value(ndarray::at(V(S), &data[0], V(S) / 2)) {}

// NOTE: comparison is on data only auto operator<=>(const Pattern &other) const { return (*this) == other ? std::strong_ordering::equal : this->hash <=> other.hash; }

// NOTE: equality comparison is on data only bool operator==(const Pattern &other) const { return this->hash == other.hash && this->data == other.data; }

inline u64 hash const { if (this->_hash) { return this->_hash; }

u64 v = 0x12345; for (const auto &x : this->data) { v ^= x + 0x9e3779b9 + (v << 6) + (v >> 2); }           return this->_hash = v;        }

private: // stored hash, only calculated once mutable u64 _hash = 0; };

// wave element struct Element { // position in output space V pos;

// coefficient, marked bits are VALID choices Bitset<D> c;

// number of valid bits remaining usize popcnt;

// value post-collapse (std::nullopt if not collapsed) std::optional<T> value = std::nullopt;

// memoized entropy values f32 sum_weights = 0.0f; f32 sum_weight_log_weights = 0.0f; f32 entropy = 0.0f;

// intialize entropy values, coefficient void init(const Wave &w, const Bitset<D> &mask) { this->c = mask; this->popcnt = this->c.popcnt;

for (               auto it = this->c.begin_on;                it != this->c.end_on;                it++) { const auto weight = w.wfc.patterns[*it].frequency; this->sum_weights += weight; this->sum_weight_log_weights += weight * std::log(weight); }       }

// applies a mask to this element's coefficient, updating memoized // entropy values // returns false on failure (0 popcnt/contradiction) bool apply(const Wave &w, const Bitset<D> &mask) { // get bits which are on in the current coefficient but off in the // new mask. exit early if nothing changes. const auto diff = this->c & mask; if (diff.popcnt == 0) { return true; }

this->c &= mask;

for (               auto it = diff.begin_on;                it != diff.end_on;                it++) { const auto weight = w.wfc.patterns[*it].frequency; this->sum_weights -= weight; this->sum_weight_log_weights -= weight * std::log(weight); }

this->entropy = std::log(this->sum_weights) - (this->sum_weight_log_weights / this->sum_weights); this->popcnt = this->c.popcnt; return this->popcnt != 0; }

// collapse this element to pattern n       bool collapse(usize n, const T &value) { if (!this->c[n]) { return false; }

this->value = value; this->c.reset; this->c.set(n); this->popcnt = 1; this->entropy = 0.0f; this->sum_weights = 0.0f; this->sum_weight_log_weights = 0.0f; return true; }

// returns true if this element is collapsed bool collapsed const { return static_cast (this->value); }   };

// wave to collapse struct Wave { const WFC &wfc;

// size of output wave V size_wave;

// output wave elements std::vector<Element> wave;

// optional preset values const std::optional<T> *preset;

// total number of collapsed elements usize num_collapsed = 0;

Wave(           const WFC &wfc,            const V &size_wave,            const std::optional<T> *preset = nullptr) : wfc(wfc), size_wave(size_wave), preset(preset) {}

// collapses the specified wave element to the only remaining // possibility, or n if specified result::Result<void, V> collapse(           Element &e,            usize n = std::numeric_limits ::max) { n = (n == std::numeric_limits ::max) ? e.c.nth_set(0) : n;

const auto &p = this->wfc.patterns[n]; if (!e.collapse(n, p.value)) { return result::Err(e.pos); }

this->num_collapsed++; return result::Ok; }

// observe specified wave element, collapsing it to one of its possible // values result::Result<void, V> observe(Element &e) { const auto n = this->wfc.pattern_fn(*this, e); return this->collapse(e, n); }

// propagate the current value of the specified wave element // returns Ok on success, erroneous position V on failure // (contradiction) result::Result<void, V> propagate(Element &to_propagate) { // DFS elements to update std::stack<Element*> es; es.push(to_propagate);

// if not std::nullopt, there is an unresolvable contradiction in           // the wave std::optional<V> contradiction = std::nullopt;

// propagate each stack entry to neighbors while (!es.empty) { auto &e = *es.top; es.pop;

// get only valid non-collapsed neighbors std::array<Element*, N * 2> neighbors; for (usize i = 0; i < N * 2; i++) { neighbors[i] = nullptr;

const auto &n = Neighbors<N>::neighbors[i]; const auto pos_n = e.pos + n;

if (!ndarray::in_bounds(this->size_wave, pos_n)) { continue; }

auto &e_n = ndarray::at(                           this->size_wave,                            &this->wave[0],                            pos_n);

if (e_n.collapsed) { continue; }

neighbors[i] = &e_n; }

// compute superpatterns for valid neighbors std::array<Bitset<D>, N * 2> neighbor_patterns; for (                   auto it = e.c.begin_on;                    it != e.c.end_on;                    it++) { const auto &p = this->wfc.patterns[*it]; for (usize i = 0; i < N * 2; i++) { if (neighbors[i]) { neighbor_patterns[i] |= p.valid[i]; }                   }                }

// apply superpatterns for (usize i = 0; i < N * 2; i++) { if (!neighbors[i]) { continue; }

auto &e_n = *neighbors[i]; const auto popcnt_old = e_n.popcnt; e_n.apply(*this, neighbor_patterns[i]);

if (e_n.popcnt != popcnt_old) { if (e_n.popcnt == 0) { // zero popcount = failure/contradiction this->collapse(e_n, 0); contradiction = e_n.pos; break; } else if (e_n.popcnt == 1) { // one popcount = one remaining possibility/collapse auto res = this->collapse(e_n); if (res.isErr) { return res; }                       }

// propagate changed value es.push(&e_n); }               }            }

if (contradiction) { return result::Err(*contradiction); }

if (this->wfc.on_propagate) { (*this->wfc.on_propagate)(*this); }

return result::Ok; }

// collapse the wave result::Result<void, V> collapse { // initialize the wave, all patterns are valid for each element this->wave = std::vector<Element>(math::prod(this->size_wave));

// safe to parallelize, only one element modified at a time #pragma omp parallel for for (usize i = 0; i < this->wave.size; i++) { auto &e = this->wave[i]; e.pos = ndarray::unravel_index(this->size_wave, i); e.init(*this, this->wfc.mask_used); }

// load preset values if present if (this->preset) { ndarray::each(                   this->size_wave,                    [&](const V &pos) {                        const auto &p =                            ndarray::at(this->size_wave, &this->preset[0], pos);                        if (p) {                            auto &e =                                ndarray::at( this->size_wave, &this->wave[0], pos);                           e.value = *p;                        }                    }); }

// collapse the wave while (this->num_collapsed != this->wave.size) { auto &e = this->wfc.next_cell_fn(*this);

const auto res_observe = this->observe(e); if (res_observe.isErr) { return res_observe; }

const auto res_prop = this->propagate(e); if (res_prop.isErr) { return res_prop; }           }

// success! return result::Ok; }   };

// size of input data V size_in;

// input data const T *in;

// possible patterns std::vector<Pattern> patterns;

// function to select pattern to collapse to   PatternFn pattern_fn;

// function to select next cell to collapse NextCellFn next_cell_fn;

// behavior of patterns on borders BorderBehavior border_behavior;

// mask of used bits of coefficient bitsets // bits are also zeroed for disallowed patterns (patterns without valid   // neighbors) Bitset<D> mask_used;

// random generator Rand rand;

// options usize flags;

// optional callback to be called after propagation of each collapsed wave // element std::optional<CallbackFn> on_propagate = std::nullopt;

explicit WFC(       const V &size_in,        const T *in,        PatternFunction pattern_function,        NextCellFunction next_cell_function,        BorderBehavior border_behavior,        Rand &&rand,        usize flags) : size_in(size_in), in(in), border_behavior(border_behavior), rand(std::move(rand)), flags(flags) { // get pattern data from input at specified location // returns std::nullopt if pattern is made illegal by border behavior const auto data_at = [&](const V &center) -> std::optional<std::array<T, VOL>> { const auto base = center - (V(S) / 2);

if (border_behavior == BorderBehavior::EXCLUDE) { if (!ndarray::in_bounds(size_in, base)                           || !ndarray::in_bounds(size_in, base + V(S) - 1)) { return std::nullopt; }               }

std::array<T, VOL> dst; ndarray::each(                   V(S),                    [&](const V &offset) {                        std::optional<T> override = std::nullopt;                        V pos = base + offset;

switch (border_behavior) { case BorderBehavior::EXCLUDE: break; case BorderBehavior::ZERO: if (!ndarray::in_bounds(size_in, pos)) { override = T(0); }                               break; case BorderBehavior::CLAMP: pos = math::clamp(pos, V(0), size_in - V(1)); break; case BorderBehavior::WRAP: pos = ((pos % size_in) + size_in) % size_in; break; };

ndarray::at(V(S), &dst[0], offset) = override ? *override : ndarray::at(size_in, in, pos); });               return std::make_optional(dst);            };

// slide along input data creating patterns ndarray::each(           size_in,            [&](const V &p) {                if (const auto data = data_at(p)) {                    this->patterns.emplace_back(Pattern(data));                }            });

// calculate per-pattern frequencies (normalization occurs later once       // patterns have been deduplicated) std::unordered_map<u64, usize> pattern_hash_to_freq; for (const auto &p : this->patterns) { pattern_hash_to_freq[p.hash]++; }

// assign base frequencies (again, not normalized) for (auto &p : this->patterns) { p.frequency = static_cast (pattern_hash_to_freq[p.hash]); }

// removes duplicate patterns from this->patterns const auto deduplicate = [&] {               std::sort(this->patterns.begin, this->patterns.end); this->patterns.erase(                   std::unique(this->patterns.begin, this->patterns.end),                    this->patterns.end); };

// remove duplicate patterns deduplicate;

// add rotations, reflections const auto base_patterns = this->patterns; this->patterns.clear; for (const auto &p : base_patterns) { this->patterns.push_back(p);

if (flags & FLAGS_ROTATE) { ASSERT(N == 2, "can only rotate patterns in 2 dimensions"); if constexpr (N == 2) { const auto permutations = Rotator<N>::template permute<T, S>(p.data); for (usize i = 1; i < permutations.size; i++) { auto &q = this->patterns.emplace_back(                               pattern(permutations[i])); q.frequency = p.frequency; }               }            }            if (flags & FLAGS_REFLECT) { const auto permutations = Reflector<N>::template permute<T, S>(p.data); for (usize i = 1; i < permutations.size; i++) { auto &q = this->patterns.emplace_back(                           pattern(permutations[i])); q.frequency = p.frequency; }           }        }

// deduplicate again to remove duplicates added by reflection/rotation deduplicate;

// normalize pattern frequencies, pattern set will no longer change f32 frequency_total = 0.0f; for (const auto &p : this->patterns) { frequency_total += p.frequency; }

for (auto &p : this->patterns) { p.frequency /= frequency_total; }

// compute used mask, assign IDs this->mask_used.reset; for (usize i = 0; i < this->patterns.size; i++) { this->patterns[i].id = i;           this->mask_used.set(i); }

// compuate valid patterns around each pattern (adjacency) // check against all overlapping slots for each pattern pair (p, q) for // every side //       // safe to parallelize on p because only p is being written to and not // read from :)       #pragma omp parallel for        for (auto &p : this->patterns) {            for (const auto &q : this->patterns) {                for (usize i = 0; i < 2 * N; i++) {                    const auto &n = Neighbors<N>::neighbors[i];                    bool valid = true;                    ndarray::each( V(S), [&](const auto &offset_q) { if (!valid) { return; }

// compute offset into p's data const auto offset_p = n + offset_q; if (!ndarray::in_bounds(V(S), offset_p)) { return; }

const auto v_p = ndarray::at(V(S), &p.data[0], offset_p), v_q = ndarray::at(V(S), &q.data[0], offset_q);

// data must be equal at each offset for patterns to                           // match (be valid neighbors) if (v_p != v_q) { valid = false; }                       });

if (valid) { p.valid[i].set(q.id); }               }            }        }

switch (pattern_function) { case PatternFunction::WEIGHTED: this->pattern_fn = this->pattern_weighted; break; }

switch (next_cell_fn) { case NextCellFunction::MIN_ENTROPY: this->next_cell_fn = this->next_cell_min_entropy; break; }   }

// collapses a wave into the specified output // returns true on success bool collapse(       const V &size_out,        T *out,        const std::optional<T> *preset = nullptr) const { auto w = Wave(*this, size_out, preset); const auto res = w.collapse; if (res.isErr) { return false; }

// map elements to output ndarray::each(           w.size_wave,            [&](const V &pos) {                ndarray::at(size_out, out, pos) =                    *ndarray::at(size_out, &w.wave, pos).value;            });

return true; }

// returns a function which selects a pattern based on the distribution of   // patterns in the input data PatternFn pattern_weighted { return [&](Wave &w, Element &e) -> usize { f32 sum_cs = 0.0f; std::vector cs(this->patterns.size); for (               auto it = e.c.begin_on;                it != e.c.end_on;                it++) { cs[*it] = this->patterns[*it].frequency; sum_cs += cs[*it]; }

const auto r = this->rand.template next (0.0f, sum_cs); f32 acc = 0.0f; for (usize i = 0; i < cs.size; i++) { acc += cs[i];

if (acc >= r) { return i;               } }

ASSERT(false, "failed to select pattern for {}", e.pos); return e.c.nth_set(0); };   }

// returns a function which selects the next cell based on finding the cell // with the minimum entropy in those remaining NextCellFn next_cell_min_entropy { return [&](Wave &w) -> Element& { f32 min = 1e4; Element *argmin = nullptr;

// min entropy with a bit of noise for (auto &e : w.wave) { if (!e.collapsed                       && e.entropy < min                        && e.entropy + rand.next (0.0f, 1e-6) < min) { argmin = &e; }           }

ASSERT(argmin); return *argmin; };   } }; }

isometric grid view
Grid is rotated 45 deg and height reduced 50%

func cartesian_to_isometric(vector): return Vector2(vector.x - vector.y, (vector.x + vector.y) / 2) When a character moves in one direction in the isometric system, always moves both on the X and Y axis in the game.

// These are the four numbers that define the transform, i hat and j hat const i_x = 1; const i_y = 0.5; const j_x = -1; const j_y = 0.5;

// Sprite size const w = 32; const h = 32;

function to_screen_coordinate(tile: Vector2) { // Without accounting for sprite size return { x: tile.x * i_x + tile.y * j_x, y: tile.x * i_y + tile.y * j_y, }

// Accounting for sprite size return { x: tile.x * i_x * 0.5 * w + tile.y * j_x * 0.5 * w,   y: tile.x * i_y * 0.5 * h + tile.y * j_y * 0.5 * h,  } }

// Going from screen coordinate to grid coordinate

function invert_matrix(a, b, c, d) { // Determinant const det = (1 / (a * d - b * c)); return { a: det * d,   b: det * -b, c: det * -c, d: det * a, } }

function to_grid_coordinate(screen: Vector2) { const a = i_x * 0.5 * w; const b = j_x * 0.5 * w;  const c = i_y * 0.5 * h;  const d = j_y * 0.5 * h;  const inv = invert_matrix(a, b, c, d); return { x: screen.x * inv.a + screen.y * inv.b,   y: screen.x * inv.c + screen.y * inv.d,  } }

You have to manage the game data as if you were creating a top-down title, and you must then convert all the positions and motion vectors to render the characters and the levels properly


 * 1) include <raylib.h>
 * 2) include <raymath.h>


 * 1) define GRID_WIDTH 8
 * 2) define GRID_HEIGHT 8
 * 3) define TILE_SIZE 64
 * 4) define PLAYER_SPEED 1
 * 5) define SCREEN_WIDTH 640
 * 6) define SCREEN_HEIGHT 480

// Define tile types (add more as needed) enum TileType { TILE_FLOOR = 0, TILE_WALL, TILE_TREE, TILE_WATER, TILE_ELEVATION, // New tile type for elevation TILE_GRASS, };

int playerX = 0; int playerY = 0;

// 3D array representing the isometric grid with tile types and elevation int grid[GRID_WIDTH][GRID_HEIGHT][2] = {0}; // Initialize with all floor tiles at elevation 0

// Function to convert grid coordinates to screen coordinates Vector2 GridToScreen(int x, int y, int elevation) { Vector2 screenPos; screenPos.x = (x - y) * (TILE_SIZE / 2); screenPos.y = (x + y) * (TILE_SIZE / 4) - elevation * (TILE_SIZE / 2); return screenPos; }

// Function to check if the player can move to the specified grid position bool CanMoveTo(int x, int y) { if (x < 0 || x >= GRID_WIDTH || y < 0 || y >= GRID_HEIGHT) { // Out of bounds return false; }

// Check the tile type and elevation at the specified grid position int tileType = grid[x][y][0]; int elevation = grid[x][y][1];

// Check if the target tile has an elevation of 1 or is flat ground (elevation 0) if (elevation == 1 || elevation == 0) { // If the tile is a wall or tree, return false if (tileType == TILE_WALL || tileType == TILE_TREE) { return false; }

return true; // Otherwise, the player can move to this tile }

// Check if the player is moving from elevation 1 to elevation 2 or vice versa int currentElevation = grid[playerX][playerY][1]; if ((currentElevation == 1 && elevation == 2) || (currentElevation == 2 && elevation == 1)){ return true; }

return false; // Elevation is 2 or higher, and it's not a valid move from elevation 0 }

int main { InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Isometric Grid with Raylib"); SetTargetFPS(60);

// Place wall tiles at specific locations with elevation 1 (you can change these as needed) grid[2][5][0] = TILE_WALL; grid[3][1][0] = TILE_WALL; grid[4][3][0] = TILE_WALL; grid[2][4][0] = TILE_WALL; grid[3][3][0] = TILE_WALL;

// Add other tile types (e.g., tree, water, grass) at specific locations and elevations grid[1][3][0] = TILE_TREE; grid[6][4][0] = TILE_TREE; grid[4][1][0] = TILE_WATER; grid[0][7][0] = TILE_ELEVATION; // Elevation at (0, 7) represented by the rock tile grid[7][0][0] = TILE_GRASS;

// Set the elevation value for the tile representing the rock elevation grid[0][7][1] = 1; // Elevation level of 1 for the rock tile grid[1][7][1] = 2; // Elevation level of 1 for the rock tile

// Load textures Texture2D floorTexture    = LoadTexture("images/floorTile.png"); Texture2D wallTexture     = LoadTexture("images/wallTile.png"); Texture2D playerTexture   = LoadTexture("images/playerTile.png"); Texture2D treeTexture     = LoadTexture("images/treeTile.png"); Texture2D waterTexture    = LoadTexture("images/waterTile.png"); Texture2D elevationTexture = LoadTexture("images/rockTile.png"); // Texture for elevation (rock tile) Texture2D grassTexture    = LoadTexture("images/grassTile.png");

while (!WindowShouldClose) { // Handle player movement if (IsKeyPressed(KEY_W) && CanMoveTo(playerX, playerY - 1)) { playerY -= PLAYER_SPEED; }       if (IsKeyPressed(KEY_A) && CanMoveTo(playerX - 1, playerY)) { playerX -= PLAYER_SPEED; }       if (IsKeyPressed(KEY_S) && CanMoveTo(playerX, playerY + 1)) { playerY += PLAYER_SPEED; }       if (IsKeyPressed(KEY_D) && CanMoveTo(playerX + 1, playerY)) { playerX += PLAYER_SPEED; }

// Ensure the player stays within the grid boundaries playerX = Clamp(playerX, 0, GRID_WIDTH - 1); playerY = Clamp(playerY, 0, GRID_HEIGHT - 1);

BeginDrawing; ClearBackground(BLACK);

// Render tiles from back to front (lower y-axis first) for (int y = 0; y < GRID_HEIGHT; y++) { for (int x = 0; x < GRID_WIDTH; x++) { Vector2 screenPos = GridToScreen(x, y, grid[x][y][1]); // Use the elevation value

// Render the tile at grid[x][y] at (screenPos.x, screenPos.y)               switch (grid[x][y][0]) { case TILE_WALL: DrawTexture(wallTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE); break; case TILE_TREE: DrawTexture(treeTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE); break; case TILE_WATER: DrawTexture(waterTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE); break; case TILE_ELEVATION: DrawTexture(elevationTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE); break; case TILE_GRASS: DrawTexture(grassTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE); break; default: DrawTexture(floorTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE); break; }

// Render the player if (x == playerX && y == playerY) { DrawTexture(playerTexture, screenPos.x + SCREEN_WIDTH / 2, screenPos.y, WHITE); }           }        }

EndDrawing; }

// Unload textures UnloadTexture(floorTexture); UnloadTexture(wallTexture); UnloadTexture(playerTexture); UnloadTexture(treeTexture); UnloadTexture(waterTexture); UnloadTexture(elevationTexture); UnloadTexture(grassTexture);

CloseWindow;

return 0; }


 * 1) include <SDL2/SDL.h>
 * 2) include <SDL2/SDL_image.h>
 * 3) include <SDL2/SDL_ttf.h>
 * 4) include


 * 1) define WIDTH 920
 * 2) define HEIGHT 620
 * 3) define FONT_SIZE 32
 * 4) define TILE_SIZE 64

struct object { SDL_Rect dest, src; SDL_Texture* img; };

object grid[12][12]; object selected;

bool running;

SDL_Renderer* renderer; SDL_Window* window; TTF_Font *font; SDL_Color fcolor;

SDL_Point mouse; int frameCount, timerFPS, lastFrame, fps;

SDL_Texture* setImage(std::string filename) { return IMG_LoadTexture(renderer, filename.c_str); }

void draw(object o) { SDL_RenderCopyEx(renderer, o.img, &o.src, &o.dest, 0, NULL, SDL_FLIP_NONE); }

SDL_Surface *surface; SDL_Texture *texture; SDL_Rect wrect; void write(std::string text, int x, int y) { if (font == NULL) { fprintf(stderr, "error: font not found\n"); exit(EXIT_FAILURE); } fcolor.r = 0; fcolor.g = 0; fcolor.b = 0; const char* t = text.c_str; surface = TTF_RenderText_Solid(font, t, fcolor); texture = SDL_CreateTextureFromSurface(renderer, surface); wrect.w = surface->w; wrect.h = surface->h; wrect.x = x-wrect.w; wrect.y = y-wrect.h; SDL_FreeSurface(surface); SDL_RenderCopy(renderer, texture, NULL, &wrect); SDL_DestroyTexture(texture); }

void update { }

const Uint8 *keystates; void input { SDL_Event e;   keystates = SDL_GetKeyboardState(NULL); while(SDL_PollEvent(&e)) { if(e.type == SDL_QUIT) running=false; }   if(keystates[SDL_SCANCODE_ESCAPE]) running=false;

SDL_GetMouseState(&mouse.x, &mouse.y); }

bool touching; std::string m; void render { SDL_SetRenderDrawColor(renderer, 240, 240, 240, 255); SDL_RenderClear(renderer);

frameCount++; int timerFPS = SDL_GetTicks-lastFrame; if(timerFPS<(1000/60)) { SDL_Delay((1000/60)-timerFPS); }

touching=0; for(int i=0; i<12; i++) { for(int j=0; j<12; j++) { draw(grid[i][j]); if(SDL_PointInRect(&mouse, &grid[i][j].dest)) { m = std::to_string(i) + " " + std::to_string(j); selected.dest = grid[i][j].dest; touching=1; //SDL_RenderDrawRect(renderer, &grid[i][j].dest); }    }    }    if(touching) { draw(selected); write(m, mouse.x, mouse.y); }

SDL_RenderPresent(renderer); }

void init { object tile; tile.img=setImage("res/block.png"); tile.src.w=32;tile.src.h=32; tile.src.x=tile.src.y=0; tile.dest.w=TILE_SIZE; tile.dest.h=TILE_SIZE; for(int i=0; i<12; i++) { for(int j=0; j<12; j++) { tile.dest.x=(i*TILE_SIZE - j*TILE_SIZE)/2 + 426; tile.dest.y=(j*TILE_SIZE + i*TILE_SIZE)/4 + 140; grid[i][j]=tile; } } selected=tile; selected.img=setImage("res/select.png"); }

int main { running=1; static int lastTime=0; SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); if(SDL_Init(SDL_INIT_EVERYTHING) < 0) std::cout << "Failed at SDL_Init" << std::endl; if(SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, 0, &window, &renderer) < 0) std::cout << "Failed at SDL_CreateWindowAndRenderer" << std::endl; SDL_SetWindowTitle(window, "Isometric Grid"); TTF_Init; font = TTF_OpenFont("res/BebasNeue.ttf", FONT_SIZE); if(font == NULL) std::cout << "failed to load font" << std::endl;

init;

while(running) { lastFrame=SDL_GetTicks; if(lastFrame>=(lastTime+1000)) { lastTime=lastFrame; fps=frameCount; frameCount=0; }

update; input; render; }   TTF_CloseFont(font); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit; }

invert matrix

// These are the four numbers that define the transform, i hat and j hat const i_x = 1; const i_y = 0.5; const j_x = -1; const j_y = 0.5;

// Sprite size const w = 32; const h = 32;

function to_screen_coordinate(tile: Vector2) { // Without accounting for sprite size return { x: tile.x * i_x + tile.y * j_x, y: tile.x * i_y + tile.y * j_y, }

// Accounting for sprite size return { x: tile.x * i_x * 0.5 * w + tile.y * j_x * 0.5 * w,   y: tile.x * i_y * 0.5 * h + tile.y * j_y * 0.5 * h,  } }

// Going from screen coordinate to grid coordinate

function invert_matrix(a, b, c, d) { // Determinant const det = (1 / (a * d - b * c)); return { a: det * d,   b: det * -b, c: det * -c, d: det * a, } }

function to_grid_coordinate(screen: Vector2) { const a = i_x * 0.5 * w; const b = j_x * 0.5 * w;  const c = i_y * 0.5 * h;  const d = j_y * 0.5 * h;  const inv = invert_matrix(a, b, c, d); return { x: screen.x * inv.a + screen.y * inv.b,   y: screen.x * inv.c + screen.y * inv.d,  } }

rhythm
Simple scroll in C, [], [],

breakout clones
3D in C++, [], [],

pathfinding
From ,

metroidvania
Topology - Abilities and Upgrades - Secrets and Misc - Locks and Keys

Macro Top down design - Overworld - Area - Room


 * Overworld, critical points and necessary destinations
 * Area,
 * Main routes, Landmarks, POI,
 * Storyboard and events
 * Landscapes and Lore

Game design document GDD
Top 100 games have over 90% market share

Concept (marketing hook in order of difficulty) - '''gamestyle with gamestyle but ... ''' rhythm, text, visual novel, platformer, endless runner, mazes, tower defense, puzzle, city builder, adventure, party, shoot 'em up, metrovania, bullet hell, beat 'em up, walking sim on rails, card deck builder, cooking, racing, fighter, tactical turn based, real time strategy rts long term, relationships, survival, collectothon, fps, sandbox, management simulator, trading, sports, betting, rogue, roguelite, roguelike, dungeon crawler, rpg, horror, souls, soulslite, soulslike, battle royale, arena,

Similar games - same ... look / feel / genre / scope / target avatar audience

Measurement (Scale) - how the character / enemies interact, like reach, swing, grab, etc

Prototype - ugly grey box version, mock ups, concepts, screenshots, color schemes, logo, fonts, etc

10min demo - vertical slice for funding, getting initial impressions about good bits, poor ideas, missing parts, etc i.e playtesting

Fun like overcoming obstacles challenges, progression (quests logs to do lists) and rewards, sense of wonder

Design Patterns - finite state machines (behaviors through states entities transitions), event bus singleton (manage signals from objects), entity component patterns (building blocks)

Game Play Loop - , extraction, looter shooter,

Mechanics
 * Walls, Spikes,, etc

Story - Narrative, storyline,

Shipping
 * game jam to limit scope and allow completion within 1 week with clean code
 * then expand to 3,4 and 6 month cycles later as you gain experience and knowledge, later 9 or 12 months max to gain experience and stay focused

design process - Empathize: Research user needs - Define: State user needs and problems - Refine: Challenge assumptions and create ideas - Prototype: Start to create solutions - Test: Try out solutions

Examples in C C++
Languages in 3 Hours, [], [],

Raylib Pong Video with, Pong Tutorial C++, [],

C game template, game premake, Asteroids in C raylib, Catch items in C, [],

bullet hell, [], [],

Puzzle,

, Co-ordinates,, [],

C++ RPG simple, C++ RPG simple, c++ dungeon crawler, [],

2D and 3D examples, Stars c++, [], [],

Car physics rally, pdf, [],

Simple AI Maze runner, [], [],

wfc in c, [],

GL_VERSION: 1.4 Mesa 7.11 GL_EXTENSIONS: GL_ARB_multisample GL_EXT_abgr GL_EXT_bgra GL_EXT_blend_color GL_EXT_blend_logic_op GL_EXT_blend_minmax GL_EXT_blend_subtract GL_EXT_copy_texture GL_EXT_polygon_offset GL_EXT_subtexture GL_EXT_texture_object GL_EXT_vertex_array GL_EXT_compiled_vertex_array GL_EXT_texture GL_EXT_texture3D GL_IBM_rasterpos_clip GL_ARB_point_parameters GL_EXT_draw_range_elements GL_EXT_packed_pixels GL_EXT_point_parameters GL_EXT_rescale_normal GL_EXT_separate_specular_color GL_EXT_texture_edge_clamp GL_SGIS_generate_mipmap GL_SGIS_texture_border_clamp GL_SGIS_texture_edge_clamp GL_SGIS_texture_lod GL_ARB_multitexture GL_IBM_multimode_draw_arrays GL_IBM_texture_mirrored_repeat GL_ARB_texture_cube_map GL_ARB_texture_env_add GL_ARB_transpose_matrix GL_EXT_blend_func_separate GL_EXT_fog_coord GL_EXT_multi_draw_arrays GL_EXT_secondary_color GL_EXT_texture_env_add GL_EXT_texture_filter_anisotropic GL_EXT_texture_lod_bias GL_INGR_blend_func_separate GL_NV_blend_square GL_NV_light_max_exponent GL_NV_texgen_reflection GL_NV_texture_env_combine4 GL_SUN_multi_draw_arrays GL_ARB_texture_border_clamp GL_ARB_texture_compression GL_EXT_framebuffer_object GL_EXT_texture_env_dot3 GL_MESA_window_pos GL_NV_packed_depth_stencil GL_NV_texture_rectangle GL_ARB_depth_texture GL_ARB_shadow GL_ARB_texture_env_combine GL_ARB_texture_env_crossbar GL_ARB_texture_env_dot3 GL_ARB_texture_mirrored_repeat GL_ARB_window_pos GL_EXT_stencil_two_side GL_EXT_texture_cube_map GL_APPLE_packed_pixels GL_APPLE_vertex_array_object GL_ARB_draw_buffers GL_ARB_fragment_program GL_ARB_vertex_program GL_ATI_draw_buffers GL_ATI_texture_env_combine3 GL_EXT_shadow_funcs GL_EXT_stencil_wrap GL_MESA_pack_invert GL_MESA_ycbcr_texture GL_NV_primitive_restart GL_ARB_fragment_program_shadow GL_ARB_half_float_pixel GL_ARB_point_sprite GL_ARB_sync GL_ARB_texture_non_power_of_two GL_ARB_vertex_buffer_object GL_OES_read_format GL_ARB_color_buffer_float GL_ARB_pixel_buffer_object GL_ARB_texture_rectangle GL_EXT_pixel_buffer_object GL_EXT_texture_rectangle GL_ARB_framebuffer_object GL_EXT_framebuffer_blit GL_EXT_framebuffer_multisample GL_EXT_packed_depth_stencil GL_ARB_vertex_array_object GL_ATI_separate_stencil GL_EXT_gpu_program_parameters GL_EXT_texture_env_combine GL_OES_EGL_image GL_ARB_copy_buffer GL_ARB_map_buffer_range GL_ARB_vertex_array_bgra GL_EXT_vertex_array_bgra GL_ARB_draw_elements_base_vertex GL_ARB_fragment_coord_conventions GL_ARB_provoking_vertex GL_ARB_sampler_objects GL_EXT_provoking_vertex GL_ARB_robustness GL_RENDERER: Gallium 0.4 on i915 (chipset: 915GM) GL_VENDOR: VMware, Inc. GLU_VERSION: 1.3 GLU_EXTENSIONS: GLU_EXT_nurbs_tessellator GLU_EXT_object_space_tess GLUT_API_VERSION: 5 GLUT_XLIB_IMPLEMENTATION: 15