Advertisement
artemx32

starfallEx non-textured mesh loader

Jan 22nd, 2025
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 30.11 KB | None | 0 0
  1. --@name MODULE_ComplexMeshLoader
  2. --@author artybyte
  3. --@client
  4.  
  5. -- module for coroutine loading of complex objects consists of multiple meshes with different properties and functions
  6.  
  7. --[[
  8.     made ON and FOR StarfallEx
  9.  
  10.                                                     Guide :: how to use this module                      READ THIS BEFORE USE
  11.  
  12.  
  13.  
  14.  
  15.     This module should to use in clientside case. It runs on client.
  16.    
  17.     >> INCLUDING
  18.    
  19.     to include this module add these lines to start of your chip:
  20.     >>
  21.     --@include module/module_complexmeshloader.txt
  22.     require('module/module_complexmeshloader.txt')
  23.     >>
  24.  
  25.     Now it's ready to go. Then you should get the module table. add in code this line
  26.     ComplexMeshLoader = MODULE__GetComplexMeshLoader()  -- get module table
  27.    
  28.    
  29.     >> USAGE
  30.    
  31.     now we ready to use it. Using of module splitted to some steps
  32.    
  33.     ==================================================================================================================================================================================
  34.     1) set your host URL of models.
  35.     ComplexMeshLoader.SetHostURL("http://55.55.55.55:22222/") (slash ("/") symbol is NECESSARY in this URL. Keep it in mind.
  36.    
  37.     when module will start download models, it will concatenate this URL + "obj_name"
  38.    
  39.     ==================================================================================================================================================================================
  40.     2) set base parent of your meshes. If you will not provide parent_params, hologram will be parented to base parent.
  41.     (UNNECESSARY)
  42.    
  43.     chip() is default.
  44.    
  45.     ComplexMeshLoader.SetBaseParent(entity(101))
  46.    
  47.     ==================================================================================================================================================================================
  48.     3) push all your mesh parts to module. Example:
  49.    
  50.     ComplexMeshLoader.PushComponent( {
  51.         obj_name="vehicle_body.obj",
  52.         mat="models/shiny",
  53.         local_pos=Vector(0, 0.5, 14.3),
  54.         local_ang=Angle(90,0,0),
  55.         color=Color(100, 200, 200),
  56.         part_name="body"
  57.     } )
  58.    
  59.     About fields of part (component):
  60.     3.1) obj_name (NECESSARY)           - string name of your .obj file. It should match with file name on provided host (URL)
  61.     3.2) mat (UNNECESSARY)              - string of material of mesh. (default game materials or addon materials)
  62.     3.3) local_pos (UNNECESSARY)        - local position offset relatively the Base Parent. 0, 0, 0, if not provided
  63.     3.4) local_ang (UNNECESSARY)        - local angle offset relatively the Base Parent. 0, 0, 0 if not provided
  64.     3.5) color (UNNECESSARY)            - color of mesh. 255, 255, 255, 255 if not provided
  65.     3.6) part_name (UNNECESSARY)        - UNIQUE part name. It should be always unique for each part. if not provided, it will set as "mesh_part_(ORDINAL INTEGER BY IT'S ORDER IN COMPONENTS TABLE)
  66.     3.7) scale (UNNECESSARY)            - scale of holo/mesh. 1, 1, 1 if not provided
  67.     3.8) create_callback (UNNECESSARY)  - function value that will be called after hologram will be created and pasted. callback will run with 1 argument as it's hologram.
  68.     3.9) parent_params (UNNECESSARY)    - table value. If not provided: mesh will be parented to Base Parent. If provided:
  69.     If you no provide "part_parent" string, module will create parent holo to this part via given .local_pos and .local_ang values.
  70.     If you PROVIDE "part_parent" - mesh will be parented to existing part by it's name after all pasting process.
  71.     example:
  72.     parent_params={     -- this param will parent current part to part "right_door" that you declared.
  73.         part_parent="right_door"
  74.     }
  75.     parent_params={     -- this param will create new holo as parent for this current part.   In this case holo will contain "parent" field and you can get it like Holo["parent"]
  76.         local_pos=Vector(0,0,10),       -- UNNECESSARY. default is 0, 0, 0
  77.         local_ang=Angle(0,90,0),        -- UNNECESSARY. default is 0, 0, 0
  78.         scale=Vector(0,0,0)             -- UNNECESSARY. default is 0.25, 0.25, 0.25
  79.     }
  80.    
  81.     3.10) render_mode (UNNECESSARY)    -- the render mode for this holo. See Gmod Lua "RENDERMODE" default ENUMs. If not provided - holo will have normal RenderMode.
  82.  
  83.     ==================================================================================================================================================================================
  84.     4) Declare function that will execute only once after all downloading & pasting process will finish.    (optionally)
  85.    
  86.     ComplexMeshLoader.SetOnPasteDoneOneTimeFunction( function()
  87.        print("hello world") -- this code will execute once after all holos(meshes) will paste
  88.     end )
  89.    
  90.     ==================================================================================================================================================================================
  91.     5) Declare function that will start to execute constantly after all downloading & pasting process will finish.    (optionally)
  92.    
  93.     ComplexMeshLoader.SetOnPasteDoneContinuousFunction( function()
  94.         print("hello world again")  -- this code will execute each tick inside Think hook.
  95.     end )
  96.  
  97.     ==================================================================================================================================================================================
  98.     6) **OPTIONALLY** you can disable drawing of 3D2D loading panel. Just call
  99.     ComplexMeshLoader.DisableDownloadProgressHUD()
  100.    
  101.     ==================================================================================================================================================================================
  102.     7) and finally we can start the module.
  103.     ComplexMeshLoader.Initialize()
  104.    
  105.    
  106.    
  107.     ==================================================================================================================================================================================
  108.     Module will download all meshes via coroutine "threads" and then it will be transformed to holograms and pasted with provided parameters.
  109.     Ensure your host address is match with allowed urls on server you playing. By default is dropbox, googleDrive etc. (popular hostings)
  110.  
  111.  
  112.     --              [ MESH LOADING MODES ]              --
  113.  
  114.     BE CAREFULL WITH PASTING SLASH IN LOADING PATH! IT SHOULDN'T DOUBLES WITH SLASH IN OBJ NAME PROVIDED IN PART TABLES!!!!
  115.    
  116.  
  117.  
  118.     IF YOU WANT TO LOAD MODELS LOCALLY, CALL THIS FUNCTION BEFORE INITIALIZATION:
  119.     ComplexMeshLoader.SetLoadLocalModels()
  120.    
  121.    
  122.     Actually you need to provide local path to load. Make it too via function: (before init too)
  123.     ComplexMeshLoader.SetLocalModelsPath(string path)
  124.  
  125.  
  126.  
  127.     IF YOU WANT TO PROVIDE READY RAW OBJ MESHES TABLE, JUST CALL FUNCTION
  128.    
  129.     ComplexMeshLoader.SetReadyTable(table)
  130.    
  131.     provide table of strings. This table should be like
  132.     tbl['obj_part_name.obj'] = "RAW OBJ VERTICES AND FACES FILE as string"
  133.    
  134.     ***
  135.     also you can use this Python converter to get ready structure of model
  136.     https://pastebin.com/gWB96Yqj
  137.    
  138.     usage: place script into .obj folder. then set variable "module_name" to your preferable name.
  139.         then run script and get created folder with your module name to your "GarrysMod/data/starfall/" directory.
  140.             then include & require that structure via "entry_point.txt" file LIKE:
  141.                 -- @include moduleName/entry_point.txt
  142.                 local obj_txt_Tbl = require('moduleName/entry_point.txt')
  143.                 >>obj_txt_Tbl will be contain all .obj meshes from that folder with .py script and keys is original obj file names.
  144.                
  145.                 Enjoy!
  146.    
  147.     *** VERY IMPORTANT ***
  148.    
  149.     DO NOT CALL ComplexMeshLoader.SetLoadLocalModels()    and   ComplexMeshLoader.SetReadyTable(table)    TOGETHER!!!! use these modes independently.
  150.  
  151.     >> useful info
  152.  
  153.     to get holos to interact with (for example in continuous function) just get it like
  154.     ComplexMeshLoader.HologramCollection["right_door_exterior"]
  155.    
  156.     or if you attach it to another part or created holo - just
  157.     ComplexMeshLoader.HologramCollection["right_door_exterior"].parent
  158.  
  159.     end of guide
  160. ]]--
  161.  
  162. local ComplexMeshLoader = { }
  163.  
  164. ComplexMeshLoader.host_address = "www.google.com"
  165. ComplexMeshLoader.components = { } -- it will store array structure of all needed holograms to be created with individual parameters (also with callback functions)
  166. ComplexMeshLoader.current_loaded_mesh = { } -- TEMP remove after
  167. ComplexMeshLoader.DownloadedObjData = { } -- stores raw downloaded obj model objects
  168. ComplexMeshLoader.HologramCollection = { } -- it will store done finished and transformed holograms
  169. ComplexMeshLoader.ConversionPool = { }
  170. ComplexMeshLoader.PartsParentPool = { }
  171. ComplexMeshLoader.HologramsRenderBounds = {Vector(-2000), Vector(2000)}
  172. ComplexMeshLoader.default_holo_model = "models/holograms/sphere3.mdl"
  173. ComplexMeshLoader.TOTAL_LOADING_DONE = false
  174. ComplexMeshLoader.YieldConversionPoolExecution = false
  175. ComplexMeshLoader.SetModuleModeToLoadLocalTxtModels = false
  176. ComplexMeshLoader.InitDrawDownloadingProgress = true
  177. ComplexMeshLoader.CURRENT_LOADING_ID = 1
  178. ComplexMeshLoader.ModelPasteInterval = 0.1 -- IN SECONDS
  179. ComplexMeshLoader.QuotaOverloadCooldown = 0.1 -- IN SECONDS
  180. ComplexMeshLoader.ConversionPoolWorker = { } -- coroutine
  181. ComplexMeshLoader.ReadyMeshTable = nil
  182. ComplexMeshLoader.LoadingPanelScale = 0.1
  183. ComplexMeshLoader.LastAverageQuota = 0
  184. ComplexMeshLoader.ReplaceNameWhat = nil
  185. ComplexMeshLoader.ReplaceNameTo = nil
  186. ComplexMeshLoader.LocalModelLoadingPath = 'obj_models'
  187. ComplexMeshLoader.LoadingPanelFont = render.createFont("Roboto", 64, 400, true)
  188. ComplexMeshLoader.VisualDecorHolo = holograms.create(chip():localToWorld(Vector(0, 0, 300)), chip():localToWorldAngles(Angle()), "models/holograms/icosphere2.mdl")
  189. ComplexMeshLoader.VisualDecorHolo:setScale(Vector(3, 3, 3))
  190. ComplexMeshLoader.VisualDecorHolo:setMaterial('models/wireframe')
  191. ComplexMeshLoader.VisualDecorHolo:setColor(Color(50, 255, 50))
  192. ComplexMeshLoader.default_parent = chip()
  193. ComplexMeshLoader.SetHostURL = function(url) ComplexMeshLoader.host_address = url end
  194. ComplexMeshLoader.DisableDownloadProgressHUD = function() ComplexMeshLoader.InitDrawDownloadingProgress = false end
  195. ComplexMeshLoader.SetBaseParent = function(ent) ComplexMeshLoader.default_parent = ent end
  196. ComplexMeshLoader.BackgroundCoroutineOnPasteFinishFunction = nil
  197. ComplexMeshLoader.OnPasteFinishFunction = nil
  198. ComplexMeshLoader.BackgroundCoroutineOnPasteFinishHookName = 'artybyte_cml_think_after_paste_' .. chip():entIndex()
  199. ComplexMeshLoader.HolosPasteDoneEvent = function()
  200.     ComplexMeshLoader.DownloadedObjData = { }           -- clear obj raw meshes that was downloaded from host
  201.     ComplexMeshLoader.VisualDecorHolo:remove()
  202.     ComplexMeshLoader.ParentPartsToAnotherParts()
  203.     if ComplexMeshLoader.OnPasteFinishFunction ~= nil then  -- run oncely callback if it's provided
  204.         ComplexMeshLoader.OnPasteFinishFunction()
  205.     end
  206.  
  207.     if ComplexMeshLoader.BackgroundCoroutineOnPasteFinishFunction ~= nil then -- run constant execution callback if it's provided
  208.         hook.add('Think', ComplexMeshLoader.BackgroundCoroutineOnPasteFinishHookName, function( )
  209.             ComplexMeshLoader.BackgroundCoroutineOnPasteFinishFunction()
  210.         end )
  211.     end
  212. end
  213.  
  214. ComplexMeshLoader.SetReadyTable = function(tbl)
  215.     ComplexMeshLoader.ReadyMeshTable = tbl
  216. end
  217.  
  218. ComplexMeshLoader.ParentPartsToAnotherParts = function()
  219.     for i, part_pair in pairs(ComplexMeshLoader.PartsParentPool) do
  220.         local target_part_name = part_pair.target
  221.         local parent_part_name = part_pair.parent
  222.        
  223.         local pos_to_reset = part_pair.target_pos
  224.         local ang_to_reset = part_pair.target_ang
  225.        
  226.         local target_holo = ComplexMeshLoader.HologramCollection[target_part_name]
  227.         local parent_holo = ComplexMeshLoader.HologramCollection[parent_part_name]
  228.        
  229.         local PARENT_TO_TARGETS_PARENT = part_pair.affect_target_parent
  230.        
  231.         if target_holo ~= nil and parent_holo ~= nil then
  232.             if PARENT_TO_TARGETS_PARENT then                -- NEED TESTS : MAY BE SHOULD REMOVE.
  233.                 target_holo:setParent(parent_holo.parent)
  234.                 target_holo["parent"] = parent_holo.parent
  235.             else
  236.                 target_holo:setParent(parent_holo)
  237.                 target_holo["parent"] = parent_holo
  238.             end
  239.            
  240.             target_holo:setPos(ComplexMeshLoader.default_parent:localToWorld(pos_to_reset))
  241.             target_holo:setAngles(ComplexMeshLoader.default_parent:localToWorldAngles(ang_to_reset))
  242.         else
  243.            print('ComplexMeshLoader :: parent error [target: ' .. tostring(target_part_name) .. '| parent: ' .. tostring(parent_part_name) .. ']')
  244.         end
  245.        
  246.     end
  247. end
  248.  
  249. ComplexMeshLoader.SetFileNameReplacing = function(str_what, str_to)
  250.     ComplexMeshLoader.ReplaceNameWhat = str_what
  251.     ComplexMeshLoader.ReplaceNameTo = str_to
  252. end
  253.  
  254. ComplexMeshLoader.SetLoadLocalModels = function(bool)
  255.     ComplexMeshLoader.SetModuleModeToLoadLocalTxtModels = bool or true
  256. end
  257.  
  258. ComplexMeshLoader.SetLocalModelsPath = function(path)
  259.     ComplexMeshLoader.LocalModelLoadingPath = path
  260. end
  261.  
  262. ComplexMeshLoader.SetOnPasteDoneContinuousFunction = function(func)           -- will execute constantly after pasting all holos
  263.    ComplexMeshLoader.BackgroundCoroutineOnPasteFinishFunction = func
  264. end
  265.  
  266. ComplexMeshLoader.SetOnPasteDoneOneTimeFunction = function(func)           -- will call once at pasting finish
  267.    ComplexMeshLoader.OnPasteFinishFunction = func
  268. end
  269.  
  270. ComplexMeshLoader.InitDrawingLoadingProgress = function()   -- loading visualization
  271.     hook.add("PostDrawOpaqueRenderables", "artybyte_ComplexMeshLoader_loading", function()
  272.         local m = chip():getMatrix()
  273.         m:translate(Vector(0, 0, 100))
  274.         m:setAngles((eyePos() - m:getTranslation()):getAngle() + Angle(90, 0, 0))
  275.         m:rotate(Angle(0, 90, 0))
  276.         m:setScale(Vector(ComplexMeshLoader.LoadingPanelScale, -ComplexMeshLoader.LoadingPanelScale))
  277.        
  278.         render.pushMatrix(m)
  279.             render.setColor(Color(0, 0, 0, 80))
  280.             render.drawRect(-512, -128, 1024, 220)
  281.    
  282.             local loadingProgress = #ComplexMeshLoader.DownloadedObjData / #ComplexMeshLoader.components
  283.    
  284.             render.setColor(Color(140, 140, 140, 200))
  285.             render.drawRect(-512 + 40, -128 + 40, (1024 - 80) * loadingProgress, 50)
  286.    
  287.             local pastingProgress = #table.getKeys(ComplexMeshLoader.HologramCollection) / #ComplexMeshLoader.components
  288.    
  289.             render.setColor(Color(140, 140, 140, 200))
  290.             render.drawRect(-512 + 40, 0, (1024 - 80) * pastingProgress, 50)
  291.    
  292.             -- Override depth for text rendering, otherwise it's gonna draw on top of the world
  293.             render.enableDepth(true)
  294.             render.setColor(Color(200, 200, 200, 130))
  295.             render.setFont(ComplexMeshLoader.LoadingPanelFont)
  296.             render.drawSimpleText(0, -70, "download", 1, 1)
  297.            
  298.             render.setColor(Color(208, 200, 200, 130))
  299.             render.drawSimpleText(0, 20, "paste", 1, 1)
  300.            
  301.             if math.floor(pastingProgress) == 1 then
  302.                 hook.remove("PostDrawOpaqueRenderables", "artybyte_ComplexMeshLoader_loading")
  303.                 enableHud(nil, false)
  304.             end
  305.         render.popMatrix()
  306.     end)
  307.    
  308.     enableHud(nil, true)
  309. end
  310.  
  311. -- download from web OR
  312. -- load from locals if ComplexMeshLoader.SetModuleModeToLoadLocalTxtModels used.
  313. ComplexMeshLoader.DownloadObjData = function()
  314.     local Tasks = { }
  315.     local TaskID = 1
  316.    
  317.     for i = 1, #ComplexMeshLoader.components do
  318.         -- download model if it have .obj extension
  319.        
  320.         local objName = ComplexMeshLoader.components[ i ].obj_name
  321.        
  322.         if ComplexMeshLoader.ReplaceNameWhat ~= nil and ComplexMeshLoader.ReplaceNameTo ~= nil then
  323.             objName = string.replace(objName, ComplexMeshLoader.ReplaceNameWhat, ComplexMeshLoader.ReplaceNameTo)
  324.         end
  325.        
  326.         if ComplexMeshLoader.ReadyMeshTable ~= nil then                             -- if we set ready table and we can paste meshes via strings
  327.             local component = ComplexMeshLoader.components[i]
  328.             local remapValue = ComplexMeshLoader.ReadyMeshTable[component.obj_name]   -- we need to change order of models according to component collection order.
  329.             table.insert( ComplexMeshLoader.DownloadedObjData, remapValue)
  330.            
  331.             if ComplexMeshLoader.ReadyMeshTable[component.obj_name] == nil then
  332.                 print("***ComplexMeshLoader ERROR: component \"" .. tostring(component.obj_name) .. "\" not exist")
  333.             end
  334.            
  335.             if i == #ComplexMeshLoader.components then
  336.                 ComplexMeshLoader.ConvertObjDataToMeshes()
  337.                 print("ComplexMeshLoader :: converting...")
  338.             end
  339.            
  340.             -- ComplexMeshLoader.components[ i ].obj_name
  341.         else
  342.         local URL = ComplexMeshLoader.host_address .. objName
  343.         table.insert( Tasks,  function()
  344.             coroutine.wrap( function()
  345.            
  346.                 if not ComplexMeshLoader.SetModuleModeToLoadLocalTxtModels then         -- if we need to download
  347.                    
  348.                     http.get(URL, function(objdata)
  349.                         table.insert( ComplexMeshLoader.DownloadedObjData, objdata )
  350.                        
  351.                         ComplexMeshLoader.VisualDecorHolo:emitSound("npc/turret_floor/ping.wav", 75, 100, 1, 0)
  352.                        
  353.                         TaskID = TaskID + 1
  354.                        
  355.                         if TaskID <= #Tasks then
  356.                             Tasks[TaskID] ()
  357.                         else
  358.                             -- ALL PARTS download complete, let's convert to mesh and spawn holos!
  359.                             ComplexMeshLoader.ConvertObjDataToMeshes() -- start converting all downloaded models to holos
  360.                         end
  361.                     end, function(err)
  362.                         print('ComplexMeshLoader: load fail ' .. tostring(ComplexMeshLoader.components[ i ].obj_name) .. ' at component [' .. tostring(ComplexMeshLoader.components[ i ].part_name) .. ']. Error text: ' .. tostring(err))
  363.                         table.insert( ComplexMeshLoader.DownloadedObjData, {  } )
  364.                        
  365.                         TaskID = TaskID + 1
  366.                        
  367.                         if TaskID <= #Tasks then
  368.                             Tasks[TaskID] ()
  369.                         else
  370.                             -- ALL PARTS download complete, let's convert to mesh and spawn holos!
  371.                             ComplexMeshLoader.ConvertObjDataToMeshes() -- start converting all downloaded models to holos
  372.                             print("ComplexMeshLoader :: converting...")
  373.                         end
  374.                     end )
  375.                    
  376.                 else                                                                    -- if we need to load locally
  377.                    
  378.                    
  379.                     local obj_name = ComplexMeshLoader.components[ i ].obj_name
  380.                     obj_name = string.replace(obj_name, '.obj', '.txt') -- if we want to switch from loading to locals and we lazy to change file ext
  381.                    
  382.                     local obj_txt = file.read(ComplexMeshLoader.LocalModelLoadingPath .. obj_name)
  383.                    
  384.                     if obj_txt == nil then
  385.                         -- file loaded successfully.
  386.                         print("ComplexMeshLoader error: can't load file " .. tostring(obj_name))
  387.                     end
  388.                
  389.                     table.insert( ComplexMeshLoader.DownloadedObjData, obj_txt )
  390.                    
  391.                     TaskID = TaskID + 1
  392.                        
  393.                     if TaskID <= #Tasks then
  394.                         Tasks[TaskID] ()
  395.                     else
  396.                         -- All parts loaded locally from drive. ("data/sf_filedata/")
  397.                         ComplexMeshLoader.ConvertObjDataToMeshes() -- start converting all downloaded models to holos
  398.                         print("ComplexMeshLoader :: converting...")
  399.                     end
  400.                    
  401.                 end
  402.                
  403.             end ) ()
  404.         end )
  405.         end
  406.     end
  407.     if #Tasks > 0 then -- it could be 0 if we using ready table
  408.         Tasks[1] () -- init all sequence level 1
  409.     end
  410. end
  411. ComplexMeshLoader.ConvertObjDataToMeshes = function()
  412.     local function MeshLoadComplete(_mesh, componentData)
  413.         -- this function calls by converter from obj to mesh to install and set up hologram
  414.  
  415.         if type(_mesh) == 'Mesh' then
  416.             local pos = componentData.local_pos
  417.             local ang = componentData.local_ang
  418.             local mat = componentData.mat
  419.             local color = componentData.color
  420.             local scale = componentData.scale
  421.             local callback = componentData.create_callback
  422.             local part_name = componentData.part_name
  423.             local parent = componentData.parent
  424.             local parent_params = componentData.parent_params
  425.             local render_mode = componentData.render_mode
  426.             local skin = componentData.skin
  427.            
  428.             local holo = holograms.create(
  429.             ComplexMeshLoader.default_parent:localToWorld(pos),
  430.             ComplexMeshLoader.default_parent:localToWorldAngles(ang),
  431.             ComplexMeshLoader.default_holo_model
  432.             )
  433.            
  434.             if skin ~= nil then
  435.                 holo:setSkin(skin)
  436.             end
  437.            
  438.             if parent_params ~= nil then
  439.                 if parent_params.part_parent == nil then    -- if we need to create parent point by params
  440.                     local parent_pos = parent_params.local_pos
  441.                     local parent_ang = parent_params.local_ang
  442.                     local parent_scale = parent_params.scale
  443.                    
  444.                     local parent_to_target_parent = parent_params.affect_target_parent
  445.                    
  446.                     if parent_params.local_pos == nil then parent_pos = Vector(0, 0, 0) end
  447.                     if parent_params.local_ang == nil then parent_ang = Angle(0, 0, 0) end
  448.                     if parent_params.scale == nil then parent_scale = Vector(0.25, 0.25, 0.25) end
  449.                    
  450.                     local parent = holograms.create(
  451.                     ComplexMeshLoader.default_parent:localToWorld(parent_pos),
  452.                     ComplexMeshLoader.default_parent:localToWorldAngles(parent_ang),
  453.                     ComplexMeshLoader.default_holo_model
  454.                     )
  455.                    
  456.                     parent:setScale(parent_scale)
  457.                    
  458.                     parent:setParent(ComplexMeshLoader.default_parent)
  459.                    
  460.                     parent:setPos(ComplexMeshLoader.default_parent:localToWorld(parent_pos))
  461.                     parent:setAngles(ComplexMeshLoader.default_parent:localToWorldAngles(parent_ang))
  462.                    
  463.                     holo:setParent(parent)
  464.                    
  465.                     -- to prevent offsetting
  466.                     holo:setPos(ComplexMeshLoader.default_parent:localToWorld(pos))
  467.                     holo:setAngles(ComplexMeshLoader.default_parent:localToWorldAngles(ang))
  468.                     holo["parent"] = parent
  469.                 else                                        -- if we need to parent part to existing part by name
  470.                     -- reason to think:     may be we need to provide local_pos & local_ang to move target part relatively parent on it's values.
  471.                     -- just to offset pos and ang target relatively parent
  472.                     table.insert( ComplexMeshLoader.PartsParentPool,
  473.                     {
  474.                         target=part_name,
  475.                         target_pos=pos,
  476.                         target_ang=ang,
  477.                         parent=parent_params.part_parent,
  478.                         affect_target_parent=parent_to_target_parent
  479.                     } )
  480.                 end
  481.             else
  482.                 if parent == nil then
  483.                     holo:setParent(ComplexMeshLoader.default_parent)
  484.                 else
  485.                     holo:setParent(parent)
  486.                 end
  487.             -- to prevent offsetting
  488.                 holo:setPos(ComplexMeshLoader.default_parent:localToWorld(pos))
  489.                 holo:setAngles(ComplexMeshLoader.default_parent:localToWorldAngles(ang))
  490.             end
  491.             if type(mat) == 'string' then
  492.                 holo:setMaterial(mat)
  493.             else
  494.                 holo:setMeshMaterial(mat)
  495.             end
  496.             holo:setColor(color)
  497.            
  498.             -- do not change scale if it's equal to 1.1.1. It's unnecessary action
  499.             if scale != Vector(1, 1 ,1) then holo:setScale(scale) end
  500.            
  501.             -- do not set rendermode if it's 0 (normal). unnecessary action
  502.             if render_mode != nil then
  503.                 if render_mode != 0 then
  504.                     holo:setRenderMode(render_mode)
  505.                 end
  506.             end
  507.            
  508.             holo:setMesh(_mesh)
  509.             holo:setRenderBounds(unpack(ComplexMeshLoader.HologramsRenderBounds))
  510.            
  511.             ComplexMeshLoader.HologramCollection[part_name] = holo
  512.            
  513.             -- decor point
  514.             ComplexMeshLoader.VisualDecorHolo:setPos(holo:getPos())
  515.             ComplexMeshLoader.VisualDecorHolo:emitSound("npc/roller/remote_yes.wav", 75, 100, 1, 0)
  516.            
  517.             if callback ~= nil then
  518.                 callback( holo )
  519.             end
  520.         end
  521.        
  522.         -- turn on coroutine
  523.         timer.simple(ComplexMeshLoader.ModelPasteInterval, function()
  524.             coroutine.resume(ComplexMeshLoader.ConversionPoolWorker)    
  525.         end )
  526.        
  527.     end
  528.     -- conversion. push all coroutine examplars to pool that will run these coroutines till it's complete.
  529.     for i = 1, #ComplexMeshLoader.DownloadedObjData do
  530.         local obj = ComplexMeshLoader.DownloadedObjData[i]
  531.        
  532.         -- if MODEL TABLE length is 0, it's empty table, skip conversion. (empty table goes from downloader and sets if we create .mdl part)
  533.         -- if table is not empty, convert from obj
  534.         local doConversion = coroutine.wrap( function()
  535.             local _mesh = { }
  536.             if type(obj) == 'string' then
  537.                 if string.len(obj) > 0 then
  538.                     local model = { }
  539.                    
  540.                     local succ, err = pcall( function( )
  541.                     model = mesh.createFromObj(obj, true, true)
  542.                     end )
  543.                    
  544.                     if not succ then
  545.                         print("ComplexMeshLoader :: PARSE ERROR AT COMPONENT " .. string.sub(obj, 0, 100))
  546.                     end
  547.                    
  548.                     _mesh = model[ table.getKeys(model)[1] ]
  549.                 else
  550.                     print("ComplexMeshLoader error: empty .obj file")
  551.                 end
  552.             end
  553.             return true, _mesh, i
  554.         end )
  555.        
  556.         table.insert( ComplexMeshLoader.ConversionPool, doConversion )
  557.     end
  558.    
  559.     -- conversion pool execution control
  560.    
  561.         ComplexMeshLoader.ConversionPoolWorker = coroutine.create( function( )
  562.             while #ComplexMeshLoader.ConversionPool > 0 do
  563.                 if ComplexMeshLoader.LastAverageQuota ~= quotaAverage() then
  564.                     if ComplexMeshLoader.LastAverageQuota > quotaMax()/2 then
  565.                         timer.simple(ComplexMeshLoader.QuotaOverloadCooldown, function( )
  566.                             coroutine.resume( ComplexMeshLoader.ConversionPoolWorker )
  567.                         end )
  568.                         coroutine.yield()
  569.                     end
  570.                     ComplexMeshLoader.LastAverageQuota = quotaAverage()
  571.                 end
  572.                
  573.                 local task = ComplexMeshLoader.ConversionPool[1]
  574.                 local done, _mesh, componentID = task()
  575.                 if done then
  576.                     MeshLoadComplete(_mesh, ComplexMeshLoader.components[componentID] )
  577.                     table.remove(ComplexMeshLoader.ConversionPool, 1)
  578.                     coroutine.yield()
  579.                     if #ComplexMeshLoader.ConversionPool == 0 then
  580.                        
  581.                         ComplexMeshLoader.HolosPasteDoneEvent()
  582.                        
  583.                         break
  584.                     end
  585.                 end
  586.             end
  587.     end )
  588.    
  589.     coroutine.resume( ComplexMeshLoader.ConversionPoolWorker )
  590. end
  591.  
  592. ComplexMeshLoader.PushComponent = function( args )
  593.     local component = { }
  594.     local keys = table.getKeys(args)
  595.    
  596.     for i, key in pairs(keys) do
  597.        component[key] = args[key]
  598.     end
  599.    
  600.     -- insert defaults
  601.     if component.mat == nil then mat = "default" end
  602.     if component.local_pos == nil then component.local_pos = Vector(0, 0, 0) end
  603.     if component.local_ang == nil then component.local_ang = Angle(0, 0, 0) end
  604.     if component.color == nil then component.color = Color(255,255,255) end
  605.     if component.part_name == nil then component.part_name = "mesh_part_" .. #ComplexMeshLoader end
  606.     if component.scale == nil then component.scale = Vector(1, 1, 1) end
  607.    
  608.     table.insert(ComplexMeshLoader.components, component)
  609. end
  610.  
  611. ComplexMeshLoader.Initialize = function()  -- main method (entry point) to initialize job of module
  612.     ComplexMeshLoader.DownloadObjData()
  613.     print("ComplexMeshLoader :: downloading...")
  614.     if ComplexMeshLoader.InitDrawDownloadingProgress then
  615.         ComplexMeshLoader.InitDrawingLoadingProgress()
  616.     end
  617. end
  618.  
  619. function MODULE__GetComplexMeshLoader()
  620.     return ComplexMeshLoader
  621. end
  622.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement