abstracting the interfaces
authorThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Wed, 18 Sep 2024 13:24:20 +0000 (13:24 +0000)
committerThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Wed, 18 Sep 2024 13:24:20 +0000 (13:24 +0000)
developer/cc/Frame.c
developer/cc/Pixel.c
developer/cc/Pixel_2.c [new file with mode: 0644]
developer/cc/Pixel_2024-09-18T2100.c [new file with mode: 0644]

index ed2225d..91b18d5 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
+#include <stdint.h>
+#include <stdbool.h>
 
-// --------------------------------------------------------------------------------
-// instance
+//--------------------------------------------------------------------------------
+// Abstract Frame Interface for any pixel type
 
-typedef enum {
-  FRAME_TYPE_LOCAL
-  ,FRAME_TYPE_EXTERNAL  // external data (e.g., DRM)
-} FrameType;
+typedef struct {
+  void (*alloc)(void *frame_instance, int width, int height);
+  void (*alloc_external_data)(void *frame_instance, int width, int height, void *data);
+  void (*dealloc)(void *frame_instance);
+  void (*copy)(void *from_frame, void *to_frame);
+  void (*read)(void *frame, int i, int j, void *result_px);
+  void (*write)(void *frame, int i, int j, const void *px);
+  void (*fill)(void *frame, const void *px);
+  void (*every)(void *frame, void (*f)(void *frame, void *px, void *arg), void *arg);
+} Frame;
+
+//--------------------------------------------------------------------------------
+// FrameGeneric instance state
 
 typedef struct {
   uint32_t width;
   uint32_t height;
-  PixelRGBA *data;     // Pointer to pixel data (local or external)
-  void *meta_data;     // Backend-specific metadata (e.g., DRM, file, etc.)
-  FrameType type;      // Frame type: local or external
-} FrameRGBA;
-
-// replace this with a general destructure method, add a structure method.
-void FrameRGBA·dimensions(FrameRGBA *frame ,uint32_t *width ,uint32_t *height){
-  if(!frame){
-    *width = 0;
-    *height = 0;
+  Pixel *pixel_interface;  // Pointer to the Pixel interface
+  void *data;              // Pointer to pixel data (generic)
+  void *meta_data;         // Optional metadata
+} FrameGeneric·Instance;
+
+//--------------------------------------------------------------------------------
+// FrameGeneric interface
+
+// Allocate a frame and its pixel data
+void FrameGeneric·alloc(void *frame_instance, int width, int height) {
+  FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
+  if (width == 0 || height == 0) {
+    fprintf(stderr, "FrameGeneric·alloc:: invalid dimensions\n");
     return;
   }
-  *width = frame->width;
-  *height = frame->height;
-}
-
-// --------------------------------------------------------------------------------
-// interface
 
-FrameRGBA *FrameRGBA·alloc(int width, int height, void *meta_data) {
-  FrameRGBA *frame = malloc(sizeof(FrameRGBA));
-  if (!frame) return NULL;
-  
   frame->width = width;
   frame->height = height;
-  frame->data = malloc(width * height * sizeof(PixelRGBA));  // Allocate pixel buffer
-  frame->meta_data = meta_data;  // Store metadata (e.g., backend-specific info)
-  frame->type = FRAME_TYPE_LOCAL;
-  
-  return frame;
-}
-
-FrameRGBA *FrameRGBA·alloc_external_data(int width, int height, void *meta_data, PixelRGBA *data) {
-  FrameRGBA *frame = malloc(sizeof(FrameRGBA));
-  if (!frame) return NULL;
-  
-  frame->width = width;
-  frame->height = height;
-  frame->data = data;  // Use the provided external buffer
-  frame->meta_data = meta_data;
-  frame->type = FRAME_TYPE_EXTERNAL;
-  
-  return frame;
-}
-
-#include <drm/drm.h>
-#include <drm/drm_mode.h>
-
-FrameRGBA *FrameRGBA·alloc_capture_drm(int fd ,int width ,int height ,int buffer_id) {
-  FrameRGBA *frame = malloc(sizeof(FrameRGBA));
-  if( !frame ){
-    perror("Failed to allocate FrameRGBA");
-    return NULL;
+  size_t pixel_size = frame->pixel_interface->size();
+  frame->data = malloc(width * height * pixel_size);
+  if (!frame->data) {
+    fprintf(stderr, "FrameGeneric·alloc:: failed to allocate pixel data\n");
   }
+}
 
+// Allocate a frame with external pixel data
+void FrameGeneric·alloc_external_data(void *frame_instance, int width, int height, void *data) {
+  FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
   frame->width = width;
   frame->height = height;
-
-  // Use drmModeGetFB2 for framebuffer access
-  drmModeFB2 *fb = drmModeGetFB2(fd, buffer_id);
-  if( !fb ){
-    perror("Failed to get framebuffer details (drmModeGetFB2)");
-    free(frame);
-    return NULL;
-  }
-
-  // Check size based on pitches and height
-  size_t buffer_size = fb->height * fb->pitches[0];
-  size_t buffer_size2 = width * height * 4;
-  off_t offset = fb->offsets[0];
-
-  // Log details for debugging
-  fprintf(stderr, "FrameRGBA·alloc_capture_drm:: Buffer size: %zu\n", buffer_size);
-  fprintf(stderr, "FrameRGBA·alloc_capture_drm:: Buffer size2: %zu\n", buffer_size2);
-  fprintf(stderr, "FrameRGBA·alloc_capture_drm:: Buffer size: 0x%xu\n", buffer_size);
-  fprintf(stderr, "FrameRGBA·alloc_capture_drm:: Pitch: 0x%xu\n", fb->pitches[0]);
-  fprintf(stderr, "FrameRGBA·alloc_capture_drm:: Offset: %ld\n", (long)offset);
-  fprintf(stderr, "Attempting mmap with fd: %d, size: %zu, offset: %ld\n", fd, buffer_size, (long)offset);
-
-
-  // Map the framebuffer
-  frame->data = mmap(NULL, buffer_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
-  if( frame->data == MAP_FAILED ){
-    perror("FrameRGBA·alloc_capture_drm:: mmap failed");
-    drmModeFreeFB2(fb);
-    free(frame);
-    return NULL;
-  }
-
-  drmModeFreeFB2(fb);
-  return frame;
-}
-
-// Deallocate a frame (local or DRM)
-void FrameRGBA·dealloc(FrameRGBA **frame){
-  if(!frame || !(*frame)) return;
-
-  if((*frame)->type == FRAME_TYPE_LOCAL){
-    free((*frame)->data);  // Free local pixel data
-  }else if((*frame)->type == FRAME_TYPE_DRM){
-    munmap((*frame)->data, (*frame)->width * (*frame)->height * sizeof(PixelRGBA));  // Unmap DRM buffer
-  }
-
-  free(*frame);
-  *frame = NULL;
+  frame->data = data; // External data passed in
 }
 
-
-// Method to send a frame to the display
-int FrameRGBA·display(FrameRGBA *frame ,int fd ,uint32_t crtc_id ,uint32_t connector_id){
-  if(frame->type != FRAME_TYPE_DRM){
-    fprintf(stderr ,"FrameRGBA·display:: can only display DRM frames\n");
-    return -1;
+// Deallocate the frame
+void FrameGeneric·dealloc(void *frame_instance) {
+  FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
+  if (frame->data) {
+    free(frame->data);
+    frame->data = NULL;
   }
-
-  // Use drmModeSetCrtc to display the DRM framebuffer
-  int ret = drmModeSetCrtc(fd, crtc_id, frame->drm_fb_id, 0, 0, &connector_id, 1, NULL);
-  if(ret){
-    perror("drmModeSetCrtc failed");
-    return ret;
-  }
-
-  return 0;  // Success
 }
 
 // Copy one frame to another
-void FrameRGBA·copy(FrameRGBA *from_frame ,FrameRGBA **to_frame_arg){
-  if( !to_frame_arg || !(*to_frame_arg) || !from_frame ) return;
+void FrameGeneric·copy(void *from_frame_instance, void *to_frame_instance) {
+  FrameGeneric·Instance *from_frame = (FrameGeneric·Instance *)from_frame_instance;
+  FrameGeneric·Instance *to_frame = (FrameGeneric·Instance *)to_frame_instance;
 
-  FrameRGBA *to_frame = *to_frame_arg;
-  uint32_t width ,height;
-  FrameRGBA·dimensions(from_frame ,&width ,&height);
-
-  if(to_frame->width != width || to_frame->height != height){
-    fprintf(stderr ,"FrameRGBA·copy:: dimensions mismatch\n");
+  if (to_frame->width != from_frame->width || to_frame->height != from_frame->height) {
+    fprintf(stderr, "FrameGeneric·copy:: dimensions mismatch\n");
     return;
   }
-
-  memcpy(to_frame->data, from_frame->data, width * height * sizeof(PixelRGBA));
-}
-
-// if i and j walk out of frame returns NULL
-PixelRGBA *FrameRGBA·access(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
-  if(!from_frame) return NULL;
-  uint32_t width ,height;
-  FrameRGBA·dimensions(from_frame ,&width ,&height);
-  if(i >= width) return NULL;
-  if(j >= height) return NULL;
-  return &(from_frame->data[j * width + i]);
+  
+  size_t pixel_size = from_frame->pixel_interface->size();
+  memcpy(to_frame->data, from_frame->data, from_frame->width * from_frame->height * pixel_size);
 }
 
-PixelRGBA FrameRGBA·read(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
-  if(!from_frame){
-    fprintf(stderr, "FrameRGBA·read:: warning, empty frame, so returning a neutral pixel.");
-    return PixelRGBA·neutral;
+// Read a pixel from the frame
+void FrameGeneric·read(void *frame_instance, int i, int j, void *result_px) {
+  FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
+  if (i >= frame->width || j >= frame->height) {
+    fprintf(stderr, "FrameGeneric·read:: index out of bounds\n");
+    return;
   }
-  return *FrameRGBA·access(from_frame ,i ,j);
+  
+  size_t pixel_size = frame->pixel_interface->size();
+  void *px = (char *)frame->data + (j * frame->width + i) * pixel_size;
+  memcpy(result_px, px, pixel_size);
 }
 
-void FrameRGBA·write(FrameRGBA *to_frame ,uint32_t i ,uint32_t j ,PixelRGBA px){
-  if(!to_frame){
-    fprintf(stderr, "FrameRGBA·write:: warning, empty frame, write ignored.");
+// Write a pixel to the frame
+void FrameGeneric·write(void *frame_instance, int i, int j, const void *px) {
+  FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
+  if (i >= frame->width || j >= frame->height) {
+    fprintf(stderr, "FrameGeneric·write:: index out of bounds\n");
     return;
   }
-  *FrameRGBA·access(to_frame ,i ,j) = px;
+  
+  size_t pixel_size = frame->pixel_interface->size();
+  void *dst_px = (char *)frame->data + (j * frame->width + i) * pixel_size;
+  memcpy(dst_px, px, pixel_size);
 }
 
-// search frame for condition where f returns a non-null pointer
-// f is handed successive pointers to pixels in the frame.
-// f is given the frame in case it needs context.
-// f is given an argument is it is difficult to curry functions in C.
-void *FrameRGBA·exist
-(
-  FrameRGBA *frame 
-  ,void *(*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
-  ,void *arg
-  ){
-
-  if(!frame) return NULL;
-
-  void *item;
-  uint32_t width ,height;
-  FrameRGBA·dimensions(frame ,&width ,&height);
-  uint32_t i = 0;
-  uint32_t j = 0;
-  do{
-    PixelRGBA *px = FrameRGBA·access(frame ,i ,j);
-    if( item=f(frame ,px ,arg) ) return item;
-
-    if( i == width - 1 ){
-      i = 0;
-      j++;
-    }else{ 
-      i++;
+// Fill the frame with a specific pixel
+void FrameGeneric·fill(void *frame_instance, const void *px) {
+  FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
+  for (int j = 0; j < frame->height; j++) {
+    for (int i = 0; i < frame->width; i++) {
+      FrameGeneric·write(frame_instance, i, j, px);
     }
-  }while(j < height);
-  return NULL;
+  }
 }
 
-typedef struct{
-  void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg);
-  void *arg;
-} every_arg_t;
-void *every_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg0){
-  every_arg_t *ea = arg0;
-  ea->f(frame ,px ,ea->arg);
-  return NULL;
-}
-void FrameRGBA·every
-(
-  FrameRGBA *frame 
-  ,void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg) 
-  ,void *arg
-  ){
-  every_arg_t ea = {.f = f ,.arg = arg};
-  FrameRGBA·exist(frame ,every_f ,&ea);
+// Apply a function to every pixel in the frame
+void FrameGeneric·every(void *frame_instance, void (*f)(void *frame, void *px, void *arg), void *arg) {
+  FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
+  size_t pixel_size = frame->pixel_interface->size();
+  for (int j = 0; j < frame->height; j++) {
+    for (int i = 0; i < frame->width; i++) {
+      void *px = (char *)frame->data + (j * frame->width + i) * pixel_size;
+      f(frame_instance, px, arg);
+    }
+  }
 }
 
-void fill_f(FrameRGBA *to_frame ,PixelRGBA *to_px ,void *arg){
-  if(!to_frame) return;
-  PixelRGBA *px = arg;
-  *to_px = *px;
-}
-void FrameRGBA·fill(FrameRGBA *to_frame ,PixelRGBA *fill_px){
-  if(!to_frame) return;
-  FrameRGBA·every(to_frame ,fill_f ,fill_px);
-}
+//--------------------------------------------------------------------------------
+// FrameGeneric interface instance
 
-void fill_random_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg){
-  *px = PixelRGBA·random();
-}
-void FrameRGBA·fill_random(FrameRGBA *frame){
-  if(!frame) return;
-  FrameRGBA·every(frame ,fill_random_f ,NULL);
-}
+Frame FrameGeneric = {
+  .alloc = FrameGeneric·alloc
+  ,.alloc_external_data = FrameGeneric·alloc_external_data
+  ,.dealloc = FrameGeneric·dealloc
+  ,.copy = FrameGeneric·copy
+  ,.read = FrameGeneric·read
+  ,.write = FrameGeneric·write
+  ,.fill = FrameGeneric·fill
+  ,.every = FrameGeneric·every
+};
index ceff03b..4deb312 100644 (file)
@@ -5,19 +5,36 @@
   they must be packed as: 0xAARRGGBB.
 
   For the sake of consistency, pixels are always passed by reference. Functions
-  that generate new pixels, return the new pixel by value.
+  that generate new pixels return the new pixel by value.
 */
 
 #include <endian.h>
 #include <stdint.h>
 #include <stdlib.h> // for rand()
+#include <stdbool.h>
 #include <time.h>   // for seeding rand()
 
 //--------------------------------------------------------------------------------
-// instance state
+// Pixel Abstract Interface
+
+typedef struct {
+  size_t (*size)();                                          // Returns the size of the pixel type in bytes
+  void (*random)(void *result_px);                           // Generates a random pixel
+  void (*black)(void *result_px);                            // Returns a black pixel
+  void (*white)(void *result_px);                            // Returns a white pixel
+  void (*neutral)(void *result_px);                          // Returns a neutral pixel
+  void (*copy_from_uint32)(void *px0, uint32_t from_uint32);  // Copies from a uint32_t to a pixel
+  bool (*equals)(const void *px0, const void *px1);          // Compares two pixels
+  void (*blend)(const void *px0, const void *px1, void *result_px);  // Blends two pixels and returns the result in result_px
+  void (*invert)(const void *px0, void *result_px);          // Inverts a pixel and stores the result in result_px
+  void (*map_to_grayscale)(const void *px0, void *result_px); // Converts a pixel to grayscale and stores the result in result_px
+} Pixel;
+
+//--------------------------------------------------------------------------------
+// instance state for RGBA pixel type
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-  typedef union{
+  typedef union {
     uint32_t aggregate;
     struct __attribute__((packed)) {
       uint8_t blue;
@@ -25,9 +42,9 @@
       uint8_t red;
       uint8_t alpha;
     };
-  } PixelRGBA;
+  } PixelRGBA·Instance;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-  typedef union{
+  typedef union {
     uint32_t aggregate;
     struct __attribute__((packed)) {
       uint8_t alpha;
       uint8_t green;
       uint8_t blue;
     };
-  } PixelRGBA;
+  } PixelRGBA·Instance;
 #else
   #warning "Pixel.c: unknown __BYTE_ORDER__ found when packing a PixelRGBA. Probably catastrophic, but compilation will continue so as to look for more errors."
 #endif
 
-//--------------------------------------------------------------------------------
-// interface
-
-PixelRGBA PixelRGBA·black   = {.aggregate = 0xff000000};
-PixelRGBA PixelRGBA·white   = {.aggregate = 0xffffffff};
-PixelRGBA PixelRGBA·neutral = {.aggregate = 0x80808080};
-
-// makes a Pixel with a random value.
-PixelRGBA PixelRGBA·random(){
-  PixelRGBA px;
-  #if RAND_MAX < 0xFFFFFFFF
-    px.aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF);
-  #else
-    px.aggregate = (uint32_t)rand();      
-  #endif
-  #if RAND_MAX < 0xFFFF
-    #warning "Pixel.c: warning standard rand() claims to deliver less than 16-bit values."
-  #endif
-  return px;
-}
-
-// initialize a Pixel given the individual field values
-void PixelRGBA·structure
-  (
-   PixelRGBA *px 
-   ,uint8_t red 
-   ,uint8_t green 
-   ,uint8_t blue 
-   ,uint8_t alpha
-   ){
+// Initialize a Pixel given the individual field values.
+void PixelRGBA·structure(PixelRGBA *px ,uint8_t red ,uint8_t green ,uint8_t blue ,uint8_t alpha){
   px->blue  = blue;
   px->green = green;
   px->red   = red;
   px->alpha = alpha;
 }
 
-void PixelRGBA·copy_from_uint32(PixelRGBA *to_px ,uint32_t from_uint32){
-  to_px->aggregate = from_uint32;
-}
-
-void PixelRGBA·destructure
-  (
-   PixelRGBA *px 
-   ,uint8_t *red 
-   ,uint8_t *green 
-   ,uint8_t *blue 
-   ,uint8_t *alpha
-   ){
+// Decompose a Pixel into its individual color components.
+void PixelRGBA·destructure(PixelRGBA *px ,uint8_t *red ,uint8_t *green ,uint8_t *blue ,uint8_t *alpha){
   *blue  = px->blue;
   *green = px->green;
   *red   = px->red;
   *alpha = px->alpha;
 }
 
-bool PixelRGBA·equals(const PixelRGBA *px0 ,const PixelRGBA *px1) {
-  return px0->aggregate == px1->aggregate;
+//--------------------------------------------------------------------------------
+// interface for PixelRGBA type
+
+// Generate a black pixel.
+void PixelRGBA·black(void *result_px){
+  PixelRGBA *px = (PixelRGBA *)result_px;
+  px->aggregate = 0xff000000;
 }
 
-PixelRGBA PixelRGBA·blend(const PixelRGBA *px0 ,const PixelRGBA *px1) {
-  PixelRGBA px2;
-  px2.alpha = (px0->alpha + px1->alpha) / 2;
-  px2.red   = (px0->red + px1->red) / 2;
-  px2.green = (px0->green + px1->green) / 2;
-  px2.blue  = (px0->blue + px1->blue) / 2;
-  return px2;
+// Generate a white pixel.
+void PixelRGBA·white(void *result_px){
+  PixelRGBA *px = (PixelRGBA *)result_px;
+  px->aggregate = 0xffffffff;
 }
 
-PixelRGBA PixelRGBA·invert(const PixelRGBA *px0) {
-  PixelRGBA px2;
-  px2.red   = 255 - px0->red;
-  px2.green = 255 - px0->green;
-  px2.blue  = 255 - px0->blue;
-  px2.alpha = px0->alpha;
-  return px2;
+// Generate a neutral pixel.
+void PixelRGBA·neutral(void *result_px){
+  PixelRGBA *px = (PixelRGBA *)result_px;
+  px->aggregate = 0x80808080;
 }
 
-PixelRGBA PixelRGBA·map_to_grayscale(const PixelRGBA *px0) {
-  uint8_t gray_level = (uint8_t)(0.299 * px0->red + 0.587 * px0->green + 0.114 * px0->blue);
-  PixelRGBA px1 = 
-    {
-      .red    = gray_level 
-      ,.green = gray_level 
-      ,.blue  = gray_level 
-      ,.alpha = px0->alpha
-    };
-  return px1;
+// Generate a random pixel.
+void PixelRGBA·random(void *result_px){
+  PixelRGBA *px = (PixelRGBA *)result_px;
+  #if RAND_MAX < 0xFFFFFFFF
+    px->aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF);
+  #else
+    px->aggregate = (uint32_t)rand();
+  #endif
+}
+
+// Copy from a uint32_t value to a PixelRGBA.
+void PixelRGBA·copy_from_uint32(void *instance ,uint32_t from_uint32){
+  PixelRGBA *to_px = (PixelRGBA *)instance;
+  to_px->aggregate = from_uint32;
+}
+
+// Check if two pixels are equal.
+bool PixelRGBA·equals(const void *px0 ,const void *px1){
+  return ((PixelRGBA *)px0)->aggregate == ((PixelRGBA *)px1)->aggregate;
+}
+
+// Blend two pixels.
+void PixelRGBA·blend(const void *px0 ,const void *px1 ,void *result_px){
+  PixelRGBA *result = (PixelRGBA *)result_px;
+
+  const PixelRGBA *p0 = (const PixelRGBA *)px0;
+  const PixelRGBA *p1 = (const PixelRGBA *)px1;
+
+  result->alpha = (p0->alpha + p1->alpha) / 2;
+  result->red   = (p0->red + p1->red) / 2;
+  result->green = (p0->green + p1->green) / 2;
+  result->blue  = (p0->blue + p1->blue) / 2;
 }
+
+// Invert the colors of a pixel.
+void PixelRGBA·invert(const void *px0 ,void *result_px){
+  PixelRGBA *result = (PixelRGBA *)result_px;
+
+  const PixelRGBA *p = (const PixelRGBA *)px0;
+  result->red   = 255 - p->red;
+  result->green = 255 - p->green;
+  result->blue  = 255 - p->blue;
+  result->alpha = p->alpha;  // Alpha remains unchanged
+}
+
+// Convert a pixel to grayscale.
+void PixelRGBA·map_to_grayscale(const void *px0 ,void *result_px){
+  PixelRGBA *result = (PixelRGBA *)result_px;
+
+  const PixelRGBA *p = (const PixelRGBA *)px0;
+  uint8_t gray_level = (uint8_t)(0.299 * p->red + 0.587 * p->green + 0.114 * p->blue);
+
+  result->red    = gray_level;
+  result->green  = gray_level;
+  result->blue   = gray_level;
+  result->alpha  = p->alpha;
+}
+
+//--------------------------------------------------------------------------------
+// PixelRGBA interface instance
+
+Pixel PixelRGBA = {
+  .random = PixelRGBA·random
+  ,.copy_from_uint32 = PixelRGBA·copy_from_uint32
+  ,.equals = PixelRGBA·equals
+  ,.blend = PixelRGBA·blend
+  ,.invert = PixelRGBA·invert
+  ,.map_to_grayscale = PixelRGBA·map_to_grayscale
+  ,.black = PixelRGBA·black
+  ,.white = PixelRGBA·white
+  ,.neutral = PixelRGBA·neutral
+};
diff --git a/developer/cc/Pixel_2.c b/developer/cc/Pixel_2.c
new file mode 100644 (file)
index 0000000..400665d
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+  Pixel types
+
+  Currently implements only RGBA, which are specified by the hardware; hence
+  they must be packed as: 0xAARRGGBB.
+
+  For the sake of consistency, pixels are always passed by reference. Functions
+  that generate new pixels return the new pixel by value.
+*/
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdlib.h> // for rand()
+#include <stdbool.h>
+#include <time.h>   // for seeding rand()
+
+//--------------------------------------------------------------------------------
+// Pixel Abstract Interface
+
+typedef struct {
+  void* (*random)();
+  void (*copy_from_uint32)(void *px0 ,uint32_t from_uint32);
+  bool (*equal)(const void *px0 ,const void *px1);
+  void* (*blend)(const void *px0 ,const void *px1);
+  void* (*invert)(const void *px0);
+  void* (*map_to_grayscale)(const void *px0);
+  void* (*black)();
+  void* (*white)();
+  void* (*neutral)();
+} Pixel;
+
+//--------------------------------------------------------------------------------
+// instance state for RGBA pixel type
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  typedef union {
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t blue;
+      uint8_t green;
+      uint8_t red;
+      uint8_t alpha;
+    };
+  } PixelRGBA·Instance;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  typedef union {
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t alpha;
+      uint8_t red;
+      uint8_t green;
+      uint8_t blue;
+    };
+  } PixelRGBA·Instance;
+#else
+  #warning "Pixel.c: unknown __BYTE_ORDER__ found when packing a PixelRGBA. Probably catastrophic, but compilation will continue so as to look for more errors."
+#endif
+
+// Initialize a Pixel given the individual field values.
+void PixelRGBA·structure(PixelRGBA *px ,uint8_t red ,uint8_t green ,uint8_t blue ,uint8_t alpha){
+  px->blue  = blue;
+  px->green = green;
+  px->red   = red;
+  px->alpha = alpha;
+}
+
+// Decompose a Pixel into its individual color components.
+void PixelRGBA·destructure(PixelRGBA *px ,uint8_t *red ,uint8_t *green ,uint8_t *blue ,uint8_t *alpha){
+  *blue  = px->blue;
+  *green = px->green;
+  *red   = px->red;
+  *alpha = px->alpha;
+}
+
+//--------------------------------------------------------------------------------
+// interface for PixelRGBA type
+
+// Generate a black pixel.
+void* PixelRGBA·black(){
+  PixelRGBA *px = malloc(sizeof(PixelRGBA));
+  if( px ) px->aggregate = 0xff000000;
+  return px;
+}
+
+// Generate a white pixel.
+void* PixelRGBA·white(){
+  PixelRGBA *px = malloc(sizeof(PixelRGBA));
+  if( px ) px->aggregate = 0xffffffff;
+  return px;
+}
+
+// Generate a neutral pixel.
+void* PixelRGBA·neutral(){
+  PixelRGBA *px = malloc(sizeof(PixelRGBA));
+  if( px ) px->aggregate = 0x80808080;
+  return px;
+}
+
+// Generate a random pixel.
+void* PixelRGBA·random(){
+  PixelRGBA *px = malloc(sizeof(PixelRGBA));
+  if( px == NULL ) return NULL;
+
+  #if RAND_MAX < 0xFFFFFFFF
+    px->aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF);
+  #else
+    px->aggregate = (uint32_t)rand();
+  #endif
+  return px;
+}
+
+// Copy from a uint32_t value to a PixelRGBA.
+void PixelRGBA·copy_from_uint32(void *instance ,uint32_t from_uint32){
+  PixelRGBA *to_px = (PixelRGBA *)instance;
+  to_px->aggregate = from_uint32;
+}
+
+// Check if two pixels are equal.
+bool PixelRGBA·equal(const void *px0 ,const void *px1){
+  return ((PixelRGBA *)px0)->aggregate == ((PixelRGBA *)px1)->aggregate;
+}
+
+// Blend two pixels.
+void* PixelRGBA·blend(const void *px0 ,const void *px1){
+  PixelRGBA *result = malloc(sizeof(PixelRGBA));
+  if( !result ) return NULL;
+
+  const PixelRGBA *p0 = (const PixelRGBA *)px0;
+  const PixelRGBA *p1 = (const PixelRGBA *)px1;
+
+  result->alpha = (p0->alpha + p1->alpha) / 2;
+  result->red   = (p0->red + p1->red) / 2;
+  result->green = (p0->green + p1->green) / 2;
+  result->blue  = (p0->blue + p1->blue) / 2;
+
+  return result;
+}
+
+// Invert the colors of a pixel.
+void* PixelRGBA·invert(const void *px0){
+  PixelRGBA *result = malloc(sizeof(PixelRGBA));
+  if( !result ) return NULL;
+
+  const PixelRGBA *p = (const PixelRGBA *)px0;
+  result->red   = 255 - p->red;
+  result->green = 255 - p->green;
+  result->blue  = 255 - p->blue;
+  result->alpha = p->alpha;  // Alpha remains unchanged
+
+  return result;
+}
+
+// Convert a pixel to grayscale.
+void* PixelRGBA·map_to_grayscale(const void *px0){
+  PixelRGBA *result = malloc(sizeof(PixelRGBA));
+  if( !result ) return NULL;
+
+  const PixelRGBA *p = (const PixelRGBA *)px0;
+  uint8_t gray_level = (uint8_t)(0.299 * p->red + 0.587 * p->green + 0.114 * p->blue);
+
+  result->red    = gray_level;
+  result->green  = gray_level;
+  result->blue   = gray_level;
+  result->alpha  = p->alpha;
+
+  return result;
+}
+
+//--------------------------------------------------------------------------------
+// PixelRGBA interface instance
+
+Pixel PixelRGBA·Interface = {
+  .random = PixelRGBA·random
+  ,.copy_from_uint32 = PixelRGBA·copy_from_uint32
+  ,.equal = PixelRGBA·equal
+  ,.blend = PixelRGBA·blend
+  ,.invert = PixelRGBA·invert
+  ,.map_to_grayscale = PixelRGBA·map_to_grayscale
+  ,.black = PixelRGBA·black
+  ,.white = PixelRGBA·white
+  ,.neutral = PixelRGBA·neutral
+};
diff --git a/developer/cc/Pixel_2024-09-18T2100.c b/developer/cc/Pixel_2024-09-18T2100.c
new file mode 100644 (file)
index 0000000..ce17e52
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+  Pixel types
+
+  Currently implements only RGBA, which are specified by the hardware; hence
+  they must be packed as: 0xAARRGGBB.
+
+  For the sake of consistency, pixels are always passed by reference. Functions
+  that generate new pixels, return the new pixel by value.
+*/
+
+#include <endian.h>
+#include <stdint.h>
+#include <stdlib.h> // for rand()
+#include <time.h>   // for seeding rand()
+
+//--------------------------------------------------------------------------------
+// instance state
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t blue;
+      uint8_t green;
+      uint8_t red;
+      uint8_t alpha;
+    };
+  } PixelRGBA;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+  typedef union{
+    uint32_t aggregate;
+    struct __attribute__((packed)) {
+      uint8_t alpha;
+      uint8_t red;
+      uint8_t green;
+      uint8_t blue;
+    };
+  } PixelRGBA;
+#else
+  #warning "Pixel.c: unknown __BYTE_ORDER__ found when packing a PixelRGBA. Probably catastrophic, but compilation will continue so as to look for more errors."
+#endif
+
+// Initialize a Pixel given the individual field values.
+void PixelRGBA·structure
+  (
+   PixelRGBA *px 
+   ,uint8_t red 
+   ,uint8_t green 
+   ,uint8_t blue 
+   ,uint8_t alpha
+   ){
+  px->blue  = blue;
+  px->green = green;
+  px->red   = red;
+  px->alpha = alpha;
+}
+
+// take apart a Pixel
+void PixelRGBA·destructure
+  (
+   PixelRGBA *px 
+   ,uint8_t *red 
+   ,uint8_t *green 
+   ,uint8_t *blue 
+   ,uint8_t *alpha
+   ){
+  *blue  = px->blue;
+  *green = px->green;
+  *red   = px->red;
+  *alpha = px->alpha;
+}
+
+//--------------------------------------------------------------------------------
+// interface
+
+PixelRGBA PixelRGBA·black   = {.aggregate = 0xff000000};
+PixelRGBA PixelRGBA·white   = {.aggregate = 0xffffffff};
+PixelRGBA PixelRGBA·neutral = {.aggregate = 0x80808080};
+
+// makes a Pixel with a random value.
+PixelRGBA PixelRGBA·random(){
+  PixelRGBA px;
+  #if RAND_MAX < 0xFFFFFFFF
+    px.aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF);
+  #else
+    px.aggregate = (uint32_t)rand();      
+  #endif
+  #if RAND_MAX < 0xFFFF
+    #warning "Pixel.c: warning standard rand() claims to deliver less than 16-bit values."
+  #endif
+  return px;
+}
+
+
+void PixelRGBA·copy_from_uint32(PixelRGBA *to_px ,uint32_t from_uint32){
+  to_px->aggregate = from_uint32;
+}
+
+bool PixelRGBA·equals(const PixelRGBA *px0 ,const PixelRGBA *px1) {
+  return px0->aggregate == px1->aggregate;
+}
+
+PixelRGBA PixelRGBA·blend(const PixelRGBA *px0 ,const PixelRGBA *px1) {
+  PixelRGBA px2;
+  px2.alpha = (px0->alpha + px1->alpha) / 2;
+  px2.red   = (px0->red + px1->red) / 2;
+  px2.green = (px0->green + px1->green) / 2;
+  px2.blue  = (px0->blue + px1->blue) / 2;
+  return px2;
+}
+
+PixelRGBA PixelRGBA·invert(const PixelRGBA *px0) {
+  PixelRGBA px2;
+  px2.red   = 255 - px0->red;
+  px2.green = 255 - px0->green;
+  px2.blue  = 255 - px0->blue;
+  px2.alpha = px0->alpha;
+  return px2;
+}
+
+PixelRGBA PixelRGBA·map_to_grayscale(const PixelRGBA *px0) {
+  uint8_t gray_level = (uint8_t)(0.299 * px0->red + 0.587 * px0->green + 0.114 * px0->blue);
+  PixelRGBA px1 = 
+    {
+      .red    = gray_level 
+      ,.green = gray_level 
+      ,.blue  = gray_level 
+      ,.alpha = px0->alpha
+    };
+  return px1;
+}