pseudo 3D graph with hidden line removal

pseudo 3D graph

Makefile

main: main.c buf.c
	$(CC) -o $@ $^ -lm

main: buf.h

main.pbm: main
	./main

.PHONY: clean

clean:
	$(RM) main main.pbm

buf.c

#include "buf.h"
#include <stdio.h>

void
file_out(const struct buf *b, const char *filename)
{
   const int width  = b->width;
   const int height = b->height;
   const unsigned char *buffer = b->bytes;

   FILE *f = fopen(filename, "w");

   fprintf(f, "P1\n%d %d", width, height);
   for (int i = 0; i < width * height; i++) {
      fputc(i % 32 == 0 ? '\n' : ' ', f);
      fputc(buffer[i] ? '1' : '0', f); }
   fputc('\n', f);

   fclose(f);
}

buf.h

struct buf {
   int width;
   int height;
   unsigned char *bytes;
};

void file_out(const struct buf *, const char *);

static void
pset(const struct buf *b, const int x, const int y, const int val)
{
   const int i = x + y * b->width;

   if (i < 0 || i > b->width * b->height) return;

   b->bytes[i] = val ? 1 : 0;
}

main.c

#include "buf.h"
#include <math.h>
#define W 320
#define H 320

double
f(const double x, const double z)
{
   const double d = sqrt(x * x + z * z);
   const double y = pow(0.97, d) * cos(d);

   return y;
}

int
main(void)
{
   unsigned char bytes[W * H] = { 0 };
   const struct buf b = {
      .width  = W,
      .height = H,
      .bytes  = bytes,
   };
   int y_max[W] = { 0 }, y_min[W];

   for (int i = 0; i < W; i++) y_min[i] = H;

   for (int i = -32; i < H + 32; i++) {
      for (int j = 0; j < W; j++) {
         const double z = (i - H / 2) / 10.0 * 2;
         const double x = (j - W / 2) / 10.0 + z / 4.0;
         const double y = f(x, z);
         const int py = i + (int)(32 * y);

         // plane y=0
         if ((i % 8 == 0 || (fabs(x) - (int)fabs(x)) < 0.1) &&
               ((i + j) % 2 == 1) && y < 0.0 &&
               (i < y_min[j] || i > y_max[j]))
            pset(&b, j, H - i, 1);

         if (i % 4) continue;

         // hidden line removal
         if      (py < y_min[j]) y_min[j] = py;
         else if (py > y_max[j]) y_max[j] = py;
         else continue;

         // draw curve
         pset(&b, j, H - py, 1);
      }
   }

   file_out(&b, "main.pbm");
   return 0;
}
parent directory