initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 10 Oct 2022 23:16:52 +0000 (02:16 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 10 Oct 2022 23:16:52 +0000 (02:16 +0300)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
src/glfb.c [new file with mode: 0644]
src/glfb.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..98742ce
--- /dev/null
@@ -0,0 +1,4 @@
+*.o
+*.d
+*.swp
+voxscape
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..c60715d
--- /dev/null
@@ -0,0 +1,214 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <GL/gl.h>
+#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<height; i++) {
+               for(j=0; j<width; j++) {
+                       *dptr++ = cmap[sptr[j]];
+               }
+               sptr += scansz;
+       }
+}
+
+static void conv_rgb15(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<height; i++) {
+               for(j=0; j<width; j++) {
+                       pix = sptr[j];
+                       r = ((pix & 0x1f) << 3) | (pix & 7);
+                       g = ((pix & 0x3e0) >> 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<height; i++) {
+               for(j=0; j<width; j++) {
+                       pix = sptr[j];
+                       r = ((pix & 0x1f) << 3) | (pix & 7);
+                       g = ((pix & 0x7e0) >> 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<height; i++) {
+               sptr = scanptr;
+               for(j=0; j<width; j++) {
+                       r = sptr[0];
+                       g = sptr[1];
+                       b = sptr[2];
+                       sptr += 3;
+                       *dptr++ = r | (g << 8) | (b << 16);
+               }
+               scanptr += scansz;
+       }
+}
+
+static void conv_rgba32(void *pixels)
+{
+       int i, j;
+       uint32_t pix, r, g, b;
+       uint32_t *sptr = pixels;
+       uint32_t *dptr = convbuf;
+
+       for(i=0; i<height; i++) {
+               for(j=0; j<width; j++) {
+                       pix = sptr[j];
+                       r = (pix >> 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 (file)
index 0000000..9936a27
--- /dev/null
@@ -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 (file)
index 0000000..a2440af
--- /dev/null
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <GL/glut.h>
+#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<FB_H; i++) {
+               for(j=0; j<FB_W; j++) {
+                       xor = i ^ j;
+                       r = (xor >> 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;
+       }
+}