diff --git a/Makefile b/Makefile index cb52a23..6cc7f0e 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CC=$(PREFIX)gcc CXX=$(PREFIX)g++ -OPT = -O2 -march=x86-64-v3 +OPT = -O0 -march=x86-64-v3 CSTD = -std=gnu23 CXXSTD = -std=gnu++23 @@ -35,7 +35,11 @@ OBJS = \ src/collision_scene.o \ src/line_art.o \ src/boids.o \ - src/boids_scene.o + src/boids_scene.o \ + src/collada/scene.o \ + src/collada/effect.o \ + src/collada/node_state.o \ + data/scenes/ship20/ship20.o all: test.so diff --git a/data/scenes/ship20.cpp b/data/scenes/ship20.cpp new file mode 100644 index 0000000..9297e2f --- /dev/null +++ b/data/scenes/ship20.cpp @@ -0,0 +1,427 @@ +#include "collada/types.h" + +namespace ship20 { + + using namespace collada::types; + +light const light_environmentambientlight = { + .type = light_type::AMBIENT, + .color = { 0.0f, 0.0f, 0.0f }, +}; + +light const light_omni002_light = { + .type = light_type::POINT, + .color = { 1.0f, 1.0f, 1.0f }, +}; + +light const light_omni003_light = { + .type = light_type::POINT, + .color = { 1.0f, 1.0f, 1.0f }, +}; + +// shipple2_png +image const image_shipple2_png = { + .resource_name = "_0_SHIPPLE2_PNG", +}; + +image const * const images[] = { + &image_shipple2_png, +}; + +effect const effect_diffusetexture = { + .type = effect_type::BLINN, + .blinn = { + .emission = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .ambient = { + .type = color_or_texture_type::COLOR, + .color = {0.588f, 0.588f, 0.588f, 1.0f}, + }, + .diffuse = { + .type = color_or_texture_type::TEXTURE, + .texture = { .image_index = 0 }, // shipple2_png + }, + .specular = { + .type = color_or_texture_type::COLOR, + .color = {0.5f, 0.5f, 0.5f, 1.0f}, + }, + .shininess = 10.0f, + .reflective = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .reflectivity = 0.0f, + .transparent = { + .type = color_or_texture_type::COLOR, + .color = {1.0f, 1.0f, 1.0f, 1.0f}, + }, + .transparency = 1.0f, + .index_of_refraction = 0.0f, + } +}; + +effect const effect_cyanengine = { + .type = effect_type::BLINN, + .blinn = { + .emission = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.9647059f, 1.0f, 1.0f}, + }, + .ambient = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .diffuse = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .specular = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .shininess = 10.0f, + .reflective = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .reflectivity = 0.0f, + .transparent = { + .type = color_or_texture_type::COLOR, + .color = {1.0f, 1.0f, 1.0f, 1.0f}, + }, + .transparency = 1.0f, + .index_of_refraction = 0.0f, + } +}; + +effect const effect_emissivetexture = { + .type = effect_type::BLINN, + .blinn = { + .emission = { + .type = color_or_texture_type::TEXTURE, + .texture = { .image_index = 0 }, // shipple2_png + }, + .ambient = { + .type = color_or_texture_type::COLOR, + .color = {0.588f, 0.588f, 0.588f, 1.0f}, + }, + .diffuse = { + .type = color_or_texture_type::TEXTURE, + .texture = { .image_index = 0 }, // shipple2_png + }, + .specular = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .shininess = 10.0f, + .reflective = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .reflectivity = 0.0f, + .transparent = { + .type = color_or_texture_type::COLOR, + .color = {1.0f, 1.0f, 1.0f, 1.0f}, + }, + .transparency = 1.0f, + .index_of_refraction = 0.0f, + } +}; + +material const material_diffusetexture_material = { + .effect = &effect_diffusetexture, +}; + +material const material_cyanengine_material = { + .effect = &effect_cyanengine, +}; + +material const material_emissivetexture_material = { + .effect = &effect_emissivetexture, +}; + +input_element const input_elements_position_0_3_normal_0_3_texcoord_0_3[] = { + { + .semantic = "POSITION", + .semantic_index = 0, + .format = input_format::FLOAT3, + }, + { + .semantic = "NORMAL", + .semantic_index = 0, + .format = input_format::FLOAT3, + }, + { + .semantic = "TEXCOORD", + .semantic_index = 0, + .format = input_format::FLOAT3, + }, +}; + +triangles const triangles_geom_ship[] = { + { + .count = 2949, // triangles + .index_offset = 0, // indices + .inputs_index = 0, // index into inputs_list + }, + { + .count = 60, // triangles + .index_offset = 8847, // indices + .inputs_index = 0, // index into inputs_list + }, + { + .count = 239, // triangles + .index_offset = 9027, // indices + .inputs_index = 0, // index into inputs_list + }, +}; + +geometry const geometry_geom_ship = { + .mesh = { + .triangles = triangles_geom_ship, + .triangles_count = 3, + + .vertex_buffer_offset = 0, + .vertex_buffer_size = 133272, + + .index_buffer_offset = 0, + .index_buffer_size = 38976, + } +}; + +geometry const * const geometries[] = { + &geometry_geom_ship, +}; + +transform const transforms_node_environmentambientlight[] = { +}; + +instance_geometry const instance_geometries_node_environmentambientlight[] = { +}; + +instance_controller const instance_controllers_node_environmentambientlight[] = { +}; + +instance_light const instance_lights_node_environmentambientlight[] = { + { + .light = &light_environmentambientlight, + } +}; + +channel const * const node_channels_node_environmentambientlight[] = {}; + +node const node_node_environmentambientlight = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_environmentambientlight, + .transforms_count = 0, + + .instance_geometries = instance_geometries_node_environmentambientlight, + .instance_geometries_count = 0, + + .instance_controllers = instance_controllers_node_environmentambientlight, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_environmentambientlight, + .instance_lights_count = 1, + + .channels = node_channels_node_environmentambientlight, + .channels_count = 0, +}; + +transform const transforms_node_ship[] = { + { + .type = transform_type::ROTATE, + .rotate = {0.0f, 0.0f, 1.0f, -180.0f}, + }, +}; + +instance_material const instance_geometry_instance_materials_node_ship_0[] = { + { + .element_index = 1, // an index into mesh.triangles + .material = &material_cyanengine_material, + + .emission = { .input_set = -1 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = -1 }, + .specular = { .input_set = -1 }, + }, + { + .element_index = 0, // an index into mesh.triangles + .material = &material_diffusetexture_material, + + .emission = { .input_set = -1 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = 0 }, + .specular = { .input_set = -1 }, + }, + { + .element_index = 2, // an index into mesh.triangles + .material = &material_emissivetexture_material, + + .emission = { .input_set = 0 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = 0 }, + .specular = { .input_set = -1 }, + }, +}; + +instance_geometry const instance_geometries_node_ship[] = { + { + .geometry = &geometry_geom_ship, + + .instance_materials = instance_geometry_instance_materials_node_ship_0, + .instance_materials_count = 3, + }, +}; + +instance_controller const instance_controllers_node_ship[] = { +}; + +instance_light const instance_lights_node_ship[] = { +}; + +channel const * const node_channels_node_ship[] = { +}; + +node const node_node_ship = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_ship, + .transforms_count = 1, + + .instance_geometries = instance_geometries_node_ship, + .instance_geometries_count = 1, + + .instance_controllers = instance_controllers_node_ship, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_ship, + .instance_lights_count = 0, + + .channels = node_channels_node_ship, + .channels_count = 0, +}; + +transform const transforms_node_omni002[] = { + { + .type = transform_type::TRANSLATE, + .translate = {-286.5521f, 395.7583f, 161.5579f}, + }, +}; + +instance_geometry const instance_geometries_node_omni002[] = { +}; + +instance_controller const instance_controllers_node_omni002[] = { +}; + +instance_light const instance_lights_node_omni002[] = { + { + .light = &light_omni002_light, + } +}; + +channel const * const node_channels_node_omni002[] = { +}; + +node const node_node_omni002 = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_omni002, + .transforms_count = 1, + + .instance_geometries = instance_geometries_node_omni002, + .instance_geometries_count = 0, + + .instance_controllers = instance_controllers_node_omni002, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_omni002, + .instance_lights_count = 1, + + .channels = node_channels_node_omni002, + .channels_count = 0, +}; + +transform const transforms_node_omni003[] = { + { + .type = transform_type::TRANSLATE, + .translate = {333.2103f, -314.4593f, 161.5578f}, + }, +}; + +instance_geometry const instance_geometries_node_omni003[] = { +}; + +instance_controller const instance_controllers_node_omni003[] = { +}; + +instance_light const instance_lights_node_omni003[] = { + { + .light = &light_omni003_light, + } +}; + +channel const * const node_channels_node_omni003[] = { +}; + +node const node_node_omni003 = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_omni003, + .transforms_count = 1, + + .instance_geometries = instance_geometries_node_omni003, + .instance_geometries_count = 0, + + .instance_controllers = instance_controllers_node_omni003, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_omni003, + .instance_lights_count = 1, + + .channels = node_channels_node_omni003, + .channels_count = 0, +}; + +node const * const nodes[] = { + &node_node_environmentambientlight, // 0 + &node_node_ship, // 1 + &node_node_omni002, // 2 + &node_node_omni003, // 3 +}; + +inputs const inputs_list[] = { + { + .elements = input_elements_position_0_3_normal_0_3_texcoord_0_3, + .elements_count = 3, + }, +}; + +types::descriptor const descriptor = { + .nodes = nodes, + .nodes_count = (sizeof (nodes)) / (sizeof (nodes[0])), + + .inputs_list = inputs_list, + .inputs_list_count = (sizeof (inputs_list)) / (sizeof (inputs_list[0])), + + .images = images, + .images_count = (sizeof (images)) / (sizeof (images[0])), + + .position_normal_texture_buffer = "RES_SCENES_SHIP20_VTX", + .joint_weight_buffer = "RES_SCENES_SHIP20_VJW", + .index_buffer = "RES_SCENES_SHIP20_IDX", +}; + +} diff --git a/data/scenes/ship20/ship20.cpp b/data/scenes/ship20/ship20.cpp new file mode 100644 index 0000000..203f876 --- /dev/null +++ b/data/scenes/ship20/ship20.cpp @@ -0,0 +1,429 @@ +#include "collada/types.h" + +#include "data/scenes/ship20.h" + +namespace ship20 { + + using namespace collada::types; + +light const light_environmentambientlight = { + .type = light_type::AMBIENT, + .color = { 0.0f, 0.0f, 0.0f }, +}; + +light const light_omni002_light = { + .type = light_type::POINT, + .color = { 1.0f, 1.0f, 1.0f }, +}; + +light const light_omni003_light = { + .type = light_type::POINT, + .color = { 1.0f, 1.0f, 1.0f }, +}; + +// shipple2_png +image const image_shipple2_png = { + .resource_name = "_0_SHIPPLE2_PNG", +}; + +image const * const images[] = { + &image_shipple2_png, +}; + +effect const effect_diffusetexture = { + .type = effect_type::BLINN, + .blinn = { + .emission = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .ambient = { + .type = color_or_texture_type::COLOR, + .color = {0.588f, 0.588f, 0.588f, 1.0f}, + }, + .diffuse = { + .type = color_or_texture_type::TEXTURE, + .texture = { .image_index = 0 }, // shipple2_png + }, + .specular = { + .type = color_or_texture_type::COLOR, + .color = {0.5f, 0.5f, 0.5f, 1.0f}, + }, + .shininess = 10.0f, + .reflective = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .reflectivity = 0.0f, + .transparent = { + .type = color_or_texture_type::COLOR, + .color = {1.0f, 1.0f, 1.0f, 1.0f}, + }, + .transparency = 1.0f, + .index_of_refraction = 0.0f, + } +}; + +effect const effect_cyanengine = { + .type = effect_type::BLINN, + .blinn = { + .emission = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.9647059f, 1.0f, 1.0f}, + }, + .ambient = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .diffuse = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .specular = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .shininess = 10.0f, + .reflective = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .reflectivity = 0.0f, + .transparent = { + .type = color_or_texture_type::COLOR, + .color = {1.0f, 1.0f, 1.0f, 1.0f}, + }, + .transparency = 1.0f, + .index_of_refraction = 0.0f, + } +}; + +effect const effect_emissivetexture = { + .type = effect_type::BLINN, + .blinn = { + .emission = { + .type = color_or_texture_type::TEXTURE, + .texture = { .image_index = 0 }, // shipple2_png + }, + .ambient = { + .type = color_or_texture_type::COLOR, + .color = {0.588f, 0.588f, 0.588f, 1.0f}, + }, + .diffuse = { + .type = color_or_texture_type::TEXTURE, + .texture = { .image_index = 0 }, // shipple2_png + }, + .specular = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .shininess = 10.0f, + .reflective = { + .type = color_or_texture_type::COLOR, + .color = {0.0f, 0.0f, 0.0f, 1.0f}, + }, + .reflectivity = 0.0f, + .transparent = { + .type = color_or_texture_type::COLOR, + .color = {1.0f, 1.0f, 1.0f, 1.0f}, + }, + .transparency = 1.0f, + .index_of_refraction = 0.0f, + } +}; + +material const material_diffusetexture_material = { + .effect = &effect_diffusetexture, +}; + +material const material_cyanengine_material = { + .effect = &effect_cyanengine, +}; + +material const material_emissivetexture_material = { + .effect = &effect_emissivetexture, +}; + +input_element const input_elements_position_0_3_normal_0_3_texcoord_0_3[] = { + { + .semantic = "POSITION", + .semantic_index = 0, + .format = input_format::FLOAT3, + }, + { + .semantic = "NORMAL", + .semantic_index = 0, + .format = input_format::FLOAT3, + }, + { + .semantic = "TEXCOORD", + .semantic_index = 0, + .format = input_format::FLOAT3, + }, +}; + +triangles const triangles_geom_ship[] = { + { + .count = 2949, // triangles + .index_offset = 0, // indices + .inputs_index = 0, // index into inputs_list + }, + { + .count = 60, // triangles + .index_offset = 8847, // indices + .inputs_index = 0, // index into inputs_list + }, + { + .count = 239, // triangles + .index_offset = 9027, // indices + .inputs_index = 0, // index into inputs_list + }, +}; + +geometry const geometry_geom_ship = { + .mesh = { + .triangles = triangles_geom_ship, + .triangles_count = 3, + + .vertex_buffer_offset = 0, + .vertex_buffer_size = 133272, + + .index_buffer_offset = 0, + .index_buffer_size = 38976, + } +}; + +geometry const * const geometries[] = { + &geometry_geom_ship, +}; + +transform const transforms_node_environmentambientlight[] = { +}; + +instance_geometry const instance_geometries_node_environmentambientlight[] = { +}; + +instance_controller const instance_controllers_node_environmentambientlight[] = { +}; + +instance_light const instance_lights_node_environmentambientlight[] = { + { + .light = &light_environmentambientlight, + } +}; + +channel const * const node_channels_node_environmentambientlight[] = {}; + +node const node_node_environmentambientlight = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_environmentambientlight, + .transforms_count = 0, + + .instance_geometries = instance_geometries_node_environmentambientlight, + .instance_geometries_count = 0, + + .instance_controllers = instance_controllers_node_environmentambientlight, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_environmentambientlight, + .instance_lights_count = 1, + + .channels = node_channels_node_environmentambientlight, + .channels_count = 0, +}; + +transform const transforms_node_ship[] = { + { + .type = transform_type::ROTATE, + .rotate = {0.0f, 0.0f, 1.0f, -180.0f}, + }, +}; + +instance_material const instance_geometry_instance_materials_node_ship_0[] = { + { + .element_index = 1, // an index into mesh.triangles + .material = &material_cyanengine_material, + + .emission = { .input_set = -1 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = -1 }, + .specular = { .input_set = -1 }, + }, + { + .element_index = 0, // an index into mesh.triangles + .material = &material_diffusetexture_material, + + .emission = { .input_set = -1 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = 0 }, + .specular = { .input_set = -1 }, + }, + { + .element_index = 2, // an index into mesh.triangles + .material = &material_emissivetexture_material, + + .emission = { .input_set = 0 }, + .ambient = { .input_set = -1 }, + .diffuse = { .input_set = 0 }, + .specular = { .input_set = -1 }, + }, +}; + +instance_geometry const instance_geometries_node_ship[] = { + { + .geometry = &geometry_geom_ship, + + .instance_materials = instance_geometry_instance_materials_node_ship_0, + .instance_materials_count = 3, + }, +}; + +instance_controller const instance_controllers_node_ship[] = { +}; + +instance_light const instance_lights_node_ship[] = { +}; + +channel const * const node_channels_node_ship[] = { +}; + +node const node_node_ship = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_ship, + .transforms_count = 1, + + .instance_geometries = instance_geometries_node_ship, + .instance_geometries_count = 1, + + .instance_controllers = instance_controllers_node_ship, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_ship, + .instance_lights_count = 0, + + .channels = node_channels_node_ship, + .channels_count = 0, +}; + +transform const transforms_node_omni002[] = { + { + .type = transform_type::TRANSLATE, + .translate = {-286.5521f, 395.7583f, 161.5579f}, + }, +}; + +instance_geometry const instance_geometries_node_omni002[] = { +}; + +instance_controller const instance_controllers_node_omni002[] = { +}; + +instance_light const instance_lights_node_omni002[] = { + { + .light = &light_omni002_light, + } +}; + +channel const * const node_channels_node_omni002[] = { +}; + +node const node_node_omni002 = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_omni002, + .transforms_count = 1, + + .instance_geometries = instance_geometries_node_omni002, + .instance_geometries_count = 0, + + .instance_controllers = instance_controllers_node_omni002, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_omni002, + .instance_lights_count = 1, + + .channels = node_channels_node_omni002, + .channels_count = 0, +}; + +transform const transforms_node_omni003[] = { + { + .type = transform_type::TRANSLATE, + .translate = {333.2103f, -314.4593f, 161.5578f}, + }, +}; + +instance_geometry const instance_geometries_node_omni003[] = { +}; + +instance_controller const instance_controllers_node_omni003[] = { +}; + +instance_light const instance_lights_node_omni003[] = { + { + .light = &light_omni003_light, + } +}; + +channel const * const node_channels_node_omni003[] = { +}; + +node const node_node_omni003 = { + .parent_index = -1, + + .type = node_type::NODE, + + .transforms = transforms_node_omni003, + .transforms_count = 1, + + .instance_geometries = instance_geometries_node_omni003, + .instance_geometries_count = 0, + + .instance_controllers = instance_controllers_node_omni003, + .instance_controllers_count = 0, + + .instance_lights = instance_lights_node_omni003, + .instance_lights_count = 1, + + .channels = node_channels_node_omni003, + .channels_count = 0, +}; + +node const * const nodes[] = { + &node_node_environmentambientlight, // 0 + &node_node_ship, // 1 + &node_node_omni002, // 2 + &node_node_omni003, // 3 +}; + +inputs const inputs_list[] = { + { + .elements = input_elements_position_0_3_normal_0_3_texcoord_0_3, + .elements_count = 3, + }, +}; + +collada::types::descriptor const descriptor = { + .nodes = nodes, + .nodes_count = (sizeof (nodes)) / (sizeof (nodes[0])), + + .inputs_list = inputs_list, + .inputs_list_count = (sizeof (inputs_list)) / (sizeof (inputs_list[0])), + + .images = images, + .images_count = (sizeof (images)) / (sizeof (images[0])), + + .position_normal_texture_buffer = "data/scenes/ship20/ship20.vtx", + .joint_weight_buffer = "data/scenes/ship20/ship20.vjw", + .index_buffer = "data/scenes/ship20/ship20.idx", +}; + +} diff --git a/data/scenes/ship20/ship20.idx b/data/scenes/ship20/ship20.idx new file mode 100644 index 0000000..6077f25 Binary files /dev/null and b/data/scenes/ship20/ship20.idx differ diff --git a/data/scenes/ship20/ship20.vjw b/data/scenes/ship20/ship20.vjw new file mode 100644 index 0000000..e69de29 diff --git a/data/scenes/ship20/ship20.vtx b/data/scenes/ship20/ship20.vtx new file mode 100644 index 0000000..dfbf4bb Binary files /dev/null and b/data/scenes/ship20/ship20.vtx differ diff --git a/include/collada/effect.h b/include/collada/effect.h new file mode 100644 index 0000000..6f7b746 --- /dev/null +++ b/include/collada/effect.h @@ -0,0 +1,8 @@ +#pragma once + +namespace collada::effect { + extern unsigned int program_static; + extern unsigned int program_skinned; + + void load_effects(); +} diff --git a/include/collada/instance_types.h b/include/collada/instance_types.h new file mode 100644 index 0000000..a286154 --- /dev/null +++ b/include/collada/instance_types.h @@ -0,0 +1,28 @@ +#pragma once + +#include "directxmath/directxmath.h" + +#include "collada/types.h" + +namespace collada::instance_types { + + struct __attribute__((aligned(16))) lookat { + XMVECTOR eye; + XMVECTOR at; + XMVECTOR up; + }; + + struct __attribute__((aligned(16))) transform { + union { + instance_types::lookat lookat; + XMMATRIX matrix; + XMVECTOR vector; + }; + types::transform_type type; + }; + + struct node_instance { + transform * transforms = NULL; + XMMATRIX world; + }; +} diff --git a/include/collada/scene.h b/include/collada/scene.h new file mode 100644 index 0000000..9032a5d --- /dev/null +++ b/include/collada/scene.h @@ -0,0 +1,32 @@ +#pragma once + +#include "collada/types.h" + +namespace collada::scene { + struct static_skinned { + unsigned int static_mesh; + unsigned int skinned_mesh; + }; + + struct state { + types::descriptor const * descriptor; + + unsigned int vertex_buffer_pnt; + unsigned int vertex_buffer_jw; + unsigned int index_buffer; + + static_skinned * vertex_arrays; + int * vertex_buffer_strides; + + void load_layouts(); + void load_scene(types::descriptor const * const descriptor); + + void draw_geometry(types::geometry const & geometry, + types::instance_material const * const instance_materials, + int const instance_materials_count); + void draw_instance_geometries(types::instance_geometry const * const instance_geometries, + int const instance_geometries_count); + void draw_node(types::node const & node); + void draw(); + }; +} diff --git a/include/collada/types.h b/include/collada/types.h new file mode 100644 index 0000000..b7dff97 --- /dev/null +++ b/include/collada/types.h @@ -0,0 +1,407 @@ +#pragma once + +namespace collada::types { + + struct float2 { + float const x; + float const y; + }; + + struct float3 { + float const x; + float const y; + float const z; + }; + + struct float4 { + float const x; + float const y; + float const z; + float const w; + }; + + struct float7 { + float const a; + float const b; + float const c; + float const d; + float const e; + float const f; + float const g; + }; + + struct matrix { + float const _11, _12, _13, _14; + float const _21, _22, _23, _24; + float const _31, _32, _33, _34; + float const _41, _42, _43, _44; + }; + + ////////////////////////////////////////////////////////////////////// + // geometry + ////////////////////////////////////////////////////////////////////// + + enum class input_format { + FLOAT1, + FLOAT2, + FLOAT3, + FLOAT4, + INT1, + INT2, + INT3, + INT4, + }; + + struct input_element { + char const * const semantic; + int const semantic_index; + enum input_format const format; + }; + + // inputs uniqueness is by evaluted pointer + struct inputs { + input_element const * const elements; + int const elements_count; + }; + + struct triangles { + int const count; + int const index_offset; + int const inputs_index; + }; + + struct mesh { + // `triangles` must become a union if non-triangles are implemented. + // instance_geometry is an index into this array. + types::triangles const * triangles; + int const triangles_count; + + int const vertex_buffer_offset; + int const vertex_buffer_size; + + int const index_buffer_offset; + int const index_buffer_size; + }; + + struct geometry { + types::mesh mesh; + }; + + ////////////////////////////////////////////////////////////////////// + // light + ////////////////////////////////////////////////////////////////////// + + enum class light_type { + AMBIENT, + DIRECTIONAL, + POINT, + SPOT, + }; + + struct light { + light_type type; + float3 color; + }; + + ////////////////////////////////////////////////////////////////////// + // image + ////////////////////////////////////////////////////////////////////// + + struct image { + const char * resource_name; + }; + + ////////////////////////////////////////////////////////////////////// + // effect + ////////////////////////////////////////////////////////////////////// + + enum class color_or_texture_type { + COLOR, + TEXTURE, + }; + + struct texture { + int const image_index; // index in to images + }; + + struct color_or_texture { + color_or_texture_type type; + union { + float4 color; + types::texture texture; + }; + }; + + struct blinn { + color_or_texture const emission; + color_or_texture const ambient; + color_or_texture const diffuse; + color_or_texture const specular; + float const shininess; + color_or_texture const reflective; + float const reflectivity; + color_or_texture const transparent; + float const transparency; + float const index_of_refraction; + }; + + struct lambert { + color_or_texture const emission; + color_or_texture const ambient; + color_or_texture const diffuse; + color_or_texture const reflective; + float const reflectivity; + color_or_texture const transparent; + float const transparency; + float const index_of_refraction; + }; + + struct phong { + color_or_texture const emission; + color_or_texture const ambient; + color_or_texture const diffuse; + color_or_texture const specular; + float const shininess; + color_or_texture const reflective; + float const reflectivity; + color_or_texture const transparent; + float const transparency; + float const index_of_refraction; + }; + + struct constant { + float4 const color; + color_or_texture const reflective; + float const reflectivity; + color_or_texture const transparent; + float const transparency; + float const index_of_refraction; + }; + + enum class effect_type { + BLINN, + LAMBERT, + PHONG, + CONSTANT, + }; + + struct effect { + effect_type const type; + union { + types::blinn const blinn; + types::lambert const lambert; + types::phong const phong; + types::constant const constant; + }; + }; + + ////////////////////////////////////////////////////////////////////// + // node + ////////////////////////////////////////////////////////////////////// + + struct lookat { + float3 const eye; + float3 const at; + float3 const up; + }; + + enum class transform_type { + LOOKAT, + MATRIX, + ROTATE, + SCALE, + SKEW, + TRANSLATE, + }; + + struct transform { + transform_type const type; + union { + types::lookat const lookat; + types::matrix const matrix; + float4 const rotate; + float3 const scale; + float7 const skew; + float3 const translate; + }; + }; + + enum class node_type { + JOINT, + NODE, + }; + + struct material { + types::effect const * const effect; + }; + + struct bind_vertex_input { + int input_set; // TEXCOORD semantic input slot + }; + + struct instance_material { + int const element_index; // an index into mesh.triangles + types::material const * const material; + + // heavily simplified from collada data model + bind_vertex_input const emission; + bind_vertex_input const ambient; + bind_vertex_input const diffuse; + bind_vertex_input const specular; + }; + + struct instance_geometry { + types::geometry const * const geometry; + + instance_material const * const instance_materials; + int const instance_materials_count; + }; + + struct skin { + types::geometry const * const geometry; // source + + matrix const * const inverse_bind_matrices; // one per joint + + int const vertex_buffer_offset; + int const vertex_buffer_size; + }; + + struct controller { + types::skin skin; + }; + + struct instance_controller { + types::controller const * const controller; + + //node const * const skeleton; // a reference to the root of the joint heirarchy + + int const * const joint_node_indices; // one per joint + int const joint_count; + + instance_material const * const instance_materials; + int const instance_materials_count; + }; + + struct instance_light { + types::light const * const light; + }; + + ////////////////////////////////////////////////////////////////////// + // animation + ////////////////////////////////////////////////////////////////////// + + enum class interpolation { + LINEAR, + BEZIER, + }; + + struct source { + union { + float const * const float_array; + enum interpolation const * const interpolation_array; + }; + int const count; + int const stride; + }; + + struct sampler { + source const input; + source const output; + source const in_tangent; + source const out_tangent; + source const interpolation; + }; + + enum class target_attribute { + A, // alpha color component + ANGLE, // euler angle + B, // blue color component + G, // green color component + P, // third texture component + Q, // fourth texture component + R, // red color component + S, // first texture coordinate + T, // second texture coordinate + TIME, // time in seconds + U, // first generic parameter + V, // second generic parameter + W, // fourth cartesian coordinate + X, // first cartesian coordinate + Y, // second cartesian coordinate + Z, // third cartesian coordinate + ALL, + }; + + struct channel { + sampler const * const source_sampler; + int const target_node_index; // an index into the nodes array + int const target_transform_index; + types::target_attribute const target_attribute; + }; + + /* + struct animation { + animation const * const animations; // nested animations + int const animations_count; + + channels const * const channels; + int const channels_count; + }; + */ + + struct camera { + float xfov; + float yfov; + float znear; + float zfar; + float aspect_ratio; + }; + + ////////////////////////////////////////////////////////////////////// + // scene + ////////////////////////////////////////////////////////////////////// + + struct node { + int const parent_index; + + node_type const type; + + transform const * const transforms; + int const transforms_count; + + instance_geometry const * const instance_geometries; + int const instance_geometries_count; + + instance_controller const * const instance_controllers; + int const instance_controllers_count; + + instance_light const * const instance_lights; + int const instance_lights_count; + + channel const * const * const channels; + int const channels_count; + + //node const * const * const nodes; + //int const nodes_count; + }; + + struct descriptor { + // these are only the top-level nodes; nodes may have children + node const * const * const nodes; + int const nodes_count; + + inputs const * const inputs_list; + int const inputs_list_count; + + image const * const * const images; + int const images_count; + + //animation const * const animations; + //int const animations_count; + + // hmm, this part is not really platform-agnostic: + char const * const position_normal_texture_buffer; + char const * const joint_weight_buffer; + char const * const index_buffer; + }; +} diff --git a/include/collada_scene/ship20.h b/include/collada_scene/ship20.h new file mode 100644 index 0000000..62870dc --- /dev/null +++ b/include/collada_scene/ship20.h @@ -0,0 +1,7 @@ +#pragma once + +#include "collada/types.h" + +namespace collada_scene::ship20 { + extern collada::types::descriptor const descriptor; +} diff --git a/include/data/scenes/ship20.h b/include/data/scenes/ship20.h new file mode 100644 index 0000000..bf1e416 --- /dev/null +++ b/include/data/scenes/ship20.h @@ -0,0 +1,3 @@ +namespace ship20 { + extern collada::types::descriptor const descriptor; +} diff --git a/include/new.h b/include/new.h new file mode 100644 index 0000000..b1a73dd --- /dev/null +++ b/include/new.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +template +T * New(int elements) +{ + return (T *)aligned_alloc(16, (sizeof (T)) * elements); +} diff --git a/shader/collada/generic.frag b/shader/collada/generic.frag new file mode 100644 index 0000000..8040155 --- /dev/null +++ b/shader/collada/generic.frag @@ -0,0 +1,8 @@ +#version 430 core + +out vec4 Color; + +void main() +{ + Color = vec4(1, 0, 0, 1); +} diff --git a/shader/collada/static.vert b/shader/collada/static.vert new file mode 100644 index 0000000..952d348 --- /dev/null +++ b/shader/collada/static.vert @@ -0,0 +1,12 @@ +#version 430 core + +layout (location = 0) in vec3 Position; +layout (location = 1) in vec3 Normal; +layout (location = 2) in vec3 Texture; + +layout (location = 0) uniform mat4 Transform; + +void main() +{ + gl_Position = Transform * vec4(Position, 1); +} diff --git a/src/collada/animate.cpp b/src/collada/animate.cpp new file mode 100644 index 0000000..37ec7d8 --- /dev/null +++ b/src/collada/animate.cpp @@ -0,0 +1,205 @@ + static inline float fract(float f) + { + return f - floorf(f); + } + + static inline float loop(float f, float n) + { + return fract(f / n) * n; + } + + static inline int find_frame_ix(source const& source, float t) + { + for (int i = 0; i < source.count - 1; i++) { + if (source.float_array[i] <= t && source.float_array[i+1] > t) { + return i; + } + } + return -1; + } + + static inline float linear_interpolate_iv(source const& source, int frame_ix, float t) + { + float prev = source.float_array[(frame_ix+0) * source.stride]; + float next = source.float_array[(frame_ix+1) * source.stride]; + return (t - prev) / (next - prev); + } + + static inline float linear_interpolate_value(source const& source, int frame_ix, int parameter_ix, float iv) + { + float prev = source.float_array[(frame_ix+0) * source.stride + parameter_ix]; + float next = source.float_array[(frame_ix+1) * source.stride + parameter_ix]; + return prev + iv * (next - prev); + } + + static inline float pow3(float f) + { + return f * f * f; + } + + static inline float pow2(float f) + { + return f * f; + } + + static inline XMVECTOR bezier(XMVECTOR p0, XMVECTOR c0, XMVECTOR c1, XMVECTOR p1, float s) + { + return + p0 * pow3(1 - s) + + 3 * c0 * s * pow2(1 - s) + + 3 * c1 * pow2(s) * (1 - s) + + p1 * pow3(s); + } + + static inline float bezier_binary_search(XMVECTOR p0, XMVECTOR c0, XMVECTOR c1, XMVECTOR p1, float want) + { + float low = 0.0f; + float high = 1.0f; + + int iterations = 0; + while (iterations < 20) { + iterations += 1; + + float s = (high + low) * 0.5f; + XMVECTOR bs = bezier(p0, c0, c1, p1, s); + float t = XMVectorGetX(bs); + + const float epsilon = 0.001f; + if (fabsf(t - want) < epsilon) { + return XMVectorGetY(bs); + } + + if (t > want) { + high = s; + } else { + low = s; + } + } + + print("%f %f\n", XMVectorGetX(p0), XMVectorGetY(p0)); + print("%f %f\n", XMVectorGetX(c0), XMVectorGetY(c0)); + print("%f %f\n", XMVectorGetX(c1), XMVectorGetY(c1)); + print("%f %f\n", XMVectorGetX(p1), XMVectorGetY(p1)); + assert(false); + } + + static inline XMFLOAT2 const * tangent_index(source const& source, int frame_ix, int parameter_ix) + { + int ix = frame_ix * source.stride + parameter_ix * 2; + return (XMFLOAT2 const *)&source.float_array[ix]; + } + + static float bezier_sampler(sampler const * const sampler, int frame_ix, int parameter_ix, float t) + { + /* + P0 is (INPUT[i] , OUTPUT[i]) + C0 (or T0) is (OUT_TANGENT[i][0] , OUT_TANGENT[i][1]) + C1 (or T1) is (IN_TANGENT[i+1][0], IN_TANGENT[i+1][1]) + P1 is (INPUT[i+1], OUTPUT[i+1]) + */ + + float frame0_input = sampler->input.float_array[frame_ix+0]; + float frame1_input = sampler->input.float_array[frame_ix+1]; + + float frame0_output = sampler->output.float_array[(frame_ix+0) * sampler->output.stride + parameter_ix]; + float frame1_output = sampler->output.float_array[(frame_ix+1) * sampler->output.stride + parameter_ix]; + + XMVECTOR p0 = XMVectorSet(frame0_input, frame0_output, 0, 0); + XMVECTOR c0 = XMLoadFloat2(tangent_index(sampler->out_tangent, frame_ix + 0, parameter_ix)); + XMVECTOR c1 = XMLoadFloat2(tangent_index(sampler->in_tangent, frame_ix + 1, parameter_ix)); + XMVECTOR p1 = XMVectorSet(frame1_input, frame1_output, 0, 0); + + return bezier_binary_search(p0, c0, c1, p1, t); + } + + static void apply_transform_target(transform& transform, + enum target_attribute channel_target_attribute, + float value) + { + switch (transform.type) { + case transform_type::TRANSLATE: __attribute__((fallthrough)); + case transform_type::SCALE: + switch (channel_target_attribute) { + case target_attribute::X: transform.vector = XMVectorSetX(transform.vector, value); return; + case target_attribute::Y: transform.vector = XMVectorSetY(transform.vector, value); return; + case target_attribute::Z: transform.vector = XMVectorSetZ(transform.vector, value); return; + default: assert(false); + } + case transform_type::ROTATE: + switch (channel_target_attribute) { + case target_attribute::X: transform.vector = XMVectorSetX(transform.vector, value); return; + case target_attribute::Y: transform.vector = XMVectorSetY(transform.vector, value); return; + case target_attribute::Z: transform.vector = XMVectorSetZ(transform.vector, value); return; + case target_attribute::ANGLE: transform.vector = XMVectorSetW(transform.vector, value); return; + default: assert(false); + } + default: + assert(false); + break; + } + } + + static enum target_attribute const rotate_target_attributes[] = { + target_attribute::X, + target_attribute::Y, + target_attribute::Z, + target_attribute::ANGLE, + }; + + static enum target_attribute const translate_scale_target_attributes[] = { + target_attribute::X, + target_attribute::Y, + target_attribute::Z, + }; + + static void animate_channel_segment(channel const& channel, + transform& transform, + int frame_ix, float t) + { + enum target_attribute const * target_attributes = &channel.target_attribute; + int target_attributes_count = 1; + if (channel.target_attribute == target_attribute::ALL) { + switch (transform.type) { + case transform_type::TRANSLATE: __attribute__((fallthrough)); + case transform_type::SCALE: + target_attributes = translate_scale_target_attributes; + target_attributes_count = 3; + break; + case transform_type::ROTATE: + target_attributes = rotate_target_attributes; + target_attributes_count = 4; + break; + default: + assert(false); + break; + } + } + + for (int parameter_ix = 0; parameter_ix < target_attributes_count; parameter_ix++) { + + enum collada::interpolation interpolation = channel.source_sampler->interpolation.interpolation_array[frame_ix]; + + float value; + if (interpolation == interpolation::BEZIER) { + value = bezier_sampler(channel.source_sampler, frame_ix, parameter_ix, t); + } else { + float iv = linear_interpolate_iv(channel.source_sampler->input, frame_ix, t); + value = linear_interpolate_value(channel.source_sampler->output, frame_ix, parameter_ix, iv); + } + + apply_transform_target(transform, target_attributes[parameter_ix], value); + } + } + + static void animate_node(node const& node, node_instance& node_instance, float t) + { + for (int i = 0; i < node.channels_count; i++) { + channel const& channel = *node.channels[i]; + transform& transform = node_instance.transforms[channel.target_transform_index]; + + int frame_ix = find_frame_ix(channel.source_sampler->input, t); + assert(frame_ix >= 0); // animation is missing a key frame + + animate_channel_segment(channel, transform, frame_ix, t); + } + } diff --git a/src/collada/effect.cpp b/src/collada/effect.cpp new file mode 100644 index 0000000..46d2572 --- /dev/null +++ b/src/collada/effect.cpp @@ -0,0 +1,16 @@ +#include "opengl.h" + +#include "collada/effect.h" + +namespace collada::effect { + + unsigned int program_static; + unsigned int program_skinned; + + void load_effects() + { + program_static = compile_from_files("shader/collada/static.vert", + nullptr, + "shader/collada/generic.frag"); + } +} diff --git a/src/collada/node_state.cpp b/src/collada/node_state.cpp new file mode 100644 index 0000000..b55fb1e --- /dev/null +++ b/src/collada/node_state.cpp @@ -0,0 +1,67 @@ +#include "directxmath/directxmath.h" + +#include "collada/types.h" +#include "collada/instance_types.h" + +namespace collada::node_state { + inline static void load_transform(instance_types::transform * instance_transform, + types::transform const & transform) + { + switch (transform.type) { + case types::transform_type::LOOKAT: + instance_transform->lookat.eye = XMLoadFloat3((XMFLOAT3 *)&transform.lookat.eye); + instance_transform->lookat.at = XMLoadFloat3((XMFLOAT3 *)&transform.lookat.at); + instance_transform->lookat.up = XMLoadFloat3((XMFLOAT3 *)&transform.lookat.up); + break; + case types::transform_type::MATRIX: + instance_transform->matrix = XMLoadFloat4x4((XMFLOAT4X4 *)&transform.matrix); + break; + case types::transform_type::ROTATE: + instance_transform->vector = XMLoadFloat4((XMFLOAT4 *)&transform.rotate); + break; + case types::transform_type::SCALE: + instance_transform->vector = XMLoadFloat3((XMFLOAT3*)&transform.scale); + break; + case types::transform_type::TRANSLATE: + instance_transform->vector = XMLoadFloat3((XMFLOAT3*)&transform.translate); + break; + default: + assert(false); + } + } + + void initialize_node_transforms(types::node const * const node, + instance_types::node_instance * const node_instance) + { + for (int i = 0; i < node->transforms_count; i++) { + load_transform(&node_instance->transforms[i], + node->transforms[i]); + } + } + + inline static bool vector_equal(XMVECTOR V1, XMVECTOR V2) + { + uint32_t CR; + XMVectorEqualR(&CR, V1, V2); + return XMComparisonAllTrue(CR); + } + + inline static XMMATRIX transform_matrix(instance_types::transform const& transform) + { + switch (transform.type) { + case types::transform_type::TRANSLATE: + return XMMatrixTranslationFromVector(transform.vector); + case types::transform_type::ROTATE: + assert(!vector_equal(XMVectorSetW(transform.vector, 0), XMVectorZero())); + return XMMatrixRotationNormal(transform.vector, + XMConvertToRadians(XMVectorGetW(transform.vector))); + case types::transform_type::SCALE: + return XMMatrixScalingFromVector(transform.vector); + case types::transform_type::MATRIX: + return transform.matrix; + default: + assert(false); + break; + } + } +} diff --git a/src/collada/scene.cpp b/src/collada/scene.cpp new file mode 100644 index 0000000..1c824aa --- /dev/null +++ b/src/collada/scene.cpp @@ -0,0 +1,280 @@ +#include +#include +#include + +#include "glad/gl.h" +#include "directxmath/directxmath.h" + +#include "new.h" +#include "file.h" +#include "view.h" + +#include "collada/types.h" +#include "collada/instance_types.h" +#include "collada/scene.h" +#include "collada/effect.h" + +namespace collada::scene { + + struct layout { + struct { + unsigned int position; + unsigned int normal; + unsigned int texture; + unsigned int blend_indices; + unsigned int blend_weight; + } attribute; + struct { + unsigned int transform; + } uniform; + }; + + const layout layout = { + .attribute = { + .position = 0, + .normal = 1, + .texture = 2, + .blend_indices = 3, + .blend_weight = 4, + }, + .uniform = { + .transform = 0, + }, + }; + + unsigned int attribute_location(char const * const semantic, + int semantic_index) + { + if (strcmp(semantic, "POSITION") == 0 && semantic_index == 0) { + return layout.attribute.position; + } + if (strcmp(semantic, "NORMAL") == 0 && semantic_index == 0) { + return layout.attribute.normal; + } + if (strcmp(semantic, "TEXCOORD") == 0 && semantic_index == 0) { + return layout.attribute.texture; + } + if (strcmp(semantic, "BLENDINDICES") == 0 && semantic_index == 0) { + return layout.attribute.blend_indices; + } + if (strcmp(semantic, "BLENDWEIGHT") == 0 && semantic_index == 0) { + return layout.attribute.blend_weight; + } + printf("unknown semantic %s index %d\n",semantic, semantic_index); + assert(false); + } + + unsigned int input_format_gl_size(types::input_format format) + { + switch (format) { + case types::input_format::FLOAT1: return 1; + case types::input_format::FLOAT2: return 2; + case types::input_format::FLOAT3: return 3; + case types::input_format::FLOAT4: return 4; + case types::input_format::INT1: return 1; + case types::input_format::INT2: return 2; + case types::input_format::INT3: return 3; + case types::input_format::INT4: return 4; + default: assert(false); + } + } + + unsigned int input_format_gl_type(types::input_format format) + { + switch (format) { + case types::input_format::FLOAT1: return GL_FLOAT; + case types::input_format::FLOAT2: return GL_FLOAT; + case types::input_format::FLOAT3: return GL_FLOAT; + case types::input_format::FLOAT4: return GL_FLOAT; + case types::input_format::INT1: return GL_INT; + case types::input_format::INT2: return GL_INT; + case types::input_format::INT3: return GL_INT; + case types::input_format::INT4: return GL_INT; + default: assert(false); + } + } + + // return stride + static inline int load_layout(types::inputs const & inputs, + int binding, + int start_offset, + unsigned int vertex_array) + { + glBindVertexArray(vertex_array); + int offset = start_offset; + for (int i = 0; i < inputs.elements_count; i++) { + unsigned int location = attribute_location(inputs.elements[i].semantic, inputs.elements[i].semantic_index); + glEnableVertexAttribArray(location); + unsigned int gl_size = input_format_gl_size(inputs.elements[i].format); + unsigned int gl_type = input_format_gl_type(inputs.elements[i].format); + glVertexAttribFormat(location, gl_size, gl_type, GL_FALSE, offset); + glVertexAttribBinding(location, binding); + offset += gl_size * 4; + } + int stride = offset - start_offset; + glBindVertexArray(0); + return stride; + } + + types::input_element const input_elements_blendindices_0_4_blendweight_0_4[] = { + { + .semantic = "BLENDINDICES", + .semantic_index = 0, + .format = types::input_format::INT4, + }, + { + .semantic = "BLENDWEIGHT", + .semantic_index = 0, + .format = types::input_format::FLOAT4, + }, + }; + + types::inputs const skin_inputs = { + .elements = input_elements_blendindices_0_4_blendweight_0_4, + .elements_count = 2, + }; + + void state::load_layouts() + { + vertex_arrays = New(descriptor->inputs_list_count); + vertex_buffer_strides = New(descriptor->inputs_list_count); + + glGenVertexArrays(2 * descriptor->inputs_list_count, (unsigned int *)vertex_arrays); + + for (int i = 0; i < descriptor->inputs_list_count; i++) { + // static + int stride = load_layout(descriptor->inputs_list[i], + 0, // binding + 0, // start_offset + vertex_arrays[i].static_mesh); + vertex_buffer_strides[i] = stride; + + // skinned + load_layout(descriptor->inputs_list[i], + 0, // binding + 0, // start_offset + vertex_arrays[i].skinned_mesh); + load_layout(skin_inputs, + 1, // binding + 0, // start_offset + vertex_arrays[i].skinned_mesh); + } + } + + unsigned int load_vertex_buffer(const char * filename) + { + int size; + void * data = read_file(filename, &size); + assert(data != NULL); + unsigned int vertex_buffer; + glGenBuffers(1, &vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); + + free(data); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return vertex_buffer; + } + + unsigned int load_index_buffer(const char * filename) + { + int size; + void * data = read_file(filename, &size); + assert(data != NULL); + printf("%s %d\n", filename, size); + + unsigned int index_buffer; + glGenBuffers(1, &index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); + + free(data); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + return index_buffer; + } + + void state::load_scene(types::descriptor const * const descriptor) + { + this->descriptor = descriptor; + + load_layouts(); + + vertex_buffer_pnt = load_vertex_buffer(descriptor->position_normal_texture_buffer); + vertex_buffer_jw = load_vertex_buffer(descriptor->joint_weight_buffer); + index_buffer = load_index_buffer(descriptor->index_buffer); + } + + void state::draw_geometry(types::geometry const & geometry, + types::instance_material const * const instance_materials, + int const instance_materials_count) + { + glUseProgram(collada::effect::program_static); + + types::mesh const& mesh = geometry.mesh; + + for (int j = 0; j < instance_materials_count; j++) { + types::instance_material const& instance_material = instance_materials[j]; + types::triangles const& triangles = mesh.triangles[instance_material.element_index]; + + //set_instance_material(instance_material); + + unsigned int vertex_buffer_offset = mesh.vertex_buffer_offset; + unsigned int vertex_buffer_stride = vertex_buffer_strides[triangles.inputs_index]; + unsigned int vertex_array = vertex_arrays[triangles.inputs_index].static_mesh; + + glBindVertexArray(vertex_array); + glBindVertexBuffer(0, vertex_buffer_pnt, vertex_buffer_offset, vertex_buffer_stride); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); + + unsigned int index_count = triangles.count * 3; + unsigned int indices = triangles.index_offset * (sizeof (unsigned int)) + mesh.index_buffer_offset; + + unsigned int instance_count = 1; + unsigned int base_vertex = 0; + unsigned int base_instance = 1; + glDrawElementsInstancedBaseVertexBaseInstance(GL_TRIANGLES, + index_count, + GL_UNSIGNED_INT, + (void *)((ptrdiff_t)indices), + instance_count, + base_vertex, + base_instance); + } + } + + void state::draw_instance_geometries(types::instance_geometry const * const instance_geometries, + int const instance_geometries_count) + { + for (int i = 0; i < instance_geometries_count; i++) { + types::instance_geometry const &instance_geometry = instance_geometries[i]; + draw_geometry(*instance_geometry.geometry, + instance_geometry.instance_materials, + instance_geometry.instance_materials_count); + } + } + + void state::draw_node(types::node const & node) + { + draw_instance_geometries(node.instance_geometries, node.instance_geometries_count); + } + + void state::draw() + { + glUseProgram(collada::effect::program_static); + glUniformMatrix4fv(layout.uniform.transform, 1, false, (float *)&view::state.float_transform); + + for (int i = 0; i < descriptor->nodes_count; i++) { + types::node const & node = *descriptor->nodes[i]; + + // joints are not drawn + if (node.type != types::node_type::NODE) + continue; + + draw_node(node); + } + } +} diff --git a/src/test.cpp b/src/test.cpp index 79142a4..575df30 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -21,6 +21,10 @@ #include "collision_scene.h" #include "collision.h" #include "boids_scene.h" +#include "collada/effect.h" +#include "collada/scene.h" +#include "collada/types.h" +#include "data/scenes/ship20.h" struct line_location { struct { @@ -50,6 +54,8 @@ static quad_location quad_location; // globals ////////////////////////////////////////////////////////////////////// +static collada::scene::state scene_state; + unsigned int empty_vertex_array_object = -1; unsigned int quad_index_buffer = -1; @@ -290,6 +296,13 @@ void load(const char * source_path) line_art::load(); collision_scene::load(); boids_scene::load(); + + ////////////////////////////////////////////////////////////////////// + // collada + ////////////////////////////////////////////////////////////////////// + + collada::effect::load_effects(); + scene_state.load_scene(&ship20::descriptor); } void update_keyboard(int up, int down, int left, int right, @@ -569,7 +582,8 @@ void draw() glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //collision_scene::draw(); - boids_scene::draw(); + //boids_scene::draw(); + scene_state.draw(); } last_frame_time = current_time;