summaryrefslogtreecommitdiff
path: root/memview.c
blob: c2af3ace7e2ed3c47d49a923b4f3e957e0a6573c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <SDL.h>

#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);
		}
	}
}