165 lines
4.4 KiB
C
165 lines
4.4 KiB
C
#include "duet.h"
|
|
#include <stdlib.h>
|
|
|
|
/* Bresenham algorithm */
|
|
void dcircle(int cx, int cy, int r0, int color, bool fill)
|
|
{
|
|
int x=-r0, y=0, e=2-2*r0, r=r0;
|
|
|
|
do {
|
|
dpixel(cx-x, cy-y, color);
|
|
dpixel(cx+y, cy-x, color);
|
|
dpixel(cx+x, cy+y, color);
|
|
dpixel(cx-y, cy+x, color);
|
|
|
|
if(fill) {
|
|
dline(cx+x, cy-y, cx-x, cy-y, color);
|
|
dline(cx+x, cy+y, cx-x, cy+y, color);
|
|
}
|
|
|
|
r = e;
|
|
if(r <= y)
|
|
e += (++y * 2) + 1;
|
|
if(r > x || e > y)
|
|
e += (++x * 2) + 1;
|
|
}
|
|
while(x < 0);
|
|
}
|
|
|
|
/* Blend to white (slow) */
|
|
static uint16_t blend(uint16_t bg, uint16_t fg, int opacity)
|
|
{
|
|
int R_bg = (bg >> 11);
|
|
int G_bg = (bg >> 6) & 0x1f;
|
|
int B_bg = bg & 0x1f;
|
|
|
|
int R_fg = (fg >> 11);
|
|
int G_fg = (fg >> 6) & 0x1f;
|
|
int B_fg = fg & 0x1f;
|
|
|
|
int R = (R_fg * opacity + R_bg * (256 - opacity)) >> 8;
|
|
int G = (G_fg * opacity + G_bg * (256 - opacity)) >> 8;
|
|
int B = (B_fg * opacity + B_bg * (256 - opacity)) >> 8;
|
|
return C_RGB(R, G, B);
|
|
}
|
|
|
|
/* From Windmill::render_triangle_black */
|
|
static int edge_start(int x1, int y1, int x2, int y2, int px, int py)
|
|
{
|
|
return (y2 - y1) * (px - x1) - (x2 - x1) * (py - y1);
|
|
}
|
|
static int min(int x, int y)
|
|
{
|
|
return (x < y) ? x : y;
|
|
}
|
|
static int max(int x, int y)
|
|
{
|
|
return (x > y) ? x : y;
|
|
}
|
|
void dtriangle(int x1, int y1, int x2, int y2, int x3, int y3, int color,
|
|
int opacity)
|
|
{
|
|
// calcul du rectangle circonscrit au triangle
|
|
int min_x = max(0, min(x1, min(x2, x3)));
|
|
int max_x = min(DWIDTH-1, max(x1, max(x2, x3)));
|
|
int min_y = max(0, min(y1, min(y2, y3)));
|
|
int max_y = min(DHEIGHT-1, max(y1, max(y2, y3)));
|
|
|
|
// calcul des produits vectoriels
|
|
int u0_start = edge_start(x2, y2, x3, y3, min_x, min_y);
|
|
int u0_step_x = y3 - y2;
|
|
int u0_step_y = x2 - x3;
|
|
int u1_start = edge_start(x3, y3, x1, y1, min_x, min_y);
|
|
int u1_step_x = y1 - y3;
|
|
int u1_step_y = x3 - x1;
|
|
int u2_start = edge_start(x1, y1, x2, y2, min_x, min_y);
|
|
int u2_step_x = y2 - y1;
|
|
int u2_step_y = x1 - x2;
|
|
|
|
int u0, u1, u2;
|
|
|
|
// parcours en ligne
|
|
for(int x=min_x; x<=max_x; x++)
|
|
{
|
|
u0 = u0_start; u1 = u1_start; u2 = u2_start;
|
|
|
|
// parcours en colonne
|
|
for(int y=min_y; y<=max_y; y++)
|
|
{
|
|
// si le pixel (x;y) est dans le triangle
|
|
if ((u0 | u1 | u2) > 0)
|
|
{
|
|
int i = DWIDTH * y + x;
|
|
|
|
if(opacity > 0xff)
|
|
gint_vram[i] = color;
|
|
else
|
|
gint_vram[i] = blend(gint_vram[i], color, opacity);
|
|
}
|
|
u0 += u0_step_y; u1 += u1_step_y; u2 += u2_step_y;
|
|
}
|
|
u0_start += u0_step_x; u1_start += u1_step_x; u2_start += u2_step_x;
|
|
}
|
|
}
|
|
|
|
void drectoid(rect_t const *r, float extra_size, int color)
|
|
{
|
|
if(r->opacity == 0)
|
|
return;
|
|
|
|
float w = r->w + 2 * extra_size;
|
|
float h = r->h + 2 * extra_size;
|
|
|
|
if(r->x - max(w,h)/2 > DWIDTH || r->x + max(w,h)/2 < 0)
|
|
return;
|
|
|
|
float x0[4] = { w/2, -w/2, -w/2, w/2 };
|
|
float y0[4] = { -h/2, -h/2, h/2, h/2 };
|
|
|
|
if(r->r == 0) {
|
|
int x1=r->x+x0[1], x2=r->x+x0[3], y1=r->y+y0[1], y2=r->y+y0[3];
|
|
if(r->opacity > 0xff)
|
|
drect(x1, y1, x2, y2, color);
|
|
else {
|
|
y1 = max(y1, 0);
|
|
y2 = min(y2, DHEIGHT-1);
|
|
x1 = max(x1, 0);
|
|
x2 = min(x2, DWIDTH-1);
|
|
for(int y = y1; y <= y2; y++)
|
|
for(int x = x1; x <= x2; x++) {
|
|
int i = y * DWIDTH + x;
|
|
gint_vram[i] = blend(gint_vram[i], color, r->opacity);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
float sin, cos;
|
|
sincosf(r->r, &sin, &cos);
|
|
int x[4], y[4];
|
|
|
|
for(int i = 0; i < 4; i++) {
|
|
x[i] = r->x + x0[i] * cos + y0[i] * sin;
|
|
y[i] = r->y - x0[i] * sin + y0[i] * cos;
|
|
}
|
|
|
|
dtriangle(x[0], y[0], x[1], y[1], x[2], y[2], color, r->opacity);
|
|
dtriangle(x[2], y[2], x[3], y[3], x[0], y[0], color, r->opacity);
|
|
}
|
|
|
|
void render_player(int x, int y, float angle)
|
|
{
|
|
dcircle(x, y, PLAYER_R, C_RGB(10, 10, 10), false);
|
|
|
|
float x1, y1, x2, y2;
|
|
player_position(angle, &x1, &y1, &x2, &y2);
|
|
|
|
x1 = x1 - PLAYER_X + x;
|
|
y1 = y1 - DHEIGHT/2 + y;
|
|
x2 = x2 - PLAYER_X + x;
|
|
y2 = y2 - DHEIGHT/2 + y;
|
|
|
|
dcircle(x1, y1, PLAYER_SIZE, C_RGB(0, 16, 26), true);
|
|
dcircle(x2, y2, PLAYER_SIZE, C_RGB(31, 6, 0), true);
|
|
}
|