Ekstensi OpenXR XR_ANDROID_trackables

String Nama

XR_ANDROID_trackables

Jenis Ekstensi

Ekstensi instance

Registered Extension Number

456

Revisi

1

Dependensi Ekstensi dan Versi

OpenXR 1.0

Tanggal Terakhir Diubah

2024-09-30

Status IP

Tidak ada klaim IP yang diketahui.

Kontributor

Spencer Quin, Google

Nihav Jain, Google

John Pursey, Google

Jared Finder, Google

Levana Chen, Google

Kenny Vercaemer, Google

Ringkasan

Ekstensi ini memungkinkan aplikasi mengakses pelacak dari lingkungan fisik, dan membuat anchor yang terpasang ke pelacak.

Ekstensi ini menentukan pelacak bidang. Ekstensi lain mungkin menambahkan jenis yang dapat dilacak lainnya. Misalnya, XR_ANDROID_trackables_object menambahkan objek yang dapat dilacak, dan XR_ANDROID_depth_texture menambahkan buffering kedalaman yang memungkinkan raycasting ke titik arbitrer di lingkungan.

Trackable adalah sesuatu yang dilacak di lingkungan fisik (lihat XrTrackableTypeANDROID):

  • bidang (misalnya, dinding, lantai, langit-langit, meja)
  • objek (misalnya keyboard, mouse, laptop)

Membuat pelacak yang dapat dilacak

XrTrackableTrackerANDROID adalah nama sebutan yang mewakili resource yang diperlukan untuk menemukan dan memperbarui trackable dari XrTrackableTypeANDROID tertentu di lingkungan.

XR_DEFINE_HANDLE(XrTrackableTrackerANDROID)

Fungsi xrCreateTrackableTrackerANDROID ditentukan sebagai:

XrResult xrCreateTrackableTrackerANDROID(
    XrSession                                   session,
    const XrTrackableTrackerCreateInfoANDROID*  createInfo,
    XrTrackableTrackerANDROID*                  trackableTracker);

Deskripsi Parameter

Aplikasi dapat menggunakan fungsi xrCreateTrackableTrackerANDROID untuk membuat pelacak yang dapat dilacak.

  • XR_ERROR_FEATURE_UNSUPPORTED akan ditampilkan jika sistem tidak mendukung pelacak dari jenis yang ditentukan.
  • XR_ERROR_PERMISSION_INSUFFICIENT akan ditampilkan jika izin yang diperlukan belum diberikan ke aplikasi panggilan.

Aplikasi dapat menggunakan nama sebutan pelacak yang ditampilkan dalam panggilan API berikutnya. Pengendali XrTrackableTrackerANDROID harus dibebaskan pada akhirnya menggunakan fungsi xrDestroyTrackableTrackerANDROID.

Penggunaan yang Valid (Implisit)

Kode Status

Berhasil

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

Kegagalan

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_FEATURE_UNSUPPORTED

Struktur XrTrackableTrackerCreateInfoANDROID ditentukan sebagai:

typedef struct XrTrackableTrackerCreateInfoANDROID {
    XrStructureType           type;
    void*                     next;
    XrTrackableTypeANDROID    trackableType;
} XrTrackableTrackerCreateInfoANDROID;

Deskripsi Anggota

  • type adalah XrStructureType dari struktur ini.
  • next adalah NULL atau pointer ke struktur berikutnya dalam rantai struktur. Tidak ada struktur semacam itu yang ditentukan di OpenXR inti atau ekstensi ini.
  • trackableType adalah XrTrackableTypeANDROID yang akan dilacak oleh pelacak.

Struktur XrTrackableTrackerCreateInfoANDROID menyediakan opsi pembuatan untuk XrTrackableTrackerANDROID saat diteruskan ke xrCreateTrackableTrackerANDROID.

Ekstensi dapat menentukan struktur yang dapat dilampirkan ke next untuk mengizinkan konfigurasi tambahan bagi pelacak yang dapat dilacak.

Penggunaan yang Valid (Implisit)

Enum XrTrackableTypeANDROID ditentukan sebagai:

typedef enum XrTrackableTypeANDROID {
    XR_TRACKABLE_TYPE_NOT_VALID_ANDROID = 0,
    XR_TRACKABLE_TYPE_PLANE_ANDROID = 1,
    XR_TRACKABLE_TYPE_DEPTH_ANDROID = 1000463000,
    XR_TRACKABLE_TYPE_OBJECT_ANDROID = 1000466000
} XrTrackableTypeANDROID;

Fungsi xrDestroyTrackableTrackerANDROID ditentukan sebagai:

XrResult xrDestroyTrackableTrackerANDROID(
    XrTrackableTrackerANDROID                   trackableTracker);

Deskripsi Parameter

Fungsi xrDestroyTrackableTrackerANDROID menghancurkan pelacak yang dapat dilacak.

Jika tidak ada XrTrackableTrackerANDROID valid lainnya yang dibuat dengan XrTrackableTypeANDROID yang sama, sistem dapat menonaktifkan layanan pelacakan yang diperlukan untuk jenis yang dapat dilacak tersebut guna menghemat resource sistem.

Penggunaan yang Valid (Implisit)

Keamanan Thread

  • Akses ke trackableTracker, dan setiap nama sebutan turunan, harus disinkronkan secara eksternal

Kode Status

Berhasil

  • XR_SUCCESS

Kegagalan

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_HANDLE_INVALID

Mendapatkan semua item yang dapat dilacak

Atom XrTrackableANDROID ditentukan sebagai:

XR_DEFINE_ATOM(XrTrackableANDROID)

XrTrackableANDROID digunakan untuk mewakili satu objek yang dapat dilacak dan hanya valid dalam siklus proses XrTrackableTrackerANDROID terkait.

Fungsi xrGetAllTrackablesANDROID ditentukan sebagai:

XrResult xrGetAllTrackablesANDROID(
    XrTrackableTrackerANDROID                   trackableTracker,
    uint32_t                                    trackableCapacityInput,
    uint32_t*                                   trackableCountOutput,
    XrTrackableANDROID*                         trackables);

Deskripsi Parameter

  • trackableTracker adalah XrTrackableTrackerANDROID yang akan dikueri.

  • trackableCapacityInput adalah kapasitas array trackables, atau 0 untuk menunjukkan permintaan guna mengambil kapasitas yang diperlukan.

  • trackableCountOutput adalah pointer ke jumlah trackables yang ditulis, atau pointer ke kapasitas yang diperlukan jika trackables tidak memadai.

  • trackables adalah pointer ke array XrTrackableANDROID. Nilainya dapat berupa NULL jika trackableCapacityInput adalah 0.

  • Lihat bagian Parameter Ukuran Buffer untuk mengetahui penjelasan mendetail tentang pengambilan ukuran trackables yang diperlukan.

xrGetAllTrackablesANDROID mengisi array XrTrackableANDROID yang mewakili trackable yang ditemukan di lingkungan. XrTrackableTypeANDROID dari trackables yang ditampilkan harus cocok dengan XrTrackableTypeANDROID dari trackableTracker.

Mendapatkan pesawat yang dapat dilacak

Fungsi xrGetTrackablePlaneANDROID ditentukan sebagai:

XrResult xrGetTrackablePlaneANDROID(
    XrTrackableTrackerANDROID                   trackableTracker,
    const XrTrackableGetInfoANDROID*            getInfo,
    XrTrackablePlaneANDROID*                    planeOutput);

Deskripsi Parameter

Fungsi xrGetTrackablePlaneANDROID menampilkan detail tentang bidang yang dapat dilacak, seperti geometri, orientasi, dan status pelacakannya.

Informasi bidang di-resolve dan relatif terhadap ruang dasar pada saat panggilan ke xrGetTrackablePlaneANDROID menggunakan XrTrackableGetInfoANDROID::time, XrTrackableGetInfoANDROID::baseSpace.

Penggunaan yang Valid (Implisit)

Kode Status

Berhasil

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

Kegagalan

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_TIME_INVALID

Struktur XrTrackableGetInfoANDROID ditentukan sebagai:

typedef struct XrTrackableGetInfoANDROID {
    XrStructureType       type;
    void*                 next;
    XrTrackableANDROID    trackable;
    XrSpace               baseSpace;
    XrTime                time;
} XrTrackableGetInfoANDROID;

Deskripsi Anggota

  • type adalah XrStructureType dari struktur ini.
  • next adalah NULL atau pointer ke struktur berikutnya dalam rantai struktur. Tidak ada struktur semacam itu yang ditentukan di OpenXR inti atau ekstensi ini.
  • trackable adalah bidang XrTrackableANDROID yang akan dikueri.
  • baseSpace pose bidang akan relatif terhadap XrSpace ini di time.
  • time adalah XrTime tempat mengevaluasi koordinat secara relatif terhadap baseSpace.

Struktur XrTrackableGetInfoANDROID menyediakan opsi kueri saat diteruskan ke xrGetTrackablePlaneANDROID. trackable harus sesuai dengan trackableTracker yang digunakan dalam xrGetTrackablePlaneANDROID.

XR_ERROR_MISMATCHING_TRACKABLE_TYPE_ANDROID akan ditampilkan jika jenis trackable yang dapat dilacak bukan XR_TRACKABLE_TYPE_PLANE_ANDROID.

Penggunaan yang Valid (Implisit)

Struktur XrTrackablePlaneANDROID ditentukan sebagai:

typedef struct XrTrackablePlaneANDROID {
    XrStructureType           type;
    void*                     next;
    XrTrackingStateANDROID    trackingState;
    XrPosef                   centerPose;
    XrExtent2Df               extents;
    XrPlaneTypeANDROID        planeType;
    XrPlaneLabelANDROID       planeLabel;
    XrTrackableANDROID        subsumedByPlane;
    XrTime                    lastUpdatedTime;
    uint32_t                  vertexCapacityInput;
    uint32_t*                 vertexCountOutput;
    XrVector2f*               vertices;
} XrTrackablePlaneANDROID;

Deskripsi Anggota

  • type adalah XrStructureType dari struktur ini.
  • next adalah NULL atau pointer ke struktur berikutnya dalam rantai struktur. Tidak ada struktur semacam itu yang ditentukan di OpenXR inti atau ekstensi ini.
  • trackingState adalah XrTrackingStateANDROID dari bidang.
  • centerPose adalah XrPosef yang menentukan posisi dan orientasi bidang dalam frame referensi XrTrackableGetInfoANDROID::baseSpace yang sesuai. Orientasi identitas di sini mewakili sumbu koordinat dengan +Y sejajar dengan normal bidang.
  • extents adalah dimensi XrExtent2Df bidang.
  • planeType adalah XrPlaneTypeANDROID yang telah ditentukan runtime untuk bidang ini.
  • planeLabel adalah XrPlaneLabelANDROID yang telah ditentukan runtime untuk bidang ini.
  • subsumedByPlane adalah XrTrackableANDROID bidang yang menyerap bidang ini (XR_NULL_TRACKABLE_ANDROID jika tidak ada).
  • lastUpdatedTime adalah XrTime dari update terakhir bidang.
  • vertexCapacityInput adalah kapasitas array vertices, atau 0 untuk menunjukkan permintaan guna mengambil kapasitas yang diperlukan.
  • vertexCountOutput adalah pointer ke jumlah vertices yang ditulis, atau pointer ke kapasitas yang diperlukan jika vertices tidak memadai.
  • vertices adalah pointer ke array XrVector2f. Nilai ini dapat berupa NULL jika vertexCapacityInput adalah 0. Verteks berada dalam urutan berlawanan arah jarum jam. Poligon dapat cekung dan tidak boleh bersimpangan sendiri.
  • Lihat bagian Parameter Ukuran Buffer untuk mengetahui penjelasan mendetail tentang pengambilan ukuran vertices yang diperlukan.

Penggunaan yang Valid (Implisit)

Enum XrTrackingStateANDROID menjelaskan status pelacakan XrTrackableANDROID.

typedef enum XrTrackingStateANDROID {
    XR_TRACKING_STATE_PAUSED_ANDROID = 0,
    XR_TRACKING_STATE_STOPPED_ANDROID = 1,
    XR_TRACKING_STATE_TRACKING_ANDROID = 2
} XrTrackingStateANDROID;

XrTrackingStateANDROID

Deskripsi

XR_TRACKING_STATE_PAUSED_ANDROID

Menunjukkan bahwa pelacakan anchor atau yang dapat dilacak dijeda, tetapi dapat dilanjutkan di masa mendatang.

XR_TRACKING_STATE_STOPPED_ANDROID

Pelacakan telah dihentikan pada Item yang Dapat Dilacak ini dan tidak akan pernah dilanjutkan.

XR_TRACKING_STATE_TRACKING_ANDROID

Objek dilacak dan posenya saat ini.

Enum XrPlaneTypeANDROID adalah jenis bidang XrTrackableANDROID.

typedef enum XrPlaneTypeANDROID {
    XR_PLANE_TYPE_HORIZONTAL_DOWNWARD_FACING_ANDROID = 0,
    XR_PLANE_TYPE_HORIZONTAL_UPWARD_FACING_ANDROID = 1,
    XR_PLANE_TYPE_VERTICAL_ANDROID = 2,
    XR_PLANE_TYPE_ARBITRARY_ANDROID = 3
} XrPlaneTypeANDROID;

Enum XrPlaneLabelANDROID adalah label untuk bidang XrTrackableANDROID.

typedef enum XrPlaneLabelANDROID {
    XR_PLANE_LABEL_UNKNOWN_ANDROID = 0,
    XR_PLANE_LABEL_WALL_ANDROID = 1,
    XR_PLANE_LABEL_FLOOR_ANDROID = 2,
    XR_PLANE_LABEL_CEILING_ANDROID = 3,
    XR_PLANE_LABEL_TABLE_ANDROID = 4
} XrPlaneLabelANDROID;

Membuat ruang anchor

XrResult xrCreateAnchorSpaceANDROID(
    XrSession                                   session,
    const XrAnchorSpaceCreateInfoANDROID*       createInfo,
    XrSpace*                                    anchorOutput);

Deskripsi Parameter

  • session adalah XrSession yang membuat ruang anchor.
  • createInfo adalah pointer ke struktur XrAnchorSpaceCreateInfoANDROID yang berisi parameter yang akan digunakan untuk membuat ruang anchor.
  • anchorOutput adalah pointer ke handle tempat XrSpace yang dibuat ditampilkan.

Pada waktu kapan pun, posisi dan arah anchor dilacak atau tidak dilacak. Artinya, XR_SPACE_LOCATION_POSITION_TRACKED_BIT dan XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT harus ditetapkan atau keduanya harus dihapus saat aplikasi memanggil xrLocateSpace atau xrLocateSpaces untuk anchorOutput.

Aplikasi harus pada akhirnya mengosongkan XrSpace yang ditampilkan menggunakan xrDestroySpace.

  • XR_ERROR_FEATURE_UNSUPPORTED harus ditampilkan jika sistem tidak mendukung anchor.
  • XR_ERROR_TRACKABLE_TYPE_NOT_SUPPORTED_ANDROID harus ditampilkan jika lampiran anchor tertentu tidak didukung.

Penggunaan yang Valid (Implisit)

Kode Status

Berhasil

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

Kegagalan

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_TRACKABLE_TYPE_NOT_SUPPORTED_ANDROID
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_POSE_INVALID
  • XR_ERROR_TIME_INVALID
  • XR_ERROR_OUT_OF_MEMORY

Struktur XrAnchorSpaceCreateInfoANDROID ditentukan sebagai:

typedef struct XrAnchorSpaceCreateInfoANDROID {
    XrStructureType       type;
    void*                 next;
    XrSpace               space;
    XrTime                time;
    XrPosef               pose;
    XrTrackableANDROID    trackable;
} XrAnchorSpaceCreateInfoANDROID;

Deskripsi Anggota

  • type adalah XrStructureType dari struktur ini.
  • next adalah NULL atau pointer ke struktur berikutnya dalam rantai struktur. Tidak ada struktur semacam itu yang ditentukan di OpenXR inti atau ekstensi ini.
  • space adalah XrSpace tempat anchor akan dibuat.
  • time adalah XrTime pembuatan anchor.
  • pose adalah XrPosef anchor.
  • trackable adalah XrTrackableANDROID tempat anchor akan dilampirkan. XR_NULL_TRACKABLE_ANDROID mungkin untuk membuat anchor spasial.

Penggunaan yang Valid (Implisit)

Contoh kode untuk mendapatkan semua item yang dapat dilacak

Kode contoh berikut menunjukkan cara mendapatkan semua objek pelacak dari jenis tertentu.

XrSession session; // previously initialized

// The function pointers are previously initialized using xrGetInstanceProcAddr.
PFN_xrCreateTrackableTrackerANDROID xrCreateTrackableTrackerANDROID; // previously initialized
PFN_xrGetAllTrackablesANDROID xrGetAllTrackablesANDROID; // previously initialized
PFN_xrDestroyTrackableTrackerANDROID xrDestroyTrackableTrackerANDROID; // previously initialized

XrTrackableTrackerCreateInfoANDROID createInfo{XR_TYPE_TRACKABLE_TRACKER_CREATE_INFO_ANDROID};
createInfo.trackableType = XR_TRACKABLE_TYPE_PLANE_ANDROID;
XrTrackableTrackerANDROID planeTrackableTracker;
XrResult result = xrCreateTrackableTrackerANDROID(
  session,
  &createInfo,
  &planeTrackableTracker);
if (result != XR_SUCCESS) { /* Handle failures. */ }

uint32_t trackableCountOutput = 0;
std::vector<XrTrackableANDROID> allPlaneTrackables;

// Query the number of trackables available.
result = xrGetAllTrackablesANDROID(
  planeTrackableTracker,
  0,
  &trackableCountOutput,
  nullptr
);

if (result == XR_SUCCESS) {
  allPlaneTrackables.resize(trackableCountOutput, XR_NULL_HANDLE);

  // Fetch the actual trackable handles in the appropriately resized array.
  result = xrGetAllTrackablesANDROID(
    planeTrackableTracker,
    trackableCountOutput,
    &trackableCountOutput,
    allPlaneTrackables.data());

  if (result == XR_SUCCESS) {
    for (XrTrackableANDROID trackable : allPlaneTrackables) {
      // You now have all trackables of the specified type.
    }
  }
}

// Release trackable tracker.
result = xrDestroyTrackableTrackerANDROID(planeTrackableTracker);

Contoh kode untuk mendapatkan bidang yang dapat dilacak

Kode contoh berikut menunjukkan cara mendapatkan bidang yang dapat dilacak dari XrTrackableANDROID yang ada, yang diperoleh dari hasil hit XR_ANDROID_raycast atau xrGetTrackablesANDROID.

XrTrackableTrackerANDROID planeTracker; // previously created

// The function pointers are previously initialized using xrGetInstanceProcAddr.
PFN_xrGetTrackablePlaneANDROID xrGetTrackablePlaneANDROID; // previously initialized

XrTime updateTime; // Time used for the current frame's simulation update.
XrSpace appSpace; // Space created for XR_REFERENCE_SPACE_TYPE_LOCAL.
XrTrackableANDROID planeTrackable; // Acquired from a hit result or getTrackables().

XrTrackableGetInfoANDROID planeGetInfo;
planeGetInfo.type = XR_TYPE_TRACKABLE_GET_INFO_ANDROID;
planeGetInfo.next = nullptr;
planeGetInfo.trackable = planeTrackable;
planeGetInfo.space = appSpace;
planeGetInfo.time = updateTime;

XrTrackablePlaneANDROID plane = { XR_TYPE_TRACKABLE_PLANE_ANDROID };
result = xrGetTrackablePlaneANDROID(
  planeTracker,
  &planeGetInfo,
  &plane
);

if (result == XR_SUCCESS) {
  // Plane tracking state, center pose, extents, type now available in plane.
}

Contoh kode untuk membuat ruang anchor

Contoh kode berikut menunjukkan cara membuat ruang anchor yang dilampirkan ke objek yang dapat dilacak.

XrSession session; // Created at app startup.
XrTime updateTime; // Time used for the current frame's simulation update.
XrSpace appSpace; // Space created for XR_REFERENCE_SPACE_TYPE_LOCAL.
XrTrackableANDROID planeTrackable; // Acquired from a hit result or getTrackables().

// Create an anchor at (2, 2, 2) world-coordinates.
XrAnchorSpaceCreateInfoANDROID spatialAnchorCreateInfo;
spatialAnchorCreateInfo.type = XR_TYPE_ANCHOR_SPACE_CREATE_INFO_ANDROID;
spatialAnchorCreateInfo.next = nullptr;
spatialAnchorCreateInfo.space = appSpace;
spatialAnchorCreateInfo.time = updateTime;
spatialAnchorCreateInfo.pose = { { 0, 0, 0, 1 }, { 2, 2, 2 } };

XrSpace spatialAnchor = XR_NULL_HANDLE;
XrResult result = xrCreateAnchorSpaceANDROID(
  session,
  &spatialAnchorCreateInfo,
  &spatialAnchor
);

// Create an anchor attached to a trackable.
XrTrackablePlane plane = ...;
XrAnchorSpaceCreateInfoANDROID trackableAnchorCreateInfo;
trackableAnchorCreateInfo.type = XR_TYPE_ANCHOR_SPACE_CREATE_INFO_ANDROID;
trackableAnchorCreateInfo.next = nullptr;
trackableAnchorCreateInfo.space = appState;
trackableAnchorCreateInfo.pose = plane.centerPose;
trackableAnchorCreateInfo.trackable = planeTrackable;

XrSpace trackableAnchor = XR_NULL_HANDLE;
XrResult result = xrCreateAnchorSpaceANDROID(
  session,
  &trackableAnchorCreateInfo,
  &trackableAnchor
);
while (true) {
  // app update loop
  // ...

  // Get the current location of the anchor's space w.r.t the world.
  XrSpaceLocation anchorLocation = { XR_TYPE_SPACE_LOCATION };
  result = xrLocateSpace(trackableAnchor, appSpace, updateTime, &anchorLocation);

  if (anchor.trackingState == XR_TRACKING_STATE_TRACKING_ANDROID) {
    // Update anchor pose.
    doDrawingForAnchor(anchorLocation.pose);
  } else {
    // ...
  }
}

// Cleanup - destroy the space, detatch the anchor so its no longer tracked by the
// runtime and then release all resources held by it.
xrDestroySpace(spatialAnchor);
xrDestroySpace(trackableAnchor);

Jenis Dasar Baru

Jenis Objek Baru

Konstanta Enum Baru

Enumerasi XrStructureType diperluas dengan:

  • XR_TYPE_TRACKABLE_GET_INFO_ANDROID
  • XR_TYPE_ANCHOR_SPACE_CREATE_INFO_ANDROID
  • XR_TYPE_TRACKABLE_PLANE_ANDROID
  • XR_TYPE_TRACKABLE_TRACKER_CREATE_INFO_ANDROID

Enumerasi XrObjectType diperluas dengan:

  • XR_OBJECT_TYPE_TRACKABLE_TRACKER_ANDROID

Enumerasi XrResult diperluas dengan:

  • XR_ERROR_MISMATCHING_TRACKABLE_TYPE_ANDROID
  • XR_ERROR_TRACKABLE_TYPE_NOT_SUPPORTED_ANDROID

Enum Baru

Struktur Baru

Fungsi Baru

Masalah

Histori Versi

  • Revisi 1, 27-09-2024 (Kenny Vercaemer)
    • Deskripsi ekstensi awal.