diff --git a/graph_dev_opengl.c b/graph_dev_opengl.c index 54446650..09487858 100644 --- a/graph_dev_opengl.c +++ b/graph_dev_opengl.c @@ -102,6 +102,8 @@ struct vertex_triangle_buffer_data { union vec3 tvertex2; union vec3 wireframe_edge_mask; union vec2 texture_coord; + union vec3 tangent; + union vec3 bitangent; }; struct vertex_wireframe_line_buffer_data { @@ -209,6 +211,14 @@ void mesh_graph_dev_init(struct mesh *m) g_vt_buffer_data[v_index].tvertex2.v.y = m->t[i].v[2]->y; g_vt_buffer_data[v_index].tvertex2.v.z = m->t[i].v[2]->z; + g_vt_buffer_data[v_index].tangent.v.x = m->t[i].vtangent[j].x; + g_vt_buffer_data[v_index].tangent.v.y = m->t[i].vtangent[j].y; + g_vt_buffer_data[v_index].tangent.v.z = m->t[i].vtangent[j].z; + + g_vt_buffer_data[v_index].bitangent.v.x = m->t[i].vbitangent[j].x; + g_vt_buffer_data[v_index].bitangent.v.y = m->t[i].vbitangent[j].y; + g_vt_buffer_data[v_index].bitangent.v.z = m->t[i].vbitangent[j].z; + /* bias the edge distance to make the coplanar edges not draw */ if ((j == 1 || j == 2) && (m->t[i].flag & TRIANGLE_1_2_COPLANAR)) g_vt_buffer_data[v_index].wireframe_edge_mask.v.x = 1000; @@ -669,11 +679,14 @@ struct graph_dev_gl_textured_shader { GLint normal_matrix_id; GLint vertex_position_id; GLint vertex_normal_id; + GLint vertex_tangent_id; + GLint vertex_bitangent_id; GLint tint_color_id; GLint texture_coord_id; GLint texture_2d_id; GLint emit_texture_2d_id; GLint texture_cubemap_id; + GLint normalmap_cubemap_id; GLint light_pos_id; GLint shadow_sphere_id; @@ -777,8 +790,10 @@ static struct graph_dev_gl_textured_shader textured_with_sphere_shadow_shader; static struct graph_dev_gl_textured_shader textured_lit_shader; static struct graph_dev_gl_textured_shader textured_lit_emit_shader; static struct graph_dev_gl_textured_shader textured_cubemap_lit_shader; +static struct graph_dev_gl_textured_shader textured_cubemap_lit_normal_map_shader; static struct graph_dev_gl_textured_shader textured_cubemap_shield_shader; static struct graph_dev_gl_textured_shader textured_cubemap_lit_with_annulus_shadow_shader; +static struct graph_dev_gl_textured_shader textured_cubemap_normal_mapped_lit_with_annulus_shadow_shader; static struct graph_dev_gl_textured_particle_shader textured_particle_shader; static struct graph_dev_gl_fs_effect_shader fs_copy_shader; static struct graph_dev_smaa_effect smaa_effect; @@ -1173,7 +1188,7 @@ static void graph_dev_draw_normal_lines(const struct mat44 *mat_mvp, struct mesh static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader, const struct mat44 *mat_mvp, const struct mat44 *mat_mv, const struct mat33 *mat_normal, struct mesh *m, struct sng_color *triangle_color, float alpha, union vec3 *eye_light_pos, GLuint texture_number, - GLuint emit_texture_number, struct shadow_sphere_data *shadow_sphere, + GLuint emit_texture_number, GLuint normalmap_texture_number, struct shadow_sphere_data *shadow_sphere, struct shadow_annulus_data *shadow_annulus, int do_cullface, int do_blend, float ring_texture_v, float ring_inner_radius, float ring_outer_radius) { @@ -1205,6 +1220,9 @@ static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader else if (shader->texture_cubemap_id >= 0) BIND_TEXTURE(GL_TEXTURE0, GL_TEXTURE_CUBE_MAP, texture_number); + if (shader->normalmap_cubemap_id >= 0) + BIND_TEXTURE(GL_TEXTURE3, GL_TEXTURE_CUBE_MAP, normalmap_texture_number); + if (shader->emit_texture_2d_id >= 0) BIND_TEXTURE(GL_TEXTURE1, GL_TEXTURE_2D, emit_texture_number); @@ -1281,6 +1299,32 @@ static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader ); } + if (shader->vertex_tangent_id >= 0) { + glEnableVertexAttribArray(shader->vertex_tangent_id); + glBindBuffer(GL_ARRAY_BUFFER, ptr->triangle_vertex_buffer); + glVertexAttribPointer( + shader->vertex_tangent_id, /* The attribute we want to configure */ + 3, /* size */ + GL_FLOAT, /* type */ + GL_FALSE, /* normalized? */ + sizeof(struct vertex_triangle_buffer_data), /* stride */ + (void *)offsetof(struct vertex_triangle_buffer_data, tangent.v.x) /* array buffer offset */ + ); + } + + if (shader->vertex_bitangent_id >= 0) { + glEnableVertexAttribArray(shader->vertex_bitangent_id); + glBindBuffer(GL_ARRAY_BUFFER, ptr->triangle_vertex_buffer); + glVertexAttribPointer( + shader->vertex_bitangent_id, /* The attribute we want to configure */ + 3, /* size */ + GL_FLOAT, /* type */ + GL_FALSE, /* normalized? */ + sizeof(struct vertex_triangle_buffer_data), /* stride */ + (void *)offsetof(struct vertex_triangle_buffer_data, bitangent.v.x) /* array buffer offset */ + ); + } + if (shader->texture_coord_id >= 0) { glEnableVertexAttribArray(shader->texture_coord_id); glBindBuffer(GL_ARRAY_BUFFER, ptr->triangle_vertex_buffer); @@ -1294,6 +1338,10 @@ static void graph_dev_raster_texture(struct graph_dev_gl_textured_shader *shader glDisableVertexAttribArray(shader->vertex_position_id); if (shader->vertex_normal_id >= 0) glDisableVertexAttribArray(shader->vertex_normal_id); + if (shader->vertex_tangent_id >= 0) + glDisableVertexAttribArray(shader->vertex_tangent_id); + if (shader->vertex_bitangent_id >= 0) + glDisableVertexAttribArray(shader->vertex_bitangent_id); if (shader->texture_coord_id >= 0) glDisableVertexAttribArray(shader->texture_coord_id); glUseProgram(0); @@ -1837,7 +1885,7 @@ static void graph_dev_draw_nebula(const struct mat44 *mat_mvp, const struct mat4 float alpha = fabs(vec3_dot(&camera_normal, &camera_ent_vector)) * mt->alpha; graph_dev_raster_texture(&textured_shader, &mat_mvp_local_r, &mat_mv_local_r, &mat_normal_local_r, - e->m, &mt->tint, alpha, eye_light_pos, mt->texture_id[i], 0, 0, 0, 0, 1, 0.0f, + e->m, &mt->tint, alpha, eye_light_pos, mt->texture_id[i], 0, -1, 0, 0, 0, 1, 0.0f, 2.0f, 4.0f); if (draw_billboard_wireframe) { @@ -2080,6 +2128,7 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve float texture_alpha = 1.0; GLuint texture_id = 0; GLuint emit_texture_id = 0; + GLuint normalmap_id = -1; /* for sphere shadows */ struct shadow_sphere_data shadow_sphere; @@ -2162,9 +2211,14 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve case MATERIAL_TEXTURED_PLANET: { struct material_textured_planet *mt = &e->material_ptr->textured_planet; texture_id = mt->texture_id; + normalmap_id = mt->normalmap_id; if (mt->ring_material && mt->ring_material->type == MATERIAL_TEXTURED_PLANET_RING) { - tex_shader = &textured_cubemap_lit_with_annulus_shadow_shader; + if (normalmap_id == (GLuint) -1) + tex_shader = &textured_cubemap_lit_with_annulus_shadow_shader; + else + tex_shader = + &textured_cubemap_normal_mapped_lit_with_annulus_shadow_shader; struct material_textured_planet_ring *ring_mt = &mt->ring_material->textured_planet_ring; @@ -2187,7 +2241,10 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve shadow_annulus.r2 = vec3_cwise_max(&e->scale) * ring_outer_radius; } else { - tex_shader = &textured_cubemap_lit_shader; + if (normalmap_id != (GLuint) -1) + tex_shader = &textured_cubemap_lit_normal_map_shader; + else + tex_shader = &textured_cubemap_lit_shader; } } break; @@ -2245,8 +2302,8 @@ void graph_dev_draw_entity(struct entity_context *cx, struct entity *e, union ve if (tex_shader) graph_dev_raster_texture(tex_shader, mat_mvp, mat_mv, mat_normal, e->m, &texture_tint, texture_alpha, eye_light_pos, texture_id, - emit_texture_id, &shadow_sphere, &shadow_annulus, do_cullface, - do_blend, ring_texture_v, + emit_texture_id, normalmap_id, &shadow_sphere, &shadow_annulus, + do_cullface, do_blend, ring_texture_v, ring_inner_radius, ring_outer_radius); else if (atmosphere) graph_dev_raster_atmosphere(mat_mvp, mat_mv, mat_normal, @@ -2748,17 +2805,21 @@ static void setup_textured_shader(const char *basename, const char *defines, shader->shadow_sphere_id = glGetUniformLocation(shader->program_id, "u_Sphere"); } -static void setup_textured_cubemap_shader(const char *basename, struct graph_dev_gl_textured_shader *shader) +static void setup_textured_cubemap_shader(const char *basename, int use_normal_map, + struct graph_dev_gl_textured_shader *shader) { /* set all attributes to -1 */ memset(shader, 0xff, sizeof(*shader)); - const char *vert_header = - UNIVERSAL_SHADER_HEADER - "#define INCLUDE_VS 1\n"; - const char *frag_header = - UNIVERSAL_SHADER_HEADER - "#define INCLUDE_FS 1\n"; + char vert_header[1024]; + char frag_header[1024]; + + sprintf(vert_header, "%s\n%s\n%s\n", + UNIVERSAL_SHADER_HEADER, "#define INCLUDE_VS 1\n", + use_normal_map ? "#define USE_NORMAL_MAP 1\n" : "\n"); + sprintf(frag_header, "%s\n%s\n%s\n", + UNIVERSAL_SHADER_HEADER, "#define INCLUDE_FS 1\n", + use_normal_map ? "#define USE_NORMAL_MAP 1\n" : "\n"); char shader_filename[PATH_MAX]; snprintf(shader_filename, sizeof(shader_filename), "%s.shader", basename); @@ -2776,6 +2837,10 @@ static void setup_textured_cubemap_shader(const char *basename, struct graph_dev shader->light_pos_id = glGetUniformLocation(shader->program_id, "u_LightPos"); shader->texture_cubemap_id = glGetUniformLocation(shader->program_id, "u_AlbedoTex"); glUniform1i(shader->texture_cubemap_id, 0); + if (use_normal_map) { + shader->normalmap_cubemap_id = glGetUniformLocation(shader->program_id, "u_NormalMapTex"); + glUniform1i(shader->normalmap_cubemap_id, 3); /* GL_TEXTURE3 */ + } shader->tint_color_id = glGetUniformLocation(shader->program_id, "u_TintColor"); shader->ring_texture_v_id = glGetUniformLocation(shader->program_id, "u_ring_texture_v"); if (shader->ring_texture_v_id >= 0) @@ -2790,6 +2855,8 @@ static void setup_textured_cubemap_shader(const char *basename, struct graph_dev /* Get a handle for our buffers */ shader->vertex_position_id = glGetAttribLocation(shader->program_id, "a_Position"); shader->vertex_normal_id = glGetAttribLocation(shader->program_id, "a_Normal"); + shader->vertex_tangent_id = glGetAttribLocation(shader->program_id, "a_Tangent"); + shader->vertex_bitangent_id = glGetAttribLocation(shader->program_id, "a_BiTangent"); shader->shadow_annulus_texture_id = glGetUniformLocation(shader->program_id, "u_AnnulusAlbedoTex"); glUniform1i(shader->shadow_annulus_texture_id, 1); @@ -3362,10 +3429,13 @@ int graph_dev_setup(const char *shader_dir) setup_textured_shader("textured-and-lit-per-pixel", UNIVERSAL_SHADER_HEADER, &textured_lit_shader); setup_textured_shader("textured-and-lit-per-pixel", UNIVERSAL_SHADER_HEADER "#define USE_EMIT_MAP", &textured_lit_emit_shader); - setup_textured_cubemap_shader("textured-cubemap-and-lit-per-pixel", &textured_cubemap_lit_shader); - setup_textured_cubemap_shader("textured-cubemap-shield-per-pixel", &textured_cubemap_shield_shader); - setup_textured_cubemap_shader("textured-cubemap-and-lit-with-annulus-shadow-per-pixel", + setup_textured_cubemap_shader("textured-cubemap-and-lit-per-pixel", 0, &textured_cubemap_lit_shader); + setup_textured_cubemap_shader("textured-cubemap-and-lit-per-pixel", 1, &textured_cubemap_lit_normal_map_shader); + setup_textured_cubemap_shader("textured-cubemap-shield-per-pixel", 0, &textured_cubemap_shield_shader); + setup_textured_cubemap_shader("textured-cubemap-and-lit-with-annulus-shadow-per-pixel", 0, &textured_cubemap_lit_with_annulus_shadow_shader); + setup_textured_cubemap_shader("textured-cubemap-and-lit-with-annulus-shadow-per-pixel", 1, + &textured_cubemap_normal_mapped_lit_with_annulus_shadow_shader); setup_textured_particle_shader(&textured_particle_shader); setup_fs_effect_shader("fs-effect-copy", &fs_copy_shader); diff --git a/material.h b/material.h index 6299ab6f..bf7759fa 100644 --- a/material.h +++ b/material.h @@ -106,6 +106,7 @@ struct material_textured_planet_ring { struct material_textured_planet { int texture_id; + int normalmap_id; struct material *ring_material; }; diff --git a/mesh_viewer.c b/mesh_viewer.c index 4357a525..5f4f1533 100644 --- a/mesh_viewer.c +++ b/mesh_viewer.c @@ -49,6 +49,7 @@ static int frame_counter = 0; static int periodic_snapshots = 0; static int snapshot_number = 0; static char *planetname = NULL; +static char *normalmapname = NULL; static char *program; union quat autorotation; static int icosohedron_subdivision = 4; @@ -610,7 +611,8 @@ static void setup_skybox(char *skybox_prefix) __attribute__((noreturn)) void usage(char *program) { fprintf(stderr, "Usage:\n"); - fprintf(stderr, " %s [ -p ] [ -i icosohedron-subdivision]\n", program); + fprintf(stderr, " %s -p [ -i icosohedrion-subdivision] [ -n ]\n", + program); fprintf(stderr, " %s \n", program); exit(-1); } @@ -631,6 +633,7 @@ static struct option long_options[] = { { "help", no_argument, NULL, 'h' }, { "planetmode", required_argument, NULL, 'p' }, { "icosohedron", required_argument, NULL, 'i' }, + { "normalmap", required_argument, NULL, 'n' }, }; static int process_options(int argc, char *argv[]) @@ -641,7 +644,7 @@ static int process_options(int argc, char *argv[]) while (1) { int option_index; - c = getopt_long(argc, argv, "hi:p:", long_options, &option_index); + c = getopt_long(argc, argv, "hi:n:p:", long_options, &option_index); if (c < 0) { break; } @@ -660,6 +663,9 @@ static int process_options(int argc, char *argv[]) icosohedron_subdivision = 0; } break; + case 'n': + normalmapname = optarg; + break; case 'h': usage(program); default: @@ -776,6 +782,10 @@ int main(int argc, char *argv[]) atmosphere_mesh = mesh_unit_icosphere(icosohedron_subdivision); material_init_textured_planet(&planet_material); planet_material.textured_planet.texture_id = load_cubemap_textures(0, planetname); + if (normalmapname) + planet_material.textured_planet.normalmap_id = load_cubemap_textures(0, normalmapname); + else + planet_material.textured_planet.normalmap_id = -1; planet_material.textured_planet.ring_material = 0; material_init_atmosphere(&atmosphere_material); } else { diff --git a/share/snis/shader/textured-cubemap-and-lit-per-pixel.shader b/share/snis/shader/textured-cubemap-and-lit-per-pixel.shader index b8c97ce8..2be32df5 100644 --- a/share/snis/shader/textured-cubemap-and-lit-per-pixel.shader +++ b/share/snis/shader/textured-cubemap-and-lit-per-pixel.shader @@ -1,5 +1,6 @@ /* Copyright (C) 2014 Jeremy Van Grinsven + Copyright (C) 2016 Stephen M. Cameron This file is part of Spacenerds In Space. @@ -17,8 +18,8 @@ along with Spacenerds in Space; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Author: - Jeremy Van Grinsven + Authors: + Jeremy Van Grinsven, Stephen M. Cameron */ #if !defined(AMBIENT) @@ -29,22 +30,36 @@ varying vec3 v_Position; varying vec3 v_Normal; varying vec3 v_TexCoord; +#if defined(USE_NORMAL_MAP) +varying vec3 v_Tangent; +varying vec3 v_BiTangent; +varying mat3 tbn; +#endif + #if defined(INCLUDE_VS) uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix. uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix. uniform mat3 u_NormalMatrix; attribute vec4 a_Position; // Per-vertex position information we will pass in. - attribute vec3 a_Normal; // Per-vertex normal information we will pass in. + attribute vec3 a_Normal; // Per-vertex normal, tangent, and bitangent information we will pass in. +#if defined(USE_NORMAL_MAP) + attribute vec3 a_Tangent; + attribute vec3 a_BiTangent; +#endif void main() { /* Transform the vertex into eye space. */ v_Position = vec3(u_MVMatrix * a_Position); - /* Transform the normal's orientation into eye space. */ - v_Normal = normalize(u_NormalMatrix * a_Normal); - + /* Transform the normal's, Tangent's and BiTangent's orientations into eye space. */ + v_Normal = normalize(u_NormalMatrix * a_Normal); +#if defined(USE_NORMAL_MAP) + v_Tangent = normalize(u_NormalMatrix * a_Tangent); + v_BiTangent = normalize(u_NormalMatrix * a_BiTangent); + tbn = mat3(v_Tangent, v_BiTangent, v_Normal); +#endif v_TexCoord = a_Position.xyz; /* gl_Position is a special variable used to store the final position. @@ -57,21 +72,28 @@ varying vec3 v_TexCoord; uniform samplerCube u_AlbedoTex; uniform vec4 u_TintColor; uniform vec3 u_LightPos; // The position of the light in eye space. +#if defined(USE_NORMAL_MAP) + uniform samplerCube u_NormalMapTex; +#endif void main() { /* Get a lighting direction vector from the light to the vertex. */ vec3 light_dir = normalize(u_LightPos - v_Position); - /* Calculate the dot product of the light vector and vertex normal. If the normal and light vector are - pointing in the same direction then it will get max illumination. */ - float direct = dot(normalize(v_Normal), light_dir); +#if defined(USE_NORMAL_MAP) + vec3 pixel_normal = tbn * normalize(textureCube(u_NormalMapTex, v_TexCoord).xyz * 2.0 - 1.0); + float normal_map_shadow = max(0.0, dot(pixel_normal, light_dir)); /* make diffuse light atleast ambient */ - float diffuse = max(AMBIENT, direct); - + float diffuse = max(AMBIENT, normal_map_shadow); +#else + /* Calculate the dot product of the light vector and vertex normal. If the normal and light vector are + pointing in the same direction then it will get max illumination. */ + float diffuse = dot(normalize(v_Normal), light_dir); + diffuse = max(AMBIENT, diffuse); +#endif gl_FragColor = textureCube(u_AlbedoTex, v_TexCoord); - gl_FragColor.rgb *= diffuse; /* tint with alpha pre multiply */ diff --git a/share/snis/shader/textured-cubemap-and-lit-per-vertex.shader b/share/snis/shader/textured-cubemap-and-lit-per-vertex.shader index 2ce481e1..60b0f9b8 100644 --- a/share/snis/shader/textured-cubemap-and-lit-per-vertex.shader +++ b/share/snis/shader/textured-cubemap-and-lit-per-vertex.shader @@ -40,6 +40,7 @@ varying vec3 v_LightColor; #if defined(INCLUDE_FS) uniform samplerCube u_AlbedoTex; + uniform samplerCube u_NormalMapTex; uniform vec4 u_TintColor; void main() diff --git a/share/snis/shader/textured-cubemap-and-lit-with-annulus-shadow-per-pixel.shader b/share/snis/shader/textured-cubemap-and-lit-with-annulus-shadow-per-pixel.shader index 355424bc..f4a12edd 100644 --- a/share/snis/shader/textured-cubemap-and-lit-with-annulus-shadow-per-pixel.shader +++ b/share/snis/shader/textured-cubemap-and-lit-with-annulus-shadow-per-pixel.shader @@ -25,21 +25,36 @@ varying vec3 v_Position; varying vec3 v_Normal; varying vec3 v_TexCoord; +#if defined(USE_NORMAL_MAP) +varying vec3 v_Tangent; +varying vec3 v_BiTangent; +varying mat3 tbn; +#endif + #if defined(INCLUDE_VS) uniform mat4 u_MVPMatrix; // A constant representing the combined model/view/projection matrix. uniform mat4 u_MVMatrix; // A constant representing the combined model/view matrix. uniform mat3 u_NormalMatrix; attribute vec4 a_Position; // Per-vertex position information we will pass in. - attribute vec3 a_Normal; // Per-vertex normal information we will pass in. + attribute vec3 a_Normal; // Per-vertex normal, tangent, and bitangent information we will pass in. +#if defined(USE_NORMAL_MAP) + attribute vec3 a_Tangent; + attribute vec3 a_BiTangent; +#endif void main() { /* Transform the vertex into eye space. */ v_Position = vec3(u_MVMatrix * a_Position); - /* Transform the normal's orientation into eye space. */ + /* Transform the normal's, Tangent's and BiTangent's orientations into eye space. */ v_Normal = normalize(u_NormalMatrix * a_Normal); +#if defined(USE_NORMAL_MAP) + v_Tangent = normalize(u_NormalMatrix * a_Tangent); + v_BiTangent = normalize(u_NormalMatrix * a_BiTangent); + tbn = mat3(v_Tangent, v_BiTangent, v_Normal); +#endif v_TexCoord = a_Position.xyz; @@ -53,6 +68,9 @@ varying vec3 v_TexCoord; uniform samplerCube u_AlbedoTex; uniform vec4 u_TintColor; uniform vec3 u_LightPos; // The position of the light in eye space. +#if defined(USE_NORMAL_MAP) + uniform samplerCube u_NormalMapTex; +#endif uniform sampler2D u_AnnulusAlbedoTex; uniform vec3 u_AnnulusCenter; // center of disk in eye space @@ -116,12 +134,16 @@ varying vec3 v_TexCoord; shadow = 1.0 - ring_color.a; } } - +#if defined(USE_NORMAL_MAP) + vec3 pixel_normal = tbn * normalize(textureCube(u_NormalMapTex, v_TexCoord).xyz * 2.0 - 1.0); + float normal_map_shadow = max(0.0, dot(pixel_normal, light_dir)); + float diffuse = max(shadow * normal_map_shadow, AMBIENT); +#else /* make diffuse light atleast ambient */ float diffuse = max(direct * shadow, AMBIENT); +#endif gl_FragColor = textureCube(u_AlbedoTex, v_TexCoord); - gl_FragColor.rgb *= diffuse; /* tint with alpha pre multiply */ diff --git a/share/snis/solarsystems/default/assets.txt b/share/snis/solarsystems/default/assets.txt index 9c5b194b..42f446c1 100644 --- a/share/snis/solarsystems/default/assets.txt +++ b/share/snis/solarsystems/default/assets.txt @@ -1,11 +1,11 @@ # Locations of assets for "default" solar system planet texture count: 5 -planet texture: ../../textures/planet-texture0- gas-giant -planet texture: ../../textures/planet-texture1- gas-giant -planet texture: ../../textures/planet-texture2- gas-giant -planet texture: ../../textures/planet-texture3- gas-giant -planet texture: ../../textures/planet-texture4- earth-like +planet texture: ../../textures/planet-texture0- no-normal-map gas-giant +planet texture: ../../textures/planet-texture1- no-normal-map gas-giant +planet texture: ../../textures/planet-texture2- no-normal-map gas-giant +planet texture: ../../textures/planet-texture3- no-normal-map gas-giant +planet texture: ../../textures/planet-texture4- no-normal-map earth-like sun texture: ../../textures/sun.png diff --git a/snis_client.c b/snis_client.c index fd9cb2f7..8b32a4af 100644 --- a/snis_client.c +++ b/snis_client.c @@ -12016,6 +12016,12 @@ static void load_per_solarsystem_textures() material_init_textured_planet(&planet_material[i]); planet_material[i].textured_planet.texture_id = load_cubemap_textures(0, path); planet_material[i].textured_planet.ring_material = 0; + if (strcmp(solarsystem_assets->planet_normalmap[i], "no-normal-map") == 0) { + planet_material[i].textured_planet.normalmap_id = -1; + } else { + sprintf(path, "solarsystems/%s/%s", solarsystem_name, solarsystem_assets->planet_normalmap[i]); + planet_material[i].textured_planet.normalmap_id = load_cubemap_textures(0, path); + } int k; for (k = 0; k < NPLANETARY_RING_MATERIALS; k++) { @@ -12743,7 +12749,7 @@ static struct mesh *snis_read_model(char *directory, char *filename) if (!m) { printf("Failed to read model from file '%s'\n", path); printf("Assume form of . . . A SPHERICAL COW!\n"); - m = mesh_unit_icosphere(3); + m = mesh_unit_spherified_cube(8); if (!m) printf("...or possibly a spherical cow dump!\n"); else @@ -12801,7 +12807,7 @@ static void init_meshes() printf("zzz radius %d = %f\n", i, mesh_compute_radius(asteroid_mesh[i])); } - sphere_mesh = mesh_unit_icosphere(4); + sphere_mesh = mesh_unit_spherified_cube(16); warp_tunnel_mesh = mesh_tube(XKNOWN_DIM, 450.0, 20); planetary_ring_mesh = mesh_fabricate_planetary_ring(MIN_RING_RADIUS, MAX_RING_RADIUS); diff --git a/solarsystem_config.c b/solarsystem_config.c index ef8c0240..a3e9a901 100644 --- a/solarsystem_config.c +++ b/solarsystem_config.c @@ -99,6 +99,8 @@ struct solarsystem_asset_spec *solarsystem_asset_spec_read(char *filename) a->nplanet_textures = value; a->planet_texture = malloc(sizeof(a->planet_texture[0]) * value); memset(a->planet_texture, 0, sizeof(a->planet_texture[0]) * value); + a->planet_normalmap = malloc(sizeof(a->planet_normalmap[0]) * value); + memset(a->planet_normalmap, 0, sizeof(a->planet_normalmap[0]) * value); a->planet_type = malloc(sizeof(a->planet_type[0]) * value); memset(a->planet_type, 0, sizeof(a->planet_type[0]) * value); continue; @@ -112,18 +114,34 @@ struct solarsystem_asset_spec *solarsystem_asset_spec_read(char *filename) fprintf(stderr, "%s:line %d: too many planet textures.\n", filename, ln); goto bad_line; } - char word1[1000], word2[1000]; + char word1[1000], word2[1000], word3[1000]; field = get_field(line); + rc = sscanf(field, "%s %s %s", word1, word2, word3); + if (rc == 3) { + a->planet_texture[planet_textures_read] = strdup(word1); + a->planet_normalmap[planet_textures_read] = strdup(word2); + a->planet_type[planet_textures_read] = strdup(word3); + planet_textures_read++; + continue; + } rc = sscanf(field, "%s %s", word1, word2); - if (rc != 2) { - fprintf(stderr, "%s:line %d: expected planet texture prefix and planet type\n", + if (rc == 2) { /* old style, no normal map */ + a->planet_texture[planet_textures_read] = strdup(word1); + a->planet_normalmap[planet_textures_read] = strdup("no-normal-map"); + a->planet_type[planet_textures_read] = strdup(word3); + planet_textures_read++; + fprintf(stderr, + "%s:line %d: expected planet texture prefix, planet normal map prefix, and planet type\n", filename, ln); - goto bad_line; + fprintf(stderr, + "%s:line %d: Assuming old style without normal map (use no-normal-map to suppress this message).\n", + filename, ln); + continue; } - a->planet_texture[planet_textures_read] = strdup(word1); - a->planet_type[planet_textures_read] = strdup(word2); - planet_textures_read++; - continue; + fprintf(stderr, + "%s:line %d: expected planet texture prefix, [ planet normal map prefix ], and planet type\n", + filename, ln); + goto bad_line; } else if (has_prefix("sun texture:", line)) { if (a->sun_texture != NULL) { fprintf(stderr, "%s:line %d: too many sun textures.\n", filename, ln); diff --git a/solarsystem_config.h b/solarsystem_config.h index 8bd9a405..45e2bac7 100644 --- a/solarsystem_config.h +++ b/solarsystem_config.h @@ -27,6 +27,7 @@ struct solarsystem_asset_spec { char *skybox_prefix; int nplanet_textures; char **planet_texture; + char **planet_normalmap; char **planet_type; };