mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
CHECKPOINT: polygon rendering
This commit is contained in:
parent
3b24bc882c
commit
f0c2963793
1 changed files with 272 additions and 105 deletions
|
|
@ -450,9 +450,10 @@ static double view_x_min = -10, view_x_max = 10;
|
||||||
static double view_y_min = -6.4, view_y_max = 6.4;
|
static double view_y_min = -6.4, view_y_max = 6.4;
|
||||||
|
|
||||||
// 3D view
|
// 3D view
|
||||||
static double rot_x = 0.5, rot_y = 0.6; // radians
|
static double rot_x = 0.5, rot_y = 0.6;
|
||||||
static double range_3d = 5.0;
|
static double range_3d = 5.0;
|
||||||
static double zoom_3d = 1.0; // multiplier, 1.0 = auto-fit viewport
|
static double zoom_3d = 1.0;
|
||||||
|
static bool filled_mode = false;
|
||||||
static bool is_explicit_3d = false;
|
static bool is_explicit_3d = false;
|
||||||
static bool is_explicit_2d = false;
|
static bool is_explicit_2d = false;
|
||||||
|
|
||||||
|
|
@ -460,17 +461,16 @@ static bool is_explicit_2d = false;
|
||||||
static bool right_dragging = false;
|
static bool right_dragging = false;
|
||||||
static int drag_last_x = 0, drag_last_y = 0;
|
static int drag_last_x = 0, drag_last_y = 0;
|
||||||
|
|
||||||
// 3D surface data
|
#define MAX_Z_PER_POINT 4
|
||||||
static double surf_x[GRID_3D][GRID_3D];
|
typedef struct {
|
||||||
static double surf_y_3d[GRID_3D][GRID_3D];
|
double z[MAX_Z_PER_POINT];
|
||||||
static double surf_z1[GRID_3D][GRID_3D]; // Front root
|
float nx[MAX_Z_PER_POINT], ny[MAX_Z_PER_POINT], nz[MAX_Z_PER_POINT];
|
||||||
static double surf_z2[GRID_3D][GRID_3D]; // Back root
|
int sx[MAX_Z_PER_POINT], sy[MAX_Z_PER_POINT], dz[MAX_Z_PER_POINT];
|
||||||
static bool surf_v1[GRID_3D][GRID_3D];
|
int count;
|
||||||
static bool surf_v2[GRID_3D][GRID_3D];
|
} surf_point_t;
|
||||||
|
|
||||||
// Screen-space vertex cache for parallel rasterization
|
static double surf_x[GRID_3D][GRID_3D], surf_y_3d[GRID_3D][GRID_3D];
|
||||||
static int surf_sx1[GRID_3D][GRID_3D], surf_sy1[GRID_3D][GRID_3D], surf_dz1[GRID_3D][GRID_3D];
|
static surf_point_t surf[GRID_3D][GRID_3D];
|
||||||
static int surf_sx2[GRID_3D][GRID_3D], surf_sy2[GRID_3D][GRID_3D], surf_dz2[GRID_3D][GRID_3D];
|
|
||||||
|
|
||||||
static bool surface_needs_eval = true;
|
static bool surface_needs_eval = true;
|
||||||
|
|
||||||
|
|
@ -480,6 +480,7 @@ static double rot_cx, rot_sx, rot_cy, rot_sy;
|
||||||
// Widgets
|
// Widgets
|
||||||
static widget_textbox_t tb_equation;
|
static widget_textbox_t tb_equation;
|
||||||
static widget_button_t btn_plot;
|
static widget_button_t btn_plot;
|
||||||
|
static widget_button_t btn_mode;
|
||||||
static widget_button_t btn_range_minus;
|
static widget_button_t btn_range_minus;
|
||||||
static widget_button_t btn_range_plus;
|
static widget_button_t btn_range_plus;
|
||||||
|
|
||||||
|
|
@ -565,6 +566,39 @@ static void gfb_line_z(int x0, int y0, int z0, int x1, int y1, int z1, uint32_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gfb_triangle_z(int x0, int y0, int z0, int x1, int y1, int z1, int x2, int y2, int z2, uint32_t c) {
|
||||||
|
if (y1 < y0) { int t; t=x0; x0=x1; x1=t; t=y0; y0=y1; y1=t; t=z0; z0=z1; z1=t; }
|
||||||
|
if (y2 < y0) { int t; t=x0; x0=x2; x2=t; t=y0; y0=y2; y2=t; t=z0; z0=z2; z2=t; }
|
||||||
|
if (y2 < y1) { int t; t=x1; x1=x2; x2=t; t=y1; y1=y2; y2=t; t=z1; z1=z2; z2=t; }
|
||||||
|
|
||||||
|
if (y0 == y2) return;
|
||||||
|
|
||||||
|
for (int y = y0; y <= y2; y++) {
|
||||||
|
if (y < 0 || y >= graph_h) continue;
|
||||||
|
bool second_half = y > y1 || y1 == y0;
|
||||||
|
int h1 = second_half ? (y2 - y1) : (y1 - y0);
|
||||||
|
int h2 = y2 - y0;
|
||||||
|
if (h1 == 0) h1 = 1;
|
||||||
|
if (h2 == 0) h2 = 1;
|
||||||
|
|
||||||
|
float alpha = (float)(y - y0) / h2;
|
||||||
|
float beta = (float)(y - (second_half ? y1 : y0)) / h1;
|
||||||
|
|
||||||
|
int ax = x0 + (int)((x2 - x0) * alpha);
|
||||||
|
int bx = second_half ? x1 + (int)((x2 - x1) * beta) : x0 + (int)((x1 - x0) * beta);
|
||||||
|
int az = z0 + (int)((z2 - z0) * alpha);
|
||||||
|
int bz = second_half ? z1 + (int)((z2 - z1) * beta) : z0 + (int)((z1 - z0) * beta);
|
||||||
|
|
||||||
|
if (ax > bx) { int t; t=ax; ax=bx; bx=t; t=az; az=bz; bz=t; }
|
||||||
|
for (int x = ax; x <= bx; x++) {
|
||||||
|
if (x < 0 || x >= graph_w) continue;
|
||||||
|
float phi = (ax == bx) ? 1.0f : (float)(x - ax) / (bx - ax);
|
||||||
|
int cz = az + (int)((bz - az) * phi);
|
||||||
|
gfb_pixel_z(x, y, cz, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static uint32_t color_by_height(double z, double zmin, double zmax) {
|
static uint32_t color_by_height(double z, double zmin, double zmax) {
|
||||||
if (zmax <= zmin) return COLOR_CURVE;
|
if (zmax <= zmin) return COLOR_CURVE;
|
||||||
double t = (z - zmin) / (zmax - zmin);
|
double t = (z - zmin) / (zmax - zmin);
|
||||||
|
|
@ -578,6 +612,30 @@ static uint32_t color_by_height(double z, double zmin, double zmax) {
|
||||||
return 0xFF000000 | (r<<16) | (g<<8) | b;
|
return 0xFF000000 | (r<<16) | (g<<8) | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t apply_shading(uint32_t color, double nx, double ny, double nz) {
|
||||||
|
double len = my_sqrt(nx*nx + ny*ny + nz*nz);
|
||||||
|
if (len > 1e-9) { nx /= len; ny /= len; nz /= len; }
|
||||||
|
else { nx = 0; ny = 1; nz = 0; }
|
||||||
|
|
||||||
|
double lx = 0.577, ly = 0.707, lz = 0.408;
|
||||||
|
double dot = nx * lx + ny * ly + nz * lz;
|
||||||
|
if (dot < 0) dot = -dot * 0.2;
|
||||||
|
|
||||||
|
double intensity = 0.3 + 0.7 * dot;
|
||||||
|
if (intensity > 1.0) intensity = 1.0;
|
||||||
|
|
||||||
|
int r = (color >> 16) & 0xFF;
|
||||||
|
int g = (color >> 8) & 0xFF;
|
||||||
|
int b = color & 0xFF;
|
||||||
|
|
||||||
|
r = (int)(r * intensity);
|
||||||
|
g = (int)(g * intensity);
|
||||||
|
b = (int)(b * intensity);
|
||||||
|
if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255;
|
||||||
|
|
||||||
|
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||||
|
}
|
||||||
|
|
||||||
// ========================
|
// ========================
|
||||||
// 2D coordinate transforms
|
// 2D coordinate transforms
|
||||||
// ========================
|
// ========================
|
||||||
|
|
@ -920,69 +978,118 @@ static void eval_3d_explicit_job(void *arg) {
|
||||||
double wz = eval_rhs_only(wx, wy, 0);
|
double wz = eval_rhs_only(wx, wy, 0);
|
||||||
surf_x[j][i] = wx;
|
surf_x[j][i] = wx;
|
||||||
surf_y_3d[j][i] = wy;
|
surf_y_3d[j][i] = wy;
|
||||||
|
surf[j][i].count = 0;
|
||||||
|
|
||||||
if (my_fabs(wz) > 1e10 || wz != wz) {
|
if (my_fabs(wz) > 1e10 || wz != wz) {
|
||||||
surf_z1[j][i] = 0; surf_v1[j][i] = false;
|
// Invalid value
|
||||||
} else {
|
return;
|
||||||
surf_z1[j][i] = wz; surf_v1[j][i] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Valid explicit surface point
|
||||||
|
surf[j][i].z[0] = wz;
|
||||||
|
|
||||||
|
// Compute normal for explicit surface z = f(x,y)
|
||||||
|
// Normal = (-df/dx, -df/dy, 1) normalized
|
||||||
|
double eps = 0.001;
|
||||||
|
double dfx = 0.5 * (eval_rhs_only(wx+eps, wy, 0) - eval_rhs_only(wx-eps, wy, 0)) / eps;
|
||||||
|
double dfy = 0.5 * (eval_rhs_only(wx, wy+eps, 0) - eval_rhs_only(wx, wy-eps, 0)) / eps;
|
||||||
|
|
||||||
|
double nx = -dfx;
|
||||||
|
double ny = -dfy;
|
||||||
|
double nz = 1.0;
|
||||||
|
double len = my_sqrt(nx*nx + ny*ny + nz*nz);
|
||||||
|
if (len > 1e-9) { nx /= len; ny /= len; nz /= len; }
|
||||||
|
else { nx = 0; ny = 0; nz = 1; }
|
||||||
|
|
||||||
|
surf[j][i].nx[0] = (float)nx;
|
||||||
|
surf[j][i].ny[0] = (float)ny;
|
||||||
|
surf[j][i].nz[0] = (float)nz;
|
||||||
|
surf[j][i].count = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eval_3d_implicit_job(void *arg) {
|
static void eval_3d_implicit_job(void *arg) {
|
||||||
eval_job_t *job = (eval_job_t *)arg;
|
eval_job_t *job = (eval_job_t *)arg;
|
||||||
int z_steps = 100;
|
int z_steps = 512;
|
||||||
double z_step = job->range * 2.0 / z_steps;
|
double z_step = job->range * 2.0 / z_steps;
|
||||||
|
|
||||||
for (int j = job->start_j; j < job->end_j; j++) {
|
for (int j = job->start_j; j < job->end_j; j++) {
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
surf_v1[j][i] = surf_v2[j][i] = false;
|
|
||||||
double wx = -job->range + i * job->step;
|
double wx = -job->range + i * job->step;
|
||||||
double wy = -job->range + j * job->step;
|
double wy = -job->range + j * job->step;
|
||||||
surf_x[j][i] = wx;
|
surf_x[j][i] = wx;
|
||||||
surf_y_3d[j][i] = wy;
|
surf_y_3d[j][i] = wy;
|
||||||
|
surf[j][i].count = 0;
|
||||||
|
|
||||||
double prev_f = eval_implicit(wx, wy, -job->range);
|
double prev_f = eval_implicit(wx, wy, -job->range);
|
||||||
|
double found_roots[MAX_Z_PER_POINT];
|
||||||
int roots_found = 0;
|
int roots_found = 0;
|
||||||
for (int k = 1; k <= z_steps && roots_found < 2; k++) {
|
|
||||||
|
for (int k = 1; k <= z_steps && roots_found < MAX_Z_PER_POINT; k++) {
|
||||||
double zz = -job->range + k * z_step;
|
double zz = -job->range + k * z_step;
|
||||||
double cur_f = eval_implicit(wx, wy, zz);
|
double cur_f = eval_implicit(wx, wy, zz);
|
||||||
if ((prev_f > 0) != (cur_f > 0) && my_fabs(prev_f) < 1e10 && my_fabs(cur_f) < 1e10) {
|
|
||||||
double za = zz - z_step, zb = zz;
|
if ((prev_f > 0) != (cur_f > 0)) {
|
||||||
for (int b = 0; b < 15; b++) {
|
if (my_fabs(prev_f) < 1e10 && my_fabs(cur_f) < 1e10) {
|
||||||
double zm = (za + zb) * 0.5;
|
double za = zz - z_step, zb = zz;
|
||||||
double fm = eval_implicit(wx, wy, zm);
|
double fa = prev_f, fb = cur_f;
|
||||||
if ((prev_f > 0) != (fm > 0)) zb = zm; else { za = zm; prev_f = fm; }
|
|
||||||
}
|
for (int b = 0; b < 15; b++) {
|
||||||
if (roots_found == 0) {
|
double zm = (za + zb) * 0.5;
|
||||||
surf_z1[j][i] = (za + zb) * 0.5; surf_v1[j][i] = true;
|
double fm = eval_implicit(wx, wy, zm);
|
||||||
} else {
|
if ((fa > 0) != (fm > 0)) {
|
||||||
surf_z2[j][i] = (za + zb) * 0.5; surf_v2[j][i] = true;
|
zb = zm;
|
||||||
// Simple sort: ensure z1 < z2 (in screen space d/zd will handle it, but keep it stable here)
|
fb = fm;
|
||||||
if (surf_z1[j][i] > surf_z2[j][i]) {
|
} else {
|
||||||
double tmp = surf_z1[j][i];
|
za = zm;
|
||||||
surf_z1[j][i] = surf_z2[j][i];
|
fa = fm;
|
||||||
surf_z2[j][i] = tmp;
|
}
|
||||||
}
|
}
|
||||||
|
found_roots[roots_found++] = (za + zb) * 0.5;
|
||||||
}
|
}
|
||||||
roots_found++;
|
|
||||||
}
|
}
|
||||||
prev_f = cur_f;
|
prev_f = cur_f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int r = 0; r < roots_found - 1; r++) {
|
||||||
|
for (int s = r + 1; s < roots_found; s++) {
|
||||||
|
if (found_roots[r] > found_roots[s]) {
|
||||||
|
double tmp = found_roots[r];
|
||||||
|
found_roots[r] = found_roots[s];
|
||||||
|
found_roots[s] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int r = 0; r < roots_found; r++) {
|
||||||
|
surf[j][i].z[r] = found_roots[r];
|
||||||
|
|
||||||
|
double wz = found_roots[r];
|
||||||
|
double eps = 0.001;
|
||||||
|
double nx = eval_implicit(wx+eps, wy, wz) - eval_implicit(wx-eps, wy, wz);
|
||||||
|
double ny = eval_implicit(wx, wy+eps, wz) - eval_implicit(wx, wy-eps, wz);
|
||||||
|
double nz = eval_implicit(wx, wy, wz+eps) - eval_implicit(wx, wy, wz-eps);
|
||||||
|
double d = my_sqrt(nx*nx + ny*ny + nz*nz);
|
||||||
|
if (d > 1e-12) { nx /= d; ny /= d; nz /= d; }
|
||||||
|
else { nx = 0; ny = 1; nz = 0; }
|
||||||
|
|
||||||
|
surf[j][i].nx[r] = (float)nx;
|
||||||
|
surf[j][i].ny[r] = (float)ny;
|
||||||
|
surf[j][i].nz[r] = (float)nz;
|
||||||
|
}
|
||||||
|
surf[j][i].count = roots_found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parallel Projection Job
|
|
||||||
static void eval_3d_project_job(void *arg) {
|
static void eval_3d_project_job(void *arg) {
|
||||||
eval_job_t *job = (eval_job_t *)arg;
|
eval_job_t *job = (eval_job_t *)arg;
|
||||||
for (int j = job->start_j; j < job->end_j; j++) {
|
for (int j = job->start_j; j < job->end_j; j++) {
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
if (surf_v1[j][i]) {
|
for (int s = 0; s < surf[j][i].count; s++) {
|
||||||
project_3d(surf_x[j][i], surf_z1[j][i] * job->z_scale, surf_y_3d[j][i], &surf_sx1[j][i], &surf_sy1[j][i], &surf_dz1[j][i]);
|
project_3d(surf_x[j][i], surf[j][i].z[s] * job->z_scale, surf_y_3d[j][i],
|
||||||
}
|
&surf[j][i].sx[s], &surf[j][i].sy[s], &surf[j][i].dz[s]);
|
||||||
if (surf_v2[j][i]) {
|
|
||||||
project_3d(surf_x[j][i], surf_z2[j][i] * job->z_scale, surf_y_3d[j][i], &surf_sx2[j][i], &surf_sy2[j][i], &surf_dz2[j][i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -993,50 +1100,101 @@ typedef struct {
|
||||||
double zmin, zmax;
|
double zmin, zmax;
|
||||||
} draw_job_t;
|
} draw_job_t;
|
||||||
|
|
||||||
// Parallel Draw Job
|
|
||||||
static void render_3d_draw_job(void *arg) {
|
static void render_3d_draw_job(void *arg) {
|
||||||
draw_job_t *job = (draw_job_t *)arg;
|
draw_job_t *job = (draw_job_t *)arg;
|
||||||
for (int j = job->start_j; j < job->end_j; j++) {
|
for (int j = job->start_j; j < job->end_j; j++) {
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
for (int s = 0; s < 2; s++) {
|
if (surf[j][i].count == 0) continue;
|
||||||
bool *v = (s == 0) ? surf_v1[j] : surf_v2[j];
|
|
||||||
int *sx_row = (s == 0) ? surf_sx1[j] : surf_sx2[j];
|
|
||||||
int *sy_row = (s == 0) ? surf_sy1[j] : surf_sy2[j];
|
|
||||||
int *dz_row = (s == 0) ? surf_dz1[j] : surf_dz2[j];
|
|
||||||
double *z_row = (s == 0) ? surf_z1[j] : surf_z2[j];
|
|
||||||
|
|
||||||
if (!v[i]) continue;
|
// 1. Regular Surface Rendering
|
||||||
|
for (int s = 0; s < surf[j][i].count; s++) {
|
||||||
|
int sx0 = surf[j][i].sx[s], sy0 = surf[j][i].sy[s], dz0 = surf[j][i].dz[s];
|
||||||
|
uint32_t col = color_by_height(surf[j][i].z[s], job->zmin, job->zmax);
|
||||||
|
|
||||||
int sx0 = sx_row[i], sy0 = sy_row[i], dz0 = dz_row[i];
|
if (filled_mode) {
|
||||||
uint32_t col = color_by_height(z_row[i], job->zmin, job->zmax);
|
bool v_tr = (i+1 < GRID_3D) && (s < surf[j][i+1].count);
|
||||||
|
bool v_bl = (j+1 < GRID_3D) && (s < surf[j+1][i].count);
|
||||||
|
bool v_br = (i+1 < GRID_3D && j+1 < GRID_3D) && (s < surf[j+1][i+1].count);
|
||||||
|
|
||||||
if (i + 1 < GRID_3D) {
|
if (v_tr && v_bl && v_br) {
|
||||||
bool v_next = (s == 0) ? surf_v1[j][i+1] : surf_v2[j][i+1];
|
int sx_tr = surf[j][i+1].sx[s], sy_tr = surf[j][i+1].sy[s], dz_tr = surf[j][i+1].dz[s];
|
||||||
if (v_next) {
|
int sx_bl = surf[j+1][i].sx[s], sy_bl = surf[j+1][i].sy[s], dz_bl = surf[j+1][i].dz[s];
|
||||||
int *sx_next_row = (s == 0) ? surf_sx1[j] : surf_sx2[j];
|
int sx_br = surf[j+1][i+1].sx[s], sy_br = surf[j+1][i+1].sy[s], dz_br = surf[j+1][i+1].dz[s];
|
||||||
int *sy_next_row = (s == 0) ? surf_sy1[j] : surf_sy2[j];
|
|
||||||
int *dz_next_row = (s == 0) ? surf_dz1[j] : surf_dz2[j];
|
float avg_nx = surf[j][i].nx[s] + surf[j][i+1].nx[s] + surf[j+1][i].nx[s] + surf[j+1][i+1].nx[s];
|
||||||
gfb_line_z(sx0, sy0, dz0, sx_next_row[i+1], sy_next_row[i+1], dz_next_row[i+1], col);
|
float avg_ny = surf[j][i].ny[s] + surf[j][i+1].ny[s] + surf[j+1][i].ny[s] + surf[j+1][i+1].ny[s];
|
||||||
}
|
float avg_nz = surf[j][i].nz[s] + surf[j][i+1].nz[s] + surf[j+1][i].nz[s] + surf[j+1][i+1].nz[s];
|
||||||
}
|
avg_nx *= 0.25f; avg_ny *= 0.25f; avg_nz *= 0.25f;
|
||||||
if (j + 1 < GRID_3D) {
|
|
||||||
bool v_next = (s == 0) ? surf_v1[j+1][i] : surf_v2[j+1][i];
|
float nlen = (float)my_sqrt(avg_nx*avg_nx + avg_ny*avg_ny + avg_nz*avg_nz);
|
||||||
if (v_next) {
|
if (nlen > 1e-9) { avg_nx /= nlen; avg_ny /= nlen; avg_nz /= nlen; }
|
||||||
int *sx_next_row = (s == 0) ? surf_sx1[j+1] : surf_sx2[j+1];
|
else { avg_nx = 0; avg_ny = 0; avg_nz = 1; }
|
||||||
int *sy_next_row = (s == 0) ? surf_sy1[j+1] : surf_sy2[j+1];
|
|
||||||
int *dz_next_row = (s == 0) ? surf_dz1[j+1] : surf_dz2[j+1];
|
uint32_t scol = apply_shading(col, avg_nx, avg_ny, avg_nz);
|
||||||
gfb_line_z(sx0, sy0, dz0, sx_next_row[i], sy_next_row[i], dz_next_row[i], col);
|
gfb_triangle_z(sx0, sy0, dz0, sx_tr, sy_tr, dz_tr, sx_bl, sy_bl, dz_bl, scol);
|
||||||
|
gfb_triangle_z(sx_tr, sy_tr, dz_tr, sx_br, sy_br, dz_br, sx_bl, sy_bl, dz_bl, scol);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i + 1 < GRID_3D && s < surf[j][i+1].count) {
|
||||||
|
gfb_line_z(sx0, sy0, dz0, surf[j][i+1].sx[s], surf[j][i+1].sy[s], surf[j][i+1].dz[s], col);
|
||||||
|
}
|
||||||
|
if (j + 1 < GRID_3D && s < surf[j+1][i].count) {
|
||||||
|
gfb_line_z(sx0, sy0, dz0, surf[j+1][i].sx[s], surf[j+1][i].sy[s], surf[j+1][i].dz[s], col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (s == 0 && surf_v1[j][i] && surf_v2[j][i]) {
|
if (surf[j][i].count > 1) {
|
||||||
bool edge = false;
|
int s_last = surf[j][i].count - 1;
|
||||||
if (i+1 < GRID_3D && !surf_v1[j][i+1]) edge = true;
|
int sx0 = surf[j][i].sx[0], sy0 = surf[j][i].sy[0], dz0 = surf[j][i].dz[0];
|
||||||
if (i-1 >= 0 && !surf_v1[j][i-1]) edge = true;
|
int sx1 = surf[j][i].sx[s_last], sy1 = surf[j][i].sy[s_last], dz1 = surf[j][i].dz[s_last];
|
||||||
if (j+1 < GRID_3D && !surf_v1[j+1][i]) edge = true;
|
|
||||||
if (j-1 >= 0 && !surf_v1[j-1][i]) edge = true;
|
bool right_empty = (i + 1 >= GRID_3D || surf[j][i+1].count == 0);
|
||||||
if (edge) {
|
bool left_empty = (i - 1 < 0 || surf[j][i-1].count == 0);
|
||||||
gfb_line_z(sx0, sy0, dz0, surf_sx2[j][i], surf_sy2[j][i], surf_dz2[j][i], col);
|
bool bottom_empty = (j + 1 >= GRID_3D || surf[j+1][i].count == 0);
|
||||||
|
bool top_empty = (j - 1 < 0 || surf[j-1][i].count == 0);
|
||||||
|
|
||||||
|
bool is_edge = (right_empty || left_empty || bottom_empty || top_empty);
|
||||||
|
|
||||||
|
if (is_edge) {
|
||||||
|
if (!filled_mode) {
|
||||||
|
uint32_t col = color_by_height(surf[j][i].z[0], job->zmin, job->zmax);
|
||||||
|
gfb_line_z(sx0, sy0, dz0, sx1, sy1, dz1, col);
|
||||||
|
} else {
|
||||||
|
double mid_z = (surf[j][i].z[0] + surf[j][i].z[s_last]) * 0.5;
|
||||||
|
double eps = 0.001;
|
||||||
|
double wx = surf_x[j][i], wy = surf_y_3d[j][i];
|
||||||
|
double gnx = eval_implicit(wx + eps, wy, mid_z) - eval_implicit(wx - eps, wy, mid_z);
|
||||||
|
double gny = eval_implicit(wx, wy + eps, mid_z) - eval_implicit(wx, wy - eps, mid_z);
|
||||||
|
double dmag = my_sqrt(gnx*gnx + gny*gny);
|
||||||
|
if (dmag > 1e-12) { gnx /= dmag; gny /= dmag; }
|
||||||
|
else { gnx = 0; gny = 1; }
|
||||||
|
|
||||||
|
uint32_t wcol = apply_shading(color_by_height(mid_z, job->zmin, job->zmax), gnx, gny, 0);
|
||||||
|
|
||||||
|
if (j + 1 < GRID_3D && surf[j+1][i].count > 1) {
|
||||||
|
bool segment_is_right_edge = right_empty && (i + 1 >= GRID_3D || surf[j+1][i+1].count == 0);
|
||||||
|
bool segment_is_left_edge = left_empty && (i - 1 < 0 || surf[j+1][i-1].count == 0);
|
||||||
|
|
||||||
|
if (segment_is_right_edge || segment_is_left_edge) {
|
||||||
|
int ns0 = surf[j+1][i].sx[0], ny0 = surf[j+1][i].sy[0], nz0 = surf[j+1][i].dz[0];
|
||||||
|
int ns1 = surf[j+1][i].sx[surf[j+1][i].count-1], ny1 = surf[j+1][i].sy[surf[j+1][i].count-1], nz1 = surf[j+1][i].dz[surf[j+1][i].count-1];
|
||||||
|
gfb_triangle_z(sx0, sy0, dz0, sx1, sy1, dz1, ns0, ny0, nz0, wcol);
|
||||||
|
gfb_triangle_z(sx1, sy1, dz1, ns1, ny1, nz1, ns0, ny0, nz0, wcol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i + 1 < GRID_3D && surf[j][i+1].count > 1) {
|
||||||
|
bool segment_is_bottom_edge = bottom_empty && (j + 1 >= GRID_3D || surf[j+1][i+1].count == 0);
|
||||||
|
bool segment_is_top_edge = top_empty && (j - 1 < 0 || surf[j-1][i+1].count == 0);
|
||||||
|
|
||||||
|
if (segment_is_bottom_edge || segment_is_top_edge) {
|
||||||
|
int ns0 = surf[j][i+1].sx[0], ny0 = surf[j][i+1].sy[0], nz0 = surf[j][i+1].dz[0];
|
||||||
|
int ns1 = surf[j][i+1].sx[surf[j][i+1].count-1], ny1 = surf[j][i+1].sy[surf[j][i+1].count-1], nz1 = surf[j][i+1].dz[surf[j][i+1].count-1];
|
||||||
|
gfb_triangle_z(sx0, sy0, dz0, sx1, sy1, dz1, ns0, ny0, nz0, wcol);
|
||||||
|
gfb_triangle_z(sx1, sy1, dz1, ns1, ny1, nz1, ns0, ny0, nz0, wcol);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1049,7 +1207,11 @@ static void render_3d_explicit(void) {
|
||||||
double zmin = 1e30, zmax = -1e30;
|
double zmin = 1e30, zmax = -1e30;
|
||||||
|
|
||||||
if (surface_needs_eval) {
|
if (surface_needs_eval) {
|
||||||
for (int j = 0; j < GRID_3D; j++) { for (int i = 0; i < GRID_3D; i++) { surf_v1[j][i] = false; surf_v2[j][i] = false; } }
|
for (int j = 0; j < GRID_3D; j++) {
|
||||||
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
|
surf[j][i].count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int num_chunks = 4;
|
int num_chunks = 4;
|
||||||
eval_job_t jobs[4];
|
eval_job_t jobs[4];
|
||||||
|
|
@ -1070,9 +1232,9 @@ static void render_3d_explicit(void) {
|
||||||
// Compute min/max for coloring
|
// Compute min/max for coloring
|
||||||
for (int j = 0; j < GRID_3D; j++) {
|
for (int j = 0; j < GRID_3D; j++) {
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
if (surf_v1[j][i]) {
|
for (int s = 0; s < surf[j][i].count; s++) {
|
||||||
if (surf_z1[j][i] < zmin) zmin = surf_z1[j][i];
|
if (surf[j][i].z[s] < zmin) zmin = surf[j][i].z[s];
|
||||||
if (surf_z1[j][i] > zmax) zmax = surf_z1[j][i];
|
if (surf[j][i].z[s] > zmax) zmax = surf[j][i].z[s];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1099,7 +1261,6 @@ static void render_3d_explicit(void) {
|
||||||
sys_parallel_run(eval_3d_project_job, job_args, num_chunks);
|
sys_parallel_run(eval_3d_project_job, job_args, num_chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass 3: Parallel Drawing
|
|
||||||
{
|
{
|
||||||
int num_chunks = 4;
|
int num_chunks = 4;
|
||||||
draw_job_t jobs[4];
|
draw_job_t jobs[4];
|
||||||
|
|
@ -1125,7 +1286,11 @@ static void render_3d_implicit(void) {
|
||||||
int num_chunks = 4;
|
int num_chunks = 4;
|
||||||
eval_job_t jobs[4];
|
eval_job_t jobs[4];
|
||||||
void *job_args[4];
|
void *job_args[4];
|
||||||
for (int j = 0; j < GRID_3D; j++) { for (int i = 0; i < GRID_3D; i++) { surf_v1[j][i] = false; surf_v2[j][i] = false; } }
|
for (int j = 0; j < GRID_3D; j++) {
|
||||||
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
|
surf[j][i].count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int rows_per_chunk = GRID_3D / num_chunks;
|
int rows_per_chunk = GRID_3D / num_chunks;
|
||||||
|
|
||||||
|
|
@ -1140,7 +1305,6 @@ static void render_3d_implicit(void) {
|
||||||
sys_parallel_run(eval_3d_implicit_job, job_args, num_chunks);
|
sys_parallel_run(eval_3d_implicit_job, job_args, num_chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass 2: Parallel Projection
|
|
||||||
{
|
{
|
||||||
int num_chunks = 4;
|
int num_chunks = 4;
|
||||||
eval_job_t jobs[4];
|
eval_job_t jobs[4];
|
||||||
|
|
@ -1157,21 +1321,15 @@ static void render_3d_implicit(void) {
|
||||||
sys_parallel_run(eval_3d_project_job, job_args, num_chunks);
|
sys_parallel_run(eval_3d_project_job, job_args, num_chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute min/max for coloring based on what's visible
|
|
||||||
for (int j = 0; j < GRID_3D; j++) {
|
for (int j = 0; j < GRID_3D; j++) {
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
if (surf_v1[j][i]) {
|
for (int s = 0; s < surf[j][i].count; s++) {
|
||||||
if (surf_z1[j][i] < zmin) zmin = surf_z1[j][i];
|
if (surf[j][i].z[s] < zmin) zmin = surf[j][i].z[s];
|
||||||
if (surf_z1[j][i] > zmax) zmax = surf_z1[j][i];
|
if (surf[j][i].z[s] > zmax) zmax = surf[j][i].z[s];
|
||||||
}
|
|
||||||
if (surf_v2[j][i]) {
|
|
||||||
if (surf_z2[j][i] < zmin) zmin = surf_z2[j][i];
|
|
||||||
if (surf_z2[j][i] > zmax) zmax = surf_z2[j][i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass 3: Parallel Drawing
|
|
||||||
{
|
{
|
||||||
int num_chunks = 4;
|
int num_chunks = 4;
|
||||||
draw_job_t jobs[4];
|
draw_job_t jobs[4];
|
||||||
|
|
@ -1232,10 +1390,9 @@ static void render_graph(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (graph_mode == MODE_2D) {
|
if (graph_mode == MODE_2D) {
|
||||||
if (is_explicit_2d) render_2d_explicit(); // auto-fits Y before grid
|
if (is_explicit_2d) render_2d_explicit();
|
||||||
render_2d_grid();
|
render_2d_grid();
|
||||||
if (is_explicit_2d) {
|
if (is_explicit_2d) {
|
||||||
// Re-draw curve on top of grid
|
|
||||||
int prev_sx = -1, prev_sy = -1;
|
int prev_sx = -1, prev_sy = -1;
|
||||||
bool prev_valid = false;
|
bool prev_valid = false;
|
||||||
for (int px = 0; px < graph_w; px++) {
|
for (int px = 0; px < graph_w; px++) {
|
||||||
|
|
@ -1256,12 +1413,10 @@ static void render_graph(void) {
|
||||||
|
|
||||||
ui_draw_image(win_graph, 0, GRAPH_Y, graph_w, graph_h, graph_fb);
|
ui_draw_image(win_graph, 0, GRAPH_Y, graph_w, graph_h, graph_fb);
|
||||||
|
|
||||||
// Post-image overlay (labels)
|
|
||||||
if (graph_mode == MODE_2D) {
|
if (graph_mode == MODE_2D) {
|
||||||
double x_step = get_nice_step(view_x_max - view_x_min, 8);
|
double x_step = get_nice_step(view_x_max - view_x_min, 8);
|
||||||
double y_step = get_nice_step(view_y_max - view_y_min, 6);
|
double y_step = get_nice_step(view_y_max - view_y_min, 6);
|
||||||
|
|
||||||
// Labels need coordinate mapping to the window
|
|
||||||
int axis_y = screen_y_2d(0);
|
int axis_y = screen_y_2d(0);
|
||||||
if (axis_y < 10) axis_y = 10;
|
if (axis_y < 10) axis_y = 10;
|
||||||
if (axis_y > graph_h - 20) axis_y = graph_h - 20;
|
if (axis_y > graph_h - 20) axis_y = graph_h - 20;
|
||||||
|
|
@ -1311,6 +1466,7 @@ static void paint_all(void) {
|
||||||
ui_draw_rect(win_graph, 0, 0, win_w, TOOLBAR_H, COLOR_TOOLBAR_BG);
|
ui_draw_rect(win_graph, 0, 0, win_w, TOOLBAR_H, COLOR_TOOLBAR_BG);
|
||||||
widget_textbox_draw(&wctx, &tb_equation);
|
widget_textbox_draw(&wctx, &tb_equation);
|
||||||
widget_button_draw(&wctx, &btn_plot);
|
widget_button_draw(&wctx, &btn_plot);
|
||||||
|
widget_button_draw(&wctx, &btn_mode);
|
||||||
ui_draw_rounded_rect_filled(win_graph, win_w - 80, 4, 70, 22, 4, 0xFF3A3A5A);
|
ui_draw_rounded_rect_filled(win_graph, win_w - 80, 4, 70, 22, 4, 0xFF3A3A5A);
|
||||||
ui_draw_string(win_graph, win_w - 72, 8, "Presets", COLOR_DARK_TEXT);
|
ui_draw_string(win_graph, win_w - 72, 8, "Presets", COLOR_DARK_TEXT);
|
||||||
render_graph();
|
render_graph();
|
||||||
|
|
@ -1338,7 +1494,6 @@ static void paint_all(void) {
|
||||||
widget_button_draw(&wctx, &btn_range_plus);
|
widget_button_draw(&wctx, &btn_range_plus);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Presets dropdown overlay
|
|
||||||
if (presets_open) {
|
if (presets_open) {
|
||||||
int px = win_w - 150, py = TOOLBAR_H;
|
int px = win_w - 150, py = TOOLBAR_H;
|
||||||
ui_draw_rounded_rect_filled(win_graph, px, py, 140, NUM_PRESETS * 20 + 4, 4, COLOR_DARK_PANEL);
|
ui_draw_rounded_rect_filled(win_graph, px, py, 140, NUM_PRESETS * 20 + 4, 4, COLOR_DARK_PANEL);
|
||||||
|
|
@ -1357,9 +1512,8 @@ static void paint_all(void) {
|
||||||
static void reset_view(void) {
|
static void reset_view(void) {
|
||||||
if (graph_mode == MODE_2D) {
|
if (graph_mode == MODE_2D) {
|
||||||
view_x_min = -10.0; view_x_max = 10.0;
|
view_x_min = -10.0; view_x_max = 10.0;
|
||||||
// Centralize 0,0
|
|
||||||
view_y_min = -6.4; view_y_max = 6.4;
|
view_y_min = -6.4; view_y_max = 6.4;
|
||||||
apply_aspect_ratio(); // This will ensure 0,0 is at the center correctly
|
apply_aspect_ratio();
|
||||||
} else {
|
} else {
|
||||||
zoom_3d = 1.0;
|
zoom_3d = 1.0;
|
||||||
rot_x = -0.5;
|
rot_x = -0.5;
|
||||||
|
|
@ -1400,15 +1554,15 @@ static void handle_scroll(int dz) {
|
||||||
if (dz > 0) zoom_2d(0.85);
|
if (dz > 0) zoom_2d(0.85);
|
||||||
else zoom_2d(1.18);
|
else zoom_2d(1.18);
|
||||||
} else {
|
} else {
|
||||||
// Scroll only alters zoom factor, not computational bounds
|
|
||||||
if (dz > 0) zoom_3d *= 1.15;
|
if (dz > 0) zoom_3d *= 1.15;
|
||||||
else zoom_3d *= 0.87;
|
else zoom_3d *= 0.87;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_widget_layout(void) {
|
static void update_widget_layout(void) {
|
||||||
tb_equation.w = win_w - 160;
|
tb_equation.w = win_w - 220;
|
||||||
btn_plot.x = win_w - 140;
|
btn_plot.x = win_w - 200;
|
||||||
|
widget_button_init(&btn_mode, win_w - 145, 4, 60, 22, filled_mode ? "Wire" : "Filled");
|
||||||
|
|
||||||
int sty = win_h - STATUSBAR_H - 20;
|
int sty = win_h - STATUSBAR_H - 20;
|
||||||
widget_button_init(&btn_range_minus, win_w - 95, sty + 4, 30, 22, "-");
|
widget_button_init(&btn_range_minus, win_w - 95, sty + 4, 30, 22, "-");
|
||||||
|
|
@ -1465,10 +1619,14 @@ int main(void) {
|
||||||
eq_len = strlen(eq_buffer);
|
eq_len = strlen(eq_buffer);
|
||||||
needs_repaint = true;
|
needs_repaint = true;
|
||||||
}
|
}
|
||||||
} else if ((c == 'r' || c == 'R') && ev.arg3 == 1) { // reset view with ctrl + R
|
} else if ((c == 'r' || c == 'R') && ev.arg3 == 1) {
|
||||||
reset_view();
|
reset_view();
|
||||||
surface_needs_eval = true;
|
surface_needs_eval = true;
|
||||||
needs_repaint = true;
|
needs_repaint = true;
|
||||||
|
} else if ((c == 'f' || c == 'F')) {
|
||||||
|
filled_mode = !filled_mode;
|
||||||
|
update_widget_layout();
|
||||||
|
needs_repaint = true;
|
||||||
}
|
}
|
||||||
} else if (ev.type == GUI_EVENT_RESIZE) {
|
} else if (ev.type == GUI_EVENT_RESIZE) {
|
||||||
win_w = ev.arg1;
|
win_w = ev.arg1;
|
||||||
|
|
@ -1526,6 +1684,13 @@ int main(void) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (widget_button_handle_mouse(&btn_mode, mx, my, false, true, NULL)) {
|
||||||
|
filled_mode = !filled_mode;
|
||||||
|
update_widget_layout();
|
||||||
|
needs_repaint = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (graph_mode == MODE_3D) {
|
if (graph_mode == MODE_3D) {
|
||||||
if (widget_button_handle_mouse(&btn_range_plus, mx, my, false, true, NULL)) {
|
if (widget_button_handle_mouse(&btn_range_plus, mx, my, false, true, NULL)) {
|
||||||
range_3d *= 1.25;
|
range_3d *= 1.25;
|
||||||
|
|
@ -1547,6 +1712,7 @@ int main(void) {
|
||||||
} else if (ev.type == GUI_EVENT_MOUSE_DOWN) {
|
} else if (ev.type == GUI_EVENT_MOUSE_DOWN) {
|
||||||
int mx = ev.arg1, my = ev.arg2;
|
int mx = ev.arg1, my = ev.arg2;
|
||||||
widget_button_handle_mouse(&btn_plot, mx, my, true, false, NULL);
|
widget_button_handle_mouse(&btn_plot, mx, my, true, false, NULL);
|
||||||
|
widget_button_handle_mouse(&btn_mode, mx, my, true, false, NULL);
|
||||||
if (graph_mode == MODE_3D) {
|
if (graph_mode == MODE_3D) {
|
||||||
widget_button_handle_mouse(&btn_range_plus, mx, my, true, false, NULL);
|
widget_button_handle_mouse(&btn_range_plus, mx, my, true, false, NULL);
|
||||||
widget_button_handle_mouse(&btn_range_minus, mx, my, true, false, NULL);
|
widget_button_handle_mouse(&btn_range_minus, mx, my, true, false, NULL);
|
||||||
|
|
@ -1556,6 +1722,7 @@ int main(void) {
|
||||||
} else if (ev.type == GUI_EVENT_MOUSE_UP) {
|
} else if (ev.type == GUI_EVENT_MOUSE_UP) {
|
||||||
int mx = ev.arg1, my = ev.arg2;
|
int mx = ev.arg1, my = ev.arg2;
|
||||||
widget_button_handle_mouse(&btn_plot, mx, my, false, false, NULL);
|
widget_button_handle_mouse(&btn_plot, mx, my, false, false, NULL);
|
||||||
|
widget_button_handle_mouse(&btn_mode, mx, my, false, false, NULL);
|
||||||
if (graph_mode == MODE_3D) {
|
if (graph_mode == MODE_3D) {
|
||||||
widget_button_handle_mouse(&btn_range_plus, mx, my, false, false, NULL);
|
widget_button_handle_mouse(&btn_range_plus, mx, my, false, false, NULL);
|
||||||
widget_button_handle_mouse(&btn_range_minus, mx, my, false, false, NULL);
|
widget_button_handle_mouse(&btn_range_minus, mx, my, false, false, NULL);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue