diff --git a/etc/art/assetbusy.pdn b/etc/art/assetbusy.pdn new file mode 100644 index 0000000..ac2c5aa Binary files /dev/null and b/etc/art/assetbusy.pdn differ diff --git a/etc/art/brick loading anim/loadinganim.blend b/etc/art/brick loading anim/loadinganim.blend new file mode 100644 index 0000000..f077e00 Binary files /dev/null and b/etc/art/brick loading anim/loadinganim.blend differ diff --git a/etc/art/brick loading anim/togif.bat b/etc/art/brick loading anim/togif.bat new file mode 100644 index 0000000..8574ffb --- /dev/null +++ b/etc/art/brick loading anim/togif.bat @@ -0,0 +1,5 @@ +REM : XlXi 2022 +REM : Put this in the directory of your PNG export. +REM : ImageMagick is required. + +magick convert -delay 333,10000 -loop 0 -alpha set -dispose previous *.png ani.gif \ No newline at end of file diff --git a/etc/graphictoria.conf b/etc/graphictoria.conf index adc676e..0c12539 100644 --- a/etc/graphictoria.conf +++ b/etc/graphictoria.conf @@ -29,6 +29,9 @@ RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] + RewriteCond %{HTTPS} off + RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} + DocumentRoot "D:/wamp320/graphictoria/sitetest3/web/public" diff --git a/web/app/Helpers/CdnHelper.php b/web/app/Helpers/CdnHelper.php new file mode 100644 index 0000000..450c748 --- /dev/null +++ b/web/app/Helpers/CdnHelper.php @@ -0,0 +1,51 @@ + 'local', + 'root' => storage_path('app/content'), + ]); + } + + public static function Hash($content) + { + return hash('sha256', $content); + } + + public static function SaveContent($content, $mime) + { + $disk = self::GetDisk(); + $hash = self::Hash($content); + + if(!$disk->exists($hash) || !CdnHash::where('hash', $hash)->exists()) { + $disk->put($hash, $content); + + $cdnItem = new CdnHash(); + $cdnItem->hash = $hash; + $cdnItem->mime_type = $mime; + $cdnItem->save(); + } + + return $hash; + } + + public static function SaveContentB64($contentB64, $mime) + { + return self::SaveContent(base64_decode($contentB64), $mime); + } +} diff --git a/web/app/Helpers/QAaMBHelper.php b/web/app/Helpers/QAaMBHelper.php index 42eb6b6..5e92ffd 100644 --- a/web/app/Helpers/QAaMBHelper.php +++ b/web/app/Helpers/QAaMBHelper.php @@ -115,11 +115,13 @@ class QAaMBHelper { $memoryInfo = self::getSystemMemoryInfo(); + // XlXi: the -2 is required so it fits inside of the bar thing + // XlXi: change this if theres ever a separate graph return sprintf( '%s of %s (%s%%)
%s Free', self::memoryString($memoryInfo['MemTotal'] - $memoryInfo['MemFree']), self::memoryString($memoryInfo['MemTotal']), - round(self::getMemoryPercentage() * 100), + round(self::getMemoryPercentage() * (100-2)), self::memoryString($memoryInfo['MemFree']) ); } @@ -133,9 +135,11 @@ class QAaMBHelper public static function getCpuUsage() { + // XlXi: the -2 is required so it fits inside of the bar thing + // XlXi: change this if theres ever a separate graph return sprintf( '%s%% CPU Usage', - round(self::getSystemCpuInfo() * 100) + round(self::getSystemCpuInfo() * (100-2)) ); } } diff --git a/web/app/Http/Controllers/Api/ThumbnailController.php b/web/app/Http/Controllers/Api/ThumbnailController.php new file mode 100644 index 0000000..83ff9d1 --- /dev/null +++ b/web/app/Http/Controllers/Api/ThumbnailController.php @@ -0,0 +1,67 @@ +all(), [ + 'id' => [ + 'required', + Rule::exists('App\Models\Asset', 'id')->where(function($query) { + return $query->where('moderated', false); + }) + ], + 'type' => 'regex:/(3D|2D)/i' + ]); + + if($validator->fails()) + return ValidationHelper::generateValidatorError($validator); + + $valid = $validator->valid(); + $asset = Asset::where('id', $valid['id'])->first(); + + $valid['type'] = strtolower($valid['type']); + + if($asset->thumbnail2DHash && $valid['type'] == '2d') + return response(['status' => 'success', 'data' => route('content', $asset->thumbnail2DHash)]); + + if($asset->thumbnail3DHash && $valid['type'] == '3d') + return response(['status' => 'success', 'data' => route('content', $asset->thumbnail3DHash)]); + + $tracker = RenderTracker::where('type', sprintf('asset%s', $valid['type'])) + ->where('target', $valid['id']); + + if(!$tracker->exists()) { + $tracker = new RenderTracker; + $tracker->type = sprintf('asset%s', $valid['type']); + $tracker->target = $valid['id']; + $tracker->save(); + + ArbiterRender::dispatch($tracker, $valid['type'] == '3d'); + } + + return response(['status' => 'loading']); + } + + public function renderUser() + { + // + } + + public function tryAsset() + { + // + } +} diff --git a/web/app/Http/Controllers/Cdn/CdnController.php b/web/app/Http/Controllers/Cdn/CdnController.php new file mode 100644 index 0000000..192668a --- /dev/null +++ b/web/app/Http/Controllers/Cdn/CdnController.php @@ -0,0 +1,34 @@ +exists($hash)) { + $content = CdnHash::where('hash', $hash)->first(); + + if(!$content || $content->deleted) + return response('This item is currently unavailable.') + ->header('content-type', 'text/plain'); + + return response($disk->get($hash)) + ->header('content-type', $content->mime_type); + } else { + return response('Invalid hash.') + ->header('content-type', 'text/plain'); + } + } +} diff --git a/web/app/Http/Controllers/Web/TestController.php b/web/app/Http/Controllers/Web/TestController.php index 3181e6b..dcf4be6 100644 --- a/web/app/Http/Controllers/Web/TestController.php +++ b/web/app/Http/Controllers/Web/TestController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Web; use Illuminate\Http\Request; +use Illuminate\Support\Str; use App\Http\Controllers\Controller; use App\Grid\SoapService; diff --git a/web/app/Jobs/ArbiterRender.php b/web/app/Jobs/ArbiterRender.php new file mode 100644 index 0000000..9e6e24c --- /dev/null +++ b/web/app/Jobs/ArbiterRender.php @@ -0,0 +1,149 @@ +tracker = $tracker; + $this->is3D = $is3D; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $testScript = <<OpenJob(SoapService::MakeJobJSON(Str::uuid()->toString(), 120, 0, 0, sprintf('Render %s %d', $this->tracker->type, $this->tracker->target), $testScript)); + + if(is_soap_fault($result)) + $this->fail(sprintf('SOAP Fault: (faultcode: %s, faultstring: %s)', $result->faultcode, $result->faultstring)); + + $result = $result->OpenJobExResult->LuaValue[0]->value; + + if($this->is3D) { + $content = json_decode($result); + $result = [ + 'camera' => $content->camera, + 'AABB' => $content->AABB, + 'obj' => '', + 'mtl' => '', + 'textures' => [] + ]; + + $mtlTmp; + foreach($content->files as $file => $fileB64) { + $extension = strtolower(substr(strrchr($file, '.'), 1)); + if($extension == 'mtl') + $mtlTmp = base64_decode($fileB64->content); + } + + // RCC adds map_d for whatever reason. (alpha map) + $mtlTmp = preg_replace('/^map_d.+\n/im', '', $mtlTmp); + // Fix the shine + $mtlTmp = preg_replace('/^Ns \d+/im', 'Ns 0', $mtlTmp); + $mtlTmp = preg_replace('/^Ks.+/im', 'Ks 0.0627451 0.0627451 0.0627451', $mtlTmp); + + foreach($content->files as $file => $fileB64) { + $extension = strtolower(substr(strrchr($file, '.'), 1)); + + if($extension != 'obj' && $extension != 'mtl') + $extension = 'textures'; + + if($extension == 'mtl') + continue; + + $cdnHash = CdnHelper::SaveContentB64($fileB64->content, ($extension == 'png' ? 'image/png' : 'text/plain')); + $mtlTmp = str_replace($file, $cdnHash, $mtlTmp); + + if(array_key_exists($extension, $result)) { + if(gettype($result[$extension]) == 'array') + array_push($result[$extension], $cdnHash); + else + $result[$extension] = $cdnHash; + } else { + $result[$extension] = $cdnHash; + } + } + + $result['mtl'] = CdnHelper::SaveContent($mtlTmp, 'text/plain'); + + $this->tracker->targetObj->set3DHash(CdnHelper::SaveContent(json_encode($result), 'text/plain')); + } else { + $this->tracker->targetObj->set2DHash(CdnHelper::SaveContentB64($result, 'image/png')); + } + + $this->tracker->delete(); + } +} diff --git a/web/app/Models/CdnHash.php b/web/app/Models/CdnHash.php new file mode 100644 index 0000000..a79c85c --- /dev/null +++ b/web/app/Models/CdnHash.php @@ -0,0 +1,11 @@ +type == 'user2d' || $this->type == 'user3d') + return $this->belongsTo(User::class, 'target'); + elseif($this->type == 'asset2d' || $this->type == 'asset3d') + return $this->belongsTo(Asset::class, 'target'); + } +} diff --git a/web/app/Models/asset.php b/web/app/Models/asset.php index edae3f1..287fe26 100644 --- a/web/app/Models/asset.php +++ b/web/app/Models/asset.php @@ -6,9 +6,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Carbon\Carbon; -use App\Models\AssetVersion; -use App\Models\User; - class Asset extends Model { use HasFactory; @@ -153,6 +150,18 @@ class Asset extends Model return 'https://gtoria.local/images/testing/hat.png'; } + public function set2DHash($hash) + { + $this->thumbnail2DHash = $hash; + $this->save(); + } + + public function set3DHash($hash) + { + $this->thumbnail3DHash = $hash; + $this->save(); + } + public function getCreated() { $date = $this['created_at']; diff --git a/web/app/Providers/AppServiceProvider.php b/web/app/Providers/AppServiceProvider.php index 34fc9ce..485a9b0 100644 --- a/web/app/Providers/AppServiceProvider.php +++ b/web/app/Providers/AppServiceProvider.php @@ -3,6 +3,7 @@ namespace App\Providers; use Illuminate\Support\Facades\Blade; +use Illuminate\Support\Facades\URL; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -24,6 +25,8 @@ class AppServiceProvider extends ServiceProvider */ public function boot() { + URL::forceScheme('https'); + Blade::directive('owner', function() { return 'hasRoleset(\'Owner\')): ?>'; }); diff --git a/web/app/Providers/RouteServiceProvider.php b/web/app/Providers/RouteServiceProvider.php index c52e035..f7479ca 100644 --- a/web/app/Providers/RouteServiceProvider.php +++ b/web/app/Providers/RouteServiceProvider.php @@ -54,6 +54,14 @@ class RouteServiceProvider extends ServiceProvider ->middleware('api') ->namespace('App\Http\Controllers\Api') ->group(base_path('routes/api.php')); + + // + // Domain: cdn.gtoria.net + // + Route::domain('cdn.' . DomainHelper::TopLevelDomain()) + ->middleware('api') + ->namespace('App\Http\Controllers\Cdn') + ->group(base_path('routes/cdn.php')); }); } diff --git a/web/config/queue.php b/web/config/queue.php index 25ea5a8..6112837 100644 --- a/web/config/queue.php +++ b/web/config/queue.php @@ -13,7 +13,7 @@ return [ | */ - 'default' => env('QUEUE_CONNECTION', 'sync'), + 'default' => env('QUEUE_CONNECTION', 'database'), /* |-------------------------------------------------------------------------- diff --git a/web/database/migrations/2022_06_05_140351_create_assets_table.php b/web/database/migrations/2022_06_05_140351_create_assets_table.php index c02d27a..e801963 100644 --- a/web/database/migrations/2022_06_05_140351_create_assets_table.php +++ b/web/database/migrations/2022_06_05_140351_create_assets_table.php @@ -31,10 +31,8 @@ return new class extends Migration $table->unsignedSmallInteger('assetAttributeId')->nullable(); $table->unsignedBigInteger('assetVersionId')->comment('The most recent version id for the asset. This is used internally as asset version 0 when using the /asset api.'); - // Calculating the subdomain on runtime is too expensive. - // So full URLs are used instead of just the hashes. - $table->string('thumbnailURL')->nullable(); - $table->string('3dThumbnailURL')->nullable(); + $table->string('thumbnail2DHash')->nullable(); + $table->string('thumbnail3DHash')->nullable(); $table->timestamps(); }); diff --git a/web/database/migrations/2022_08_12_203428_create_cdn_hashes_table.php b/web/database/migrations/2022_08_12_203428_create_cdn_hashes_table.php new file mode 100644 index 0000000..b408980 --- /dev/null +++ b/web/database/migrations/2022_08_12_203428_create_cdn_hashes_table.php @@ -0,0 +1,36 @@ +id(); + $table->string('hash'); + $table->string('mime_type'); + $table->unsignedBigInteger('user_id')->nullable(); + $table->unsignedBigInteger('asset_version_id')->nullable(); + $table->boolean('deleted')->default(false); // XlXi: in the case of copyright or whatever + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('cdn_hashes'); + } +}; diff --git a/web/database/migrations/2022_08_14_232602_create_render_trackers_table.php b/web/database/migrations/2022_08_14_232602_create_render_trackers_table.php new file mode 100644 index 0000000..9b2264a --- /dev/null +++ b/web/database/migrations/2022_08_14_232602_create_render_trackers_table.php @@ -0,0 +1,33 @@ +id(); + $table->string('type'); + $table->unsignedBigInteger('target'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('render_trackers'); + } +}; diff --git a/web/database/migrations/2022_08_15_164445_create_jobs_table.php b/web/database/migrations/2022_08_15_164445_create_jobs_table.php new file mode 100644 index 0000000..a786a89 --- /dev/null +++ b/web/database/migrations/2022_08_15_164445_create_jobs_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('jobs'); + } +}; diff --git a/web/database/migrations/2019_08_19_000000_create_failed_jobs_table.php b/web/database/migrations/2022_08_15_164451_create_failed_jobs_table.php similarity index 100% rename from web/database/migrations/2019_08_19_000000_create_failed_jobs_table.php rename to web/database/migrations/2022_08_15_164451_create_failed_jobs_table.php diff --git a/web/package-lock.json b/web/package-lock.json index ac97591..d8a7392 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -5,6 +5,7 @@ "packages": { "": { "dependencies": { + "@react-three/postprocessing": "^2.6.1", "@restart/ui": "^1.3.1", "classnames": "^2.3.1", "install": "^0.13.0", @@ -1613,7 +1614,6 @@ "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.1.2.tgz", "integrity": "sha512-E/XrL0QlzExycPzwhOEZGVOheJ/Clr5uNv3oCds88MiNqEmg3UU1iauZk7DhjsUo3jgEW4lf0I5HRl7/HC5ZkQ==", - "dev": true, "dependencies": { "@chevrotain/gast": "^10.1.2", "@chevrotain/types": "^10.1.2", @@ -1624,7 +1624,6 @@ "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.1.2.tgz", "integrity": "sha512-er+TcxUOMuGOPoiOq8CJsRm92zGE4YPIYtyxJfxoVwVgtj4AMrPNCmrHvYaK/bsbt2DaDuFdcbbAfM9bcBXW6Q==", - "dev": true, "dependencies": { "@chevrotain/types": "^10.1.2", "lodash": "4.17.21" @@ -1633,14 +1632,12 @@ "node_modules/@chevrotain/types": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.1.2.tgz", - "integrity": "sha512-4qF9SmmWKv8AIG/3d+71VFuqLumNCQTP5GoL0CW6x7Ay2OdXm6FUgWFLTMneGUjYUk2C+MSCf7etQfdq3LEr1A==", - "dev": true + "integrity": "sha512-4qF9SmmWKv8AIG/3d+71VFuqLumNCQTP5GoL0CW6x7Ay2OdXm6FUgWFLTMneGUjYUk2C+MSCf7etQfdq3LEr1A==" }, "node_modules/@chevrotain/utils": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.1.2.tgz", - "integrity": "sha512-bbZIpW6fdyf7FMaeDmw3cBbkTqsecxEkwlVKgVfqqXWBPLH6azxhPA2V9F7OhoZSVrsnMYw7QuyK6qutXPjEew==", - "dev": true + "integrity": "sha512-bbZIpW6fdyf7FMaeDmw3cBbkTqsecxEkwlVKgVfqqXWBPLH6azxhPA2V9F7OhoZSVrsnMYw7QuyK6qutXPjEew==" }, "node_modules/@colors/colors": { "version": "1.5.0", @@ -1874,7 +1871,6 @@ "version": "8.0.13", "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.0.13.tgz", "integrity": "sha512-hJdVS2F8LJFenR07l80JnkLAMeJ7gf3wiB8OzQ49GjSwjPgPG8bjYumMmchY/eouU+myYtNej0tK6mV6wctmdQ==", - "dev": true, "dependencies": { "@babel/runtime": "^7.17.8", "@types/react-reconciler": "^0.26.6", @@ -1912,6 +1908,22 @@ } } }, + "node_modules/@react-three/postprocessing": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@react-three/postprocessing/-/postprocessing-2.6.1.tgz", + "integrity": "sha512-IX6i8JI5iY9zYSjOh9ZKr3URQ+V8NSnFEOL0xBPDP7BdyLjwXKs5fPR/ClnW4bGt/4T1TMsGmLCXJ97gtZVRZA==", + "dependencies": { + "postprocessing": "^6.28.5", + "react-merge-refs": "^1.1.0", + "screen-space-reflections": "2.1.1", + "three-stdlib": "^2.8.11" + }, + "peerDependencies": { + "@react-three/fiber": ">=7.0", + "react": ">=17.0", + "three": ">=0.136.0" + } + }, "node_modules/@restart/hooks": { "version": "0.4.7", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.7.tgz", @@ -2209,7 +2221,6 @@ "version": "0.26.6", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.6.tgz", "integrity": "sha512-N8MpyC6PJksD+CbMaZ1GW1t940+L4K+f7soiNKcKfgOgof3xWLvs5nPRQ/Q0P6QwDX0GH1PT1MsiQh2FtUY6aw==", - "dev": true, "dependencies": { "@types/react": "*" } @@ -2434,8 +2445,7 @@ "node_modules/@webgpu/glslang": { "version": "0.0.15", "resolved": "https://registry.npmjs.org/@webgpu/glslang/-/glslang-0.0.15.tgz", - "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==", - "dev": true + "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==" }, "node_modules/@webpack-cli/configtest": { "version": "1.1.1", @@ -3213,7 +3223,6 @@ "version": "10.1.2", "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.1.2.tgz", "integrity": "sha512-hvRiQuhhTZxkPMGD/dke+s1EGo8AkKDBU05CcufBO278qgAQSwIC4QyLdHz0CFHVtqVYWjlAS5D1KwvBbaHT+w==", - "dev": true, "dependencies": { "@chevrotain/cst-dts-gen": "^10.1.2", "@chevrotain/gast": "^10.1.2", @@ -3853,8 +3862,7 @@ "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "dev": true + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" }, "node_modules/debug": { "version": "4.3.4", @@ -4153,8 +4161,7 @@ "node_modules/draco3d": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.2.tgz", - "integrity": "sha512-AeRQ25Fb29c14vpjnh167UGW0nGY0ZpEM3ld+zEXoEySlmEXcXfsCHZeTgo5qXH925V1JsdjrzasdaQ22/vXog==", - "dev": true + "integrity": "sha512-AeRQ25Fb29c14vpjnh167UGW0nGY0ZpEM3ld+zEXoEySlmEXcXfsCHZeTgo5qXH925V1JsdjrzasdaQ22/vXog==" }, "node_modules/ee-first": { "version": "1.1.1", @@ -4500,8 +4507,7 @@ "node_modules/fflate": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", - "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", - "dev": true + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" }, "node_modules/file-loader": { "version": "6.2.0", @@ -5604,8 +5610,7 @@ "node_modules/ktx-parse": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.2.2.tgz", - "integrity": "sha512-cFBc1jnGG2WlUf52NbDUXK2obJ+Mo9WUkBRvr6tP6CKxRMvZwDDFNV3JAS4cewETp5KyexByfWm9sm+O8AffiQ==", - "dev": true + "integrity": "sha512-cFBc1jnGG2WlUf52NbDUXK2obJ+Mo9WUkBRvr6tP6CKxRMvZwDDFNV3JAS4cewETp5KyexByfWm9sm+O8AffiQ==" }, "node_modules/laravel-mix": { "version": "6.0.43", @@ -6119,8 +6124,7 @@ "node_modules/mmd-parser": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mmd-parser/-/mmd-parser-1.0.4.tgz", - "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==", - "dev": true + "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==" }, "node_modules/ms": { "version": "2.1.2", @@ -8643,7 +8647,6 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", - "dev": true, "dependencies": { "string.prototype.codepointat": "^0.2.1", "tiny-inflate": "^1.0.3" @@ -9475,11 +9478,21 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/postprocessing": { + "version": "6.28.5", + "resolved": "https://registry.npmjs.org/postprocessing/-/postprocessing-6.28.5.tgz", + "integrity": "sha512-e9aH6T720AiQpStdgqrQSsHzpddFQ7Q8v204sZx4iSTnUuYvkq7mFPOyzhVDlx5NrmXXbwz2PEK2XTq+qEYSMg==", + "engines": { + "node": ">= 0.13.2" + }, + "peerDependencies": { + "three": ">= 0.107.0 < 0.144.0" + } + }, "node_modules/potpack": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "dev": true + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" }, "node_modules/pretty-time": { "version": "1.1.0", @@ -9723,7 +9736,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz", "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==", - "dev": true, "funding": { "type": "github", "url": "https://github.com/sponsors/gregberge" @@ -9733,7 +9745,6 @@ "version": "0.27.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.21.0" @@ -9789,7 +9800,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", - "dev": true, "dependencies": { "debounce": "^1.2.1" }, @@ -9889,8 +9899,7 @@ "node_modules/regexp-to-ast": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", - "dev": true + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==" }, "node_modules/regexpu-core": { "version": "5.0.1", @@ -10159,7 +10168,6 @@ "version": "0.21.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", - "dev": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -10181,6 +10189,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/screen-space-reflections": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/screen-space-reflections/-/screen-space-reflections-2.1.1.tgz", + "integrity": "sha512-UwBaTb6Ss/8EfhDHEdybPhMbHXmtchOcpHHTa5guFFzjj1f0998twZRr/svOJaA/Nyi44VL2Cqf3xGhdu3hC2w==", + "peerDependencies": { + "postprocessing": ">=6.28.0", + "three": ">=0.141.0" + } + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -10590,8 +10607,7 @@ "node_modules/string.prototype.codepointat": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", - "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==", - "dev": true + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" }, "node_modules/strip-ansi": { "version": "6.0.1", @@ -10689,7 +10705,6 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.0.8.tgz", "integrity": "sha512-ZC3r8Hu1y0dIThzsGw0RLZplnX9yXwfItcvaIzJc2VQVi8TGyGDlu92syMB5ulybfvGLHAI5Ghzlk23UBPF8xg==", - "dev": true, "peerDependencies": { "react": ">=17.0" } @@ -10874,10 +10889,9 @@ } }, "node_modules/three": { - "version": "0.140.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.140.0.tgz", - "integrity": "sha512-jcHjbnYspPLDdsDQChmzyAoZ5KhJbgFk6pNGlAIc9fQMvsfPGjF5H9glrngqvb2CR/qXcClMyp5PYdF996lldA==", - "dev": true, + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.143.0.tgz", + "integrity": "sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg==", "peer": true }, "node_modules/three-mesh-bvh": { @@ -10893,7 +10907,6 @@ "version": "2.10.1", "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.10.1.tgz", "integrity": "sha512-qKJLFB5KMUhPe4JgtJ6bnY7+nEuNPVbxfKyAeRIRbTTBF1oP/rKogZAio+NI5SXSo4iuIu59e02AzOzh8AR9cQ==", - "dev": true, "dependencies": { "@babel/runtime": "^7.16.7", "@webgpu/glslang": "^0.0.15", @@ -10929,8 +10942,7 @@ "node_modules/tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", - "dev": true + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" }, "node_modules/to-arraybuffer": { "version": "1.0.1", @@ -11916,14 +11928,12 @@ "node_modules/zstddec": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz", - "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==", - "dev": true + "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==" }, "node_modules/zustand": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", - "dev": true, "engines": { "node": ">=12.7.0" }, @@ -13000,7 +13010,6 @@ "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-10.1.2.tgz", "integrity": "sha512-E/XrL0QlzExycPzwhOEZGVOheJ/Clr5uNv3oCds88MiNqEmg3UU1iauZk7DhjsUo3jgEW4lf0I5HRl7/HC5ZkQ==", - "dev": true, "requires": { "@chevrotain/gast": "^10.1.2", "@chevrotain/types": "^10.1.2", @@ -13011,7 +13020,6 @@ "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-10.1.2.tgz", "integrity": "sha512-er+TcxUOMuGOPoiOq8CJsRm92zGE4YPIYtyxJfxoVwVgtj4AMrPNCmrHvYaK/bsbt2DaDuFdcbbAfM9bcBXW6Q==", - "dev": true, "requires": { "@chevrotain/types": "^10.1.2", "lodash": "4.17.21" @@ -13020,14 +13028,12 @@ "@chevrotain/types": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-10.1.2.tgz", - "integrity": "sha512-4qF9SmmWKv8AIG/3d+71VFuqLumNCQTP5GoL0CW6x7Ay2OdXm6FUgWFLTMneGUjYUk2C+MSCf7etQfdq3LEr1A==", - "dev": true + "integrity": "sha512-4qF9SmmWKv8AIG/3d+71VFuqLumNCQTP5GoL0CW6x7Ay2OdXm6FUgWFLTMneGUjYUk2C+MSCf7etQfdq3LEr1A==" }, "@chevrotain/utils": { "version": "10.1.2", "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-10.1.2.tgz", - "integrity": "sha512-bbZIpW6fdyf7FMaeDmw3cBbkTqsecxEkwlVKgVfqqXWBPLH6azxhPA2V9F7OhoZSVrsnMYw7QuyK6qutXPjEew==", - "dev": true + "integrity": "sha512-bbZIpW6fdyf7FMaeDmw3cBbkTqsecxEkwlVKgVfqqXWBPLH6azxhPA2V9F7OhoZSVrsnMYw7QuyK6qutXPjEew==" }, "@colors/colors": { "version": "1.5.0", @@ -13201,7 +13207,6 @@ "version": "8.0.13", "resolved": "https://registry.npmjs.org/@react-three/fiber/-/fiber-8.0.13.tgz", "integrity": "sha512-hJdVS2F8LJFenR07l80JnkLAMeJ7gf3wiB8OzQ49GjSwjPgPG8bjYumMmchY/eouU+myYtNej0tK6mV6wctmdQ==", - "dev": true, "requires": { "@babel/runtime": "^7.17.8", "@types/react-reconciler": "^0.26.6", @@ -13213,6 +13218,17 @@ "zustand": "^3.7.1" } }, + "@react-three/postprocessing": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@react-three/postprocessing/-/postprocessing-2.6.1.tgz", + "integrity": "sha512-IX6i8JI5iY9zYSjOh9ZKr3URQ+V8NSnFEOL0xBPDP7BdyLjwXKs5fPR/ClnW4bGt/4T1TMsGmLCXJ97gtZVRZA==", + "requires": { + "postprocessing": "^6.28.5", + "react-merge-refs": "^1.1.0", + "screen-space-reflections": "2.1.1", + "three-stdlib": "^2.8.11" + } + }, "@restart/hooks": { "version": "0.4.7", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.7.tgz", @@ -13496,7 +13512,6 @@ "version": "0.26.6", "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.26.6.tgz", "integrity": "sha512-N8MpyC6PJksD+CbMaZ1GW1t940+L4K+f7soiNKcKfgOgof3xWLvs5nPRQ/Q0P6QwDX0GH1PT1MsiQh2FtUY6aw==", - "dev": true, "requires": { "@types/react": "*" } @@ -13718,8 +13733,7 @@ "@webgpu/glslang": { "version": "0.0.15", "resolved": "https://registry.npmjs.org/@webgpu/glslang/-/glslang-0.0.15.tgz", - "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==", - "dev": true + "integrity": "sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q==" }, "@webpack-cli/configtest": { "version": "1.1.1", @@ -14311,7 +14325,6 @@ "version": "10.1.2", "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-10.1.2.tgz", "integrity": "sha512-hvRiQuhhTZxkPMGD/dke+s1EGo8AkKDBU05CcufBO278qgAQSwIC4QyLdHz0CFHVtqVYWjlAS5D1KwvBbaHT+w==", - "dev": true, "requires": { "@chevrotain/cst-dts-gen": "^10.1.2", "@chevrotain/gast": "^10.1.2", @@ -14804,8 +14817,7 @@ "debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", - "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "dev": true + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==" }, "debug": { "version": "4.3.4", @@ -15031,8 +15043,7 @@ "draco3d": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.2.tgz", - "integrity": "sha512-AeRQ25Fb29c14vpjnh167UGW0nGY0ZpEM3ld+zEXoEySlmEXcXfsCHZeTgo5qXH925V1JsdjrzasdaQ22/vXog==", - "dev": true + "integrity": "sha512-AeRQ25Fb29c14vpjnh167UGW0nGY0ZpEM3ld+zEXoEySlmEXcXfsCHZeTgo5qXH925V1JsdjrzasdaQ22/vXog==" }, "ee-first": { "version": "1.1.1", @@ -15310,8 +15321,7 @@ "fflate": { "version": "0.6.10", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz", - "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==", - "dev": true + "integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==" }, "file-loader": { "version": "6.2.0", @@ -16088,8 +16098,7 @@ "ktx-parse": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.2.2.tgz", - "integrity": "sha512-cFBc1jnGG2WlUf52NbDUXK2obJ+Mo9WUkBRvr6tP6CKxRMvZwDDFNV3JAS4cewETp5KyexByfWm9sm+O8AffiQ==", - "dev": true + "integrity": "sha512-cFBc1jnGG2WlUf52NbDUXK2obJ+Mo9WUkBRvr6tP6CKxRMvZwDDFNV3JAS4cewETp5KyexByfWm9sm+O8AffiQ==" }, "laravel-mix": { "version": "6.0.43", @@ -16481,8 +16490,7 @@ "mmd-parser": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mmd-parser/-/mmd-parser-1.0.4.tgz", - "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==", - "dev": true + "integrity": "sha512-Qi0VCU46t2IwfGv5KF0+D/t9cizcDug7qnNoy9Ggk7aucp0tssV8IwTMkBlDbm+VqAf3cdQHTCARKSsuS2MYFg==" }, "ms": { "version": "2.1.2", @@ -18198,7 +18206,6 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", - "dev": true, "requires": { "string.prototype.codepointat": "^0.2.1", "tiny-inflate": "^1.0.3" @@ -18711,11 +18718,16 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "postprocessing": { + "version": "6.28.5", + "resolved": "https://registry.npmjs.org/postprocessing/-/postprocessing-6.28.5.tgz", + "integrity": "sha512-e9aH6T720AiQpStdgqrQSsHzpddFQ7Q8v204sZx4iSTnUuYvkq7mFPOyzhVDlx5NrmXXbwz2PEK2XTq+qEYSMg==", + "requires": {} + }, "potpack": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "dev": true + "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==" }, "pretty-time": { "version": "1.1.0", @@ -18903,14 +18915,12 @@ "react-merge-refs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/react-merge-refs/-/react-merge-refs-1.1.0.tgz", - "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==", - "dev": true + "integrity": "sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==" }, "react-reconciler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.27.0.tgz", "integrity": "sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==", - "dev": true, "requires": { "loose-envify": "^1.1.0", "scheduler": "^0.21.0" @@ -18947,7 +18957,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.1.tgz", "integrity": "sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==", - "dev": true, "requires": { "debounce": "^1.2.1" } @@ -19036,8 +19045,7 @@ "regexp-to-ast": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", - "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", - "dev": true + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==" }, "regexpu-core": { "version": "5.0.1", @@ -19210,7 +19218,6 @@ "version": "0.21.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.21.0.tgz", "integrity": "sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==", - "dev": true, "requires": { "loose-envify": "^1.1.0" } @@ -19225,6 +19232,12 @@ "ajv-keywords": "^3.5.2" } }, + "screen-space-reflections": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/screen-space-reflections/-/screen-space-reflections-2.1.1.tgz", + "integrity": "sha512-UwBaTb6Ss/8EfhDHEdybPhMbHXmtchOcpHHTa5guFFzjj1f0998twZRr/svOJaA/Nyi44VL2Cqf3xGhdu3hC2w==", + "requires": {} + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -19570,8 +19583,7 @@ "string.prototype.codepointat": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", - "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==", - "dev": true + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" }, "strip-ansi": { "version": "6.0.1", @@ -19633,7 +19645,6 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/suspend-react/-/suspend-react-0.0.8.tgz", "integrity": "sha512-ZC3r8Hu1y0dIThzsGw0RLZplnX9yXwfItcvaIzJc2VQVi8TGyGDlu92syMB5ulybfvGLHAI5Ghzlk23UBPF8xg==", - "dev": true, "requires": {} }, "svgo": { @@ -19757,10 +19768,9 @@ } }, "three": { - "version": "0.140.0", - "resolved": "https://registry.npmjs.org/three/-/three-0.140.0.tgz", - "integrity": "sha512-jcHjbnYspPLDdsDQChmzyAoZ5KhJbgFk6pNGlAIc9fQMvsfPGjF5H9glrngqvb2CR/qXcClMyp5PYdF996lldA==", - "dev": true, + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.143.0.tgz", + "integrity": "sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg==", "peer": true }, "three-mesh-bvh": { @@ -19774,7 +19784,6 @@ "version": "2.10.1", "resolved": "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.10.1.tgz", "integrity": "sha512-qKJLFB5KMUhPe4JgtJ6bnY7+nEuNPVbxfKyAeRIRbTTBF1oP/rKogZAio+NI5SXSo4iuIu59e02AzOzh8AR9cQ==", - "dev": true, "requires": { "@babel/runtime": "^7.16.7", "@webgpu/glslang": "^0.0.15", @@ -19804,8 +19813,7 @@ "tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", - "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", - "dev": true + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" }, "to-arraybuffer": { "version": "1.0.1", @@ -20540,14 +20548,12 @@ "zstddec": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.0.2.tgz", - "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==", - "dev": true + "integrity": "sha512-DCo0oxvcvOTGP/f5FA6tz2Z6wF+FIcEApSTu0zV5sQgn9hoT5lZ9YRAKUraxt9oP7l4e8TnNdi8IZTCX6WCkwA==" }, "zustand": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/zustand/-/zustand-3.7.2.tgz", "integrity": "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==", - "dev": true, "requires": {} } } diff --git a/web/package.json b/web/package.json index f15d77c..fcfa1a0 100644 --- a/web/package.json +++ b/web/package.json @@ -30,6 +30,7 @@ "tailwindcss": "^3.0.24" }, "dependencies": { + "@react-three/postprocessing": "^2.6.1", "@restart/ui": "^1.3.1", "classnames": "^2.3.1", "install": "^0.13.0", diff --git a/web/public/images/busy/3d.gif b/web/public/images/busy/3d.gif new file mode 100644 index 0000000..fd45b32 Binary files /dev/null and b/web/public/images/busy/3d.gif differ diff --git a/web/public/images/busy/asset.png b/web/public/images/busy/asset.png new file mode 100644 index 0000000..f9482ce Binary files /dev/null and b/web/public/images/busy/asset.png differ diff --git a/web/resources/js/components/Comments.js b/web/resources/js/components/Comments.js index 136b65e..afacc0a 100644 --- a/web/resources/js/components/Comments.js +++ b/web/resources/js/components/Comments.js @@ -42,7 +42,7 @@ class Comments extends Component { } componentDidMount() { - let commentsElement = document.getElementById(commentsId); + let commentsElement = this.props.element; if (commentsElement) { this.assetId = commentsElement.getAttribute('data-asset-id') this.setState({ diff --git a/web/resources/js/components/ProgressiveImage.js b/web/resources/js/components/ProgressiveImage.js new file mode 100644 index 0000000..2daec52 --- /dev/null +++ b/web/resources/js/components/ProgressiveImage.js @@ -0,0 +1,22 @@ +// https://levelup.gitconnected.com/react-lazy-load-image-e6a5ca944f32 +// XlXi: i was too lazy to write this myself + +import React, { useCallback, useEffect, useState } from "react"; +export default ({ src, placeholderImg, ...props }) => { + const [imgSrc, setSrc] = useState(placeholderImg || src); + const onLoad = useCallback(() => { + setSrc(src); + }, [src]); + + useEffect(() => { + const img = new Image(); + img.src = src; + img.addEventListener("load", onLoad); + + return () => { + img.removeEventListener("load", onLoad); + }; + }, [src, onLoad]); + + return ; +}; \ No newline at end of file diff --git a/web/resources/js/components/PurchaseButton.js b/web/resources/js/components/PurchaseButton.js index 46e35d4..14a621c 100644 --- a/web/resources/js/components/PurchaseButton.js +++ b/web/resources/js/components/PurchaseButton.js @@ -4,7 +4,6 @@ */ import { createRef, Component } from 'react'; -import ReactDOM from 'react-dom'; import classNames from 'classnames/bind'; diff --git a/web/resources/js/components/ThumbnailTool.js b/web/resources/js/components/ThumbnailTool.js new file mode 100644 index 0000000..1dbe14c --- /dev/null +++ b/web/resources/js/components/ThumbnailTool.js @@ -0,0 +1,221 @@ +/* + Graphictoria 5 (https://gtoria.net) + Copyright © XlXi 2022 +*/ + +import { Component, Suspense, useEffect, useRef } from 'react'; + +import * as THREE from 'three'; +import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'; +import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader'; +import { OrbitControls, PerspectiveCamera } from "@react-three/drei"; +import { Canvas, useLoader, useThree } from '@react-three/fiber'; +import { EffectComposer, SSAO } from '@react-three/postprocessing'; +import { BlendFunction } from 'postprocessing'; + +import axios from 'axios'; + +import { buildGenericApiUrl } from '../util/HTTP.js'; +import ProgressiveImage from './ProgressiveImage'; +import Loader from './Loader'; + +axios.defaults.withCredentials = true; + +const Scene = ({json}) => { + const mtl = useLoader(MTLLoader, json.mtl); + const obj = useLoader(OBJLoader, json.obj, (loader) => { + mtl.preload(); + loader.setMaterials(mtl); + }); + let controls = useRef(); + let midPoint; + + useThree(({camera, scene}) => { + let aabbMax = json.AABB.max; + let aabbMin = json.AABB.min; + aabbMax = new THREE.Vector3(aabbMax.x, aabbMax.y, aabbMax.z); + aabbMin = new THREE.Vector3(aabbMin.x, aabbMin.y, aabbMin.z); + + midPoint = new THREE.Vector3(); + midPoint.copy(aabbMax).add(aabbMin).multiplyScalar(0.5); + + let initialPosition = json.camera.position; + let initialDirection = json.camera.direction; + + let thumbnailCameraPosition = new THREE.Vector3(initialPosition.x, initialPosition.y, initialPosition.z); + let thumbnailCameraDirection = new THREE.Vector3(initialDirection.x, initialDirection.y, initialDirection.z); + + let pointToLookat = new THREE.Vector3(); + pointToLookat.copy(thumbnailCameraPosition); + pointToLookat.sub(thumbnailCameraDirection); + + camera.position.set(thumbnailCameraPosition.x, thumbnailCameraPosition.y, thumbnailCameraPosition.z); + camera.lookAt(pointToLookat); + + // lighting + // FIXME: XlXi: if you toggle 3d on and off it'll create these twice + let ambient = new THREE.AmbientLight(0x878780); + scene.add(ambient); + + let sunLight = new THREE.DirectionalLight(0xacacac); + sunLight.position.set(0.671597898, 0.671597898, -0.312909544).normalize(); + scene.add(sunLight); + + let backLight = new THREE.DirectionalLight(0x444444); + let backLightPos = new THREE.Vector3() + .copy(sunLight.position) + .negate() + .normalize(); // inverse of sun direction + backLight.position.set(backLightPos); + scene.add(backLight); + }); + + useEffect(() => { + controls.current.target = midPoint; + controls.current.update(); + }); + + return ( + <> + + {/* + + + + */} + + + ) +} + +class ThumbnailTool extends Component { + constructor(props) { + super(props); + this.state = { + initialLoading: true, + loading: false, + is3d: false, + seed3d: 0 + }; + + this.tryAsset = this.tryAsset.bind(this); + this.loadThumbnail = this.loadThumbnail.bind(this); + this.toggle3D = this.toggle3D.bind(this); + } + + componentDidMount() { + let thumbnailElement = this.props.element; + if (thumbnailElement) { + this.thumbnail2d = thumbnailElement.getAttribute('data-asset-thumbnail-2d'); + this.assetId = thumbnailElement.getAttribute('data-asset-id'); + this.assetName = thumbnailElement.getAttribute('data-asset-name'); + + this.setState({ initialLoading: false }); + } + } + + loadThumbnail(url, is3d) { + axios.get(buildGenericApiUrl('api', url)) + .then(res => { + let data = res.data; + + if(data.status === 'success') { + if(is3d) { + axios.get(data.data) + .then(res => { + let newJson = res.data; + newJson.mtl = buildGenericApiUrl('cdn', newJson.mtl); + newJson.obj = buildGenericApiUrl('cdn', newJson.obj); + if(Array.isArray(newJson.textures)) { + let newTextures = []; + newJson.textures.map((hash) => { + newTextures.push(buildGenericApiUrl('cdn', hash)); + }); + newJson.textures = newTextures; + } else { + newJson.textures = buildGenericApiUrl('cdn', newJson.textures); + } + + this.setState({ loading: false, json3d: res.data }); + }); + } else { + this.setState({ loading: false }); + } + } else { + let lt = this.loadThumbnail; + setTimeout(function(){lt(url,is3d)}, 1000); + } + }); + } + + tryAsset() { + let is3d = !this.state.is3d; + + this.setState({ loading: true, is3d: is3d }); + this.loadThumbnail(`thumbnails/v1/try-asset?id=${this.assetId}&type=${this.state.is3d ? '3D' : '2D'}`, is3d); + } + + toggle3D() { + let is3d = !this.state.is3d; + + this.setState({ loading: true, is3d: is3d, seed3d: Math.random() }); + + if(is3d) { + this.loadThumbnail(`thumbnails/v1/asset?id=${this.assetId}&type=3D`, true); + } else { + this.setState({ loading: false }); + } + } + + render() { + return ( + <> + { + this.state.initialLoading + ? +
+ +
+ : + <> + { + this.state.loading + ? +
+ +
+ : + ( + this.state.is3d + ? + + + + + + : + + ) + } +
+ + +
+ + } + + ); + } +} + +export default ThumbnailTool; \ No newline at end of file diff --git a/web/resources/js/components/ThumbnailToolbar.js b/web/resources/js/components/ThumbnailToolbar.js deleted file mode 100644 index e69de29..0000000 diff --git a/web/resources/js/pages/Item.js b/web/resources/js/pages/Item.js index e1e3983..7563d45 100644 --- a/web/resources/js/pages/Item.js +++ b/web/resources/js/pages/Item.js @@ -10,15 +10,22 @@ import { render } from 'react-dom'; import Comments from '../components/Comments'; import PurchaseButton from '../components/PurchaseButton'; +import ThumbnailTool from '../components/ThumbnailTool'; const purchaseId = 'gt-purchase-button'; -const commentsId = 'gt-comments'; // XlXi: Keep this in sync with the Comments component. +const commentsId = 'gt-comments'; +const thumbnailId = 'gt-thumbnail'; $(document).ready(function() { if (document.getElementById(commentsId)) { - render(, document.getElementById(commentsId)); + let cElem = document.getElementById(commentsId); + render(, cElem); } if (document.getElementById(purchaseId)) { render(, document.getElementById(purchaseId)); } + if (document.getElementById(thumbnailId)) { + let tElem = document.getElementById(thumbnailId); + render(, tElem); + } }); \ No newline at end of file diff --git a/web/resources/sass/Graphictoria.scss b/web/resources/sass/Graphictoria.scss index 4cc8710..f5a91fa 100644 --- a/web/resources/sass/Graphictoria.scss +++ b/web/resources/sass/Graphictoria.scss @@ -36,6 +36,11 @@ img.twemoji { // Shop +.graphictoria-asset-thumbnail { + width: 420px; + height: 420px; +} + .graphictoria-item-page { max-width: 1096px; margin: 0 auto 0 auto; diff --git a/web/resources/views/layouts/nav.blade.php b/web/resources/views/layouts/nav.blade.php index 8e326e9..f784a6e 100644 --- a/web/resources/views/layouts/nav.blade.php +++ b/web/resources/views/layouts/nav.blade.php @@ -62,6 +62,12 @@ @@ -105,7 +111,7 @@ @endphp
@@ -173,7 +179,6 @@

diff --git a/web/resources/views/web/shop/asset.blade.php b/web/resources/views/web/shop/asset.blade.php index bf5e655..b007a06 100644 --- a/web/resources/views/web/shop/asset.blade.php +++ b/web/resources/views/web/shop/asset.blade.php @@ -7,6 +7,26 @@ @endsection @section('quick-admin') +@owner +

+@endowner +@admin + + + +@endadmin