2 * Copyright (C) 2011 Gilead Kutnick "Exophase" <exophase@gmail.com>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
22 typedef s32 fixed_type;
24 #define EDGE_STEP_BITS 32
27 #define fixed_center(value) \
28 ((((fixed_type)value) << FIXED_BITS) + (1 << (FIXED_BITS - 1))) \
30 #define int_to_fixed(value) \
31 (((fixed_type)value) << FIXED_BITS) \
33 #define fixed_to_int(value) \
34 ((value) >> FIXED_BITS) \
36 #define fixed_mul(_a, _b) \
37 (((s64)(_a) * (_b)) >> FIXED_BITS) \
39 #define fixed_to_double(value) \
40 ((value) / (double)(1 << FIXED_BITS)) \
42 #define double_to_fixed(value) \
43 (fixed_type)(((value) * (double)(1 << FIXED_BITS))) \
47 fixed_type current_value;
50 fixed_type gradient_area_x;
51 fixed_type gradient_area_y;
76 u32 span_pixel_blocks = 0;
83 u32 untextured_pixels = 0;
85 u32 transparent_pixels = 0;
87 u32 state_changes = 0;
88 u32 render_buffer_flushes = 0;
89 u32 trivial_rejects = 0;
91 void flush_render_block_buffer(psx_gpu_struct *psx_gpu)
97 u32 fixed_reciprocal(u32 denominator, u32 *_shift)
99 u32 shift = __builtin_clz(denominator);
100 u32 denominator_normalized = denominator << shift;
102 // Implement with a DP divide
104 (double)((1ULL << 62) + (denominator_normalized - 1)) /
105 (double)denominator_normalized;
107 *_shift = 62 - shift;
111 fixed_type fixed_reciprocal_multiply(s32 numerator, u32 reciprocal,
112 u32 reciprocal_sign, u32 shift)
114 u32 numerator_sign = (u32)numerator >> 31;
115 u32 flip_sign = numerator_sign ^ reciprocal_sign;
116 u32 flip_sign_mask = ~(flip_sign - 1);
119 numerator = abs(numerator);
121 value = ((u64)numerator * reciprocal) >> shift;
123 value ^= flip_sign_mask;
124 value -= flip_sign_mask;
129 s32 triangle_signed_area_x2(s32 x0, s32 y0, s32 x1, s32 y1, s32 x2, s32 y2)
131 return ((x1 - x0) * (y2 - y1)) - ((x2 - x1) * (y1 - y0));
134 u32 fetch_texel_4bpp(psx_gpu_struct *psx_gpu, u32 u, u32 v)
136 u8 *texture_ptr_8bpp = psx_gpu->texture_page_ptr;
137 u32 texel = texture_ptr_8bpp[(v * 2048) + (u / 2)];
146 return psx_gpu->clut_ptr[texel];
149 u32 fetch_texel_8bpp(psx_gpu_struct *psx_gpu, u32 u, u32 v)
151 u8 *texture_ptr_8bpp = psx_gpu->texture_page_ptr;
152 u32 texel = texture_ptr_8bpp[(v * 2048) + u];
156 return psx_gpu->clut_ptr[texel];
159 u32 fetch_texel_16bpp(psx_gpu_struct *psx_gpu, u32 u, u32 v)
161 u16 *texture_ptr_16bpp = psx_gpu->texture_page_ptr;
165 return texture_ptr_16bpp[(v * 1024) + u];
168 u32 fetch_texel(psx_gpu_struct *psx_gpu, u32 u, u32 v)
170 u &= psx_gpu->texture_mask_width;
171 v &= psx_gpu->texture_mask_height;
173 switch(psx_gpu->texture_mode)
175 case TEXTURE_MODE_4BPP:
176 return fetch_texel_4bpp(psx_gpu, u, v);
178 case TEXTURE_MODE_8BPP:
179 return fetch_texel_8bpp(psx_gpu, u, v);
181 case TEXTURE_MODE_16BPP:
182 return fetch_texel_16bpp(psx_gpu, u, v);
188 void draw_pixel(psx_gpu_struct *psx_gpu, s32 r, s32 g, s32 b, u32 texel,
189 u32 x, u32 y, u32 flags)
202 if(flags & RENDER_FLAGS_BLEND)
204 if(((flags & RENDER_FLAGS_TEXTURE_MAP) == 0) || (texel & 0x8000))
206 s32 fb_pixel = psx_gpu->vram[(y * 1024) + x];
207 s32 fb_r = fb_pixel & 0x1F;
208 s32 fb_g = (fb_pixel >> 5) & 0x1F;
209 s32 fb_b = (fb_pixel >> 10) & 0x1F;
213 switch(psx_gpu->blend_mode)
215 case BLEND_MODE_AVERAGE:
237 case BLEND_MODE_SUBTRACT:
253 case BLEND_MODE_ADD_FOURTH:
272 pixel = r | (g << 5) | (b << 10);
274 if(psx_gpu->mask_apply || (texel & 0x8000))
277 psx_gpu->vram[(y * 1024) + x] = pixel;
280 s32 dither_table[4][4] =
288 void render_span(psx_gpu_struct *psx_gpu, _span_struct *span, s32 y,
291 s32 left_x = span->left_x >> EDGE_STEP_BITS;
292 s32 right_x = span->right_x >> EDGE_STEP_BITS;
293 s32 current_x = left_x;
296 fixed_type current_u = span->u.current_value;
297 fixed_type current_v = span->v.current_value;
298 fixed_type current_r = span->r.current_value;
299 fixed_type current_g = span->g.current_value;
300 fixed_type current_b = span->b.current_value;
302 if(y < psx_gpu->viewport_start_y)
305 if(y > psx_gpu->viewport_end_y)
308 if(right_x < psx_gpu->viewport_start_x)
311 if(current_x > psx_gpu->viewport_end_x)
316 if(current_x < psx_gpu->viewport_start_x)
317 current_x = psx_gpu->viewport_start_x;
319 if(right_x > psx_gpu->viewport_end_x + 1)
320 right_x = psx_gpu->viewport_end_x + 1;
322 delta_x = current_x - span->base_x;
324 current_u += delta_x * span->u.step_dx;
325 current_v += delta_x * span->v.step_dx;
326 current_r += delta_x * span->r.step_dx;
327 current_g += delta_x * span->g.step_dx;
328 current_b += delta_x * span->b.step_dx;
330 span_pixels += right_x - current_x;
331 span_pixel_blocks += ((right_x / 8) - (current_x / 8)) + 1;
333 while(current_x < right_x)
335 s32 color_r, color_g, color_b;
338 if(psx_gpu->mask_evaluate &&
339 (psx_gpu->vram[(y * 1024) + current_x] & 0x8000))
344 if(flags & RENDER_FLAGS_SHADE)
346 color_r = fixed_to_int(current_r);
347 color_g = fixed_to_int(current_g);
348 color_b = fixed_to_int(current_b);
352 color_r = psx_gpu->primitive_color & 0xFF;
353 color_g = (psx_gpu->primitive_color >> 8) & 0xFF;
354 color_b = (psx_gpu->primitive_color >> 16) & 0xFF;
357 if(flags & RENDER_FLAGS_TEXTURE_MAP)
359 u32 texel_r, texel_g, texel_b;
360 u32 u = fixed_to_int(current_u);
361 u32 v = fixed_to_int(current_v);
363 texel = fetch_texel(psx_gpu, u, v);
367 transparent_pixels++;
371 texel_r = texel & 0x1F;
372 texel_g = (texel >> 5) & 0x1F;
373 texel_b = (texel >> 10) & 0x1F;
375 if((flags & RENDER_FLAGS_MODULATE_TEXELS) == 0)
383 color_r = texel_r << 7;
384 color_g = texel_g << 7;
385 color_b = texel_b << 7;
397 if(psx_gpu->dither_mode && ((flags & RENDER_FLAGS_SHADE) ||
398 ((flags & RENDER_FLAGS_TEXTURE_MAP) &&
399 ((flags & RENDER_FLAGS_MODULATE_TEXELS) == 0))))
401 s32 dither_offset = dither_table[y % 4][current_x % 4];
402 color_r += dither_offset;
403 color_g += dither_offset;
404 color_b += dither_offset;
420 draw_pixel(psx_gpu, color_r, color_g, color_b, texel, current_x, y, flags);
424 current_u += span->u.step_dx;
425 current_v += span->v.step_dx;
426 current_r += span->r.step_dx;
427 current_g += span->g.step_dx;
428 current_b += span->b.step_dx;
434 void increment_span(_span_struct *span)
436 span->left_x += span->left_dx_dy;
437 span->right_x += span->right_dx_dy;
439 span->u.current_value += span->u.step_dy;
440 span->v.current_value += span->v.step_dy;
441 span->r.current_value += span->r.step_dy;
442 span->g.current_value += span->g.step_dy;
443 span->b.current_value += span->b.step_dy;
446 void decrement_span(_span_struct *span)
448 span->left_x += span->left_dx_dy;
449 span->right_x += span->right_dx_dy;
451 span->u.current_value -= span->u.step_dy;
452 span->v.current_value -= span->v.step_dy;
453 span->r.current_value -= span->r.step_dy;
454 span->g.current_value -= span->g.step_dy;
455 span->b.current_value -= span->b.step_dy;
459 #define compute_gradient_area_x(interpolant) \
461 span.interpolant.gradient_area_x = \
462 triangle_signed_area_x2(a->interpolant, a->y, b->interpolant, b->y, \
463 c->interpolant, c->y); \
466 #define compute_gradient_area_y(interpolant) \
468 span.interpolant.gradient_area_y = \
469 triangle_signed_area_x2(a->x, a->interpolant, b->x, b->interpolant, \
470 c->x, c->interpolant); \
473 #define compute_all_gradient_areas() \
474 compute_gradient_area_x(u); \
475 compute_gradient_area_x(v); \
476 compute_gradient_area_x(r); \
477 compute_gradient_area_x(g); \
478 compute_gradient_area_x(b); \
479 compute_gradient_area_y(u); \
480 compute_gradient_area_y(v); \
481 compute_gradient_area_y(r); \
482 compute_gradient_area_y(g); \
483 compute_gradient_area_y(b) \
485 #define set_interpolant_base(interpolant, base_vertex) \
486 span->interpolant.step_dx = \
487 fixed_reciprocal_multiply(span->interpolant.gradient_area_x, reciprocal, \
488 span->triangle_winding, shift); \
489 span->interpolant.step_dy = \
490 fixed_reciprocal_multiply(span->interpolant.gradient_area_y, reciprocal, \
491 span->triangle_winding, shift); \
492 span->interpolant.current_value = fixed_center(base_vertex->interpolant) \
494 #define set_interpolant_bases(base_vertex) \
497 u32 reciprocal = fixed_reciprocal(span->triangle_area, &shift); \
498 shift -= FIXED_BITS; \
499 set_interpolant_base(u, base_vertex); \
500 set_interpolant_base(v, base_vertex); \
501 set_interpolant_base(r, base_vertex); \
502 set_interpolant_base(g, base_vertex); \
503 set_interpolant_base(b, base_vertex); \
504 span->base_x = span->left_x >> EDGE_STEP_BITS; \
507 #define compute_edge_delta(edge, start, end, height) \
509 s32 x_start = start->x; \
510 s32 x_end = end->x; \
511 s32 width = x_end - x_start; \
513 s32 shift = __builtin_clz(height); \
514 u32 height_normalized = height << shift; \
515 u32 height_reciprocal = ((1ULL << 50) + (height_normalized - 1)) / \
518 shift -= (50 - EDGE_STEP_BITS); \
521 ((((s64)x_start * height) + (height - 1)) * height_reciprocal) << shift; \
522 span->edge##_dx_dy = ((s64)width * height_reciprocal) << shift; \
526 #define render_spans_up(height) \
529 decrement_span(span); \
530 render_span(psx_gpu, span, current_y, flags); \
535 #define render_spans_down(height) \
538 render_span(psx_gpu, span, current_y, flags); \
539 increment_span(span); \
544 #define render_spans_up_up(minor, major) \
545 s32 current_y = bottom->y - 1; \
546 s32 height_minor_a = bottom->y - middle->y; \
547 s32 height_minor_b = middle->y - top->y; \
548 s32 height_major = height_minor_a + height_minor_b; \
550 compute_edge_delta(major, bottom, top, height_major); \
551 compute_edge_delta(minor, bottom, middle, height_minor_a); \
552 set_interpolant_bases(bottom); \
554 render_spans_up(height_minor_a); \
556 compute_edge_delta(minor, middle, top, height_minor_b); \
557 render_spans_up(height_minor_b) \
559 void render_spans_up_left(psx_gpu_struct *psx_gpu, _span_struct *span,
560 vertex_struct *bottom, vertex_struct *middle, vertex_struct *top, u32 flags)
562 render_spans_up_up(left, right);
565 void render_spans_up_right(psx_gpu_struct *psx_gpu, _span_struct *span,
566 vertex_struct *bottom, vertex_struct *middle, vertex_struct *top, u32 flags)
568 render_spans_up_up(right, left);
571 #define render_spans_down_down(minor, major) \
572 s32 current_y = top->y; \
573 s32 height_minor_a = middle->y - top->y; \
574 s32 height_minor_b = bottom->y - middle->y; \
575 s32 height_major = height_minor_a + height_minor_b; \
577 compute_edge_delta(minor, top, middle, height_minor_a); \
578 compute_edge_delta(major, top, bottom, height_major); \
579 set_interpolant_bases(top); \
581 render_spans_down(height_minor_a); \
583 compute_edge_delta(minor, middle, bottom, height_minor_b); \
584 render_spans_down(height_minor_b) \
586 void render_spans_down_left(psx_gpu_struct *psx_gpu, _span_struct *span,
587 vertex_struct *top, vertex_struct *middle, vertex_struct *bottom, u32 flags)
589 render_spans_down_down(left, right);
592 void render_spans_down_right(psx_gpu_struct *psx_gpu, _span_struct *span,
593 vertex_struct *top, vertex_struct *middle, vertex_struct *bottom, u32 flags)
595 render_spans_down_down(right, left);
598 #define render_spans_up_flat(bottom_left, bottom_right, top_left, top_right) \
599 s32 current_y = bottom_left->y - 1; \
600 s32 height = bottom_left->y - top_left->y; \
602 compute_edge_delta(left, bottom_left, top_left, height); \
603 compute_edge_delta(right, bottom_right, top_right, height); \
604 set_interpolant_bases(bottom_left); \
605 render_spans_up(height) \
607 void render_spans_up_a(psx_gpu_struct *psx_gpu, _span_struct *span,
608 vertex_struct *bottom_left, vertex_struct *bottom_right, vertex_struct *top,
611 render_spans_up_flat(bottom_left, bottom_right, top, top);
614 void render_spans_up_b(psx_gpu_struct *psx_gpu, _span_struct *span,
615 vertex_struct *bottom, vertex_struct *top_left, vertex_struct *top_right,
618 render_spans_up_flat(bottom, bottom, top_left, top_right);
621 #define render_spans_down_flat(top_left, top_right, bottom_left, bottom_right) \
622 s32 current_y = top_left->y; \
623 s32 height = bottom_left->y - top_left->y; \
625 compute_edge_delta(left, top_left, bottom_left, height); \
626 compute_edge_delta(right, top_right, bottom_right, height); \
627 set_interpolant_bases(top_left); \
628 render_spans_down(height) \
630 void render_spans_down_a(psx_gpu_struct *psx_gpu, _span_struct *span,
631 vertex_struct *top_left, vertex_struct *top_right, vertex_struct *bottom,
634 render_spans_down_flat(top_left, top_right, bottom, bottom);
637 void render_spans_down_b(psx_gpu_struct *psx_gpu, _span_struct *span,
638 vertex_struct *top, vertex_struct *bottom_left, vertex_struct *bottom_right,
641 render_spans_down_flat(top, top, bottom_left, bottom_right);
644 void render_spans_up_down(psx_gpu_struct *psx_gpu, _span_struct *span,
645 vertex_struct *middle, vertex_struct *top, vertex_struct *bottom, u32 flags)
647 s32 middle_y = middle->y;
648 s32 current_y = middle_y - 1;
649 s32 height_minor_a = middle->y - top->y;
650 s32 height_minor_b = bottom->y - middle->y;
651 s32 height_major = height_minor_a + height_minor_b;
655 compute_edge_delta(left, middle, top, height_minor_a);
656 compute_edge_delta(right, bottom, top, height_major);
657 set_interpolant_bases(middle);
659 right_x_mid = span->right_x + (span->right_dx_dy * height_minor_b);
660 span->right_x = right_x_mid;
662 render_spans_up(height_minor_a);
664 compute_edge_delta(left, middle, bottom, height_minor_b);
665 set_interpolant_bases(middle);
667 span->right_dx_dy *= -1;
668 span->right_x = right_x_mid;
669 current_y = middle_y;
671 render_spans_down(height_minor_b);
674 #define vertex_swap(_a, _b) \
676 vertex_struct *temp_vertex = _a; \
679 triangle_winding ^= 1; \
683 #define triangle_y_direction_up 1
684 #define triangle_y_direction_flat 2
685 #define triangle_y_direction_down 0
687 #define triangle_winding_positive 0
688 #define triangle_winding_negative 1
690 #define triangle_set_direction(direction_variable, value) \
691 u32 direction_variable = (u32)(value) >> 31; \
693 direction_variable = 2 \
695 #define triangle_case(direction_a, direction_b, direction_c, winding) \
696 case (triangle_y_direction_##direction_a | \
697 (triangle_y_direction_##direction_b << 2) | \
698 (triangle_y_direction_##direction_c << 4) | \
699 (triangle_winding_##winding << 6)) \
702 void render_triangle(psx_gpu_struct *psx_gpu, vertex_struct *vertexes,
706 u32 triangle_winding = 0;
709 vertex_struct *a = &(vertexes[0]);
710 vertex_struct *b = &(vertexes[1]);
711 vertex_struct *c = &(vertexes[2]);
713 triangle_area = triangle_signed_area_x2(a->x, a->y, b->x, b->y, c->x, c->y);
717 if(triangle_area == 0)
731 if((c->y - a->y) >= 512)
734 if(triangle_area < 0)
736 triangle_area = -triangle_area;
737 triangle_winding ^= 1;
752 if((c->x - a->x) >= 1024)
755 s32 y_delta_a = b->y - a->y;
756 s32 y_delta_b = c->y - b->y;
757 s32 y_delta_c = c->y - a->y;
759 triangle_set_direction(y_direction_a, y_delta_a);
760 triangle_set_direction(y_direction_b, y_delta_b);
761 triangle_set_direction(y_direction_c, y_delta_c);
763 compute_all_gradient_areas();
764 span.triangle_area = triangle_area;
765 span.triangle_winding = triangle_winding;
767 switch(y_direction_a | (y_direction_b << 2) | (y_direction_c << 4) |
768 (triangle_winding << 6))
770 triangle_case(up, up, up, negative):
771 triangle_case(up, up, flat, negative):
772 triangle_case(up, up, down, negative):
773 render_spans_up_right(psx_gpu, &span, a, b, c, flags);
776 triangle_case(flat, up, up, negative):
777 triangle_case(flat, up, flat, negative):
778 triangle_case(flat, up, down, negative):
779 render_spans_up_a(psx_gpu, &span, a, b, c, flags);
782 triangle_case(down, up, up, negative):
783 render_spans_up_down(psx_gpu, &span, a, c, b, flags);
786 triangle_case(down, up, flat, negative):
787 render_spans_down_a(psx_gpu, &span, a, c, b, flags);
790 triangle_case(down, up, down, negative):
791 render_spans_down_right(psx_gpu, &span, a, c, b, flags);
794 triangle_case(down, flat, up, negative):
795 triangle_case(down, flat, flat, negative):
796 triangle_case(down, flat, down, negative):
797 render_spans_down_b(psx_gpu, &span, a, b, c, flags);
800 triangle_case(down, down, up, negative):
801 triangle_case(down, down, flat, negative):
802 triangle_case(down, down, down, negative):
803 render_spans_down_left(psx_gpu, &span, a, b, c, flags);
806 triangle_case(up, up, up, positive):
807 triangle_case(up, up, flat, positive):
808 triangle_case(up, up, down, positive):
809 render_spans_up_left(psx_gpu, &span, a, b, c, flags);
812 triangle_case(up, flat, up, positive):
813 triangle_case(up, flat, flat, positive):
814 triangle_case(up, flat, down, positive):
815 render_spans_up_b(psx_gpu, &span, a, b, c, flags);
818 triangle_case(up, down, up, positive):
819 render_spans_up_right(psx_gpu, &span, a, c, b, flags);
822 triangle_case(up, down, flat, positive):
823 render_spans_up_a(psx_gpu, &span, a, c, b, flags);
826 triangle_case(up, down, down, positive):
827 render_spans_up_down(psx_gpu, &span, a, b, c, flags);
830 triangle_case(flat, down, up, positive):
831 triangle_case(flat, down, flat, positive):
832 triangle_case(flat, down, down, positive):
833 render_spans_down_a(psx_gpu, &span, a, b, c, flags);
836 triangle_case(down, down, up, positive):
837 triangle_case(down, down, flat, positive):
838 triangle_case(down, down, down, positive):
839 render_spans_down_right(psx_gpu, &span, a, b, c, flags);
846 void render_sprite(psx_gpu_struct *psx_gpu, s32 x, s32 y, u32 u, u32 v,
847 s32 width, s32 height, u32 flags)
850 s32 current_x, current_y;
851 u32 current_u, current_v;
852 u32 primitive_color = psx_gpu->primitive_color;
853 u32 sprite_r, sprite_g, sprite_b;
859 sprite_r = primitive_color & 0xFF;
860 sprite_g = (primitive_color >> 8) & 0xFF;
861 sprite_b = (primitive_color >> 16) & 0xFF;
863 static u32 sprites = 0;
867 for(current_y = y, current_v = v;
868 current_y < y + height; current_y++, current_v++)
870 for(current_x = x, current_u = u;
871 current_x < x + width; current_x++, current_u++)
873 if((current_x >= psx_gpu->viewport_start_x) &&
874 (current_y >= psx_gpu->viewport_start_y) &&
875 (current_x <= psx_gpu->viewport_end_x) &&
876 (current_y <= psx_gpu->viewport_end_y))
878 if(psx_gpu->mask_evaluate &&
879 (psx_gpu->vram[(y * 1024) + current_x] & 0x8000))
884 if(flags & RENDER_FLAGS_TEXTURE_MAP)
886 texel = fetch_texel(psx_gpu, current_u, current_v);
890 color_r = texel & 0x1F;
891 color_g = (texel >> 5) & 0x1F;
892 color_b = (texel >> 10) & 0x1F;
894 if((flags & RENDER_FLAGS_MODULATE_TEXELS) == 0)
907 color_r = sprite_r >> 3;
908 color_g = sprite_g >> 3;
909 color_b = sprite_b >> 3;
912 draw_pixel(psx_gpu, color_r, color_g, color_b, texel, current_x,
920 #define draw_pixel_line(_x, _y) \
921 if((_x >= psx_gpu->viewport_start_x) && (_y >= psx_gpu->viewport_start_y) && \
922 (_x <= psx_gpu->viewport_end_x) && (_y <= psx_gpu->viewport_end_y)) \
924 if(flags & RENDER_FLAGS_SHADE) \
926 color_r = fixed_to_int(current_r); \
927 color_g = fixed_to_int(current_g); \
928 color_b = fixed_to_int(current_b); \
930 current_r += gradient_r; \
931 current_g += gradient_g; \
932 current_b += gradient_b; \
936 color_r = primitive_color & 0xFF; \
937 color_g = (primitive_color >> 8) & 0xFF; \
938 color_b = (primitive_color >> 16) & 0xFF; \
941 if(psx_gpu->dither_mode) \
943 s32 dither_offset = dither_table[_y % 4][_x % 4]; \
945 color_r += dither_offset; \
946 color_g += dither_offset; \
947 color_b += dither_offset; \
964 draw_pixel(psx_gpu, color_r, color_g, color_b, 0, _x, _y, flags); \
967 #define update_increment(value) \
970 #define update_decrement(value) \
973 #define compare_increment(a, b) \
976 #define compare_decrement(a, b) \
979 #define set_line_gradients(minor) \
981 s32 gradient_divisor = delta_##minor; \
982 gradient_r = int_to_fixed(vertex_b->r - vertex_a->r) / gradient_divisor; \
983 gradient_g = int_to_fixed(vertex_b->g - vertex_a->g) / gradient_divisor; \
984 gradient_b = int_to_fixed(vertex_b->b - vertex_a->b) / gradient_divisor; \
985 current_r = fixed_center(vertex_a->r); \
986 current_g = fixed_center(vertex_a->g); \
987 current_b = fixed_center(vertex_a->b); \
990 #define draw_line_span_horizontal(direction) \
993 error_step = delta_y * 2; \
994 error_wrap = delta_x * 2; \
998 set_line_gradients(x); \
1000 for(current_x = x_a; current_x <= x_b; current_x++) \
1002 draw_pixel_line(current_x, current_y); \
1003 error += error_step; \
1005 if(error >= error_wrap) \
1007 update_##direction(current_y); \
1008 error -= error_wrap; \
1013 #define draw_line_span_vertical(direction) \
1016 error_step = delta_x * 2; \
1017 error_wrap = delta_y * 2; \
1021 set_line_gradients(y); \
1023 for(current_y = y_a; compare_##direction(current_y, y_b); \
1024 update_##direction(current_y)) \
1026 draw_pixel_line(current_x, current_y); \
1027 error += error_step; \
1029 if(error > error_wrap) \
1032 error -= error_wrap; \
1037 void render_line(psx_gpu_struct *psx_gpu, vertex_struct *vertexes, u32 flags)
1039 u32 primitive_color = psx_gpu->primitive_color;
1040 s32 color_r, color_g, color_b;
1042 fixed_type gradient_r = 0;
1043 fixed_type gradient_g = 0;
1044 fixed_type gradient_b = 0;
1045 fixed_type current_r = 0;
1046 fixed_type current_g = 0;
1047 fixed_type current_b = 0;
1052 s32 delta_x, delta_y;
1053 u32 triangle_winding = 0;
1062 vertex_struct *vertex_a = &(vertexes[0]);
1063 vertex_struct *vertex_b = &(vertexes[1]);
1065 if(vertex_a->x >= vertex_b->x)
1067 vertex_swap(vertex_a, vertex_b);
1076 delta_x = x_b - x_a;
1077 delta_y = y_b - y_a;
1082 flags &= ~RENDER_FLAGS_TEXTURE_MAP;
1091 if(delta_x > delta_y)
1092 draw_line_span_horizontal(decrement);
1094 draw_line_span_vertical(decrement);
1101 if(delta_x > delta_y)
1102 draw_line_span_horizontal(increment);
1104 draw_line_span_vertical(increment);
1109 void render_block_fill(psx_gpu_struct *psx_gpu, u32 color, u32 x, u32 y,
1110 u32 width, u32 height)
1112 u32 r = color & 0xFF;
1113 u32 g = (color >> 8) & 0xFF;
1114 u32 b = (color >> 16) & 0xFF;
1115 u32 color_16bpp = (r >> 3) | ((g >> 3) << 5) | ((b >> 3) << 10);
1117 u16 *vram_ptr = psx_gpu->vram + x + (y * 1024);
1120 for(draw_y = 0; draw_y < height; draw_y++)
1122 for(draw_x = 0; draw_x < width; draw_x++)
1124 vram_ptr[draw_x] = color_16bpp;
1131 void render_block_copy(psx_gpu_struct *psx_gpu, u16 *source, u32 x, u32 y,
1132 u32 width, u32 height, u32 pitch)
1134 u16 *vram_ptr = psx_gpu->vram + x + (y * 1024);
1137 for(draw_y = 0; draw_y < height; draw_y++)
1139 for(draw_x = 0; draw_x < width; draw_x++)
1141 vram_ptr[draw_x] = source[draw_x];
1149 void render_block_move(psx_gpu_struct *psx_gpu, u32 source_x, u32 source_y,
1150 u32 dest_x, u32 dest_y, u32 width, u32 height)
1152 render_block_copy(psx_gpu, psx_gpu->vram + source_x + (source_y * 1024),
1153 dest_x, dest_y, width, height, 1024);
1156 void initialize_psx_gpu(psx_gpu_struct *psx_gpu)
1158 psx_gpu->pixel_count_mode = 0;
1159 psx_gpu->pixel_compare_mode = 0;
1161 psx_gpu->vram_pixel_counts_a = malloc(sizeof(u8) * 1024 * 512);
1162 psx_gpu->vram_pixel_counts_b = malloc(sizeof(u8) * 1024 * 512);
1163 memset(psx_gpu->vram_pixel_counts_a, 0, sizeof(u8) * 1024 * 512);
1164 memset(psx_gpu->vram_pixel_counts_b, 0, sizeof(u8) * 1024 * 512);
1165 psx_gpu->compare_vram = malloc(sizeof(u16) * 1024 * 512);