shithub: tinygl

Download patch

ref: 2d8758d2ff5ec69fbb4c5d341fa35f0ffe6cd361
parent: 3ca166d5abe3e594626de355a000fdc911d18cee
author: David <gek@katherine>
date: Sat Feb 20 20:28:50 EST 2021

Added buffers

--- a/README.md
+++ b/README.md
@@ -89,7 +89,9 @@
 
 * Added glDrawArrays
 
+* Added Buffers
 
+
 Note that this Softrast **is not GL 1.1 compliant** and does not constitute a complete GL implementation.
 
 You *will* have to tweak your code to work with this library. That said, once you have, it will run anywhere that you can get
@@ -217,6 +219,13 @@
 This function can be added to display lists.
 
 Plot pixel directly to the buffer.
+
+### glGenBuffers, glDeleteBuffers, glBindBuffer (valid target: ARRAY_BUFFER), glBindBufferAsArray
+
+Serverside buffers! Makes it a bit easier to do clientside array stuff at the moment. 
+may be the site of future hardware acceleration.
+
+Please look at the model.c demo to see how to use these functions. They function very similarly to their GL 2.0+ counterparts.
 
 ## TOGGLEABLE FEATURES
 
--- a/SDL_Examples/model.c
+++ b/SDL_Examples/model.c
@@ -287,6 +287,7 @@
 	char needsRGBAFix = 0;
 	unsigned int count = 40;
 	GLuint modelDisplayList = 0;
+	GLuint buffers[4]; //pos,color,normal,texcoord
 	int dlExists = 0;
 	int doTextures = 1;
 	char* modelName = "extrude.obj";
@@ -438,6 +439,7 @@
 			dlExists = 1;
 			} else {
 				LoadModelArrays(m.d, m.npoints, m.c, m.n, m.t);
+				/*
 				if(ModelArray.colors)glEnableClientState(GL_COLOR_ARRAY);
 				if(ModelArray.points)glEnableClientState(GL_VERTEX_ARRAY);
 				if(ModelArray.normals)glEnableClientState(GL_NORMAL_ARRAY);
@@ -447,6 +449,47 @@
 				if(ModelArray.normals)glNormalPointer(GL_FLOAT,0,ModelArray.normals); //Must be 3!
 				if(ModelArray.colors)glColorPointer(3,GL_FLOAT,0,ModelArray.colors);
 				if(ModelArray.texcoords)glTexCoordPointer(2,GL_FLOAT,0,ModelArray.texcoords);
+				*/
+				glGenBuffers(4, buffers);
+				for(int i = 0; i < 4; i++){
+				printf("\nBuffer %d is %d", i , buffers[i]);
+					if(buffers[i] == 0){
+						printf("\nBuffer allocation failed for buffer %d!\n", i);
+						return 1;
+					}
+				}
+				glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
+				glBufferData(GL_ARRAY_BUFFER, 
+							sizeof(GLfloat) * 3 * ModelArray.npoints,
+							ModelArray.points,
+							GL_STATIC_DRAW);
+				if(glMapBuffer(GL_ARRAY_BUFFER,0) == NULL) 
+					printf("\nglBufferData failed for buffer %d!\n", 0);
+				glBindBufferAsArray(GL_VERTEX_BUFFER, buffers[0],GL_FLOAT,3,0);
+				if(ModelArray.colors){
+					glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
+					glBufferData(GL_ARRAY_BUFFER, 
+								sizeof(GLfloat) * 3 * ModelArray.npoints,
+								ModelArray.colors,
+								GL_STATIC_DRAW);
+					glBindBufferAsArray(GL_COLOR_BUFFER, buffers[1],GL_FLOAT,3,0);
+				}
+				if(ModelArray.normals){
+					glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
+					glBufferData(GL_ARRAY_BUFFER, 
+								sizeof(GLfloat) * 3 * ModelArray.npoints,
+								ModelArray.normals,
+								GL_STATIC_DRAW);
+					glBindBufferAsArray(GL_NORMAL_BUFFER, buffers[2],GL_FLOAT,3,0);
+				}
+				if(ModelArray.texcoords){
+					glBindBuffer(GL_ARRAY_BUFFER, buffers[3]);
+					glBufferData(GL_ARRAY_BUFFER, 
+								sizeof(GLfloat) * 2 * ModelArray.npoints,
+								ModelArray.texcoords,
+								GL_STATIC_DRAW);
+					glBindBufferAsArray(GL_TEXTURE_COORD_BUFFER,buffers[3],GL_FLOAT,2,0);
+				}
 			}
 			freemodel(&m);
 		}
--- a/config.mk
+++ b/config.mk
@@ -3,6 +3,7 @@
 
 CC= gcc
 CFLAGS= -Wall -O3 -g -std=c99 -Wno-undef -march=native -DNDEBUG
+#CFLAGS= -Wall -O1 -g -std=c99 -Wno-undef -DNDEBUG
 LFLAGS=
 
 
--- a/include/GL/gl.h
+++ b/include/GL/gl.h
@@ -46,12 +46,18 @@
 	GL_POLYGON			= 0x0009,
 	GL_EDGE_FLAG			= 0x0B43,
 
+	/* Necessary for glBufferData */
+	GL_STATIC_DRAW          = 0x88E4,	
 	/* Vertex Arrays */
 	GL_VERTEX_ARRAY			= 0x8074,
+	GL_VERTEX_BUFFER		= 0x8074,
 	GL_NORMAL_ARRAY			= 0x8075,
+	GL_NORMAL_BUFFER		= 0x8075,
 	GL_COLOR_ARRAY			= 0x8076,
+	GL_COLOR_BUFFER			= 0x8076,
 	GL_INDEX_ARRAY			= 0x8077,
 	GL_TEXTURE_COORD_ARRAY		= 0x8078,
+	GL_TEXTURE_COORD_BUFFER		= 0x8078,
 	GL_EDGE_FLAG_ARRAY		= 0x8079,
 	GL_VERTEX_ARRAY_SIZE		= 0x807A,
 	GL_VERTEX_ARRAY_TYPE		= 0x807B,
@@ -607,7 +613,8 @@
         GL_POLYGON_OFFSET_EXT           = 0x8037,
         GL_POLYGON_OFFSET_FACTOR_EXT    = 0x8038,
         GL_POLYGON_OFFSET_BIAS_EXT      = 0x8039,
-
+	/* GL */
+		GL_ARRAY_BUFFER                 = 0x8892,
 	/* GL_EXT_vertex_array */
 	GL_VERTEX_ARRAY_EXT		= 0x8074,
 	GL_NORMAL_ARRAY_EXT		= 0x8075,
@@ -880,6 +887,22 @@
                       const GLvoid *pointer);
 void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, 
                        const GLvoid *pointer);
+/* opengl 2.0 buffers */
+void glGenBuffers(	GLsizei n,
+ 					GLuint * buffers);
+void glDeleteBuffers(	GLsizei n,
+					 	const GLuint * buffers);
+void glBindBuffer(	GLenum target,
+ 					GLuint buffer);
+GLboolean glIsBuffer(	GLuint buffer);
+void *glMapBuffer(	GLenum target,
+				 	GLenum access);
+void glBufferData(	GLenum target,
+				 	GLsizei size,
+				 	const void * data,
+				 	GLenum usage);
+//Bonus ducks!
+void glBindBufferAsArray(GLenum target, GLuint buffer, GLenum type, GLint size, GLint stride);
 
 /* opengl 1.2 polygon offset */
 void glPolygonOffset(GLfloat factor, GLfloat units);
--- a/src/arrays.c
+++ b/src/arrays.c
@@ -7,6 +7,292 @@
 #define NORMAL_ARRAY 0x0004
 #define TEXCOORD_ARRAY 0x0008
 
+//Code for buffers is here too!
+
+
+GLint free_buffer(GLint handle){
+	GLContext* c = gl_get_context();
+	GLSharedState* s = &(c->shared_state);
+	if(handle == 0 || handle > MAX_BUFFERS) return 1; //error flag
+//HANDLE IS HENCEFORTH AN INDEX, AND NOT A HANDLE!!!
+	handle--;
+	if(s->buffers[handle]){ //if this handle exists...
+		if(c->boundarraybuffer == (handle+1)) c->boundarraybuffer = 0;
+		if(s->buffers[handle]->data) //if this handle has data...
+		{	
+			void* d = s->buffers[handle]->data;
+			gl_free(s->buffers[handle]->data); //free the data...
+			//deal with the possible bindings...
+			if(c->vertex_array == d) {c->vertex_array = NULL;c->client_states &= ~VERTEX_ARRAY;}
+			if(c->color_array == d) {c->color_array = NULL;c->client_states &= ~COLOR_ARRAY;}
+			if(c->normal_array == d) {c->normal_array = NULL;c->client_states &= ~NORMAL_ARRAY;}
+			if(c->texcoord_array == d) {c->texcoord_array = NULL;c->client_states &= ~TEXCOORD_ARRAY;}
+		}
+		gl_free(s->buffers[handle]); //free the buffer...
+		s->buffers[handle] = NULL; //Set it to null...
+		return 0;
+	} else {
+		return 0;
+	}
+}
+GLint check_buffer(GLint handle){ //1 means used, 0 means free, 2 means invalid
+	GLContext* c = gl_get_context();
+	GLSharedState* s = &(c->shared_state);
+	if(handle == 0 || handle > MAX_BUFFERS) return 2; //error flag
+	handle--;
+	if(s->buffers[handle]) return 1;
+	return 0;
+}
+GLboolean glIsBuffer(	GLuint buffer){
+	if(check_buffer(buffer) == 1) return GL_TRUE;
+	return GL_FALSE;
+}
+
+
+static inline GLBuffer* get_buffer(GLint handle){
+	GLContext* c = gl_get_context();
+	GLSharedState* s = &(c->shared_state);
+	if(handle == 0 || handle > MAX_BUFFERS) return NULL;
+	handle--;
+	return s->buffers[handle];
+}
+GLint create_buffer(GLint handle){
+	GLContext* c = gl_get_context();
+	GLSharedState* s = &(c->shared_state);
+	if(handle == 0 || handle > MAX_BUFFERS) return 1; //error flag
+	handle--;//convert from handle to index
+	if(s->buffers[handle])	free_buffer(handle+1); //this is no longer the handle so we have to add 1.
+	//This buffer is now free for usage!
+	s->buffers[handle] = gl_zalloc(sizeof(GLBuffer));
+	
+	if(!(s->buffers[handle])){
+#if TGL_FEATURE_ERROR_CHECK == 1
+#define ERROR_FLAG GL_OUT_OF_MEMORY
+#define RETVAL 1
+#include "error_check.h"
+#else
+		gl_fatal_error("GL_OUT_OF_MEMORY");
+#endif
+	}
+	s->buffers[handle]->data = NULL;
+	s->buffers[handle]->size = 0;
+	return 0;
+}
+
+void glGenBuffers(	GLsizei n,
+ 					GLuint * buffers)
+{
+	#include "error_check.h"
+	if(n > MAX_BUFFERS) goto error;
+
+	{	
+		GLint n_left = n;
+		GLuint names[n];
+		for(int i = 1; i <= MAX_BUFFERS && n_left > 0; i++)
+			if(!check_buffer(i)) names[(n_left--)-1] = i;
+
+		if(n_left) goto error; //We were unable to find enough free names.
+		for(int i = 0; i < n; i++){
+			create_buffer(names[i]);
+			
+//we have this error check here to quit out early in case of GL_OUT_OF_MEMORY
+#include "error_check.h"
+			buffers[i] = names[i];
+		}
+	}
+	return;
+	error:
+		for(int i = 0; i < n; i++)
+			buffers[i] = 0;
+		return;
+}
+void glDeleteBuffers(	GLsizei n,
+					 	const GLuint * buffers)
+{
+	#include "error_check.h"
+	for(GLint i = 0; i < n; i++) free_buffer(buffers[i]);
+}
+
+
+//TODO GL_ARRAY_BUFFER, at a minimum.
+void glBindBuffer(	GLenum target,
+ 					GLuint buffer)
+{
+	GLContext* c = gl_get_context();
+	#include "error_check.h"
+	if(buffer == 0 ||
+		check_buffer(buffer) == 1){
+		if(target == GL_ARRAY_BUFFER) c->boundarraybuffer = buffer;
+	}
+	return;
+}
+
+void glBindBufferAsArray(GLenum target, 
+						GLuint buffer,
+						GLenum type, //GL_FLOAT
+						GLint size, //number of floats
+						GLint stride){ //floats between items
+	GLContext* c = gl_get_context();
+	#include "error_check.h"
+	if(target != GL_VERTEX_BUFFER &&
+		target != GL_NORMAL_BUFFER &&
+		target != GL_COLOR_BUFFER &&
+		target != GL_TEXTURE_COORD_BUFFER){
+#if TGL_FEATURE_ERROR_CHECK == 1
+#define ERROR_FLAG GL_INVALID_ENUM
+#include "error_check.h"
+#else
+		return;
+#endif		
+
+	}
+	if(buffer == 0)
+		switch(target){
+			case GL_VERTEX_BUFFER:
+				glDisableClientState(GL_VERTEX_ARRAY);
+				glVertexPointer(size, type, stride, NULL);
+				c->boundvertexbuffer = buffer;
+				return;
+			break;
+			case GL_NORMAL_BUFFER:
+				glDisableClientState(GL_NORMAL_ARRAY);
+				glNormalPointer(type, stride, NULL);
+				c->boundnormalbuffer = buffer;
+				return;
+			break;
+			case GL_COLOR_BUFFER:
+				glDisableClientState(GL_COLOR_ARRAY);
+				glColorPointer(size, type, stride, NULL);
+				c->boundcolorbuffer = buffer;
+				return;
+			break;
+			case GL_TEXTURE_COORD_BUFFER:
+				glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+				glTexCoordPointer(size, type, stride, NULL);
+				c->boundtexcoordbuffer = buffer;
+				return;
+			break;
+			default:return;
+		}
+	if(check_buffer(buffer) != 1 ||
+		type != GL_FLOAT){
+#if TGL_FEATURE_ERROR_CHECK == 1
+#define ERROR_FLAG GL_INVALID_ENUM
+#include "error_check.h"
+#else
+		tgl_warning("\ncheck_buffer failed on buffer, or incorrect type\n");
+		return;
+#endif
+	}
+	GLBuffer* buf = c->shared_state.buffers[buffer-1];
+	if(!buf || (buf->data == NULL) || (buf->size == 0)){
+#if TGL_FEATURE_ERROR_CHECK == 1
+#define ERROR_FLAG GL_INVALID_OPERATION
+#include "error_check.h"
+#else
+		tgl_warning("\nbuffer was null, buffer data was null, or buffer size was 0\n");
+		return;
+#endif
+	}
+	switch(target){
+		case GL_VERTEX_BUFFER:
+			glEnableClientState(GL_VERTEX_ARRAY);
+			glVertexPointer(size, type, stride, buf->data);
+			c->boundvertexbuffer = buffer;
+		break;
+		case GL_NORMAL_BUFFER:
+			glEnableClientState(GL_NORMAL_ARRAY);
+			glNormalPointer(type, stride, buf->data);
+			c->boundnormalbuffer = buffer;
+		break;
+		case GL_COLOR_BUFFER:
+			glEnableClientState(GL_COLOR_ARRAY);
+			glColorPointer(size, type, stride, buf->data);
+			c->boundcolorbuffer = buffer;
+		break;
+		case GL_TEXTURE_COORD_BUFFER:
+			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+			glTexCoordPointer(size, type, stride, buf->data);
+			c->boundtexcoordbuffer = buffer;
+		break;
+
+		default:return;
+	}
+	return;
+}
+
+void *glMapBuffer(	GLenum target,
+				 	GLenum access)
+{
+	GLContext* c = gl_get_context();
+#define RETVAL NULL
+#include "error_check.h"
+	GLint handle = 0;
+	if(target == GL_ARRAY_BUFFER) handle = c->boundarraybuffer;
+	if(target == GL_VERTEX_BUFFER) handle = c->boundvertexbuffer;
+	if(target == GL_TEXTURE_COORD_BUFFER) handle = c->boundtexcoordbuffer;
+	if(target == GL_NORMAL_BUFFER) handle = c->boundnormalbuffer;
+	if(target == GL_COLOR_BUFFER) handle = c->boundcolorbuffer;
+	{
+		if(check_buffer(handle) == 1)
+			return c->shared_state.buffers[handle-1]->data;
+	}
+#if TGL_FEATURE_ERROR_CHECK == 1
+#define RETVAL NULL
+#define ERROR_FLAG GL_INVALID_ENUM
+#include "error_check.h"
+#else
+	return NULL;
+#endif
+}
+void glBufferData(	GLenum target,
+				 	GLsizei size,
+				 	const void * data,
+				 	GLenum usage) //Usage parameter is ignored.
+{
+	GLContext* c = gl_get_context();
+#include "error_check.h"
+	GLint handle = 0;
+	GLBuffer* buf = NULL;
+	if(target == GL_ARRAY_BUFFER) handle = c->boundarraybuffer;
+	if(target == GL_VERTEX_BUFFER) handle = c->boundvertexbuffer;
+	if(target == GL_TEXTURE_COORD_BUFFER) handle = c->boundtexcoordbuffer;
+	if(target == GL_NORMAL_BUFFER) handle = c->boundnormalbuffer;
+	if(target == GL_COLOR_BUFFER) handle = c->boundcolorbuffer;
+	if(check_buffer(handle) == 1)
+		buf = c->shared_state.buffers[handle-1];
+	else {
+#if TGL_FEATURE_ERROR_CHECK == 1
+#define ERROR_FLAG GL_INVALID_ENUM
+#include "error_check.h"
+#else
+		return;
+#endif
+	}
+	if(buf->data) gl_free(buf->data);
+	buf->data = NULL; buf->size = 0;
+	buf->data = gl_malloc(size);
+	buf->size = size;
+	if(!(buf->data)){
+#if TGL_FEATURE_ERROR_CHECK == 1
+#define ERROR_FLAG GL_OUT_OF_MEMORY
+#include "error_check.h"
+#else
+		gl_fatal_error("GL_OUT_OF_MEMORY")
+#endif
+	}
+	memcpy(buf->data, data, size);
+}
+
+
+
+
+
+
+
+
+
+
 void glopArrayElement(GLContext* c, GLParam* param) {
 	GLint i;
 	GLint states = c->client_states;
--- a/src/get.c
+++ b/src/get.c
@@ -170,6 +170,7 @@
 #if TGL_FEATURE_TINYGL_RUNTIME_COMPAT_TEST == 1
 "TGL_FEATURE_TINYGL_RUNTIME_COMPAT_TEST "
 #endif
+"TGL_BUFFER_EXT "
 "TGL_SOFTWARE_ACCELERATED";
 const GLubyte* glGetString(GLenum name){
 	switch(name){
--- a/src/init.c
+++ b/src/init.c
@@ -1,5 +1,5 @@
 #include "zgl.h"
-
+#include "msghandling.h"
 GLContext* gl_ctx;
 
 void initSharedState(GLContext* c) {
@@ -10,6 +10,9 @@
 	s->texture_hash_table = gl_zalloc(sizeof(GLTexture*) * TEXTURE_HASH_TABLE_SIZE);
 	if(!s->texture_hash_table)
 		gl_fatal_error("TINYGL_CANNOT_INIT_OOM");
+	s->buffers = gl_zalloc(sizeof(GLBuffer*) * MAX_BUFFERS);
+	if(!s->buffers)
+		gl_fatal_error("TINYGL_CANNOT_INIT_OOM");
 	alloc_texture(c, 0);
 #include "error_check.h"
 }
@@ -61,6 +64,17 @@
 		}
 	}
 	gl_free(s->texture_hash_table);
+	for(i = 0; i < MAX_BUFFERS; i++){
+		if(s->buffers[i])
+		{
+			//tgl_warning("\nFound a buffer that needs deleting! its handle is %d\n",i+1);
+			if(s->buffers[i]->data){
+				gl_free(s->buffers[i]->data);
+				//tgl_warning("\nIt has data too! its handle is %d\n",i+1);
+			}
+			gl_free(s->buffers[i]);
+		}
+	}
 }
 
 #if TGL_FEATURE_TINYGL_RUNTIME_COMPAT_TEST == 1
@@ -121,6 +135,12 @@
 	initSharedState(c);
 	/* ztext */
 	c->textsize = 1;
+	/* buffer */
+	c->boundarraybuffer = 0; //no bound buffer
+	c->boundvertexbuffer = 0; //no bound buffer
+	c->boundcolorbuffer = 0; //no bound buffer
+	c->boundnormalbuffer = 0; //no bound buffer
+	c->boundtexcoordbuffer = 0; //no bound buffer
 	/* lists */
 
 	c->exec_flag = 1;
--- a/src/texture.c
+++ b/src/texture.c
@@ -6,7 +6,6 @@
 
 static GLTexture* find_texture(GLContext* c, GLint h) {
 	GLTexture* t;
-
 	t = c->shared_state.texture_hash_table[h % TEXTURE_HASH_TABLE_SIZE];
 	while (t != NULL) {
 		if (t->handle == h)
--- a/src/zgl.h
+++ b/src/zgl.h
@@ -7,6 +7,8 @@
 #include <assert.h>
 #include <math.h>
 #include <stdlib.h>
+//Needed for memcpy
+#include <string.h>
 #ifndef M_PI
 #define M_PI 3.14159265358979323
 #endif
@@ -50,6 +52,8 @@
 #define TGL_OFFSET_LINE 0x2
 #define TGL_OFFSET_POINT 0x4
 
+
+
 typedef struct GLSpecBuf {
 	GLint shininess_i;
 	GLint last_used;
@@ -134,7 +138,6 @@
 /* textures */
 
 #define TEXTURE_HASH_TABLE_SIZE 256
-
 typedef struct GLTexture {
 	GLImage images[MAX_TEXTURE_LEVELS];
 	GLint handle;
@@ -141,11 +144,18 @@
 	struct GLTexture *next, *prev;
 } GLTexture;
 
-/* shared state */
+/* buffers */
+#define MAX_BUFFERS 2048
+typedef struct GLBuffer{
+	void* data;
+	GLuint size;
+} GLBuffer;
 
+/* shared state */
 typedef struct GLSharedState {
 	GLList** lists;
 	GLTexture** texture_hash_table;
+	GLBuffer** buffers;
 } GLSharedState;
 
 struct GLContext;
@@ -285,6 +295,13 @@
 
 	/* text */
 	GLTEXTSIZE textsize;
+
+	/* buffers */
+	GLint boundarraybuffer; //0 if no buffer is bound.
+	GLint boundvertexbuffer;
+	GLint boundnormalbuffer;
+	GLint boundcolorbuffer;
+	GLint boundtexcoordbuffer;
 } GLContext;
 
 extern GLContext* gl_ctx;