#include #include #include #include #include #include #include #include "memview.h" #include "procfs.h" struct viewer { int fd; SDL_Renderer *renderer; SDL_Texture *page_texture; uint8_t page_buffer[PAGE_SIZE]; }; enum color { BLACK = 0x00000000, WHITE = 0xFFFFFFFF, GREY = 0xFF303030, }; #define BIT_OF(X, I) (((X) >> (I)) & 1ULL) static uintptr_t zorder(int x, int y) { uintptr_t z = 0; unsigned int ux, uy; memcpy(&ux, &x, sizeof(unsigned int)); memcpy(&uy, &y, sizeof(unsigned int)); // interleaving bits results in a point on the z-order curve for (int i = 0; i < sizeof(x) * CHAR_BIT; i++) z |= (BIT_OF(ux, i) << i*2) | (BIT_OF(uy, i) << (i*2 + 1)); return z; } static void unzorder(uintptr_t z, int *x, int *y) { unsigned int ux, uy = 0; for (int i = 0; i < sizeof(z) * CHAR_BIT / 2; i++) { ux |= BIT_OF(z, i*2) << i; uy |= BIT_OF(z, i*2 + 1) << i; } memcpy(x, &ux, sizeof(int)); memcpy(y, &uy, sizeof(int)); } uintptr_t to_addr(int x, int y) { uintptr_t page = zorder(x / PAGE_WIDTH, y / PAGE_HEIGHT); int offset = x % PAGE_WIDTH + y % PAGE_HEIGHT * PAGE_WIDTH; return page * PAGE_SIZE + offset; } void to_pos(uintptr_t addr, int *x, int *y) { int px, py; unzorder(addr / PAGE_SIZE, &px, &py); int offset = addr % PAGE_SIZE; *x = px * PAGE_WIDTH + offset % PAGE_WIDTH; *y = py * PAGE_HEIGHT + offset / PAGE_WIDTH; } struct viewer *create_viewer(int fd, SDL_Renderer *renderer) { struct viewer *v = calloc(1, sizeof(struct viewer)); if (!v) return NULL; v->fd = fd; v->renderer = renderer; v->page_texture = SDL_CreateTexture(v->renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, PAGE_WIDTH, PAGE_HEIGHT); if (!v->page_texture) {free(v); return NULL;} return v; } void destroy_viewer(struct viewer *v) { SDL_DestroyTexture(v->page_texture); free(v); } static void render_page(SDL_Texture *tex, uint8_t *data) { uint32_t *pixels; int pitch; assert(SDL_LockTexture(tex, NULL, (void **) &pixels, &pitch) != -1); if (data) { for (int i = 0; i < PAGE_SIZE; i++) { for (int j = 0; j < CHAR_BIT; j++) { uint8_t bit = (data[i] >> j) & 1; pixels[i * CHAR_BIT + j] = bit ? WHITE : BLACK; } } } else { for (int i = 0; i < PAGE_WIDTH * PAGE_HEIGHT; i++) pixels[i] = GREY; } SDL_UnlockTexture(tex); } void render_pages(struct viewer *v, int x, int y, int width, int height, double scale, bool refresh) { int page_x = x / PAGE_WIDTH; int page_y = y / PAGE_HEIGHT; int offs_x = x % PAGE_WIDTH * scale; int offs_y = y % PAGE_HEIGHT * scale; int page_width = PAGE_WIDTH * scale; int page_height = PAGE_HEIGHT * scale; int view_width = width / page_width; int view_height = height / page_height; for (int draw_y = -1; draw_y <= view_height + 1; draw_y++) { for (int draw_x = -1; draw_x <= view_width + 1; draw_x++) { SDL_Rect src = {0, 0, PAGE_WIDTH, PAGE_HEIGHT}; SDL_Rect dest = { draw_x * page_width - offs_x, draw_y * page_height - offs_y, page_width, page_height }; uintptr_t page = zorder(page_x + draw_x, page_y + draw_y); bool success = read_page(v->fd, page, v->page_buffer) != -1; // TODO: unless refresh is true, do not redraw if page unaltered render_page(v->page_texture, success ? v->page_buffer : NULL); SDL_RenderCopy(v->renderer, v->page_texture, &src, &dest); } } }