From 6e78d00e2e0d67d5f9bd831b5440e1b477402c41 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 11 Oct 2022 02:16:52 +0300 Subject: [PATCH] initial commit --- .gitignore | 4 ++ Makefile | 24 +++++++ src/glfb.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/glfb.h | 32 +++++++++ src/main.c | 97 +++++++++++++++++++++++++++ 5 files changed, 371 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 src/glfb.c create mode 100644 src/glfb.h create mode 100644 src/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98742ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.d +*.swp +voxscape diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..816dbac --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +dep = $(src:.c=.d) +bin = voxscape + +warn = -pedantic -Wall +#opt = -O3 +dbg = -g + +CFLAGS = $(warn) $(opt) $(dbg) -MMD +LDFLAGS = -lGL -lglut -lm + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +-include $(dep) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) + +.PHONY: cleandep +cleandep: + rm -f $(dep) diff --git a/src/glfb.c b/src/glfb.c new file mode 100644 index 0000000..c60715d --- /dev/null +++ b/src/glfb.c @@ -0,0 +1,214 @@ +#include +#include +#include +#include +#include "glfb.h" + +static void conv_idx8(void *pixels); +static void conv_rgb15(void *pixels); +static void conv_rgb16(void *pixels); +static void conv_rgb24(void *pixels); +static void conv_rgba32(void *pixels); +static unsigned int next_pow2(unsigned int x); + +static int width, height, scansz; +static enum glfb_pixel_format pixfmt; +static unsigned int min_filt = GL_NEAREST, mag_filt = GL_NEAREST; +static uint32_t *convbuf; +static int convbuf_size; + +static uint32_t cmap[256]; + +static unsigned int tex; +static int tex_width, tex_height; +static float tex_sx, tex_sy; + +static void (*convert[])(void*) = { + conv_idx8, conv_rgb15, conv_rgb16, conv_rgb24, conv_rgba32 +}; + + +void glfb_setup(int x, int y, enum glfb_pixel_format fmt, int pitch) +{ + int tx, ty, newsz; + + tx = next_pow2(x); + ty = next_pow2(y); + + if(!tex || tx < tex_width || ty < height || fmt != pixfmt) { + if(!tex) { + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filt); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filt); + glEnable(GL_TEXTURE_2D); + } + glBindTexture(GL_TEXTURE_2D, tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx, ty, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + + tex_width = tx; + tex_height = ty; + } + + tex_sx = (float)x / tex_width; + tex_sy = (float)y / tex_height; + + scansz = pitch; + + newsz = x * y * 4; + if(convbuf_size < newsz) { + free(convbuf); + if(!(convbuf = malloc(newsz))) { + fprintf(stderr, "glfb: failed to allocate conversion buffer\n"); + convbuf = 0; + } + convbuf_size = newsz; + } + + width = x; + height = y; + pixfmt = fmt; +} + +void glfb_filter(enum glfb_filter filt) +{ + switch(filt) { + case GLFB_NEAREST: + min_filt = mag_filt = GL_NEAREST; + break; + case GLFB_LINEAR: + min_filt = mag_filt = GL_LINEAR; + break; + } +} + + +void glfb_color(int idx, int r, int g, int b) +{ + if(idx < 0 || idx >= 255) return; + + cmap[idx] = (b << 16) | (g << 8) | r; +} + +void glfb_update(void *pixels) +{ + convert[pixfmt](pixels); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, convbuf); +} + +void glfb_display(void) +{ + glBegin(GL_TRIANGLES); + glTexCoord2f(0, 0); + glVertex2f(-1, -1); + glTexCoord2f(tex_sx * 2.0f, 0); + glVertex2f(4, -1); + glTexCoord2f(0, tex_sy * 2.0f); + glVertex2f(-1, 4); + glEnd(); +} + +static void conv_idx8(void *pixels) +{ + int i, j; + unsigned char *sptr = pixels; + uint32_t *dptr = convbuf; + + for(i=0; i> 2) | ((pix >> 5) & 7); + b = ((pix & 0x7c00) >> 7) | ((pix >> 10) & 7); + *dptr++ = r | (g << 8) | (b << 16); + } + sptr = (uint16_t*)((char*)sptr + scansz); + } +} + +static void conv_rgb16(void *pixels) +{ + int i, j; + uint16_t pix; + uint32_t r, g, b; + uint16_t *sptr = pixels; + uint32_t *dptr = convbuf; + + for(i=0; i> 3) | ((pix >> 5) & 3); + b = ((pix & 0xf800) >> 8) | ((pix >> 11) & 7); + *dptr++ = r | (g << 8) | (b << 16); + } + sptr = (uint16_t*)((char*)sptr + scansz); + } +} + +static void conv_rgb24(void *pixels) +{ + int i, j; + uint32_t r, g, b; + unsigned char *sptr, *scanptr = pixels; + uint32_t *dptr = convbuf; + + for(i=0; i> 16) & 0xff; + g = (pix >> 8) & 0xff; + b = pix & 0xff; + *dptr++ = r | (g << 8) | (b << 16); + } + sptr = (uint32_t*)((char*)sptr + scansz); + } +} + +static unsigned int next_pow2(unsigned int x) +{ + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x + 1; +} + diff --git a/src/glfb.h b/src/glfb.h new file mode 100644 index 0000000..9936a27 --- /dev/null +++ b/src/glfb.h @@ -0,0 +1,32 @@ +#ifndef OPENGL_FRAMEBUFFER_H_ +#define OPENGL_FRAMEBUFFER_H_ + +/* show pixels with OpenGL + * + * Usage example: + * glfb_setup(width, height, GLFB_RGBA32, width * 4); + * ... + * glfb_update(pixels); + * glfb_display(); + */ + +enum glfb_pixel_format { + GLFB_IDX8, + GLFB_RGB15, /* 555 */ + GLFB_RGB16, /* 565 */ + GLFB_RGB24, /* 888 */ + GLFB_RGBA32 /* 8888 (alpha ignored) */ +}; + +enum glfb_filter { + GLFB_NEAREST, + GLFB_LINEAR +}; + +void glfb_setup(int x, int y, enum glfb_pixel_format fmt, int pitch); +void glfb_filter(enum glfb_filter filt); +void glfb_color(int idx, int r, int g, int b); +void glfb_update(void *pixels); +void glfb_display(void); + +#endif /* OPENGL_FRAMEBUFFER_H_ */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a2440af --- /dev/null +++ b/src/main.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include +#include "glfb.h" + +int init(void); +void display(void); +void idle(void); +void reshape(int x, int y); +void keyb(unsigned char key, int x, int y); + +int win_width, win_height; + +#define FB_W 640 +#define FB_H 480 +unsigned int fb[FB_W * FB_H]; + + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowSize(1280, 960); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("voxel landscape test"); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyb); + glutIdleFunc(idle); + + if(init() == -1) { + return 1; + } + + glutMainLoop(); + return 0; +} + + +int init(void) +{ + int i, j, xor, r, g, b; + unsigned int *ptr; + + ptr = fb; + for(i=0; i> 1) & 0xff; + g = xor & 0xff; + b = (xor << 1) & 0xff; + *ptr++ = b | (g << 8) | (r << 16); + } + } + + win_width = glutGet(GLUT_WINDOW_WIDTH); + win_height = glutGet(GLUT_WINDOW_HEIGHT); + + glfb_setup(FB_W, FB_H, GLFB_RGBA32, FB_W * 4); + return 0; +} + +void display(void) +{ + glfb_update(fb); + glfb_display(); + + glutSwapBuffers(); + assert(glGetError() == GL_NO_ERROR); +} + +void idle(void) +{ + glutPostRedisplay(); +} + +void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + + win_width = x; + win_height = y; +} + +void keyb(unsigned char key, int x, int y) +{ + switch(key) { + case 27: + exit(0); + + default: + break; + } +} -- 1.7.10.4