foo
[voxscape] / src / voxscape.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 #include <math.h>
6 #include <imago2.h>
7 #include "voxscape.h"
8
9 enum {
10         SLICELEN        = 1
11 };
12
13 struct voxscape {
14         int xsz, ysz;
15         unsigned char *height;
16         uint32_t *color;
17
18         /* framebuffer */
19         uint32_t *fb;
20         int fbwidth, fbheight;
21         int *coltop;
22
23         /* view */
24         int32_t x, y, angle;
25
26         /* projection */
27         int fov, znear, zfar;
28         int nslices;
29         int32_t *slicelen;      /* 24.8 */
30
31         unsigned int valid;
32 };
33
34 struct voxscape *vox_create(int xsz, int ysz)
35 {
36         struct voxscape *vox;
37
38         if(!(vox = calloc(1, sizeof *vox))) {
39                 return 0;
40         }
41         if(!(vox->height = calloc(1, xsz * ysz))) {
42                 fprintf(stderr, "vox_create: failed to allocate %dx%d heightmap\n", xsz, ysz);
43                 free(vox);
44                 return 0;
45         }
46         if(!(vox->color = calloc(xsz * ysz, sizeof *vox->color))) {
47                 fprintf(stderr, "vox_create: failed to allocate %dx%d color map\n", xsz, ysz);
48                 free(vox->height);
49                 free(vox);
50                 return 0;
51         }
52         vox->xsz = xsz;
53         vox->ysz = ysz;
54
55         return vox;
56 }
57
58 struct voxscape *vox_open(const char *hfile, const char *cfile)
59 {
60         unsigned char *hpix;
61         uint32_t *cpix;
62         int width, height, cwidth, cheight;
63         struct voxscape *vox;
64
65         if(!(hpix = img_load_pixels(hfile, &width, &height, IMG_FMT_GREY8))) {
66                 fprintf(stderr, "vox_open: failed to load heightmap: %s\n", hfile);
67                 return 0;
68         }
69         if(!(cpix = img_load_pixels(cfile, &cwidth, &cheight, IMG_FMT_RGBA32))) {
70                 fprintf(stderr, "vox_open: failed to load color map: %s\n", cfile);
71                 img_free_pixels(hpix);
72                 return 0;
73         }
74         if(cwidth != width || cheight != height) {
75                 img_free_pixels(hpix);
76                 img_free_pixels(cpix);
77                 fprintf(stderr, "vox_open: %s and %s have different dimensions\n", hfile, cfile);
78                 return 0;
79         }
80
81         if(!(vox = vox_create(width, height))) {
82                 img_free_pixels(hpix);
83                 img_free_pixels(cpix);
84                 return 0;
85         }
86         memcpy(vox->height, hpix, width * height);
87         memcpy(vox->color, cpix, width * height * sizeof *vox->color);
88
89         img_free_pixels(hpix);
90         img_free_pixels(cpix);
91
92         return vox;
93 }
94
95 void vox_free(struct voxscape *vox)
96 {
97         if(!vox) return;
98
99         free(vox->color);
100         free(vox->height);
101         free(vox->coltop);
102         free(vox->slicelen);
103         free(vox);
104 }
105
106 void vox_framebuf(struct voxscape *vox, int xres, int yres, uint32_t *fb)
107 {
108         if(xres != vox->fbwidth) {
109                 free(vox->coltop);
110                 if(!(vox->coltop = malloc(xres * sizeof *vox->coltop))) {
111                         fprintf(stderr, "vox_framebuf: failed to allocate column table (%d)\n", xres);
112                         return;
113                 }
114         }
115         vox->fb = fb;
116         vox->fbwidth = xres;
117         vox->fbheight = yres;
118 }
119
120 void vox_view(struct voxscape *vox, int32_t x, int32_t y, int32_t angle)
121 {
122         vox->x = x;
123         vox->y = y;
124         vox->angle = angle;
125         /* TODO precalc stuff */
126
127         valid &= ~SLICELEN;
128 }
129
130 void vox_proj(struct voxscape *vox, int fov, int znear, int zfar)
131 {
132         int i;
133
134         vox->fov = fov;
135         vox->znear = znear;
136         vox->zfar = zfar;
137
138         vox->nslices = vox->zfar - vox->znear;
139         free(vox->slicelen);
140         if(!(vox->slicelen = malloc(vox->nslices * sizeof *vox->slicelen))) {
141                 fprintf(stderr, "vox_proj: failed to allocate slice length table (%d)\n", vox->nslices);
142                 return;
143         }
144
145         valid &= ~SLICELEN;
146 }
147
148 /* algorithm:
149  * calculate extents of horizontal equidistant line from the viewer based on fov
150  * for each column step along this line and compute height for each pixel
151  * fill the visible (top) part of each column
152  */
153
154 void vox_render(struct voxscape *vox)
155 {
156         int i;
157
158         vox_begin(vox);
159         for(i=0; i<vox->nslices; i++) {
160                 vox_render_slice(vox, i);
161         }
162 }
163
164 void vox_begin(struct voxscape *vox)
165 {
166         int i;
167
168         for(i=0; i<vox->fbwidth; i++) {
169                 vox->coltop[i] = vox->fbheight;
170         }
171
172         if(!(vox->valid & SLICELEN)) {
173                 float theta = (float)vox->angle * M_PI / 360.0f;        /* half angle */
174                 for(i=0; i<vox->nslices; i++) {
175                         vox->slicelen[i] = (int32_t)((vox->znear + i) * tan(theta) * 2.0f * 256.0f)
176                 }
177                 vox->valid |= SLICELEN;
178         }
179 }
180
181 void vox_render_slice(struct voxscape *vox, int n)
182 {
183         int32_t len;
184
185         len = vox->slicelen[n];
186
187         /* TODO cont. */
188 }