From a1b4c92da5f1b9de5e9c289c0fd37ba060bf5377 Mon Sep 17 00:00:00 2001 From: Kamil Kaminski Date: Wed, 27 Jul 2011 11:47:44 -0500 Subject: initial commit, ported from sdl repo --- Makefile | 25 ++++ mingw32 | 45 +++++++ vbo.c | 450 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 520 insertions(+) create mode 100644 Makefile create mode 100644 mingw32 create mode 100644 vbo.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3b3f939 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +PROG = vbo +OBJS = $(PROG).o +CC = gcc +DBGFLAGS = -g -O0 +ifdef DEBUG + CFLAGS = $(DBGFLAGS) -Wall -std=c99 +else + CFLAGS = -Wall -std=c99 -O2 -march=native -mtune=native +endif +LDFLAGS = -lGLEW -lGL -lGLU -lm -lglut +SDL_CFLAGS := $(shell sdl-config --cflags) +SDL_LDFLAGS := $(shell sdl-config --libs) +SDL_image_CFLAGS := $(shell pkg-config --cflags SDL_image) +SDL_image_LDFLAGS := $(shell pkg-config --libs SDL_image) + +$(PROG): $(OBJS) + $(CC) $(LDFLAGS) $(SDL_LDFLAGS) $(SDL_image_LDFLAGS) $(OBJS) -o $(PROG) + +$(PROG).o: $(PROG).c + $(CC) -c $(CFLAGS) $(SDL_CFLAGS) $(SDL_image_CFLAGS) $(PROG).c + +.PHONY: clean + +clean: + rm -f *.o ./$(PROG) diff --git a/mingw32 b/mingw32 new file mode 100644 index 0000000..b03c73d --- /dev/null +++ b/mingw32 @@ -0,0 +1,45 @@ +BIN = vbo +SRC = vbo.c +CC = gcc +CFLAGS = -Wall -std=c99 -MD +DBGFLAGS = -g -O0 +ifdef DEBUG + CFLAGS += $(DBGFLAGS) +else + CFLAGS += -O2 -march=native -mtune=native +endif +LDFLAGS = -lglew32 -lopengl32 -lglu32 -lm -lfreeglut -lmingw32 -lsdlmain -lsdl \ + -lsdl_image -mwindows + +OBJ_DIR = obj +DEPS_DIR = obj +BIN_DIR = . + +C_FILES = $(filter %.c, $(SRC)) +DEP_FILES = $(addprefix $(DEPS_DIR)\, $(addsuffix .d, $(notdir $(subst .c,,$(SRC))))) +OBJ_FILES = $(addprefix $(OBJ_DIR)\, $(addsuffix .o, $(notdir $(subst .c,,$(SRC))))) + +INCL = -I/include + +define C_template +$(1): $(2) + @mkdir -p $$(OBJ_DIR) + @mkdir -p $$(DEPS_DIR) + $$(CC) -c $$(CFLAGS) $$(INCL) $$< -o $$@ +endef + +all: $(BIN) + +$(foreach cfile, $(C_FILES), $(eval $(call C_template, $(OBJ_DIR)\$(notdir $(subst .c,,$(cfile))).o, $(cfile)))) + +$(BIN): $(OBJ_FILES) + @mkdir -p $(BIN_DIR) + $(CC) -o $(BIN_DIR)/$@ $(OBJ_FILES) $(LDFLAGS) + +.PHONY: clean + +clean: + rm -rf $(OBJ_DIR) + rm -f $(BIN_DIR)/$(BIN).exe stdout.txt stderr.txt + +-include $(DEP_FILES) diff --git a/vbo.c b/vbo.c new file mode 100644 index 0000000..3206188 --- /dev/null +++ b/vbo.c @@ -0,0 +1,450 @@ +/* vbo.c + * + * Kamil Kaminski + * kkaminsk.com + * + * Example of using VBO + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_OFFSET(i) ((char *)NULL + (i)) + +/* for simplicity we pack */ +#pragma pack(1) +typedef struct vbo_slice +{ + GLfloat normal[3]; + GLfloat texcoord[2]; + GLubyte color[3]; +} vbo_slice_t; +#pragma pack() + +/* globals */ +int program_running = 1; +SDL_Surface *screen; +GLuint buffer_objects[3]; + +/* few light arrays */ +const GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 1.0f }; +const GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f }; +const GLfloat fMedLight[] = { 0.50f, 0.50f, 0.50f, 1.0f }; +const GLfloat fShinyLight[] = { 0.70f, 0.70f, 0.70f, 1.0f }; +const GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + +/* light values and coordinates */ +const GLfloat lightPos[] = { -10.f, 5.0f, 5.0f, 1.0f }; + +/* function prototypes */ +static void gltErrorCheck(void); +static void resize(int, int); +static void setup_opengl(void); +static void keys(SDL_keysym *, unsigned int *); +static void process_events(void); +static void render(void); +static void setup_sdl(void); +static void setup_glew(void); +static void setup_opengl(void); + +/* we have a separate buffer objects for vertex data, attributes, and indices + * gl*Pointer gets assiociated with currently binded buffer + * interleaved arrays improve cache performance, the key is locality + */ +static int gltGenVBOInterleaved(GLuint *bufferobjects, float *vert_arr, + float *texcoord_arr, float *norm_arr, unsigned char *color_arr, + unsigned short *indices_arr, size_t points_n, size_t indices_n) +{ + /* skip error check for now */ + + /* create an interleaved data structure, is it worth the cpu time? */ + size_t attrib_buff_sz = ((points_n * (3+2) * sizeof(GLfloat)) + + (points_n * 3 * sizeof(GLubyte))); + + if ((attrib_buff_sz % sizeof(vbo_slice_t)) != 0) + { + fprintf(stderr, "gen_vbo: fatal, vbo_slice_t appears to be padded!\n"); + exit(-1); + } + + size_t slices_n = attrib_buff_sz / sizeof(vbo_slice_t); + + vbo_slice_t *vbo_slices_arr = (vbo_slice_t *) malloc(attrib_buff_sz); + if (!vbo_slices_arr) + { + perror("malloc"); + exit(-1); + } + + /* build interleaved data structure, may not be cache friendly */ + int i; + for (i = 0; i < slices_n; i++) + { + vbo_slices_arr[i].normal[0] = norm_arr[i * 3 + 0]; + vbo_slices_arr[i].normal[1] = norm_arr[i * 3 + 1]; + vbo_slices_arr[i].normal[2] = norm_arr[i * 3 + 2]; + vbo_slices_arr[i].texcoord[0] = texcoord_arr[i * 2 + 0]; + vbo_slices_arr[i].texcoord[1] = texcoord_arr[i * 2 + 1]; + vbo_slices_arr[i].color[0] = color_arr[i * 3 + 0]; + vbo_slices_arr[i].color[1] = color_arr[i * 3 + 1]; + vbo_slices_arr[i].color[2] = color_arr[i * 3 + 2]; + } + + glGenBuffers(3, bufferobjects); + + /* vertex data */ + glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[0]); + glBufferData(GL_ARRAY_BUFFER, points_n * 3 * sizeof(float), (const GLvoid *) vert_arr, GL_STATIC_DRAW); + + /* attribute data, normals, texcoords, and color */ + glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[1]); + glBufferData(GL_ARRAY_BUFFER, attrib_buff_sz, (const GLvoid *) vbo_slices_arr, GL_STATIC_DRAW); + + /* indices data */ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferobjects[2]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * indices_n, (const GLvoid *) indices_arr, GL_STATIC_DRAW); + + return 0; +} + +static int gltDrawVBOInterleaved(GLuint *bufferobjects, size_t indices_n) +{ + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + /* vertex data */ + glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[0]); + glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)); + + /* attribute data, normals, texcoords, and color */ + glBindBuffer(GL_ARRAY_BUFFER, bufferobjects[1]); + glNormalPointer(GL_FLOAT, sizeof(vbo_slice_t), BUFFER_OFFSET(0)); + glClientActiveTexture(GL_TEXTURE0); + glTexCoordPointer(2, GL_FLOAT, sizeof(vbo_slice_t), BUFFER_OFFSET(sizeof(GLfloat) * 3)); + glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(vbo_slice_t), BUFFER_OFFSET(sizeof(GLfloat) * 5)); + + /* indices data */ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferobjects[2]); + glDrawElements(GL_TRIANGLES, indices_n, GL_UNSIGNED_SHORT, 0); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + return 0; +} + +static void gltErrorCheck(void) +{ + GLenum err_code; + const GLubyte *err_str; + + while ((err_code = glGetError()) != GL_NO_ERROR) + { + err_str = gluErrorString(err_code); + fprintf(stderr, "OpenGL error: %s\n", err_str); + } +} + +static void resize(int w, int h) +{ + printf("window: resizing to %dx%d\n", w, h); + GLfloat fAspect = (GLfloat) w / (GLfloat) h; + if (h == 0) + h = 1; + glViewport(0, 0, w, h); + + /* reset coordinate system */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + /* produce the perspective projection */ + /* void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) */ + gluPerspective(40.0f, fAspect, 1.0, 40.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + /* this needs to be ran again, glut does it for you I suppose */ + SDL_SetVideoMode(w, h, 32, SDL_OPENGL | SDL_RESIZABLE); +} + +static void setup_opengl(void) +{ + /* setup fog */ + glEnable(GL_FOG); + glFogfv(GL_FOG_COLOR, fLowLight); /* set fog color to match background */ + glFogf(GL_FOG_START, 4.0f); + glFogf(GL_FOG_END, 20.0f); + glFogi(GL_FOG_MODE, GL_LINEAR); /* fog equation */ + + glEnable(GL_DEPTH_TEST); /* hidden surface removal, aka Z-buffer */ + glFrontFace(GL_CCW); /* counter clock-wise polygons face out */ + glEnable(GL_CULL_FACE); /* do not calculate inside of a pyramid */ + + /* enable lighting, primitives now need to define color properties */ + glEnable(GL_LIGHTING); + + /* global illumination, ambient RGBA intensity of the entire scene */ + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fLowLight); + + /* setup and enable light 0 */ + glLightfv(GL_LIGHT0, GL_AMBIENT, fMedLight); + glLightfv(GL_LIGHT0, GL_DIFFUSE, fShinyLight); + glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight); + glLightfv(GL_LIGHT0, GL_POSITION, lightPos); + glEnable(GL_LIGHT0); + + /* set material properties to follow all glColor values */ + /* all primitives specified after the glMaterial call are affected by the + * last values set, until another call to glMaterial is made */ + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + + /* enable color tracking, should be called after glColorMaterial */ + glEnable(GL_COLOR_MATERIAL); + + /* set globally, sets specular reflection to a white color, + * this call follows all subsequent primitives */ + glMaterialfv(GL_FRONT, GL_SPECULAR, fBrightLight); + + /* default (0), by increasing this value you reduce the size and increase + * the focus of the specular highlight, causing a shiny spot to appear */ + glMateriali(GL_FRONT, GL_SHININESS, 64); + + /* multisampling for polygons, conflicts with *polygon* anti-aliasing */ + /* enabled by default, that's what man page says, hmmm! */ + glEnable(GL_MULTISAMPLE); + + /* AA is disabled, but we will keep the blending function and hints though */ + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + + /* anisotropic filtering */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8); + + /* how OpenGL combines the colors from texels with the color of the underlying + * geometry is controlled by the texture environment mode */ + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + /* once texture is loaded and enabled, it will applied to every primitive + * that specifies coordinates, ORLY? */ + glEnable(GL_TEXTURE_2D); + + /* specular highlights for textured items */ + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); + + /* gray background */ + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); +} + +static void keys(SDL_keysym *keysym, unsigned int *keys_held) +{ + switch (keysym->sym) + { + case SDLK_ESCAPE: + program_running = 0; + break; + default: + break; + } +} + +/* process SDL events */ +static void process_events(void) +{ + SDL_Event event; + unsigned static int keys_held[323]; + SDLKey sym; + + while (SDL_PollEvent(&event)) + { + sym = event.key.keysym.sym; + + switch (event.type) + { + case SDL_KEYUP: + { + /* reset the key to 0 */ + keys_held[sym] = 0; + break; + } + case SDL_KEYDOWN: + { + keys_held[sym] = 1; + keys(&event.key.keysym, keys_held); + break; + } + case SDL_VIDEORESIZE: + { + resize(event.resize.w, event.resize.h); + break; + } + case SDL_QUIT: + { + program_running = 0; + break; + } + default: + break; + } + } +} + +static void render(void) +{ + /* clear the window with current clearing color */ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* save the matrix state */ + glPushMatrix(); + { + /* draw ground using immiediate mode */ + glDisable(GL_MULTISAMPLE); + glEnable(GL_BLEND); + glEnable(GL_LINE_SMOOTH); + + GLfloat fExtent = 20.0f; + GLfloat fStep = 0.5f; + GLfloat y = -0.4f; + GLfloat iLine; + + glLineWidth(1.0f); + glBegin(GL_LINES); + for (iLine = -fExtent; iLine <= fExtent; iLine += fStep) + { + glVertex3f(iLine, y, fExtent); + glVertex3f(iLine, y, -fExtent); + glVertex3f(fExtent, y, iLine); + glVertex3f(-fExtent, y, iLine); + } + glEnd(); + + glDisable(GL_LINE_SMOOTH); + glDisable(GL_BLEND); + glEnable(GL_MULTISAMPLE); + /* end of ground */ + + glPushMatrix(); + /* draw vbo */ + glTranslatef(0.0f, 0.0f, -4.0f); + gltDrawVBOInterleaved(buffer_objects, 3); + glPopMatrix(); + } + /* restore the matrix state */ + glPopMatrix(); + + /* buffer swap */ + SDL_GL_SwapBuffers(); +} + +static void setup_sdl(void) +{ + if (SDL_Init(SDL_INIT_VIDEO) < 0 ) + { + fprintf(stderr, "SDL: unable to init, %s\n", SDL_GetError()); + exit(-1); + } + atexit(SDL_Quit); + SDL_WM_SetCaption("SDL", NULL); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + + if ((screen = SDL_SetVideoMode(640, 480, 32, SDL_OPENGL | SDL_RESIZABLE)) == NULL) + { + fprintf(stderr, "SDL: unable to set video mode: %s\n", SDL_GetError()); + exit(-1); + } + + SDL_EnableUNICODE(1); + /* SDL doesn't trigger off a ResizeEvent at startup, but as we need this + * for OpenGL, we do this ourselves */ + SDL_Event resizeEvent; + resizeEvent.type = SDL_VIDEORESIZE; + resizeEvent.resize.w = 640; + resizeEvent.resize.h = 480; + SDL_PushEvent(&resizeEvent); +} + +static void setup_glew(void) +{ + /* initalize glew */ + GLenum glewerr = glewInit(); + if (GLEW_OK != glewerr) + { + fprintf(stderr, "GLEW error: %s\n", glewGetErrorString(glewerr)); + exit(-1); + } + else + fprintf(stdout, "GLEW: using version %s\n", glewGetString(GLEW_VERSION)); + + /* display OpenGL version */ + GLint major; + GLint minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + fprintf(stdout, "GLEW: initialized OpenGL %d.%d\n", major, minor); +} + +int main(int argc, char **argv) +{ + setup_sdl(); + setup_glew(); + setup_opengl(); + gltErrorCheck(); + + /* setup a vbo */ + float vert_arr[9] = { 0.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.5f, 0.66f, 0.0f }; + + float norm_arr[9] = { 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f }; + + float texcoord_arr[6] = { 0.0f, 0.0f, + 1.0f, 0.0f, + 0.5f, 1.0f }; + + unsigned char color_arr[9] = { 255, 0, 0, + 0, 255, 0, + 0, 0, 255 }; + + unsigned short indices_arr[3] = { 0, 1, 2 }; + + gltGenVBOInterleaved(buffer_objects, vert_arr, texcoord_arr, norm_arr, color_arr, + indices_arr, 3, 3); + gltErrorCheck(); + + while (program_running) + { + process_events(); + render(); + } + + gltErrorCheck(); + glDeleteBuffers(3, buffer_objects); + if (screen) + SDL_FreeSurface(screen); + + puts("bye!"); + + return 0; +} + -- cgit v1.2.3