Difference between revisions of "Radar HUD Demo"

From Second Life Wiki
Jump to: navigation, search
Line 26: Line 26:
 
// Any linked or referenced files are not included in this license and are licensed by their respective owners under their own respective copyright and other licenses.  
 
// Any linked or referenced files are not included in this license and are licensed by their respective owners under their own respective copyright and other licenses.  
 
// Created by Kelly Linden, 2011.
 
// Created by Kelly Linden, 2011.
 
+
 
integer display_face = 4;
 
integer display_face = 4;
 
+
 
string index_html;
 
string index_html;
 
+
key request_id = NULL_KEY;
+
 
+
 
build_index(string url)
 
build_index(string url)
 
{
 
{
 
     vector rc = llGetRegionCorner();
 
     vector rc = llGetRegionCorner();
 
     string bg_url = "http://map.secondlife.com/map-1-" + (string)((integer)(rc.x / 256)) + "-" + (string)((integer)(rc.y / 256))  + "-objects.jpg";
 
     string bg_url = "http://map.secondlife.com/map-1-" + (string)((integer)(rc.x / 256)) + "-" + (string)((integer)(rc.y / 256))  + "-objects.jpg";
               
+
 
     // Build the index page.
 
     // Build the index page.
 
     index_html =  
 
     index_html =  
Line 45: Line 43:
 
var me;var req_me = false;
 
var me;var req_me = false;
 
var people;var req_people = false;
 
var people;var req_people = false;
 
+
 
function plot(ctx, points, color, border, size) {
 
function plot(ctx, points, color, border, size) {
 
   if (points != undefined) {
 
   if (points != undefined) {
Line 57: Line 55:
 
   }
 
   }
 
}
 
}
 
+
 
function updateMap() {
 
function updateMap() {
 
   canvas = document.getElementById( 'myCanvas' );
 
   canvas = document.getElementById( 'myCanvas' );
Line 63: Line 61:
 
   img = new Image();
 
   img = new Image();
 
   img.src = '" + bg_url + "';
 
   img.src = '" + bg_url + "';
 
+
 
   if (!req_me) {
 
   if (!req_me) {
 
       req_me = true;
 
       req_me = true;
 
       $.getJSON('mypos',function(data){me = data;req_me=false;});
 
       $.getJSON('mypos',function(data){me = data;req_me=false;});
 
   }
 
   }
 
+
 
   if (!req_people) {
 
   if (!req_people) {
 
     req_people = true;
 
     req_people = true;
 
     $.getJSON('avatars',function(data){people = data;req_people=false;});
 
     $.getJSON('avatars',function(data){people = data;req_people=false;});
 
   }
 
   }
 
+
 
   ctx.save();
 
   ctx.save();
 
   if (img.complete) {
 
   if (img.complete) {
 
     ctx.drawImage( img, 0, 0, canvas.getAttribute('width'), canvas.getAttribute('height') );
 
     ctx.drawImage( img, 0, 0, canvas.getAttribute('width'), canvas.getAttribute('height') );
 
   }
 
   }
 
+
 
   plot(ctx,people,'#FF0000','#FFFFFF',5);
 
   plot(ctx,people,'#FF0000','#FFFFFF',5);
 
   plot(ctx,me,'#FFFFFF','#000000',7);
 
   plot(ctx,me,'#FFFFFF','#000000',7);
Line 90: Line 88:
 
</canvas></body></html>";   
 
</canvas></body></html>";   
 
}
 
}
 
+
 
set_url(string url)
 
set_url(string url)
 
{
 
{
 
     build_index(url);
 
     build_index(url);
 
+
 
     llSetLinkMedia(LINK_THIS, display_face,              // Side to display the media on.
 
     llSetLinkMedia(LINK_THIS, display_face,              // Side to display the media on.
 
             [PRIM_MEDIA_AUTO_PLAY,TRUE,    // Show this page immediately
 
             [PRIM_MEDIA_AUTO_PLAY,TRUE,    // Show this page immediately
Line 102: Line 100:
 
             PRIM_MEDIA_WIDTH_PIXELS,256,  //  rounded up to nearest power of 2.
 
             PRIM_MEDIA_WIDTH_PIXELS,256,  //  rounded up to nearest power of 2.
 
             PRIM_MEDIA_PERMS_CONTROL, PRIM_MEDIA_PERM_NONE]);
 
             PRIM_MEDIA_PERMS_CONTROL, PRIM_MEDIA_PERM_NONE]);
           
+
 
     llOwnerSay("Mem: " + (string)llGetUsedMemory());
 
     llOwnerSay("Mem: " + (string)llGetUsedMemory());
 
}
 
}
 
+
 
default
 
default
 
{
 
{
Line 115: Line 113:
 
         { llResetScript(); }
 
         { llResetScript(); }
 
     }
 
     }
 
+
 
     http_request(key id, string method, string body)
 
     http_request(key id, string method, string body)
 
     {
 
     {
Line 126: Line 124:
 
             llOwnerSay("Failed to get url: " + body);
 
             llOwnerSay("Failed to get url: " + body);
 
         }
 
         }
       
+
 
         if (method == "GET")
 
         if (method == "GET")
 
         {
 
         {
 
             list path = llParseString2List(llGetHTTPHeader(id,"x-path-info"),["/"],[]);
 
             list path = llParseString2List(llGetHTTPHeader(id,"x-path-info"),["/"],[]);
           
+
 
             if (llGetListLength(path) == 0)
 
             if (llGetListLength(path) == 0)
 
             {
 
             {
 
                 llSetContentType(id,CONTENT_TYPE_HTML);
 
                 llSetContentType(id,CONTENT_TYPE_HTML);
               
+
 
                 llHTTPResponse(id,200,index_html);
 
                 llHTTPResponse(id,200,index_html);
 
             }
 
             }
Line 144: Line 142:
 
             else if (llList2String(path,0) == "avatars")
 
             else if (llList2String(path,0) == "avatars")
 
             {
 
             {
                 if (request_id == NULL_KEY)
+
                 list avatars = llGetAgentList(AGENT_LIST_REGION,[]);
 +
           
 +
                string body = "[";
 +
                integer i;
 +
                integer n = llGetListLength(avatars);
 +
                for(i=0;i<n;++i)
 
                 {
 
                 {
                     // If there is a request_id then we are already scanning.
+
                     if (i != 0) body += ",";
                    // Only start a scan if there is no request in process.
+
                    vector pos = llList2Vector(llGetObjectDetails(llList2Key(avatars,i),[OBJECT_POS]),0);
                    llSensor("",NULL_KEY,AGENT,64,PI);
+
                    body += "[" + (string)((integer)pos.x) + "," + (string)(256 - (integer)pos.y) + "]";
 
                 }
 
                 }
                 // Always set the id so we respond to the most recent request.
+
                 body += " ]";
                request_id = id;
+
                llHTTPResponse(id,200,body);
 
             }
 
             }
 
         }
 
         }
    }
 
   
 
    sensor(integer n)
 
    {
 
        string body = "[";
 
        integer i;
 
        for(i=0;i<n;++i)
 
        {
 
            if (i != 0) body += ",";
 
            vector pos = llDetectedPos(i);
 
            body += "[" + (string)((integer)pos.x) + "," + (string)(256 - (integer)pos.y) + "]";
 
        }
 
        body += " ]";
 
        llHTTPResponse(request_id,200,body);
 
        request_id = NULL_KEY;
 
    }
 
   
 
    no_sensor()
 
    {
 
        llHTTPResponse(request_id,200,"[]");
 
        request_id = NULL_KEY;
 
 
     }
 
     }
 
}
 
}
 
</lsl>
 
</lsl>

Revision as of 09:20, 25 June 2012

screenshots

What:

  • Single prim, single script HUD that shows dots for nearby avatars on a map image.
  • Less useful than the mini map.
  • Uses LSL's HTTP-In, html 5 canvas and ajax.
  • Currently under 16k memory as mono.

To use:

  • Create a box, attach it to a HUD point, scale and position as you like.
  • Drop this script in it.
  • Requires media on a prim be enabled.

Bugs:

  • Sometimes it just sits there blank. Not sure how/why. Requires a script restart usually to fix.

TODO:

  • Add hover text for people (names)
  • Add click action for people (profiles?)
  • Rotate the map
  • Zoom the map
  • Better scans (>16 people)
  • Options: scan different things, use different colors.
  • Make the dots look better
  • Add direction indicator to 'me' dot.

<lsl> // License: // This script itself is free to share, modify and use without restriction. // Any linked or referenced files are not included in this license and are licensed by their respective owners under their own respective copyright and other licenses. // Created by Kelly Linden, 2011.

integer display_face = 4;

string index_html;

build_index(string url) {

   vector rc = llGetRegionCorner();
   string bg_url = "http://map.secondlife.com/map-1-" + (string)((integer)(rc.x / 256)) + "-" + (string)((integer)(rc.y / 256))  + "-objects.jpg";

   // Build the index page.
   index_html = 

"<html><head> <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js' /> <script type='text/javascript' language='javascript'> var me;var req_me = false; var people;var req_people = false;

function plot(ctx, points, color, border, size) {

 if (points != undefined) {
   ctx.fillStyle=color;
   for ( p in points ) {
     ctx.fillStyle=border;
     ctx.fillRect(points[p][0] - 2,points[p][1] - 2,size,size);
     ctx.fillStyle=color;
     ctx.fillRect(points[p][0] - 1,points[p][1] - 1,size - 2,size -2); 
   }
 }

}

function updateMap() {

 canvas = document.getElementById( 'myCanvas' );
 ctx = canvas.getContext( '2d' );
 img = new Image();
 img.src = '" + bg_url + "';

 if (!req_me) {
     req_me = true;
     $.getJSON('mypos',function(data){me = data;req_me=false;});
 }

 if (!req_people) {
   req_people = true;
   $.getJSON('avatars',function(data){people = data;req_people=false;});
 }

 ctx.save();
 if (img.complete) {
   ctx.drawImage( img, 0, 0, canvas.getAttribute('width'), canvas.getAttribute('height') );
 }

 plot(ctx,people,'#FF0000','#FFFFFF',5);
 plot(ctx,me,'#FFFFFF','#000000',7);
 ctx.restore();
 setTimeout( updateMap, 500 ); 

} </script><base href='" + url + "/' /></head> <body style='background: #FFFFFF; width: 100%; height: 100%; margin: 0px;' onLoad='updateMap();'> <canvas id='myCanvas' width='256' height='256' style='position:fixed; top:0px; left:0px;'> Canvas unsupported. </canvas></body></html>"; }

set_url(string url) {

   build_index(url);

   llSetLinkMedia(LINK_THIS, display_face,              // Side to display the media on.
           [PRIM_MEDIA_AUTO_PLAY,TRUE,     // Show this page immediately
            PRIM_MEDIA_CURRENT_URL,url,    // The url if they hit 'home'
            PRIM_MEDIA_HOME_URL,url,       // The url currently showing
            PRIM_MEDIA_HEIGHT_PIXELS,256,  // Height/width of media texture will be
            PRIM_MEDIA_WIDTH_PIXELS,256,   //   rounded up to nearest power of 2.
            PRIM_MEDIA_PERMS_CONTROL, PRIM_MEDIA_PERM_NONE]);

   llOwnerSay("Mem: " + (string)llGetUsedMemory());

}

default {

   state_entry() { llRequestURL(); }
   on_rez(integer i) { llResetScript(); }
   changed(integer c)
   {
       if (c & (CHANGED_REGION | CHANGED_TELEPORT | CHANGED_OWNER))
       { llResetScript(); }
   }

   http_request(key id, string method, string body)
   {
       if (method == URL_REQUEST_GRANTED)
       {
           set_url(body);
       }
       else if (method == URL_REQUEST_DENIED)
       {
           llOwnerSay("Failed to get url: " + body);
       }

       if (method == "GET")
       {
           list path = llParseString2List(llGetHTTPHeader(id,"x-path-info"),["/"],[]);

           if (llGetListLength(path) == 0)
           {
               llSetContentType(id,CONTENT_TYPE_HTML);

               llHTTPResponse(id,200,index_html);
           }
           else if (llList2String(path,0) == "mypos")
           {
               vector my_pos = llGetPos();
               llHTTPResponse(id,200,"" +  (string)((integer)my_pos.x) + "," + (string)(256 - (integer)my_pos.y) + "");
           }
           else if (llList2String(path,0) == "avatars")
           {
               list avatars = llGetAgentList(AGENT_LIST_REGION,[]);
           
               string body = "[";
               integer i;
               integer n = llGetListLength(avatars);
               for(i=0;i<n;++i)
               {
                   if (i != 0) body += ",";
                   vector pos = llList2Vector(llGetObjectDetails(llList2Key(avatars,i),[OBJECT_POS]),0);
                   body += "[" + (string)((integer)pos.x) + "," + (string)(256 - (integer)pos.y) + "]";
               }
               body += " ]";
                llHTTPResponse(id,200,body);
           }
       }
   }

} </lsl>