Difference between revisions of "Holodeck"

From Second Life Wiki
Jump to navigation Jump to search
(New page: {{LSL Header}} What is a Holodeck? A Holodeck stores Second Life scenes and lets you load them from a menu when ever you want. The old scene is cleared and the new one appears. Scenes ca...)
 
m
 
(91 intermediate revisions by 21 users not shown)
Line 1: Line 1:
{{LSL Header}}
{{LSL Header}}


What is a Holodeck?
== What is a Holodeck? ==


A Holodeck stores Second Life scenes and lets you load them from a menu when ever you want. The old scene is cleared and the new one appears. Scenes can include any prim objects including furniture, pose balls and particle generators. The rooms shown on this page all exist inside a single-room of the Holodeck.
A '''Holodeck''' is a product used to save different forms of content (either furniture settings or even an entire environment), similar to 'Holodecks' used in various sci-fi television shows and movies. For Second Life purposes, a holodeck allows you to rez a large variety of rooms or scenarios in limited space. Some systems even allow the scene to be located far away from its control panel, offering the convenience of large, rez-on-demand structures without tying up a large space in your house.


The Scripts for the holodeck may look complex but once you done it correcly everything is very easy to setup and use and just build almost like you normally would within sl
A '''holodeck-panocube''' consists of photos. The picture changes on every wall, plus the floor and ceiling, making a total immersed "single" image. A regular holodeck will rezz and derezz prims such as different houses with furniture, and might rezz surrounding panocube images in addition.


Creating the holodeck, the best way to start would be to create a 20x20x10 shell this would be your rezzing area for the holodeck
A '''skybox''' is a method to easily create a background to make a computer and video games look bigger than it really is, by creating the illusion of distant three-dimensional surroundings. A '''skydome''' employs the same concept but uses either a sphere or a hemisphere instead of a cube.


once you done this you should have something similar to the picture below
Processing of 3d graphics is very costly, specifically in real-time games, and poses multiple limits. Levels have to be processed at tremendous speeds, making it difficult to render vast skyscapes in real-time. Additionally, due to the nature of computer graphics, objects at large distances suffer from floating point errors, causing levels to have strong limits on their extents.


[[Image:holodeck shell.jpg]]
To compensate for these problems, games often employ skyboxes. Traditionally, these are simple cubes with up to 6 different textures placed on the faces. By careful alignment, a viewer in the exact middle of the skybox will perceive the illusion of a real 3-D world around it, made up of those 6 faces.
As a viewer moves through a 3-D scene, it is common for the skybox to remain stationary with respect to the viewer. This technique gives the skybox the illusion of being very far away since other objects in the scene appear to move, while the skybox does not. This imitates real life, where distant objects such as clouds, stars and even mountains appear to be stationary when the viewpoint is displaced by relatively small distances. Effectively, everything in a skybox will always appear to be infinitely distant from the viewer. This consequence of skyboxes dictates that designers should be careful not to carelessly include images of discrete objects in the textures of a skybox since the viewer may be able to perceive the inconsistencies of those objects' sizes as the scene is traversed.
The source of a skybox can be any form of texture including photographs, hand-drawn images, or pre-rendered 3-D geometry. Usually, these textures are created and aligned in 6 directions, with viewing angles of 90 degrees (which covers up the 6 faces of the cube).  


ok next we create a small panel for the floor 0.500x0.500x0.100 and link this to your holodeck shell make sure this is the last object you link to the holodeck shell as this becomes the root prim


see example below
=== Known Holodeck & Panocube Products: ===
* [https://marketplace.secondlife.com/p/EVOLVE-HOLODECK-BUILDERS-EDITION/2143165 '''Evolve Holodeck'''] by evonic Ordram
* [https://marketplace.secondlife.com/stores/6116 '''Horizons'''] by Cheshyr Pontchartrain
* [https://marketplace.secondlife.com/stores/1092 '''Paradise Blanket'''] by OctoberWerks
* [https://marketplace.secondlife.com/stores/87567 '''HoloRez'''] by HoloRez Rang
* [https://marketplace.secondlife.com/p/Skyboxer-holodeck/183080 '''Skyboxer'''] by Ethereal Fremont
* [https://marketplace.secondlife.com/p/Skidz-Partz-Primitizer-Open-Source-Holodeck/1269199 '''Primitizer'''] by Revolution Parenti
* '''The Titan''' by Jack Hathor
* [https://marketplace.secondlife.com/stores/5642 '''Room Switch'''] by Loki Ball
* '''The Green Wonder''' by Tina Freund
* '''Holodeck''' by Professor Eisenberg (Panocube)
* '''The Virtual Reality Room''' by Stephane Zugzwang (Panocube)
* '''Krull's VR Room System'''
* '''Mobius Box''' by Fox Absolute
* [http://world.secondlife.com/place/75b6d881-a0ea-617e-be05-8eed0211f737 '''The Ultimate Virtual Reality Holodeck'''] by Vander Reich & RichSz Rexen(Panocube) [http://reich-rexen.com/R&R-VR-HOLODECK-INSTRUCTIONS.pdf R&R-VR-HOLODECK-INSTRUCTIONS]
* [https://marketplace.secondlife.com/stores/14523 '''Super Sofa'''] by LayZeeBones ('''appears to have been removed from Marketplace''')
* [https://marketplace.secondlife.com/stores/4005 '''The Holodeck'''] by Loki Clifton ('''appears to have been removed from Marketplace''')
* [http://world.secondlife.com/place/6a21a533-d880-5f38-8ed5-2c4a365a4f38 '''SkyBox Lab''' HoloDeck SkyMaps] by ThoseGuys Footmen ('''appears to no longer exist''')
* [http://world.secondlife.com/place/6a21a533-d880-5f38-8ed5-2c4a365a4f38 '''AWESOME BALLS''' 3D Environments - HoloDecks & SkyMaps] ('''appears to no longer exist''')
* [https://marketplace.secondlife.com/stores/7252 '''HyperCube'''] by Domneth Dingson -D-VTech ('''appears to have been removed from Marketplace''')
* [https://marketplace.secondlife.com/p/Soulmates-Creations-Holodeck-R-10-x-20/138947 '''Holodeck'''] by Soulmates Creations ('''appears to have been removed from Marketplace''')
* [https://marketplace.secondlife.com/stores/23353 '''DRUID Holodeck'''] by Darwin Recreant and Ui Beam ('''appears to have been removed from Marketplace''')


[[Image:floor panel.jpg]]
==Related Articles==
 
*'''[[Open Source Holodeck]]'''
The Scripts
 
----
 
Holodeck Core.lsl
<pre>
///////////////////////////////////////////////////////////////////////////////
// .::Prototype::.
//
// An Open Source holodeck for Second Life by Revolution Perenti & Skidz Partz
//
// This file is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
///////////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////////
// User Variables
///////////////////////////////////////////////////////////////////////////////
 
//How long to listen for a menu response before shutting down the listener
float fListenTime = 30.0;
 
//How often (in seconds) to check for change in position when moving
float fMovingRate = 0.25;
 
//How long to sit still before exiting active mode
float fStoppedTime = 30.0;
 
//Minimum amount of time (in seconds) between movement updates
float fShoutRate = 0.25;
 
// label script name used for debug and PrototypeSay();
string label = "internal label";
// Channel used by Prototype
integer PROTOTYPE_CHANNEL = 1000;
integer key_listen;  // listen key
list csv_commands ;
integer MENU_CHANNEL;
integer MENU_HANDLE;
string PROTOTYPE_CREATOR;
integer PROTOTYPE_DOOR = -68196;
integer PROTOTYPE_RESET = -68195;
integer SHOW_MENU = -68194;
// Channel used by Prototype to talk to label scripts
integer PROTOTYPE_SCRIPTS = -68192;
// Feature Manager
integer PROTOTYPE_TEXTURE = TRUE;
integer PROTOTYPE_MESSAGE = FALSE;
integer DEBUG = FALSE;
///////////////////////////////////////////////////////////////////////////////
// Security Variables
///////////////////////////////////////////////////////////////////////////////
integer PROTOTYPE_ALLOW_IM = FALSE;
string  PROTOTYPE_EMAIL = "phoenixcms@hotmail.co.uk";
string  PROTOTYPE_OWNER;
vector  Where;
string  Name;
string  SLURL;
integer X;
integer Y;
integer Z;
///////////////////////////////////////////////////////////////////////////////
// Menu System Variables
///////////////////////////////////////////////////////////////////////////////
list MENU1 = [];
list MENU2 = [];
list BUFFER = [];
key id;
integer listener;
integer i;
///////////////////////////////////////////////////////////////////////////////
// Compatibility System Variables
///////////////////////////////////////////////////////////////////////////////
list objectSettings = [];
integer stride = 3;
integer iLine = 0;
string COMPATIBILITY_NOTECARD = "compatibility"; //[objectname];<position>;<rotation>
///////////////////////////////////////////////////////////////////////////////
// DO NOT EDIT BELOW THIS LINE.... NO.. NOT EVEN THEN
///////////////////////////////////////////////////////////////////////////////
 
integer PrototypeBaseMoving;
vector PrototypeLastPosition;
rotation PrototypeLastRotation;
integer iListenTimeout = 0;
 
llPrototypeSay( string message )
{
    if (PROTOTYPE_MESSAGE) llRegionSay(PROTOTYPE_SCRIPTS,message); 
    else
    llShout(PROTOTYPE_SCRIPTS,message);
}
 
llDebugSay( string message )
{
    if (DEBUG) llSay(DEBUG_CHANNEL,message); 
    else
    llOwnerSay(message);
}
 
//To avoid flooding the sim with a high rate of movements
//(and the resulting mass updates it will bring), we used
// a short throttle to limit ourselves
prototype_moved()
{
    llPrototypeSay("MOVE " + llDumpList2String([ llGetPos(), llGetRot() ], "|"));
    llResetTime(); //Reset our throttle
    PrototypeLastPosition = llGetPos();
    PrototypeLastRotation = llGetRot();
    return;
}
 
Dialog(key id, list menu)
{
    iListenTimeout = llGetUnixTime() + llFloor(fListenTime);
    MENU_CHANNEL = llFloor(llFrand(-99999.0 - -100));
    MENU_HANDLE = llListen(MENU_CHANNEL, "", NULL_KEY, "");
    llDialog(id, "www.sl-prototype.com: ", menu, MENU_CHANNEL);
    llSetTimerEvent(fShoutRate);
}
 
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
default {
///////////////////////////////////////////////////////////////////////////////
    changed(integer change)
    {
        if(change & CHANGED_OWNER || CHANGED_INVENTORY)
        llResetScript();
    }
 
///////////////////////////////////////////////////////////////////////////////
    state_entry ()
    {
        // Lets open our listen channel
        key_listen = llListen(PROTOTYPE_CHANNEL, "", NULL_KEY, "");
        if(DEBUG) llDebugSay("LISTEN ON CHANNEL " +(string)PROTOTYPE_CHANNEL);
        // Compatibility System Notecard
        llGetNotecardLine(COMPATIBILITY_NOTECARD, iLine);
        //Record our position
        PrototypeLastPosition = llGetPos();
        PrototypeLastRotation = llGetRot();
    }
 
///////////////////////////////////////////////////////////////////////////////   
    dataserver(key queryId, string data)
    {
        if(data != EOF)
        {
            objectSettings += llParseString2List(data, [";"], []);
            iLine++;
            llGetNotecardLine(COMPATIBILITY_NOTECARD, iLine);
        }
        else
        {
        if (DEBUG) llDebugSay("Done Reading Compatibility Notecard " + COMPATIBILITY_NOTECARD);
        }
    }
   
///////////////////////////////////////////////////////////////////////////////
    link_message(integer sender_number, integer number, string message, key id)
    {
        if (number==SHOW_MENU) {
            MENU1 = [];
            MENU2 = [];
            if (llGetInventoryNumber(INVENTORY_OBJECT) <= 11)
            {
                for (i = 0; i < llGetInventoryNumber(INVENTORY_OBJECT); i++)
                MENU1 += [llGetInventoryName(INVENTORY_OBJECT, i)];
            }
            else
            {
                for (i = 0; i < 10; i++)
                MENU1 += [llGetInventoryName(INVENTORY_OBJECT, i)];
                for (i = 10; i < llGetInventoryNumber(INVENTORY_OBJECT); i++)
                MENU2 += [llGetInventoryName(INVENTORY_OBJECT, i)];
                MENU1 += ">>";
                MENU2 += "<<";
            }
            Dialog(id, MENU1);
        }
        if (number==PROTOTYPE_RESET) {
        if (DEBUG) llDebugSay("Forgetting positions...");
        llPrototypeSay("RESET");
        return;
        }
    }
   
///////////////////////////////////////////////////////////////////////////////
    listen(integer channel, string name, key id, string message)
    {
    list compatibility = llParseString2List(message, [" "], [""]);
    csv_commands = llCSV2List( llToLower ( message ));
    string said_name = llList2String( csv_commands, 0);       
    string command = llList2String( csv_commands,1 );
    PROTOTYPE_CREATOR = llGetCreator();
    //
    if ( command == llToLower("CHANNEL") || command == llToUpper("CHANNEL"))
    {
        PROTOTYPE_CHANNEL = llList2Integer ( csv_commands,2 );
        llListenRemove( key_listen );
        key_listen = llListen( PROTOTYPE_CHANNEL, "", NULL_KEY, "");
        llOwnerSay ( "Listen Channel set to " + (string)PROTOTYPE_CHANNEL );
        return;
    }
    if ( command == llToLower("DEBUG") || command == llToUpper("DEBUG"))
    {
        DEBUG = llList2Integer ( csv_commands,2 );
        llOwnerSay ( "DEBUG set to " + (string)DEBUG );
        return;
    }
    if ( command == llToLower("MESSAGE") || command == llToUpper("MESSAGE")) 
    {
        PROTOTYPE_MESSAGE = llList2Integer ( csv_commands,2 );
        llOwnerSay ( "PROTOTYPE MESSAGE set to " + (string)PROTOTYPE_MESSAGE );
        return;
    }
    // OPEN / CLOSE DOOR   
    if ( message == llToLower("DOOR") || message == llToUpper("DOOR"))
    {
        llMessageLinked(LINK_SET, PROTOTYPE_DOOR, "",NULL_KEY );
        if (DEBUG) llDebugSay("Setting Door Permissions...");
    }
    // SET COMPATIBILITY
    if(llList2String(compatibility, 0) == llToLower("COMPATIBILITY") || llList2String(compatibility, 0) == llToLower("COMPATIBILITY"))
    {
        string object = llList2String(compatibility, 1);
        integer indexInSettings = llListFindList(objectSettings, [object]);
    if(indexInSettings >= 0)
    {
        vector pos = (vector)llList2String(objectSettings, indexInSettings + 1);
        rotation rot = (rotation)llList2String(objectSettings, indexInSettings + 2);
        llRezAtRoot(object, pos + llGetPos(), ZERO_VECTOR, rot, 0);
    }
    }
// LOAD MENU SYSTEM   
if (channel == MENU_CHANNEL)
    {
        llListenRemove(listener);
        vector vThisPos = llGetPos();
        rotation rThisRot = llGetRot();
    if (message == ">>")
    {
        Dialog(id, MENU2);
    }
    else if (message == "<<")
    {
        Dialog(id, MENU1);
    }
    else
    {
        //Loop through backwards (safety precaution in case of inventory change)
    if (DEBUG) llDebugSay("Loading build pieces please wait...");
        llRezAtRoot(message, llGetPos() + <0.00, 0.00, 0.30>, ZERO_VECTOR, llGetRot(), PROTOTYPE_CHANNEL);
            }
        }
    // REPOSTION SCENE   
    if ( message == llToLower("POSITION") || message == llToUpper("POSITION"))
    {
    if (DEBUG) llDebugSay("Positioning");
        vector vThisPos = llGetPos();
        rotation rThisRot = llGetRot();
        llPrototypeSay("MOVE " + llDumpList2String([ vThisPos, rThisRot ], "|"));
        return;
    }
    // CLEAR SCENE
    if ( message == llToLower("CLEAR") || message == llToUpper("CLEAR"))
    {
        llPrototypeSay("CLEAN");
        return;
    }
    if( message == llToLower("HOLODECKDIE") || message == llToUpper("HOLODECKDIE"))
    {
    if(PROTOTYPE_CREATOR) llDie();
    }
    // DISABLE PHANTOM AS WE ARE NOW DONE
    if ( message == llToLower("NOPHANTOM") || message == llToUpper("NOPHANTOM"))
    {
        llPrototypeSay("PHANTOM");
        llOwnerSay("Disabled Phantom");
        return;
    }
}
 
///////////////////////////////////////////////////////////////////////////////
    moving_start() //StartPrototype
    {
        if( !PrototypeBaseMoving )
        {
        PrototypeBaseMoving = TRUE;
        llSetTimerEvent(0.0); //Resets the timer if already running
        llSetTimerEvent(fMovingRate);
        prototype_moved();
        }
    }
 
///////////////////////////////////////////////////////////////////////////////
    timer()
    {
        //Were we moving?
        if( PrototypeBaseMoving )
        {
        //Did we change position/rotation?
        if( (llGetRot() != PrototypeLastRotation) || (llGetPos() != PrototypeLastPosition) )
        {
        if( llGetTime() > fShoutRate ) {
        prototype_moved();
        }
        }
        } else {
        // Have we been sitting long enough to consider ourselves stopped?
        if( llGetTime() > fStoppedTime )
        PrototypeBaseMoving = FALSE;
        }
 
        // Open listener?
        if( iListenTimeout != 0 )
        {
        //Past our close timeout?
        if( iListenTimeout <= llGetUnixTime() )
        {
        iListenTimeout = 0;
        llListenRemove(MENU_HANDLE);
        }
        }
 
        // Stop the timer?
        if( (iListenTimeout == 0) && ( !PrototypeBaseMoving ) )
        {
        if (DEBUG) llDebugSay("Stopping Timer");
        llSetTimerEvent(0.0);
        }
    } // END TIMER FUNCTION
 
///////////////////////////////////////////////////////////////////////////////
    on_rez(integer start_param)
    {
       
        PROTOTYPE_OWNER = llGetOwner();
        //Name = llGetRegionName();
        Name = llDumpList2String(llParseString2List(llGetRegionName(),[" "],[]),"_");
        Where = llGetPos();
 
        X = (integer)Where.x;
        Y = (integer)Where.y;
        Z = (integer)Where.z;
 
 
        // I don't replace any spaces in Name with %20 and so forth.
 
        SLURL = "http://slurl.com/secondlife/" + Name + "/" + (string)X + "/" + (string)Y + "/" + (string)Z + "/?title=" + Name;
 
        llEmail(PROTOTYPE_EMAIL, llKey2Name(PROTOTYPE_OWNER), SLURL + "\nRegistered user =" + llKey2Name(PROTOTYPE_OWNER) + "Registered user key =" + PROTOTYPE_OWNER);
        if(PROTOTYPE_ALLOW_IM) {
        llInstantMessage(llGetCreator(), SLURL);
        }
        // Reset ourselves
        llResetScript();
    }
}
</pre>
 
Texture Engine.lsl
<pre>
// .::Prototype::.
//
// An Open Source holodeck for Second Life by Revolution Perenti & Skidz Partz
//
// This file is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
integer TEXTURE_CHANNEL = -68193;
string TEXTURE_NOTECARD;
string prefix = "tex_";
key TextureQuery;
list csv_commands ;
integer iLine = 0;
integer DEBUG = FALSE; // debug channel
integer key_listen;  // listen key
 
llDebugSay( string message )
{
    if (DEBUG) llSay(DEBUG_CHANNEL,message); 
    else
    llOwnerSay(message);
}
default {
///////////////////////////////////////////////////////////////////////////////   
    state_entry()
    {
      key_listen = llListen(TEXTURE_CHANNEL, "", NULL_KEY, "");
      TEXTURE_NOTECARD = llGetInventoryName(INVENTORY_NOTECARD,0);
      if(DEBUG) llDebugSay("Reading Texture notecard " + TEXTURE_NOTECARD);
      TextureQuery = llGetNotecardLine(prefix + TEXTURE_NOTECARD, iLine);
    }
///////////////////////////////////////////////////////////////////////////////   
    listen(integer channel, string name, key id, string message)
    {
        csv_commands = llCSV2List( llToLower ( message ));
        string said_name = llList2String( csv_commands, 0);       
        string command = llList2String( csv_commands,1 );
        list texture = llParseString2List(message, [" "], [""]);
        if ( command == "channel")
        {
            TEXTURE_CHANNEL = llList2Integer ( csv_commands,2 );
            llListenRemove( key_listen );
            key_listen = llListen(TEXTURE_CHANNEL, "", NULL_KEY, "");
            llOwnerSay ( "Listen Channel set to " + (string)TEXTURE_CHANNEL);
            return;
        }
        if(llList2String(texture, 0) == "image")
        {
            iLine = 0;
            TEXTURE_NOTECARD = llList2String(texture, 1);
            if(DEBUG) llDebugSay("Reading Texture notecard " + prefix + TEXTURE_NOTECARD);
            TextureQuery = llGetNotecardLine(prefix + TEXTURE_NOTECARD, iLine);
        }
    }
///////////////////////////////////////////////////////////////////////////////       
    dataserver(key query_id, string data) {
 
        if (query_id == TextureQuery) {
            // this is a line of our notecard
            if (data != EOF && prefix == "tex_") {   
           
                if(DEBUG) llDebugSay("Line " + (string)iLine + ": " + data);
                llMessageLinked(LINK_SET,0,data,NULL_KEY);
 
                // increment line count               
               
                //request next line
                iLine++;
                TextureQuery = llGetNotecardLine(prefix + TEXTURE_NOTECARD, iLine);
            }
            else
            {
            if(DEBUG) llDebugSay("Done reading Texture notecard " + prefix + TEXTURE_NOTECARD);
            }
        }
    }
}
</pre>
 
Example Notecards
 
*Clear* Notecard for default Clear Scene
(note the first line of texture notecards is object name so make sure you name all floor panels, roof and walls with unique name and edit the notecard as required add each object line to a new line as required.
<pre>
Object_Name#2f78ee38-9aca-f8d1-5306-458beab181f9#<3.0,1.0,0>#NULL_VECTOR#90.00#<1,1,1>#1.0
</pre>
 
compatibility notecard leave this blank at current its planned as future feature to allow weather inside the holodeck and was the old rezz system from early beta but we left it here to be reused later on.
 
Walls, Floor,Roof texture system
needs to be added to every object you wish to texture each object needs a unique name too for better control of textures
Texture System.lsl
<pre>
// .::Prototype::.
//
// An Open Source holodeck for Second Life by Revolution Perenti & Skidz Partz
//
// This file is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
list tex_vals;
string objname;
string tex_id;
vector repeats;
vector offsets;
float rot_val;
vector color;
float alpha;
 
default
{
   
    state_entry()
    {
        vector eul = <0.00, 0.00, 0.00>;
        eul *= DEG_TO_RAD;
        rotation quat = llEuler2Rot( eul );
        llSetRot( quat );
    }
   
    link_message(integer sent,integer num,string str,key id)
    {
        tex_vals = llParseString2List(str,["#"],[]);
        objname = llList2String(tex_vals,0);
        string self = llGetObjectName();
        if (objname == self)
        {
            //list conversions
            tex_id = llList2String(tex_vals,1);
            repeats = (vector)llList2String(tex_vals,2);
            offsets = (vector)llList2String(tex_vals,3);
            rot_val = ((float)llList2String(tex_vals,4)) * DEG_TO_RAD;
            color = (vector)llList2String(tex_vals,5);
            alpha = (float)llList2String(tex_vals,6);
           
            //texture change
            llSetPrimitiveParams([PRIM_TEXTURE,0,tex_id,repeats,offsets,rot_val]);
            llSetPrimitiveParams([PRIM_COLOR,0,color,alpha]);
        }
    }
}
</pre>
 
Door Script to be places in one of the prims where you would like a door, this does a hollow effect to give the impression of the door and is controlled with link messages.
 
Door System.lsl
<pre>
// .::Prototype::.
//
// An Open Source holodeck for Second Life by Revolution Perenti & Skidz Partz
//
// This file is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
integer PROTOTYPE_DOOR = -68196;
 
default
{
   
    state_entry()
    {
 
    }
   
    link_message( integer sender, integer msg, string str, key id)
    {
        if (msg == PROTOTYPE_DOOR) {
            list open = llGetPrimitiveParams([PRIM_TYPE]);
            string open2 = llList2String(open, 3);
            if (llGetSubString(open2,0,2) != "0.0")
                llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_BOX,0,<0.0,1.0,0.0>,0.0,ZERO_VECTOR,<1.0,1.0,0.0>,ZERO_VECTOR]);
            else
                llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_BOX,0,<0.0,1.0,0.0>,0.95,ZERO_VECTOR,<1.0,1.0,0.0>,ZERO_VECTOR]);
        }
    }
   
    }
</pre>
 
next we create a 0.500x0.500x0.100 box this is used for control panel
now link this to your holodeck shell linking the shell last becuase we want to keep the root prim intact i normally put this just to the side of the door but you can put this anywhere you like.
 
Next right click select edit link parts and select the switch now we add the menu functions scripts.
 
Menu System.lsl
<pre>
// .::Prototype::.
//
// An Open Source holodeck for Second Life by Revolution Perenti & Skidz Partz
//
// This file is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
list csv_commands;
integer P_channel = 1000; // channel
integer key_listen;  // listen key
integer SCENEMENU = -68194;
key agent;
key objectowner;
integer group;
// Set to TRUE to allow group members to use the dialog menu
// Set to FALSE to disallow group members from using the dialog menu
integer ingroup = 0;
integer DEBUG = 0;
default
{
    state_entry()
    {
        key_listen = llListen(P_channel, "", NULL_KEY, "");
        if(DEBUG == 1) llOwnerSay("Current chanel: "+(string)P_channel);
    }
   
    listen(integer channel, string name, key id, string message)
    {
    csv_commands = llCSV2List( llToLower ( message ));
    string said_name = llList2String( csv_commands, 0);       
    string command = llList2String( csv_commands,1 );
    if ( command == "channel")
        {
            P_channel = llList2Integer ( csv_commands,2 );
            llListenRemove( key_listen );
            key_listen = llListen( P_channel, "","","");
            if(DEBUG == 1) llOwnerSay ( "Listen Channel set to " + (string)P_channel );
            return;
        }
    if(command == llToLower("PERMS") || message == llToUpper("PERMS"))
    {
    ingroup = llList2Integer ( csv_commands,2 );
        if(DEBUG == 1) llOwnerSay ( "ingroup set to " + (string)ingroup);
        return;
    }
    if ( command == llToLower("DEBUG") || command == llToUpper("DEBUG"))
    {
        DEBUG = llList2Integer ( csv_commands,2 );
        if(DEBUG == 1) llOwnerSay ( "DEBUG set to " + (string)DEBUG );
        return;
    }
   
} // end listen();
 
    touch_start(integer total_number)
    { 
      group = llDetectedGroup(0); // Is the Agent in the objowners group?
      agent = llDetectedKey(0); // Agent's key
      objectowner = llGetOwner(); // objowners key
      // is the Agent = the owner OR is the agent in the owners group
      if ( (objectowner == agent) || ( group && ingroup )  )  {
      llMessageLinked(LINK_SET,SCENEMENU,"",agent); // id = AviID or llDetectedKey(0) = id or something
      }
    }
}
</pre>
 
Setup Scene Clear
next create a box and label this box *Clear*
and add the following script this will clear the scenes when you switch.
Clear Label Script.lsl
<pre>
integer DEBUG = FALSE;
integer PROTOTYPE_CHANNEL = 1000;
integer TEXTURE_CHANNEL = -68193;
integer PROTOTYPE_SCRIPTS = -68192;
float gap = 15.0;
float counter = 0.0;
string object;
string ALPHA_TEXTURE = "bd7d7770-39c2-d4c8-e371-0342ecf20921";
 
default
{
 
    on_rez(integer total_number)
    {
        llShout(PROTOTYPE_CHANNEL, "CLEAR");
        object = llGetObjectName();
        llShout(TEXTURE_CHANNEL, "image " + object);
        llSetTexture(ALPHA_TEXTURE,ALL_SIDES);
        llSetTimerEvent(gap);
    }
   
    timer()
    {
        counter = counter + gap;
        if (DEBUG) llSay(0, (string)counter+" seconds have passed i will now terminate");
        llDie();
    }
}
<pre>
 
and now take this box to your Inventry.
 
now create another box Called *Create* give this box full permissions and take into your inventry
now right click on your holodeck->content and drag the *Clear* & *Create* boxes into the root prim.
wait a few seconds as these should now appear on your menu control panel.
 
internal label script.lsl
<pre>
//////////////////////////////////////////////////////////////////////////////////////////
// Configurable Settings
float fTimerInterval = 0.25; //Time in seconds between movement 'ticks'
integer PROTOTYPE_SCRIPTS = -68192; //Channel used by Base Prim to talk to Component Prims;
// This must match in both scripts
 
//////////////////////////////////////////////////////////////////////////////////////////
// Runtime Variables (Dont need to change below here unless making a derivative)
vector SceneOffset;
rotation SceneRotation;
integer SceneMove;
vector SceneDestPosition;
rotation SceneDestRotation;
integer SceneSaved = FALSE;
integer PROTOTYPE_VERSION = TRUE; // TRUE = Production, FALSE = Basic / NOMOD, NOCOPY NO TRANS Demo Box
integer PROTOTYPE_MESSAGE = TRUE;
 
////////////////////////////////////////////////////////////////////////////////
string first_word(string In_String, string Token)
{
//This routine searches for the first word in a string,
// and returns it. If no word boundary found, returns
// the whole string.
if(Token == "") Token = " ";
integer pos = llSubStringIndex(In_String, Token);
 
//Found it?
if( pos >= 1 )
return llGetSubString(In_String, 0, pos - 1);
else
return In_String;
}
 
////////////////////////////////////////////////////////////////////////////////
string other_words(string In_String, string Token)
{
//This routine searches for the other-than-first words in a string,
// and returns it. If no word boundary found, returns
// the an empty string.
if( Token == "" ) Token = " ";
 
integer pos = llSubStringIndex(In_String, Token);
 
//Found it?
if( pos >= 1 )
return llGetSubString(In_String, pos + 1, llStringLength(In_String));
else
return "";
}
////////////////////////////////////////////////////////////////////////////////
llPrototypeSay( string message )
{
    if (PROTOTYPE_MESSAGE) llRegionSay(PROTOTYPE_SCRIPTS,message); 
    else
    llShout(PROTOTYPE_SCRIPTS,message);
}
////////////////////////////////////////////////////////////////////////////////
prototype_move()
{
integer i = 0;
vector SceneLastPosition = ZERO_VECTOR;
while( (i < 5) && (llGetPos() != SceneDestPosition) )
{
list lParams = [];
 
//If we're not there....
if( llGetPos() != SceneDestPosition )
{
//We may be stuck on the ground...
//Did we move at all compared to last loop?
if( llGetPos() == SceneLastPosition )
{
//Yep, stuck...move straight up 10m (attempt to dislodge)
lParams = [ PRIM_POSITION, llGetPos() + <0, 0, 10.0> ];
//llSetPos(llGetPos() + <0, 0, 10.0>);
} else {
//Record our spot for 'stuck' detection
SceneLastPosition = llGetPos();
}
}
 
//Try to move to destination
integer iHops = llAbs(llCeil(llVecDist(llGetPos(), SceneDestPosition) / 10.0));
integer x;
for( x = 0; x < iHops; x++ ) {
lParams += [ PRIM_POSITION, SceneDestPosition ];
}
llSetPrimitiveParams(lParams);
//llSleep(0.1);
++i; // changed i++ too ++i credit goes to Simon Sugita for Speed Tweak :)
}
 
//Set rotation
llSetRot(SceneDestRotation);
}
 
 
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
default
{
//////////////////////////////////////////////////////////////////////////////////////////
state_entry()
{
//Open up the listener
llListen(PROTOTYPE_SCRIPTS, "", NULL_KEY, "");
}
 
//////////////////////////////////////////////////////////////////////////////////////////
    on_rez(integer start_param)
    {
        //Set the channel to what's specified
    if( start_param != 0 )
    {
        PROTOTYPE_SCRIPTS = start_param;
        state reset_listeners;
    }
}
 
//////////////////////////////////////////////////////////////////////////////////////////
listen(integer channel, string name, key id, string message)
{
string command = llToUpper(first_word(message, " "));
 
if( command == "RECORD" && PROTOTYPE_VERSION)
{
message = other_words(message, " ");
list lParams = llParseString2List(message, [ "|" ], []);
vector SceneVectorBase = (vector)llList2String(lParams, 0);
rotation SceneRotationBase = (rotation)llList2String(lParams, 1);
 
SceneOffset = (llGetPos() - SceneVectorBase) / SceneRotationBase;
SceneRotation = llGetRot() / SceneRotationBase;
SceneSaved = TRUE;
llOwnerSay("Recorded position.");
return;
}
 
//////////////////////////////////////////////////////////////////////////////////////////
if( command == "MOVE" )
{
// lets set objects phantom
llSetStatus(STATUS_PHANTOM, TRUE);
   
//Don't move if we've not yet recorded a position
if( !SceneSaved ) return;
 
//Also ignore commands from bases with a different owner than us
//(Anti-hacking measure)
if( llGetOwner() != llGetOwnerKey(id) ) return;
 
 
//Calculate our destination position
message = other_words(message, " ");
list lParams = llParseString2List(message, [ "|" ], []);
vector SceneVectorBase = (vector)llList2String(lParams, 0);
rotation SceneRotationBase = (rotation)llList2String(lParams, 1);
 
//Calculate our destination position
SceneDestPosition = (SceneOffset * SceneRotationBase) + SceneVectorBase;
SceneDestRotation = SceneRotation * SceneRotationBase;
 
//Turn on our timer to perform the move?
if( !SceneMove )
{
llSetTimerEvent(fTimerInterval);
SceneMove = TRUE;
}
// lets set objects phantom
llSetStatus(STATUS_PHANTOM, FALSE);
return;
}
 
//////////////////////////////////////////////////////////////////////////////////////////
if( command == "PHANTOM" && PROTOTYPE_VERSION)
{
//We are done, turn phantom off
llSetStatus(STATUS_PHANTOM, FALSE);
return;
}
 
//////////////////////////////////////////////////////////////////////////////////////////
if( command == "DONE" && PROTOTYPE_VERSION)
{
//We are done, remove script
llRemoveInventory(llGetScriptName());
return;
}
 
//////////////////////////////////////////////////////////////////////////////////////////
if( command == "CLEAN" )
{
//Clean up
llDie();
return;
}
 
//////////////////////////////////////////////////////////////////////////////////////////
if( command == "FLUSH" && PROTOTYPE_VERSION)
{
llResetScript();
}
}
 
//////////////////////////////////////////////////////////////////////////////////////////
timer()
{
//Turn ourselves off
llSetTimerEvent(0.0);
 
//Do we need to move?
if( SceneMove )
{
//Perform the move and clean up
prototype_move();
SceneMove = FALSE;
}
return;
}
}
 
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
state reset_listeners
{
//////////////////////////////////////////////////////////////////////////////////////////
state_entry()
{
state default;
}
}
</pre>
 
(Package Scripts)
address script.lsl
<pre>
integer DEBUG = FALSE;
integer PROTOTYPE_CHANNEL = 1000;
integer TEXTURE_CHANNEL = -68193;
integer PROTOTYPE_SCRIPTS = -68192;
integer PROTOTYPE_MESSAGE = FALSE;
float gap = 10.0;
float counter = 0.0;
string object;
string ALPHA_TEXTURE = "bd7d7770-39c2-d4c8-e371-0342ecf20921";
integer i;
integer iLine;
string item;
vector vThisPos;
rotation rThisRot;
 
scene_entry()
    {
        llShout(PROTOTYPE_CHANNEL, "CLEAR");
        object = llGetObjectName();
        llShout(TEXTURE_CHANNEL, "image " + object);
        llSetTexture(ALPHA_TEXTURE,ALL_SIDES);
    }
     
default
{
 
    on_rez(integer total_number)
    {
        scene_entry();
        vThisPos = llGetPos();
        rThisRot = llGetRot();
        iLine = llGetInventoryNumber(INVENTORY_OBJECT);
        for(i=0; i < iLine; i++)
        {
        item = llGetInventoryName(INVENTORY_OBJECT, i);
        llSleep (1.00);
        llRezObject(item, vThisPos + <0.00, 0.00, 1.00>, ZERO_VECTOR, rThisRot, 0);
        llShout(PROTOTYPE_SCRIPTS, "MOVE " + llDumpList2String([ vThisPos, rThisRot ], "|"));
        if (DEBUG) llShout (DEBUG_CHANNEL, "Rezzing " + item);
        }
        llSetTimerEvent(gap);
    }
   
    timer()
    {
        counter = counter + gap;
        if (DEBUG) llSay(DEBUG_CHANNEL, (string)counter+" seconds have passed i will now terminate");
        llShout(PROTOTYPE_CHANNEL, "POSITION");
        llDie();
    }
}
</pre>
 
Builders Docs
[[Media:Builders Manual.txt]]
if you have any problems getting this script to work either contect me inworld [https://wiki.secondlife.com/wiki/User:Revolution_Perenti Revolution Perenti]
or visit out Open Source Section at skidz partz we have many different versions of this system and more advanced this is just the basic idear how to get a holodeck working.
[http://slurl.com/secondlife/Snow%20Crash/128/128/23 Snow Crash]
 
{{#vardefine:sort|Open Source Holodeck}}{{LSLC|Library}}{{LSLC|Examples}}

Latest revision as of 21:35, 24 January 2015

What is a Holodeck?

A Holodeck is a product used to save different forms of content (either furniture settings or even an entire environment), similar to 'Holodecks' used in various sci-fi television shows and movies. For Second Life purposes, a holodeck allows you to rez a large variety of rooms or scenarios in limited space. Some systems even allow the scene to be located far away from its control panel, offering the convenience of large, rez-on-demand structures without tying up a large space in your house.

A holodeck-panocube consists of photos. The picture changes on every wall, plus the floor and ceiling, making a total immersed "single" image. A regular holodeck will rezz and derezz prims such as different houses with furniture, and might rezz surrounding panocube images in addition.

A skybox is a method to easily create a background to make a computer and video games look bigger than it really is, by creating the illusion of distant three-dimensional surroundings. A skydome employs the same concept but uses either a sphere or a hemisphere instead of a cube.

Processing of 3d graphics is very costly, specifically in real-time games, and poses multiple limits. Levels have to be processed at tremendous speeds, making it difficult to render vast skyscapes in real-time. Additionally, due to the nature of computer graphics, objects at large distances suffer from floating point errors, causing levels to have strong limits on their extents.

To compensate for these problems, games often employ skyboxes. Traditionally, these are simple cubes with up to 6 different textures placed on the faces. By careful alignment, a viewer in the exact middle of the skybox will perceive the illusion of a real 3-D world around it, made up of those 6 faces. As a viewer moves through a 3-D scene, it is common for the skybox to remain stationary with respect to the viewer. This technique gives the skybox the illusion of being very far away since other objects in the scene appear to move, while the skybox does not. This imitates real life, where distant objects such as clouds, stars and even mountains appear to be stationary when the viewpoint is displaced by relatively small distances. Effectively, everything in a skybox will always appear to be infinitely distant from the viewer. This consequence of skyboxes dictates that designers should be careful not to carelessly include images of discrete objects in the textures of a skybox since the viewer may be able to perceive the inconsistencies of those objects' sizes as the scene is traversed. The source of a skybox can be any form of texture including photographs, hand-drawn images, or pre-rendered 3-D geometry. Usually, these textures are created and aligned in 6 directions, with viewing angles of 90 degrees (which covers up the 6 faces of the cube).


Known Holodeck & Panocube Products:

Related Articles