#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
+};
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;
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
+};
--- /dev/null
+/*
+ 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
+};
--- /dev/null
+/*
+ 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;
+}