draw flames on torches

This commit is contained in:
Zack Buhman 2026-03-19 20:09:06 -05:00
parent c299825859
commit ce7c4c4cc6
17 changed files with 211 additions and 12 deletions

View File

@ -47,6 +47,7 @@ OBJS = \
src/collada/animate.o \
src/lua_api.o \
src/pixel_line_art.o \
src/flame.o \
data/scenes/ship20/ship20.o \
data/scenes/noodle/noodle.o \
data/scenes/shadow_test/shadow_test.o \

7
include/flame.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
namespace flame {
void load_program();
void load_texture();
void draw(unsigned int light_uniform_buffer, int light_count);
}

View File

@ -1,5 +1,7 @@
#pragma once
#include "directxmath/directxmath.h"
namespace view {
struct view_state {
// positions

BIN
minecraft/flame.data Normal file

Binary file not shown.

View File

@ -113,8 +113,8 @@ def pack_instance_data(position, block_id, block_data, texture_id):
block_id, block_data, texture_id, special)
return packed
def pack_light_data(position, block_id):
packed = struct.pack("<ffff", position[0], position[1], position[2], block_id)
def pack_light_data(position, block_id, block_data):
packed = struct.pack("<ffff", position[0], position[1], position[2], block_data)
return packed
def build_block_instances(blocks):
@ -174,7 +174,7 @@ def build_block_instances(blocks):
with open(f"{data_path}.lights.vtx", "wb") as f:
for position, block_id, block_data in light_sources:
packed = pack_light_data(position, block_id)
packed = pack_light_data(position, block_id, block_data)
f.write(packed)
def level_table_from_path(level_table, path):

28
shader/flame.frag Normal file
View File

@ -0,0 +1,28 @@
#version 430 core
in vec4 PixelTexture;
layout (location = 0, binding = 0) uniform sampler2D FlameSampler;
layout (location = 1) uniform int Frame;
layout (location = 0) out vec3 Position;
layout (location = 1) out vec4 Normal;
layout (location = 2) out vec3 Color;
layout (location = 3) out vec4 Block;
const float frames = 1.0 / 4.0;
void main()
{
vec2 coord = vec2(PixelTexture.x, 1.0 - PixelTexture.y) * vec2(1, frames) + vec2(0, frames * Frame);
vec4 texture_color = texture(FlameSampler, coord);
if (texture_color.w == 0) {
discard;
return;
}
Position = vec3(0, 0, 0);
Normal = vec4(0, 0, 0, 0);
Color = vec3(texture_color.xyz);
Block = vec4(-1, -1, -1, -1);
}

42
shader/flame.vert Normal file
View File

@ -0,0 +1,42 @@
#version 430 core
layout (location = 2) uniform mat4 Transform;
layout (location = 3) uniform vec3 Eye;
const vec2 vtx[4] = vec2[](vec2(-1.0, 1.0), // tl
vec2( 1.0, 1.0), // tr
vec2( 1.0, -1.0), // br
vec2(-1.0, -1.0)); // bl
out vec4 PixelTexture;
const vec3 up = vec3(0, 0, 1);
layout (std140, binding = 0) uniform Lights
{
vec4 light[256];
};
void main()
{
vec2 vertex = vtx[gl_VertexID];
PixelTexture = vec4(vertex * 0.5 + 0.5, 0, 0);
vec4 light_instance = light[gl_InstanceID];
bool is_candle = light_instance.w == 5;
float z_offset = is_candle ? 0.17 : 0.5;
float y_offset = float(light_instance.w == 4) - float(light_instance.w == 3);
float x_offset = float(light_instance.w == 2) - float(light_instance.w == 1);
float size = is_candle ? 0.1 : 0.25;
vec3 global_position = light_instance.xzy + vec3(x_offset * 0.2, y_offset * 0.2, z_offset);
vec3 direction = global_position - Eye;
vec3 normal = normalize(vec3(direction.x, direction.y, 0));
vec3 right = normalize(cross(normal, up));
vec3 position = global_position + (vertex.x * right + vertex.y * up) * size;
gl_Position = Transform * vec4(position, 1);
}

View File

@ -41,5 +41,8 @@ void main()
//vec3 light_direction = normalize(Eye.xyz - position.xyz);
//float diffuse = max(dot(normal.xyz, light_direction), 0.0);
if (normal == vec4(0, 0, 0, 0))
out_color = color.xyz;
Color = vec4(out_color, 1.0);
}

View File

@ -46,7 +46,7 @@ void main()
vs_out.Position = position;
vs_out.BlockPosition = BlockPosition;
vs_out.Normal = Normal;
vs_out.Normal = orientation(Normal);
vs_out.Texture = Texture;
vs_out.BlockID = BlockID;
vs_out.Data = Data;

106
src/flame.cpp Normal file
View File

@ -0,0 +1,106 @@
#include <assert.h>
#include <stdlib.h>
#include "glad/gl.h"
#include "file.h"
#include "opengl.h"
#include "flame.h"
#include "view.h"
extern unsigned int quad_index_buffer;
extern unsigned int empty_vertex_array_object;
namespace flame {
static unsigned int program;
static unsigned int flame_texture;
static unsigned int vertex_array_object;
const int per_instance_size = 4 * (sizeof (float));
struct layout {
struct {
unsigned int flame_sampler;
unsigned int frame;
unsigned int transform;
unsigned int eye;
} uniform;
struct {
unsigned int lights;
} binding;
};
layout layout = {
.uniform = {
.flame_sampler = 0,
.frame = 1,
.transform = 2,
.eye = 3,
},
.binding = {
.lights = 0,
},
};
void load_program()
{
program = compile_from_files("shader/flame.vert",
nullptr,
"shader/flame.frag");
}
void load_texture()
{
unsigned int 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/flame.data", &texture_data_size);
assert(texture_data != nullptr);
int width = 16;
int height = 80;
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);
flame_texture = texture;
}
static int frame = 0;
void draw(unsigned int light_uniform_buffer, int light_count)
{
glUseProgram(program);
glBlendFunc(GL_ONE, GL_ZERO);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_GREATER);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, flame_texture);
glUniform1i(layout.uniform.frame, (frame / 20) % 4);
frame++;
glUniformMatrix4fv(layout.uniform.transform, 1, false, (float *)&view::state.float_transform);
XMFLOAT3 eye;
XMStoreFloat3(&eye, view::state.eye);
glUniform3fv(layout.uniform.eye, 1, (float *)&eye);
glBindBufferBase(GL_UNIFORM_BUFFER, layout.binding.lights, light_uniform_buffer);
glBindVertexArray(empty_vertex_array_object);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_index_buffer);
glDrawElementsInstanced(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, (void *)0, light_count);
}
}

View File

@ -101,9 +101,9 @@ namespace hud {
y += ter_best.desc->glyph_height;
*/
y = draw_vector(ter_best, buf, y, "eye", view::state.eye);
y = draw_vector(ter_best, buf, y, "at", view::state.at);
y = draw_vector(ter_best, buf, y, "forward", view::state.forward);
y = draw_vector(ter_best, buf, y, "eye", XMVectorSetW(view::state.eye, 0));
y = draw_vector(ter_best, buf, y, "at", XMVectorSetW(view::state.at, 0));
y = draw_vector(ter_best, buf, y, "forward", XMVectorSetW(view::state.forward, 0));
labeled_value<float>(buf, "pitch: ", "%.4f", view::state.pitch);
font::draw_string(ter_best, buf, 10, y);

View File

@ -25,6 +25,7 @@
#include "collada/types.h"
#include "collada/instance_types.h"
#include "pixel_line_art.h"
#include "flame.h"
#include "world/entry_table.h"
#include "world/world.h"
@ -195,6 +196,13 @@ void load(const char * source_path)
//node_at = scene_state.find_node_by_name("Camera001.Target");
//assert(node_at != nullptr);
//////////////////////////////////////////////////////////////////////
// flame
//////////////////////////////////////////////////////////////////////
flame::load_program();
flame::load_texture();
}
void update_keyboard(int up, int down, int left, int right,
@ -418,13 +426,15 @@ void draw()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
minecraft::draw();
//draw_line();
non_block::draw();
flame::draw(minecraft::current_world->light_uniform_buffer,
minecraft::current_world->light_count);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
lighting::draw(minecraft::current_world->light_uniform_buffer,
minecraft::current_world->light_count);
//draw_quad();

View File

@ -97,14 +97,14 @@ namespace view {
state.up = XMVectorSet(0.0f, 0.0f, 1.0f, 0.0f);
state.fov = 1.5;
state.pitch = -0.7;
state.pitch = -0.5520;
state.forward = XMVector3Normalize(XMVectorSet(-0.64, 0.77, 0, 0));
state.forward = XMVector3Normalize(XMVectorSet(0.66, -0.75, 0, 0));
state.normal = get_normal(); // on forward change
state.direction = get_direction(); // on forward/normal/pitch change
// position
state.eye = XMVectorSet(-45.5f, 43.25f, 63.0f, 1);
state.eye = XMVectorSet(4.71f, 65.30, 57.92, 1);
state.at = state.eye + state.direction * at_distance;
//state.at = XMVectorSet(0, 0, 0, 1);
//state.eye = XMVectorSet(0, -100, 0, 1);