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/>.
24 static struct pimage textures[MAX_TEXTURES];
26 void gaw_sw_reset(void)
33 void gaw_sw_init(void)
40 void gaw_sw_destroy(void)
47 void gaw_sw_framebuffer(int width, int height, void *pixels)
49 static int max_height;
50 static int max_npixels;
51 int npixels = width * height;
53 if(npixels > max_npixels) {
55 pfill_zbuf = malloc_nf(npixels * sizeof *pfill_zbuf);
56 max_npixels = npixels;
59 if(height > max_height) {
60 polyfill_fbheight(height);
67 pfill_fb.pixels = pixels;
68 pfill_fb.width = width;
69 pfill_fb.height = height;
71 gaw_viewport(0, 0, width, height);
74 /* set the framebuffer pointer, without resetting the size */
75 void gaw_sw_framebuffer_addr(void *pixels)
77 pfill_fb.pixels = pixels;
80 void gaw_enable(int what)
82 gaw_swtnl_enable(what);
85 void gaw_disable(int what)
87 gaw_swtnl_disable(what);
90 void gaw_clear(unsigned int flags)
92 int i, npix = pfill_fb.width * pfill_fb.height;
94 if(flags & GAW_COLORBUF) {
95 for(i=0; i<npix; i++) {
96 pfill_fb.pixels[i] = ST->clear_color;
100 if(flags & GAW_DEPTHBUF) {
101 for(i=0; i<npix; i++) {
102 pfill_zbuf[i] = ST->clear_depth;
107 void gaw_color_mask(int rmask, int gmask, int bmask, int amask)
109 gaw_swtnl_color_mask(rmask, gmask, bmask, amask);
112 void gaw_depth_mask(int mask)
114 gaw_swtnl_depth_mask(mask);
117 static int alloc_tex(void)
120 for(i=0; i<MAX_TEXTURES; i++) {
121 if(ST->textypes[i] == 0) {
128 unsigned int gaw_create_tex1d(int texfilter)
131 if((idx = alloc_tex()) == -1) {
134 ST->textypes[idx] = 1;
136 memset(textures + idx, 0, sizeof *textures);
141 unsigned int gaw_create_tex2d(int texfilter)
144 if((idx = alloc_tex()) == -1) {
147 ST->textypes[idx] = 2;
149 memset(textures + idx, 0, sizeof *textures);
154 void gaw_destroy_tex(unsigned int texid)
158 if(!ST->textypes[idx]) return;
160 free(textures[idx].pixels);
161 ST->textypes[idx] = 0;
164 void gaw_texfilter1d(int texfilter)
168 void gaw_texfilter2d(int texfilter)
172 void gaw_texwrap1d(int wrap)
176 void gaw_texwrap2d(int uwrap, int vwrap)
181 static __inline int calc_shift(unsigned int x)
191 void gaw_tex1d(int ifmt, int xsz, int fmt, void *pix)
193 gaw_tex2d(ifmt, xsz, 1, fmt, pix);
196 void gaw_tex2d(int ifmt, int xsz, int ysz, int fmt, void *pix)
201 if(ST->cur_tex < 0) return;
202 img = textures + ST->cur_tex;
207 img->pixels = malloc_nf(npix * sizeof *img->pixels);
211 img->xmask = xsz - 1;
212 img->ymask = ysz - 1;
213 img->xshift = calc_shift(xsz);
214 img->yshift = calc_shift(ysz);
216 gaw_subtex2d(0, 0, 0, xsz, ysz, fmt, pix);
219 void gaw_subtex2d(int lvl, int x, int y, int xsz, int ysz, int fmt, void *pix)
221 int i, j, r, g, b, val;
226 if(ST->cur_tex < 0) return;
227 img = textures + ST->cur_tex;
229 dest = img->pixels + (y << img->xshift) + x;
234 for(i=0; i<ysz; i++) {
235 for(j=0; j<xsz; j++) {
237 dest[j] = PACK_RGBA(val, val, val, 255);
244 for(i=0; i<ysz; i++) {
245 for(j=0; j<xsz; j++) {
250 dest[j] = PACK_RGBA(r, g, b, 255);
257 for(i=0; i<ysz; i++) {
258 for(j=0; j<xsz; j++) {
259 dest[j] = *((uint32_t*)src);
271 void gaw_bind_tex1d(int tex)
273 ST->cur_tex = (int)tex - 1;
274 pfill_tex = textures[ST->cur_tex];
277 void gaw_bind_tex2d(int tex)
279 ST->cur_tex = (int)tex - 1;
280 pfill_tex = textures[ST->cur_tex];
283 static void dump_texture(struct pimage *img, const char *fname)
285 int i, npix = img->width * img->height;
286 FILE *fp = fopen(fname, "wb");
289 fprintf(fp, "P6\n%d %d\n255\n", img->width, img->height);
290 for(i=0; i<npix; i++) {
291 int r = UNPACK_R(img->pixels[i]);
292 int g = UNPACK_G(img->pixels[i]);
293 int b = UNPACK_B(img->pixels[i]);
301 void gaw_sw_dump_textures(void)
306 for(i=0; i<MAX_TEXTURES; i++) {
307 if(ST->textypes[i] <= 0) continue;
309 sprintf(buf, "tex%04d.ppm", i);
310 printf("dumping %s ...\n", buf);
311 dump_texture(textures + i, buf);
315 void gaw_swtnl_drawprim(int prim, struct vertex *v, int vnum)
318 struct pvertex pv[16];
320 for(i=0; i<vnum; i++) {
321 /* viewport transformation */
322 v[i].x = (v[i].x * 0.5f + 0.5f) * (float)ST->vport[2] + ST->vport[0];
323 v[i].y = (v[i].y * -0.5f + 0.5f) * (float)ST->vport[3] + ST->vport[1] - 1;
325 /* convert pos to 24.8 fixed point */
326 pv[i].x = cround64(v[i].x * 256.0f);
327 pv[i].y = cround64(v[i].y * 256.0f);
329 if(ST->opt & (1 << GAW_DEPTH_TEST)) {
330 /* after div/w z is in [-1, 1], remap it to [0, 0xffffff] */
331 pv[i].z = cround64(v[i].z * 8388607.5f + 8388607.5f);
334 /* convert tex coords to 16.16 fixed point */
335 pv[i].u = cround64(v[i].u * 65536.0f);
336 pv[i].v = cround64(v[i].v * 65536.0f);
337 /* pass the color through as is */
344 /* backface culling */
345 #if 0 /* TODO fix culling */
346 if(vnum > 2 && (ST->opt & (1 << GAW_CULL_FACE))) {
347 int32_t ax = pv[1].x - pv[0].x;
348 int32_t ay = pv[1].y - pv[0].y;
349 int32_t bx = pv[2].x - pv[0].x;
350 int32_t by = pv[2].y - pv[0].y;
351 int32_t cross_z = (ax >> 4) * (by >> 4) - (ay >> 4) * (bx >> 4);
352 int sign = (cross_z >> 31) & 1;
354 if(!(sign ^ ST->frontface)) {
355 continue; /* back-facing */
369 fill_mode = ST->polymode;
370 if(ST->opt & ((1 << GAW_TEXTURE_2D) | (1 << GAW_TEXTURE_1D))) {
371 fill_mode |= POLYFILL_TEX_BIT;
373 if((ST->opt & (1 << GAW_BLEND)) && (ST->bsrc == GAW_SRC_ALPHA)) {
374 fill_mode |= POLYFILL_ALPHA_BIT;
375 } else if((ST->opt & (1 << GAW_BLEND)) && (ST->bsrc == GAW_ONE)) {
376 fill_mode |= POLYFILL_ADD_BIT;
378 if(ST->opt & (1 << GAW_DEPTH_TEST)) {
379 fill_mode |= POLYFILL_ZBUF_BIT;
381 polyfill(fill_mode, pv, vnum);