backdrop
[dosrtxon] / src / parts / rtxonoff.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <assert.h>
6 #include "demo.h"
7 #include "3dgfx.h"
8 #include "screen.h"
9 #include "cfgopt.h"
10 #include "polyfill.h"
11 #include "imago2.h"
12 #include "util.h"
13 #include "gfxutil.h"
14 #include "mesh.h"
15 #include "noise.h"
16
17 static int init(void);
18 static void destroy(void);
19 static void start(long trans_time);
20 static void draw(void);
21 static void keypress(int key);
22
23 static struct screen scr = {
24         "rtxonoff",
25         init,
26         destroy,
27         start, 0,
28         draw,
29         keypress
30 };
31
32 static float cam_theta = -29, cam_phi = 35;
33 static float cam_dist = 10;
34
35 static const char *car_fname[2] = {"data/ldiablo.obj", 0};
36 static const char *cartex_fname[2] = {"data/ldiablo.png", 0};
37 static struct g3d_mesh mesh_car[2];
38 static struct pimage tex_car[2];
39
40 #define BGCOL_SIZE      128
41 #define BGOFFS_SIZE     1024
42 static uint16_t bgcol[BGCOL_SIZE];
43 static uint16_t bgcol_mir[BGCOL_SIZE];
44 static int bgoffs[BGOFFS_SIZE];
45 static const int colzen[] = {98, 64, 192};
46 static const int colhor[] = {128, 80, 64};
47 static const int colmnt[] = {16, 9, 24};
48 static uint16_t mountcol, mountcol_mir;
49
50 static int shading = G3D_TEX_GOURAUD;
51 static int do_clip = 1;
52
53
54 struct screen *rtxonoff_screen(void)
55 {
56         return &scr;
57 }
58
59 static int init(void)
60 {
61         int i;
62         int col[3];
63
64         mountcol = PACK_RGB16(colmnt[0], colmnt[1], colmnt[2]);
65         mountcol_mir = PACK_RGB16(colmnt[0] / 2, colmnt[1] / 2, colmnt[2] / 2);
66
67         for(i=0; i<BGCOL_SIZE; i++) {
68                 int32_t t = (i << 8) / BGCOL_SIZE;
69                 col[0] = colhor[0] + ((colzen[0] - colhor[0]) * t >> 8);
70                 col[1] = colhor[1] + ((colzen[1] - colhor[1]) * t >> 8);
71                 col[2] = colhor[2] + ((colzen[2] - colhor[2]) * t >> 8);
72                 bgcol[i] = PACK_RGB16(col[0], col[1], col[2]);
73                 bgcol_mir[i] = PACK_RGB16(col[0] / 2, col[1] / 2, col[2] / 2);
74         }
75
76         for(i=0; i<BGOFFS_SIZE; i++) {
77                 float x = 8.0f * (float)i / (float)BGOFFS_SIZE;
78
79                 bgoffs[i] = pfbm1(x, 8.0f, 5) * 32 + 16;
80         }
81
82         for(i=0; i<sizeof car_fname / sizeof car_fname[0]; i++) {
83                 if(cartex_fname[i]) {
84                         if(!(tex_car[i].pixels = img_load_pixels(cartex_fname[i],
85                                                         &tex_car[i].width, &tex_car[i].height, IMG_FMT_RGB24))) {
86                                 fprintf(stderr, "failed to load car texture: %s\n", cartex_fname[i]);
87                                 return -1;
88                         }
89                         convimg_rgb24_rgb16(tex_car[i].pixels, (unsigned char*)tex_car[i].pixels,
90                                         tex_car[i].width, tex_car[i].height);
91                 }
92                 if(car_fname[i]) {
93                         if(load_mesh(&mesh_car[i], car_fname[i]) == -1) {
94                                 return -1;
95                         }
96                 }
97         }
98         return 0;
99 }
100
101 static void destroy(void)
102 {
103         int i;
104
105         for(i=0; i<2; i++) {
106                 free(mesh_car[i].varr);
107                 free(mesh_car[i].iarr);
108         }
109 }
110
111 #define VFOV    60
112 static void start(long trans_time)
113 {
114         g3d_matrix_mode(G3D_PROJECTION);
115         g3d_load_identity();
116         g3d_perspective(VFOV, 1.3333333, 0.5, 100.0);
117
118         g3d_enable(G3D_CULL_FACE);
119         g3d_enable(G3D_LIGHTING);
120         g3d_enable(G3D_LIGHT0);
121 }
122
123 static void update(void)
124 {
125         mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
126
127         cam_theta = fmod(cam_theta, 360.0f);
128         if(cam_theta < 0) cam_theta += 360.0f;
129
130         if(cam_phi < 0) cam_phi = 0;
131 }
132
133 static void backdrop(void)
134 {
135         static const int colzen[] = {98, 64, 192};
136         static const int colhor[] = {128, 80, 64};
137         int i, j, hory, start[3], end[3], col[3];
138         uint16_t *fbptr, pcol;
139         int cidx, offs = -10;
140         int startidx;
141
142         startidx = cround64(cam_theta * (float)BGOFFS_SIZE) / 360;
143
144         hory = (fb_height - 2 * fb_height * cround64(cam_phi) / VFOV) / 2;
145         if(hory > fb_height) hory = fb_height;
146
147         if(hory > 0) {
148                 fbptr = fb_pixels + (hory - 1) * fb_width;
149                 cidx = offs;
150                 i = 0;
151                 while(fbptr >= fb_pixels) {
152                         pcol = bgcol[cidx < 0 ? 0 : (cidx >= BGCOL_SIZE ? BGCOL_SIZE - 1 : cidx)];
153                         for(j=0; j<fb_width; j++) {
154                                 if(cidx < bgoffs[(startidx + j) & (BGOFFS_SIZE - 1)]) {
155                                         fbptr[j] = mountcol;
156                                 } else {
157                                         fbptr[j] = pcol;
158                                 }
159                         }
160                         fbptr -= fb_width;
161                         cidx++;
162                 }
163                 cidx = offs;
164         } else {
165                 cidx = offs - hory;
166                 hory = 0;
167         }
168
169         fbptr = fb_pixels + hory * fb_width;
170         for(i=hory; i<fb_height; i++) {
171                 pcol = bgcol_mir[cidx < 0 ? 0 : (cidx >= BGCOL_SIZE ? BGCOL_SIZE - 1 : cidx)];
172                 for(j=0; j<fb_width; j++) {
173                         if(cidx < bgoffs[(startidx + j) & (BGOFFS_SIZE - 1)]) {
174                                 *fbptr++ = mountcol_mir;
175                         } else {
176                                 *fbptr++ = pcol;
177                         }
178                 }
179                 cidx++;
180         }
181 }
182
183 static void draw(void)
184 {
185         int i, j;
186         uint16_t *fbptr = fb_pixels;
187         static float vdir[3];
188         float t = (float)time_msec / 16.0f;
189
190         update();
191
192         backdrop();
193
194         g3d_matrix_mode(G3D_MODELVIEW);
195         g3d_load_identity();
196         g3d_translate(0, 0, -cam_dist);
197         g3d_rotate(cam_phi, 1, 0, 0);
198         g3d_rotate(cam_theta, 0, 1, 0);
199
200         g3d_polygon_mode(shading);
201         g3d_set_texture(tex_car[0].width, tex_car[0].height, tex_car[0].pixels);
202         zsort_mesh(&mesh_car[0]);
203
204         g3d_light_color(0, 0.3, 0.3, 0.3);
205         g3d_push_matrix();
206         g3d_scale(1, -1, 1);
207         g3d_front_face(G3D_CW);
208         draw_mesh(&mesh_car[0]);
209         g3d_front_face(G3D_CCW);
210         g3d_pop_matrix();
211
212         g3d_light_color(0, 1, 1, 1);
213         draw_mesh(&mesh_car[0]);
214
215         swap_buffers(fb_pixels);
216 }
217
218 static void keypress(int key)
219 {
220         static int lighting = 1;
221         static int clipping = 1;
222
223         switch(key) {
224         case ' ':
225                 shading = (shading + 1) % 5;
226                 g3d_polygon_mode(shading);
227                 break;
228
229         case 'l':
230                 lighting = !lighting;
231                 if(lighting) {
232                         g3d_enable(G3D_LIGHTING);
233                 } else {
234                         g3d_disable(G3D_LIGHTING);
235                 }
236                 break;
237
238         case 'c':
239                 clipping = !clipping;
240                 if(clipping) {
241                         g3d_enable(G3D_CLIP_FRUSTUM);
242                 } else {
243                         g3d_disable(G3D_CLIP_FRUSTUM);
244                 }
245                 break;
246         }
247 }