/**********************************************************************
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)
***********************************************************************/
#ifndef SPAN_BUFFER_HH
#define SPAN_BUFFER_HH
#include "time/profile.hh"
union span_entry;
struct span_tri_info;
union span_entry //needs to be 8 byte aligned
{
struct
{
//dont reorder these, the position of the x and y are required for a special amd3d mmx data load
sw32 x;
sw32 y;
sw32 width;
w32 next_tri_span; //index into the global span list of the next span
float ooz; //this ooz will be the ooz at the spans start
//since this is non-intersecting span sorting,
//this is all we need
w16 *scanline_ptr;
} s;
double alignment_dummy;
}; //should be 16 bytes
struct span_tri_info //needs to be 8 byte aligned
{
tri_gradients grads;
w16 *texture;
union
{
sw32 texture_width;
w32 color;
};
sw32 texture_height;
float cur_span_start_ooz;
span_tri_info *next_stack;
span_tri_info *last_stack;
sw16 cur_span_start_x; //used when creating spans
w16 span_list_head;
w8 twidth_log2;
w8 has_leader;
w8 type;
w8 color_tint;
}; //including the tri_gradients structure, this should be 104 bytes
enum {MAX_TRIS = 20000};
extern span_tri_info global_tri_list[]; //sized of max_tris
extern int num_global_tris;
inline span_tri_info *new_span_tri()
{
if (num_global_tris < MAX_TRIS)
{
num_global_tris++;
span_tri_info *t = &global_tri_list[num_global_tris-1];
t->span_list_head=0;
t->next_stack=0;
t->last_stack=0;
t->has_leader=0;
return t;
}
#ifdef DEBUG
i4_warning("out of span_tri_info memory");
#endif
return 0;
}
enum {MAX_SPANS = 30000};
extern span_entry global_span_list[]; //sized to max_spans
extern int num_global_spans;
enum {MAX_VERTICAL_RESOLUTION = 768};
enum {MAX_NUM_EDGES = 10000};
struct span_edge //needs to be 4 byte aligned
{
sw32 x;
sw32 dxdy;
span_tri_info *tri_1;
span_edge *next_remove; //in setup and when generating spans, this is the next remove edge (ends on the same scanline as this)
span_edge *next_active; //when generating the spans, this is the next active span in the active span list
union
{
span_edge *last_active;//when generating the spans, this is the previous active span in the active span list
span_edge *next; //in setup, this is the next new edge (starts on the same scanline as this)
};
w8 flags;
//flags & LEADING_1 means its a leading edge
//lower 7 bits define the type (see mappers.hh)
w8 pad1;
w8 pad2;
w8 pad3; //pad it to 28 bytes
};
extern span_edge *new_edges[];
extern span_edge *remove_edges[];
extern span_edge global_edges[];
extern span_edge *active_list;
extern int num_global_edges;
inline span_edge *new_span_edge()
{
if (num_global_edges < MAX_NUM_EDGES)
{
num_global_edges++;
span_edge *e = &global_edges[num_global_edges-1];
e->next_active = 0;
e->last_active = 0;
return e;
}
#ifdef DEBUG
//i4_warning("out of span_edge memory");
#endif
return 0;
}
extern i4_profile_class pf_software_add_start_edge;
extern sw32 shared_edges;
extern sw32 total_edges;
inline void add_start_edge(span_edge *e,sw32 scanline)
{
pf_software_add_start_edge.start();
span_edge *compare_here = new_edges[scanline];
span_edge *last_compare = 0;
while (compare_here && e->x > compare_here->x)
{
last_compare = compare_here;
compare_here = compare_here->next;
}
e->next = compare_here;
//total_edges++;
if (last_compare)
{
last_compare->next = e;
/*
if (compare_here && (compare_here->x == e->x) && (compare_here->dxdy==e->dxdy))
{
shared_edges++;
}
*/
}
else
new_edges[scanline] = e;
pf_software_add_start_edge.stop();
}
inline void add_remove_edge(span_edge *e,sw32 scanline)
{
e->next_remove = remove_edges[scanline];
remove_edges[scanline] = e;
}
void init_span_buffer();
void clear_spans();
void flush_spans();
#endif