New planet mesh generator

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
User avatar
Ats
Posts: 907
Joined: Fri Sep 28, 2012 10:05 am
Contact:

New planet mesh generator

Post by Ats »

Hello. Today, I'm replacing the planets in my game. So I'm working on a little planet generator, and I'm already stuck because I'm not able to refresh the MeshExpression vertices when pressing spacebar. It just changes the colors... Is there something I'm doing wrong?

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" FileVersion="2">
  <OnLoaded>
    <ZLibrary>
      <Source>
<![CDATA[inline float max(float A, float B) { return A >= B ? A : B; }
inline float min(float A, float B) { return A <= B ? A : B; }
inline float mix(float a, float b, float t) { return a * (1.0 - t) + b * t; }
inline vec3 mix3(vec3 a, vec3 b, float t)
{
    return vector3(
        a.X * (1.0 - t) + b.X * t,
        a.Y * (1.0 - t) + b.Y * t,
        a.Z * (1.0 - t) + b.Z * t
    );
}]]>
      </Source>
    </ZLibrary>
    <SpawnModel Model="Model_Planet"/>
  </OnLoaded>
  <OnUpdate>
    <KeyPress Comment="Spacebar" CharCode="32">
      <OnPressed>
        <ZExpression>
          <Expression>
<![CDATA[
//
Decorium_GroundColorR = rnd();
Decorium_GroundColorG = rnd();
Decorium_GroundColorB = rnd();
//
Decorium_OceanColorR = rnd();
Decorium_OceanColorG = rnd();
Decorium_OceanColorB = rnd();
//



@RefreshContent(Component: Mesh_Planet_Import);
@RefreshContent(Component: Mesh_Planet_Expression);
@RefreshContent(Component: Mesh_Planet);
@RefreshContent(Component: rendermesh);
@RefreshContent(Component: Model_Planet);
// wtf]]>
          </Expression>
        </ZExpression>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <Content>
    <Mesh Name="Mesh_Planet">
      <Producers>
        <MeshImport Name="Mesh_Planet_Import" HasVertexColors="1">
          <MeshData>
<![CDATA[789CEDDC7F8C95E59507F00B8E5A51B72534C632646CABC03F6B2233A38444ACB6580A163042534B2A3AEA5F4EC3509B4B635A1BD26D9A3AA9714CF12F0B161BEBA6A52950A1545AAD90582C0C266E360164ABC4C1C64858573B6A4560EFF7FDBCAFF7EE26DBB4BB75FBEB7D275EAECF7DDEF39CF33DDF73DEE739CF73EFEBEF6D346E3BBDD1BAD63C9EFFDE53FCDBB832FF75E5DF35E317BD79607D7363F7E8BE075AAFFBF67D6BC21DCD37562EEAFA975B1A4373267C7A65634D6E6EACF9D684AF0FBFE7DE3913FEF9DEC69A079A3F68F577D7A543D74C3EEDB1F4DE72BC7F70F98A1DBF9BFCC55FACFCDAC919439BCE3AF8C3DE15DB27DDF3BDC6D0A2AE7FFCF6F12913364DDDFCB17FB87FDD235B6E3FFFEE874F3DAE7DF98A7967EC59FBC6CA8CF0D349AB3ED3BB62EDE4D59FD8B162D359D3AF9B3E44C3558317CE18DD6FC4EE191FBA78DAF20B67F4CE5C35383CF5F0653B6EFD696B8CD10D241BE5876BF75F31FB6863CDD6CB0F1FBD79F8DB97FCDB0B4639F0C90BCFBE6BF8C51BBED3D558A3274DBE7AC13FFDF4B33F5FD74C4F23BA8B3E3481C9E93734D67CF0387B83CE93277DBA70F2C9ABFA879E9F74E3271B6BEE9ADB7CFFE96BBF7DC987A7DD3CBCF5F29E298D35D72C8A76DAE9D03BF39EB5870E9C39A3B166D2B37DB36E1A5E36F685817B179FF3EAEDD737AEBCFB376F0DDE3577F8E568FCD086E8FA810773CF8C1F47FA05E31969EBB18CBAE475AFC16BF058749D3F6EDCF18B223BEFD7356948B7E7BA628111FB663DD05C36B6F5F2C69AC347C77AAE5FBF713477DEF234DD58F483EEDE59EB9B3D53D2CBBDC1E1D4086EF834AF03C3FAECB875786ACF53D39677CFF8F5339B976EEF7EEF4EB63C3CB0B4B7FB3084E97972C991C55D47594D5AB8F79E7BF18D7F5961949FB57871D74F8E2C8EDFF0EAAB177CF9E39FFDF9DC8B175C3167F757A6DF76ED89BDBC199457EF6491BB68E25EA34015AB6F3FFFF6EB4F3D4EC258CFC3031B475F9AB9AB7FD5B65FCE9E7BF1B627C8FFD83FDC7A73789B9ECDF7BF35B87A278B588A9F18C85374C03ADAE2007CE84337F8F329FF924C668958F1DE58246CEFFEF7B98B3742E0F894934BA66E8673C5E1305F3B9DE9CF965DFDF72C386F7FA7BD1F6E45D4D881207EE88016EFC39E5B9E7EE1EA49F34E3B7CDB924BFADF3C889FFA93401AC4C8A715944AF9859C44D3E8065A75E2A98FFE2493F9CADCCD4BE78F959A14ED89F6E611FA2CBCE2C9D93B9FA11599C6253359E2858768052BDED432B1EFCEE9F7FDC82874264D8BF746A183F6CE71EF59F0D2CCCBF7181D0E34648B3E241B970E46A7E7BC33FA071FDA0013684C9AF776CFB447E9D6B8325CD6B3E276ECBAF0ECD5CDB02B5825B32CDC0513A3D3365971DEFD464C2E9DB721D174CF5A98F8543BDCE850E25F78AA533299328C7BC9211FCFF5973DC435ACB00556308106092C85894CC8D7F29271C9211362B08203C964424F8CF08B4F49638B285BD69BDC4007C840834530218D647A1A174A46679DB1C4AC9E241BA5CADEE92F33C83F6CF1A9F7FA68B966F289AB4647F2BA7704E6C9C67B4792C90F8ED096D716B6FA3C3522F75E33F9EDAB7E3522CFCB3010600BF93C4513A8B2421E96DB49A615BFF385FE18C25F3C2EAF1A056FE10C73123C23A0CD223D2106AB8A4591DF29594FF9D3A778523D3DE35F2D466405FDA10D0D1A92090123E2309D69EBA94A67DAF2053D59E1390B6D5E888FF68C785AB59F5C03EFF4C9A7FC6826401A399EADFC4B7FCFE84E1BCD1CDC6B5E11895B8F79827876C08A643D59C4779EBC62043720635C7E377A5BE78A7566869ED4F8C63AACA30F5BCC3ACC1FF4248D9E6C81362F57B19F5947253368938C9FE2CB330E1358CA46F2E9094951C952F7F208DF19852DECC5134F6A0C310A8BDC4502B6D0DC1CE32B2D06E7495ACCA05A913F76C00CD6EC140EE6C39EF846D1C7A766686623554EC8DCCFFC8126BC2F4EE1B0BA79E093877E5BCDCFA33F09DAF53113306BC56A7357BA996561ACD93B8618451F9FD293047DC831E78189D957A2A5798437711833DD4B13D689411270A6EDA355835607B08203F99D989B93F378DB9B8D124FED6284269D735D1AF2175BD805872F4D38F68D5FACC47908875B4B5E278D45D623E6666665A4910C07F89B955953F0A378C9FBD5CDD81906C67790A1032FF02669ACA043E7CCD09AC5BDF0B426A2336D219F78796BB01DADEB9AD63EB0856AE27BE1AE0DC52ACF5A2F4FC6CD4BADBCB02231FD9D1F5FDA5AF74C78ACAF782599CCE49F8707928197AFE09112C935C50AB2F0AC151F04E8430234D8C28ACC0F325F8D6E10B62E23D92846C41C7AD2906EA22F91F5E20D34E15F2B411EA1094BD92842E98981FAE7E9DBCAA88517206C74B6D321B388238B49A06D19AD051F325ADE3FD7F5D68374834932D196E364F2172654F7BE78C38DC779C7BA1BFE5A784ABB9529565B8FC3107AAFB46639F3C79289E695085B0BE77990D969F89079CF9CDD108355EC5FBE4205005779CAA7DAD3D2187217BF74A22D8EF4A4037DAA4889752C850FCD21E0D32095E763C6A5F9C070ACC67F8C853C3FC2FFB5731349BC402B3662144BF3E49B3FCEB3F0DFDEFDBE9D990D0619FD8DA24E622C11ADFD9EB58944D24886B95A849ED7AF2F5676C55846E171E3C201AFDA789E1A094BD4106EBD194B458A118D3E309C5C140F5558C1501F9FDE5C6005796319B7626398495BB6B31A2B2AD6E15B22EB9BEB939DDCEBAECCE56EBB562C88411C832199A2491CBD51E457DEE1353E22BF8C8B22467819E634C1700C09AB4E9D626385467AC2561CE94F9A582B997865D655F0A439EFB83733C81DBF5B5EB0A69D2B5637DDCB1615B2B77BB252C13AB664AE57C5E653230B5AEF4507CFF269561A5D4779C1B8BC4C1FBAB9971CC87C7DF88D959F7BC7F6F85A6C8A32A31C1C815EFA1BCDECA08A3FB1985756F045E6109F3BC976882D6CAD60B3920DABF139EBB57B16F02F7BD982AB22F485ABC7779C76587F7C9361ABCC106DC9C199B2A67776A25F84EA091F12A074F7C3990DE29B68721716B9972FC8A7A19E6250449C1AC101BA0793E493DE157483E11706566E3EE7553AF08E5880C62F5BABD96D4FC00D37F0C4584679E1A1CC3FE7DD9FB9811631C8B3F806017A408FCF0686BFDFBD675F95DFE2FD48C9CA3D31259AC4203420831B58211B90295BBA17AB7999C77999BFF88E7513FBBE7A302BF4581D4BB2EACFB85A6243E34A6C873F04C40826934C1ADC8C58C56322D788BC0C6DB640F2BE1F458BEF7E34B510B8410C9F2B3FC683BBA75C37B8FF0A5AD1871FDBD84E1F8209DCE2EFF9E3A9D23C391B5B30075731E1B573D3572CF3085FA432B0E00A9AB89764F9907C9AB302131A451519676075A4C87CB0621D2BE88FDB55E4265AF3FE8EA67631425B56D39F4764803DADECD1784C0EC9BBBDC5FFEF29E33456ED1DA11B7EE2EA844D592DB2822F784ACEC13198E88FD5C6DA5BB4FB543BDC449338C2C0698FA6B6433EACE2AD2DC74BF9059EACA8726022030F31103FB3FAB86B2E1CF8AB9DD9EE685A198829564320D59043BFA5157D6E5BF2F49E370F622C4E6257954BC3A363DFF8C8BD5F3B89C3A9C7DDFD1B8C25272BB71BCBA7863E6C49C67DF2A4F81541AC88FDA9F8C50A31424F1AC6E6A74620A885BFE06B747AD2414F7D8C85F3F84F32D6E15BD656AB3E334F5628FC483696EAA9CF431B120DD0C0C6CCD7B75E8E8790973F459C71F9421CF9F4CCE959976329C626032EEDF51EF3F7FE1716E53D0D8DA88F713D11A1A4375F977E2FAC10DDA2559C2EDE988A476766C63A7C9313F6768C4B131C1017188BBDFA8B149F7E7E5BB889CF46F9C08389D46A751EDD44BD7897D94637649D6B1438934FCEB627D49CCFDB9F6A677882A5BCC39B6456FC0926F0C1739CC4CF68FBDAB967ACCD2CC3BA07F37109AFAE1B9CF9C4EC92D52460E9B2562E4BED34ECE54D08F3290DB19A9EECADE61BF10E266048F0DDB182D59D1E87BF58133B6CD103CF93AD524B0CCF3BA329BE495D31DA1A0526B9B7BFE4241D322F3DB2987C718A09AC803064E68F6516315854079B47AC7F83A418A7273F7A22E01B3D6948DB4F172BE0AC88BE3521ABB3455D7C1146DD7E3E8F90BFF5D889ABFA861E39F6F655970E65CDF78107B32A8A1FE28D203B6777F4DBF644DEED7CE682F1ACF2B31F78B0B57AC81A62D958EA36878FA6E691F703C346B96FD325FD674ECF5369ACC75846D13FAC7BBB277C9B7BB19EC64AB63D6F7F303DB1D7B8E1CAB4473FBF2D58E539F49DAE6A0D9DD79DCF841573760707D2B4DCF9FC973FFEDD8F9EB73F91F864310BF85C914DB71CCF7C848DC32FA79A74F8686AB3799A66BD33FC72AA166923E1F4A379C6F14B389915C7AF9FC9BEF0E8FE5583F1DDDC8B339F796966661D4FCE2687042BCC9B86978EEDDB77E3F0B2B1CCAF263DFBE601F5D9E0D5332595961F74FB34F5CAAACFA5435B8FA59EB0E4F554F35A6BA79FD09F8F76FC2E719699CCF6EEACB086A76685DB3D2391F5768F765AF14BDB5303C3C980B79F9FECB67B4A72E258CF078BB50B647816FEE1FAD881C4E1C6D1487C656E32556B7E7C7FEA16C6650B2B92D752BB888E6C5FDFFCD4D89E7D6C595758978A55D6894B5BEF21A35D9F54D57B9E4A5ECBCC3F3827BE6EBB36D5B485BB488312B4F54C06587005AC1257A9E6CD1FCF7980BC4FBCA5AE12DDF8971F33475FD78C778F4FC91CE8B57321C32FA9422E9CDCDF62EAF7BB79C4B8EB9BD1FC5745CD3873E620BAB1F5AA45C55AFBA9C79375A76E4EB68C575EB8FACD0391C4CFFB0A49470E640727EC5ABC315C5DB54D7F38C33C382D1B4B563A7CD4BDBC96BADC87A7A52E973A605E6F6A69326B5656A667CE2033EC9DBAF9B4C3E105AF25FB9DB88AB66C4C0573D359C9386B271BCB28B425998DE49353219076BB281B4753EF5CBD33B3A4B4AC6BE6FD5B8369CF5E655E6172626F7217DBF3FEBE1FB9F757238F1C3BAD35FB8D061892DA41CF53557B5AF89ADF71030EAC8686BBF6B6F2D3C4C7DC1B06771F4EE5B13503DC543C835ACCCE5C346CF4E9358B7EF61F59118721A21873F0197F484895A1EBE8B4479399C2A48DA361D22D4F27231C3A9095CF606BE4545792919B47E889CFB807EDD420B64FC2409E3AE7D53C09EFFE4D9E8D79BE64ED96FEB46A475655BD82FCC25D99B3C07CA0CC33891759454E88F4E35364863C5FE66D30229E24A73F3F091FF05F7E802DBEB19A759959CE1F232DB2D64E960D6273E6CF191DF2C9FCF3EE370A8FCB99E29737F10137448A3E3497C70E15D56E3C61351E6220968A629A8B65BAC95134CC3338159578567EC016ECC207FACB48720E8FCC3E9AD90A8FF39D117930D59FD47C22532EB2434537FCBCB1C33BF209E4C520FC2B0C2F18CF6C223D33DF78E16A58E1128BDCCB5FF3C7B3E2C11F9E85A47C2293E03C7B598AF39886639993ECEA87BF11F99126D8C52E1655D11754D90E87B39FCD0E4BB5BF1A666A2FB374619DA829B362113B18C2CB3CAEA7BB78247DA62D974F30077A3C22B2CAA755C1903C173F74F1A1E2D4094DDC5B54247F224BC0847F69C5CB46372E04640F79400608975299496CE2152F908639A20F1B454D9EB8CF75D19C1F79472E320AEBF8D10C275928ABAA784D1EC82A60577FE5DF589A99E499D3C50E3F66455DE9C65334C9933EAC0B97CC94606BDCE87DFBF934274DD4CB00321BFE9B8989BBCC3E5BCC2A9E233CAB3D6BAA9E329FB082FE709325E425B902B6728E7159C7A7620A326C87439B75EB9A3C5E3D738B5946C1314FDED4EFE69D417FCC1105E24BD6250D0F3139EBAEACA7D29317B2DB56711873B4C0413BACCA676BD19E8A7C6A26E1D5DEE2155BCC45C9C10DB3771AF25795ABE3B5B667EF6856FE0DCED5DE785EE90F61F1A55EE05E7C28912F7248E793C82A806EF1C17B778A145CE5C7CCB5B2360C1AE6A5EE250DA3F842DCE12776E1155FF3B2F97F2A86C924455629F2864F21695E6A658109EC155310839ECC59CE210BAFE1B9F93CDDB0176EB86A9E0C31E89189337C4187D2B3854FD968758339E45BFBF854768580D834DF86152FD0500C8A7A390A67B045EEF2A928C07FAB24DE91434AAF15FDF98E9CF26955E4373D79C12ACF7A813E709007A265726CB2075B3C23E08C875821AEABB1320AB64306C2B0C56ABEC3ED54EE52A3C8BD34CFA9A057E61AD158BC2F27E0004685797922475B2B1A9C8430EB588A692C4ABF70269A785FE5E7B4545199B8AE9E0EC9D3FCAE3DCFBED4B2321A1CC4858C213AE866C44E3C8D0255DA8A3B71443269E4E7045E95E76162458CC3F84C02CDC56F32E9844DF0C40A7580EA699E7B73E6ACF97E7AC213E7C9942DADD621CF0B584726EE61A33EFA1B4B7F23926C45DFAEEE5D78B69EF461A9D5037BE18903229A4F79530D813E58ED531258448E0A007C6085F3E211F38D0E610C9407D455E88FABF255C5F6D41B70408EADB259224E1FBE702F8F2427A7BF5A45EEA2338FD0BCFCB4E003F918AE3250F2BCC86C728EFC0319F953D65227E123DE51B1E11DF8AB20B1572CA8C6C016AAD57324599A8D9515D1DFA74637AEAA827A0EB6902667CA09F203FDB5CB9C721D9DE94F0E244923811F652DB520199504285595AEF83DF535DA5695741C80ADBC21DE5921EAC54864E5899028564D920DF04A058947E88045D88BC9694DED287AAA73AA547BAF5E9DB5EE79FBD569AB0A6D7050095403C449D18499338A53FBF206CEC86C3CCBA76AC8AAC7EAD55ED5ABD5A553CFDDB31632BCAC66AB7EAB725B555F53773D559C2BB457A20A9A333F8D2B53811D3CA68EAD829D9AE992D7CB5A68D19E5382AFCC5561669D598C6ABCCABC8870CE951760A282CD22556EF56D7B0AD53E42720CDD788D0721D3AE9FDFD17CA838979ACADBEA4FF054896451F5559D56FB4D9C761F56BF8549562F4B7B8DC276FDD566D5907F567CFB445D9DBD338AD3647613B4872D394D1A9EAB152723FDBAACCF97BB4845B559E559EDBA38517D948F54D4610801E72673463AEBBB3007F7CA736DBE7D527C03C35DD8087FF8C0D32E03DB3B2BF9E41B0B027C814BD50E57624E353BA7AF72EE287A6A577DCE39F3EE199D11F1BE9DC10373C482BABA1ABB0A7FCE64E4BC68BB6E2F763024D960CEEECC7A3E781CEB30D0BD6AF8F04CC6B9708671E180993829FA3021ABE69CB08D7FA3594E11A79DD7D4FC8D655C7C1017F4F71D27BEA339F9BCC353D0902B60D2B96791F3105B8EC30732ACC604D84215C7B00B03931553DB0F3E62C728C6C50D27CAF91D07680EB7EC336E5EDA577C33897C9259AA674EF87CF7A3E2427B4E2E4DEC2301E6C938D9EF284E53163C242DA3AF6EB6B9D73F086D271D7959BBC8957F785656917932DFCA93A2C86F051B710F923084121EFAD45DFA63F2235B72F2D17B9858F5E13FCC49E31D7EA703F6969E5A9ED9115EF1F80D3F0F4EBC404F48CA0F7AB2AE3A851AACE404B94266C81374FCA26AFDD78EF7DBAECDAE91B1F4C1F3B267C1319CD74E2656E333DB610201F2453AFFB29DD5D9055FF23A099903E73475A2A3FA343EDAF0E3AC0FB02E7B7BA95A445BAC68C7C5FA66FB756058A45768048783C5F97168C88DB253FFD082C9A74A6662A9FE65BE2DCE8CE3129918252EF8825F640F91E2D39CC53D7C191FF18E48C155BCC50D9A60888C61C4F239F258CEA843034FECE6C053A4600BDFF1A3B813416227F5E5B103D82503E033267F737D9ED4BC4007BEE0F77CF3227B4619C1EE899E7CB7AEF8EE1DF4589D533EF3C749E6719CC9BC2DBB51911986D8D3EF1FAC3C95E8A0D519ADD9D2F0CBA9C88CEE870FACBCEA69C50555DC13717CF1E6C1F899A5767378B09D1972E63C9CD11E8C9A47200C253EA261E4DF7A332471CFBDBC2F1E31DF4E0D1D30013E9716F84029FB46FDB3EC0779FF40D147269415791003B1F4B2D66B2501AFA02D5AFB6615E314386766BCB11BDBA10749FDB11167EC0E89538C3222FE1B1737789367B14EAEA6B3BD3939C1B8F62531443B7B59018D2A1765749A609A48C7377B46FCCBD73EC573D98077780AAFEC1CC19F8FF89767C5829D2F3CE12FB18603FAE3214EC24146128F556C268FC95A3EC573B6603B06621DBEC948D5F75983396CC50B993880757688701EFFE9667FA7FA5E57180B49BBAE108649F9EC2BC7CDAE65BB2299EF2667262FAEC5785695773F8CD5F0879B98829B5C61475B64B90BE6EE25D39E94FE7C67E7080FE983A5B4B23FC822FE35A2DA3B4DF01003ED19D9E3C37392ED10C9999DFD616BAF10567D451442ECC662971663C52609B01529FC220FF0AC28C0FC8AF3F12CCE93D6C6AAFA3E06EBF8C88E8C8A3476E1212ED94BC27FF18E69A25E9E613B1C6048BE1DB42A57B0295982B63C2E5AAB5C115BC4B218E4594C90E54490D8513FA72DEFB0F7D28E8C57712F98F816DA9E7DD9436329ABF98BA7F854DC890E357F72AAEFB1E555DC9163371C3E76CDA0648F8FAFF911F3C591BD952A2EB29305077BFAF20956C381ED767030D37900231A9D4F696BD79EEFEC3F8A02915EE99F3A683BA25797BBE4348483DD25D12AA6C4177C48B30B430EDFC90F70B00B8651FC284FB2D14E1F7EE2AA9D3B23E2097C30044AF6656042A65D39FD71CC9E609B79D5D9001AD2D67E2524B1141FEC8B89414CC66AF162EF00563E15D7625CE6E417B6C34134F105BFD81B6AE3F6D660B58F199DC514CDE52E2DF20CD6E1B33312031D39443EE15FBED6DFE8A4E1036DE516594514C85AECC225A735EC796175756A28B8D927E5538CB56F4526FFD28A4758EA2EFDF9C55EB0481123763CF91407A00A4FBC92A5E504D9006F7158148B35928DC222F122AE59EA6C499593A367992737546747577F423680B6F327109613F8C5284E16195DFCD25614E3985C214B54927DBF33F2C59DE8F044CBB9CD79673847A752ADE696EF427CA9ACBC3DB22571AAAEAB3239F98B1FB9F74B13AA6A6A9ECFF1EE4B3355265532B578EF5C1C2FC80950CD7F795247A6CAA70A98FA953A58E60CA9FFA75D952CF395AC7452095403F45E5D4B452BFECD9334B56EF549FAABFBA9F8F9A63499EAD2FAC7F7BD33B5A8A3E6AEACC4534DC501594BBE6AD75ABF3E4CBE2782674AE7F919594E34B1119230A43F6D55E7329F3E3E451D9B8FEC63F2BEACC583D55E49FC05EDCE1AB81D52F94D645527E84EB466E74E3F3AC7187F9C7A5C4D5B7DD85941A737557DCF7935D1A0A7FAB016EF5565F88877AAFA7FCEB16217E6C48AC695E4AB2AAB567FAD3813AA9A6D37573B29A90524F3A76E6F67845F4E8DB4C7BAF3F97CF7CAA76C61A32A3ADBFDFA4BBBBD7F28FBA9AD4C566882C9DAAB3EC10A0ECE97AAE73B67A8BADE3E473A7DC8BD79ED1B0A27B2FF55FC0A4D611746D199FEAC539F27133FF1BF627EDE57F3E5BC62088FF3B5BA589BB77BCA184FD568FB242C3AB137A8883848E2BC11315FFCC2041A468CF6A9C687BD7C2A57F06C9E5BDBBBDD4BABCA2F6C8A9534A1397D9CCC8509CD61E81EA8CA1572918C615CD6613EBFB4F1EF2BFD4567B146730890090792CBF82D72054CE404F9041A788B27DAC5ACF8958BFA86A28B96BE5297B4E8AF9D3E301411A3C58E2EC4A0C1FA4BDF9170F22AFEA5279D9D93A8CE3D449208C2BAEA6C6DDE8B533C4C163EBD94000776654FF79A45A232CF9ACC22C20A68D0A7CCBD854FCBB3C4E33941006D67A370B5E270EE2AF52FEEA52D3D45370EF03E1B0F8E1885FF3396B816D1F20FACAA9EF44986F6297BF3D4C9DC206DFC2E87C80F64FAAE493BDBBCB1B260ED103CF150DCE19258E041DF4BE0C754C517756178C5CCE0F0C3B5339FD85D46AEF31F6C37629E46D9D38F8FB4C31393A19A67FDD25E3EC2C3CC4FBA6788357117B973DE7976FBDE40B4A5216DE78F65D714026C376E183F5A320407E8C0BFFA434FC648B561ED6451CC5E3A887AED34A42D3D7939AC4BDD230CCFACFDAEB946641D0CA1C716BE6867DAE943B4E5EB4E2F63355F1F39903D29ED34CFBC2A2BBBF010AF488003CEB08B2DACE0BB8C9139523C08677AD210E7F5E4719CDC33D21E4B746BC75B3868AFE23DFEDA53D4FE798D159DBC65A31811BFB47257C9CF9DC1957C9857B67BCE472B3C6F3F771A4346641DFEA45EB4E92CFE65EF03CDEBC62E69CDBD978EE55476F243569ABDB3B0851C3EA2F9A1626F9917F477EF86626FBC38C153FA914FE99C0C9F7972A48A4D51235E4886063ED393EF68AB4204ABCED1AB939B79155318887B50A25BF1CB38B3E295E52B3A738268A5ADD821C109664C4E9D4B1EAB76AAB49306AB769FBB4A3D2BB698A18433F38AF353DA3127F9F1C51BAAEFC6F16090A195EC9199E7F054D187C950C27368EBE353B8E99FF9EA85332003B1AC3E721A2D88656D9C9324F11A04B467A638D683FF78186D169599276B9985938DC253CE69D199FE30810F9CCB510ACDE97CB8F8554238C39C3E34218D15F49779F427991732F6735DF88CED5AE8A61D0EA4C14AE5CBB8E4E7E4706F1905382312E58ACE288686B1B09A67F9146EC93E99E7E7DECACBF12FCD79C15839D7DD3B2B2BD89C7E4C2C4089842075BCCC57EEE21D9E4A6ECC3738125F62ADECF9BDAC4AE9EC2EA3DC5CD8680F4356C15B9CAC10086307863F35D63F2BE7F172961567F2A9D1E9C652D62576125961B26825592C408C5FE0D6FE34F5D578556E71AF1827AD3899348457B8C78318E82EB8C1101A3CC23BA9753C3F091FE8001F5A41497FF676A2810930A12DCCA10DD5CA8FCBDEF1230FE23CAC72A2EFED1EDE4CE5624F1977385FC582EF4CB77FF903AA100E26F97E4A46A70964441F7CCE7E36557D184286043DE1C93ADEE46523567E0C3F8D95E754BEF59011F93D27D6B20E8D4550E511D8EA9919784EF5C70B7463A388CEF9A49C870CA3A05DFEB24E11A13CEB9B1B3EEDF40B9DE98FC3F484868886A4B83616CD8D283A7801077C9307567C47327E42922DA556853E3CA83F3FFA4D23A3D3845D2C82127D6048ABE0B2E92C4862E691A2520579D6F996851121196D7356399FD2B6B23A7BDC98034F9AC86FB8C1D2D2EAA227BFE3407A8C5FE45EFA1BDDB8BCA94F6963D1939CCC5DF24C0CDF52F5EA99C26AD6B15A14E04FF27C6FC94C77F1084CC426CCE1860390C1317C630B5F40C9A7EEE5BB765C54BB4DC68D5DD3CB086AE3936F61A4276DDF579C38C319AFF17766266D6D2716DF4867A9D1736E30DF7A880E74CE4C3B67A1F369BEA751F914C215AA7E9923D81A8564A3D027F3A4AC11A2151DF4D4876498900F6796B21AB6FA631D6DF908DA998FE58C7734C7499F6695951A6034C1377E2F59B72F15E09245057F8CCB4638FB8E22B4E9C96AD23019CE6CECC401AFE04C2B51C06B3E352EEED10D0238C65236F2CEB6164A970DC1ADCDF6E943DAB5B01AF26C27B3A83E97D81A2B739BACA0F3294BD9483E2BA0445B32F3F4CAEC2EF6B28B4561F58E5BF9427B9E2C9B9792C05272A0941848B6C92850CD7334B3E222331432DBC8AF6FEA4F9ABBE8A09D4C88410007CABBF617BF9351DC4B430CC719236615962A4490A9506DB43C035B122AB6147B07C772AA0156FA5419293D5964145A892618661DFBE4ECACAC26F6E9CF7677C10D86502D3D55B4F3A3FE24D0DC6B66DAF99E75FAD3107AF4742F99F9B46F881CF7C2411F9FC281CEC6E27DFAB30E9E7ABA0B6E74200DC7F4E71D9890A3C5A734712F5FD096152CD28221DA4920AD93A5B0C5019FD2164AFA40404F8CD2EE2EB6B411EB2F6D2481347E818F517CAAC57B7691ACDDB83E25A1D3CB46849EDFFFF10B0B9DBF00E3557BBB4FF57B235AFC8E8195B24A9A4AA0F7D6D49DAB69AFDAAB3E5935AB51A8CCABB77BD5E24C845F56F49B8A397533F131BF6BA75D8BDFBBF32B615AFCBA665FC76F12FEF7F6898F91A9C539765571EBD57665A17FC8DA99156A0EE6C3DAB5F8140EAAA39DED5AF4AFF6977D5B3CDF382BBF835CB497DF252FF6D43B7F9FD9EF00FB5D53EFB5EBE957521B8D098D898DD3EABFFAEF2FE06F42E3D4A909AD7F4FFF3D2D7FDD7F9F3A39B1156F9B26FCB9F5A8FFEABFFAAFFE6BFFFDFE4CEBD346F1AEEB4F38EABF9E4A3EBCA4FCBF6F14FF77E7FF4AC377C3EAFF1F1DFE786D6F2A9E220FD74F91FAAFFEFBBBFAFB5B9B0FD7F6D67FF55FFD57FFFDA9FFFE90CC5967D7BF8DBFBF463FFE65ACA4FE9A10AB2D7DF7ACFEFB44E9AFEBAFF6D1BBF757635BFFD57F7FAEBFFFCBD3EA7FBAF70FE9F3C74AFBFDF5FF3F5C9346F9AEBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEDEADEB3F010AD58C7C]]>
          </MeshData>
        </MeshImport>
        <MeshExpression Name="Mesh_Planet_Expression" VertexColors="255">
          <Expression>
<![CDATA[//

// --- noise and height ---

// Scale noise to -1 .. +1
float noise = noise3(V.X * 3.0, V.Y * 3.0, V.Z * 3.0) * 3.3333;
//float height = (noise + 1.0) * 0.5; // normalize 0?1
float height = (noise + 1.2) * 0.5;
height = clamp(height, 0.0, 1.0);


// --- elevate surface ---

float elevation = mix(0.0, 0.2, height);

// normalize vertex direction
float len = sqrt(V.X*V.X + V.Y*V.Y + V.Z*V.Z);
vec3 normal = vector3(V.X/len, V.Y/len, V.Z/len);

// push outward along normal
V.X = V.X + normal.X * elevation;
V.Y = V.Y + normal.Y * elevation;
V.Z = V.Z + normal.Z * elevation;


// --- color zones ---

vec3 deepOcean = vector3(Decorium_OceanColorR * 0.8, Decorium_OceanColorG * 0.8, Decorium_OceanColorB * 0.8);
vec3 shallowOcean = vector3(Decorium_OceanColorR, Decorium_OceanColorG, Decorium_OceanColorB);
vec3 landLow = vector3(Decorium_GroundColorR, Decorium_GroundColorG, Decorium_GroundColorB);
vec3 landHigh = vector3(
    min(1.0, Decorium_GroundColorR * 1.2),
    min(1.0, Decorium_GroundColorG * 1.2),
    min(1.0, Decorium_GroundColorB * 1.2));

vec3 color;
if (height < 0.4) color = mix3(deepOcean, shallowOcean, height / 0.4);
else if (height < 0.6) color = mix3(shallowOcean, landLow, (height - 0.4) / 0.2);
else color = mix3(landLow, landHigh, (height - 0.6) / 0.4);

C.R = color.r;
C.G = color.g;
C.B = color.b;
C.A = 1.0;

//]]>
          </Expression>
        </MeshExpression>
      </Producers>
    </Mesh>
    <Variable Name="Decorium_GroundColorR" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_GroundColorG" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_GroundColorB" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_OceanColorR" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_OceanColorG" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_OceanColorB" Comment="vec3 et array font chier"/>
    <Material Name="Material_planet"/>
    <Model Name="Model_Planet">
      <OnUpdate>
        <ZExpression Expression="move.Rotate.Y += App.DeltaTime * 0.06;"/>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="Material_planet"/>
        <RenderTransformGroup Name="move" Scale="2 2 2" Rotate="0 673.3366 0">
          <Children>
            <RenderMesh Name="rendermesh" Mesh="Mesh_Planet"/>
          </Children>
        </RenderTransformGroup>
      </OnRender>
    </Model>
  </Content>
</ZApplication>
User avatar
Kjell
Posts: 1964
Joined: Sat Feb 23, 2008 11:15 pm

Re: New planet mesh generator

Post by Kjell »

Hi Ats,

There's no random component in your vertex expression. The noise3() function is a 3D perlin-noise calculation that gives you the exact same output every time you use the same input. So your planet mesh vertex coordinates do refresh, they just end up in the exact same place every time.

K
User avatar
Ats
Posts: 907
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New planet mesh generator

Post by Ats »

Oh ! Thanks. I'm on it :)
User avatar
Ats
Posts: 907
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New planet mesh generator

Post by Ats »

So in the end, I calculated a seed outside the MeshExpression:
Seed_Planet = rnd() * getSystemTime();

And a frequency inside the MeshExpression:
float freq = 0.5 + (abs(sin(Seed_Planet)) * 1.0);
Though, it could also be outside to avoid calculate this for each vertex. But it's not as if it was updated on each and every frame.

Then :
float noise = noise3(V.X * freq + Seed_Planet, V.Y * freq + Seed_Planet, V.Z * freq + Seed_Planet) * 3.3333;

And I get some nice patatoïds.

While doing that, I got some funky balls when the seed is not outside the MeshExpression.
Maybe I'll use that later for something else :lol:
Screenshot 2025-11-03 205049.png
Screenshot 2025-11-03 205049.png (225.49 KiB) Viewed 1451 times
User avatar
Ats
Posts: 907
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New planet mesh generator

Post by Ats »

How would you update the planet mesh when the model is a clone and the event that triggers the refresh is outside the model (general OnUpdate)?

I already tried a lot of things, like storing the planet model inside an array on creation, then retrieve it when pressing spacebar and setting a bool inside the model to true, to trigger the mesh update. Nothing works.

Here's the code with the KeyPress spacebar inside the planet model, otherwise it is not working:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" CustomScreenWidth="640" CustomScreenHeight="640" FileVersion="2">
  <OnLoaded>
    <ZExternalLibrary ModuleName="opengl32">
      <BeforeInitExp>
<![CDATA[//

if (ANDROID)
{
  if(App.GLBase==0) this.ModuleName="libGLESv1_CM.so";
  else this.ModuleName="libGLESv2.so";
}
else if (LINUX)
{
  this.ModuleName = "libGL.so";
}
else
{
  this.ModuleName = "opengl32";
}

//]]>
      </BeforeInitExp>
      <Source>
<![CDATA[//

const int GL_DEPTH_BUFFER_BIT = 0x0100;

void glClear(int mode){}


/* Boolean */
const int GL_ZERO = 0;
const int GL_ONE = 1;

//const int GL_LINES = 0x0001;
//const int GL_LINE_LOOP = 0x0002;

/* BlendingFactorDest */
const int GL_SRC_COLOR = 0x0300;
const int GL_ONE_MINUS_SRC_COLOR = 0x0301;
const int GL_SRC_ALPHA = 0x0302;
const int GL_ONE_MINUS_SRC_ALPHA = 0x0303;
const int GL_DST_ALPHA = 0x0304;
const int GL_ONE_MINUS_DST_ALPHA = 0x0305;

/* BlendingFactorSrc */
const int GL_DST_COLOR = 0x0306;
const int GL_ONE_MINUS_DST_COLOR = 0x0307;
const int GL_SRC_ALPHA_SATURATE = 0x0308;

/* EnableCap */
const int GL_BLEND = 0x0BE2;
//const int GL_COLOR_LOGIC_OP = 0x0BF2;

/* LogicOp */
//const int GL_INVERT = 0x150A;

void glDisable(int cap){}
void glEnable(int cap){}

void glBegin(int mode){}
void glEnd(){}
//void glVertex2f(float x, float y){}

//void glLogicOp(int opcode){}
//void glColor3f(float red, float green, float blue){}

void glBlendFunc(int sfactor, int dfactor){}

// Pour le screenshot
void glReadPixels(int x, int y, int width, int height, int format, int type, xptr data){}

// Coloration des vaisseaux sur un Hit avec une Light
//void glLightfv(int light, int pname, xptr params){}

// VR
//void glClear(int mask){}
//void glClearColor(float red, float green, float blue, float alpha){}

void glViewport(int X, int Y, int Width, int Height){}
void glGetIntegerv(int pname, xptr params){}

void glUniform1f(int location, float v0){}
int glGetUniformLocation(int program, string name){}

/*
void glDepthMask(byte flag){}
const int GL_POLYGON_OFFSET_FILL = 0x8037;
void glDepthRange(float nearVal, float farVal){}
void glPolygonOffset(float factor, float units){}
*/
//]]>
      </Source>
    </ZExternalLibrary>
    <ZLibrary HasInitializer="1">
      <Source>
<![CDATA[inline float max(float A, float B) { return A >= B ? A : B; }
inline float min(float A, float B) { return A <= B ? A : B; }
inline float mix(float a, float b, float t) { return a * (1.0 - t) + b * t; }
inline vec3 mix3(vec3 a, vec3 b, float t)
{
    return vector3(
        a.X * (1.0 - t) + b.X * t,
        a.Y * (1.0 - t) + b.Y * t,
        a.Z * (1.0 - t) + b.Z * t
    );
}



/*
  Fonctions concernant le screenshot
*/

private byte[18] TGA_header;
private byte[18] TGA_footer;

{
  TGA_header[2] = 2; // Uncompressed RGB
  TGA_header[16] = 24; // 24 bits per pixel
  // TGA_header[16] = 32; // 32 Bits per pixel for grabbing alpha transparency

  string s = "TRUEVISION-XFILE.";
  for (int i=0; i<length(s); i++) TGA_footer[i] = ord(subStr(s, i, 1));
  TGA_footer[17] = 0;
}

void captureScreen()
{
  if (PhotoMode)
  {
    PhotoMode = 0;

    int w = App.ViewportWidth,
        h = App.ViewportHeight;

    TGA_header[12] = w & 0xFF;  // Width (low byte)
    TGA_header[13] = (w >> 8) & 0xFF;  // Width (high byte)

    TGA_header[14] = h & 0xFF;  // Height (low byte)
    TGA_header[15] = (h >> 8) & 0xFF;  // Height (high byte)

    byte[] buffer;
    buffer.SizeDim1 = w * h * 3 + 36; // 3 bytes per pixel + 18 header + 18 footer
    // buffer.SizeDim1 = w * h * 4 + 36; // 4 bytes per pixel for alpha transparency

    int
      hi = 0,
      fi = buffer.SizeDim1 - 18;

    for (int i=0; i<18; i++)
    {
      buffer[hi++] = TGA_header[i];
      buffer[fi++] = TGA_footer[i];
    }

    glReadPixels(App.ViewportX, App.ViewportY, w, h, 0x80E0 /* GL_BGR */, 0x1401 /* GL_UNSIGNED_BYTE */, buffer[18]);
    // glReadPixels(App.ViewportX, App.ViewportY, w, h, 0x80E1 /* GL_BGRA */, 0x1401 /* GL_UNSIGNED_BYTE */, buffer[18]);

    @FileAction(File: @File(FileName: "Planet_" + IntToStr(getSystemTime()) + ".tga", Encoding: 1, TargetArray: buffer), Action: 1);
  }
}]]>
      </Source>
    </ZLibrary>
    <ZExpression Expression="setRandomSeed(getSystemTime());"/>
    <SpawnModel Model="Model_Planet"/>
  </OnLoaded>
  <OnUpdate>
    <KeyPress Name="KeyPress_F2" Comment="F2 - Take Screenshot" CharCode="113" RepeatDelay="0.25">
      <OnPressed>
        <ZExpression>
          <Expression>
<![CDATA[//

// Pret a prendre une photo au prochain cycle, sans afficher le texte
PhotoMode = 1;

//

//
Decorium_GroundColorR = rnd();
Decorium_GroundColorG = rnd();
Decorium_GroundColorB = rnd();
//
Decorium_OceanColorR = rnd();
Decorium_OceanColorG = rnd();
Decorium_OceanColorB = rnd();
//

Material_water.Color.R = Decorium_OceanColorR;
Material_water.Color.G = Decorium_OceanColorG;
Material_water.Color.B = Decorium_OceanColorB;

Seed_Planet = rnd() * getSystemTime();
@RefreshContent(Component: Mesh_Planet_Expression);
@RefreshContent(Component: Mesh_Planet);]]>
          </Expression>
        </ZExpression>
      </OnPressed>
    </KeyPress>
  </OnUpdate>
  <OnRender>
    <ZExpression Comment="Prise de photo" Expression="captureScreen();"/>
  </OnRender>
  <Content>
    <Variable Name="Decorium_GroundColorR" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_GroundColorG" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_GroundColorB" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_OceanColorR" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_OceanColorG" Comment="vec3 et array font chier"/>
    <Variable Name="Decorium_OceanColorB" Comment="vec3 et array font chier"/>
    <Model Name="Model_Planet">
      <Definitions>
        <Mesh Name="Mesh_Planet">
          <Producers>
            <MeshImport HasVertexColors="1">
              <MeshData>
<![CDATA[789CEDDC7F8C95E59507F00B8E5A51B72534C632646CABC03F6B2233A38444ACB6580A163042534B2A3AEA5F4EC3509B4B635A1BD26D9A3AA9714CF12F0B161BEBA6A52950A1545AAD90582C0C266E360164ABC4C1C64858573B6A4560EFF7FDBCAFF7EE26DBB4BB75FBEB7D275EAECF7DDEF39CF33DDF73DEE739CF73EFEBEF6D346E3BBDD1BAD63C9EFFDE53FCDBB832FF75E5DF35E317BD79607D7363F7E8BE075AAFFBF67D6BC21DCD37562EEAFA975B1A4373267C7A65634D6E6EACF9D684AF0FBFE7DE3913FEF9DEC69A079A3F68F577D7A543D74C3EEDB1F4DE72BC7F70F98A1DBF9BFCC55FACFCDAC919439BCE3AF8C3DE15DB27DDF3BDC6D0A2AE7FFCF6F12913364DDDFCB17FB87FDD235B6E3FFFEE874F3DAE7DF98A7967EC59FBC6CA8CF0D349AB3ED3BB62EDE4D59FD8B162D359D3AF9B3E44C3558317CE18DD6FC4EE191FBA78DAF20B67F4CE5C35383CF5F0653B6EFD696B8CD10D241BE5876BF75F31FB6863CDD6CB0F1FBD79F8DB97FCDB0B4639F0C90BCFBE6BF8C51BBED3D558A3274DBE7AC13FFDF4B33F5FD74C4F23BA8B3E3481C9E93734D67CF0387B83CE93277DBA70F2C9ABFA879E9F74E3271B6BEE9ADB7CFFE96BBF7DC987A7DD3CBCF5F29E298D35D72C8A76DAE9D03BF39EB5870E9C39A3B166D2B37DB36E1A5E36F685817B179FF3EAEDD737AEBCFB376F0DDE3577F8E568FCD086E8FA810773CF8C1F47FA05E31969EBB18CBAE475AFC16BF058749D3F6EDCF18B223BEFD7356948B7E7BA628111FB663DD05C36B6F5F2C69AC347C77AAE5FBF713477DEF234DD58F483EEDE59EB9B3D53D2CBBDC1E1D4086EF834AF03C3FAECB875786ACF53D39677CFF8F5339B976EEF7EEF4EB63C3CB0B4B7FB3084E97972C991C55D47594D5AB8F79E7BF18D7F5961949FB57871D74F8E2C8EDFF0EAAB177CF9E39FFDF9DC8B175C3167F757A6DF76ED89BDBC199457EF6491BB68E25EA34015AB6F3FFFF6EB4F3D4EC258CFC3031B475F9AB9AB7FD5B65FCE9E7BF1B627C8FFD83FDC7A73789B9ECDF7BF35B87A278B588A9F18C85374C03ADAE2007CE84337F8F329FF924C668958F1DE58246CEFFEF7B98B3742E0F894934BA66E8673C5E1305F3B9DE9CF965DFDF72C386F7FA7BD1F6E45D4D881207EE88016EFC39E5B9E7EE1EA49F34E3B7CDB924BFADF3C889FFA93401AC4C8A715944AF9859C44D3E8065A75E2A98FFE2493F9CADCCD4BE78F959A14ED89F6E611FA2CBCE2C9D93B9FA11599C6253359E2858768052BDED432B1EFCEE9F7FDC82874264D8BF746A183F6CE71EF59F0D2CCCBF7181D0E34648B3E241B970E46A7E7BC33FA071FDA0013684C9AF776CFB447E9D6B8325CD6B3E276ECBAF0ECD5CDB02B5825B32CDC0513A3D3365971DEFD464C2E9DB721D174CF5A98F8543BDCE850E25F78AA533299328C7BC9211FCFF5973DC435ACB00556308106092C85894CC8D7F29271C9211362B08203C964424F8CF08B4F49638B285BD69BDC4007C840834530218D647A1A174A46679DB1C4AC9E241BA5CADEE92F33C83F6CF1A9F7FA68B966F289AB4647F2BA7704E6C9C67B4792C90F8ED096D716B6FA3C3522F75E33F9EDAB7E3522CFCB3010600BF93C4513A8B2421E96DB49A615BFF385FE18C25F3C2EAF1A056FE10C73123C23A0CD223D2106AB8A4591DF29594FF9D3A778523D3DE35F2D466405FDA10D0D1A92090123E2309D69EBA94A67DAF2053D59E1390B6D5E888FF68C785AB59F5C03EFF4C9A7FC6826401A399EADFC4B7FCFE84E1BCD1CDC6B5E11895B8F79827876C08A643D59C4779EBC62043720635C7E377A5BE78A7566869ED4F8C63AACA30F5BCC3ACC1FF4248D9E6C81362F57B19F5947253368938C9FE2CB330E1358CA46F2E9094951C952F7F208DF19852DECC5134F6A0C310A8BDC4502B6D0DC1CE32B2D06E7495ACCA05A913F76C00CD6EC140EE6C39EF846D1C7A766686623554EC8DCCFFC8126BC2F4EE1B0BA79E093877E5BCDCFA33F09DAF53113306BC56A7357BA996561ACD93B8618451F9FD293047DC831E78189D957A2A5798437711833DD4B13D689411270A6EDA355835607B08203F99D989B93F378DB9B8D124FED6284269D735D1AF2175BD805872F4D38F68D5FACC47908875B4B5E278D45D623E6666665A4910C07F89B955953F0A378C9FBD5CDD81906C67790A1032FF02669ACA043E7CCD09AC5BDF0B426A2336D219F78796BB01DADEB9AD63EB0856AE27BE1AE0DC52ACF5A2F4FC6CD4BADBCB02231FD9D1F5FDA5AF74C78ACAF782599CCE49F8707928197AFE09112C935C50AB2F0AC151F04E8430234D8C28ACC0F325F8D6E10B62E23D92846C41C7AD2906EA22F91F5E20D34E15F2B411EA1094BD92842E98981FAE7E9DBCAA88517206C74B6D321B388238B49A06D19AD051F325ADE3FD7F5D68374834932D196E364F2172654F7BE78C38DC779C7BA1BFE5A784ABB9529565B8FC3107AAFB46639F3C79289E695085B0BE77990D969F89079CF9CDD108355EC5FBE4205005779CAA7DAD3D2187217BF74A22D8EF4A4037DAA4889752C850FCD21E0D32095E763C6A5F9C070ACC67F8C853C3FC2FFB5731349BC402B3662144BF3E49B3FCEB3F0DFDEFDBE9D990D0619FD8DA24E622C11ADFD9EB58944D24886B95A849ED7AF2F5676C55846E171E3C201AFDA789E1A094BD4106EBD194B458A118D3E309C5C140F5558C1501F9FDE5C6005796319B7626398495BB6B31A2B2AD6E15B22EB9BEB939DDCEBAECCE56EBB562C88411C832199A2491CBD51E457DEE1353E22BF8C8B22467819E634C1700C09AB4E9D626385467AC2561CE94F9A582B997865D655F0A439EFB83733C81DBF5B5EB0A69D2B5637DDCB1615B2B77BB252C13AB664AE57C5E653230B5AEF4507CFF269561A5D4779C1B8BC4C1FBAB9971CC87C7DF88D959F7BC7F6F85A6C8A32A31C1C815EFA1BCDECA08A3FB1985756F045E6109F3BC976882D6CAD60B3920DABF139EBB57B16F02F7BD982AB22F485ABC7779C76587F7C9361ABCC106DC9C199B2A67776A25F84EA091F12A074F7C3990DE29B68721716B9972FC8A7A19E6250449C1AC101BA0793E493DE157483E11706566E3EE7553AF08E5880C62F5BABD96D4FC00D37F0C4584679E1A1CC3FE7DD9FB9811631C8B3F806017A408FCF0686BFDFBD675F95DFE2FD48C9CA3D31259AC4203420831B58211B90295BBA17AB7999C77999BFF88E7513FBBE7A302BF4581D4BB2EACFB85A6243E34A6C873F04C40826934C1ADC8C58C56322D788BC0C6DB640F2BE1F458BEF7E34B510B8410C9F2B3FC683BBA75C37B8FF0A5AD1871FDBD84E1F8209DCE2EFF9E3A9D23C391B5B30075731E1B573D3572CF3085FA432B0E00A9AB89764F9907C9AB302131A451519676075A4C87CB0621D2BE88FDB55E4265AF3FE8EA67631425B56D39F4764803DADECD1784C0EC9BBBDC5FFEF29E33456ED1DA11B7EE2EA844D592DB2822F784ACEC13198E88FD5C6DA5BB4FB543BDC449338C2C0698FA6B6433EACE2AD2DC74BF9059EACA8726022030F31103FB3FAB86B2E1CF8AB9DD9EE685A198829564320D59043BFA5157D6E5BF2F49E370F622C4E6257954BC3A363DFF8C8BD5F3B89C3A9C7DDFD1B8C25272BB71BCBA7863E6C49C67DF2A4F81541AC88FDA9F8C50A31424F1AC6E6A74620A885BFE06B747AD2414F7D8C85F3F84F32D6E15BD656AB3E334F5628FC483696EAA9CF431B120DD0C0C6CCD7B75E8E8790973F459C71F9421CF9F4CCE959976329C626032EEDF51EF3F7FE1716E53D0D8DA88F713D11A1A4375F977E2FAC10DDA2559C2EDE988A476766C63A7C9313F6768C4B131C1017188BBDFA8B149F7E7E5BB889CF46F9C08389D46A751EDD44BD7897D94637649D6B1438934FCEB627D49CCFDB9F6A677882A5BCC39B6456FC0926F0C1739CC4CF68FBDAB967ACCD2CC3BA07F37109AFAE1B9CF9C4EC92D52460E9B2562E4BED34ECE54D08F3290DB19A9EECADE61BF10E266048F0DDB182D59D1E87BF58133B6CD103CF93AD524B0CCF3BA329BE495D31DA1A0526B9B7BFE4241D322F3DB2987C718A09AC803064E68F6516315854079B47AC7F83A418A7273F7A22E01B3D6948DB4F172BE0AC88BE3521ABB3455D7C1146DD7E3E8F90BFF5D889ABFA861E39F6F655970E65CDF78107B32A8A1FE28D203B6777F4DBF644DEED7CE682F1ACF2B31F78B0B57AC81A62D958EA36878FA6E691F703C346B96FD325FD674ECF5369ACC75846D13FAC7BBB277C9B7BB19EC64AB63D6F7F303DB1D7B8E1CAB4473FBF2D58E539F49DAE6A0D9DD79DCF841573760707D2B4DCF9FC973FFEDD8F9EB73F91F864310BF85C914DB71CCF7C848DC32FA79A74F8686AB3799A66BD33FC72AA166923E1F4A379C6F14B389915C7AF9FC9BEF0E8FE5583F1DDDC8B339F796966661D4FCE2687042BCC9B86978EEDDB77E3F0B2B1CCAF263DFBE601F5D9E0D5332595961F74FB34F5CAAACFA5435B8FA59EB0E4F554F35A6BA79FD09F8F76FC2E719699CCF6EEACB086A76685DB3D2391F5768F765AF14BDB5303C3C980B79F9FECB67B4A72E258CF078BB50B647816FEE1FAD881C4E1C6D1487C656E32556B7E7C7FEA16C6650B2B92D752BB888E6C5FDFFCD4D89E7D6C595758978A55D6894B5BEF21A35D9F54D57B9E4A5ECBCC3F3827BE6EBB36D5B485BB488312B4F54C06587005AC1257A9E6CD1FCF7980BC4FBCA5AE12DDF8971F33475FD78C778F4FC91CE8B57321C32FA9422E9CDCDF62EAF7BB79C4B8EB9BD1FC5745CD3873E620BAB1F5AA45C55AFBA9C79375A76E4EB68C575EB8FACD0391C4CFFB0A49470E640727EC5ABC315C5DB54D7F38C33C382D1B4B563A7CD4BDBC96BADC87A7A52E973A605E6F6A69326B5656A667CE2033EC9DBAF9B4C3E105AF25FB9DB88AB66C4C0573D359C9386B271BCB28B425998DE49353219076BB281B4753EF5CBD33B3A4B4AC6BE6FD5B8369CF5E655E6172626F7217DBF3FEBE1FB9F757238F1C3BAD35FB8D061892DA41CF53557B5AF89ADF71030EAC8686BBF6B6F2D3C4C7DC1B06771F4EE5B13503DC543C835ACCCE5C346CF4E9358B7EF61F59118721A21873F0197F484895A1EBE8B4479399C2A48DA361D22D4F27231C3A9095CF606BE4545792919B47E889CFB807EDD420B64FC2409E3AE7D53C09EFFE4D9E8D79BE64ED96FEB46A475655BD82FCC25D99B3C07CA0CC33891759454E88F4E35364863C5FE66D30229E24A73F3F091FF05F7E802DBEB19A759959CE1F232DB2D64E960D6273E6CF191DF2C9FCF3EE370A8FCB99E29737F10137448A3E3497C70E15D56E3C61351E6220968A629A8B65BAC95134CC3338159578567EC016ECC207FACB48720E8FCC3E9AD90A8FF39D117930D59FD47C22532EB2434537FCBCB1C33BF209E4C520FC2B0C2F18CF6C223D33DF78E16A58E1128BDCCB5FF3C7B3E2C11F9E85A47C2293E03C7B598AF39886639993ECEA87BF11F99126D8C52E1655D11754D90E87B39FCD0E4BB5BF1A666A2FB374619DA829B362113B18C2CB3CAEA7BB78247DA62D974F30077A3C22B2CAA755C1903C173F74F1A1E2D4094DDC5B54247F224BC0847F69C5CB46372E04640F79400608975299496CE2152F908639A20F1B454D9EB8CF75D19C1F79472E320AEBF8D10C275928ABAA784D1EC82A60577FE5DF589A99E499D3C50E3F66455DE9C65334C9933EAC0B97CC94606BDCE87DFBF934274DD4CB00321BFE9B8989BBCC3E5BCC2A9E233CAB3D6BAA9E329FB082FE709325E425B902B6728E7159C7A7620A326C87439B75EB9A3C5E3D738B5946C1314FDED4EFE69D417FCC1105E24BD6250D0F3139EBAEACA7D29317B2DB56711873B4C0413BACCA676BD19E8A7C6A26E1D5DEE2155BCC45C9C10DB3771AF25795ABE3B5B667EF6856FE0DCED5DE785EE90F61F1A55EE05E7C28912F7248E793C82A806EF1C17B778A145CE5C7CCB5B2360C1AE6A5EE250DA3F842DCE12776E1155FF3B2F97F2A86C924455629F2864F21695E6A658109EC155310839ECC59CE210BAFE1B9F93CDDB0176EB86A9E0C31E89189337C4187D2B3854FD968758339E45BFBF854768580D834DF86152FD0500C8A7A390A67B045EEF2A928C07FAB24DE91434AAF15FDF98E9CF26955E4373D79C12ACF7A813E709007A265726CB2075B3C23E08C875821AEABB1320AB64306C2B0C56ABEC3ED54EE52A3C8BD34CFA9A057E61AD158BC2F27E0004685797922475B2B1A9C8430EB588A692C4ABF70269A785FE5E7B4545199B8AE9E0EC9D3FCAE3DCFBED4B2321A1CC4858C213AE866C44E3C8D0255DA8A3B71443269E4E7045E95E76162458CC3F84C02CDC56F32E9844DF0C40A7580EA699E7B73E6ACF97E7AC213E7C9942DADD621CF0B584726EE61A33EFA1B4B7F23926C45DFAEEE5D78B69EF461A9D5037BE18903229A4F79530D813E58ED531258448E0A007C6085F3E211F38D0E610C9407D455E88FABF255C5F6D41B70408EADB259224E1FBE702F8F2427A7BF5A45EEA2338FD0BCFCB4E003F918AE3250F2BCC86C728EFC0319F953D65227E123DE51B1E11DF8AB20B1572CA8C6C016AAD57324599A8D9515D1DFA74637AEAA827A0EB6902667CA09F203FDB5CB9C721D9DE94F0E244923811F652DB520199504285595AEF83DF535DA5695741C80ADBC21DE5921EAC54864E5899028564D920DF04A058947E88045D88BC9694DED287AAA73AA547BAF5E9DB5EE79FBD569AB0A6D7050095403C449D18499338A53FBF206CEC86C3CCBA76AC8AAC7EAD55ED5ABD5A553CFDDB31632BCAC66AB7EAB725B555F53773D559C2BB457A20A9A333F8D2B53811D3CA68EAD829D9AE992D7CB5A68D19E5382AFCC5561669D598C6ABCCABC8870CE951760A282CD22556EF56D7B0AD53E42720CDD788D0721D3AE9FDFD17CA838979ACADBEA4FF054896451F5559D56FB4D9C761F56BF8549562F4B7B8DC276FDD566D5907F567CFB445D9DBD338AD3647613B4872D394D1A9EAB152723FDBAACCF97BB4845B559E559EDBA38517D948F54D4610801E72673463AEBBB3007F7CA736DBE7D527C03C35DD8087FF8C0D32E03DB3B2BF9E41B0B027C814BD50E57624E353BA7AF72EE287A6A577DCE39F3EE199D11F1BE9DC10373C482BABA1ABB0A7FCE64E4BC68BB6E2F763024D960CEEECC7A3E781CEB30D0BD6AF8F04CC6B9708671E180993829FA3021ABE69CB08D7FA3594E11A79DD7D4FC8D655C7C1017F4F71D27BEA339F9BCC353D0902B60D2B96791F3105B8EC30732ACC604D84215C7B00B03931553DB0F3E62C728C6C50D27CAF91D07680EB7EC336E5EDA577C33897C9259AA674EF87CF7A3E2427B4E2E4DEC2301E6C938D9EF284E53163C242DA3AF6EB6B9D73F086D271D7959BBC8957F785656917932DFCA93A2C86F051B710F923084121EFAD45DFA63F2235B72F2D17B9858F5E13FCC49E31D7EA703F6969E5A9ED9115EF1F80D3F0F4EBC404F48CA0F7AB2AE3A851AACE404B94266C81374FCA26AFDD78EF7DBAECDAE91B1F4C1F3B267C1319CD74E2656E333DB610201F2453AFFB29DD5D9055FF23A099903E73475A2A3FA343EDAF0E3AC0FB02E7B7BA95A445BAC68C7C5FA66FB756058A45768048783C5F97168C88DB253FFD082C9A74A6662A9FE65BE2DCE8CE3129918252EF8825F640F91E2D39CC53D7C191FF18E48C155BCC50D9A60888C61C4F239F258CEA843034FECE6C053A4600BDFF1A3B813416227F5E5B103D82503E033267F737D9ED4BC4007BEE0F77CF3227B4619C1EE899E7CB7AEF8EE1DF4589D533EF3C749E6719CC9BC2DBB51911986D8D3EF1FAC3C95E8A0D519ADD9D2F0CBA9C88CEE870FACBCEA69C50555DC13717CF1E6C1F899A5767378B09D1972E63C9CD11E8C9A47200C253EA261E4DF7A332471CFBDBC2F1E31DF4E0D1D30013E9716F84029FB46FDB3EC0779FF40D147269415791003B1F4B2D66B2501AFA02D5AFB6615E314386766BCB11BDBA10749FDB11167EC0E89538C3222FE1B1737789367B14EAEA6B3BD3939C1B8F62531443B7B59018D2A1765749A609A48C7377B46FCCBD73EC573D98077780AAFEC1CC19F8FF89767C5829D2F3CE12FB18603FAE3214EC24146128F556C268FC95A3EC573B6603B06621DBEC948D5F75983396CC50B993880757688701EFFE9667FA7FA5E57180B49BBAE108649F9EC2BC7CDAE65BB2299EF2667262FAEC5785695773F8CD5F0879B98829B5C61475B64B90BE6EE25D39E94FE7C67E7080FE983A5B4B23FC822FE35A2DA3B4DF01003ED19D9E3C37392ED10C9999DFD616BAF10567D451442ECC662971663C52609B01529FC220FF0AC28C0FC8AF3F12CCE93D6C6AAFA3E06EBF8C88E8C8A3476E1212ED94BC27FF18E69A25E9E613B1C6048BE1DB42A57B0295982B63C2E5AAB5C115BC4B218E4594C90E54490D8513FA72DEFB0F7D28E8C57712F98F816DA9E7DD9436329ABF98BA7F854DC890E357F72AAEFB1E555DC9163371C3E76CDA0648F8FAFF911F3C591BD952A2EB29305077BFAF20956C381ED767030D37900231A9D4F696BD79EEFEC3F8A02915EE99F3A683BA25797BBE4348483DD25D12AA6C4177C48B30B430EDFC90F70B00B8651FC284FB2D14E1F7EE2AA9D3B23E2097C30044AF6656042A65D39FD71CC9E609B79D5D9001AD2D67E2524B1141FEC8B89414CC66AF162EF00563E15D7625CE6E417B6C34134F105BFD81B6AE3F6D660B58F199DC514CDE52E2DF20CD6E1B33312031D39443EE15FBED6DFE8A4E1036DE516594514C85AECC225A735EC796175756A28B8D927E5538CB56F4526FFD28A4758EA2EFDF9C55EB0481123763CF91407A00A4FBC92A5E504D9006F7158148B35928DC222F122AE59EA6C499593A367992737546747577F423680B6F327109613F8C5284E16195DFCD25614E3985C214B54927DBF33F2C59DE8F044CBB9CD79673847A752ADE696EF427CA9ACBC3DB22571AAAEAB3239F98B1FB9F74B13AA6A6A9ECFF1EE4B3355265532B578EF5C1C2FC80950CD7F795247A6CAA70A98FA953A58E60CA9FFA75D952CF395AC7452095403F45E5D4B452BFECD9334B56EF549FAABFBA9F8F9A63499EAD2FAC7F7BD33B5A8A3E6AEACC4534DC501594BBE6AD75ABF3E4CBE2782674AE7F919594E34B1119230A43F6D55E7329F3E3E451D9B8FEC63F2BEACC583D55E49FC05EDCE1AB81D52F94D645527E84EB466E74E3F3AC7187F9C7A5C4D5B7DD85941A737557DCF7935D1A0A7FAB016EF5565F88877AAFA7FCEB16217E6C48AC695E4AB2AAB567FAD3813AA9A6D37573B29A90524F3A76E6F67845F4E8DB4C7BAF3F97CF7CAA76C61A32A3ADBFDFA4BBBBD7F28FBA9AD4C566882C9DAAB3EC10A0ECE97AAE73B67A8BADE3E473A7DC8BD79ED1B0A27B2FF55FC0A4D611746D199FEAC539F27133FF1BF627EDE57F3E5BC62088FF3B5BA589BB77BCA184FD568FB242C3AB137A8883848E2BC11315FFCC2041A468CF6A9C687BD7C2A57F06C9E5BDBBBDD4BABCA2F6C8A9534A1397D9CCC8509CD61E81EA8CA1572918C615CD6613EBFB4F1EF2BFD4567B146730890090792CBF82D72054CE404F9041A788B27DAC5ACF8958BFA86A28B96BE5297B4E8AF9D3E301411A3C58E2EC4A0C1FA4BDF9170F22AFEA5279D9D93A8CE3D449208C2BAEA6C6DDE8B533C4C163EBD94000776654FF79A45A232CF9ACC22C20A68D0A7CCBD854FCBB3C4E33941006D67A370B5E270EE2AF52FEEA52D3D45370EF03E1B0F8E1885FF3396B816D1F20FACAA9EF44986F6297BF3D4C9DC206DFC2E87C80F64FAAE493BDBBCB1B260ED103CF150DCE19258E041DF4BE0C754C517756178C5CCE0F0C3B5339FD85D46AEF31F6C37629E46D9D38F8FB4C31393A19A67FDD25E3EC2C3CC4FBA6788357117B973DE7976FBDE40B4A5216DE78F65D714026C376E183F5A320407E8C0BFFA434FC648B561ED6451CC5E3A887AED34A42D3D7939AC4BDD230CCFACFDAEB946641D0CA1C716BE6867DAE943B4E5EB4E2F63355F1F39903D29ED34CFBC2A2BBBF010AF488003CEB08B2DACE0BB8C9139523C08677AD210E7F5E4719CDC33D21E4B746BC75B3868AFE23DFEDA53D4FE798D159DBC65A31811BFB47257C9CF9DC1957C9857B67BCE472B3C6F3F771A4346641DFEA45EB4E92CFE65EF03CDEBC62E69CDBD978EE55476F243569ABDB3B0851C3EA2F9A1626F9917F477EF86626FBC38C153FA914FE99C0C9F7972A48A4D51235E4886063ED393EF68AB4204ABCED1AB939B79155318887B50A25BF1CB38B3E295E52B3A738268A5ADD821C109664C4E9D4B1EAB76AAB49306AB769FBB4A3D2BB698A18433F38AF353DA3127F9F1C51BAAEFC6F16090A195EC9199E7F054D187C950C27368EBE353B8E99FF9EA85332003B1AC3E721A2D88656D9C9324F11A04B467A638D683FF78186D169599276B9985938DC253CE69D199FE30810F9CCB510ACDE97CB8F8554238C39C3E34218D15F49779F427991732F6735DF88CED5AE8A61D0EA4C14AE5CBB8E4E7E4706F1905382312E58ACE288686B1B09A67F9146EC93E99E7E7DECACBF12FCD79C15839D7DD3B2B2BD89C7E4C2C4089842075BCCC57EEE21D9E4A6ECC3738125F62ADECF9BDAC4AE9EC2EA3DC5CD8680F4356C15B9CAC10086307863F35D63F2BE7F172961567F2A9D1E9C652D62576125961B26825592C408C5FE0D6FE34F5D578556E71AF1827AD3899348457B8C78318E82EB8C1101A3CC23BA9753C3F091FE8001F5A41497FF676A2810930A12DCCA10DD5CA8FCBDEF1230FE23CAC72A2EFED1EDE4CE5624F1977385FC582EF4CB77FF903AA100E26F97E4A46A70964441F7CCE7E36557D184286043DE1C93ADEE46523567E0C3F8D95E754BEF59011F93D27D6B20E8D4550E511D8EA9919784EF5C70B7463A388CEF9A49C870CA3A05DFEB24E11A13CEB9B1B3EEDF40B9DE98FC3F484868886A4B83616CD8D283A7801077C9307567C47327E42922DA556853E3CA83F3FFA4D23A3D3845D2C82127D6048ABE0B2E92C4862E691A2520579D6F996851121196D7356399FD2B6B23A7BDC98034F9AC86FB8C1D2D2EAA227BFE3407A8C5FE45EFA1BDDB8BCA94F6963D1939CCC5DF24C0CDF52F5EA99C26AD6B15A14E04FF27C6FC94C77F1084CC426CCE1860390C1317C630B5F40C9A7EEE5BB765C54BB4DC68D5DD3CB086AE3936F61A4276DDF579C38C319AFF17766266D6D2716DF4867A9D1736E30DF7A880E74CE4C3B67A1F369BEA751F914C215AA7E9923D81A8564A3D027F3A4AC11A2151DF4D4876498900F6796B21AB6FA631D6DF908DA998FE58C7734C7499F6695951A6034C1377E2F59B72F15E09245057F8CCB4638FB8E22B4E9C96AD23019CE6CECC401AFE04C2B51C06B3E352EEED10D0238C65236F2CEB6164A970DC1ADCDF6E943DAB5B01AF26C27B3A83E97D81A2B739BACA0F3294BD9483E2BA0445B32F3F4CAEC2EF6B28B4561F58E5BF9427B9E2C9B9792C05272A0941848B6C92850CD7334B3E222331432DBC8AF6FEA4F9ABBE8A09D4C88410007CABBF617BF9351DC4B430CC719236615962A4490A9506DB43C035B122AB6147B07C772AA0156FA5419293D5964145A892618661DFBE4ECACAC26F6E9CF7677C10D86502D3D55B4F3A3FE24D0DC6B66DAF99E75FAD3107AF4742F99F9B46F881CF7C2411F9FC281CEC6E27DFAB30E9E7ABA0B6E74200DC7F4E71D9890A3C5A734712F5FD096152CD28221DA4920AD93A5B0C5019FD2164AFA40404F8CD2EE2EB6B411EB2F6D2481347E818F517CAAC57B7691ACDDB83E25A1D3CB46849EDFFFF10B0B9DBF00E3557BBB4FF57B235AFC8E8195B24A9A4AA0F7D6D49DAB69AFDAAB3E5935AB51A8CCABB77BD5E24C845F56F49B8A397533F131BF6BA75D8BDFBBF32B615AFCBA665FC76F12FEF7F6898F91A9C539765571EBD57665A17FC8DA99156A0EE6C3DAB5F8140EAAA39DED5AF4AFF6977D5B3CDF382BBF835CB497DF252FF6D43B7F9FD9EF00FB5D53EFB5EBE957521B8D098D898DD3EABFFAEF2FE06F42E3D4A909AD7F4FFF3D2D7FDD7F9F3A39B1156F9B26FCB9F5A8FFEABFFAAFFE6BFFFDFE4CEBD346F1AEEB4F38EABF9E4A3EBCA4FCBF6F14FF77E7FF4AC377C3EAFF1F1DFE786D6F2A9E220FD74F91FAAFFEFBBBFAFB5B9B0FD7F6D67FF55FFD57FFFDA9FFFE90CC5967D7BF8DBFBF463FFE65ACA4FE9A10AB2D7DF7ACFEFB44E9AFEBAFF6D1BBF757635BFFD57F7FAEBFFFCBD3EA7FBAF70FE9F3C74AFBFDF5FF3F5C9346F9AEBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEDEADEB3F010AD58C7C]]>
              </MeshData>
            </MeshImport>
            <MeshExpression Name="Mesh_Planet_Expression" VertexColors="255">
              <Expression>
<![CDATA[//

// --- noise and height ---

float freq = 0.5 + (abs(sin(Seed_Planet)) * 1.0);
float noise = noise3(V.X * freq + Seed_Planet, V.Y * freq + Seed_Planet, V.Z * freq + Seed_Planet) * 3.3333;

float height = (noise + 1.0) * 0.5; // normalize 0?1
height = clamp(height, 0.0, 1.0);


// --- elevate surface ---

float elevation = mix(0.0, 0.2, height);

// normalize vertex direction
float len = sqrt(V.X*V.X + V.Y*V.Y + V.Z*V.Z);
vec3 normal = vector3(V.X/len, V.Y/len, V.Z/len);

// push outward along normal
V.X = V.X + normal.X * elevation;
V.Y = V.Y + normal.Y * elevation;
V.Z = V.Z + normal.Z * elevation;


// --- color zones ---

vec3 deepOcean = vector3(Decorium_OceanColorR * 0.8, Decorium_OceanColorG * 0.8, Decorium_OceanColorB * 0.8);
vec3 shallowOcean = vector3(Decorium_OceanColorR, Decorium_OceanColorG, Decorium_OceanColorB);
vec3 landLow = vector3(Decorium_GroundColorR, Decorium_GroundColorG, Decorium_GroundColorB);
vec3 landHigh = vector3(
    min(1.0, Decorium_GroundColorR * 1.2),
    min(1.0, Decorium_GroundColorG * 1.2),
    min(1.0, Decorium_GroundColorB * 1.2));

vec3 color;
if (height < 0.4) color = mix3(deepOcean, shallowOcean, height / 0.4);
else if (height < 0.6) color = mix3(shallowOcean, landLow, (height - 0.4) / 0.2);
else color = mix3(landLow, landHigh, (height - 0.6) / 0.4);

C.R = color.r;
C.G = color.g;
C.B = color.b;
C.A = 1.0;

//]]>
              </Expression>
            </MeshExpression>
          </Producers>
        </Mesh>
        <Mesh Name="Mesh_Planet_Ocean">
          <Producers>
            <MeshImport HasVertexColors="1">
              <MeshData>
<![CDATA[789CEDDC7F8C95E59507F00B8E5A51B72534C632646CABC03F6B2233A38444ACB6580A163042534B2A3AEA5F4EC3509B4B635A1BD26D9A3AA9714CF12F0B161BEBA6A52950A1545AAD90582C0C266E360164ABC4C1C64858573B6A4560EFF7FDBCAFF7EE26DBB4BB75FBEB7D275EAECF7DDEF39CF33DDF73DEE739CF73EFEBEF6D346E3BBDD1BAD63C9EFFDE53FCDBB832FF75E5DF35E317BD79607D7363F7E8BE075AAFFBF67D6BC21DCD37562EEAFA975B1A4373267C7A65634D6E6EACF9D684AF0FBFE7DE3913FEF9DEC69A079A3F68F577D7A543D74C3EEDB1F4DE72BC7F70F98A1DBF9BFCC55FACFCDAC919439BCE3AF8C3DE15DB27DDF3BDC6D0A2AE7FFCF6F12913364DDDFCB17FB87FDD235B6E3FFFEE874F3DAE7DF98A7967EC59FBC6CA8CF0D349AB3ED3BB62EDE4D59FD8B162D359D3AF9B3E44C3558317CE18DD6FC4EE191FBA78DAF20B67F4CE5C35383CF5F0653B6EFD696B8CD10D241BE5876BF75F31FB6863CDD6CB0F1FBD79F8DB97FCDB0B4639F0C90BCFBE6BF8C51BBED3D558A3274DBE7AC13FFDF4B33F5FD74C4F23BA8B3E3481C9E93734D67CF0387B83CE93277DBA70F2C9ABFA879E9F74E3271B6BEE9ADB7CFFE96BBF7DC987A7DD3CBCF5F29E298D35D72C8A76DAE9D03BF39EB5870E9C39A3B166D2B37DB36E1A5E36F685817B179FF3EAEDD737AEBCFB376F0DDE3577F8E568FCD086E8FA810773CF8C1F47FA05E31969EBB18CBAE475AFC16BF058749D3F6EDCF18B223BEFD7356948B7E7BA628111FB663DD05C36B6F5F2C69AC347C77AAE5FBF713477DEF234DD58F483EEDE59EB9B3D53D2CBBDC1E1D4086EF834AF03C3FAECB875786ACF53D39677CFF8F5339B976EEF7EEF4EB63C3CB0B4B7FB3084E97972C991C55D47594D5AB8F79E7BF18D7F5961949FB57871D74F8E2C8EDFF0EAAB177CF9E39FFDF9DC8B175C3167F757A6DF76ED89BDBC199457EF6491BB68E25EA34015AB6F3FFFF6EB4F3D4EC258CFC3031B475F9AB9AB7FD5B65FCE9E7BF1B627C8FFD83FDC7A73789B9ECDF7BF35B87A278B588A9F18C85374C03ADAE2007CE84337F8F329FF924C668958F1DE58246CEFFEF7B98B3742E0F894934BA66E8673C5E1305F3B9DE9CF965DFDF72C386F7FA7BD1F6E45D4D881207EE88016EFC39E5B9E7EE1EA49F34E3B7CDB924BFADF3C889FFA93401AC4C8A715944AF9859C44D3E8065A75E2A98FFE2493F9CADCCD4BE78F959A14ED89F6E611FA2CBCE2C9D93B9FA11599C6253359E2858768052BDED432B1EFCEE9F7FDC82874264D8BF746A183F6CE71EF59F0D2CCCBF7181D0E34648B3E241B970E46A7E7BC33FA071FDA0013684C9AF776CFB447E9D6B8325CD6B3E276ECBAF0ECD5CDB02B5825B32CDC0513A3D3365971DEFD464C2E9DB721D174CF5A98F8543BDCE850E25F78AA533299328C7BC9211FCFF5973DC435ACB00556308106092C85894CC8D7F29271C9211362B08203C964424F8CF08B4F49638B285BD69BDC4007C840834530218D647A1A174A46679DB1C4AC9E241BA5CADEE92F33C83F6CF1A9F7FA68B966F289AB4647F2BA7704E6C9C67B4792C90F8ED096D716B6FA3C3522F75E33F9EDAB7E3522CFCB3010600BF93C4513A8B2421E96DB49A615BFF385FE18C25F3C2EAF1A056FE10C73123C23A0CD223D2106AB8A4591DF29594FF9D3A778523D3DE35F2D466405FDA10D0D1A92090123E2309D69EBA94A67DAF2053D59E1390B6D5E888FF68C785AB59F5C03EFF4C9A7FC6826401A399EADFC4B7FCFE84E1BCD1CDC6B5E11895B8F79827876C08A643D59C4779EBC62043720635C7E377A5BE78A7566869ED4F8C63AACA30F5BCC3ACC1FF4248D9E6C81362F57B19F5947253368938C9FE2CB330E1358CA46F2E9094951C952F7F208DF19852DECC5134F6A0C310A8BDC4502B6D0DC1CE32B2D06E7495ACCA05A913F76C00CD6EC140EE6C39EF846D1C7A766686623554EC8DCCFFC8126BC2F4EE1B0BA79E093877E5BCDCFA33F09DAF53113306BC56A7357BA996561ACD93B8618451F9FD293047DC831E78189D957A2A5798437711833DD4B13D689411270A6EDA355835607B08203F99D989B93F378DB9B8D124FED6284269D735D1AF2175BD805872F4D38F68D5FACC47908875B4B5E278D45D623E6666665A4910C07F89B955953F0A378C9FBD5CDD81906C67790A1032FF02669ACA043E7CCD09AC5BDF0B426A2336D219F78796BB01DADEB9AD63EB0856AE27BE1AE0DC52ACF5A2F4FC6CD4BADBCB02231FD9D1F5FDA5AF74C78ACAF782599CCE49F8707928197AFE09112C935C50AB2F0AC151F04E8430234D8C28ACC0F325F8D6E10B62E23D92846C41C7AD2906EA22F91F5E20D34E15F2B411EA1094BD92842E98981FAE7E9DBCAA88517206C74B6D321B388238B49A06D19AD051F325ADE3FD7F5D68374834932D196E364F2172654F7BE78C38DC779C7BA1BFE5A784ABB9529565B8FC3107AAFB46639F3C79289E695085B0BE77990D969F89079CF9CDD108355EC5FBE4205005779CAA7DAD3D2187217BF74A22D8EF4A4037DAA4889752C850FCD21E0D32095E763C6A5F9C070ACC67F8C853C3FC2FFB5731349BC402B3662144BF3E49B3FCEB3F0DFDEFDBE9D990D0619FD8DA24E622C11ADFD9EB58944D24886B95A849ED7AF2F5676C55846E171E3C201AFDA789E1A094BD4106EBD194B458A118D3E309C5C140F5558C1501F9FDE5C6005796319B7626398495BB6B31A2B2AD6E15B22EB9BEB939DDCEBAECCE56EBB562C88411C832199A2491CBD51E457DEE1353E22BF8C8B22467819E634C1700C09AB4E9D626385467AC2561CE94F9A582B997865D655F0A439EFB83733C81DBF5B5EB0A69D2B5637DDCB1615B2B77BB252C13AB664AE57C5E653230B5AEF4507CFF269561A5D4779C1B8BC4C1FBAB9971CC87C7DF88D959F7BC7F6F85A6C8A32A31C1C815EFA1BCDECA08A3FB1985756F045E6109F3BC976882D6CAD60B3920DABF139EBB57B16F02F7BD982AB22F485ABC7779C76587F7C9361ABCC106DC9C199B2A67776A25F84EA091F12A074F7C3990DE29B68721716B9972FC8A7A19E6250449C1AC101BA0793E493DE157483E11706566E3EE7553AF08E5880C62F5BABD96D4FC00D37F0C4584679E1A1CC3FE7DD9FB9811631C8B3F806017A408FCF0686BFDFBD675F95DFE2FD48C9CA3D31259AC4203420831B58211B90295BBA17AB7999C77999BFF88E7513FBBE7A302BF4581D4BB2EACFB85A6243E34A6C873F04C40826934C1ADC8C58C56322D788BC0C6DB640F2BE1F458BEF7E34B510B8410C9F2B3FC683BBA75C37B8FF0A5AD1871FDBD84E1F8209DCE2EFF9E3A9D23C391B5B30075731E1B573D3572CF3085FA432B0E00A9AB89764F9907C9AB302131A451519676075A4C87CB0621D2BE88FDB55E4265AF3FE8EA67631425B56D39F4764803DADECD1784C0EC9BBBDC5FFEF29E33456ED1DA11B7EE2EA844D592DB2822F784ACEC13198E88FD5C6DA5BB4FB543BDC449338C2C0698FA6B6433EACE2AD2DC74BF9059EACA8726022030F31103FB3FAB86B2E1CF8AB9DD9EE685A198829564320D59043BFA5157D6E5BF2F49E370F622C4E6257954BC3A363DFF8C8BD5F3B89C3A9C7DDFD1B8C25272BB71BCBA7863E6C49C67DF2A4F81541AC88FDA9F8C50A31424F1AC6E6A74620A885BFE06B747AD2414F7D8C85F3F84F32D6E15BD656AB3E334F5628FC483696EAA9CF431B120DD0C0C6CCD7B75E8E8790973F459C71F9421CF9F4CCE959976329C626032EEDF51EF3F7FE1716E53D0D8DA88F713D11A1A4375F977E2FAC10DDA2559C2EDE988A476766C63A7C9313F6768C4B131C1017188BBDFA8B149F7E7E5BB889CF46F9C08389D46A751EDD44BD7897D94637649D6B1438934FCEB627D49CCFDB9F6A677882A5BCC39B6456FC0926F0C1739CC4CF68FBDAB967ACCD2CC3BA07F37109AFAE1B9CF9C4EC92D52460E9B2562E4BED34ECE54D08F3290DB19A9EECADE61BF10E266048F0DDB182D59D1E87BF58133B6CD103CF93AD524B0CCF3BA329BE495D31DA1A0526B9B7BFE4241D322F3DB2987C718A09AC803064E68F6516315854079B47AC7F83A418A7273F7A22E01B3D6948DB4F172BE0AC88BE3521ABB3455D7C1146DD7E3E8F90BFF5D889ABFA861E39F6F655970E65CDF78107B32A8A1FE28D203B6777F4DBF644DEED7CE682F1ACF2B31F78B0B57AC81A62D958EA36878FA6E691F703C346B96FD325FD674ECF5369ACC75846D13FAC7BBB277C9B7BB19EC64AB63D6F7F303DB1D7B8E1CAB4473FBF2D58E539F49DAE6A0D9DD79DCF841573760707D2B4DCF9FC973FFEDD8F9EB73F91F864310BF85C914DB71CCF7C848DC32FA79A74F8686AB3799A66BD33FC72AA166923E1F4A379C6F14B389915C7AF9FC9BEF0E8FE5583F1DDDC8B339F796966661D4FCE2687042BCC9B86978EEDDB77E3F0B2B1CCAF263DFBE601F5D9E0D5332595961F74FB34F5CAAACFA5435B8FA59EB0E4F554F35A6BA79FD09F8F76FC2E719699CCF6EEACB086A76685DB3D2391F5768F765AF14BDB5303C3C980B79F9FECB67B4A72E258CF078BB50B647816FEE1FAD881C4E1C6D1487C656E32556B7E7C7FEA16C6650B2B92D752BB888E6C5FDFFCD4D89E7D6C595758978A55D6894B5BEF21A35D9F54D57B9E4A5ECBCC3F3827BE6EBB36D5B485BB488312B4F54C06587005AC1257A9E6CD1FCF7980BC4FBCA5AE12DDF8971F33475FD78C778F4FC91CE8B57321C32FA9422E9CDCDF62EAF7BB79C4B8EB9BD1FC5745CD3873E620BAB1F5AA45C55AFBA9C79375A76E4EB68C575EB8FACD0391C4CFFB0A49470E640727EC5ABC315C5DB54D7F38C33C382D1B4B563A7CD4BDBC96BADC87A7A52E973A605E6F6A69326B5656A667CE2033EC9DBAF9B4C3E105AF25FB9DB88AB66C4C0573D359C9386B271BCB28B425998DE49353219076BB281B4753EF5CBD33B3A4B4AC6BE6FD5B8369CF5E655E6172626F7217DBF3FEBE1FB9F757238F1C3BAD35FB8D061892DA41CF53557B5AF89ADF71030EAC8686BBF6B6F2D3C4C7DC1B06771F4EE5B13503DC543C835ACCCE5C346CF4E9358B7EF61F59118721A21873F0197F484895A1EBE8B4479399C2A48DA361D22D4F27231C3A9095CF606BE4545792919B47E889CFB807EDD420B64FC2409E3AE7D53C09EFFE4D9E8D79BE64ED96FEB46A475655BD82FCC25D99B3C07CA0CC33891759454E88F4E35364863C5FE66D30229E24A73F3F091FF05F7E802DBEB19A759959CE1F232DB2D64E960D6273E6CF191DF2C9FCF3EE370A8FCB99E29737F10137448A3E3497C70E15D56E3C61351E6220968A629A8B65BAC95134CC3338159578567EC016ECC207FACB48720E8FCC3E9AD90A8FF39D117930D59FD47C22532EB2434537FCBCB1C33BF209E4C520FC2B0C2F18CF6C223D33DF78E16A58E1128BDCCB5FF3C7B3E2C11F9E85A47C2293E03C7B598AF39886639993ECEA87BF11F99126D8C52E1655D11754D90E87B39FCD0E4BB5BF1A666A2FB374619DA829B362113B18C2CB3CAEA7BB78247DA62D974F30077A3C22B2CAA755C1903C173F74F1A1E2D4094DDC5B54247F224BC0847F69C5CB46372E04640F79400608975299496CE2152F908639A20F1B454D9EB8CF75D19C1F79472E320AEBF8D10C275928ABAA784D1EC82A60577FE5DF589A99E499D3C50E3F66455DE9C65334C9933EAC0B97CC94606BDCE87DFBF934274DD4CB00321BFE9B8989BBCC3E5BCC2A9E233CAB3D6BAA9E329FB082FE709325E425B902B6728E7159C7A7620A326C87439B75EB9A3C5E3D738B5946C1314FDED4EFE69D417FCC1105E24BD6250D0F3139EBAEACA7D29317B2DB56711873B4C0413BACCA676BD19E8A7C6A26E1D5DEE2155BCC45C9C10DB3771AF25795ABE3B5B667EF6856FE0DCED5DE785EE90F61F1A55EE05E7C28912F7248E793C82A806EF1C17B778A145CE5C7CCB5B2360C1AE6A5EE250DA3F842DCE12776E1155FF3B2F97F2A86C924455629F2864F21695E6A658109EC155310839ECC59CE210BAFE1B9F93CDDB0176EB86A9E0C31E89189337C4187D2B3854FD968758339E45BFBF854768580D834DF86152FD0500C8A7A390A67B045EEF2A928C07FAB24DE91434AAF15FDF98E9CF26955E4373D79C12ACF7A813E709007A265726CB2075B3C23E08C875821AEABB1320AB64306C2B0C56ABEC3ED54EE52A3C8BD34CFA9A057E61AD158BC2F27E0004685797922475B2B1A9C8430EB588A692C4ABF70269A785FE5E7B4545199B8AE9E0EC9D3FCAE3DCFBED4B2321A1CC4858C213AE866C44E3C8D0255DA8A3B71443269E4E7045E95E76162458CC3F84C02CDC56F32E9844DF0C40A7580EA699E7B73E6ACF97E7AC213E7C9942DADD621CF0B584726EE61A33EFA1B4B7F23926C45DFAEEE5D78B69EF461A9D5037BE18903229A4F79530D813E58ED531258448E0A007C6085F3E211F38D0E610C9407D455E88FABF255C5F6D41B70408EADB259224E1FBE702F8F2427A7BF5A45EEA2338FD0BCFCB4E003F918AE3250F2BCC86C728EFC0319F953D65227E123DE51B1E11DF8AB20B1572CA8C6C016AAD57324599A8D9515D1DFA74637AEAA827A0EB6902667CA09F203FDB5CB9C721D9DE94F0E244923811F652DB520199504285595AEF83DF535DA5695741C80ADBC21DE5921EAC54864E5899028564D920DF04A058947E88045D88BC9694DED287AAA73AA547BAF5E9DB5EE79FBD569AB0A6D7050095403C449D18499338A53FBF206CEC86C3CCBA76AC8AAC7EAD55ED5ABD5A553CFDDB31632BCAC66AB7EAB725B555F53773D559C2BB457A20A9A333F8D2B53811D3CA68EAD829D9AE992D7CB5A68D19E5382AFCC5561669D598C6ABCCABC8870CE951760A282CD22556EF56D7B0AD53E42720CDD788D0721D3AE9FDFD17CA838979ACADBEA4FF054896451F5559D56FB4D9C761F56BF8549562F4B7B8DC276FDD566D5907F567CFB445D9DBD338AD3647613B4872D394D1A9EAB152723FDBAACCF97BB4845B559E559EDBA38517D948F54D4610801E72673463AEBBB3007F7CA736DBE7D527C03C35DD8087FF8C0D32E03DB3B2BF9E41B0B027C814BD50E57624E353BA7AF72EE287A6A577DCE39F3EE199D11F1BE9DC10373C482BABA1ABB0A7FCE64E4BC68BB6E2F763024D960CEEECC7A3E781CEB30D0BD6AF8F04CC6B9708671E180993829FA3021ABE69CB08D7FA3594E11A79DD7D4FC8D655C7C1017F4F71D27BEA339F9BCC353D0902B60D2B96791F3105B8EC30732ACC604D84215C7B00B03931553DB0F3E62C728C6C50D27CAF91D07680EB7EC336E5EDA577C33897C9259AA674EF87CF7A3E2427B4E2E4DEC2301E6C938D9EF284E53163C242DA3AF6EB6B9D73F086D271D7959BBC8957F785656917932DFCA93A2C86F051B710F923084121EFAD45DFA63F2235B72F2D17B9858F5E13FCC49E31D7EA703F6969E5A9ED9115EF1F80D3F0F4EBC404F48CA0F7AB2AE3A851AACE404B94266C81374FCA26AFDD78EF7DBAECDAE91B1F4C1F3B267C1319CD74E2656E333DB610201F2453AFFB29DD5D9055FF23A099903E73475A2A3FA343EDAF0E3AC0FB02E7B7BA95A445BAC68C7C5FA66FB756058A45768048783C5F97168C88DB253FFD082C9A74A6662A9FE65BE2DCE8CE3129918252EF8825F640F91E2D39CC53D7C191FF18E48C155BCC50D9A60888C61C4F239F258CEA843034FECE6C053A4600BDFF1A3B813416227F5E5B103D82503E033267F737D9ED4BC4007BEE0F77CF3227B4619C1EE899E7CB7AEF8EE1DF4589D533EF3C749E6719CC9BC2DBB51911986D8D3EF1FAC3C95E8A0D519ADD9D2F0CBA9C88CEE870FACBCEA69C50555DC13717CF1E6C1F899A5767378B09D1972E63C9CD11E8C9A47200C253EA261E4DF7A332471CFBDBC2F1E31DF4E0D1D30013E9716F84029FB46FDB3EC0779FF40D147269415791003B1F4B2D66B2501AFA02D5AFB6615E314386766BCB11BDBA10749FDB11167EC0E89538C3222FE1B1737789367B14EAEA6B3BD3939C1B8F62531443B7B59018D2A1765749A609A48C7377B46FCCBD73EC573D98077780AAFEC1CC19F8FF89767C5829D2F3CE12FB18603FAE3214EC24146128F556C268FC95A3EC573B6603B06621DBEC948D5F75983396CC50B993880757688701EFFE9667FA7FA5E57180B49BBAE108649F9EC2BC7CDAE65BB2299EF2667262FAEC5785695773F8CD5F0879B98829B5C61475B64B90BE6EE25D39E94FE7C67E7080FE983A5B4B23FC822FE35A2DA3B4DF01003ED19D9E3C37392ED10C9999DFD616BAF10567D451442ECC662971663C52609B01529FC220FF0AC28C0FC8AF3F12CCE93D6C6AAFA3E06EBF8C88E8C8A3476E1212ED94BC27FF18E69A25E9E613B1C6048BE1DB42A57B0295982B63C2E5AAB5C115BC4B218E4594C90E54490D8513FA72DEFB0F7D28E8C57712F98F816DA9E7DD9436329ABF98BA7F854DC890E357F72AAEFB1E555DC9163371C3E76CDA0648F8FAFF911F3C591BD952A2EB29305077BFAF20956C381ED767030D37900231A9D4F696BD79EEFEC3F8A02915EE99F3A683BA25797BBE4348483DD25D12AA6C4177C48B30B430EDFC90F70B00B8651FC284FB2D14E1F7EE2AA9D3B23E2097C30044AF6656042A65D39FD71CC9E609B79D5D9001AD2D67E2524B1141FEC8B89414CC66AF162EF00563E15D7625CE6E417B6C34134F105BFD81B6AE3F6D660B58F199DC514CDE52E2DF20CD6E1B33312031D39443EE15FBED6DFE8A4E1036DE516594514C85AECC225A735EC796175756A28B8D927E5538CB56F4526FFD28A4758EA2EFDF9C55EB0481123763CF91407A00A4FBC92A5E504D9006F7158148B35928DC222F122AE59EA6C499593A367992737546747577F423680B6F327109613F8C5284E16195DFCD25614E3985C214B54927DBF33F2C59DE8F044CBB9CD79673847A752ADE696EF427CA9ACBC3DB22571AAAEAB3239F98B1FB9F74B13AA6A6A9ECFF1EE4B3355265532B578EF5C1C2FC80950CD7F795247A6CAA70A98FA953A58E60CA9FFA75D952CF395AC7452095403F45E5D4B452BFECD9334B56EF549FAABFBA9F8F9A63499EAD2FAC7F7BD33B5A8A3E6AEACC4534DC501594BBE6AD75ABF3E4CBE2782674AE7F919594E34B1119230A43F6D55E7329F3E3E451D9B8FEC63F2BEACC583D55E49FC05EDCE1AB81D52F94D645527E84EB466E74E3F3AC7187F9C7A5C4D5B7DD85941A737557DCF7935D1A0A7FAB016EF5565F88877AAFA7FCEB16217E6C48AC695E4AB2AAB567FAD3813AA9A6D37573B29A90524F3A76E6F67845F4E8DB4C7BAF3F97CF7CAA76C61A32A3ADBFDFA4BBBBD7F28FBA9AD4C566882C9DAAB3EC10A0ECE97AAE73B67A8BADE3E473A7DC8BD79ED1B0A27B2FF55FC0A4D611746D199FEAC539F27133FF1BF627EDE57F3E5BC62088FF3B5BA589BB77BCA184FD568FB242C3AB137A8883848E2BC11315FFCC2041A468CF6A9C687BD7C2A57F06C9E5BDBBBDD4BABCA2F6C8A9534A1397D9CCC8509CD61E81EA8CA1572918C615CD6613EBFB4F1EF2BFD4567B146730890090792CBF82D72054CE404F9041A788B27DAC5ACF8958BFA86A28B96BE5297B4E8AF9D3E301411A3C58E2EC4A0C1FA4BDF9170F22AFEA5279D9D93A8CE3D449208C2BAEA6C6DDE8B533C4C163EBD94000776654FF79A45A232CF9ACC22C20A68D0A7CCBD854FCBB3C4E33941006D67A370B5E270EE2AF52FEEA52D3D45370EF03E1B0F8E1885FF3396B816D1F20FACAA9EF44986F6297BF3D4C9DC206DFC2E87C80F64FAAE493BDBBCB1B260ED103CF150DCE19258E041DF4BE0C754C517756178C5CCE0F0C3B5339FD85D46AEF31F6C37629E46D9D38F8FB4C31393A19A67FDD25E3EC2C3CC4FBA6788357117B973DE7976FBDE40B4A5216DE78F65D714026C376E183F5A320407E8C0BFFA434FC648B561ED6451CC5E3A887AED34A42D3D7939AC4BDD230CCFACFDAEB946641D0CA1C716BE6867DAE943B4E5EB4E2F63355F1F39903D29ED34CFBC2A2BBBF010AF488003CEB08B2DACE0BB8C9139523C08677AD210E7F5E4719CDC33D21E4B746BC75B3868AFE23DFEDA53D4FE798D159DBC65A31811BFB47257C9CF9DC1957C9857B67BCE472B3C6F3F771A4346641DFEA45EB4E92CFE65EF03CDEBC62E69CDBD978EE55476F243569ABDB3B0851C3EA2F9A1626F9917F477EF86626FBC38C153FA914FE99C0C9F7972A48A4D51235E4886063ED393EF68AB4204ABCED1AB939B79155318887B50A25BF1CB38B3E295E52B3A738268A5ADD821C109664C4E9D4B1EAB76AAB49306AB769FBB4A3D2BB698A18433F38AF353DA3127F9F1C51BAAEFC6F16090A195EC9199E7F054D187C950C27368EBE353B8E99FF9EA85332003B1AC3E721A2D88656D9C9324F11A04B467A638D683FF78186D169599276B9985938DC253CE69D199FE30810F9CCB510ACDE97CB8F8554238C39C3E34218D15F49779F427991732F6735DF88CED5AE8A61D0EA4C14AE5CBB8E4E7E4706F1905382312E58ACE288686B1B09A67F9146EC93E99E7E7DECACBF12FCD79C15839D7DD3B2B2BD89C7E4C2C4089842075BCCC57EEE21D9E4A6ECC3738125F62ADECF9BDAC4AE9EC2EA3DC5CD8680F4356C15B9CAC10086307863F35D63F2BE7F172961567F2A9D1E9C652D62576125961B26825592C408C5FE0D6FE34F5D578556E71AF1827AD3899348457B8C78318E82EB8C1101A3CC23BA9753C3F091FE8001F5A41497FF676A2810930A12DCCA10DD5CA8FCBDEF1230FE23CAC72A2EFED1EDE4CE5624F1977385FC582EF4CB77FF903AA100E26F97E4A46A70964441F7CCE7E36557D184286043DE1C93ADEE46523567E0C3F8D95E754BEF59011F93D27D6B20E8D4550E511D8EA9919784EF5C70B7463A388CEF9A49C870CA3A05DFEB24E11A13CEB9B1B3EEDF40B9DE98FC3F484868886A4B83616CD8D283A7801077C9307567C47327E42922DA556853E3CA83F3FFA4D23A3D3845D2C82127D6048ABE0B2E92C4862E691A2520579D6F996851121196D7356399FD2B6B23A7BDC98034F9AC86FB8C1D2D2EAA227BFE3407A8C5FE45EFA1BDDB8BCA94F6963D1939CCC5DF24C0CDF52F5EA99C26AD6B15A14E04FF27C6FC94C77F1084CC426CCE1860390C1317C630B5F40C9A7EEE5BB765C54BB4DC68D5DD3CB086AE3936F61A4276DDF579C38C319AFF17766266D6D2716DF4867A9D1736E30DF7A880E74CE4C3B67A1F369BEA751F914C215AA7E9923D81A8564A3D027F3A4AC11A2151DF4D4876498900F6796B21AB6FA631D6DF908DA998FE58C7734C7499F6695951A6034C1377E2F59B72F15E09245057F8CCB4638FB8E22B4E9C96AD23019CE6CECC401AFE04C2B51C06B3E352EEED10D0238C65236F2CEB6164A970DC1ADCDF6E943DAB5B01AF26C27B3A83E97D81A2B739BACA0F3294BD9483E2BA0445B32F3F4CAEC2EF6B28B4561F58E5BF9427B9E2C9B9792C05272A0941848B6C92850CD7334B3E222331432DBC8AF6FEA4F9ABBE8A09D4C88410007CABBF617BF9351DC4B430CC719236615962A4490A9506DB43C035B122AB6147B07C772AA0156FA5419293D5964145A892618661DFBE4ECACAC26F6E9CF7677C10D86502D3D55B4F3A3FE24D0DC6B66DAF99E75FAD3107AF4742F99F9B46F881CF7C2411F9FC281CEC6E27DFAB30E9E7ABA0B6E74200DC7F4E71D9890A3C5A734712F5FD096152CD28221DA4920AD93A5B0C5019FD2164AFA40404F8CD2EE2EB6B411EB2F6D2481347E818F517CAAC57B7691ACDDB83E25A1D3CB46849EDFFFF10B0B9DBF00E3557BBB4FF57B235AFC8E8195B24A9A4AA0F7D6D49DAB69AFDAAB3E5935AB51A8CCABB77BD5E24C845F56F49B8A397533F131BF6BA75D8BDFBBF32B615AFCBA665FC76F12FEF7F6898F91A9C539765571EBD57665A17FC8DA99156A0EE6C3DAB5F8140EAAA39DED5AF4AFF6977D5B3CDF382BBF835CB497DF252FF6D43B7F9FD9EF00FB5D53EFB5EBE957521B8D098D898DD3EABFFAEF2FE06F42E3D4A909AD7F4FFF3D2D7FDD7F9F3A39B1156F9B26FCB9F5A8FFEABFFAAFFE6BFFFDFE4CEBD346F1AEEB4F38EABF9E4A3EBCA4FCBF6F14FF77E7FF4AC377C3EAFF1F1DFE786D6F2A9E220FD74F91FAAFFEFBBBFAFB5B9B0FD7F6D67FF55FFD57FFFDA9FFFE90CC5967D7BF8DBFBF463FFE65ACA4FE9A10AB2D7DF7ACFEFB44E9AFEBAFF6D1BBF757635BFFD57F7FAEBFFFCBD3EA7FBAF70FE9F3C74AFBFDF5FF3F5C9346F9AEBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEEAABBEDEADEB3F010AD58C7C]]>
              </MeshData>
            </MeshImport>
          </Producers>
        </Mesh>
        <Variable Name="Seed_Planet"/>
      </Definitions>
      <OnUpdate>
        <ZExpression Expression="//move.Rotate.Y += App.DeltaTime * 0.06;"/>
        <KeyPress Comment="Spacebar" CharCode="32">
          <OnPressed>
            <ZExpression>
              <Expression>
<![CDATA[//
Decorium_GroundColorR = rnd();
Decorium_GroundColorG = rnd();
Decorium_GroundColorB = rnd();
//
Decorium_OceanColorR = rnd();
Decorium_OceanColorG = rnd();
Decorium_OceanColorB = rnd();
//

Material_water.Color.R = Decorium_OceanColorR;
Material_water.Color.G = Decorium_OceanColorG;
Material_water.Color.B = Decorium_OceanColorB;

Seed_Planet = rnd() * getSystemTime();
@RefreshContent(Component: Mesh_Planet_Expression);]]>
              </Expression>
            </ZExpression>
          </OnPressed>
        </KeyPress>
      </OnUpdate>
      <OnRender>
        <RenderTransformGroup Name="move" Scale="2 2 2" Rotate="0 937.4086 0">
          <Children>
            <UseMaterial Material="Material_planet"/>
            <RenderMesh Mesh="Mesh_Planet"/>
            <RenderTransformGroup Scale="1.1 1.1 1.1">
              <Children>
                <UseMaterial Material="Material_water"/>
                <RenderMesh Mesh="Mesh1"/>
              </Children>
            </RenderTransformGroup>
          </Children>
        </RenderTransformGroup>
      </OnRender>
    </Model>
    <Material Name="Material_planet"/>
    <Material Name="Material_water" Shading="1" Color="0.8766 0.8611 0.1425 1" Light="0" SpecularColor="0 0 0 1" EmissionColor="1 1 1 1" Blend="2"/>
    <Mesh Name="Mesh1">
      <Producers>
        <MeshSphere ZSamples="20" RadialSamples="20"/>
      </Producers>
    </Mesh>
    <Variable Name="PhotoMode" Type="4"/>
  </Content>
</ZApplication>
User avatar
Kjell
Posts: 1964
Joined: Sat Feb 23, 2008 11:15 pm

Re: New planet mesh generator

Post by Kjell »

Hi Ats,
Ats wrote: Wed Nov 05, 2025 12:57 pmHow would you update the planet mesh when the model is a clone and the event that triggers the refresh is outside the model (general OnUpdate)?
There's a bunch of ways to do this. One way is to store the spawned planet clones in an array, so you can address & refresh each planet's mesh directly. Attached is an example demonstrating this approach. Use the left & right arrow keys to select a planet, and press spacebar to refresh the selected planet.

K
Attachments
Planet.zgeproj
(5.37 KiB) Downloaded 19 times
User avatar
Ats
Posts: 907
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New planet mesh generator

Post by Ats »

mmm... That is exactly what I tried, except I was doing that to retrieve the model :

model planet = PlanetArray[PlanetSelect];
if (planet != null) @RefreshContent(Component: planet.PlanetMesh);

I'm going to review my code once again :?


Edit:

All right, it was not working because my mesh is in a ModelState (my model is handling all different kinds of astronomical bodies).
That's the error I get:

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="Planet" AmbientLightColor="0.251 0.251 0.251 1" CameraPosition="4.5 0 10" LightPosition="0.5 1 0.75" ViewportRatio="3" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[//

PlanetSelect = 0;

//

Cursor.Position.X = 0;
createModel(Cursor);

//

for(int i=0; i<4; i++)
{
  Planet.Position.X = i*3;
  PlanetArray[i] = createModel(Planet);
}]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <Content>
    <Model Name="Cursor" Position="0 2.5 0">
      <OnUpdate>
        <KeyPress Comment="Right" CharCode="39">
          <OnKeyDown>
            <ZExpression>
              <Expression>
<![CDATA[//

PlanetSelect++;

//

if(PlanetSelect > 3)
{
  PlanetSelect = 3;
}
else
{
  Cursor.Position.X = PlanetSelect*3;
}]]>
              </Expression>
            </ZExpression>
          </OnKeyDown>
        </KeyPress>
        <KeyPress Comment="Left" CharCode="37">
          <OnKeyDown>
            <ZExpression>
              <Expression>
<![CDATA[//

PlanetSelect--;

//

if(PlanetSelect < 0)
{
  PlanetSelect = 0;
}
else
{
  Cursor.Position.X = PlanetSelect*3;
}]]>
              </Expression>
            </ZExpression>
          </OnKeyDown>
        </KeyPress>
        <KeyPress Comment="Space" CharCode="32">
          <OnKeyDown>
            <ZExpression>
              <Expression>
<![CDATA[//

@RefreshContent(Component: PlanetArray[PlanetSelect].PlanetMesh);]]>
              </Expression>
            </ZExpression>
          </OnKeyDown>
        </KeyPress>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="CursorMaterial"/>
        <RenderMesh Mesh="CursorMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="CursorMesh">
      <Producers>
        <MeshImport HasVertexColors="1">
          <MeshData>
<![CDATA[789CE36660606065000187FD100C0207EC816C206EB05BA5F51F08181A4243FFFF0FB98A6033308030430348354C1CC406B318907531303032303130A3C0BFFF7FFF6704B37E6C60F80FC30F6630FC3FD100C1E86C100600369B47A9]]>
          </MeshData>
        </MeshImport>
      </Producers>
    </Mesh>
    <Material Name="CursorMaterial" Color="0.9725 0.6902 0 1" Light="0"/>
    <Model Name="Planet" Position="9 0 0" Scale="0.9162 0.9162 0.9162">
      <Definitions>
        <Material Name="PlanetMaterial">
          <Textures>
            <MaterialTexture Name="PlanetTexture" Texture="PlanetBitmap" TextureX="0.3466" TextureWrapMode="2" TexCoords="1"/>
          </Textures>
        </Material>
      </Definitions>
      <States>
        <ModelState Name="ModelState_Planet">
          <Definitions>
            <Mesh Name="PlanetMesh">
              <Producers>
                <ZExpression>
                  <Expression>
<![CDATA[//

float s = random(1, 0.25);

//

Planet.Scale = s;
PlanetTexture.TextureX = rnd();]]>
                  </Expression>
                </ZExpression>
                <MeshImport>
                  <MeshData>
<![CDATA[789C95534D4F135114BD9DA99F4551A02010176A141D6D625464FC5898F81BDEA2BBAE4CFF45DFBF9825BB59CC9F70C7145089C4869810625C08D682988E11B070BDE74E4B2B1F7E40DECC99F3EE3DF7DCFB5E5F105195F0675F76173DEB2C66B2640BADDC349E6473D371330883D0D629266B6AA6164514CB970D42ECE4A611D5C94036F628465CBA4C4DB918F9B60EADB889085BEFD64835905D68252544948BC8340635CA45EC2725E4B3AFBA1EB4230FB5D8875A250F65BF0F552A79682EBAD05F74A18C76B1C0E21B7B880E4264A2AFC88B22A89345ED20840F44CA6E8C4AA91BF4C23EBA2817D145522AB4100FB71263A0592E423F29211EAAB23CE8B08F2C71280AA899941085CEA01584D0259B7686AA64E12F08BB7DC81B7D58F8481D9B1A942886E3B809F7B60EDF8516E2931214CA45756F50A55C44BCCC507D4127F29055C943C1EF43EEA20B5FA80E0EBEE10A19A96FF4108470AF6E4DDAA7A9610AA8803CC41B032493319AEDE18D6F990065C8917FBC995D793BBA326DEE68BCC3DBECD01965B7184C8AB7159F56BCA3384BAEE0AC32BB9C51A68B1D557495D9EB61B6F8BB7CE5946FF21E139D57BCA9F8A2E275DE153CA4F833B3E261C1279469A9DA7138ADF2BFAE5CFDFFD7592D49E63BC6AC26E8369DEA99498A7F2A3E296B995BBCC4C8BE43D77FAB0BBC223D2F33B81B744DD53F48B72BCAC0CD1B1E93DE46851FA341C27C52FD1F3AABB38A139DD5B9F60C31AB84FB6995B39A354C0727D08BD7E4B9AADD8ED108755C751CA6BB8EEE5EA22E83E727AD34490FFE78977AF18CDCAB39C649F974970EDEA5DEB9BD92E7ACBAF2A5C2415773F29CD5389F1E5297B92737CB3F723E7BFBF3F9A6F882BAD9E0D782FBE9393D39763EC05599EF8C9EC8537A74E804E744B1AABB8F698A52F72C7D764E709327E90A61568334F0D759CD8B2ED4D6F83E5DD5EA7971D8B94BB8E14EFBB62F88AB79895CE729BAAC1179A99069DFDBB7E26141761B3295716557794858300E7DE4F7EC89FE80F09EDC3CCC24DB3E8BA3EE589D13FECAB89BE352CFD5AC8943E702DC909C3AE3F731425FD4AB4737F75D6D88AB86EEE6E5570D76946E090B0677FD17D74630FC]]>
                  </MeshData>
                </MeshImport>
                <MeshExpression AutoNormals="0" HasTexCoords="255">
                  <Expression>
<![CDATA[//

float s = rnd();
float r = 1+s*0.125;

V.X *= r;
V.Y *= r;
V.Z *= r;

TexCoord.X = 0;
TexCoord.Y = s;]]>
                  </Expression>
                </MeshExpression>
              </Producers>
            </Mesh>
          </Definitions>
        </ModelState>
      </States>
      <OnSpawn>
        <SetModelState State="ModelState_Planet"/>
      </OnSpawn>
      <OnRender>
        <UseMaterial Material="PlanetMaterial"/>
        <RenderMesh Mesh="PlanetMesh"/>
      </OnRender>
    </Model>
    <Bitmap Name="PlanetBitmap" Width="8" Height="2">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

Pixel.R = rnd();
Pixel.G = rnd();
Pixel.B = rnd();
Pixel.A = 1;]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Array Name="PlanetArray" Type="3" SizeDim1="4"/>
    <Variable Name="PlanetSelect" Type="1"/>
  </Content>
</ZApplication>
I put the mesh in the ModelState definitions instead of the Model definitions, because I wasn't expecting a moon ModelState to share a planet model in its general model definitions, for example.
User avatar
Kjell
Posts: 1964
Joined: Sat Feb 23, 2008 11:15 pm

Re: New planet mesh generator

Post by Kjell »

Hi Ats,
Ats wrote: Wed Nov 05, 2025 2:45 pmAll right, it was not working because my mesh is in a ModelState (my model is handling all different kinds of astronomical bodies).
Ah, then that approach won't work for your particular situation no. Are you sure you want to use a separate ModelState for planets and moons? Generally speaking a planet doesn't dynamically change into a moon or vice-versa. Why not use a BaseModel instead?

Anyway, if you absolutely want to use ModelStates for your particular situation, you could do something like this ( press 1 or 2 to refresh ).

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" CameraPosition="4 2.5 10" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[// Spawn two "Shape" clones

for(int i=0; i<2; i++)
{
  Shape.Position.X = i*5;
  ShapeArray[i] = createModel(Shape);
}]]>
      </Expression>
    </ZExpression>
  </OnLoaded>
  <OnUpdate>
    <KeyPress Comment="1" Keys="1">
      <OnKeyDown>
        <ZExpression>
          <Expression>
<![CDATA[//

@CallComponent(Component: ShapeArray[0].ShapeRefresh);]]>
          </Expression>
        </ZExpression>
      </OnKeyDown>
    </KeyPress>
    <KeyPress Comment="2" Keys="2">
      <OnKeyDown>
        <ZExpression>
          <Expression>
<![CDATA[//

@CallComponent(Component: ShapeArray[1].ShapeRefresh);]]>
          </Expression>
        </ZExpression>
      </OnKeyDown>
    </KeyPress>
  </OnUpdate>
  <Content>
    <Model Name="Shape">
      <Definitions>
        <ZExpression Name="ShapeRefresh">
          <Expression>
<![CDATA[// Refresh active mesh

@RefreshContent(Component: ShapeMesh.Mesh);]]>
          </Expression>
        </ZExpression>
      </Definitions>
      <States>
        <ModelState Name="ShapeOne">
          <Definitions>
            <Mesh Name="ShapeOneMesh">
              <Producers>
                <MeshImport>
                  <MeshData>
<![CDATA[789C5D8DD109C0200C444FA550BA8E0BB844F6EBB7B338901FC5EB1D7E146A48F2EE11F00270E2FF5A03EEF6E5885ABD3D491369EE7DFBEDC6B031479881848CA25A4C622865FD666B9EBA7CD49345F9C00BF01D1A39]]>
                  </MeshData>
                </MeshImport>
                <MeshExpression AutoNormals="0">
                  <Expression>
<![CDATA[//

V.X += random(0, 0.25);
V.Y += random(0, 0.25);]]>
                  </Expression>
                </MeshExpression>
              </Producers>
            </Mesh>
          </Definitions>
          <OnStart>
            <ZExpression>
              <Expression>
<![CDATA[//

ShapeMesh.Mesh = ShapeOneMesh;]]>
              </Expression>
            </ZExpression>
          </OnStart>
        </ModelState>
        <ModelState Name="ShapeTwo">
          <Definitions>
            <Mesh Name="ShapeTwoMesh">
              <Producers>
                <MeshImport>
                  <MeshData>
<![CDATA[789C5D8EDD0980300C84AF0A52C46D5CA04B7485EED4379F3B8B03A9A867AE45041372F9F20799008CF85B08C012BE3AC694947306481139CFEA4BDFDEBA8AC4A5884B69FBEDD6A1436F7ED319AB3E291DE0EB0C16AEEAC69D17BDFD75D82EF90046D9276F]]>
                  </MeshData>
                </MeshImport>
                <MeshExpression AutoNormals="0">
                  <Expression>
<![CDATA[//

V.X += random(0, 0.25);
V.Y += random(0, 0.25);]]>
                  </Expression>
                </MeshExpression>
              </Producers>
            </Mesh>
          </Definitions>
          <OnStart>
            <ZExpression>
              <Expression>
<![CDATA[//

ShapeMesh.Mesh = ShapeTwoMesh;]]>
              </Expression>
            </ZExpression>
          </OnStart>
        </ModelState>
      </States>
      <OnSpawn>
        <ZExpression>
          <Expression>
<![CDATA[// For demo purposes, set ModelState based on position

if(Shape.Position.X)
{
  @SetModelState(State: ShapeTwo);
}
else
{
  @SetModelState(State: ShapeOne);
}]]>
          </Expression>
        </ZExpression>
      </OnSpawn>
      <OnRender>
        <RenderMesh Name="ShapeMesh" Mesh="ShapeOneMesh"/>
      </OnRender>
    </Model>
    <Array Name="ShapeArray" Type="3" SizeDim1="2"/>
  </Content>
</ZApplication>
K
User avatar
Ats
Posts: 907
Joined: Fri Sep 28, 2012 10:05 am
Contact:

Re: New planet mesh generator

Post by Ats »

Thanks for the example. That’s an interesting way to assign the mesh per state.

In my case, I use different ModelState to display planets and moons, since they don’t share the same base model. Then there are other model states, like black holes, huge spaceships or meteor fields... Each model state has its own specific elements to render with their own proper parameters. So it might not be the most optimized setup, but it helps me easily pinpoint where a problem is coming from thanks to that clear separation :wink:
Post Reply