228 lines
6.2 KiB
C
228 lines
6.2 KiB
C
#include "duet.h"
|
|
#include <stdlib.h>
|
|
|
|
/* Extreme hacks for intersecting circles; we draw a pixel as [color], but if
|
|
there is already [rep1] on that pixel we turn it into [rep2], and if we see
|
|
[rep2] we don't paint over it */
|
|
void dcircle_pixel(int x, int y, int color, int rep1, int rep2)
|
|
{
|
|
if(x < 0 || x >= DWIDTH || y < 0 || y >= DHEIGHT)
|
|
return;
|
|
int i = DWIDTH * y + x;
|
|
if(gint_vram[i] == rep2)
|
|
return;
|
|
gint_vram[i] = (gint_vram[i] == rep1) ? rep2 : color;
|
|
}
|
|
/* Bresenham algorithm */
|
|
void dcircle(int cx, int cy, int r0, int color, bool fill, int rep1, int rep2)
|
|
{
|
|
int x=-r0, y=0, e=2-2*r0, r=r0;
|
|
|
|
do {
|
|
dcircle_pixel(cx-x, cy-y, color, rep1, rep2);
|
|
dcircle_pixel(cx+y, cy-x, color, rep1, rep2);
|
|
dcircle_pixel(cx+x, cy+y, color, rep1, rep2);
|
|
dcircle_pixel(cx-y, cy+x, color, rep1, rep2);
|
|
|
|
if(fill) {
|
|
for(int sx = cx+x; sx <= cx-x; sx++) {
|
|
dcircle_pixel(sx, cy-y, color, rep1, rep2);
|
|
dcircle_pixel(sx, cy+y, color, rep1, rep2);
|
|
}
|
|
}
|
|
|
|
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, int r, float opacity)
|
|
{
|
|
int c = 10 * opacity;
|
|
dcircle(x, y, r, C_RGB(c, c, c), false, -1, -1);
|
|
|
|
float x1, y1, x2, y2;
|
|
player_position(angle, &x1, &y1, &x2, &y2, r);
|
|
|
|
x1 = x1 - PLAYER_X + x;
|
|
y1 = y1 - DHEIGHT/2 + y;
|
|
x2 = x2 - PLAYER_X + x;
|
|
y2 = y2 - DHEIGHT/2 + y;
|
|
|
|
int c1 = C_RGB(0, 16, 26);
|
|
int c2 = C_RGB(31, 6, 0);
|
|
int c3 = C_WHITE;
|
|
|
|
dcircle(x1, y1, PLAYER_SIZE, c1, true, -1, -1);
|
|
dcircle(x2, y2, PLAYER_SIZE, c2, true, c1, c3);
|
|
}
|
|
|
|
void render_glow(int x, int y, int r1, int r2, int color1, int color2,
|
|
float angle, float opacity)
|
|
{
|
|
float s1, c1, s2, c2;
|
|
sincosf(angle, &s2, &c2);
|
|
|
|
for(int i = 0; i < 16; i++) {
|
|
s1 = s2;
|
|
c1 = c2;
|
|
angle += M_PI / 8.0;
|
|
sincosf(angle, &s2, &c2);
|
|
|
|
int r = (i & 1) ? r2 : r1;
|
|
int color = (i & 1) ? color2 : color1;
|
|
dtriangle(x, y, x+r*c2, y+r*s2, x+r*c1, y+r*s1, color, 256 * opacity);
|
|
}
|
|
}
|
|
|
|
void radial_fadeout(int cx, int cy, int r1, int r2, int c)
|
|
{
|
|
int x1 = max(0, cx - r2);
|
|
int x2 = min(DWIDTH-1, cx + r2);
|
|
int y1 = max(0, cy - r2);
|
|
int y2 = min(DHEIGHT-1, cy + r2);
|
|
|
|
for(int y = y1; y <= y2; y++)
|
|
for(int x = x1; x <= x2; x++) {
|
|
int i = DWIDTH * y + x;
|
|
int r_sq = (x - cx) * (x - cx) + (y - cy) * (y - cy);
|
|
|
|
if(r_sq < r1 * r1)
|
|
continue;
|
|
if(r_sq > r2 * r2) {
|
|
gint_vram[i] = c;
|
|
continue;
|
|
}
|
|
|
|
float r = sqrtf(r_sq);
|
|
float opacity = fmaxf(0.0, fminf(1.0, (r - r1) / (r2 - r1)));
|
|
|
|
gint_vram[i] = blend(gint_vram[i], c, 256*opacity);
|
|
}
|
|
}
|