rev |
line source |
nuclear@14
|
1 #include <string.h>
|
nuclear@17
|
2 #include <stdarg.h>
|
nuclear@9
|
3 #include "renderer.h"
|
nuclear@14
|
4 #include "rayzor.h"
|
nuclear@15
|
5 #include "scene.h"
|
nuclear@14
|
6 #include "keyb.h"
|
nuclear@14
|
7 #include "scrman.h"
|
nuclear@15
|
8 #include "timer.h"
|
nuclear@15
|
9 #include "logger.h"
|
nuclear@17
|
10 #include "raytrace.h"
|
nuclear@17
|
11
|
nuclear@17
|
12 enum {
|
nuclear@17
|
13 MSG_START,
|
nuclear@17
|
14 MSG_GAMMA,
|
nuclear@17
|
15 MSG_USE_GAMMA,
|
nuclear@17
|
16
|
nuclear@17
|
17 NUM_MESSAGES
|
nuclear@17
|
18 };
|
nuclear@14
|
19
|
nuclear@14
|
20 struct RendererImpl {
|
nuclear@14
|
21 bool in_progress;
|
nuclear@14
|
22 int cur_x, cur_y; // current pixel being rendered
|
nuclear@15
|
23
|
nuclear@15
|
24 uint32_t *pixels;
|
nuclear@15
|
25
|
nuclear@17
|
26 float gamma, inv_gamma;
|
nuclear@17
|
27 bool use_gamma;
|
nuclear@17
|
28
|
nuclear@17
|
29 MsgAtom msg[NUM_MESSAGES];
|
nuclear@14
|
30 };
|
nuclear@9
|
31
|
nuclear@15
|
32
|
nuclear@9
|
33 Renderer::Renderer()
|
nuclear@9
|
34 {
|
nuclear@9
|
35 set_name("renderer");
|
nuclear@9
|
36 }
|
nuclear@9
|
37
|
nuclear@14
|
38 bool Renderer::init()
|
nuclear@14
|
39 {
|
nuclear@14
|
40 rend = new RendererImpl;
|
nuclear@14
|
41 memset(rend, 0, sizeof *rend);
|
nuclear@15
|
42
|
nuclear@15
|
43 rend->pixels = new uint32_t[fb_width * fb_height];
|
nuclear@15
|
44 if(!rend->pixels) {
|
nuclear@15
|
45 return false;
|
nuclear@15
|
46 }
|
nuclear@15
|
47 memset(rend->pixels, 0, fb_width * fb_height * 4);
|
nuclear@15
|
48
|
nuclear@17
|
49 rend->gamma = 1.8;
|
nuclear@17
|
50 rend->inv_gamma = 1.0 / rend->gamma;
|
nuclear@17
|
51 rend->use_gamma = true;
|
nuclear@17
|
52
|
nuclear@17
|
53 rend->msg[MSG_START] = message_atom("start");
|
nuclear@17
|
54 rend->msg[MSG_GAMMA] = message_atom("gamma");
|
nuclear@17
|
55 rend->msg[MSG_USE_GAMMA] = message_atom("use-gamma");
|
nuclear@15
|
56
|
nuclear@14
|
57 return true;
|
nuclear@14
|
58 }
|
nuclear@14
|
59
|
nuclear@14
|
60 void Renderer::shutdown()
|
nuclear@14
|
61 {
|
nuclear@14
|
62 if(rend) {
|
nuclear@15
|
63 delete [] rend->pixels;
|
nuclear@14
|
64 delete rend;
|
nuclear@14
|
65 rend = 0;
|
nuclear@14
|
66 }
|
nuclear@14
|
67 }
|
nuclear@14
|
68
|
nuclear@9
|
69 void Renderer::draw() const
|
nuclear@9
|
70 {
|
nuclear@15
|
71 Camera *cam = scene->get_active_camera();
|
nuclear@15
|
72
|
nuclear@15
|
73 // if a rendering is not in progress, just show the last buffer
|
nuclear@15
|
74 if(!rend->in_progress || !cam) {
|
nuclear@15
|
75 memcpy(fb_pixels, rend->pixels, fb_width * fb_height * 4);
|
nuclear@15
|
76 return;
|
nuclear@15
|
77 }
|
nuclear@15
|
78
|
nuclear@15
|
79 // render for approximately half a second, then show and return
|
nuclear@15
|
80 unsigned long start = get_msec();
|
nuclear@15
|
81 uint32_t *dest = rend->pixels + rend->cur_y * fb_width + rend->cur_x;
|
nuclear@15
|
82
|
nuclear@15
|
83 for(;;) {
|
nuclear@15
|
84 Ray ray = cam->get_primary_ray(rend->cur_x, rend->cur_y);
|
nuclear@15
|
85 Vector3 color = ray_trace(ray);
|
nuclear@15
|
86
|
nuclear@17
|
87 // gamma-correct before storing the pixel
|
nuclear@17
|
88 if(rend->use_gamma) {
|
nuclear@17
|
89 color.x = pow(color.x, rend->inv_gamma);
|
nuclear@17
|
90 color.y = pow(color.y, rend->inv_gamma);
|
nuclear@17
|
91 color.z = pow(color.z, rend->inv_gamma);
|
nuclear@17
|
92 }
|
nuclear@17
|
93
|
nuclear@15
|
94 int r = color.x > 1.0 ? 255 : (int)(color.x * 255.0);
|
nuclear@15
|
95 int g = color.y > 1.0 ? 255 : (int)(color.y * 255.0);
|
nuclear@15
|
96 int b = color.z > 1.0 ? 255 : (int)(color.z * 255.0);
|
nuclear@15
|
97
|
nuclear@15
|
98 *dest++ = (r << 16) | (g << 8) | b;
|
nuclear@15
|
99
|
nuclear@15
|
100 if(++rend->cur_x >= fb_width) {
|
nuclear@15
|
101 rend->cur_x = 0;
|
nuclear@15
|
102 if(++rend->cur_y >= fb_height) {
|
nuclear@15
|
103 rend->in_progress = false;
|
nuclear@15
|
104 printlog("done!\n");
|
nuclear@15
|
105 break;
|
nuclear@15
|
106 }
|
nuclear@15
|
107 }
|
nuclear@15
|
108
|
nuclear@15
|
109 if(get_msec() - start >= 500) {
|
nuclear@15
|
110 break;
|
nuclear@15
|
111 }
|
nuclear@15
|
112 }
|
nuclear@15
|
113
|
nuclear@15
|
114 memcpy(fb_pixels, rend->pixels, fb_width * fb_height * 4);
|
nuclear@9
|
115 }
|
nuclear@14
|
116
|
nuclear@14
|
117 void Renderer::handle_keyboard(int key, bool press)
|
nuclear@14
|
118 {
|
nuclear@14
|
119 switch(key) {
|
nuclear@14
|
120 case KB_ESC:
|
nuclear@14
|
121 deactivate_screen();
|
nuclear@14
|
122 break;
|
nuclear@14
|
123
|
nuclear@15
|
124 default:
|
nuclear@15
|
125 break;
|
nuclear@14
|
126 }
|
nuclear@14
|
127 }
|
nuclear@15
|
128
|
nuclear@17
|
129 void Renderer::message(MsgAtom msg, ...)
|
nuclear@15
|
130 {
|
nuclear@17
|
131 va_list ap;
|
nuclear@17
|
132 va_start(ap, msg);
|
nuclear@15
|
133
|
nuclear@17
|
134 for(int i=0; i<NUM_MESSAGES; i++) {
|
nuclear@17
|
135 if(msg == rend->msg[i]) {
|
nuclear@17
|
136 switch(i) {
|
nuclear@17
|
137 case MSG_START:
|
nuclear@17
|
138 rend->cur_x = rend->cur_y = 0;
|
nuclear@17
|
139 rend->in_progress = true;
|
nuclear@17
|
140 memset(rend->pixels, 0, fb_width * fb_height * 4);
|
nuclear@17
|
141
|
nuclear@17
|
142 printlog("starting a new rendering!\n");
|
nuclear@17
|
143 break;
|
nuclear@17
|
144
|
nuclear@17
|
145 case MSG_GAMMA:
|
nuclear@18
|
146 rend->gamma = va_arg(ap, double);
|
nuclear@17
|
147 rend->inv_gamma = 1.0 / rend->gamma;
|
nuclear@17
|
148 break;
|
nuclear@17
|
149
|
nuclear@17
|
150 case MSG_USE_GAMMA:
|
nuclear@18
|
151 rend->use_gamma = va_arg(ap, int);
|
nuclear@17
|
152 break;
|
nuclear@17
|
153 }
|
nuclear@17
|
154 }
|
nuclear@15
|
155 }
|
nuclear@17
|
156
|
nuclear@17
|
157 va_end(ap);
|
nuclear@15
|
158 }
|