/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
#include "r1_api.hh"
#include "r1_win.hh"
#include "image/image.hh"
#include "palette/pal.hh"
#include "threads/threads.hh"
#include "tmanage.hh"
#include "time/time.hh"
// this lock prevents 2 threads from drawing at the same time
static i4_critical_section_class softz_lock;
static int defer_draws=0;
static i4_pixel_format softz_pixel_fmt;
class r1_softz_window;
static r1_softz_window *cur_win=0;
class r1_softz_window : public r1_render_window_class
{
public:
i4_image_class *im;
float *zbuffer;
i4_draw_context_class ctext;
volatile int rendering;
r1_softz_window(int w, int h, r1_expand_type type);
void clear_z(int x1, int y1, int x2, int y2, float z)
{
float *s=zbuffer + y1*width()+x1;
int t=(x2-x1+1);
for (int y=y1; y<=y2; y++)
{
for (int i=0; iput_image(local_image, 0,0, context);
r1_render_window_class::draw(context);
}
virtual void begin_render()
{
softz_lock.lock();
rendering=1;
cur_win=this;
if (cur_win->width()!=cur_win->im->width() ||
cur_win->height()!=cur_win->im->height())
i4_error("image wrong size");
}
virtual void end_render()
{
cur_win=0;
rendering=0;
softz_lock.unlock();
}
char *name() { return "softz_window"; }
virtual void private_resize(w16 new_width, w16 new_height)
{
r1_render_window_class::private_resize(new_width, new_height);
delete im;
i4_free(zbuffer);
zbuffer=(float *)i4_malloc(new_width* new_height*sizeof(float), "");
im=i4_create_image(new_width, new_height, i4_pal_man.register_pal(&softz_pixel_fmt));
}
~r1_softz_window()
{
while (rendering)
{
i4_warning("waiting on render to finish");
i4_sleep(1);
}
delete im;
i4_free(zbuffer);
}
};
class r1_softz_tman : public r1_texture_manager_class
{
public:
r1_softz_tman(const i4_pal *pal) : r1_texture_manager_class(pal) {}
virtual void init() {}
virtual void uninit() {}
virtual void next_frame() {}
virtual void reset() {}
virtual void toggle_texture_loading() {}
virtual r1_miplevel_t *get_texture(r1_texture_handle handle,
w32 frame_counter,
sw32 desired_width,
sw32 &w, sw32 &h)
{
return 0;
}
virtual i4_bool valid_handle(r1_texture_handle handle)
{
return i4_F;
}
public:
virtual i4_bool immediate_mip_load(r1_mip_load_info *load_info) { return i4_T; }
virtual i4_bool async_mip_load(r1_mip_load_info *load_info) { return i4_T; }
virtual void free_mip(r1_vram_handle_type vram_handle) {}
};
class r1_softz_api : public r1_render_api_class
{
public:
char *name() { return "Software Z Buffer"; }
virtual void use_texture(r1_texture_handle material_ref,
sw32 desired_width,
w32 frame)
{}
virtual void disable_texture() {}
virtual void set_z_range(float near_z, float far_z) {}
virtual void render_poly(int t_verts, r1_vert *verts)
{
render_lines(t_verts-1, verts);
r1_vert l[2];
l[0]=verts[0];
l[1]=verts[t_verts-1];
render_lines(1, l);
}
r1_softz_api()
{
softz_pixel_fmt.default_format();
softz_pixel_fmt.alpha_mask=0;
softz_pixel_fmt.calc_shift();
}
i4_bool init(i4_display_class *display)
{
tmanager=new r1_softz_tman(display->get_palette());
return i4_T;
}
void uninit()
{
delete tmanager;
}
virtual void render_pixel(r1_vert *pixel)
{
int iw=cur_win->width();
float *zbuffer=cur_win->zbuffer;
int off=(int)pixel->px + ((int)pixel->py)*iw;
if (write_mask & R1_COMPARE_W)
if (zbuffer[off]<=pixel->v.z)
return ;
w32 *im_data=(w32 *)cur_win->im->data;
if (write_mask & R1_WRITE_COLOR)
{
int r=(int)(pixel->r*255.0),
g=(int)(pixel->g*255.0),
b=(int)(pixel->b*255.0);
w32 c=(r<<16)|(g<<8)|b;
im_data[off]=c;
}
if (write_mask & R1_WRITE_W)
zbuffer[off]=pixel->v.z;
}
virtual void render_lines(int t_lines, r1_vert *verts)
{
w32 *im_data=(w32 *)cur_win->im->data;
int iw=cur_win->im->width();
float *zbuffer=cur_win->zbuffer;
for (int i=0; iyd ? xd+1 : yd+1;
float r=verts[i].r, g=verts[i].g, b=verts[i].b;
float rs=(verts[i+1].r-r)/(float)steps;
float gs=(verts[i+1].g-g)/(float)steps;
float bs=(verts[i+1].b-b)/(float)steps;
float xs=(verts[i+1].px-x)/(float)steps;
float ys=(verts[i+1].py-y)/(float)steps;
float zs=(verts[i+1].v.z-z)/(float)steps;
for (int j=0; jz)
{
if (write_mask & R1_WRITE_COLOR)
{
int ir=(int)(r*255.0), ig=(int)(g*255.0), ib=(int)(b*255.0);
w32 c=(ir<<16)|(ig<<8)|ib;
im_data[off]=c;
r+=rs;
g+=gs;
b+=bs;
}
if (write_mask & R1_WRITE_W)
zbuffer[off]=z;
}
x+=xs;
y+=ys;
z+=zs;
}
}
}
virtual i4_image_class *create_compatible_image(w16 w, w16 h)
{
return i4_create_image(w,h, i4_pal_man.register_pal(&softz_pixel_fmt));
}
virtual void clear_area(int x1, int y1, int x2, int y2, w32 color, float z)
{
if (write_mask & R1_WRITE_COLOR)
cur_win->im->bar(x1,y1,x2,y2, color, cur_win->ctext);
if (write_mask & R1_WRITE_W)
cur_win->clear_z(x1,y1,x2,y2, z);
}
virtual r1_render_window_class *create_render_window(int visable_w, int visable_h,
r1_expand_type type)
{
return new r1_softz_window(visable_w, visable_h, type);
}
virtual void copy_part(i4_image_class *im,
int x, int y, // position on screen
int x1, int y1, // area of image to copy
int x2, int y2) {}
};
static r1_softz_api softz;
r1_softz_window::r1_softz_window(int w, int h, r1_expand_type type)
: r1_render_window_class(w,h, type, &softz),
ctext(0,0,w-1,h-1)
{
zbuffer=(float *)i4_malloc(w*h*sizeof(float), "");
im=i4_create_image(w,h, i4_pal_man.register_pal(&softz_pixel_fmt));
rendering=0;
}