nuclear@14: #include nuclear@17: #include nuclear@9: #include "renderer.h" nuclear@14: #include "rayzor.h" nuclear@15: #include "scene.h" nuclear@14: #include "keyb.h" nuclear@14: #include "scrman.h" nuclear@15: #include "timer.h" nuclear@15: #include "logger.h" nuclear@17: #include "raytrace.h" nuclear@17: nuclear@17: enum { nuclear@17: MSG_START, nuclear@17: MSG_GAMMA, nuclear@17: MSG_USE_GAMMA, nuclear@17: nuclear@17: NUM_MESSAGES nuclear@17: }; nuclear@14: nuclear@14: struct RendererImpl { nuclear@14: bool in_progress; nuclear@14: int cur_x, cur_y; // current pixel being rendered nuclear@15: nuclear@15: uint32_t *pixels; nuclear@15: nuclear@17: float gamma, inv_gamma; nuclear@17: bool use_gamma; nuclear@17: nuclear@17: MsgAtom msg[NUM_MESSAGES]; nuclear@14: }; nuclear@9: nuclear@15: nuclear@9: Renderer::Renderer() nuclear@9: { nuclear@9: set_name("renderer"); nuclear@9: } nuclear@9: nuclear@14: bool Renderer::init() nuclear@14: { nuclear@14: rend = new RendererImpl; nuclear@14: memset(rend, 0, sizeof *rend); nuclear@15: nuclear@15: rend->pixels = new uint32_t[fb_width * fb_height]; nuclear@15: if(!rend->pixels) { nuclear@15: return false; nuclear@15: } nuclear@15: memset(rend->pixels, 0, fb_width * fb_height * 4); nuclear@15: nuclear@17: rend->gamma = 1.8; nuclear@17: rend->inv_gamma = 1.0 / rend->gamma; nuclear@17: rend->use_gamma = true; nuclear@17: nuclear@17: rend->msg[MSG_START] = message_atom("start"); nuclear@17: rend->msg[MSG_GAMMA] = message_atom("gamma"); nuclear@17: rend->msg[MSG_USE_GAMMA] = message_atom("use-gamma"); nuclear@15: nuclear@14: return true; nuclear@14: } nuclear@14: nuclear@14: void Renderer::shutdown() nuclear@14: { nuclear@14: if(rend) { nuclear@15: delete [] rend->pixels; nuclear@14: delete rend; nuclear@14: rend = 0; nuclear@14: } nuclear@14: } nuclear@14: nuclear@9: void Renderer::draw() const nuclear@9: { nuclear@15: Camera *cam = scene->get_active_camera(); nuclear@15: nuclear@15: // if a rendering is not in progress, just show the last buffer nuclear@15: if(!rend->in_progress || !cam) { nuclear@15: memcpy(fb_pixels, rend->pixels, fb_width * fb_height * 4); nuclear@15: return; nuclear@15: } nuclear@15: nuclear@15: // render for approximately half a second, then show and return nuclear@15: unsigned long start = get_msec(); nuclear@15: uint32_t *dest = rend->pixels + rend->cur_y * fb_width + rend->cur_x; nuclear@15: nuclear@15: for(;;) { nuclear@15: Ray ray = cam->get_primary_ray(rend->cur_x, rend->cur_y); nuclear@15: Vector3 color = ray_trace(ray); nuclear@15: nuclear@17: // gamma-correct before storing the pixel nuclear@17: if(rend->use_gamma) { nuclear@17: color.x = pow(color.x, rend->inv_gamma); nuclear@17: color.y = pow(color.y, rend->inv_gamma); nuclear@17: color.z = pow(color.z, rend->inv_gamma); nuclear@17: } nuclear@17: nuclear@15: int r = color.x > 1.0 ? 255 : (int)(color.x * 255.0); nuclear@15: int g = color.y > 1.0 ? 255 : (int)(color.y * 255.0); nuclear@15: int b = color.z > 1.0 ? 255 : (int)(color.z * 255.0); nuclear@15: nuclear@15: *dest++ = (r << 16) | (g << 8) | b; nuclear@15: nuclear@15: if(++rend->cur_x >= fb_width) { nuclear@15: rend->cur_x = 0; nuclear@15: if(++rend->cur_y >= fb_height) { nuclear@15: rend->in_progress = false; nuclear@15: printlog("done!\n"); nuclear@15: break; nuclear@15: } nuclear@15: } nuclear@15: nuclear@15: if(get_msec() - start >= 500) { nuclear@15: break; nuclear@15: } nuclear@15: } nuclear@15: nuclear@15: memcpy(fb_pixels, rend->pixels, fb_width * fb_height * 4); nuclear@9: } nuclear@14: nuclear@14: void Renderer::handle_keyboard(int key, bool press) nuclear@14: { nuclear@14: switch(key) { nuclear@14: case KB_ESC: nuclear@14: deactivate_screen(); nuclear@14: break; nuclear@14: nuclear@15: default: nuclear@15: break; nuclear@14: } nuclear@14: } nuclear@15: nuclear@17: void Renderer::message(MsgAtom msg, ...) nuclear@15: { nuclear@17: va_list ap; nuclear@17: va_start(ap, msg); nuclear@15: nuclear@17: for(int i=0; imsg[i]) { nuclear@17: switch(i) { nuclear@17: case MSG_START: nuclear@17: rend->cur_x = rend->cur_y = 0; nuclear@17: rend->in_progress = true; nuclear@17: memset(rend->pixels, 0, fb_width * fb_height * 4); nuclear@17: nuclear@17: printlog("starting a new rendering!\n"); nuclear@17: break; nuclear@17: nuclear@17: case MSG_GAMMA: nuclear@18: rend->gamma = va_arg(ap, double); nuclear@17: rend->inv_gamma = 1.0 / rend->gamma; nuclear@17: break; nuclear@17: nuclear@17: case MSG_USE_GAMMA: nuclear@18: rend->use_gamma = va_arg(ap, int); nuclear@17: break; nuclear@17: } nuclear@17: } nuclear@15: } nuclear@17: nuclear@17: va_end(ap); nuclear@15: }