nuclear@14: #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@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@15: MsgAtom msg_start; nuclear@14: }; nuclear@9: nuclear@15: nuclear@15: static Vector3 ray_trace(const Ray &ray, int iter = 0); nuclear@15: static Vector3 shade(const Ray &ray, float t, int iter); nuclear@15: 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@15: rend->msg_start = message_atom("start"); 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@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@15: void Renderer::message(MsgAtom msg) nuclear@15: { nuclear@15: if(msg == rend->msg_start) { nuclear@15: rend->cur_x = rend->cur_y = 0; nuclear@15: rend->in_progress = true; nuclear@15: memset(rend->pixels, 0, fb_width * fb_height * 4); nuclear@15: nuclear@15: printlog("starting a new rendering!\n"); nuclear@15: } nuclear@15: } nuclear@15: nuclear@15: nuclear@15: static Vector3 ray_trace(const Ray &ray, int iter) nuclear@15: { nuclear@15: return shade(ray, 0, iter); nuclear@15: } nuclear@15: nuclear@15: static Vector3 shade(const Ray &ray, float t, int iter) nuclear@15: { nuclear@15: return Vector3(1.0, 0.0, 0.0); nuclear@15: }