2 RetroRay - integrated standalone vintage modeller/renderer
3 Copyright (C) 2023 John Tsiombikas <nuclear@mutantstargoat.com>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
25 static struct pimage textures[MAX_TEXTURES];
27 void gaw_sw_reset(void)
34 void gaw_sw_init(void)
41 void gaw_sw_destroy(void)
48 void gaw_sw_framebuffer(int width, int height, void *pixels)
50 static int max_height;
51 static int max_npixels;
52 int npixels = width * height;
54 if(npixels > max_npixels) {
56 pfill_zbuf = malloc_nf(npixels * sizeof *pfill_zbuf);
57 max_npixels = npixels;
60 if(height > max_height) {
61 polyfill_fbheight(height);
68 pfill_fb.pixels = pixels;
69 pfill_fb.width = width;
70 pfill_fb.height = height;
72 gaw_viewport(0, 0, width, height);
75 /* set the framebuffer pointer, without resetting the size */
76 void gaw_sw_framebuffer_addr(void *pixels)
78 pfill_fb.pixels = pixels;
81 void gaw_enable(int what)
83 gaw_swtnl_enable(what);
86 void gaw_disable(int what)
88 gaw_swtnl_disable(what);
91 void gaw_clear(unsigned int flags)
93 int i, npix = pfill_fb.width * pfill_fb.height;
95 if(flags & GAW_COLORBUF) {
96 for(i=0; i<npix; i++) {
97 pfill_fb.pixels[i] = ST->clear_color;
101 if(flags & GAW_DEPTHBUF) {
102 for(i=0; i<npix; i++) {
103 pfill_zbuf[i] = ST->clear_depth;
108 void gaw_color_mask(int rmask, int gmask, int bmask, int amask)
110 gaw_swtnl_color_mask(rmask, gmask, bmask, amask);
113 void gaw_depth_mask(int mask)
115 gaw_swtnl_depth_mask(mask);
118 static int alloc_tex(void)
121 for(i=0; i<MAX_TEXTURES; i++) {
122 if(ST->textypes[i] == 0) {
129 unsigned int gaw_create_tex1d(int texfilter)
132 if((idx = alloc_tex()) == -1) {
135 ST->textypes[idx] = 1;
137 memset(textures + idx, 0, sizeof *textures);
142 unsigned int gaw_create_tex2d(int texfilter)
145 if((idx = alloc_tex()) == -1) {
148 ST->textypes[idx] = 2;
150 memset(textures + idx, 0, sizeof *textures);
155 void gaw_destroy_tex(unsigned int texid)
159 if(!ST->textypes[idx]) return;
161 free(textures[idx].pixels);
162 ST->textypes[idx] = 0;
165 void gaw_texfilter1d(int texfilter)
169 void gaw_texfilter2d(int texfilter)
173 void gaw_texwrap1d(int wrap)
177 void gaw_texwrap2d(int uwrap, int vwrap)
182 static __inline int calc_shift(unsigned int x)
192 void gaw_tex1d(int ifmt, int xsz, int fmt, void *pix)
194 gaw_tex2d(ifmt, xsz, 1, fmt, pix);
197 void gaw_tex2d(int ifmt, int xsz, int ysz, int fmt, void *pix)
202 if(ST->cur_tex < 0) return;
203 img = textures + ST->cur_tex;
208 img->pixels = malloc_nf(npix * sizeof *img->pixels);
212 img->xmask = xsz - 1;
213 img->ymask = ysz - 1;
214 img->xshift = calc_shift(xsz);
215 img->yshift = calc_shift(ysz);
217 gaw_subtex2d(0, 0, 0, xsz, ysz, fmt, pix);
220 void gaw_subtex2d(int lvl, int x, int y, int xsz, int ysz, int fmt, void *pix)
222 int i, j, r, g, b, val;
227 if(ST->cur_tex < 0) return;
228 img = textures + ST->cur_tex;
230 dest = img->pixels + (y << img->xshift) + x;
235 for(i=0; i<ysz; i++) {
236 for(j=0; j<xsz; j++) {
238 dest[j] = PACK_RGBA(val, val, val, 255);
245 for(i=0; i<ysz; i++) {
246 for(j=0; j<xsz; j++) {
251 dest[j] = PACK_RGBA(r, g, b, 255);
258 for(i=0; i<ysz; i++) {
259 for(j=0; j<xsz; j++) {
260 dest[j] = *((uint32_t*)src);
272 void gaw_bind_tex1d(int tex)
274 ST->cur_tex = (int)tex - 1;
275 pfill_tex = textures[ST->cur_tex];
278 void gaw_bind_tex2d(int tex)
280 ST->cur_tex = (int)tex - 1;
281 pfill_tex = textures[ST->cur_tex];
284 static void dump_texture(struct pimage *img, const char *fname)
286 int i, npix = img->width * img->height;
287 FILE *fp = fopen(fname, "wb");
290 fprintf(fp, "P6\n%d %d\n255\n", img->width, img->height);
291 for(i=0; i<npix; i++) {
292 int r = UNPACK_R(img->pixels[i]);
293 int g = UNPACK_G(img->pixels[i]);
294 int b = UNPACK_B(img->pixels[i]);
302 void gaw_sw_dump_textures(void)
307 for(i=0; i<MAX_TEXTURES; i++) {
308 if(ST->textypes[i] <= 0) continue;
310 sprintf(buf, "tex%04d.ppm", i);
311 printf("dumping %s ...\n", buf);
312 dump_texture(textures + i, buf);
316 void gaw_swtnl_drawprim(int prim, struct vertex *v, int vnum)
319 struct pvertex pv[16];
321 for(i=0; i<vnum; i++) {
322 /* viewport transformation */
323 v[i].x = (v[i].x * 0.5f + 0.5f) * (float)ST->vport[2] + ST->vport[0];
324 v[i].y = (v[i].y * -0.5f + 0.5f) * (float)ST->vport[3] + ST->vport[1] - 1;
326 /* convert pos to 24.8 fixed point */
327 pv[i].x = cround64(v[i].x * 256.0f);
328 pv[i].y = cround64(v[i].y * 256.0f);
330 if(ST->opt & (1 << GAW_DEPTH_TEST)) {
331 /* after div/w z is in [-1, 1], remap it to [0, 0xffffff] */
332 pv[i].z = cround64(v[i].z * 8388607.5f + 8388607.5f);
335 /* convert tex coords to 16.16 fixed point */
336 pv[i].u = cround64(v[i].u * 65536.0f);
337 pv[i].v = cround64(v[i].v * 65536.0f);
338 /* pass the color through as is */
345 /* backface culling */
346 #if 0 /* TODO fix culling */
347 if(vnum > 2 && (ST->opt & (1 << GAW_CULL_FACE))) {
348 int32_t ax = pv[1].x - pv[0].x;
349 int32_t ay = pv[1].y - pv[0].y;
350 int32_t bx = pv[2].x - pv[0].x;
351 int32_t by = pv[2].y - pv[0].y;
352 int32_t cross_z = (ax >> 4) * (by >> 4) - (ay >> 4) * (bx >> 4);
353 int sign = (cross_z >> 31) & 1;
355 if(!(sign ^ ST->frontface)) {
356 continue; /* back-facing */
370 fill_mode = ST->polymode;
371 if(ST->opt & ((1 << GAW_TEXTURE_2D) | (1 << GAW_TEXTURE_1D))) {
372 fill_mode |= POLYFILL_TEX_BIT;
374 if((ST->opt & (1 << GAW_BLEND)) && (ST->bsrc == GAW_SRC_ALPHA)) {
375 fill_mode |= POLYFILL_ALPHA_BIT;
376 } else if((ST->opt & (1 << GAW_BLEND)) && (ST->bsrc == GAW_ONE)) {
377 fill_mode |= POLYFILL_ADD_BIT;
379 if(ST->opt & (1 << GAW_DEPTH_TEST)) {
380 fill_mode |= POLYFILL_ZBUF_BIT;
382 polyfill(fill_mode, pv, vnum);