source: golgotha/src/render/software/span_buffer.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 12 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 17.6 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "arch.hh"
10#include "math/num_type.hh"
11#include "time/profile.hh"
12#include "software/r1_software.hh"
13#include "software/r1_software_globals.hh"
14#include "software/mappers.hh"
15#include "software/span_buffer.hh"
16#include "software/inline_fpu.hh"
17#include "software/amd3d/amd3d.h"
18
19//declarations of the arrays
20span_tri_info global_tri_list[MAX_TRIS];
21span_entry    global_span_list[MAX_SPANS];
22span_edge     global_edges[MAX_NUM_EDGES];
23span_edge     *new_edges[MAX_VERTICAL_RESOLUTION];
24span_edge     *remove_edges[MAX_VERTICAL_RESOLUTION];
25
26int num_global_tris  = 0;
27int num_global_spans = 1; //span #0 is a sentinel, unused
28int num_global_edges = 0;
29
30//"background" edges (so there are no holes. or if there are, you can
31//make them funky colors or somethin)
32span_tri_info tri_stack;
33span_edge active_list_head;
34span_edge active_list_tail;
35
36span_edge *compare_here;
37span_edge *temp_edge,*t1;
38
39inline void sort_in_new_edges(span_edge *first)
40{
41  compare_here = &active_list_head;
42
43  while (first)
44  {   
45    while (first->x > compare_here->next_active->x)
46    {     
47      compare_here = compare_here->next_active;     
48    }       
49   
50    //store first->next. remember, ->next and ->last_active are a union
51    // (to save space)
52
53    temp_edge = first->next;
54
55    first->last_active = compare_here;
56    first->next_active = compare_here->next_active;
57
58    compare_here->next_active->last_active = first;
59    compare_here->next_active = first;   
60   
61    compare_here = first;
62   
63    #ifdef DEBUG
64        if (!first->next_active)
65        {
66        sw32 a=0;
67        }
68    #endif
69
70        //first = first->next,see comment above
71    first = temp_edge;
72  }
73}
74
75span_entry *next_new_span;
76span_tri_info *cur_stack;
77span_tri_info *temp_stack;
78span_tri_info *e_tri;
79i4_bool everything_transparent;
80sw32 span_buff_x,span_buff_y,span_length;
81w16  *cur_scanline;
82
83span_edge **new_edge_list = new_edges;
84span_edge **remove_edge_list = remove_edges;
85
86float fx_fy[2];
87
88#define fx (fx_fy[0])
89#define fy (fx_fy[1])
90
91float e_ooz;
92float ooz_compare;
93
94i4_bool on_top;
95
96inline void intel_depth_at_pixel(tri_gradients *grads, float *result)
97{
98#ifdef USE_ASM
99  _asm
100  {
101    mov edi,dword ptr [grads]
102    mov esi,dword ptr [result]
103
104    fld dword ptr [fx_fy]
105    fld dword ptr [fx_fy+4]
106    fmul qword ptr [edi]tri_gradients.doozdy
107    fxch st(1)
108    fmul qword ptr [edi]tri_gradients.doozdx
109    fxch st(1)
110    fadd qword ptr [edi]tri_gradients.oozat00
111    fxch st(1)
112    faddp st(1),st(0)
113   
114    fstp dword ptr [esi]
115  }
116#else
117  *result = grads->oozat00 + fx*grads->doozdx + fy*grads->doozdy;
118#endif
119}
120
121i4_bool intel_build_triangle_span_lists()
122{
123  register span_edge *e;
124
125  new_edge_list    = new_edges;
126  remove_edge_list = remove_edges;
127  cur_scanline     = r1_software_render_buffer_ptr;
128  next_new_span    = &global_span_list[num_global_spans];
129
130  for (span_buff_y = 0; span_buff_y < r1_software_render_buffer_height;
131       span_buff_y++, cur_scanline += r1_software_render_buffer_wpl)
132  {
133    if (*new_edge_list)
134    {
135      sort_in_new_edges(*new_edge_list);
136    }
137    new_edge_list++;
138       
139    tri_stack.has_leader         = 0;
140    tri_stack.cur_span_start_x   = 0;
141    tri_stack.cur_span_start_ooz = -99999.f;
142    tri_stack.next_stack = tri_stack.last_stack = &tri_stack;
143   
144    fy = (float)span_buff_y;
145
146    //go through the x sorted active spans for this scanline
147    for (e=active_list_head.next_active; e != &active_list_tail; e=e->next_active)
148    {     
149      //round to nearest x
150      span_buff_x  = (e->x+0xFFFF) >> 16;
151     
152      fx = ((float)span_buff_x);// * oo65536);
153
154      e_tri = e->tri_1;
155
156      if (e->flags & LEADING_1)
157      {         
158        if ((e_tri->has_leader++)==0)
159        {
160          //e_ooz = e_tri->grads.oozat00 + (fx*e_tri->grads.doozdx) + (fy*e_tri->grads.doozdy);
161          intel_depth_at_pixel(&e_tri->grads, &e_ooz);
162
163          //leading edge. stack manipulation stuff
164          cur_stack = tri_stack.next_stack;
165         
166          everything_transparent = i4_T;
167          on_top                 = i4_T;
168         
169          //go down the stack until we find where this guy will go.         
170          while (cur_stack != &tri_stack)
171          {
172            //ooz_compare = e_ooz - (cur_stack->grads.oozat00     +
173                                   //cur_stack->grads.doozdx * fx +
174                                   //cur_stack->grads.doozdy * fy);
175
176            intel_depth_at_pixel(&cur_stack->grads, &ooz_compare);
177            ooz_compare = e_ooz - ooz_compare;
178
179            if ( ( (*(int *)&ooz_compare) & (1<<31) ) == 0) //if its positive
180              break;
181           
182            //if (ooz_compare == 0)
183            if ((*(int *)&ooz_compare) == 0) //its zero
184            {
185              //edges are of equal depth. compare the gradient.
186              if (e_tri->grads.doozdx > cur_stack->grads.doozdx)
187                break;
188            }
189           
190            on_top = i4_F;
191
192            //this will tell us if everything on top of (in front of) this surface is see-thru-able
193            if (cur_stack->type < SPAN_TRI_SEE_THRU)
194              everything_transparent = i4_F;
195           
196            cur_stack = cur_stack->next_stack;                                                           
197          }
198         
199          e_tri->next_stack = cur_stack;
200          e_tri->last_stack = cur_stack->last_stack;         
201 
202          cur_stack->last_stack->next_stack = e_tri;
203          cur_stack->last_stack             = e_tri;
204 
205          e_tri->cur_span_start_x = span_buff_x;
206          *(int *)&e_tri->cur_span_start_ooz = *(int *)&e_ooz; //for some reason the compiler did this with fld / fst
207
208          //if this is a solid span, and everything above it is transparent, gotta draw whatever is below it
209          //if this is a solid span, and its on top, gotta draw whatever is below it
210         
211          if (e_tri->type<SPAN_TRI_SEE_THRU && (on_top || everything_transparent))
212          {
213            cur_stack = e_tri->next_stack;
214
215            while (cur_stack != &tri_stack)
216            {
217              //we've gotta create spans for everything below this in the stack.
218              span_length = span_buff_x - cur_stack->cur_span_start_x;
219              if (span_length>0)
220              {
221                //make a span
222                next_new_span->s.x            = cur_stack->cur_span_start_x;
223                next_new_span->s.y            = span_buff_y;
224                next_new_span->s.width        = span_length;
225                next_new_span->s.ooz          = cur_stack->cur_span_start_ooz;
226                next_new_span->s.scanline_ptr = cur_scanline;
227               
228                //add to its triangles list of spans
229                next_new_span->s.next_tri_span = cur_stack->span_list_head;
230                cur_stack->span_list_head = num_global_spans;
231               
232                num_global_spans++;
233                next_new_span++;
234                if (num_global_spans>=MAX_SPANS) return i4_F;
235              }       
236              if (cur_stack->type<SPAN_TRI_SEE_THRU) break;             
237              cur_stack = cur_stack->next_stack;           
238            }
239          }
240        }
241      }
242      else //is a trailer
243      if ((e_tri->has_leader--)==1)
244      {
245        //trailing edge
246        //is this the end of a span for the tri currently on top of the stack?
247        if (tri_stack.next_stack==e_tri)
248        {
249          cur_stack = e_tri;
250         
251          span_length = span_buff_x - cur_stack->cur_span_start_x;
252          if (span_length>0)
253          {
254            //make a span           
255            next_new_span->s.x            = cur_stack->cur_span_start_x;
256            next_new_span->s.y            = span_buff_y;
257            next_new_span->s.width        = span_length;
258            next_new_span->s.ooz          = cur_stack->cur_span_start_ooz;
259            next_new_span->s.scanline_ptr = cur_scanline;
260               
261            //add to its triangles list of spans
262            next_new_span->s.next_tri_span = cur_stack->span_list_head;
263            cur_stack->span_list_head = num_global_spans;               
264               
265            num_global_spans++;
266            next_new_span++;
267            if (num_global_spans>=MAX_SPANS) return i4_F;
268          }
269                   
270          //setup the start of the next span on the stack
271          //IF this one wasnt transparent. otherwise,
272          //we want the span start info for that span to be
273          //maintained (unaltered)
274          if (e_tri->type<SPAN_TRI_SEE_THRU)
275          {
276            do
277            {
278              cur_stack = cur_stack->next_stack;
279             
280              if (cur_stack==&tri_stack)
281                break;
282             
283              cur_stack->cur_span_start_x = span_buff_x;
284
285              //calculate the ooz value for this span (needed for depth comparisons as well as actually
286              //writing out the span)
287
288              intel_depth_at_pixel(&cur_stack->grads, &cur_stack->cur_span_start_ooz);
289              // = cur_stack->grads.oozat00 + (cur_stack->grads.doozdy * fy) + (cur_stack->grads.doozdx * fx);
290
291            } while (cur_stack->type > SPAN_TRI_SEE_THRU);
292          }
293        }
294        else
295        {
296          //this span ends below whats on top of the stack.
297          //but if everything above this span is transparent, we need to draw it
298          temp_stack = e_tri->last_stack;
299         
300          while (temp_stack->type>SPAN_TRI_SEE_THRU)
301            temp_stack = temp_stack->last_stack;
302         
303          //did we make it past everything in the stack?
304          if (temp_stack==&tri_stack)
305          {
306            //if so, that means everything above us is transparent and this span
307            //will be seen, so we gotta draw it
308         
309            span_length = span_buff_x - e_tri->cur_span_start_x;
310            if (span_length>0)
311            {                         
312              //make a span
313              next_new_span->s.x            = e_tri->cur_span_start_x;
314              next_new_span->s.y            = span_buff_y;
315              next_new_span->s.width        = span_length;
316              next_new_span->s.ooz          = e_tri->cur_span_start_ooz;
317              next_new_span->s.scanline_ptr = cur_scanline;
318               
319              //add to its triangles list of spans
320              next_new_span->s.next_tri_span = e_tri->span_list_head;
321              e_tri->span_list_head = num_global_spans;
322               
323              num_global_spans++;
324              next_new_span++;
325              if (num_global_spans>=MAX_SPANS) return i4_F;
326            }
327
328            //setup the start of the next span in
329            //IF this one wasnt transparent. otherwise,
330            //we want the span start info for that span to be
331            //maintained (unaltered)
332            temp_stack = e_tri;
333
334            if (e_tri->type<SPAN_TRI_SEE_THRU)
335            {
336              do
337              {
338                temp_stack = temp_stack->next_stack;
339                if (temp_stack == &tri_stack)
340                  break;
341               
342                temp_stack->cur_span_start_x = span_buff_x;
343
344                //calculate the ooz value for this span (needed for depth comparisons as well as actually
345                //writing out the span)           
346                //temp_stack->cur_span_start_ooz = temp_stack->grads.oozat00 +
347                //                                (temp_stack->grads.doozdy * fy) +
348                //                                (temp_stack->grads.doozdx * fx);
349
350                intel_depth_at_pixel(&temp_stack->grads, &temp_stack->cur_span_start_ooz);
351
352              } while (temp_stack->type > SPAN_TRI_SEE_THRU);
353            }
354          }                   
355        }
356               
357        e_tri->last_stack->next_stack = e_tri->next_stack;
358        e_tri->next_stack->last_stack = e_tri->last_stack;               
359      }     
360    }
361       
362    //done with this scanline.
363    //dont forget that IF we want to draw the background, we need to make one more span going from
364    //tri_stack.cur_span_start_x to the rightmost pixel on the screen (if that area is "open")
365
366    //remove the ones that need removing
367    temp_edge = *remove_edge_list;
368    while (temp_edge)
369    {     
370      temp_edge->last_active->next_active = temp_edge->next_active;
371      temp_edge->next_active->last_active = temp_edge->last_active;
372
373      temp_edge = temp_edge->next_remove;
374    }
375    remove_edge_list++;
376
377    //step the active edges
378    temp_edge = active_list_head.next_active;
379    while (temp_edge != &active_list_tail)
380    {
381      temp_edge->x += temp_edge->dxdy;
382     
383      //make sure the edges remain sorted           
384      compare_here = temp_edge;
385      if (temp_edge->x < compare_here->last_active->x)
386      {
387        t1 = temp_edge->next_active;
388
389        while (temp_edge->x < compare_here->last_active->x)
390          compare_here = compare_here->last_active;
391     
392        //get temp_edge out of its current spot
393        temp_edge->last_active->next_active = temp_edge->next_active;
394        temp_edge->next_active->last_active = temp_edge->last_active;
395
396        //insert it between compare_here and its predecessor     
397        compare_here->last_active->next_active = temp_edge;
398       
399        temp_edge->last_active = compare_here->last_active;
400        compare_here->last_active = temp_edge;
401
402        temp_edge->next_active = compare_here;
403       
404        temp_edge = t1;
405      }
406      else
407      {
408        temp_edge = temp_edge->next_active;
409      }
410    }   
411  } 
412  return i4_T;
413}
414
415void span_draw_solid_color(span_tri_info *tri)
416
417  span_entry *s = &global_span_list[tri->span_list_head];
418  w16 *start_pixel;
419
420  solid_blend_span left; 
421 
422  left.color = tri->color;
423
424  while (s!=global_span_list)
425  {   
426    cur_scanline_texture_func(s->s.scanline_ptr,(s->s.x<<1),&left,s->s.width);
427
428    s = &global_span_list[s->s.next_tri_span];
429  }
430}
431
432void init_span_buffer()
433{
434  memset(remove_edges,0,sizeof(span_edge *) * MAX_VERTICAL_RESOLUTION);
435  memset(new_edges,0,sizeof(span_edge *) * MAX_VERTICAL_RESOLUTION);
436  num_global_spans = 1; //span #0 is a sentinel, unused
437  num_global_tris  = 0;
438  num_global_edges = 0;
439 
440  //setup "background" (leaves no holes) 
441  active_list_head.x           = (sw32)(-2048) << 16; //large negative fixed number
442  active_list_head.dxdy        = 0;
443  active_list_head.flags       = LEADING_1;
444  active_list_head.tri_1       = &tri_stack;
445
446  active_list_tail.x           = (sw32)(2048) << 16; //large fixed number
447  active_list_tail.dxdy        = 0;
448  active_list_tail.flags       = 0;
449  active_list_tail.tri_1       = &tri_stack;
450
451  tri_stack.next_stack = tri_stack.last_stack = &tri_stack;
452  tri_stack.grads.doozdx = 0;
453  tri_stack.grads.doozdy = 0;
454  tri_stack.grads.oozat00 = -999999.f;
455 
456  tri_stack.color = 0x55555555;
457
458  tri_stack.type = SPAN_TRI_SOLID_FILL;
459}
460
461i4_profile_class build_span_lists("build span lists");
462i4_profile_class pf_software_add_start_edge("software::add_start_edge");
463
464sw32 shared_edges = 0;
465sw32 total_edges  = 0;
466
467void clear_spans()
468{
469  memset(remove_edges,0,sizeof(span_edge *) * MAX_VERTICAL_RESOLUTION);
470  memset(new_edges,0,sizeof(span_edge *) * MAX_VERTICAL_RESOLUTION);
471 
472  num_global_spans = 1; //span #0 is a sentinel, unused
473  num_global_tris  = 0;
474  num_global_edges = 0;
475 
476  //i4_warning("total edges: %3d shared edges: %3d",total_edges,shared_edges);
477  total_edges  = 0;
478  shared_edges = 0;
479}
480
481void flush_spans() //set all pointers in the scanline list to 0
482{
483  //take it out of single precision
484  if (!num_global_tris) return;
485
486  sw32 i;
487  span_tri_info *t;
488 
489  //reset these pointers incase they got messed with
490  active_list_head.next_active = &active_list_tail;
491  active_list_head.last_active = 0;
492 
493  active_list_tail.next_active = 0;
494  active_list_tail.last_active = &active_list_head;
495 
496  build_span_lists.start();
497 
498  //single precision truncate mode from here on out
499  start_trunc();
500  start_single();
501
502  if (!cur_build_span_lists_function || !cur_build_span_lists_function())
503  {
504    //if the function isnt defined or didnt succeed, issue an error
505    i4_warning("software::build triangle span lists failed");   
506  }
507 
508  build_span_lists.stop();
509
510  //draw all the solid ones
511  for (i=0,t=global_tri_list; i<num_global_tris; i++,t++)
512  {
513    if (!t->span_list_head) continue;           
514    if (t->type > SPAN_TRI_SEE_THRU) continue;
515   
516    cur_scanline_texture_func = texture_scanline_functions[t->type];
517    (span_draw_functions[t->type])(t);   
518  }   
519 
520 
521  //draw all the transparent ones
522  for (i=0,t=global_tri_list; i<num_global_tris; i++,t++)
523  {   
524    if (!t->span_list_head) continue;
525    if (t->type < SPAN_TRI_SEE_THRU) continue;       
526   
527    cur_scanline_texture_func = texture_scanline_functions[t->type];
528    (span_draw_functions[t->type])(t);       
529  }
530 
531#ifdef USE_AMD3D 
532  if (do_amd3d)
533    _asm femms  //end the mmx usage for all the tmappers
534#endif
535
536  stop_single();
537  stop_trunc();   
538}
Note: See TracBrowser for help on using the repository browser.