foo
[voxscape] / src / glfb.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <GL/gl.h>
5 #include "glfb.h"
6
7 static void conv_idx8(void *pixels);
8 static void conv_rgb15(void *pixels);
9 static void conv_rgb16(void *pixels);
10 static void conv_rgb24(void *pixels);
11 static void conv_rgba32(void *pixels);
12 static unsigned int next_pow2(unsigned int x);
13
14 static int width, height, scansz;
15 static enum glfb_pixel_format pixfmt;
16 static unsigned int min_filt = GL_NEAREST, mag_filt = GL_NEAREST;
17 static uint32_t *convbuf;
18 static int convbuf_size;
19
20 static uint32_t cmap[256];
21
22 static unsigned int tex;
23 static int tex_width, tex_height;
24 static float tex_sx, tex_sy;
25
26 static void (*convert[])(void*) = {
27         conv_idx8, conv_rgb15, conv_rgb16, conv_rgb24, conv_rgba32
28 };
29
30
31 void glfb_setup(int x, int y, enum glfb_pixel_format fmt, int pitch)
32 {
33         int tx, ty, newsz;
34
35         tx = next_pow2(x);
36         ty = next_pow2(y);
37
38         if(!tex || tx < tex_width || ty < height || fmt != pixfmt) {
39                 if(!tex) {
40                         glGenTextures(1, &tex);
41                         glBindTexture(GL_TEXTURE_2D, tex);
42                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filt);
43                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filt);
44                         glEnable(GL_TEXTURE_2D);
45                 }
46                 glBindTexture(GL_TEXTURE_2D, tex);
47                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx, ty, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
48
49                 tex_width = tx;
50                 tex_height = ty;
51         }
52
53         tex_sx = (float)x / tex_width;
54         tex_sy = (float)y / tex_height;
55
56         scansz = pitch;
57
58         newsz = x * y * 4;
59         if(convbuf_size < newsz) {
60                 free(convbuf);
61                 if(!(convbuf = malloc(newsz))) {
62                         fprintf(stderr, "glfb: failed to allocate conversion buffer\n");
63                         convbuf = 0;
64                 }
65                 convbuf_size = newsz;
66         }
67
68         width = x;
69         height = y;
70         pixfmt = fmt;
71 }
72
73 void glfb_filter(enum glfb_filter filt)
74 {
75         switch(filt) {
76         case GLFB_NEAREST:
77                 min_filt = mag_filt = GL_NEAREST;
78                 break;
79         case GLFB_LINEAR:
80                 min_filt = mag_filt = GL_LINEAR;
81                 break;
82         }
83 }
84
85
86 void glfb_color(int idx, int r, int g, int b)
87 {
88         if(idx < 0 || idx >= 255) return;
89
90         cmap[idx] = (b << 16) | (g << 8) | r;
91 }
92
93 void glfb_update(void *pixels)
94 {
95         convert[pixfmt](pixels);
96         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, convbuf);
97 }
98
99 void glfb_display(void)
100 {
101         glClearColor(0.2, 0.2, 0.2, 1);
102         glClear(GL_COLOR_BUFFER_BIT);
103
104         glBegin(GL_TRIANGLES);
105         glTexCoord2f(0, 0);
106         glVertex2f(-1, -1);
107         glTexCoord2f(tex_sx * 2.0f, 0);
108         glVertex2f(3, -1);
109         glTexCoord2f(0, tex_sy * 2.0f);
110         glVertex2f(-1, 3);
111         glEnd();
112 }
113
114 static void conv_idx8(void *pixels)
115 {
116         int i, j;
117         unsigned char *sptr = pixels;
118         uint32_t *dptr = convbuf;
119
120         for(i=0; i<height; i++) {
121                 for(j=0; j<width; j++) {
122                         *dptr++ = cmap[sptr[j]];
123                 }
124                 sptr += scansz;
125         }
126 }
127
128 static void conv_rgb15(void *pixels)
129 {
130         int i, j;
131         uint16_t pix;
132         uint32_t r, g, b;
133         uint16_t *sptr = pixels;
134         uint32_t *dptr = convbuf;
135
136         for(i=0; i<height; i++) {
137                 for(j=0; j<width; j++) {
138                         pix = sptr[j];
139                         r = ((pix & 0x1f) << 3) | (pix & 7);
140                         g = ((pix & 0x3e0) >> 2) | ((pix >> 5) & 7);
141                         b = ((pix & 0x7c00) >> 7) | ((pix >> 10) & 7);
142                         *dptr++ = r | (g << 8) | (b << 16);
143                 }
144                 sptr = (uint16_t*)((char*)sptr + scansz);
145         }
146 }
147
148 static void conv_rgb16(void *pixels)
149 {
150         int i, j;
151         uint16_t pix;
152         uint32_t r, g, b;
153         uint16_t *sptr = pixels;
154         uint32_t *dptr = convbuf;
155
156         for(i=0; i<height; i++) {
157                 for(j=0; j<width; j++) {
158                         pix = sptr[j];
159                         r = ((pix & 0x1f) << 3) | (pix & 7);
160                         g = ((pix & 0x7e0) >> 3) | ((pix >> 5) & 3);
161                         b = ((pix & 0xf800) >> 8) | ((pix >> 11) & 7);
162                         *dptr++ = r | (g << 8) | (b << 16);
163                 }
164                 sptr = (uint16_t*)((char*)sptr + scansz);
165         }
166 }
167
168 static void conv_rgb24(void *pixels)
169 {
170         int i, j;
171         uint32_t r, g, b;
172         unsigned char *sptr, *scanptr = pixels;
173         uint32_t *dptr = convbuf;
174
175         for(i=0; i<height; i++) {
176                 sptr = scanptr;
177                 for(j=0; j<width; j++) {
178                         r = sptr[0];
179                         g = sptr[1];
180                         b = sptr[2];
181                         sptr += 3;
182                         *dptr++ = r | (g << 8) | (b << 16);
183                 }
184                 scanptr += scansz;
185         }
186 }
187
188 static void conv_rgba32(void *pixels)
189 {
190         int i, j;
191         uint32_t pix, r, g, b;
192         uint32_t *sptr = pixels;
193         uint32_t *dptr = convbuf;
194
195         for(i=0; i<height; i++) {
196                 for(j=0; j<width; j++) {
197                         pix = sptr[j];
198                         r = (pix >> 16) & 0xff;
199                         g = (pix >> 8) & 0xff;
200                         b = pix & 0xff;
201                         *dptr++ = r | (g << 8) | (b << 16);
202                 }
203                 sptr = (uint32_t*)((char*)sptr + scansz);
204         }
205 }
206
207 static unsigned int next_pow2(unsigned int x)
208 {
209         x--;
210         x |= x >> 1;
211         x |= x >> 2;
212         x |= x >> 4;
213         x |= x >> 8;
214         x |= x >> 16;
215         return x + 1;
216 }
217