Tests for displaying graphics
This commit is contained in:
parent
aec1612de2
commit
c87dcdbe3c
@ -71,7 +71,7 @@ dealloc(GraphicsManager* self) {
|
|||||||
for (i = 0; i < self->image_count; i++) free_image(self->images + i);
|
for (i = 0; i < self->image_count; i++) free_image(self->images + i);
|
||||||
free(self->images);
|
free(self->images);
|
||||||
}
|
}
|
||||||
free(self->render_pointers); free(self->render_data);
|
free(self->render_data);
|
||||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,7 +528,7 @@ handle_put_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c, b
|
|||||||
num_rows = t / global_state.cell_height;
|
num_rows = t / global_state.cell_height;
|
||||||
if (t > num_rows * global_state.cell_height) num_rows += 1;
|
if (t > num_rows * global_state.cell_height) num_rows += 1;
|
||||||
}
|
}
|
||||||
c->x += num_cols; c->y += num_rows;
|
c->x += num_cols; c->y += num_rows - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -540,7 +540,7 @@ cmp_by_zindex_and_image(const void *a_, const void *b_) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float xstart, float ystart, float dx, float dy) {
|
grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float screen_left, float screen_top, float dx, float dy, unsigned int num_cols, unsigned int num_rows) {
|
||||||
if (self->last_scrolled_by != scrolled_by) self->layers_dirty = true;
|
if (self->last_scrolled_by != scrolled_by) self->layers_dirty = true;
|
||||||
self->last_scrolled_by = scrolled_by;
|
self->last_scrolled_by = scrolled_by;
|
||||||
if (!self->layers_dirty) return;
|
if (!self->layers_dirty) return;
|
||||||
@ -549,17 +549,22 @@ grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float xstar
|
|||||||
self->num_of_negative_refs = 0; self->num_of_positive_refs = 0;
|
self->num_of_negative_refs = 0; self->num_of_positive_refs = 0;
|
||||||
Image *img; ImageRef *ref;
|
Image *img; ImageRef *ref;
|
||||||
ImageRect r;
|
ImageRect r;
|
||||||
|
float screen_width = dx * num_cols, screen_height = dy * num_rows;
|
||||||
|
float screen_bottom = screen_top + screen_height;
|
||||||
|
float screen_width_px = num_cols * global_state.cell_width;
|
||||||
|
float screen_height_px = num_rows * global_state.cell_height;
|
||||||
|
|
||||||
// Iterate over all visible refs and create render data
|
// Iterate over all visible refs and create render data
|
||||||
self->count = 0;
|
self->count = 0;
|
||||||
for (i = 0; i < self->image_count; i++) { img = self->images + i; for (j = 0; j < img->refcnt; j++) { ref = img->refs + j;
|
for (i = 0; i < self->image_count; i++) { img = self->images + i; for (j = 0; j < img->refcnt; j++) { ref = img->refs + j;
|
||||||
r.top = ystart + (scrolled_by + ref->start_row) * dy + dy * (float)ref->cell_y_offset / (float)global_state.cell_height;
|
r.top = screen_top + (scrolled_by + ref->start_row) * dy + dy * (float)ref->cell_y_offset / (float)global_state.cell_height;
|
||||||
if (ref->num_rows) r.bottom = ystart + (scrolled_by + ref->start_row + ref->num_rows) * dy;
|
if (ref->num_rows) r.bottom = screen_top + (scrolled_by + ref->start_row + ref->num_rows) * dy;
|
||||||
else r.bottom = r.top + 2.0f * (float)ref->src_height / (float)global_state.viewport_height;
|
else r.bottom = r.top + screen_height * (float)ref->src_height / screen_height_px;
|
||||||
if (r.top > 1.0f || r.bottom < -1.0f) continue; // not visible
|
if (r.top > screen_bottom || r.bottom < screen_top) continue; // not visible
|
||||||
r.left = xstart + ref->start_column * dx + dx * (float)ref->cell_x_offset / (float) global_state.cell_width;
|
|
||||||
if (ref->num_cols) r.right = xstart + (ref->start_column + ref->num_cols) * dx;
|
r.left = screen_left + ref->start_column * dx + dx * (float)ref->cell_x_offset / (float) global_state.cell_width;
|
||||||
else r.right = r.left + 2.0f * (float)ref->src_width / (float)global_state.viewport_width;
|
if (ref->num_cols) r.right = screen_left + (ref->start_column + ref->num_cols) * dx;
|
||||||
|
else r.right = r.left + screen_width * (float)ref->src_width / screen_width_px;
|
||||||
|
|
||||||
if (ref->z_index < 0) self->num_of_negative_refs++; else self->num_of_positive_refs++;
|
if (ref->z_index < 0) self->num_of_negative_refs++; else self->num_of_positive_refs++;
|
||||||
ensure_space_for(self, render_data, ImageRenderData, self->count + 1, capacity, 100);
|
ensure_space_for(self, render_data, ImageRenderData, self->count + 1, capacity, 100);
|
||||||
@ -571,16 +576,16 @@ grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float xstar
|
|||||||
}}
|
}}
|
||||||
if (!self->count) return;
|
if (!self->count) return;
|
||||||
// Sort visible refs in draw order (z-index, img)
|
// Sort visible refs in draw order (z-index, img)
|
||||||
ensure_space_for(self, render_pointers, ImageRenderData*, self->count, rp_capacity, 100);
|
qsort(self->render_data, self->count, sizeof(ImageRenderData), cmp_by_zindex_and_image);
|
||||||
for (i = 0; i < self->count; i++) self->render_pointers[i] = self->render_data + i;
|
|
||||||
qsort(self->render_pointers, self->count, sizeof(ImageRenderData*), cmp_by_zindex_and_image);
|
|
||||||
// Calculate the group counts
|
// Calculate the group counts
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < self->count) {
|
while (i < self->count) {
|
||||||
size_t image_id = self->render_pointers[i]->image_id, start;
|
size_t image_id = self->render_data[i].image_id, start = i;
|
||||||
start = i;
|
if (start == self->count - 1) i = self->count;
|
||||||
while (i < self->count - 1 && self->render_pointers[++i]->image_id == image_id) {}
|
else {
|
||||||
self->render_pointers[start]->group_count = i - start;
|
while (i < self->count - 1 && self->render_data[++i].image_id == image_id) {}
|
||||||
|
}
|
||||||
|
self->render_data[start].group_count = i - start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,12 +687,12 @@ W(set_send_to_gpu) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
W(update_layers) {
|
W(update_layers) {
|
||||||
unsigned int scrolled_by; float xstart, ystart, dx, dy;
|
unsigned int scrolled_by, sx, sy; float xstart, ystart, dx, dy;
|
||||||
PA("Iffff", &scrolled_by, &xstart, &ystart, &dx, &dy);
|
PA("IffffII", &scrolled_by, &xstart, &ystart, &dx, &dy, &sx, &sy);
|
||||||
grman_update_layers(self, scrolled_by, xstart, ystart, dx, dy);
|
grman_update_layers(self, scrolled_by, xstart, ystart, dx, dy, sx, sy);
|
||||||
PyObject *ans = PyTuple_New(self->count);
|
PyObject *ans = PyTuple_New(self->count);
|
||||||
for (size_t i = 0; i < self->count; i++) {
|
for (size_t i = 0; i < self->count; i++) {
|
||||||
ImageRenderData *r = self->render_pointers[i];
|
ImageRenderData *r = self->render_data + i;
|
||||||
#define R(attr) Py_BuildValue("{sf sf sf sf}", "left", r->attr.left, "top", r->attr.top, "right", r->attr.right, "bottom", r->attr.bottom)
|
#define R(attr) Py_BuildValue("{sf sf sf sf}", "left", r->attr.left, "top", r->attr.top, "right", r->attr.right, "bottom", r->attr.bottom)
|
||||||
PyTuple_SET_ITEM(ans, i,
|
PyTuple_SET_ITEM(ans, i,
|
||||||
Py_BuildValue("{sN sN sI si sI}", "src_rect", R(src_rect), "dest_rect", R(dest_rect), "group_count", r->group_count, "z_index", r->z_index, "image_id", r->image_id)
|
Py_BuildValue("{sN sN sI si sI}", "src_rect", R(src_rect), "dest_rect", R(dest_rect), "group_count", r->group_count, "z_index", r->z_index, "image_id", r->image_id)
|
||||||
|
|||||||
@ -66,7 +66,7 @@ typedef struct {
|
|||||||
size_t image_count, images_capacity, loading_image;
|
size_t image_count, images_capacity, loading_image;
|
||||||
Image *images;
|
Image *images;
|
||||||
size_t count, capacity, rp_capacity;
|
size_t count, capacity, rp_capacity;
|
||||||
ImageRenderData *render_data, **render_pointers;
|
ImageRenderData *render_data;
|
||||||
bool layers_dirty;
|
bool layers_dirty;
|
||||||
size_t num_of_negative_refs, num_of_positive_refs;
|
size_t num_of_negative_refs, num_of_positive_refs;
|
||||||
unsigned int last_scrolled_by;
|
unsigned int last_scrolled_by;
|
||||||
|
|||||||
@ -589,7 +589,7 @@ parse_graphics_code(Screen *screen, PyObject UNUSED *dump_callback) {
|
|||||||
|
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
if (screen->parser_buf[pos++] != '=') {
|
if (screen->parser_buf[pos++] != '=') {
|
||||||
REPORT_ERROR("Malformed graphics control block, no = after key");
|
REPORT_ERROR("Malformed graphics control block, no = after key, found: 0x%x instead", screen->parser_buf[pos-1]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state = value_state;
|
state = value_state;
|
||||||
|
|||||||
@ -238,6 +238,11 @@ PYWRAP0(destroy_global_data) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PYWRAP1(set_display_state) {
|
||||||
|
PA("iiII", &global_state.viewport_width, &global_state.viewport_height, &global_state.cell_width, &global_state.cell_height);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
#define WF(name) PYWRAP1(name) { \
|
#define WF(name) PYWRAP1(name) { \
|
||||||
unsigned int tab_id, window_id; \
|
unsigned int tab_id, window_id; \
|
||||||
PyObject *title; \
|
PyObject *title; \
|
||||||
@ -275,6 +280,7 @@ static PyMethodDef module_methods[] = {
|
|||||||
MW(set_window_render_data, METH_VARARGS),
|
MW(set_window_render_data, METH_VARARGS),
|
||||||
MW(update_window_visibility, METH_VARARGS),
|
MW(update_window_visibility, METH_VARARGS),
|
||||||
MW(set_boss, METH_O),
|
MW(set_boss, METH_O),
|
||||||
|
MW(set_display_state, METH_VARARGS),
|
||||||
MW(destroy_global_data, METH_NOARGS),
|
MW(destroy_global_data, METH_NOARGS),
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||||
|
|||||||
@ -9,7 +9,9 @@ import zlib
|
|||||||
from base64 import standard_b64encode
|
from base64 import standard_b64encode
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from kitty.fast_data_types import parse_bytes, shm_write, shm_unlink, set_send_to_gpu
|
from kitty.fast_data_types import (
|
||||||
|
parse_bytes, set_display_state, set_send_to_gpu, shm_unlink, shm_write
|
||||||
|
)
|
||||||
|
|
||||||
from . import BaseTest
|
from . import BaseTest
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ def send_command(screen, cmd, payload=b''):
|
|||||||
return c.wtcbuf
|
return c.wtcbuf
|
||||||
|
|
||||||
|
|
||||||
def helpers(self):
|
def load_helpers(self):
|
||||||
s = self.create_screen()
|
s = self.create_screen()
|
||||||
g = s.grman
|
g = s.grman
|
||||||
|
|
||||||
@ -72,7 +74,7 @@ def helpers(self):
|
|||||||
class TestGraphics(BaseTest):
|
class TestGraphics(BaseTest):
|
||||||
|
|
||||||
def test_load_images(self):
|
def test_load_images(self):
|
||||||
s, g, l, sl = helpers(self)
|
s, g, l, sl = load_helpers(self)
|
||||||
|
|
||||||
# Test simple load
|
# Test simple load
|
||||||
for f in 32, 24:
|
for f in 32, 24:
|
||||||
@ -120,7 +122,7 @@ class TestGraphics(BaseTest):
|
|||||||
|
|
||||||
@unittest.skipIf(Image is None, 'PIL not available, skipping PNG tests')
|
@unittest.skipIf(Image is None, 'PIL not available, skipping PNG tests')
|
||||||
def test_load_png(self):
|
def test_load_png(self):
|
||||||
s, g, l, sl = helpers(self)
|
s, g, l, sl = load_helpers(self)
|
||||||
w, h = 5, 3
|
w, h = 5, 3
|
||||||
img = Image.new('RGBA', (w, h), 'red')
|
img = Image.new('RGBA', (w, h), 'red')
|
||||||
rgba_data = img.tobytes()
|
rgba_data = img.tobytes()
|
||||||
@ -142,3 +144,55 @@ class TestGraphics(BaseTest):
|
|||||||
data = png('L')
|
data = png('L')
|
||||||
sl(data, f=100, expecting_data=rgba_data)
|
sl(data, f=100, expecting_data=rgba_data)
|
||||||
self.ae(l(b'a' * 20, f=100, S=20).partition(':')[0], 'EBADPNG')
|
self.ae(l(b'a' * 20, f=100, S=20).partition(':')[0], 'EBADPNG')
|
||||||
|
|
||||||
|
def test_image_put(self):
|
||||||
|
cw, ch = 10, 20
|
||||||
|
iid = 0
|
||||||
|
|
||||||
|
def create_screen():
|
||||||
|
s = self.create_screen(10, 5)
|
||||||
|
set_display_state(s.columns * cw, s.lines * ch, cw, ch)
|
||||||
|
return s, 2 / s.columns, 2 / s.lines
|
||||||
|
|
||||||
|
def put_cmd(z=0, num_cols=0, num_lines=0, x_off=0, y_off=0, width=0, height=0, cell_x_off=0, cell_y_off=0):
|
||||||
|
return 'z=%d,c=%d,r=%d,x=%d,y=%d,w=%d,h=%d,X=%d,Y=%d' % (z, num_cols, num_lines, x_off, y_off, width, height, cell_x_off, cell_y_off)
|
||||||
|
|
||||||
|
def put_image(screen, w, h, **kw):
|
||||||
|
nonlocal iid
|
||||||
|
iid += 1
|
||||||
|
cmd = 'a=T,f=24,i=%d,s=%d,v=%d,%s' % (iid, w, h, put_cmd(**kw))
|
||||||
|
data = b'x' * w * h * 3
|
||||||
|
send_command(screen, cmd, data)
|
||||||
|
|
||||||
|
def put_ref(screen, iid, **kw):
|
||||||
|
cmd = 'a=p,i=%d,%s' % (iid, put_cmd(**kw))
|
||||||
|
send_command(screen, cmd)
|
||||||
|
|
||||||
|
def layers(screen, scrolled_by=0, xstart=0, ystart=0):
|
||||||
|
dx, dy = (2 - xstart) / s.columns, (2 - ystart) / s.lines
|
||||||
|
return screen.grman.update_layers(scrolled_by, xstart, ystart, dx, dy, screen.columns, screen.lines)
|
||||||
|
|
||||||
|
def rect_eq(r, left, top, right, bottom):
|
||||||
|
for side in 'left top right bottom'.split():
|
||||||
|
a, b = r[side], locals()[side]
|
||||||
|
if abs(a - b) > 0.0001:
|
||||||
|
self.ae(a, b, 'the %s side is not equal' % side)
|
||||||
|
|
||||||
|
s, dx, dy = create_screen()
|
||||||
|
put_image(s, 10, 20)
|
||||||
|
l = layers(s)
|
||||||
|
self.ae(len(l), 1)
|
||||||
|
rect_eq(l[0]['src_rect'], 0, 0, 1, 1)
|
||||||
|
rect_eq(l[0]['dest_rect'], 0, 0, dx, dy)
|
||||||
|
self.ae(l[0]['group_count'], 1)
|
||||||
|
self.ae(s.cursor.x, 1), self.ae(s.cursor.y, 0)
|
||||||
|
put_ref(s, iid, num_cols=s.columns, x_off=2, y_off=1, width=3, height=5, cell_x_off=3, cell_y_off=1, z=-1)
|
||||||
|
l = layers(s)
|
||||||
|
self.ae(len(l), 2)
|
||||||
|
rect_eq(l[0]['src_rect'], 2 / 10, 1 / 20, (2 + 3) / 10, (1 + 5)/20)
|
||||||
|
left, top = dx + 3 * dx / cw, 1 * dy / ch
|
||||||
|
rect_eq(l[0]['dest_rect'], left, top, (1 + s.columns) * dx, top + dy * 5 / ch)
|
||||||
|
rect_eq(l[1]['src_rect'], 0, 0, 1, 1)
|
||||||
|
rect_eq(l[1]['dest_rect'], 0, 0, dx, dy)
|
||||||
|
self.ae(l[0]['group_count'], 1), self.ae(l[1]['group_count'], 1)
|
||||||
|
self.ae(s.cursor.x, 0), self.ae(s.cursor.y, 1)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user