summaryrefslogtreecommitdiff
path: root/src/ui/visbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/visbuf.c')
-rw-r--r--src/ui/visbuf.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/ui/visbuf.c b/src/ui/visbuf.c
new file mode 100644
index 00000000..82346ff0
--- /dev/null
+++ b/src/ui/visbuf.c
@@ -0,0 +1,116 @@
1#include "visbuf.h"
2#include "window.h"
3#include "util.h"
4
5iDefineTypeConstruction(VisBuf)
6
7void init_VisBuf(iVisBuf *d) {
8 d->texSize = zero_I2();
9 iZap(d->buffers);
10}
11
12void deinit_VisBuf(iVisBuf *d) {
13 dealloc_VisBuf(d);
14}
15
16void invalidate_VisBuf(iVisBuf *d) {
17 iForIndices(i, d->buffers) {
18 iZap(d->buffers[i].validRange);
19 }
20}
21
22void alloc_VisBuf(iVisBuf *d, const iInt2 size, int granularity) {
23 const iInt2 texSize = init_I2(size.x, (size.y / 2 / granularity + 1) * granularity);
24 if (!d->buffers[0].texture || !isEqual_I2(texSize, d->texSize)) {
25 d->texSize = texSize;
26 iForIndices(i, d->buffers) {
27 iVisBufTexture *tex = &d->buffers[i];
28 if (tex->texture) {
29 SDL_DestroyTexture(tex->texture);
30 }
31 tex->texture =
32 SDL_CreateTexture(renderer_Window(get_Window()),
33 SDL_PIXELFORMAT_RGBA8888,
34 SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET,
35 texSize.x,
36 texSize.y);
37 SDL_SetTextureBlendMode(tex->texture, SDL_BLENDMODE_NONE);
38 tex->origin = i * texSize.y;
39 iZap(tex->validRange);
40 }
41 }
42}
43
44void dealloc_VisBuf(iVisBuf *d) {
45 d->texSize = zero_I2();
46 iForIndices(i, d->buffers) {
47 SDL_DestroyTexture(d->buffers[i].texture);
48 d->buffers[i].texture = NULL;
49 }
50}
51
52void reposition_VisBuf(iVisBuf *d, const iRangei vis) {
53 d->vis = vis;
54 iRangei good = { 0, 0 };
55 size_t avail[3], numAvail = 0;
56 /* Check which buffers are available for reuse. */ {
57 iForIndices(i, d->buffers) {
58 iVisBufTexture *buf = d->buffers + i;
59 const iRangei region = { buf->origin, buf->origin + d->texSize.y };
60 if (region.start >= vis.end || region.end <= vis.start) {
61 avail[numAvail++] = i;
62 iZap(buf->validRange);
63 }
64 else {
65 good = union_Rangei(good, region);
66 }
67 }
68 }
69 if (numAvail == iElemCount(d->buffers)) {
70 /* All buffers are outside the visible range, do a reset. */
71 d->buffers[0].origin = vis.start;
72 d->buffers[1].origin = vis.start + d->texSize.y;
73 d->buffers[2].origin = vis.start + 2 * d->texSize.y;
74 }
75 else {
76 /* Extend to cover the visible range. */
77 while (vis.start < good.start) {
78 iAssert(numAvail > 0);
79 d->buffers[avail[--numAvail]].origin = good.start - d->texSize.y;
80 good.start -= d->texSize.y;
81 }
82 while (vis.end > good.end) {
83 iAssert(numAvail > 0);
84 d->buffers[avail[--numAvail]].origin = good.end;
85 good.end += d->texSize.y;
86 }
87 }
88}
89
90void invalidRanges_VisBuf(const iVisBuf *d, const iRangei full, iRangei *out_invalidRanges) {
91 iForIndices(i, d->buffers) {
92 const iVisBufTexture *buf = d->buffers + i;
93 const iRangei before = { full.start, buf->validRange.start };
94 const iRangei after = { buf->validRange.end, full.end };
95 const iRangei region = intersect_Rangei(d->vis, (iRangei){ buf->origin,
96 buf->origin + d->texSize.y });
97 out_invalidRanges[i] = intersect_Rangei(before, region);
98 if (isEmpty_Rangei(out_invalidRanges[i])) {
99 out_invalidRanges[i] = intersect_Rangei(after, region);
100 }
101 }
102}
103
104void draw_VisBuf(const iVisBuf *d, iInt2 topLeft) {
105 SDL_Renderer *render = renderer_Window(get_Window());
106 iForIndices(i, d->buffers) {
107 const iVisBufTexture *buf = d->buffers + i;
108 SDL_RenderCopy(render,
109 buf->texture,
110 NULL,
111 &(SDL_Rect){ topLeft.x,
112 topLeft.y + buf->origin,
113 d->texSize.x,
114 d->texSize.y });
115 }
116}