1 #include <stdlib.h>
2 #include <assert.h>
3 #include <math.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 #include "config.h"
8
9 #if MYPAINT_CONFIG_USE_GLIB
10 #include <glib.h>
11 #endif
12
13 #include "mypaint-fixed-tiled-surface.h"
14
15
16 struct MyPaintFixedTiledSurface {
17 MyPaintTiledSurface parent;
18
19 size_t tile_size; // Size (in bytes) of single tile
20 uint16_t *tile_buffer; // Stores tiles in a linear chunk of memory (16bpc RGBA)
21 uint16_t *null_tile; // Single tile that we hand out and ignore writes to
22 int tiles_width; // width in tiles
23 int tiles_height; // height in tiles
24 int width; // width in pixels
25 int height; // height in pixels
26
27 };
28
29 void free_simple_tiledsurf(MyPaintSurface *surface);
30
reset_null_tile(MyPaintFixedTiledSurface * self)31 void reset_null_tile(MyPaintFixedTiledSurface *self)
32 {
33 memset(self->null_tile, 0, self->tile_size);
34 }
35
36 static void
tile_request_start(MyPaintTiledSurface * tiled_surface,MyPaintTileRequest * request)37 tile_request_start(MyPaintTiledSurface *tiled_surface, MyPaintTileRequest *request)
38 {
39 MyPaintFixedTiledSurface *self = (MyPaintFixedTiledSurface *)tiled_surface;
40
41 const int tx = request->tx;
42 const int ty = request->ty;
43
44 uint16_t *tile_pointer = NULL;
45
46 if (tx >= self->tiles_width || ty >= self->tiles_height || tx < 0 || ty < 0) {
47 // Give it a tile which we will ignore writes to
48 tile_pointer = self->null_tile;
49
50 } else {
51 // Compute the offset for the tile into our linear memory buffer of tiles
52 size_t rowstride = self->tiles_width * self->tile_size;
53 size_t x_offset = tx * self->tile_size;
54 size_t tile_offset = (rowstride * ty) + x_offset;
55
56 tile_pointer = self->tile_buffer + tile_offset/sizeof(uint16_t);
57 }
58
59 request->buffer = tile_pointer;
60 }
61
62 static void
tile_request_end(MyPaintTiledSurface * tiled_surface,MyPaintTileRequest * request)63 tile_request_end(MyPaintTiledSurface *tiled_surface, MyPaintTileRequest *request)
64 {
65 MyPaintFixedTiledSurface *self = (MyPaintFixedTiledSurface *)tiled_surface;
66
67 const int tx = request->tx;
68 const int ty = request->ty;
69
70 if (tx >= self->tiles_width || ty >= self->tiles_height || tx < 0 || ty < 0) {
71 // Wipe any changed done to the null tile
72 reset_null_tile(self);
73 } else {
74 // We hand out direct pointers to our buffer, so for the normal case nothing needs to be done
75 }
76 }
77
78 MyPaintSurface *
mypaint_fixed_tiled_surface_interface(MyPaintFixedTiledSurface * self)79 mypaint_fixed_tiled_surface_interface(MyPaintFixedTiledSurface *self)
80 {
81 return (MyPaintSurface *)self;
82 }
83
84 int
mypaint_fixed_tiled_surface_get_width(MyPaintFixedTiledSurface * self)85 mypaint_fixed_tiled_surface_get_width(MyPaintFixedTiledSurface *self)
86 {
87 return self->width;
88 }
89
90 int
mypaint_fixed_tiled_surface_get_height(MyPaintFixedTiledSurface * self)91 mypaint_fixed_tiled_surface_get_height(MyPaintFixedTiledSurface *self)
92 {
93 return self->height;
94 }
95
96 MyPaintFixedTiledSurface *
mypaint_fixed_tiled_surface_new(int width,int height)97 mypaint_fixed_tiled_surface_new(int width, int height)
98 {
99 assert(width > 0);
100 assert(height > 0);
101
102 MyPaintFixedTiledSurface *self = (MyPaintFixedTiledSurface *)malloc(sizeof(MyPaintFixedTiledSurface));
103
104 mypaint_tiled_surface_init(&self->parent, tile_request_start, tile_request_end);
105
106 const int tile_size_pixels = self->parent.tile_size;
107
108 // MyPaintSurface vfuncs
109 self->parent.parent.destroy = free_simple_tiledsurf;
110
111 const int tiles_width = ceil((float)width / tile_size_pixels);
112 const int tiles_height = ceil((float)height / tile_size_pixels);
113 const size_t tile_size = tile_size_pixels * tile_size_pixels * 4 * sizeof(uint16_t);
114 const size_t buffer_size = tiles_width * tiles_height * tile_size;
115
116 assert(tile_size_pixels*tiles_width >= width);
117 assert(tile_size_pixels*tiles_height >= height);
118 assert(buffer_size >= width*height*4*sizeof(uint16_t));
119
120 uint16_t * buffer = (uint16_t *)malloc(buffer_size);
121 if (!buffer) {
122 fprintf(stderr, "CRITICAL: unable to allocate enough memory: %zu bytes", buffer_size);
123 free(self);
124 return NULL;
125 }
126 memset(buffer, 255, buffer_size);
127
128 self->tile_buffer = buffer;
129 self->tile_size = tile_size;
130 self->null_tile = (uint16_t *)malloc(tile_size);
131 self->tiles_width = tiles_width;
132 self->tiles_height = tiles_height;
133 self->height = height;
134 self->width = width;
135
136 reset_null_tile(self);
137
138 return self;
139 }
140
free_simple_tiledsurf(MyPaintSurface * surface)141 void free_simple_tiledsurf(MyPaintSurface *surface)
142 {
143 MyPaintFixedTiledSurface *self = (MyPaintFixedTiledSurface *)surface;
144
145 mypaint_tiled_surface_destroy(&self->parent);
146
147 free(self->tile_buffer);
148 free(self->null_tile);
149
150 free(self);
151 }
152
153