diff options
Diffstat (limited to 'src/media.c')
-rw-r--r-- | src/media.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/media.c b/src/media.c new file mode 100644 index 00000000..9f6acd19 --- /dev/null +++ b/src/media.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* Copyright 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
2 | |||
3 | Redistribution and use in source and binary forms, with or without | ||
4 | modification, are permitted provided that the following conditions are met: | ||
5 | |||
6 | 1. Redistributions of source code must retain the above copyright notice, this | ||
7 | list of conditions and the following disclaimer. | ||
8 | 2. Redistributions in binary form must reproduce the above copyright notice, | ||
9 | this list of conditions and the following disclaimer in the documentation | ||
10 | and/or other materials provided with the distribution. | ||
11 | |||
12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | ||
16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | ||
22 | |||
23 | #include "media.h" | ||
24 | #include "gmdocument.h" | ||
25 | #include "ui/window.h" | ||
26 | |||
27 | #include <the_Foundation/ptrarray.h> | ||
28 | #include <stb_image.h> | ||
29 | #include <SDL_hints.h> | ||
30 | #include <SDL_render.h> | ||
31 | |||
32 | iDeclareType(GmImage) | ||
33 | |||
34 | struct Impl_GmImage { | ||
35 | iInt2 size; | ||
36 | size_t numBytes; | ||
37 | iString mime; | ||
38 | iGmLinkId linkId; | ||
39 | iBool isPermanent; | ||
40 | SDL_Texture *texture; | ||
41 | }; | ||
42 | |||
43 | void init_GmImage(iGmImage *d, const iBlock *data) { | ||
44 | init_String(&d->mime); | ||
45 | d->isPermanent = iFalse; | ||
46 | d->numBytes = size_Block(data); | ||
47 | uint8_t *imgData = stbi_load_from_memory( | ||
48 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); | ||
49 | if (!imgData) { | ||
50 | d->size = zero_I2(); | ||
51 | d->texture = NULL; | ||
52 | } | ||
53 | else { | ||
54 | SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormatFrom( | ||
55 | imgData, d->size.x, d->size.y, 32, d->size.x * 4, SDL_PIXELFORMAT_ABGR8888); | ||
56 | /* TODO: In multiwindow case, all windows must have the same shared renderer? | ||
57 | Or at least a shared context. */ | ||
58 | SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"); /* linear scaling */ | ||
59 | d->texture = SDL_CreateTextureFromSurface(renderer_Window(get_Window()), surface); | ||
60 | SDL_FreeSurface(surface); | ||
61 | stbi_image_free(imgData); | ||
62 | } | ||
63 | d->linkId = 0; | ||
64 | } | ||
65 | |||
66 | void deinit_GmImage(iGmImage *d) { | ||
67 | SDL_DestroyTexture(d->texture); | ||
68 | deinit_String(&d->mime); | ||
69 | } | ||
70 | |||
71 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) | ||
72 | |||
73 | /*----------------------------------------------------------------------------------------------*/ | ||
74 | |||
75 | struct Impl_Media { | ||
76 | iPtrArray images; | ||
77 | }; | ||
78 | |||
79 | iDefineTypeConstruction(Media) | ||
80 | |||
81 | void init_Media(iMedia *d) { | ||
82 | init_PtrArray(&d->images); | ||
83 | } | ||
84 | |||
85 | void deinit_Media(iMedia *d) { | ||
86 | clear_Media(d); | ||
87 | deinit_PtrArray(&d->images); | ||
88 | } | ||
89 | |||
90 | void clear_Media(iMedia *d) { | ||
91 | iForEach(PtrArray, i, &d->images) { | ||
92 | deinit_GmImage(i.ptr); | ||
93 | } | ||
94 | clear_PtrArray(&d->images); | ||
95 | } | ||
96 | |||
97 | void setImage_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlock *data, | ||
98 | iBool allowHide) { | ||
99 | if (!mime || !data) { | ||
100 | iGmImage *img; | ||
101 | const iMediaId existing = findLinkImage_Media(d, linkId); | ||
102 | if (existing) { | ||
103 | take_PtrArray(&d->images, existing - 1, (void **) &img); | ||
104 | delete_GmImage(img); | ||
105 | } | ||
106 | } | ||
107 | else { | ||
108 | /* TODO: check if we know this MIME type */ | ||
109 | /* Upload the image. */ { | ||
110 | iGmImage *img = new_GmImage(data); | ||
111 | img->linkId = linkId; /* TODO: use a hash? */ | ||
112 | img->isPermanent = !allowHide; | ||
113 | set_String(&img->mime, mime); | ||
114 | if (img->texture) { | ||
115 | pushBack_PtrArray(&d->images, img); | ||
116 | } | ||
117 | else { | ||
118 | delete_GmImage(img); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | // doLayout_GmDocument_(d); | ||
123 | } | ||
124 | |||
125 | iMediaId findLinkImage_Media(const iMedia *d, iGmLinkId linkId) { | ||
126 | /* TODO: use a hash */ | ||
127 | iConstForEach(PtrArray, i, &d->images) { | ||
128 | const iGmImage *img = i.ptr; | ||
129 | if (img->linkId == linkId) { | ||
130 | return index_PtrArrayConstIterator(&i) + 1; | ||
131 | } | ||
132 | } | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | SDL_Texture *imageTexture_Media(const iMedia *d, uint16_t imageId) { | ||
137 | if (imageId > 0 && imageId <= size_PtrArray(&d->images)) { | ||
138 | const iGmImage *img = constAt_PtrArray(&d->images, imageId - 1); | ||
139 | return img->texture; | ||
140 | } | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | void imageInfo_Media(const iMedia *d, uint16_t imageId, iGmImageInfo *info_out) { | ||
145 | if (imageId > 0 && imageId <= size_PtrArray(&d->images)) { | ||
146 | const iGmImage *img = constAt_PtrArray(&d->images, imageId - 1); | ||
147 | info_out->size = img->size; | ||
148 | info_out->numBytes = img->numBytes; | ||
149 | info_out->mime = cstr_String(&img->mime); | ||
150 | info_out->isPermanent = img->isPermanent; | ||
151 | } | ||
152 | else { | ||
153 | iZap(*info_out); | ||
154 | } | ||
155 | } | ||