From c0c3093140e89afb9b8ff7f076610926c0b2d0e6 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Fri, 21 Aug 2015 14:27:39 -0400 Subject: [PATCH] Encode cursor hotspots into GIF comments --- rsrc/graphics.exd/mac/cursors/E.gif | Bin 872 -> 889 bytes rsrc/graphics.exd/mac/cursors/N.gif | Bin 870 -> 886 bytes rsrc/graphics.exd/mac/cursors/NE.gif | Bin 875 -> 892 bytes rsrc/graphics.exd/mac/cursors/NW.gif | Bin 873 -> 889 bytes .../mac/cursors/READ_BEFORE_EDITING.txt | 10 +++ rsrc/graphics.exd/mac/cursors/S.gif | Bin 872 -> 889 bytes rsrc/graphics.exd/mac/cursors/SE.gif | Bin 878 -> 896 bytes rsrc/graphics.exd/mac/cursors/SW.gif | Bin 878 -> 895 bytes rsrc/graphics.exd/mac/cursors/W.gif | Bin 870 -> 886 bytes rsrc/graphics.exd/mac/cursors/boot.gif | Bin 873 -> 889 bytes rsrc/graphics.exd/mac/cursors/bottomright.gif | Bin 863 -> 879 bytes rsrc/graphics.exd/mac/cursors/brush.gif | Bin 868 -> 885 bytes rsrc/graphics.exd/mac/cursors/drop.gif | Bin 880 -> 897 bytes rsrc/graphics.exd/mac/cursors/eraser.gif | Bin 859 -> 875 bytes rsrc/graphics.exd/mac/cursors/eyedropper.gif | Bin 862 -> 879 bytes rsrc/graphics.exd/mac/cursors/hand.gif | Bin 880 -> 897 bytes rsrc/graphics.exd/mac/cursors/key.gif | Bin 872 -> 888 bytes rsrc/graphics.exd/mac/cursors/look.gif | Bin 874 -> 890 bytes rsrc/graphics.exd/mac/cursors/spraycan.gif | Bin 860 -> 89 bytes rsrc/graphics.exd/mac/cursors/sword.gif | Bin 875 -> 891 bytes rsrc/graphics.exd/mac/cursors/talk.gif | Bin 872 -> 889 bytes rsrc/graphics.exd/mac/cursors/target.gif | Bin 878 -> 894 bytes rsrc/graphics.exd/mac/cursors/topleft.gif | Bin 863 -> 879 bytes rsrc/graphics.exd/mac/cursors/wait.gif | Bin 887 -> 903 bytes rsrc/graphics.exd/mac/cursors/wand.gif | Bin 873 -> 889 bytes rsrc/graphics.exd/mac/cursors/watch.gif | Bin 883 -> 899 bytes src/tools/resmgr/restypes.hpp | 67 ++++++++++-------- 27 files changed, 49 insertions(+), 28 deletions(-) create mode 100644 rsrc/graphics.exd/mac/cursors/READ_BEFORE_EDITING.txt diff --git a/rsrc/graphics.exd/mac/cursors/E.gif b/rsrc/graphics.exd/mac/cursors/E.gif index fa105e7a4b0b0dd6f5b838ce8273950f18c05a72..fbea297226b8e5cde3fa7f1de911fc7923b63e22 100644 GIT binary patch delta 42 ycmaFC_LGgr-P6s&GEsm*fZ_SSjXX@u0{?hD@=J;f@=G)fO?1pP87A{GM*{#Ld<={L delta 25 gcmey#_JWPa-P6s&GEsm*fZ;jAMjj^S$@0um0AJDudH?_b diff --git a/rsrc/graphics.exd/mac/cursors/N.gif b/rsrc/graphics.exd/mac/cursors/N.gif index ecb291c3b5e2122396229a5f8c5b642e6933c83f..fb4d5f8711caac974f6654eef240618d6f768db7 100644 GIT binary patch delta 41 xcmaFH_Kl6l-P6s&GEsm*fZ_SSjXX@u{Qr17@=J;f@=G)i3{wCA delta 25 gcmeyy_Kc0k-P6s&GEsm*fZ;jAMjj^S$#TpQ0AExFasU7T diff --git a/rsrc/graphics.exd/mac/cursors/NE.gif b/rsrc/graphics.exd/mac/cursors/NE.gif index 777cb8af7c8923edd5645c5d2fc4ee62f7f4a42f..7a18e2c2e16b714e69ecf5d05b642355d78abc95 100644 GIT binary patch delta 42 ycmaFO_J@tf-P6s&GEsm*fZ_SSjXX@u0{?hD@=J;f@=G)fjdYAP87A{G#{mE#M+}bu delta 25 gcmeyv_L_~y-P6s&GEsm*fZ;jAMjj^S$@0vx0AOVXg8%>k diff --git a/rsrc/graphics.exd/mac/cursors/NW.gif b/rsrc/graphics.exd/mac/cursors/NW.gif index 68df212c1a95631ec2b67a15cc10c152bdd7dd19..3ff0c0726a7baeb88053d6bb5b9af66e5225e43b 100644 GIT binary patch delta 41 xcmaFK_LGgr-P6s&GEsm*fZ_SSjXX@u{Qr17@=J;f@=G*~b&NF`Ci61K000xz3|0UD delta 25 gcmey#_L7aq-P6s&GEsm*fZ;jAMjj^S$#Trm0AJ?@djJ3c diff --git a/rsrc/graphics.exd/mac/cursors/READ_BEFORE_EDITING.txt b/rsrc/graphics.exd/mac/cursors/READ_BEFORE_EDITING.txt new file mode 100644 index 00000000..ebba114f --- /dev/null +++ b/rsrc/graphics.exd/mac/cursors/READ_BEFORE_EDITING.txt @@ -0,0 +1,10 @@ +When editing the GIF files in this folder, you need to be aware how the hotspot is stored. +Each of these GIF files encodes the cursor's hotspot into a GIF comment with the following +syntax (case-sensitive): + + Hotspot(x,y) + +where x and y are substituted with the actual integer coordinates. There should be no extra +spaces anywhere in that. (However, anything after the closing parenthesis will be ignored.) + +If you edit any of these images, be sure to update the hotspot if necessary! diff --git a/rsrc/graphics.exd/mac/cursors/S.gif b/rsrc/graphics.exd/mac/cursors/S.gif index 4b53949657e11577db1c171bc249c137b98e1b84..40d519565e9fd07ea31956955662e1b45d0ecadb 100644 GIT binary patch delta 42 ycmaFC_LGgr-P6s&GEsm*fZ_SSjXX@u0{?hD@=J;f@=G)nJB;@!0`OvMjj?+!GC-n`6a~#`6U{LMmmN@nhcY9nG*pT^bAY@ delta 25 gcmZo*f5*n-?&)S>nJB;@!0?=5BM%evWCi8~093374*&oF diff --git a/rsrc/graphics.exd/mac/cursors/SW.gif b/rsrc/graphics.exd/mac/cursors/SW.gif index 4647059c4cf3d304b8c6bbcb59231f7c083c7a9c..2bc054449a5758ee61bec74990c1d4d51d9d85be 100644 GIT binary patch delta 42 ycmaFI_MeT%-P6s&GEsm*fZ_SSjXX@u0{?hD@=J;f@=G*~bqtL(87A{GCjtN>KMa@v delta 25 gcmey*_KuCm-P6s&GEsm*fZ;jAMjj^S$@0tz0ATnAi~s-t diff --git a/rsrc/graphics.exd/mac/cursors/W.gif b/rsrc/graphics.exd/mac/cursors/W.gif index 68b8b0c5437b442be49bdc69d79119e01d8931ab..456d6a44897a368da0653c6974abc1cc6463d78f 100644 GIT binary patch delta 41 xcmaFH_Kl6l-P6s&GEsm*fZ_SSjXX@u{Qr17@=J;f@=G*~bj&pwCi5~!0ss>93{U_7 delta 25 gcmeyy_Kc0k-P6s&GEsm*fZ;jAMjj^S$#TpQ0AExFasU7T diff --git a/rsrc/graphics.exd/mac/cursors/boot.gif b/rsrc/graphics.exd/mac/cursors/boot.gif index 71fd13225e8e792892a5e66024b3a362b836dec5..81bc8dc3c95f64b83d1676b6647d4ea8751ecba2 100644 GIT binary patch delta 41 xcmaFK_LGgr-P6s&GEsm*fZ_SSjXX@u{Qr17@=J;f@=G*~bj&mvCi61K000x<3|IgF delta 25 gcmey#_L7aq-P6s&GEsm*fZ=)cMjj^S$#Trm0Am^k)&Kwi diff --git a/rsrc/graphics.exd/mac/cursors/bottomright.gif b/rsrc/graphics.exd/mac/cursors/bottomright.gif index 6fc74f283bcbfe847c689f8fe5df8bf9e90d99ae..1dc0c84852a5d0871a1af923e90736f0f62f7285 100644 GIT binary patch delta 41 xcmcc5_MVN$-P6s&GEsm*fZ_SSjXX@u{Qr17@=J;f@=G)t<8 diff --git a/rsrc/graphics.exd/mac/cursors/brush.gif b/rsrc/graphics.exd/mac/cursors/brush.gif index 51461c3166a4d3ed7f0a0a460c3a1d3a37adc83e..f54b218debba7b27f6141d394a132e38d468cc2c 100644 GIT binary patch delta 42 ycmaFD_LYst-P6s&GEsm*fZ_SSjXX@u0{?hD@=J;f@=G*KbqtL)87A{GhXVi~91MK` delta 25 gcmey$_Jobc-P6s&GEsm*fZ=)cMjj^S$@0u$0AfJ~$p8QV diff --git a/rsrc/graphics.exd/mac/cursors/drop.gif b/rsrc/graphics.exd/mac/cursors/drop.gif index da032da11f9357f6ab1a6a2d167142d8f50c4490..9fe48830a21aaecb7bd02f7ac2e13d9a5e8cc5f6 100644 GIT binary patch delta 42 xcmeys*2vD|?&)S>nJB;@!0`OvMjj?+fq%Rn`6a~#`6U{LCOQV143l}8lK~G33?2Xg delta 25 gcmZo<|G>uM?&)S>nJB;@!0c2@Gfe delta 25 gcmaFQc8`t6-P6s&GEsm*fZ=)cMjj^S$@0tr0AU*jw*UYD diff --git a/rsrc/graphics.exd/mac/cursors/hand.gif b/rsrc/graphics.exd/mac/cursors/hand.gif index da032da11f9357f6ab1a6a2d167142d8f50c4490..9fe48830a21aaecb7bd02f7ac2e13d9a5e8cc5f6 100644 GIT binary patch delta 42 xcmeys*2vD|?&)S>nJB;@!0`OvMjj?+fq%Rn`6a~#`6U{LCOQV143l}8lK~G33?2Xg delta 25 gcmZo<|G>uM?&)S>nJB;@!0@~ literal 860 zcmV-i1Ec&$Nk%w1VGsZi0Owl(000010RaL60s{jB1Ox;H1qB8M1_uWR2nYxX2?+`c z3JVJh3=9kn4Gj(s4i66x5D*X%5fKs+5)%^>6ciK{6%`g178e&67#J8C85tTH8XFrM z92^`S9UUGX9v>ecARr(iAt53nA|oRsBqSsyB_$>%CMPE+C@3f?DJd!{Dl021EG#T7 zEiEoCE-x=HFfcGNF)=bSGBYzXG&D3dH8nOiHa9mnI5;>tIXOByIy*Z%JUl!-Jv}}? zK0iM{KtMo2K|w-7LPJACL_|bIMMXwNMn^|SNJvOYNl8jdN=r*iOiWBoO-)WtPESuy zP*6}&QBhJ-Qd3h?R8&+|RaI72R##V7SXfwDSy@_IT3cINTwGjTU0q&YUSD5dU|?Wj zVPRroVq;@tWMpJzWo2e&W@l$-XlQ6@X=!R|YHMq2Y;0_8ZEbFDZf|dIaBy&OadC2T za&vQYbaZreb#-=jc6WDoczAeud3kzzdV70&e0+R;eSLm@et&;|fPjF3fq{a8f`fyD zgoK2Jg@uNOhKGlTh=_=ZiHVAeii?YjjEszpjg5|uj*pLzkdTm(k&%*;l9Q8@l$4Z} zm6ev3mY0{8n3$NEnVFiJnwy)OoSdAUot>VZo}ZteprD|kp`oIpqNAguq@<*!rKP5( zrl+T;sHmu^si~@}s;jH3tgNi9t*x%EuCK4Ju&}VPv9YqUva_?Zw6wIfwY9dkwzs#p zxVX5vxw*Q!y1To(yu7@dCU$jHda z$;ryf%FD~k%*@Qq&CSlv&d<-!(9qD)(b3Y<($mw^)YR0~)z#M4*4Nk9*x1lt)=I7_<=;-L_>FMg~>g((4 z?Ck9A?d|UF?(gsK@bK{Q@$vHV^7Hfa^z`)g_4W4l_V@Sq`1ttw`T6?#`uqF){QUg= z{r&#_{{R2~A^8LW3IP8AEC2ui01yBW000O%0RIUb_zwWVg9r&4Jh*UR!-N7KLWJ1R mphSrYFGieLFe5{U2p3}9ND(ASlN>d6t<8 diff --git a/rsrc/graphics.exd/mac/cursors/wait.gif b/rsrc/graphics.exd/mac/cursors/wait.gif index 92ca31e17f854e26e88621e1aa3edc2b41503c1f..56febfaa18f3a5e9747d7e6d7844536c785530fe 100644 GIT binary patch delta 41 wcmey)*3Qo3?&)S>nJB;@!0`OvMjj?+{(n3k`6a~#`6U__Iu@D?lX;o500lS<3jhEB delta 25 gcmZo?|IWta?&)S>nJB;@!0nJB;@!0`OvMjj?+{(n3k`6a~#`6U__Iu@D?lX;ob00Z<3{{R30 delta 25 gcmZo>|IEhY?&)S>nJB;@!0`P4Mjj^S$#Tr80A64R82|tP diff --git a/src/tools/resmgr/restypes.hpp b/src/tools/resmgr/restypes.hpp index 6940cc2c..8ad44349 100644 --- a/src/tools/resmgr/restypes.hpp +++ b/src/tools/resmgr/restypes.hpp @@ -42,43 +42,54 @@ namespace ResMgr { } /// Load a cursor from a GIF file. - /// The cursor's hotspot location is stored in a .hot file, as plaintext: - /// simply the X value followed by the Y value, separated by whitespace. + /// The cursor's hotspot location is stored in a GIF comment, with the following syntax (case-sensitive): + /// "Hotspot(x,y)" template<> inline CursorRsrc* resLoader::operator() (std::string fname) { - // TODO: Store the hotspots on disk instead of hardcoded here - static const std::map cursor_hs = { - {"wand", {4, 1}}, {"eyedropper", {1, 14}}, {"brush", {5, 13}}, {"spraycan", {8, 8}}, - {"eraser", {8, 8}}, {"topleft", {8, 8}}, {"bottomright", {8, 8}}, {"hand", {14, 0}}, - {"NW", {3, 3}}, {"N", {9, 3}}, {"NE", {12, 3}}, - {"W", {2, 7}}, {"wait", {8, 8}}, {"E", {14, 7}}, - {"SW", {3, 12}}, {"S", {9, 12}}, {"SE", {12, 12}}, - {"sword", {1, 1}}, {"boot", {2, 6}}, {"drop", {14, 0}}, {"target", {8, 8}}, - {"talk", {2, 13}}, {"key", {3, 2}}, {"look", {7, 6}}, {"watch", {8,8}}, - }; fs::path fpath = resPool::rel2abs(fname + ".gif"); - fs::path hotpath = resPool::rel2abs(fname + ".hot"); - int x = 0, y = 0; - if(fs::exists(hotpath)) { - std::ifstream fin(hotpath.c_str()); - fin >> x >> y; - fin.close(); - } else { - auto entry = cursor_hs.find(fname); - if(entry == cursor_hs.end()) - std::cerr << "Cursor hotspot missing: " << fname << std::endl; - else { - std::cerr << "Cursor hotspot missing (using fallback value): " << fname << std::endl; - location hs = entry->second; - x = hs.x; y = hs.y; + if(!fs::exists(fpath)) + throw xResMgrErr("Failed to load GIF cursor: " + fname); + int x = 0, y = 0, f_sz; + std::ifstream fin(fpath.c_str(), std::ios::binary); + fin.seekg(0, std::ios::end); + f_sz = fin.tellg(); + fin.clear(); + fin.seekg(0, std::ios::beg); + bool found_hotspot = false; + while(fin && !found_hotspot) { + unsigned char c = fin.get(); + if(c != 0x21) continue; + c = fin.get(); + if(c != 0xfe) continue; + // If we get here, we've probably found a GIF comment + std::string str; + int count; + found_hotspot = true; + do { + count = fin.get(); + if(count + fin.tellg() >= f_sz) { + found_hotspot = false; + break; + } + std::copy_n(std::istream_iterator(fin), count, std::back_inserter(str)); + } while(count > 0); + if(found_hotspot) { + if(str.substr(0,7) == "Hotspot") { + size_t open_paren = str.find_first_of('('), comma = str.find_first_of(','), close_paren = str.find_first_of(')'); + std::string x_str = str.substr(open_paren + 1, comma - open_paren - 1); + std::string y_str = str.substr(comma + 1, close_paren - comma - 1); + x = std::stoi(x_str); + y = std::stoi(y_str); + } else found_hotspot = false; } } + if(!found_hotspot) + std::cerr << "Cursor hotspot missing: " << fname << std::endl; // TODO: Handle errors? CursorRsrc* cur = new Cursor(fpath.string(),x,y); return cur; - throw xResMgrErr("Failed to load GIF cursor: " + fname); } - /// Load a font form a TTF file. + /// Load a font from a TTF file. template<> inline FontRsrc* resLoader::operator() (std::string fname) { fs::path fpath = resPool::rel2abs(fname + ".ttf"); FontRsrc* theFont = new FontRsrc;