From: Thomas Walker Lynch Date: Wed, 18 Sep 2024 13:24:20 +0000 (+0000) Subject: abstracting the interfaces X-Git-Url: https://git.reasoningtechnology.com/style/static/gitweb.css?a=commitdiff_plain;h=fd2f6f001b5ac020969936ef3eb804cc977ab9cc;p=noflash abstracting the interfaces --- diff --git a/developer/cc/Frame.c b/developer/cc/Frame.c index ed2225d..91b18d5 100644 --- a/developer/cc/Frame.c +++ b/developer/cc/Frame.c @@ -15,252 +15,143 @@ #include #include #include -#include -#include +#include +#include -// -------------------------------------------------------------------------------- -// 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 -#include - -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 +}; diff --git a/developer/cc/Pixel.c b/developer/cc/Pixel.c index ceff03b..4deb312 100644 --- a/developer/cc/Pixel.c +++ b/developer/cc/Pixel.c @@ -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 #include #include // for rand() +#include #include // 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; @@ -35,95 +52,117 @@ 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 index 0000000..400665d --- /dev/null +++ b/developer/cc/Pixel_2.c @@ -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 +#include +#include // for rand() +#include +#include // 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 index 0000000..ce17e52 --- /dev/null +++ b/developer/cc/Pixel_2024-09-18T2100.c @@ -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 +#include +#include // for rand() +#include // 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; +}