diff --git a/Makefile b/Makefile index 6cc7f0e..7a95fae 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ OBJS = \ src/line_art.o \ src/boids.o \ src/boids_scene.o \ + src/dds_validate.o \ src/collada/scene.o \ src/collada/effect.o \ src/collada/node_state.o \ diff --git a/data/scenes/ship20.cpp b/data/scenes/ship20.cpp deleted file mode 100644 index 9297e2f..0000000 --- a/data/scenes/ship20.cpp +++ /dev/null @@ -1,427 +0,0 @@ -#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 index 203f876..0203f61 100644 --- a/data/scenes/ship20/ship20.cpp +++ b/data/scenes/ship20/ship20.cpp @@ -23,7 +23,7 @@ light const light_omni003_light = { // shipple2_png image const image_shipple2_png = { - .resource_name = "_0_SHIPPLE2_PNG", + .resource_name = "data/scenes/ship20/shipple2.dds", }; image const * const images[] = { diff --git a/data/scenes/ship20/shipple2.dds b/data/scenes/ship20/shipple2.dds new file mode 100644 index 0000000..e389313 Binary files /dev/null and b/data/scenes/ship20/shipple2.dds differ diff --git a/include/collada/scene.h b/include/collada/scene.h index 9032a5d..b31869b 100644 --- a/include/collada/scene.h +++ b/include/collada/scene.h @@ -18,9 +18,17 @@ namespace collada::scene { static_skinned * vertex_arrays; int * vertex_buffer_strides; + unsigned int * textures; + void load_layouts(); + void load_images(); void load_scene(types::descriptor const * const descriptor); + void set_color_or_texture(types::color_or_texture const& color_or_texture, + unsigned int color_uniform, + unsigned int texture_unit); + void set_instance_material(types::instance_material const& instance_material); + void draw_geometry(types::geometry const & geometry, types::instance_material const * const instance_materials, int const instance_materials_count); diff --git a/include/dds.h b/include/dds.h new file mode 100644 index 0000000..50d6431 --- /dev/null +++ b/include/dds.h @@ -0,0 +1,127 @@ +//-------------------------------------------------------------------------------------- +// dds.h +// +// This header defines constants and structures that are useful when parsing +// DDS files. DDS files were originally designed to use several structures +// and constants that are native to DirectDraw and are defined in ddraw.h, +// such as DDSURFACEDESC2 and DDSCAPS2. This file defines similar +// (compatible) constants and structures so that one can use DDS files +// without needing to include ddraw.h. +//-------------------------------------------------------------------------------------- + +#ifndef _DDS_H_ +#define _DDS_H_ + +#pragma pack(push,1) + +#define DDS_MAGIC 0x20534444 // "DDS " + +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned int)(unsigned char)(ch0) | ((unsigned int)(unsigned char)(ch1) << 8) | \ + ((unsigned int)(unsigned char)(ch2) << 16) | ((unsigned int)(unsigned char)(ch3) << 24 )) + +struct DDS_PIXELFORMAT +{ + unsigned int dwSize; + unsigned int dwFlags; + unsigned int dwFourCC; + unsigned int dwRGBBitCount; + unsigned int dwRBitMask; + unsigned int dwGBitMask; + unsigned int dwBBitMask; + unsigned int dwABitMask; +}; + +#define DDS_FOURCC 0x00000004 // DDPF_FOURCC +#define DDS_RGB 0x00000040 // DDPF_RGB +#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS +#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE +#define DDS_ALPHA 0x00000002 // DDPF_ALPHA + +const DDS_PIXELFORMAT DDSPF_DXT1 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT2 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT3 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT4 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_DXT5 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 }; + +const DDS_PIXELFORMAT DDSPF_A8R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; + +const DDS_PIXELFORMAT DDSPF_A1R5G5B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 }; + +const DDS_PIXELFORMAT DDSPF_A4R4G4B4 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 }; + +const DDS_PIXELFORMAT DDSPF_R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 }; + +const DDS_PIXELFORMAT DDSPF_R5G6B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 }; + +// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat) +const DDS_PIXELFORMAT DDSPF_DX10 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }; + +#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT +#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT +#define DDS_HEADER_FLAGS_VOLUME 0x00800000 // DDSD_DEPTH +#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH +#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE + +#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE +#define DDS_SURFACE_FLAGS_MIPMAP 0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP +#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX + +#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX +#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX +#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY +#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY +#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ +#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ + +#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\ + DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\ + DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ ) + +#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME + +typedef struct +{ + unsigned int dwSize; + unsigned int dwHeaderFlags; + unsigned int dwHeight; + unsigned int dwWidth; + unsigned int dwPitchOrLinearSize; + unsigned int dwDepth; // only if DDS_HEADER_FLAGS_VOLUME is set in dwHeaderFlags + unsigned int dwMipMapCount; + unsigned int dwReserved1[11]; + DDS_PIXELFORMAT ddspf; + unsigned int dwSurfaceFlags; + unsigned int dwCubemapFlags; + unsigned int dwReserved2[3]; +} DDS_HEADER; + +/* +typedef struct +{ + DXGI_FORMAT dxgiFormat; + D3D10_RESOURCE_DIMENSION resourceDimension; + unsigned int miscFlag; + unsigned int arraySize; + unsigned int reserved; +} DDS_HEADER_DXT10; +*/ + +#pragma pack(pop) + +#endif // _DDS_H diff --git a/include/dds_validate.h b/include/dds_validate.h new file mode 100644 index 0000000..1aa733e --- /dev/null +++ b/include/dds_validate.h @@ -0,0 +1,10 @@ +#pragma once + +#include "dds.h" + +struct DDS_FILE { + unsigned int dwMagic; + DDS_HEADER header; +}; + +DDS_FILE const * dds_validate(void * data, unsigned int size, void ** out_data, int * out_size); diff --git a/include/glad/gl.h b/include/glad/gl.h index a9fb7c7..c34be4b 100644 --- a/include/glad/gl.h +++ b/include/glad/gl.h @@ -1,11 +1,11 @@ /** - * Loader generated by glad 2.0.8 on Thu Mar 5 16:16:42 2026 + * Loader generated by glad 2.0.8 on Tue Mar 17 02:15:55 2026 * * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 * * Generator: C/C++ * Specification: gl - * Extensions: 0 + * Extensions: 1 * * APIs: * - gl:core=4.3 @@ -19,10 +19,10 @@ * - ON_DEMAND = False * * Commandline: - * --api='gl:core=4.3' --extensions='' c + * --api='gl:core=4.3' --extensions='GL_EXT_texture_compression_s3tc' c * * Online: - * http://glad.sh/#api=gl%3Acore%3D4.3&extensions=&generator=c&options= + * http://glad.sh/#api=gl%3Acore%3D4.3&extensions=GL_EXT_texture_compression_s3tc&generator=c&options= * */ @@ -332,8 +332,12 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro #define GL_COMPRESSED_RGBA 0x84EE #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC @@ -1578,6 +1582,8 @@ GLAD_API_CALL int GLAD_GL_VERSION_4_1; GLAD_API_CALL int GLAD_GL_VERSION_4_2; #define GL_VERSION_4_3 1 GLAD_API_CALL int GLAD_GL_VERSION_4_3; +#define GL_EXT_texture_compression_s3tc 1 +GLAD_API_CALL int GLAD_GL_EXT_texture_compression_s3tc; typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program); diff --git a/include/opengl.h b/include/opengl.h index 46de730..23ca694 100644 --- a/include/opengl.h +++ b/include/opengl.h @@ -10,6 +10,8 @@ extern "C" { unsigned int load_uniform_buffer(char const * const path); + void load_dds_texture_2D(char const * const path); + #ifdef __cplusplus } #endif diff --git a/shader/collada/generic.frag b/shader/collada/generic.frag index 8040155..6aa9ba2 100644 --- a/shader/collada/generic.frag +++ b/shader/collada/generic.frag @@ -1,8 +1,65 @@ #version 430 core -out vec4 Color; +in vec3 PixelNormal; +in vec2 PixelTexture; +/* + +in vec4 PixelViewPosition; +in vec4 PixelWorldPosition; +in vec4 PixelLightPosition; +*/ + +layout (location = 10) uniform vec4 EmissionColor; +layout (location = 11) uniform vec4 AmbientColor; +layout (location = 12) uniform vec4 DiffuseColor; +layout (location = 13) uniform vec4 SpecularColor; + +layout (location = 14) uniform float shininess; + +layout (location = 15) uniform sampler2D EmissionSampler; +layout (location = 16) uniform sampler2D AmbientSampler; +layout (location = 17) uniform sampler2D DiffuseSampler; +layout (location = 18) uniform sampler2D SpecularSampler; + +layout (location = 19) uniform ivec4 TextureChannel; + +layout (location = 0) out vec4 g_color; +//layout (location = 1) out vec4 g_position; +//layout (location = 2) out vec4 g_normal; void main() { - Color = vec4(1, 0, 0, 1); + vec4 emission; + vec4 ambient; + vec4 diffuse; + vec4 specular; + if (TextureChannel.x >= 0) { // emission + emission = texture(EmissionSampler, PixelTexture.xy); + } else { + emission = EmissionColor; + } + if (TextureChannel.y >= 0) { // ambient + ambient = texture(AmbientSampler, PixelTexture.xy); + } else { + ambient = AmbientColor; + } + if (TextureChannel.z >= 0) { // diffuse + diffuse = texture(DiffuseSampler, PixelTexture.xy); + } else { + diffuse = DiffuseColor; + } + if (TextureChannel.w >= 0) { // specular + specular = texture(SpecularSampler, PixelTexture.xy); + } else { + specular = SpecularColor; + } + + vec3 color = emission.xyz * 0; + color += ambient.xyz * 0.05; + color += diffuse.xyz * 1; + color += specular.xyz * 0 * 0.3; + + g_color = vec4(color, 1.0); + //g_color = vec4(PixelNormal.xyz, 1.0); + //g_color = vec4(PixelTexture.xy, 0, 1); } diff --git a/shader/collada/static.vert b/shader/collada/static.vert index 952d348..971eba0 100644 --- a/shader/collada/static.vert +++ b/shader/collada/static.vert @@ -2,11 +2,17 @@ layout (location = 0) in vec3 Position; layout (location = 1) in vec3 Normal; -layout (location = 2) in vec3 Texture; +layout (location = 2) in vec2 Texture; layout (location = 0) uniform mat4 Transform; +out vec3 PixelNormal; +out vec2 PixelTexture; + void main() { + PixelNormal = Normal; + PixelTexture = vec2(Texture.x, 1.0 - Texture.y); + gl_Position = Transform * vec4(Position, 1); } diff --git a/src/collada/scene.cpp b/src/collada/scene.cpp index 1c824aa..afc2bc5 100644 --- a/src/collada/scene.cpp +++ b/src/collada/scene.cpp @@ -8,6 +8,7 @@ #include "new.h" #include "file.h" #include "view.h" +#include "opengl.h" #include "collada/types.h" #include "collada/instance_types.h" @@ -25,8 +26,29 @@ namespace collada::scene { unsigned int blend_weight; } attribute; struct { + // vertex unsigned int transform; + // fragment + unsigned int emission_color; + unsigned int ambient_color; + unsigned int diffuse_color; + unsigned int specular_color; + + unsigned int shininess; + + unsigned int emission_sampler; + unsigned int ambient_sampler; + unsigned int diffuse_sampler; + unsigned int specular_sampler; + + unsigned int texture_channels; } uniform; + struct { + unsigned int emission; + unsigned int ambient; + unsigned int diffuse; + unsigned int specular; + } texture_unit; }; const layout layout = { @@ -38,7 +60,28 @@ namespace collada::scene { .blend_weight = 4, }, .uniform = { + // vertex .transform = 0, + // fragment + .emission_color = 10, + .ambient_color = 11, + .diffuse_color = 12, + .specular_color = 13, + + .shininess = 14, + + .emission_sampler = 15, + .ambient_sampler = 16, + .diffuse_sampler = 17, + .specular_sampler = 18, + + .texture_channels = 19, + }, + .texture_unit { + .emission = GL_TEXTURE0, + .ambient = GL_TEXTURE1, + .diffuse = GL_TEXTURE2, + .specular = GL_TEXTURE3, }, }; @@ -197,6 +240,27 @@ namespace collada::scene { return index_buffer; } + void state::load_images() + { + textures = New(descriptor->images_count); + glGenTextures(descriptor->images_count, textures); + + for (int i = 0; i < descriptor->images_count; i++) { + types::image const * const image = descriptor->images[i]; + + glBindTexture(GL_TEXTURE_2D, textures[i]); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + load_dds_texture_2D(image->resource_name); + } + + glBindTexture(GL_TEXTURE_2D, 0); + } + void state::load_scene(types::descriptor const * const descriptor) { this->descriptor = descriptor; @@ -206,6 +270,64 @@ namespace collada::scene { 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); + + load_images(); + } + + void state::set_color_or_texture(types::color_or_texture const& color_or_texture, + unsigned int color_uniform, + unsigned int texture_unit) + { + switch (color_or_texture.type) { + case types::color_or_texture_type::COLOR: + glUniform4fv(color_uniform, 1, (float *)&color_or_texture.color); + break; + case types::color_or_texture_type::TEXTURE: + glActiveTexture(texture_unit); + glBindTexture(GL_TEXTURE_2D, textures[color_or_texture.texture.image_index]); + break; + default: + assert(false); + } + } + + void state::set_instance_material(types::instance_material const& instance_material) + { + types::effect const& effect = *instance_material.material->effect; + switch (effect.type) { + case types::effect_type::BLINN: + set_color_or_texture(effect.blinn.emission, layout.uniform.emission_color, layout.texture_unit.emission); + set_color_or_texture(effect.blinn.ambient, layout.uniform.ambient_color, layout.texture_unit.ambient); + set_color_or_texture(effect.blinn.diffuse, layout.uniform.diffuse_color, layout.texture_unit.diffuse); + set_color_or_texture(effect.blinn.specular, layout.uniform.specular_color, layout.texture_unit.specular); + glUniform1f(layout.uniform.shininess, effect.blinn.shininess); + break; + case types::effect_type::LAMBERT: + set_color_or_texture(effect.lambert.emission, layout.uniform.emission_color, layout.texture_unit.emission); + set_color_or_texture(effect.lambert.ambient, layout.uniform.ambient_color, layout.texture_unit.ambient); + set_color_or_texture(effect.lambert.diffuse, layout.uniform.diffuse_color, layout.texture_unit.diffuse); + break; + case types::effect_type::PHONG: + set_color_or_texture(effect.phong.emission, layout.uniform.emission_color, layout.texture_unit.emission); + set_color_or_texture(effect.phong.ambient, layout.uniform.ambient_color, layout.texture_unit.ambient); + set_color_or_texture(effect.phong.diffuse, layout.uniform.diffuse_color, layout.texture_unit.diffuse); + set_color_or_texture(effect.phong.specular, layout.uniform.specular_color, layout.texture_unit.specular); + glUniform1f(layout.uniform.shininess, effect.phong.shininess); + break; + case types::effect_type::CONSTANT: + glUniform4fv(layout.uniform.emission_color, 1, (float *)&effect.constant.color); + break; + default: + break; + } + + int texture_channels[4] = { + instance_material.emission.input_set, + instance_material.ambient.input_set, + instance_material.diffuse.input_set, + instance_material.specular.input_set, + }; + glUniform4iv(layout.uniform.texture_channels, 1, texture_channels); } void state::draw_geometry(types::geometry const & geometry, @@ -217,10 +339,13 @@ namespace collada::scene { types::mesh const& mesh = geometry.mesh; for (int j = 0; j < instance_materials_count; j++) { + //if (j != 1) + //continue; + types::instance_material const& instance_material = instance_materials[j]; types::triangles const& triangles = mesh.triangles[instance_material.element_index]; - //set_instance_material(instance_material); + 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]; @@ -235,7 +360,7 @@ namespace collada::scene { unsigned int instance_count = 1; unsigned int base_vertex = 0; - unsigned int base_instance = 1; + unsigned int base_instance = 0; glDrawElementsInstancedBaseVertexBaseInstance(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, @@ -266,6 +391,16 @@ namespace collada::scene { { glUseProgram(collada::effect::program_static); glUniformMatrix4fv(layout.uniform.transform, 1, false, (float *)&view::state.float_transform); + glUniform1i(layout.uniform.emission_sampler, 0); + glUniform1i(layout.uniform.ambient_sampler, 1); + glUniform1i(layout.uniform.diffuse_sampler, 2); + glUniform1i(layout.uniform.specular_sampler, 3); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_GREATER); + glDisable(GL_CULL_FACE); + //glCullFace(GL_FRONT); + //glFrontFace(GL_CCW); for (int i = 0; i < descriptor->nodes_count; i++) { types::node const & node = *descriptor->nodes[i]; diff --git a/src/dds_validate.cpp b/src/dds_validate.cpp new file mode 100644 index 0000000..a99ff35 --- /dev/null +++ b/src/dds_validate.cpp @@ -0,0 +1,69 @@ +#include +#include + +#include "dds_validate.h" + +static inline unsigned int max(unsigned int a, unsigned int b) +{ + return (a > b) ? a : b; +} + +struct dds_size_levels { + unsigned int const size; + unsigned int const levels; +}; + +static inline unsigned int dim(unsigned int d) +{ + return max(1, (d / 4)); +} + +static inline dds_size_levels dds_mip_total_size(uintptr_t data, + unsigned int height, + unsigned int width, + unsigned int max_mip_levels) +{ + unsigned int mip_total_size = 0; + unsigned int mip_levels = 0; + while (true) { + unsigned int mip_size = dim(height) * dim(width) * 8; + mip_total_size += mip_size; + //subresourceData[mip_levels].pSysMem = (const void *)data; + //subresourceData[mip_levels].SysMemPitch = dim(width) * 8; + mip_levels += 1; + assert(mip_levels <= max_mip_levels); + data += mip_size; + + if (max_mip_levels == 1 || (width == 1 && height == 1)) + break; + + height /= 2; + width /= 2; + } + + return (dds_size_levels){mip_total_size, mip_levels}; +} + +DDS_FILE const * dds_validate(void * data, unsigned int size, void ** out_data, int * out_size) +{ + DDS_FILE const * const dds = (DDS_FILE const *)data; + assert(dds->dwMagic == DDS_MAGIC); + assert(dds->header.dwSize == 124); + assert(dds->header.ddspf.dwSize == 32); + assert(dds->header.ddspf.dwFlags == DDS_FOURCC); + assert(dds->header.ddspf.dwFourCC == MAKEFOURCC('D','X','T','1')); + + assert(dds->header.dwDepth == 0); + + uintptr_t image_data = ((uintptr_t)dds) + (sizeof (DDS_FILE)); + dds_size_levels ret = dds_mip_total_size(image_data, + dds->header.dwHeight, + dds->header.dwWidth, + dds->header.dwMipMapCount); + assert(ret.size + (sizeof (DDS_FILE)) == size); + assert(ret.levels == dds->header.dwMipMapCount); + + *out_data = (void *)image_data; + *out_size = ret.size; + return dds; +} diff --git a/src/gl.c b/src/gl.c index b027d1e..64faa39 100644 --- a/src/gl.c +++ b/src/gl.c @@ -39,6 +39,7 @@ int GLAD_GL_VERSION_4_0 = 0; int GLAD_GL_VERSION_4_1 = 0; int GLAD_GL_VERSION_4_2 = 0; int GLAD_GL_VERSION_4_3 = 0; +int GLAD_GL_EXT_texture_compression_s3tc = 0; @@ -1259,7 +1260,7 @@ static int glad_gl_find_extensions_gl(void) { char **exts_i = NULL; if (!glad_gl_get_extensions(&exts, &exts_i)) return 0; - GLAD_UNUSED(&glad_gl_has_extension); + GLAD_GL_EXT_texture_compression_s3tc = glad_gl_has_extension(exts, exts_i, "GL_EXT_texture_compression_s3tc"); glad_gl_free_extensions(exts_i); diff --git a/src/opengl.c b/src/opengl.cpp similarity index 71% rename from src/opengl.c rename to src/opengl.cpp index d0629af..0806181 100644 --- a/src/opengl.c +++ b/src/opengl.cpp @@ -7,12 +7,13 @@ #include "glad/gl.h" #include "opengl.h" #include "file.h" +#include "dds_validate.h" -unsigned int compile(const char * vertex_source, +unsigned int compile(char const * vertex_source, int vertex_source_size, - const char * geometry_source, + char const * geometry_source, int geometry_source_size, - const char * fragment_source, + char const * fragment_source, int fragment_source_size) { int compile_status; @@ -75,16 +76,16 @@ unsigned int compile(const char * vertex_source, return shader_program; } -unsigned int compile_from_files(const char * vertex_path, - const char * geometry_path, - const char * fragment_path) +unsigned int compile_from_files(char const * vertex_path, + char const * geometry_path, + char const * fragment_path) { int vertex_source_size = 0; - char * vertex_source = NULL; + void * vertex_source = NULL; int geometry_source_size = 0; - char * geometry_source = NULL; + void * geometry_source = NULL; int fragment_source_size = 0; - char * fragment_source = NULL; + void * fragment_source = NULL; vertex_source = read_file(vertex_path, &vertex_source_size); assert(vertex_source != NULL); @@ -97,9 +98,9 @@ unsigned int compile_from_files(const char * vertex_path, fragment_source = read_file(fragment_path, &fragment_source_size); assert(fragment_source != NULL); - unsigned int program = compile(vertex_source, vertex_source_size, - geometry_source, geometry_source_size, - fragment_source, fragment_source_size); + unsigned int program = compile((char const *)vertex_source, vertex_source_size, + (char const *)geometry_source, geometry_source_size, + (char const *)fragment_source, fragment_source_size); free(vertex_source); free(geometry_source); @@ -125,3 +126,27 @@ unsigned int load_uniform_buffer(char const * const path) return buffer; } + +void load_dds_texture_2D(char const * const path) +{ + fprintf(stderr, "load DDS texture: %s\n", path); + + int size; + void * data = read_file(path, &size); + assert(data != NULL); + + void * image_data; + int image_size; + DDS_FILE const * dds = dds_validate(data, size, &image_data, &image_size); + + glCompressedTexImage2D(GL_TEXTURE_2D, + 0, + GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + dds->header.dwWidth, + dds->header.dwHeight, + 0, + image_size, + image_data); + + free(data); +} diff --git a/src/test.cpp b/src/test.cpp index 575df30..b6c8259 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -380,6 +380,7 @@ void update_joystick(int joystick_index, delta_yaw, delta_pitch); view::apply_fov(0.01 * up + -0.01 * down); + /* XMVECTOR sphere_position = view::state.at; float sphere_radius = 0.48; @@ -411,7 +412,9 @@ void update_joystick(int joystick_index, // apply the last direction impulse view::state.at = sphere.center + direction; } + */ + view::state.at = view::state.at + direction; view::state.eye = view::state.at - view::state.direction * view::at_distance; /* @@ -558,10 +561,9 @@ void update_mouse(int x, int y) void draw() { + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(-1.0f); if (false) { - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepth(-1.0f); - // possibly re-initialize geometry buffer if window width/height changes init_geometry_buffer(geometry_buffer_pnc, geometry_buffer_pnc_types);