add relative mouse handling in mouse.asm
[retroray] / src / texture.c
1 /*
2 RetroRay - integrated standalone vintage modeller/renderer
3 Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
4
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.
9
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.
14
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/>.
17 */
18 #include "texture.h"
19 #include "geom.h"
20 #include "imago2.h"
21 #include "logger.h"
22 #include "sizeint.h"
23 #include "util.h"
24
25 static cgm_vec3 lookup_pixmap(const struct texture *btex, const struct rayhit *hit);
26 static cgm_vec3 lookup_chess(const struct texture *btex, const struct rayhit *hit);
27 static cgm_vec3 lookup_fbm2d(const struct texture *btex, const struct rayhit *hit);
28 static cgm_vec3 lookup_fbm3d(const struct texture *btex, const struct rayhit *hit);
29 static cgm_vec3 lookup_marble2d(const struct texture *btex, const struct rayhit *hit);
30 static cgm_vec3 lookup_marble3d(const struct texture *btex, const struct rayhit *hit);
31
32 static const cgm_vec3 (*lookup[])(const struct texture*, const struct rayhit*) = {
33         lookup_pixmap,
34         lookup_chess,
35         lookup_fbm2d,
36         lookup_fbm3d,
37         lookup_marble2d,
38         lookup_marble3d
39 };
40
41 static const char *defname_fmt[] = {
42         "pixmap%03d", "chess%03d",
43         "fbm%03d", "sfbm%03d",
44         "marble%03d", "smarble%03d"
45 };
46
47 struct texture *create_texture(int type)
48 {
49         struct texture *tex;
50         struct tex_pixmap *tpix;
51         struct tex_chess *tchess;
52         struct tex_fbm *tfbm;
53         static int texidx;
54         char namebuf[64];
55
56         switch(type) {
57         case TEX_PIXMAP:
58                 if(!(tpix = malloc(sizeof *tpix))) {
59                         goto fail;
60                 }
61                 tex = (struct texture*)tpix;
62                 tpix->img = 0;
63                 break;
64
65         case TEX_CHESS:
66                 if(!(tchess = malloc(sizeof *tchess))) {
67                         goto fail;
68                 }
69                 tex = (struct texture*)tchess;
70                 cgm_vcons(tchess->color, 0, 0, 0);
71                 cgm_vcons(tchess->color + 1, 1, 1, 1);
72                 break;
73
74         case TEX_FBM2D:
75         case TEX_FBM3D:
76                 if(!(tfbm = malloc(sizeof *tfbm))) {
77                         goto fail;
78                 }
79                 tex = (struct texture*)tfbm;
80                 tfbm->octaves = 1;
81                 cgm_vcons(tfbm->color, 0, 0, 0);
82                 cgm_vcons(tfbm->color + 1, 1, 1, 1);
83                 break;
84
85         default:
86                 errormsg("tried to allocate invalid texture type (%d)\n", type);
87                 return 0;
88         }
89
90         tex->type = type;
91         tex->name = 0;
92         cgm_vcons(&tex->offs, 0, 0, 0);
93         cgm_vcons(&tex->scale, 1, 1, 1);
94         tex->lookup = lookup[type];
95
96         sprintf(namebuf, defname_fmt[type], texidx++);
97         tex_set_name(tex, namebuf);
98         return tex;
99
100 fail:
101         errormsg("failed to allocate texture\n");
102         return 0;
103 }
104
105 void free_texture(struct texture *tex)
106 {
107         if(!tex) return;
108         free(tex->name);
109         free(tex);
110 }
111
112 void tex_set_name(struct texture *tex, const char *name)
113 {
114         char *tmp = strdup(name);
115         if(!tmp) return;
116         free(tex->name);
117         tex->name = tmp;
118 }
119
120 #define XFORM_UV(tex, u, v) \
121         do { \
122                 u *= (tex)->scale.x + (tex)->offs.x; \
123                 v *= (tex)->scale.y + (tex)->offs.y; \
124         } while(0)
125
126 #define XFORM_UVW(tex, u, v, w) \
127         do { \
128                 u *= (tex)->scale.x + (tex)->offs.x; \
129                 v *= (tex)->scale.y + (tex)->offs.y; \
130                 w *= (tex)->scale.z * (tex)->offs.z; \
131         } while(0)
132
133 static cgm_vec3 lookup_pixmap(const struct texture *btex, const struct rayhit *hit)
134 {
135         struct tex_pixmap *tex = (struct tex_pixmap*)btex;
136         int px, py, twidth, theight;
137         int r, g, b;
138         uint32_t texel;
139         float u = hit->uv.x;
140         float v = hit->uv.y;
141
142         twidth = tex->img->width;
143         theight = tex->img->height;
144
145         XFORM_UV(tex, u, v);
146
147         px = cround64((float)twidth * u) % twidth;
148         py = cround64((float)theight * v) % theight;
149         if(px < 0) px += twidth;
150         if(py < 0) py += theight;
151
152         texel = ((uint32_t*)tex->img->pixels)[py * twidth + px];
153         r = texel & 0xff;
154         g = (texel >> 8) & 0xff;
155         b = (texel >> 16) & 0xff;
156
157         return cgm_vvec(r / 255.0f, g / 255.0f, b / 255.0f);
158 }
159
160 static cgm_vec3 lookup_chess(const struct texture *btex, const struct rayhit *hit)
161 {
162         struct tex_chess *tex = (struct tex_chess*)btex;
163         int cx, cy, chess;
164         float u = hit->uv.x;
165         float v = hit->uv.y;
166
167         XFORM_UV(tex, u, v);
168
169         cx = cround64(u) & 1;
170         cy = cround64(v) & 1;
171         chess = cx ^ cy;
172         return tex->color[chess];
173 }
174
175 static cgm_vec3 lookup_fbm2d(const struct texture *btex, const struct rayhit *hit)
176 {
177         return cgm_vvec(1, 0, 0);       /* TODO */
178 }
179
180 static cgm_vec3 lookup_fbm3d(const struct texture *btex, const struct rayhit *hit)
181 {
182         return cgm_vvec(1, 0, 0);       /* TODO */
183 }
184
185 static cgm_vec3 lookup_marble2d(const struct texture *btex, const struct rayhit *hit)
186 {
187         return cgm_vvec(1, 0, 0);       /* TODO */
188 }
189
190 static cgm_vec3 lookup_marble3d(const struct texture *btex, const struct rayhit *hit)
191 {
192         return cgm_vvec(1, 0, 0);       /* TODO */
193 }