tag:blogger.com,1999:blog-91951280915074877302024-03-19T00:24:33.802-07:00Auto GeneratedDisassociated ramblings on code and whatever else crosses my mind.Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.comBlogger30125tag:blogger.com,1999:blog-9195128091507487730.post-62587638696629309002021-06-12T14:54:00.002-07:002021-06-12T14:54:23.608-07:00Controlling a Second Avatar with the Unity AR Foundation Controlled Robot<p>
Body Tracking with ARKit works very well as does the Unity integration into AR Foundation. However, the rig that <a href="https://developer.apple.com/documentation/arkit/content_anchors/rigging_a_model_for_motion_capture">Apple provides</a>, as well as the version Unity includes in their <a href="https://github.com/Unity-Technologies/arfoundation-samples">sample project</a> have some complexities that have made working with them challenging.
</p>
<p>
While initially I had thought to replace the sample controlled robot model I found it difficult. My solution was to keep the controlled robot and pair its movements to a second avatar and, if desired, overlay the positions and hide the controlled robot. The ARKit rig is not like other rigs (7 spine bones, 4 neck bones, different orientations, etc.) in common usage. The Unity version has no avatar associated with it so you are unable to access some of the built in HumanBones and retarteging functionality normally available. Attempts to rig my own version failed for various reasons.
</p>
<p>Here I'm connecting the armature from the recently updated <a href="https://assetstore.unity.com/packages/essentials/starter-assets-third-person-character-controller-196526">3rd Person Unity Starter Assets</a> to the AR Foundation samples ControlledRobot asset.
</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrb79i8adcyoouCr02zC0tyA_aGNimty7k9e5qgZNWnX99jUNav4SmSwG1h5zCJy8Lt9POexfP0d_qHV3zHxtCHtUOsixyQHlQM99T7UmtBn5t5bcimx9upORNRUoDgSorOMafFlwg9DLx/s1245/Screenshot+2021-06-11+231550.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="961" data-original-width="1245" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrb79i8adcyoouCr02zC0tyA_aGNimty7k9e5qgZNWnX99jUNav4SmSwG1h5zCJy8Lt9POexfP0d_qHV3zHxtCHtUOsixyQHlQM99T7UmtBn5t5bcimx9upORNRUoDgSorOMafFlwg9DLx/s320/Screenshot+2021-06-11+231550.png"/></a></div>
<p>
The primary requirement is to map the avatar bones to the controlled robot bones and the code synchronizes the respective joint rotations. I'm sure there are more elegant solutions, but I thought I would post <a href="https://github.com/genereddick/BodyTracking">my version</a> on GitHub in case it helps anyone else attempting this. Feel free to make suggestions or point towards better solutions that may be out there.
</p>
<div>
<span>Another avatar:</span>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVq78I-7UmnLIB_OIlup4aQd3Ec63QnnU29UE4CgXICzqWr_CEXsTGfbv9lVinJtvLT_nfw06c3JxPqnK_xyQOKxzcJNJ2lTx-XwRI5uhKXfw6Iye9K3BdKDzTNFrz0jt2hvnqGbbJi13b/s1173/robot1.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="994" data-original-width="1173" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVq78I-7UmnLIB_OIlup4aQd3Ec63QnnU29UE4CgXICzqWr_CEXsTGfbv9lVinJtvLT_nfw06c3JxPqnK_xyQOKxzcJNJ2lTx-XwRI5uhKXfw6Iye9K3BdKDzTNFrz0jt2hvnqGbbJi13b/s320/robot1.png"/></a></div>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZiK6YSqlQm0KOg0SX7YPmersTty06qMq_ApsSagkZwWnnG2BEOKcJ9r6UmhNwXlt02C8aYCPUVdfGh-a2kuDyzPF_Y2TsQ2R1Oc0t1LXDRl3s5tkGUB42B6V1A1pTUjg3ZBj1-UJeaj97/s1324/robot2.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="981" data-original-width="1324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZiK6YSqlQm0KOg0SX7YPmersTty06qMq_ApsSagkZwWnnG2BEOKcJ9r6UmhNwXlt02C8aYCPUVdfGh-a2kuDyzPF_Y2TsQ2R1Oc0t1LXDRl3s5tkGUB42B6V1A1pTUjg3ZBj1-UJeaj97/s320/robot2.png"/></a></div>
</div>
<p>There are still issues with initial positions and offsets especially when live on an iOS device, and models lose tracking and experience jitter every now and than, so still a work in process.</p>
<dl>
<dt>Apple documentation:</dt>
<dd><a href="https://developer.apple.com/documentation/arkit/content_anchors/rigging_a_model_for_motion_capture">https://developer.apple.com/documentation/arkit/content_anchors/rigging_a_model_for_motion_capture</a></dd>
<dt>AR Foundation Sample Project:</dt>
<dd><a href="https://github.com/Unity-Technologies/arfoundation-samples">https://github.com/Unity-Technologies/arfoundation-samples</a></dd>
<dt>My GitHub Repo:</dt>
<dd><a href="https://github.com/genereddick/ARBodyTrackingAndPuppeteering">https://github.com/genereddick/ARBodyTrackingAndPuppeteering</a></dd>
</dl>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com2tag:blogger.com,1999:blog-9195128091507487730.post-76686255169498884692018-06-20T21:02:00.001-07:002018-06-20T21:02:55.792-07:00Unity Standard Assets Water and HoloLensTurns out the Unity water prefab from Standard Assets hololdoesn't work with Single Pass Instanced on HoloLens — unless I close one eye. It works with Multi Pass, but still doesn't appear in a photo.<br />
<br />
Just so I remember next time...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/9jWGbvemTag/0.jpg" src="https://www.youtube.com/embed/9jWGbvemTag?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com12tag:blogger.com,1999:blog-9195128091507487730.post-27846262590145447312017-02-27T13:17:00.000-08:002017-02-27T13:17:21.714-08:00Building Star Wars Armada for HoloLensAs I continue to learn <a href="https://unity3d.com/" target="_blank">Unity</a>, <a href="https://www.microsoft.com/microsoft-hololens/en-us" target="_blank">HoloLens</a>, I wanted to take on something more complex. <a href="https://www.fantasyflightgames.com/en/products/star-wars-armada/" target="_blank">Fantasy Flight Game's Star Wars Armada</a> seemed a suitable challenge.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/zSnZZLGKE1M/0.jpg" src="https://www.youtube.com/embed/zSnZZLGKE1M?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
Armada is a table top game using miniatures to simulate combat between Star Wars capital ships and squadrons. And, it turns out to translate really well to HoloLens. This post is mostly a series of notes related to what I tried and what I learned along the way.<br />
<br />
I started off using using primitives for the ships, cubes and spheres. While this was workable and I could have built the entire game this way it was uninspiring. So I created 3D models using a <a href="https://matterandform.net/scanner" target="_blank">Matter and Form</a> scanner and the actual Armada miniatures. While, I was eventually able to get to reasonable quality scans, the process of converting those scans into clean, low-poly models that could be used in Unity required more time than I wanted to commit. So I switched to using various open source models and edited them in <a href="https://www.blender.org/" target="_blank">Blender</a> (which was it's own learning adventure).<br />
<br />
While Armada is played on a table, taking the game into 3D seemed obvious though it required changes to the rules that impacted game balance. These include the number of shields a ship has, the number of batteries that can fire, possible targeting surfaces and moving damage from one shield to another. I'm not sure what I did would work if this was a production game but, it was fun to try to put myself in the game designer's shoes for a bit.<br />
<br />
The Armada miniature scale turned out to be too small for comfortable gaze targeting. I experimented with various sizes and ended up at 2X the physical model scale. This resulted in a play area that was a 2 meter cube or a 2x2x3 meter rectangle which is what is shown in the videos.<br />
<br />
I tried and implemented many different user interface versions as I went, and while many of these remain in the project — some are decent others not so much, by the end I kept coming back to voice. I tried to always have a gaze or gesture option available as well, but voice almost always ended up being simpler and more flexible.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/I1a2sXjYG2g/0.jpg" src="https://www.youtube.com/embed/I1a2sXjYG2g?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/XWaBWBvR7mQ/0.jpg" src="https://www.youtube.com/embed/XWaBWBvR7mQ?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
<br />
Squadron movement ended up being quite difficult and was re-implemented a half-dozen times. Precise movement of objects in 3D and placing them are in relation to other objects required, in many cases, for physically moving around them to check perspective. I'm still not happy with the result.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Ni3pxKUMjvI/0.jpg" src="https://www.youtube.com/embed/Ni3pxKUMjvI?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />
Overall, I probably implemented 75% of the rule set. I did everything from ship selection, tracking points, the movement tool, actual movement, combat, and victory scoring.<br />
<br />
Some game features — command dials and targeting adjustments, which are core to the game, I automated with an algorithm making the decisions. Others, such as upgrade cards and obstacles, I didn't even attempt. I also started work on sharing so you could play the game with multiple headsets, but didn't manage to get it working using an emulator and a single HoloLens. <br />
<br />
And, importantly, the game is actually pretty fun to play as is. Next up (maybe), D&D mass combat with holographic miniatures.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe width="320" height="266" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/yC_wKW_1LuE/0.jpg" src="https://www.youtube.com/embed/yC_wKW_1LuE?feature=player_embedded" frameborder="0" allowfullscreen></iframe></div>
<br />
<br />Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com4tag:blogger.com,1999:blog-9195128091507487730.post-77452681271574628332016-11-07T16:47:00.003-08:002016-11-10T14:54:58.121-08:00Creating a holographic map of Barovia<strong>TL;DR</strong> Download Unity and create a project. Add a terrain game object. Size it to match the map proportions. Add the map as a texture. Use the fixed height terrain tools to paint the appropriate parts of the map to the right elevations. All done.
<br />
<br />
<b>First Version</b><br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/VX9TEADmVQ0/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/VX9TEADmVQ0?feature=player_embedded" width="320"></iframe><br />
<b><br /></b>
<b><br /></b>
<b>With Fog, Sound Effects, et.al.</b><br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/ePJWUP6aI1Y/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/ePJWUP6aI1Y?feature=player_embedded" width="320"></iframe><br />
<b><br /></b>
<b><br /></b>
<b><br /></b>
I have been a big fan of <a href="http://www.mikeschley.com/">Mike Schley's</a> <a href="http://dnd.wizards.com/">Dungeons & Dragons</a> maps for a while. Their high resolution and detail make them great for working with on <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and.html">alternate platforms</a>. Recently, I decided to try and convert some of his maps of <a href="http://mikeschley.com/the-land-of-barovia">Barovia</a> from <a href="http://dnd.wizards.com/products/tabletop-games/rpg-products/curse-strahd">Curse of Strahd</a> to display on <a href="https://www.microsoft.com/microsoft-hololens/">HoloLens</a>.<br />
<br />
Well... and this is going to be a short post... it turns out to be really easy and not necessarily deserving of too much detail, but I'll pad it a bit to make it look a bit more impressive.<br />
<br />
First off, I used <a href="https://unity3d.com/">Unity</a>, which you can get for free. There are technical preview builds for AR/VR platforms — I used <a href="https://unity3d.com/partners/microsoft/hololens">this one</a> for HoloLens. In my case, as I'm building for HoloLens you need that though you could also use the HoloLens emulator. If you wanted you could also build for another platform — this process should work equally well for Occulus, Cardboard, etc., or even just for display within Unity or even output for PC, just wouldn't be a holographic virtual 3D map.<br />
<br />
First I trimmed the edges of the Barovia map — not technically necessary but helps to reduce file and image sizes a bit. This left me with a map size of 7050 x 4400 pixels representing ~90K x ~56K feet or 27,538 meters by 17,187 meters.<br />
<br />
The map of Barovia has contour lines which will be used for elevation. The contour lines are 1000 feet each or 10K feet from lowest to highest elevation.<br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV4fhH4cguTvOmVa1Eqnr4t7laRRT_beW67PWj6sqHN0hEAVcV6QV9ahG2qd16SYMXh3n6k5iV5hFzhRTN-OoYHy1sJuFh8i09H1NTzEn8mTjcp6U1pgQVGMqaVIjQVfKsYrVez_x6ouXx/s1600/barovia+map+detail+1.png" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="244" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhV4fhH4cguTvOmVa1Eqnr4t7laRRT_beW67PWj6sqHN0hEAVcV6QV9ahG2qd16SYMXh3n6k5iV5hFzhRTN-OoYHy1sJuFh8i09H1NTzEn8mTjcp6U1pgQVGMqaVIjQVfKsYrVez_x6ouXx/s320/barovia+map+detail+1.png" width="320" /></a><br />
<br />
The next step was a bit of math to determine the display size. Unity uses arbitrary units and HoloLens works on a scale of 1 Unity unit = 1 meter. I wanted the map to be big, so to fit (barely) my living room, I chose a scale factor of 2000 which ends up with a map size of 3.525 x 2.2 which is both the Unity map size and the size, in meters, of the resulting hologram.<br />
<br />
Within Unity I created a 3D terrain. Select the terrain object, and go to settings. Set the length and width to 2.2 and 3.525 (the z and x axis). For the height, if using the same scale as the length and width, it would end up being around 0.05. However, when I tested this it was less dramatic than I would like. After experimenting with various options I settled on a 4x vertical scale on the y axis relative to the x and z, which ended up at 0.2 height. With my vertical scale set, each increase in a contour line — 1000 feet in the map — is an elevation increase of 0.02 in Unity.<br />
<br />
The Unity terrain tools are not well loved, and many people use third party tools, but the built in tools are free and you can get what you need done, if a bit slowly. With the terrain selected choose the Paint Texture tool and then Edit Textures. Add the map (the map of Barovia that is) and set it to the same size as the terrain itself (2.2 by 3.525).<br />
<br />
Next select the fixed height terrain tool. Using the hard edge brush with a 100 opacity and then a height equal to the elevation (in contour lines) you are painting x 0.02. I tend to vary the size of the brush as I go. Then I painted the map, raising each contour section of the map's elevation. When roughly done there was a fair amount of touch up but as the contour lines themselves stretch between the lower and higher elevations they handle distortion well. Below are examples from a call out map of Yester Hill.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx737pTnmAzzFUSGuh3cezQY1MvU1m4Bz2u67ka_kG_Mt7rdg-OkxAjKia-wpzZD8NgQiW5-TRebr5QQ_ACwlVWj9LSz3jwyyBSlM2fFFaYzjSQS4o3iMH3zeUK66w2XWewod0GG2ZJ4nU/s1600/barovia-yester-hill-1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjx737pTnmAzzFUSGuh3cezQY1MvU1m4Bz2u67ka_kG_Mt7rdg-OkxAjKia-wpzZD8NgQiW5-TRebr5QQ_ACwlVWj9LSz3jwyyBSlM2fFFaYzjSQS4o3iMH3zeUK66w2XWewod0GG2ZJ4nU/s320/barovia-yester-hill-1.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivpMGUx5zKTTYVdBy0MP96SgbBUVn5MFA8VGB7KMOKQKMsMjpLiKaJ1MBCyzlLuHXuriLYVfaf7Srlk0qYeEzt8ZQm6EVzkhzvGDHq5zOSqRqaeQFoHOzAezsdKUDE9ceCdfd1nhag8TYH/s1600/barovia-yester-hill-2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivpMGUx5zKTTYVdBy0MP96SgbBUVn5MFA8VGB7KMOKQKMsMjpLiKaJ1MBCyzlLuHXuriLYVfaf7Srlk0qYeEzt8ZQm6EVzkhzvGDHq5zOSqRqaeQFoHOzAezsdKUDE9ceCdfd1nhag8TYH/s320/barovia-yester-hill-2.PNG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjyV3qaaIUEiEwuF9A8Bq5rwkt7JEgtvZSBte3aI-aFlZLt7k94ELvKj3GYfaomYZju9tyFsnLl3jtansVajrP-lDFLgw-a-q8Sqps4v_qrUbIsoZtnH_IZuBBoD1tXT0s-XegdxQUJ1we/s1600/barovia-yester-hill-3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="195" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjyV3qaaIUEiEwuF9A8Bq5rwkt7JEgtvZSBte3aI-aFlZLt7k94ELvKj3GYfaomYZju9tyFsnLl3jtansVajrP-lDFLgw-a-q8Sqps4v_qrUbIsoZtnH_IZuBBoD1tXT0s-XegdxQUJ1we/s320/barovia-yester-hill-3.PNG" width="320" /></a></div>
<br />
I also looked at smoothing the terrain between elevations, but this quickly started to look like a couple orders of magnitude more work and a lot more artistic judgement than I had time for. Once that was done, I set various HoloLens specific settings, built and deployed to HoloLens. As HoloLens has built in video capture I could create video of the result and save it. And that was version one.<br />
<br />
For additional versions I made it darker with moon and moonlight, added spatial sound effects — sound that emanates from a specific location and varies by direction and distance, fog clouds from the Unity standard assets, as well as lightning, and more.<br />
<br />
I also added gaze events to open additional maps such as this one of Tsolenka Pass. This map was generated at mini / battle map scale to 5 map feet = 1 physical inch. The map has 1000 feet of elevation which results in a holographic object that is 16.67 feet tall.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Jn37oPQjXqw/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/Jn37oPQjXqw?feature=player_embedded" width="320"></iframe></div>
<br />Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com23tag:blogger.com,1999:blog-9195128091507487730.post-46161746134433280722016-09-11T20:13:00.003-07:002016-09-11T20:52:23.811-07:00A holographic pit trapAs one of my first projects for <a href="https://www.microsoft.com/microsoft-hololens/en-us">HoloLens</a> I decided to build a <a href="https://plus.google.com/+GeneReddick/posts/Nrt2Fj8Mxwk">pit trap</a> (in case the video below isn't loading).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzImXEEI3820AqBs4R3YU-p9_x_U6bbIC9sFPWnGb4vkG0AoaGisQec1gKG5wja9YBZqXIeyk2sE3skYU6YNA' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br />
I went through various versions of this. <a href="https://plus.google.com/+GeneReddick/posts/Nrt2Fj8Mxwk">Here </a>is an earlier attempt.<br />
<br />
First, I picked up some <a href="https://www.assetstore.unity3d.com/en/#!/content/50655">traps</a> assets from the Unity asset store. Then started messing around with a bunch of options. With Unity I spent a lot of time getting the center of the object positioned at the top of the pit so I could place the pit on the floor, and then sizing the various assets.<br />
<br />
Once I added a trap door, I spent way too long adding a workable gravity hinge and a motor to close the lid based on your proximity to the pit and then starting and stopping the spike animation at the same time.<br />
I spent even more time with this not working before I sorted out that I needed a collider on the pit GameObject before I could use the TapToPlace script to move it, and then get my collider to not block the pit door from opening, and making sure the collider wasn't hidden behind the spatial map once I placed it, and on and on.<br />
<br />
By far the biggest challenge for this was working with spatial mapping and placement. I'll have a lot more to say about this later. Initially, I tried to remove the spatial map vertices where they intersected the pit and have the spatial map do the occlusion — to give the illusion that the pit trap was actually in the floor. Though I think I now understand why it didn't work, I wasn't able to sort this out at the time. So, instead I added quads with an Occlusion surface material along the lines of the <a href="https://developer.microsoft.com/en-us/windows/holographic/holograms_230">HoloLens Academy 230 </a>project.<br />
<br />
Finally, I used the web cam to take a picture of the floor near the pit trap and then mapped that to the surface of the door to make it blend in.Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com3tag:blogger.com,1999:blog-9195128091507487730.post-56039687598681640262016-09-11T20:13:00.001-07:002016-09-11T20:13:52.145-07:00As if my reality wasn't mixed up enough already<p>When <a href="https://www.google.com/glass/start/">Google Glass</a> first launched, I was excited. Despite the unfortunate (and, I think, unfair) stigma that became attached to Glass it felt like a first step to long awaited augmented and mixed reality devices. So I built a Glass app for <a href="http://www.kitchme.com">KitchMe</a>. And, being one of the first to launch, got my company some nice, pre-glasshole press. I spoke to <a href="https://www.youtube.com/watch?v=thejYAGsHB8">Robert Scoble</a> about it. Helped cook something for the <a href="http://www.wsj.com/video/cook-a-greek-dinner-with-google-glass/4C2E6C72-8E12-4D9E-A97F-DB269EF43567.html">WSJ</a>. And then it was dead. And I was sad.</p>
<p>Then, suddenly we have a sudden explosion of VR / AR / Mixed Reality devices to play with. I picked up a copy of the <a href="https://www.oculus.com/">Occulus Rift</a> dev kit and played around with that. Tried out <a href="https://vr.google.com/cardboard/">Google Cardboard</a> and project <a href="https://get.google.com/tango/">Tango</a>. Read whatever I could find on <a href="https://www.magicleap.com/#/home">Magic Leap</a>.</p>
<p>And now I'm monkeying around with <a href="https://www.microsoft.com/microsoft-hololens/en-us">HoloLens</a> and I love it. It is what I had thought Glass would be, or might become. I have no opinion, as of yet, as to which devices, platforms, or paradigms will win... or if any of this first generation will. But I'm happy to get started with whatever is available.</p>
<p>To start, I went through the various <a href="https://developer.microsoft.com/en-us/windows/holographic/academy">Holographic Academy</a> projects, downloaded the technical preview of <a href="https://unity3d.com/partners/windows/hololens">Unity</a> for HoloLens. Went through a bunch of free tutorials as well as some paid one's like this <a href="https://www.udemy.com/vrcourse/">Make VR Games in Unity with C# - Cardboard, Gear VR, Oculus</a>. </p>
<p>While not strictly necessary, I also downloaded and learned a bit about <a href="https://www.blender.org/download/">Blender</a>. Picked up a <a href="https://matterandform.net/scanner">Matter and Form 3d Scanner</a> and learned how to make some, barely, competent scans.</p>
<p>For me, this was almost all entirely new. Which is to say it has been a lot of fun learning a whole range of new apps and skills. To go along with all of this I was listening to <a href="http://podcastnotes.org/2016/06/08/tim-ferriss-kevin-kelly-ai-virtual-reality-and-the-inevitable/">Tim Ferris interviewing Kevin Kelly</a> and this comment struck me:</p>
<blockquote>Right now there are no experts in VR, we have no idea how it will work – what content, equipment, consumer breakthrough, etc. So anyone has the chance NOW to become that future expert</blockquote>
<p>He discusses how to go about this: get the tools and start monkeying around (paraphrasing). Which is what I am doing, so, uh, confirmation bias I guess.</p>
<p>Anyway, I thought I would go ahead and lightly blog my various comical attempts at building various mixed reality projects! Hopefully, leading to a little self improvement if nothing else. Fun for me, if not for thee.</p>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com3tag:blogger.com,1999:blog-9195128091507487730.post-56636293058578731162015-12-14T12:43:00.001-08:002017-09-08T12:20:41.081-07:00Nerdy Mapping Fun with Faerun and Google Earth, Part IV, KML FilesIn <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and.html">Part I</a>, I discussed the process of getting this awesome and massively detailed map of <a href="http://mikeschley.zenfolio.com/p858006957/h5ea715c3#h5ea715c3">Northern Faerun</a> by <a href="http://www.mikeschley.com/">Mike Schley</a>, onto Google Earth.
<br />
Going a little further than in previous posts, I wanted to see if I could display different maps at different zooms. For this I needed to create a KML file. This is actually easy to do manually, just create an xml file with a KML extension. You can get a lot of information on what is possible from <a href="https://developers.google.com/maps/support/kmlmaps?hl=en">KML files on Google Maps</a>. Also, KML files use decimal degrees so I had to use the translated coordinates from previous posts.
<br />
<br />
I created two KML files. You can probably do it in one, but I had some issues with properly nesting the xml, so I separated them. <br />
<br />
The first file just positions the same four maps (though I'm using versions I created without text overlays) I used in my other posts. Getting the "href" path in the xml right on a Windows machine took a while to sort out, but otherwise this was fairly straightforward.<br />
<br />
Then I created a second KML to bring in a detailed view of the Dessarin Valley and set the zoom level so it would only show up when you were in close. For this, I used another one of <a href="http://mikeschley.zenfolio.com/p530730153/h268fd5c4#h13196d69">Mike Schley's maps</a>. It took some work to get the edges more or less lined up and the scale to match, and I could delete the borders, to clean it up a bit more, but in this case I was just testing out creating KML files so I wasn't overthinking it. Clearly, it would also be easier with maps designed for this purpose (Mike!?)<br />
Here is the view zoomed out:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcAzLC8wZkrE2A_NA9yxi6DgWcekLAEwSCLzh28_twt_1h3w3d__9kbNweaJJSnCJ7_omy5LrswNOs0rWGmJcB9w_hV2Yt4vinqXRM-pRlCxJlNyoHXN_nRoD4UdFt0hlhPRPzyT102eG5/s1600/faerun+on+earth+-+dessarin+valley+3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcAzLC8wZkrE2A_NA9yxi6DgWcekLAEwSCLzh28_twt_1h3w3d__9kbNweaJJSnCJ7_omy5LrswNOs0rWGmJcB9w_hV2Yt4vinqXRM-pRlCxJlNyoHXN_nRoD4UdFt0hlhPRPzyT102eG5/s400/faerun+on+earth+-+dessarin+valley+3.png" /></a></div>
And zoomed in just a little:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEief_7G_bhhOP0pdycPGY2NzCX0CrGOZpxl2jyKe-ThMG898F1EFuu4MDO3M5CkiFW-9k5Adf97178OpG7qu3q70j25S8Y8ZqgzY6BcSRS8m8oRTAiRfGzNuWqCEsqLqAGUeCv4FGjik05n/s1600/faerun+on+earth+-+dessarin+valley+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEief_7G_bhhOP0pdycPGY2NzCX0CrGOZpxl2jyKe-ThMG898F1EFuu4MDO3M5CkiFW-9k5Adf97178OpG7qu3q70j25S8Y8ZqgzY6BcSRS8m8oRTAiRfGzNuWqCEsqLqAGUeCv4FGjik05n/s400/faerun+on+earth+-+dessarin+valley+2.png" /></a></div>
I also added a placemark for Neverwinter, just to experiment with adding individual elements on the page. You can of course swap out the icons, position the text more elegantly but this was enough for a test.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_3fgavp4m7FM9XwDmRN_9XWmsN28hCSG9eA7jUxIPIWVSTVtK5YLCx2rCxp709O95M6WEOhaQp4hQGtu5-PYT6E2GTOSrTgrG2axNB16BdhgzAa3FOK_qFrhmGVovpqAmHWop_60N5JFu/s1600/faerun+on+earth+-+dessarin+valley+4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_3fgavp4m7FM9XwDmRN_9XWmsN28hCSG9eA7jUxIPIWVSTVtK5YLCx2rCxp709O95M6WEOhaQp4hQGtu5-PYT6E2GTOSrTgrG2axNB16BdhgzAa3FOK_qFrhmGVovpqAmHWop_60N5JFu/s400/faerun+on+earth+-+dessarin+valley+4.png" /></a></div>
Here is the first KML file.<br />
<code>
</code>
<pre><code><kml xmlns="http://www.opengis.net/kml/2.2">
<folder>
<name>Northwest Faerun</name>
<description></description>
<groundoverlay>
<name>Faerun SW Corner</name>
<description></description>
<icon>
<href>D:\[filepath]\nw-faerun-sw.jpg</href>
</icon>
<latlonbox>
<north>41.250</north>
<south>26.0000</south>
<east>-118.475</east>
<west>-150.000</west>
<rotation>0</rotation>
</latlonbox>
</groundoverlay>
<groundoverlay>
<name>Faerun SE Corner</name>
<description></description>
<icon>
<href>D:\[filepath]\nw-faerun-se.jpg</href>
</icon>
<latlonbox>
<north>41.250</north>
<south>26.0000</south>
<east>-89.950</east>
<west>-118.475</west>
<rotation>0</rotation>
</latlonbox>
</groundoverlay>
<groundoverlay>
<name>Faerun NE Corner</name>
<description></description>
<icon>
<href>D:\[filepath]\nw-faerun-ne.jpg</href>
</icon>
<latlonbox>
<north>56.500</north>
<south>41.250</south>
<east>-89.950</east>
<west>-118.475</west>
<rotation>0</rotation>
</latlonbox>
</groundoverlay>
<groundoverlay>
<name>Faerun NW Corner</name>
<description></description>
<icon>
<href>D:\[filepath]\nw-faerun-nw.jpg</href>
</icon>
<latlonbox>
<north>56.500</north>
<south>41.250</south>
<east>-150.000</east>
<west>-118.475</west>
<rotation>0</rotation>
</latlonbox>
</groundoverlay>
<placemark>
<name>Neverwinter</name>
<description>A city.</description>
<point>
<coordinates>-124.92085,50.227359,0</coordinates>
</point>
</placemark>
</folder>
</kml>
</code></pre>
<code>
</code>
<br />
And here is the Dessarin Valley KML file.<br />
<code>
</code>
<pre><code><kml xmlns="http://www.opengis.net/kml/2.2">
<folder>
<name>Dessarin Valley</name>
<description></description>
<groundoverlay>
<name>Dessarin Valley</name>
<description></description>
<icon>
<href>D:\[FilePath]\dessarin-valley.jpg</href>
</icon>
<region>
<latlonbox>
<north>50.400</north>
<south>45.8</south>
<east>-117.640</east>
<west>-122.150</west>
<rotation>0</rotation>
</latlonbox>
<lod>
<minlodpixels>65000</minlodpixels>
<maxlodpixels>-1</maxlodpixels>
</lod>
</region>
<latlonbox>
<north>50.400</north>
<south>45.8</south>
<east>-117.640</east>
<west>-122.150</west>
<rotation>0</rotation>
</latlonbox>
</groundoverlay>
</folder>
</kml>
</code></pre>
<code>
</code>
<br />
Getting this into Google Earth is now just a matter of File | Open and select each KML file. KML files can be used in other mapping software as well.<br />
<h5>
Nerdy Mapping Fun</h5>
<ol>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part I</a> I overlay a map of Faerun on Google Earth.</li>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part II, Stitching it Together</a> I repeat this process with the 34 part PDF map.</li>
<li><a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_29.html">Part III, Higher Resolution</a> and now moving it around.</li>
<li>In <a href="http://www.autogenerated.com/2015/12/nerdy-mapping-fun-with-faerun-and.html">Part IV, KML Files</a> I use KML files to display maps at different zoom levels.</li>
</ol>
Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com4tag:blogger.com,1999:blog-9195128091507487730.post-76464717868081693382015-10-29T18:02:00.002-07:002017-09-08T12:19:20.298-07:00Nerdy Mapping Fun with Faerun and Google Earth, Part III, Higher ResolutionIn <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and.html">Part I</a>, I discussed the process of getting this this awesome and massively detailed map of <a href="http://mikeschley.zenfolio.com/p858006957/h5ea715c3#h5ea715c3">Northern Faerun</a> by <a href="http://www.mikeschley.com/">Mike Schley</a>, onto Google Earth.<br />
Anonymous commented on <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and.html">Part I</a> that he thought the map should be shifted North. My position was based on trying to keep the Jungle of Chult within the tropics. However, various older maps of Faerun have considerable variations in distances. Pending new updated maps from Mike / WoTC, I thought it would be reasonable to shift the whole map at least 4 degrees North, putting the Southern edge at 28N and the Northern edge at 56N. You could probably shift at least another 4 degrees depending on which map you use as a reference.<br />
This also moves Baldur's Gate to about San Francisco, Waterdeep to Portland, and Neverwinter to a bit North of Vancouver, BC.<br />
So in this version — I'm using the higher resolution tiled image from <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part II</a> — you get the following corners:<br />
<ul>
<li>150° 0'0.00"W 28° 0'0.00"N</li>
<li> 89°42'0.00"W 28° 0'0.00"N</li>
<li> 89°42'0.00"W 56°14'0.00"N</li>
<li>150° 0'0.00"W 56°14'0.00"N</li>
</ul>
The midpoint for calculating the width is at 42° 7'0.00"N.<br />
And here is how it looks.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrzB6Xx6jr-dA7upmZUrcnrluhOev_TPMMhGuOaqQAk9FcsF-bkKYjvF5ODyM0Ufu9GBRSWVujnzrZ1HJnPExnAF_GnGKrbx2txi8-JQC_T80JvlQsf88BGYQERRpVzU5ZhlaOY2J9oDXp/s1600/Faerun+GE+Snip+3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Northwest Faerun on Google Earth" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrzB6Xx6jr-dA7upmZUrcnrluhOev_TPMMhGuOaqQAk9FcsF-bkKYjvF5ODyM0Ufu9GBRSWVujnzrZ1HJnPExnAF_GnGKrbx2txi8-JQC_T80JvlQsf88BGYQERRpVzU5ZhlaOY2J9oDXp/s400/Faerun+GE+Snip+3.PNG" /></a></div>
<h5>
Nerdy Mapping Fun</h5>
<ol>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part I</a> I overlay a map of Faerun on Google Earth.</li>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part II, Stitching it Together</a> I repeat this process with the 34 part PDF map.</li>
<li><a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_29.html">Part III, Higher Resolution</a> and now moving it around.</li>
<li>In <a href="http://www.autogenerated.com/2015/12/nerdy-mapping-fun-with-faerun-and.html">Part IV, KML Files</a> I use KML files to display maps at different zoom levels.</li>
</ol>
Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com420tag:blogger.com,1999:blog-9195128091507487730.post-53323984695524294932015-10-28T18:14:00.002-07:002015-12-15T07:41:27.722-08:00Nerdy Mapping Fun with Faerun and Google Earth, Part II, Stitching it Together<p>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and.html">Part I</a>, I discussed the process of getting this this awesome and massively detailed map of <a href="http://mikeschley.zenfolio.com/p858006957/h5ea715c3#h5ea715c3">Northern Faerun</a> by <a href="http://www.mikeschley.com/">Mike Schley</a>, onto Google Earth.</p>
<p>In addition to the map I originally used there is a ~34 part PDF version at about 2x the resolution of the JPG image. So, I decided to try using this and adding multiple image maps that I could tile together.</p>
<p>For this, I copied each PDF page into Paint.NET and alligned them. This turned out to be a bit of work as, in some cases, some of the images were off by a pixel or two. I'm not sure if this is an artifact of the conversion to and from the PDF or maybe my accidentally nudging pixels around as I worked. However, after some effort I had a nice 645 MB Paint file.</p>
<p>I then stripped the borders and cut the image into 4 equal 9735x6175 pngs. Before being optimized each image was about 140MB, after about MB.</p>
<p>I then ran a similar process as in <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and.html">Part I</a>, bringing in the image, converting the coordinates to radians, measuring the distance between points and adjusting until they matched the map dimensions. As before, the North–South dimensions match the map, but only the mid-point line is accurate, with the Southern border stretched and the Northern border compressed.</p>
<p>For this version the combined tiles ran from Longitude 150° 0'0.00"W to 93°12'0.00"W and Latitude 24° 0'0.00"N to 52°14'0.00"N.
<p>And looks good with double the resolution of the map in <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and.html">Part I</a>.</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpSd6s87r94oi2llCNvKgFegqxwUGPp9yZrIaGNVZMI3LdDV7_N6ZyIQD9P00CMosEQNDXL7_WAusTeW4ZkgBbLSx8oRsJwO2BCAdx0sEuJIOGVARZngUiwtOjEcXLRNjqkLwVNkOi107G/s1600/Faerun+GE+Snip+2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpSd6s87r94oi2llCNvKgFegqxwUGPp9yZrIaGNVZMI3LdDV7_N6ZyIQD9P00CMosEQNDXL7_WAusTeW4ZkgBbLSx8oRsJwO2BCAdx0sEuJIOGVARZngUiwtOjEcXLRNjqkLwVNkOi107G/s400/Faerun+GE+Snip+2.PNG" /></a></div>
<h5>Nerdy Mapping Fun</h5>
<ol>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part I</a> I overlay a map of Faerun on Google Earth.</li>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part II, Stitching it Together</a> I repeat this process with the 34 part PDF map.</li>
<li><a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_29.html">Part III, Higher Resolution</a> and now moving it around.</li>
<li>In <a href="http://www.autogenerated.com/2015/12/nerdy-mapping-fun-with-faerun-and.html">Part IV, KML Files</a> I use KML files to display maps at different zoom levels.</li>
</ol>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com4tag:blogger.com,1999:blog-9195128091507487730.post-37686791033573647002015-10-28T09:56:00.000-07:002017-09-08T12:44:16.023-07:00Nerdy Mapping Fun with Faerun and Google Earth, Part I<strong>Updated with a few math fixes</strong><br />
I purchased this awesome and massive detailed map of <a href="http://mikeschley.zenfolio.com/p858006957/h5ea715c3#h5ea715c3">Northern Faerun</a> by <a href="http://www.mikeschley.com/">Mike Schley</a>, a digital version of the one included in the <a href="http://dnd.wizards.com/">Dungeons & Dragons</a> <a href="http://www.amazon.com/Sword-Coast-Adventurers-Guide-Accessory/dp/0786965800">Sword Coast Adventurer's Guide</a>.<br />
The map weighs in at 10200 x 6600 px — a little less if you shave the borders — and also comes with a 34 page even higher detail PDF version. If I get ambitious I might stitch that together and use that instead.<br />
However, at this scale the map really needs to be on a globe, for which Google Earth will do nicely. Now, some literature suggests Toril is slightly larger than Earth, some literature says the same size, but as far as I know Google Earth doesn't allow for rolling out your own planets, so our Earth will have to do.<br />
First off, it is easy enough to overlay an image in Google Earth. In the menu bar: Add | Image Overlay. Wait a bit for the image to load. Then, change to the Location tab in the New Image Overlay popup and click the "Convert to LatLonQuad" button. This will give you the ability to set the four corners independently.<br />
The Edit Image Overlay dialog's Location tab then lists four corners with Longitude and Latitude. The 1st corner is Southwest (bottom left) then Southeast (bottom right), Northeast (top right) then Northwest (top left).
<br />
The map legend is about 1820px = 500 miles. After shaving the borders I ended up with a map that was about 2674 x 1696 miles. Further, I assumed that this is actually a Mercator projection and so the distances are accurate North-South, but that East-West the scale is only accurate at the middle of the map.<br />
Given those assumptions, everything is nicely parallel, with the Southern edge of the map ending up at about 3,124 nautical miles while the Northern edge is only 2,074 nautical miles.<br />
I picked a starting point where Baldur's Gate will end up roughly on top of Los Angeles, CA (Waterdeep at Ashland, OR and Neverwinter at Seattle, WA). Using formulas from <a href="http://excel.tips.net/T003275_Calculating_the_Distance_between_Points.html">Allen Wyatt's ExcelTips</a> I started plugging numbers into Excel.<br />
I converted each LAT/LNG pair into radians using this formula:<br />
<code>=RADIANS((DEGREES*3600+MINUTES*60+SECONDS)/3600)</code>
Then plugged a N-S pair into Excel, and adjusted, to get one edge using this forumula:<br />
<code>=ACOS(SIN(LAT1)*SIN(LAT2)+COS(LAT1)*COS(LAT2)*COS(LON2-LON1))*3443.89849</code>
With that done, I took the mid-point between the North South edges, and plugged those into the same formulas to get the East West coordinates. I plugged those numbers back into the Google Earth location tab on the image overlay. And success!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYMAxdhgJL_NJnYXfi7IeadE97B2xD-1m5ECI-DfyEA1nSwIySo4ePBU4UOdFEwfZGlAZBQBGZcUwtUTwwUn8l9YCm22ygnhRaaLDIVlrC2V9QjRM9TrajJY8ocsiIaDXYINIOkHWqzfuA/s1600/Google+Earth+snip.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYMAxdhgJL_NJnYXfi7IeadE97B2xD-1m5ECI-DfyEA1nSwIySo4ePBU4UOdFEwfZGlAZBQBGZcUwtUTwwUn8l9YCm22ygnhRaaLDIVlrC2V9QjRM9TrajJY8ocsiIaDXYINIOkHWqzfuA/s400/Google+Earth+snip.PNG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3Wej1592ZUyKmMf8gPoTHLC30nKrC9ME9C5F13g4CVdi6Gfj7w-2x7buSCvavsfVfMei7kDiqyY4ad2X22y4FaAlqa0NAjfQae5g4sQ8cUKJ1rYbzF_e0xMVYVZK2ztk5_bZKBDI4jDRE/s1600/Google+Earth+Fearun+detail+snip.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3Wej1592ZUyKmMf8gPoTHLC30nKrC9ME9C5F13g4CVdi6Gfj7w-2x7buSCvavsfVfMei7kDiqyY4ad2X22y4FaAlqa0NAjfQae5g4sQ8cUKJ1rYbzF_e0xMVYVZK2ztk5_bZKBDI4jDRE/s400/Google+Earth+Fearun+detail+snip.PNG" /></a>
</div>
Hard to see here but if you look close you can see the latitude and longitude markings.
The final values I used were:<br />
<br />
<ol>
<li><strong>1st Corner:</strong> 150° 0'0.00"W Longitude and 24° 0'0.00"N Latitude</li>
<li><strong>2nd Corner:</strong> 92°12'0.00"W Longitude and 24° 0'0.00"N Latitude</li>
<li><strong>3rd Corner:</strong> 92°12'0.00"W Longitude and 52°16'0.00"N Latitude</li>
<li><strong>4th Corner:</strong> 150° 0'0.00"W Longitude and 52°16'0.00"N Latitude</li>
</ol>
<h5>
Nerdy Mapping Fun</h5>
<ol>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part I</a> I overlay a map of Faerun on Google Earth.</li>
<li>In <a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_28.html">Part II, Stitching it Together</a> I repeat this process with the 34 part PDF map.</li>
<li><a href="http://www.autogenerated.com/2015/10/nerdy-mapping-fun-with-faerun-and_29.html">Part III, Higher Resolution</a> and now moving it around.</li>
<li>In <a href="http://www.autogenerated.com/2015/12/nerdy-mapping-fun-with-faerun-and.html">Part IV, KML Files</a> I use KML files to display maps at different zoom levels.</li>
</ol>
<br />
<br />
Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com8tag:blogger.com,1999:blog-9195128091507487730.post-29191424752492410602013-04-27T14:40:00.001-07:002013-04-27T14:40:17.365-07:00First days with Google Glass<p>On this past Wednesday, April 24, after 11 months of — I'll admit to anxiously — waiting I was invited to come down to Google and pick them up (after forking over the cash of course). I was surprised at the level of attention I got from two Googlers who spent 30 minutes teaching me to use the device and getting the fit right. They followed this with a campus tour. They are definitely putting out the red carpet for Glass developers and it was low key but still fun and exciting.</p>
<p>With Glass the first thing I noticed was how high the build quality was and how comfortable they were to wear. The weight becomes noticeable to me only after having them on for several hours. And, though I wear contacts (or at least I do since I got the invite) after three days of on and off use, I have not felt any eye strain or issues. While I had trouble hearing the speaker if there was a lot of ambient noise, in other conditions it is loud enough.</p>
<p>Like many others, I think it would benefit from a less bulky and more aesthetically pleasing frame but I find the appearance less jarring than it appears in pictures, especially with (optional) sun glass lenses in place. The biggest issue I have had was setting the vertical adjustment of the screen. I had to twist the frame and the nose pads to get it to stay consistently in my FOV. Also, the battery life seems less than the all-day they suggested and, if participating in a hangout have your charger nearby. Making it work with existing glasses or the ability to add prescription lenses is also an obvious need.</p>
<p>Meanwhile, the deluge of anti-glass articles, some bordering on hysteria, and the "glasshole" meme have certainly managed to get the word out. I brought them to work and the existing level of knowledge and curiosity was crazy — better than any other product I've ever seen (including the <a href="http://techcrunch.com/2013/04/26/eric-schmidt-is-right-using-google-glasses-is-weird-heres-my-experience/">Segway</a>).</p>
<p>Of course, curiosity doesn't mean love, and I think many of the points that are being raised about the negative social implications and issues such as with using a voice as a primary interface in public, are real. I can recall the backlash against cell phones (long before smartphones) when they first began to encroach on daily life. It took years before a still-rough social etiquette developed. I will not be at all surprised if Glass and similar wearable computing devices' initial usage ends up being somewhat limited rather than in broad public and social settings. Although the dork factor is quite capable of doing serious damage. Just look at what happened to Segway and cell phone belt clips — hopefully Google will take this issue seriously.</p>
<p>Still, the naysayers seem to be primarily focused on the potential negative social aspects without giving thought to the utility. For me, I became a convert when my son asked me who the president of India was, and I said: "OK Glass, Google: who is the president of India?" and it whispered the answer in my ear. And to say I could take out my phone and look up the answer is like saying I can go to my desktop and look up the answer which is like saying I can get the answer by calling my local librarian — which is to say, not even close. The immediacy is amazing and almost shocking. Want to translate something? "OK Glass, Google: how do I say 'where is is the bathroom' in Turkish?" Want to know if it is raining outside just ask. Need to call your spouse, just say so.</p>
<p>I think this is a revolutionary product and the beginning of a trend that will be nearly unstoppable. While I expect social backlash and for many to reject these devices or at least be slow to adopt, and who knows what interface or products finally win out. The borg meme actually seems fitting here so, in the end, resistance is futile, you will be assimilated.</p>
Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com2tag:blogger.com,1999:blog-9195128091507487730.post-60221116146838119662012-11-30T18:55:00.000-08:002012-11-30T18:55:41.965-08:00A knockout binding handler to update dynamically loaded Facebook plugins<p>
When you are loading Facebook social plugins, Facebook takes the values, such as for the "data-href" value for a comments box, when the page is initially created.</p>
<p>Sometimes, you want to update the plugin after an observable has been updated or based on dynamic values coming in from a knockout template.</p>
<p>Here is a simple knockout binding handler that will call FB.XFBML.parse() to update the page after an element is bound.</p>
<pre>
<code>
ko.bindingHandlers.updateFacebook = {
init: function (element) {
FB.XFBML.parse();
}
};
</code>
</pre>
<p>And you can can use it like this, overwriting the initial value with the attr value:</p>
<pre>
<code>
<div class="fb-comments" data-bind="attr: { 'data-href': viewModelUrl }, updateFacebook: true" data-href="@Request.Url" data-num-posts="10" data-width="400">
</div>
</code>
</pre>
<p>The FB.XFBML.parse() method will allow you update either the whole page or an element by id, so you could also do:</p>
<pre>
<code>
ko.bindingHandlers.updateFacebook = {
init: function (element) {
var id = $(element).attr('id');
FB.XFBML.parse( document.getElementById(id) );
}
};
</code>
</pre>
<p>This is put together from <a href="https://developers.facebook.com/docs/reference/javascript/FB.XFBML.parse/">Facebook's parse function</a>, <a href="http://jsfiddle.net/rniemeyer/Ampng/37/">Ryan Niemeyer</a> and from <a href="http://www.autogenerated.com/2012/03/loading-facebook-social-plugins-in.html">this post</a></p>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com0tag:blogger.com,1999:blog-9195128091507487730.post-65258750029073010522012-09-21T13:47:00.001-07:002012-09-21T13:47:44.686-07:00Set KeyTips z-index<p>Because I pretty much just do whatever <a href="http://www.hanselman.com/blog/TheWebIsTheNewTerminalAreYouUsingTheWebsKeyboardShortcutsAndHotkeys.aspx">Hanselman</a> tells me to do, I was trying to get some keyboard shortcuts set up on my website.</p>
<p>While testing with Damien Edwards <a href="http://damianedwards.com/files/KeyTips/">KeyTips</a> I could get the keyboard commands to work, but the popup would not display. It is a complex site, lots of css, ajax loaded objects, etc.
Long story, short, I needed to set the z-index in the .KeyTips__popup class to be higher than the surrounding elements.
<code>
.KeyTips__popup {
//removed for clarity
z-index: 1000;
}
</code>
Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com1tag:blogger.com,1999:blog-9195128091507487730.post-1443385860829491212012-09-04T16:40:00.000-07:002012-09-04T16:40:57.724-07:00Knockout RequireJs / AMD module name convention inconsistency<p>
When using various RequireJS/ AMD with various knockout-related scripts if there is an inconsistency in the named knockout module it will throw a RequireJS module load error.
</p>
<p>
While Knockout itself isn't exporting itself with a specific name, various scripts that depend on Knockout look for a named module (or at least a relative module. In my case, I'm using both <a href="https://github.com/SteveSanderson/knockout.mapping/tree/master/build/output">knockout.mapping</a> and <a href="https://github.com/ifandelse/Knockout.js-External-Template-Engine">koExternalTemplateEngine-amd</a>
</p>
<p>
In knockout.mapping:</p>
<code>
else if (typeof define === "function" && define["amd"]) {
define(["knockout", "exports"], factory);
</code>
<p>
In koExternalTemplateEngine-amd.js
</p>
<code>
define(['ko','jquery', 'infuser'], function(ko, jQuery, infuser){
</code>
<p>
If you have abstracted away the knockout version numbers in a config paths setting:
</p>
<code>
requirejs.config({
paths: {
ko: 'knockout-2.1.0.debug'
}
});
</code>
<p>
Knockout.mapping will fail to find the named 'knockout' module. To fix this you need to change the module name to be consistent with your path alias (you could change the alias to 'knockout' and update koExternalTemplate-amd as well of course). More importantly you need to remember that you changed it so next time you update knockout-mapping you don't break your code and spend an hour trying to figure out why! :-)
</p>
<code>
else if (typeof define === "function" && define["amd"]) {
define(["ko", "exports"], factory);
</code>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com0tag:blogger.com,1999:blog-9195128091507487730.post-29218696727759820362012-07-17T11:30:00.000-07:002012-07-17T11:30:33.288-07:00Change the font size in Chrome Developer Tools<p>Chrome dev tools default font sizes seem to have been set for fighter jet pilots but my eyesight is not what it used to be, which wasn't good to begin with.</p>
<p>You can find out how to reset the <a href="http://blog.dotsmart.net/2011/09/30/change-font-size-in-chrome-devtools/">font sizes here</a> with instructions for Mac and Linux.</p>
<p>In brief on Windows, you can to to this folder:</p>
<code>
C:\Users\[user]\AppData\Local\Google\Chrome\User Data\Default\User StyleSheets</code>
<p>...or, for Canary...</p>
<code>
C:\Users\[user]\AppData\Local\Google\Chrome SxS\User Data\Default\User StyleSheets</code>
<p>
Create a Custom.css stylesheet, add the css below changing the font size to whatever you want:</p>
<pre>
<code>
body.platform-windows .monospace, body.platform-windows .source-code {
font-size: 16px !important;
font-family: Consolas, Lucida Console, monospace;
}
</code>
</pre>
<p>
And you are good to go.</p>
<p>
Here's an <a href="http://darcyclarke.me/design/skin-your-chrome-inspector/">article on skinning the dev tools</a>. and you can find all the styles, in case you want to do it yourself, at:<br /><br />chrome-devtools://devtools/devTools.css
</p>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com5tag:blogger.com,1999:blog-9195128091507487730.post-66863878238270850832012-07-14T01:15:00.002-07:002012-07-17T11:40:14.881-07:00A Knockout History.js ajaxify bindingHandler<p>I've been playing around with <a href="https://gist.github.com/balupton">balupton's</a> <a href="https://github.com/balupton/History.js/">History.js</a> and <a href="https://gist.github.com/854622">Ajaxify</a> scripts for my current project. I had tried both a year or so ago and, while they worked well at first I ran into some problems here and there. I'm making a second attempt and so far it's going well.</p>
<p>
However, balupon's ajaxify code is run once on the initial page load or the return of the ajax load event so it does not catch template fragments that are loaded or bound after the load completes.</p>
<p>As I am using <a href="http://knockoutjs.com/">Knockout</a> extensively with a lot of dynamically loaded content, I wanted extend balupton's ajaxify function to my dynamically loaded content using a knockout bindingHandler:</p>
<p> This is the helper function:
<pre>
<code>
// Ajaxify Helper
$.fn.ajaxify = function(){
// Prepare
var $this = $(this);
// Ajaxify
$this.find('a:internal:not(.no-ajaxy)').click(function(event){
// Prepare
var
$this = $(this),
url = $this.attr('href'),
title = $this.attr('title')||null;
// Continue as normal for cmd clicks etc
if ( event.which == 2 || event.metaKey ) { return true; }
// Ajaxify this link
History.pushState(null,title,url);
event.preventDefault();
return false;
});
// Chain
return $this;
};
</code>
</pre>
<p>
And here it is, <a href="http://requirejs.org/docs/whyamd.html">amd style</a>:</p>
<pre>
<code>
define(['jquery', 'ko'], function($, ko) {
"use strict";
ko.bindingHandlers.ajaxify = {
update: function(element) {
// Prepare
var $this = $(element);
// Ajaxify
$this.find('a:internal:not(.no-ajaxy)').click(function(event) {
// Prepare
var $this = $(this),
url = $this.attr('href'),
title = $this.attr('title') || null;
// Continue as normal for cmd clicks etc
if (event.which == 2 || event.metaKey) {
return true;
}
// Ajaxify this link
History.pushState(null, title, url);
event.preventDefault();
return false;
});
}
};
});
</code>
</pre>
This assumes you have the other 5000 scripts already on the page (JQuery, History, ScrollTo, Ajaxify, Knockout, Require to name a few) of course. After which usage is simple (well after all that pretty much anything is simple):
<pre>
<code>
<div data-bind="foreach: item, ajaxify: true"><br />
//any links loaded here will get ajaxified<br />
</a>
</code>
</pre>
<p>Now this works well when I'm loading the content from the ko native template and the html is already on the page. When trying to do this when loading the html from templates, no dice. However, by putting the 'ajaxify' binding on the template element being bound, it worked nicely.</p>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com1tag:blogger.com,1999:blog-9195128091507487730.post-1868959510103563222012-03-20T10:03:00.003-07:002012-03-20T12:30:11.867-07:00Loading Facebook social plugins in dynamic, ajax contentIf you include a Facebook social plugin inside of a piece of content (JQuery UI dialog, template, whatever) that you add to the page dynamically, the plugin fails to render. This is because Facebook parses the page only initial load and so doesn't pick up the dynamic content. You need to explicitly tell it to re-parse the entire page, or just the new content.<br />
<br />
So here I have a function that will use JQuery to load a piece of content containing Facebook plugins. All I need to do is call FB.XFBLM.parse(...) after the content is loaded and problem solved.<br />
<br />
<br />
<pre><code>
var url = "/shared/facebooklikes";
$(#facebookLikesPlaceholder").load(url, function () {
FB.XFBML.parse(document.getElementById('facebookLikesPlaceholder'));
});
</code>
</pre><br />
Here's the <a href="https://developers.facebook.com/docs/reference/javascript/FB.XFBML.parse/"> article reference</a>.<br />
<br />
Now, there is a further complication if you are loading the Facebook SDK async. In this case, the script may not have been fully loaded by the time your ajax call is made and returns. So, you need to check that the script is loaded before you make your call to parse.<br />
<br />
Here is a <a href="http://stackoverflow.com/questions/2977432/what-is-a-replacement-for-fb-ensureinit-now">Stackoverflow post</a> that addresses this case and which I'm using here.<br />
<br />
Now, in the script block where I load the FB SDK, I add:<br />
<br />
<pre><code>
var fbApiInitialized = false;
FB.Init({}),fbApiInitialized = true;
(fbEnsureInit = function (callback) {
if (!window.fbApiInitialized) {
setTimeout(function () { fbEnsureInit(callback); }, 50);
} else {
if (callback) {
callback();
}
}
})();
</code></pre><br />
So it looks like this:<br />
<br />
<pre><code>
<script>
var fbApiInitialized = false;
window.fbAsyncInit = function () {
FB.init({
appId: '[YOUR APP ID]',
channelURL: '[channelUrl]'
status: true,
cookie: true,
xfbml: true,
frictionlessRequests: true
}),
fbApiInitialized = true;
};
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
(fbEnsureInit = function (callback) {
if (!window.fbApiInitialized) {
setTimeout(function () { fbEnsureInit(callback); }, 50);
} else {
if (callback) {
callback();
}
}
})();
</script>
</code></pre><br />
And my ajax load method now looks like:<br />
<br />
<pre><code>
var url = "/shared/facebooklikes";
$(#facebookLikesPlaceholder").load(url, function () {
window.fbEnsureInit(function () {
FB.XFBML.parse(document.getElementById('facebookLikesPlaceholder'));
});
});
</code>
</pre><br />
And it correctly checks that the script is loaded before calling FB.XFBML.parse().Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com2tag:blogger.com,1999:blog-9195128091507487730.post-77010891806204842312012-03-14T16:16:00.002-07:002014-06-19T13:04:02.460-07:00Custom Knockout binding for truncating text with an ellipsis[UPDATE]
Added an AMD version at the end.
Adapting this <a href="http://jsfiddle.net/k5VET/">JsFiddle</a> I created a custom knockout binding for truncating multi-line text to fit within an available space:<br />
<br />
<pre><code>
ko.bindingHandlers.truncate = {
update: function (element, valueAccessor, allBindingsAccessor, context) {
var value = valueAccessor();
var $element = $(element);
var divh = $element.parent().height();
$element.text(value());
while ($element.outerHeight() > divh) {
$element.text(function (index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
}
};
</code>
</pre><br />
Both the parent and child need to be block level elements and the parent needs a fixed height I believe.<br />
<br />
Of course, if you have just a single line, you can do this easily with pure css (from <a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a>)<br />
<br />
<pre><code>
// Text overflow
// -------------------------
// Requires inline-block or block for proper styling
.text-overflow {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</code>
</pre>
Here is a <a href="http://jsfiddle.net/genereddick/2QNb7/">JsFiddle</a> showing this in action.
[UPDATE]
And now here is an AMD version. Where 'jquery' is, of course, jQuery, and 'ko' is knockout.
<pre>
<code>
define(['jquery', 'ko'], function ($, ko) {
ko.bindingHandlers.truncate = {
update: function (element, valueAccessor) {
var value = valueAccessor();
var $element = $(element);
var divh = $element.parent().height();
$element.text(value());
while ($element.outerHeight() > divh) {
$element.text(function (index, text) {
return text.replace(/\W*\s(\S)*$/, '...');
});
}
}
};
});
</code>
</pre>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com10tag:blogger.com,1999:blog-9195128091507487730.post-6348637787631305102012-03-05T14:14:00.002-08:002012-03-20T12:45:01.308-07:00Sprite and Image Optimization Framework and .NET Minifier Bundling[NOTE: This code doesn't fully work (with the version of bundler in Visual Studio 11 Beta, newer versions may address this) s the bundler combines the files but leaves the relative path urls in the css unchanged. As they no longer point to the correct paths they break. If the images are base 64 encoded in the css it will work however. So, as I don't want to right my own parser, <a href="https://github.com/jetheredge/SquishIt/downloads">SquishIt</a> remains my choice as it will create the bundles with the correct path to the root.]<br />
<br />
I use the <a href="http://aspnet.codeplex.com/releases/view/65787">Sprite and Image Optimization Framework</a> for spriting images. The SIOF is currently on preview 4, but hopefully still going forwards.<br />
<br />
Previously I have been using <a href="https://github.com/jetheredge/SquishIt/downloads">SquishIt</a> for bundling and minification and it has worked really well for me. But, with Bundling and Minification built in to Visual Studio 11, I thought I would see what it took to get it working with the SIOF.<br />
<br />
Specifically, the SIOF generates a separate css file on the fly for each subfolder inside an "App_Sprites" directory (by convention, but can be configured otherwise of course). Also, it generates two different versions of the css, a 'lowCompat.css' for older browsers and a 'highCompat.css' for modern browsers.<br />
<br />
In my case, I like to separate my sprite folders for clarity and for possible inclusion in specific locations and so end up with a lot of css files. I don't want the overhead of making separate http calls to load each css file individually, so I need to bundle them together.<br />
<br />
So this is what I needed to do to get bundling working. Note, this approach does not provide minification as there are problems with how the SIOF spits out css when it is minified.<br />
<br />
In the global.asax.cs file, in Application_Start, I had to create custom bundles, which look like this:<br />
<br />
<br />
BundleTable.Bundles.EnableDefaultBundles();<br />
<br />
var highCompat = new Bundle("~/spritehighbundle", new NoTransform());<br />
var lowCompat = new Bundle("~/spritelowbundle", new NoTransform());<br />
<br />
highCompat.AddDirectory("~/App_Sprites","highCompat.css",true);<br />
lowCompat.AddDirectory("~/App_Sprites","lowCompat.css",true);<br />
<br />
BundleTable.Bundles.Add(highCompat);<br />
BundleTable.Bundles.Add(lowCompat);<br />
<br />
The first line is used for the regular bundles you might create and isn't part of the custom bundles I'm creating here, but I left it in as I use it in other places.<br />
<br />
First, I create a new bundle and tell it where to create the file and give it a transform.<br />
<br />
<br />
var highCompat = new Bundle("~/spritehighbundle", new NoTransform());<br />
<br />
<br />
Because of the way the SIOF creates the css, if you attempt to minify the file it will generate bad css, so I set it to "new NoTransform()". I had the same issue with SquishIt and used a similar approach to deal with the issue.<br />
<br />
If you want to try minifying you could use "new CssMinify()" instead and that might actually work for the lowCompat.css file, but I didn't check.<br />
<br />
Then, I point it to the directory I want to bundle, "~/App_Sprites".<br />
<br />
highCompat.AddDirectory("~/App_Sprites","highCompat.css",true);<br />
<br />
By default it will take all the subfolders under that, though you can configure them individually. I give it a string match, in this case either "highCompat.css" or "lowCompat.css" so I can get two different bundled css files depending on the users browser capabilities.<br />
<br />
Then, add to the BundleTable.Bundles:<br />
<br />
<br />
BundleTable.Bundles.Add(highCompat);<br />
<br />
And we are done in the global. In the head of my html page (or layout.master):<br />
<br />
<br />
@if(ImageOptimizations.LinkCompatibleCssFile(Request.Browser) == "highCompat.css") {<br />
<link href="@BundleTable.Bundles.ResolveBundleUrl(" rel="stylesheet" spritehighbundle")"="" type="text/css" ~=""></link><br />
} else {<br />
<link href="@BundleTable.Bundles.ResolveBundleUrl(" rel="stylesheet" spritelowbundle")"="" type="text/css" ~=""></link><br />
}<br />
<br />
The first line checks to see which version of the css your browser should see. Inside the if statement it points you to the bundle you configured in the Application_Start.<br />
<br />
The output in the html looks like:<br />
<br />
<br />
<link href="/spritehighbundle?v=Pz1dYVdxXX3byT-0-Sd3NUQdrbaEEsozXT6mYfGVn5o1" rel="stylesheet" type="text/css"></link><br />
<br />
<br />
With a version hash that will invalidate the css if you make a change.<br />
<br />
And that is it. Not necessarily painless and not necessarily better than how I had it set up under SquishIt, but working at least.<br />
Labels: sprite and image optimization framework bundling minification<br />Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com2tag:blogger.com,1999:blog-9195128091507487730.post-30524754208871741342012-03-01T12:25:00.001-08:002020-01-28T12:02:17.760-08:00Force the .net Web Api to return JSON to the browser by default.Even though by default the Web Api has Json set as the first formatter, if you hit your Api in a browser it will attempt to return Xml. This is because Chrome and other browsers have a default accept header that looks something like:
<br />
<pre>
<code>
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
</code>
</pre>
<br />
The Json formatter is only looking for an "application/json" or similar accept header and so is skipped over, triggering the Xml formatter when it sees the "application/xml" accept header.
<br />
<br />
You could clear the SupportedMediaTypes from the XmlFormatter (in Application_Start):
<br />
<br />
<pre>
<code>
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
</code>
</pre>
<br />
But then no one would get Xml. So, easy peasy, just add "text/html" to the JsonFormatters supported media types and you get Json in the browser, but if someone really wants "application/xml" they can get that too by only requesting the appropriate type.
<br />
<br />
You can doublecheck in the debugger that Json is the first formatter, but this worked for me:<br />
<br />
<pre>
<code>
GlobalConfiguration.Configuration.Formatters[0] .SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
</code>
</pre>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com1tag:blogger.com,1999:blog-9195128091507487730.post-12316134381585917272011-02-18T10:40:00.000-08:002012-04-06T10:07:22.584-07:00Crazy Pool Trick ShotsApropos of nothing except that I like <a href="http://www.youtube.com/watch?v=b91yIF-PEtI">pool</a>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com0tag:blogger.com,1999:blog-9195128091507487730.post-14721052618631863562011-01-15T13:52:00.000-08:002011-01-15T13:52:32.158-08:00Entity Code First Login Failed for IIS APPPOOLTook a few searches to find this one, but, while converting my database from the build in VS server to using IIS my connection string was failing on attempting to connect to the database, with an error message of:<br />
<br />
Cannot open database "[databasename]" requested by the login. The login failed.<br />
Login failed for user 'IIS APPPOOL\[the site's apppool name]'.<br />
<br />
Long story short, in IIS 7.5 the AppPool is given serveral different identities: Local Service, Local System, Network Service and ApplicationPoolIdentity (the default). You can find this in <br />
<br />
IIS Manager : Application Pools : Right click on the app pool for your site : Advanced Settings : Process Model : Identity : Select from the ... button<br />
<br />
In my case, network service has permissions to hit the database but the new ApplicationPoolIdentity did not. Either change the App pool identity or give ApplicationPoolIdentity permissions.<br />
<br />
Problem solved.Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com0tag:blogger.com,1999:blog-9195128091507487730.post-45897387075058796922010-12-17T16:11:00.000-08:002010-12-17T16:14:14.216-08:00SlightWords, my windows phone 7 app on track to hit one million download......sometime around the year 2260. <br />
<br />
Oh, I'm sorry. Was that a misleading headline? Sure it seems like a long time from now — if you are a Monarch Butterfly or a human. But I'm in this for the long haul. By the time the Sun becomes a red giant and swallows the earth I will have hit something like 40 billion downloads, at the current rate. And I'll take that to the bank, thank you very much.<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTv-wd5mOiAQRiEHf62vOWsMVXUMhiQhzq1s_d7v-p_kwqkJyXmq5l0usBXiwqadnRfoCdUkabGE6OalqU6z1KgoGv1tLOOdIrlF4OUmbBtmXE8Vjucb6_s65Q8HgbygkWDn0dC_1QSJHN/s1600/ScreenShot.png" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"><img border="0" height="320" width="192" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTv-wd5mOiAQRiEHf62vOWsMVXUMhiQhzq1s_d7v-p_kwqkJyXmq5l0usBXiwqadnRfoCdUkabGE6OalqU6z1KgoGv1tLOOdIrlF4OUmbBtmXE8Vjucb6_s65Q8HgbygkWDn0dC_1QSJHN/s320/ScreenShot.png" /></a></div>Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com0tag:blogger.com,1999:blog-9195128091507487730.post-26169369341722468142010-09-08T17:31:00.000-07:002010-09-08T17:31:47.820-07:00Studying study habitsThe New York Times, reports on <a href="http://www.nytimes.com/2010/09/07/health/views/07mind.html">new findings on study habits</a>. This seems to repeat and support the research of <a href="http://www.wired.com/medtech/health/magazine/16-05/ff_wozniak">Piotr Wozniak's</a> reported in Wired a couple years ago. Spaced repetition seems to be the key. Learn it. Learn it again a short time later. Then keep stretching out the periods between relearning the same thing.Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com0tag:blogger.com,1999:blog-9195128091507487730.post-5712152879061760022010-07-02T21:46:00.000-07:002010-07-02T21:46:10.132-07:00Our new social gaming site, gameinsects.com, because we're so socialYes. we are a veritable socialite, everybody's friend, life of the party kind of person. And so, we have built, along with an excellent designer and our esteemed nose to the grindstone, foot to the fire boss in all but name, a new site. Still in beta, still rough around the edges, not quite right on all browsers / versions, not quite ready for prime time, spit when you say its name, but we are pretty happy with the progress.<br />
<br />
You can find <a href="http://www.gameinsects.com/">gameinsects</a> here. It is — whatever it is, not really quite sure yet — going to be big. Or not. Probably not, But we think it looks good anyway. But not too good. Please no lightning. Or negative comments. It's just a baby.Machinehttp://www.blogger.com/profile/08969093410412994583noreply@blogger.com0