#include #include #include #include "glad/gl.h" #include "directxmath/directxmath.h" #include "opengl.h" #include "file.h" #include "view.h" #include "minecraft.h" #include "minecraft_data.inc" #include "new.h" #include "world/world.h" namespace minecraft { struct location { struct { unsigned int position; unsigned int normal; unsigned int texture; unsigned int block_position; unsigned int block_id; unsigned int data; unsigned int texture_id; unsigned int special; } attrib; struct { unsigned int transform; unsigned int terrain_sampler; } uniform; }; static unsigned int program; static location location; static unsigned int vertex_array_object; static unsigned int per_vertex_buffer; static const int per_instance_size = (3 + 1 + 3 + 1) * 2; static const int per_vertex_size = (3 + 3 + 2) * 2; static unsigned int index_buffer; static unsigned int texture; static const int world_count = 2; static world::state world_state[world_count]; world::state * current_world; void load_program() { program = compile_from_files("shader/minecraft.vert", NULL, "shader/minecraft.frag"); location.attrib.position = glGetAttribLocation(program, "Position"); location.attrib.normal = glGetAttribLocation(program, "Normal"); location.attrib.texture = glGetAttribLocation(program, "Texture"); location.attrib.block_position = glGetAttribLocation(program, "BlockPosition"); location.attrib.block_id = glGetAttribLocation(program, "BlockID"); location.attrib.data = glGetAttribLocation(program, "Data"); location.attrib.texture_id = glGetAttribLocation(program, "TextureID"); location.attrib.special = glGetAttribLocation(program, "Special"); printf("minecraft program:\n"); printf(" attributes:\n position %u\n normal %u\n texture %u\n block_position %u\n block_id %u\n data %u\n texture_id %u\n special %u\n", location.attrib.position, location.attrib.normal, location.attrib.texture, location.attrib.block_position, location.attrib.block_id, location.attrib.data, location.attrib.texture_id, location.attrib.special); location.uniform.transform = glGetUniformLocation(program, "Transform"); location.uniform.terrain_sampler = glGetUniformLocation(program, "TerrainSampler"); printf(" uniforms:\n transform %u\n terrain_sampler %u\n", location.uniform.transform, location.uniform.terrain_sampler); } void load_vertex_attributes() { glGenVertexArrays(1, &vertex_array_object); glBindVertexArray(vertex_array_object); glVertexBindingDivisor(0, 0); glVertexBindingDivisor(1, 1); glEnableVertexAttribArray(location.attrib.position); glVertexAttribFormat(location.attrib.position, 3, GL_HALF_FLOAT, GL_FALSE, 0); glVertexAttribBinding(location.attrib.position, 0); glEnableVertexAttribArray(location.attrib.normal); glVertexAttribFormat(location.attrib.normal, 3, GL_HALF_FLOAT, GL_FALSE, 6); glVertexAttribBinding(location.attrib.normal, 0); glEnableVertexAttribArray(location.attrib.texture); glVertexAttribFormat(location.attrib.texture, 2, GL_HALF_FLOAT, GL_FALSE, 12); glVertexAttribBinding(location.attrib.texture, 0); glEnableVertexAttribArray(location.attrib.block_position); glVertexAttribFormat(location.attrib.block_position, 3, GL_SHORT, GL_FALSE, 0); glVertexAttribBinding(location.attrib.block_position, 1); glEnableVertexAttribArray(location.attrib.block_id); glVertexAttribIFormat(location.attrib.block_id, 1, GL_SHORT, 8); glVertexAttribBinding(location.attrib.block_id, 1); glEnableVertexAttribArray(location.attrib.data); glVertexAttribIFormat(location.attrib.data, 1, GL_SHORT, 10); glVertexAttribBinding(location.attrib.data, 1); glEnableVertexAttribArray(location.attrib.texture_id); glVertexAttribIFormat(location.attrib.texture_id, 1, GL_SHORT, 12); glVertexAttribBinding(location.attrib.texture_id, 1); glEnableVertexAttribArray(location.attrib.special); glVertexAttribIFormat(location.attrib.special, 1, GL_SHORT, 14); glVertexAttribBinding(location.attrib.special, 1); glBindVertexArray(0); } void load_per_vertex_buffer() { glGenBuffers(1, &per_vertex_buffer); int vertex_buffer_data_size; void * vertex_buffer_data = read_file("minecraft/per_vertex.vtx", &vertex_buffer_data_size); glBindBuffer(GL_ARRAY_BUFFER, per_vertex_buffer); glBufferData(GL_ARRAY_BUFFER, vertex_buffer_data_size, vertex_buffer_data, GL_STATIC_DRAW); free(vertex_buffer_data); glBindBuffer(GL_ARRAY_BUFFER, 0); } void load_index_buffer() { glGenBuffers(1, &index_buffer); int index_buffer_data_size; void * index_buffer_data = read_file("minecraft/configuration.idx", &index_buffer_data_size); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_data_size, index_buffer_data, GL_STATIC_DRAW); free(index_buffer_data); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } void load_texture() { glGenTextures(1, &texture); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); 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); int texture_data_size; void * texture_data = read_file("minecraft/terrain2.data", &texture_data_size); assert(texture_data != NULL); int width = 128; int height = 128; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture_data); free(texture_data); glBindTexture(GL_TEXTURE_2D, 0); } ////////////////////////////////////////////////////////////////////// // per-world load ////////////////////////////////////////////////////////////////////// namespace per_world { static void load_instance_cfg(char const * path, world::instance_cfg_entry * entries) { int data_size; void * data = read_file(path, &data_size); printf("%s %d %d %ld\n", path, data_size, world::instance_cfg_length, (sizeof (struct world::instance_cfg_entry))); assert(data_size == (sizeof (struct world::instance_cfg_entry)) * world::instance_cfg_length); memcpy(entries, data, data_size); } static void load_per_instance_vertex_buffer(char const * path, unsigned int vertex_buffer) { int vertex_buffer_data_size; void * vertex_buffer_data = read_file(path, &vertex_buffer_data_size); // vertex_paths[i].vtx glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); //per_instance_vertex_buffers[i] glBufferData(GL_ARRAY_BUFFER, vertex_buffer_data_size, vertex_buffer_data, GL_STATIC_DRAW); free(vertex_buffer_data); glBindBuffer(GL_ARRAY_BUFFER, 0); } static void load_regions(world::descriptor const * const descriptor, world::region * region) { unsigned int per_instance_vertex_buffers[descriptor->region_count]; glGenBuffers(descriptor->region_count, per_instance_vertex_buffers); for (int i = 0; i < descriptor->region_count; i++) { // vtx load_per_instance_vertex_buffer(descriptor->vertex_paths[i].vtx, per_instance_vertex_buffers[i]); region[i].per_instance_vertex_buffer = per_instance_vertex_buffers[i]; // cfg load_instance_cfg(descriptor->vertex_paths[i].cfg, region[i].instance_cfg); } } void load_world(world::descriptor const * const descriptor, world::state & state) { state.descriptor = descriptor; state.region = New(descriptor->region_count); load_regions(descriptor, state.region); state.light_uniform_buffer = load_uniform_buffer(descriptor->lights_path); // collision data world::entry_table::load_entry_table(descriptor->entry_table_path, &state.entry_table, &state.entry_table_length, descriptor->hash_func); } } void load() { ////////////////////////////////////////////////////////////////////// // program ////////////////////////////////////////////////////////////////////// load_program(); load_vertex_attributes(); ////////////////////////////////////////////////////////////////////// // vertex/index buffers ////////////////////////////////////////////////////////////////////// // per-vertex buffer load_per_vertex_buffer(); // index buffer load_index_buffer(); ////////////////////////////////////////////////////////////////////// // textures ////////////////////////////////////////////////////////////////////// load_texture(); ////////////////////////////////////////////////////////////////////// // worlds ////////////////////////////////////////////////////////////////////// for (int i = 0; i < world_count; i++) { if (i == 0) continue; per_world::load_world(&world::descriptors[i], world_state[i]); } current_world = &world_state[world::world_id::GRANDLECTURN]; } static inline int popcount(int x) { return __builtin_popcount(x); } void draw() { glUseProgram(program); glBlendFunc(GL_ONE, GL_ZERO); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_GREATER); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); glUniformMatrix4fv(location.uniform.transform, 1, false, (float *)&view::state.float_transform); glUniform1i(location.uniform.terrain_sampler, 0); //glEnable(GL_CULL_FACE); //glCullFace(GL_FRONT); //glFrontFace(GL_CCW); glBindVertexArray(vertex_array_object); glBindVertexBuffer(0, per_vertex_buffer, 0, per_vertex_size); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); for (int region_index = 0; region_index < current_world->descriptor->region_count; region_index++) { glBindVertexBuffer(1, current_world->region[region_index].per_instance_vertex_buffer, 0, per_instance_size); ////////////////////////////////////////////////////////////////////// // cube blocks ////////////////////////////////////////////////////////////////////// for (int configuration = 1; configuration < 64; configuration++) { int element_count = 6 * popcount(configuration); const void * indices = (void *)(2 * (ptrdiff_t)index_buffer_configuration_offsets[configuration]); // index into configuration.idx int instance_count = current_world->region[region_index].instance_cfg[configuration].count; int base_instance = current_world->region[region_index].instance_cfg[configuration].offset / per_instance_size; // index into region.0.0.instance.vtx if (instance_count == 0) continue; glDrawElementsInstancedBaseInstance(GL_TRIANGLES, element_count, GL_UNSIGNED_SHORT, indices, instance_count, base_instance); } ////////////////////////////////////////////////////////////////////// // custom blocks ////////////////////////////////////////////////////////////////////// for (int i = 0; i < world::custom_block_types; i++) { int element_count = index_buffer_custom_offsets[i].count; const void * indices = (void *)(2 * (ptrdiff_t)index_buffer_custom_offsets[i].offset); int instance_count = current_world->region[region_index].instance_cfg[64 + i].count; int base_instance = current_world->region[region_index].instance_cfg[64 + i].offset / per_instance_size; // index into region.0.0.instance.vtx if (instance_count == 0) continue; glDrawElementsInstancedBaseInstance(GL_TRIANGLES, element_count, GL_UNSIGNED_SHORT, indices, instance_count, base_instance); } } } }