2020-08-11 12:07:21 -04:00
# include "asset.hpp"
# include <map>
# include <array>
# include <stb_image.h>
# include "log.hpp"
# include "engine.hpp"
# include "gfx.hpp"
# include "json_conversions.hpp"
# include "gfx_commandbuffer.hpp"
# include "assertions.hpp"
2020-09-21 09:37:52 -04:00
# include "renderer.hpp"
# include "input.hpp"
# include "physics.hpp"
2021-04-20 10:37:56 -04:00
# include "imgui_backend.hpp"
2020-08-11 12:07:21 -04:00
2021-05-12 09:05:56 -04:00
std : : unique_ptr < Mesh > load_mesh ( const prism : : path path ) {
2020-08-11 12:07:21 -04:00
Expects ( ! path . empty ( ) ) ;
2021-05-12 08:50:02 -04:00
auto file = prism : : open_file ( path , true ) ;
2020-08-11 12:07:21 -04:00
if ( ! file . has_value ( ) ) {
2021-09-13 23:41:54 -04:00
prism : : log ( " Failed to load mesh from {}! " , path . string ( ) ) ;
2020-08-11 12:07:21 -04:00
return nullptr ;
}
int version = 0 ;
file - > read ( & version ) ;
2022-02-03 10:49:02 -05:00
if ( version = = 5 | | version = = 6 | | version = = 7 ) {
2020-08-11 12:07:21 -04:00
} else {
2021-09-13 23:41:54 -04:00
prism : : log ( " {} failed the mesh version check! reported version = {} " , path . string ( ) , version ) ;
2020-08-11 12:07:21 -04:00
return nullptr ;
}
auto mesh = std : : make_unique < Mesh > ( ) ;
2020-08-13 07:48:50 -04:00
mesh - > path = path . string ( ) ;
2020-08-11 12:07:21 -04:00
enum MeshType : int {
Static ,
Skinned
} mesh_type ;
file - > read ( & mesh_type ) ;
// TODO: use unsigned int here
int numVertices = 0 ;
file - > read ( & numVertices ) ;
Expects ( numVertices > 0 ) ;
const auto read_buffer = [ & f = file . value ( ) , numVertices ] ( unsigned int size ) - > GFXBuffer * {
auto buffer = engine - > get_gfx ( ) - > create_buffer ( nullptr , size * static_cast < unsigned int > ( numVertices ) , false , GFXBufferUsage : : Vertex ) ;
2022-02-03 10:49:02 -05:00
auto buffer_ptr = reinterpret_cast < unsigned char * > ( engine - > get_gfx ( ) - > get_buffer_contents ( buffer ) ) ;
2020-08-11 12:07:21 -04:00
f . read ( buffer_ptr , size * static_cast < unsigned int > ( numVertices ) ) ;
engine - > get_gfx ( ) - > release_buffer_contents ( buffer , buffer_ptr ) ;
return buffer ;
} ;
// read positions
2021-05-12 09:56:44 -04:00
mesh - > position_buffer = read_buffer ( sizeof ( prism : : float3 ) ) ;
mesh - > normal_buffer = read_buffer ( sizeof ( prism : : float3 ) ) ;
mesh - > texture_coord_buffer = read_buffer ( sizeof ( prism : : float2 ) ) ;
mesh - > tangent_buffer = read_buffer ( sizeof ( prism : : float3 ) ) ;
mesh - > bitangent_buffer = read_buffer ( sizeof ( prism : : float3 ) ) ;
2020-08-11 12:07:21 -04:00
if ( mesh_type = = MeshType : : Skinned )
mesh - > bone_buffer = read_buffer ( sizeof ( BoneVertexData ) ) ;
int numIndices = 0 ;
file - > read ( & numIndices ) ;
Expects ( numIndices > 0 ) ;
mesh - > index_buffer = engine - > get_gfx ( ) - > create_buffer ( nullptr , sizeof ( uint32_t ) * numIndices , false , GFXBufferUsage : : Index ) ;
auto index_ptr = reinterpret_cast < uint32_t * > ( engine - > get_gfx ( ) - > get_buffer_contents ( mesh - > index_buffer ) ) ;
file - > read ( index_ptr , sizeof ( uint32_t ) * numIndices ) ;
engine - > get_gfx ( ) - > release_buffer_contents ( mesh - > index_buffer , index_ptr ) ;
int bone_len = 0 ;
file - > read ( & bone_len ) ;
mesh - > bones . reserve ( bone_len ) ;
if ( bone_len > 0 ) {
file - > read ( & mesh - > global_inverse_transformation ) ;
std : : map < std : : string , uint32_t > boneMapping ;
std : : map < int , std : : string > parentQueue ;
for ( int v = 0 ; v < bone_len ; v + + ) {
std : : string bone , parent ;
file - > read_string ( bone ) ;
file - > read_string ( parent ) ;
2021-05-12 09:56:44 -04:00
prism : : float3 pos ;
2020-08-11 12:07:21 -04:00
file - > read ( & pos ) ;
Quaternion rot ;
file - > read ( & rot ) ;
2021-05-12 09:56:44 -04:00
prism : : float3 scl ;
2020-08-11 12:07:21 -04:00
file - > read ( & scl ) ;
2021-02-18 08:31:36 -05:00
if ( ! boneMapping . count ( bone ) ) {
2020-08-11 12:07:21 -04:00
Bone b ;
b . index = mesh - > bones . size ( ) ;
b . name = bone ;
b . name = bone ;
b . position = pos ;
b . rotation = rot ;
b . scale = scl ;
if ( parent ! = " none " & & ! parent . empty ( ) )
parentQueue [ b . index ] = parent ;
mesh - > bones . push_back ( b ) ;
boneMapping [ bone ] = b . index ;
}
}
for ( auto & [ index , parentName ] : parentQueue ) {
for ( auto & bone : mesh - > bones ) {
if ( bone . name = = parentName )
mesh - > bones [ index ] . parent = & bone ;
}
}
for ( auto & bone : mesh - > bones ) {
if ( bone . parent = = nullptr )
mesh - > root_bone = & bone ;
}
}
int numMeshes = 0 ;
file - > read ( & numMeshes ) ;
Expects ( numMeshes > 0 ) ;
mesh - > parts . resize ( numMeshes ) ;
uint32_t vertexOffset = 0 , indexOffset = 0 ;
for ( int i = 0 ; i < numMeshes ; i + + ) {
auto & p = mesh - > parts [ i ] ;
p . vertex_offset = vertexOffset ;
p . index_offset = indexOffset ;
file - > read_string ( p . name ) ;
2022-02-03 10:49:02 -05:00
if ( version > = 6 ) {
2021-05-12 09:56:44 -04:00
file - > read ( & p . bounding_box ) ;
2020-08-11 12:07:21 -04:00
}
int numVerts = 0 ;
file - > read ( & numVerts ) ;
file - > read ( & p . index_count ) ;
int numBones = 0 ;
file - > read ( & numBones ) ;
p . bone_batrix_buffer = engine - > get_gfx ( ) - > create_buffer ( nullptr , sizeof ( Matrix4x4 ) * 128 , true , GFXBufferUsage : : Storage ) ;
if ( numBones > 0 ) {
p . offset_matrices . resize ( numBones ) ;
file - > read ( p . offset_matrices . data ( ) , sizeof ( Matrix4x4 ) * numBones ) ;
}
file - > read ( & p . material_override ) ;
2022-02-03 10:49:02 -05:00
if ( version = = 7 ) {
file - > read_string ( p . material_hint ) ;
}
2020-08-11 12:07:21 -04:00
vertexOffset + = numVerts ;
indexOffset + = p . index_count ;
}
mesh - > num_indices = static_cast < uint32_t > ( numIndices ) ;
return mesh ;
}
2021-05-12 09:05:56 -04:00
std : : unique_ptr < Texture > load_texture ( const prism : : path path ) {
2020-08-11 12:07:21 -04:00
Expects ( ! path . empty ( ) ) ;
2021-05-12 08:50:02 -04:00
auto file = prism : : open_file ( path , true ) ;
2020-08-11 12:07:21 -04:00
if ( ! file . has_value ( ) ) {
2021-09-13 23:41:54 -04:00
prism : : log ( " Failed to load texture from {}! " , path . string ( ) ) ;
2020-08-11 12:07:21 -04:00
return nullptr ;
}
2020-08-19 17:39:05 -04:00
// TODO: expose somehow??
const bool should_generate_mipmaps = true ;
2020-08-11 12:07:21 -04:00
file - > read_all ( ) ;
int width , height , channels ;
unsigned char * data = stbi_load_from_memory ( file - > cast_data < unsigned char > ( ) , file - > size ( ) , & width , & height , & channels , 4 ) ;
if ( ! data ) {
2021-09-13 23:41:54 -04:00
prism : : log ( " Failed to load texture from {}! " , path . string ( ) ) ;
2020-08-11 12:07:21 -04:00
return nullptr ;
}
Expects ( width > 0 ) ;
Expects ( height > 0 ) ;
auto texture = std : : make_unique < Texture > ( ) ;
2020-08-13 07:48:50 -04:00
texture - > path = path . string ( ) ;
2020-08-11 12:07:21 -04:00
texture - > width = width ;
texture - > height = height ;
GFXTextureCreateInfo createInfo = { } ;
2021-02-04 08:21:40 -05:00
createInfo . label = path . string ( ) ;
2020-08-11 12:07:21 -04:00
createInfo . width = width ;
createInfo . height = height ;
createInfo . format = GFXPixelFormat : : R8G8B8A8_UNORM ;
2022-02-07 09:57:54 -05:00
createInfo . usage = GFXTextureUsage : : Sampled | GFXTextureUsage : : TransferDst | GFXTextureUsage : : TransferSrc ; // src and dst are needed for copy tex data -> image and mipmap gen (from image data) respectively
2020-08-11 12:07:21 -04:00
if ( should_generate_mipmaps )
createInfo . mip_count = std : : floor ( std : : log2 ( std : : max ( width , height ) ) ) + 1 ;
texture - > handle = engine - > get_gfx ( ) - > create_texture ( createInfo ) ;
engine - > get_gfx ( ) - > copy_texture ( texture - > handle , data , width * height * 4 ) ;
if ( createInfo . mip_count > 1 ) {
GFXCommandBuffer * cmd_buf = engine - > get_gfx ( ) - > acquire_command_buffer ( ) ;
2020-08-17 09:54:55 -04:00
2020-08-11 12:07:21 -04:00
cmd_buf - > generate_mipmaps ( texture - > handle , createInfo . mip_count ) ;
engine - > get_gfx ( ) - > submit ( cmd_buf ) ;
}
stbi_image_free ( data ) ;
return texture ;
}
2021-05-12 09:05:56 -04:00
std : : unique_ptr < Material > load_material ( const prism : : path path ) {
2020-08-11 12:07:21 -04:00
Expects ( ! path . empty ( ) ) ;
2021-05-12 08:50:02 -04:00
auto file = prism : : open_file ( path ) ;
2020-08-11 12:07:21 -04:00
if ( ! file . has_value ( ) ) {
2021-09-13 23:41:54 -04:00
prism : : log ( " Failed to load material from {}! " , path . string ( ) ) ;
2020-08-11 12:07:21 -04:00
return { } ;
}
nlohmann : : json j ;
file - > read_as_stream ( ) > > j ;
auto mat = std : : make_unique < Material > ( ) ;
2020-08-13 07:48:50 -04:00
mat - > path = path . string ( ) ;
2020-08-11 12:07:21 -04:00
2022-02-03 10:00:59 -05:00
if ( ! j . count ( " version " ) | | j [ " version " ] ! = 3 ) {
2021-09-13 23:41:54 -04:00
prism : : log ( " Material {} failed the version check! " , path . string ( ) ) ;
2020-08-11 12:07:21 -04:00
return mat ;
}
2022-02-08 10:18:31 -05:00
const auto loadProperty = [ ] ( nlohmann : : json property ) - > MaterialProperty {
MaterialProperty p ;
p . value = property [ " value " ] ;
p . float_value = property [ " float_value " ] ;
p . type = property [ " type " ] ;
if ( ! property [ " asset_value " ] . get < std : : string > ( ) . empty ( ) ) {
p . value_tex = assetm - > get < Texture > ( prism : : app_domain / property [ " asset_value " ] . get < std : : string > ( ) ) ;
}
return p ;
} ;
mat - > colorProperty = loadProperty ( j [ " color " ] ) ;
if ( j . contains ( " normal " ) )
mat - > normalProperty = loadProperty ( j [ " normal " ] ) ;
2022-02-03 10:00:59 -05:00
2020-08-11 12:07:21 -04:00
return mat ;
}
2021-05-12 09:05:56 -04:00
void save_material ( Material * material , const prism : : path path ) {
2020-08-11 12:07:21 -04:00
Expects ( material ! = nullptr ) ;
Expects ( ! path . empty ( ) ) ;
nlohmann : : json j ;
2022-02-03 10:00:59 -05:00
j [ " version " ] = 3 ;
2020-08-11 12:07:21 -04:00
2022-02-08 10:18:31 -05:00
const auto save_property = [ ] ( MaterialProperty & property ) - > nlohmann : : json {
nlohmann : : json p ;
p [ " name " ] = property . name ;
p [ " value " ] = property . value ;
p [ " asset_value " ] = property . value_tex ? property . value_tex - > path : " " ;
p [ " float_value " ] = property . float_value ;
p [ " type " ] = property . type ;
return p ;
} ;
2022-02-03 10:00:59 -05:00
2022-02-08 10:18:31 -05:00
j [ " color " ] = save_property ( material - > colorProperty ) ;
j [ " normal " ] = save_property ( material - > normalProperty ) ;
2020-08-11 12:07:21 -04:00
2020-08-17 10:21:32 -04:00
std : : ofstream out ( path ) ;
2020-08-11 12:07:21 -04:00
out < < j ;
}