Skip to content

abnore/Canopy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Canopy Logo

Lightweight windowing and event handling for macOS, built in C with a Cocoa backend.


About

Canopy is a simple windowing and input library for macOS. It is written in C with a native Objective-C backend and uses Cocoa directly. No third-party dependencies.

This project is educational and experimental in nature. It’s not intended for production or anything like that. I just want to better understand macOS internals and build something from scratch.

Warning

This project is under active development and is evolving quickly. Features, function names, and structures may change at any time. Breaking changes are likely.


Goals

  • Create and manage native macOS windows
  • Handle mouse, keyboard, and scroll input
  • Provide a backbuffer and rendering pipeline
  • Add a logging system (broke this out as BlackBox)
  • Enable hardware acceleration
  • Add sprite support and simple 2D rendering helpers

Getting Started

Requirements

  • macOS (tested on Monterey and later)
  • Clang (or Xcode CLI tools)
  • C99-compatible compiler

Installation

git clone <link>
make install

And it will be installed on your system.

Minimal Example

Example Output

(Examples and demos to come)

Example output with colored background


/*******************************************************************************
*
*   CANOPY [Example] - Custom Framebuffer Rendering
*
*   Description:
*       Renders a solid-colored rectangle using a manually created framebuffer.
*       Demonstrates how to allocate, fill, and display a custom framebuffer.
*       Assumes installation of Canopy and BlackBox.
*       Error checking is kept to a minimum for brevity.
*
*   Controls:
*       [Close Window] - Exit application
*
*******************************************************************************/

#include <canopy.h>
#include <blackbox.h>

#define WIDTH   400
#define HEIGHT  400

// Phthalo Blue
// https://colors.artyclick.com/color-names-dictionary/color-names/phthalo-blue-color
// little endian, abgr (rgba backwards)
#define PHTALO_BLUE 0xff890f00
#define CANOPY_BLUE 0xffff0000

int main(void)
{
    // Initialization
    //--------------------------------------------------------------------------
    init_log(LOG_DEFAULT);

    Window* win = create_window("Canopy - Custom Framebuffer",
                                WIDTH, HEIGHT,
                                CANOPY_WINDOW_STYLE_DEFAULT);

    /* get_framebuffer(win) would return the framebuffer to the window, allowing
     * direct manipulation. This is the other way, for situations where it is
     * best to finish creating the buffer, and swap.
     * [!NOTE] you can not use WIDTH, HEIGHT because of content scaling */
    framebuffer fb;
    get_framebuffer_size(win, &fb.width, &fb.height);
    int pixels_arr = fb.width * fb.height;
    fb.pitch = fb.width * CANOPY_BYTES_PER_PIXEL;

    size_t buffer_size = fb.pitch * fb.height;
    fb.pixels = canopy_malloc(buffer_size);

    //--------------------------------------------------------------------------
    // Main Game Loop
    while (!window_should_close(win))
    {
        // Update
        pump_messages();
        //----------------------------------------------------------------------
        /* `dispatch_events(win)` allows you to create custom callbacks for both
         * key, mouse and text events that handles everything. If not, doing it
         * manually like this also works */
        canopy_event event;
        while (poll_event(&event))
        {
            // Handle events (mouse, keyboard, etc.)
        }
        //----------------------------------------------------------------------

        // Draw
        //----------------------------------------------------------------------
        if (should_render_frame())
        {
            // Fill the framebuffer with its clear color
            for (int i = 0; i < pixels_arr; ++i) {
                if(i >= pixels_arr/2){
                    fb.pixels[i] = CANOPY_BLUE;
                }
                else{
                    fb.pixels[i] = PHTALO_BLUE;
                }
            }

            // Do other stuff graphicly here

            swap_backbuffer(win,&fb);   // Switch pointers of custom framebuffer
            present_buffer(win);        // Present on screen
        }
        //----------------------------------------------------------------------
    }

    // De-Initialization
    //--------------------------------------------------------------------------
    free(fb.pixels);
    free_window(win);
    shutdown_log();
    //--------------------------------------------------------------------------

    return 0;
}

Building

Use clang to build:

clang main.c src/canopy.m src/canopy_event.c src/canopy_time.c \
     -framework Cocoa -I. -Ilib -lblackbox -o bin/test

Or integrate it into your own CMake or Makefile setup.

License & Disclaimer

This is a side project, built for fun and learning.

If you’re interested in how to work directly with Cocoa and C, Canopy might be a good reference.

Feel free to use, just don’t expect it to replace SDL, Raylib or GLFW (yet)!

About

Windowing library for macOS

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors