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