#include "gl_local.h"
#include "render_mesh.h"
struct SH1 shadelight;
ALIAS_GL_SHADER(vertex,
code(
layout(location = 0) out vec2 out_st;
layout(location = 1) out vec3 out_normal;
mat3 quaternion_to_matrix(vec4 q) {
vec4 qn = normalize(q);
vec4 q2 = qn * 2;
float wy = q2.y * qn.w;
float wz = q2.z * qn.w;
float xy = q2.y * qn.x;
float xz = q2.z * qn.x;
float yy = q2.y * qn.y;
float zz = q2.z * qn.z;
vec3 normal = vec3(1 - (yy + zz), xy + wz, xz - wy);
float wx = q2.x * qn.w;
float xx = q2.x * qn.x;
float yz = q2.z * qn.y;
vec3 tangent = vec3(xy - wz, 1 - (xx + zz), yz + wx);
vec3 bitangent = sign(q.w) * cross(normal, tangent);
return mat3(tangent, bitangent, normal);
}
),
main(
gl_Position = u_projection_matrix * u_view_matrix * u_model_matrix * vec4(in_position, 1);
out_st = in_st;
mat3 tbn = quaternion_to_matrix(in_quaternion);
out_normal = tbn[2];
)
)
ALIAS_GL_SHADER(fragment,
code(
layout(location = 0) in vec2 in_st;
layout(location = 1) in vec3 in_normal;
layout(location = 0) out vec4 out_color;
float do_sh1(float r0, vec3 r1, vec3 normal) {
float r1_length = length(r1);
vec3 r1_normalized = r1 / r1_length;
float q = 0.5 * (1 + dot(r1_normalized, normal));
float r1_length_over_r0 = r1_length / r0;
float p = 1 + 2 * r1_length_over_r0;
float a = (1 - r1_length_over_r0) / (1 + r1_length_over_r0);
return r0 * (1 + (1 - a) * (p + 1) * pow(q, p));
}
),
main(
vec3 albedo_map = texture(u_albedo_map, in_st).rgb;
vec3 normal = in_normal;
vec3 lightmap = vec3(do_sh1(u_light_rgb0.r, u_light_r1, normal),
do_sh1(u_light_rgb0.g, u_light_g1, normal),
do_sh1(u_light_rgb0.b, u_light_b1, normal));
out_color = vec4(albedo_map * lightmap * 2, 1);
)
)
#define VERTEX_FORMAT \
.attribute[0] = {0, alias_memory_Format_Float32, 3, "position", 0}, \
.attribute[1] = {1, alias_memory_Format_Unorm16, 2, "st", 0}, \
.attribute[2] = {1, alias_memory_Format_Snorm16, 4, "quaternion", 4}, .binding[0] = {sizeof(float) * 3, 0}, \
.binding[1] = {sizeof(uint16_t) * 2 + sizeof(int16_t) * 4, 0}
#define UNIFORMS_FORMAT \
.uniform[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_rgb0"}, \
.uniform[1] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_r1"}, \
.uniform[2] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_g1"}, \
.uniform[3] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_float3, "light_b1"}, \
.global[0] = {ALIAS_GL_VERTEX_BIT, &u_model_matrix}, .global[1] = {ALIAS_GL_VERTEX_BIT, &u_view_matrix}, \
.global[2] = {ALIAS_GL_VERTEX_BIT, &u_projection_matrix}
#define IMAGES_FORMAT .image[0] = {ALIAS_GL_FRAGMENT_BIT, alias_gl_Type_sampler2D, "albedo_map"}
#define DRAW_STATE \
.primitive = GL_TRIANGLES, VERTEX_FORMAT, UNIFORMS_FORMAT, IMAGES_FORMAT, .fragment_shader = &fragment_shader
#define NO_SHELL .vertex_shader = &vertex_shader
#define SHELL .vertex_shader = &vertex_shader_shell
#define OPAQUE .depth_mask = true, .depth_test_enable = true
#define TRANSPARENT \
.depth_mask = false, .depth_test_enable = true, .blend_enable = true, .blend_src_factor = GL_SRC_ALPHA, \
.blend_dst_factor = GL_ONE_MINUS_SRC_ALPHA
#define NO_DEPTH_HACK .depth_range_min = 0, .depth_range_max = 1
#define DEPTH_HACK .depth_range_min = 0, .depth_range_max = 0.3
static struct alias_gl_DrawState draw_state_opaque = {DRAW_STATE, NO_SHELL, OPAQUE, NO_DEPTH_HACK};
static struct alias_gl_DrawState draw_state_opaque_depthhack = {DRAW_STATE, NO_SHELL, OPAQUE, DEPTH_HACK};
static struct alias_gl_DrawState draw_state_transparent = {DRAW_STATE, NO_SHELL, TRANSPARENT, NO_DEPTH_HACK};
static struct alias_gl_DrawState draw_state_transparent_depthhack = {DRAW_STATE, NO_SHELL, TRANSPARENT, DEPTH_HACK};
void R_DrawAliasModel(entity_t *e, model_t *model) {
int i;
image_t *skin;
if(e->flags & RF_WEAPONMODEL && r_lefthand->value == 2)
return;
vec3_t shell_color;
if(currententity->flags & (RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE)) {
if((currententity->flags & RF_SHELL_RED) && (currententity->flags & RF_SHELL_BLUE) &&
(currententity->flags & RF_SHELL_GREEN)) {
for(i = 0; i < 3; i++)
shell_color[i] = 1.0;
} else if(currententity->flags & (RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE)) {
VectorClear(shell_color);
if(currententity->flags & RF_SHELL_RED) {
shell_color[0] = 1.0;
if(currententity->flags & (RF_SHELL_BLUE | RF_SHELL_DOUBLE))
shell_color[2] = 1.0;
} else if(currententity->flags & RF_SHELL_BLUE) {
if(currententity->flags & RF_SHELL_DOUBLE) {
shell_color[1] = 1.0;
shell_color[2] = 1.0;
} else {
shell_color[2] = 1.0;
}
} else if(currententity->flags & RF_SHELL_DOUBLE) {
shell_color[0] = 0.9;
shell_color[1] = 0.7;
}
} else if(currententity->flags & (RF_SHELL_HALF_DAM | RF_SHELL_GREEN)) {
VectorClear(shell_color);
if(currententity->flags & RF_SHELL_HALF_DAM) {
shell_color[0] = 0.56;
shell_color[1] = 0.59;
shell_color[2] = 0.45;
}
if(currententity->flags & RF_SHELL_GREEN) {
shell_color[1] = 1.0;
}
}
shadelight = SH1_FromDirectionalLight(vec3_origin, shell_color);
}
else if(currententity->flags & RF_FULLBRIGHT) {
shadelight = SH1_FromDirectionalLight(vec3_origin, (float[]){1, 1, 1});
} else {
shadelight = R_LightPoint(r_worldmodel[r_newrefdef.cmodel_index], currententity->origin);
if(currententity->flags & RF_WEAPONMODEL) {
SH1_Normalize(shadelight, &r_lightlevel->value);
r_lightlevel->value *= 255;
}
}
if(currententity->flags & RF_MINLIGHT) {
}
if(currententity->flags & RF_GLOW) {
}
if(r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE) {
}
if((currententity->flags & RF_WEAPONMODEL) && (r_lefthand->value == 1.0F)) {
}
alias_matrix_translation((currententity->oldorigin[0] - currententity->origin[0]) * currententity->backlerp,
(currententity->oldorigin[1] - currententity->origin[1]) * currententity->backlerp,
(currententity->oldorigin[2] - currententity->origin[2]) * currententity->backlerp,
u_model_matrix.uniform.data.mat);
e->angles[PITCH] = -e->angles[PITCH]; GL_TransformForEntity(e);
e->angles[PITCH] = -e->angles[PITCH];
if(currententity->skin)
skin = (image_t *)currententity->skin; else {
if(currententity->skinnum >= MAX_MD2SKINS)
skin = model->skins[0];
else {
skin = model->skins[currententity->skinnum];
if(!skin)
skin = model->skins[0];
}
}
if(!skin)
skin = r_notexture;
const struct RenderMesh *render_mesh = (const struct RenderMesh *)model->extradata;
if((currententity->frame >= render_mesh->num_shapes) || (currententity->frame < 0)) {
ri.Con_Printf(PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n", model->name, currententity->frame);
currententity->frame = 0;
currententity->oldframe = 0;
}
if((currententity->oldframe >= render_mesh->num_shapes) || (currententity->oldframe < 0)) {
ri.Con_Printf(PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n", model->name, currententity->oldframe);
currententity->frame = 0;
currententity->oldframe = 0;
}
if(!r_lerpmodels->value)
currententity->backlerp = 0;
struct alias_gl_DrawState *draw_state =
(currententity->flags & RF_TRANSLUCENT)
? ((currententity->flags & RF_DEPTHHACK) ? &draw_state_transparent_depthhack : &draw_state_transparent)
: ((currententity->flags & RF_DEPTHHACK) ? &draw_state_opaque_depthhack : &draw_state_opaque);
{
struct VertexPosition {
float position[3];
};
struct VertexAttribute {
uint16_t st[2];
int16_t quaternion[4];
};
struct alias_gl_Buffer element_vbo =
alias_gl_allocateTemporaryBuffer(GL_ELEMENT_ARRAY_BUFFER, render_mesh->num_indexes * sizeof(uint32_t));
struct alias_gl_Buffer position_vbo =
alias_gl_allocateTemporaryBuffer(GL_ARRAY_BUFFER, render_mesh->num_vertexes * sizeof(struct VertexPosition));
struct alias_gl_Buffer attribute_vbo =
alias_gl_allocateTemporaryBuffer(GL_ARRAY_BUFFER, render_mesh->num_vertexes * sizeof(struct VertexAttribute));
struct RenderMesh_output output = {
.indexes = {.count = render_mesh->num_indexes,
.pointer = (uint32_t *)element_vbo.mapping,
.stride = sizeof(uint32_t),
.type_format = alias_memory_Format_Uint32,
.type_length = 1},
.position = {.count = render_mesh->num_vertexes,
.pointer = &((struct VertexPosition *)position_vbo.mapping)->position[0],
.stride = sizeof(struct VertexPosition),
.type_format = alias_memory_Format_Float32,
.type_length = 3},
.texture_coord_1 = {.count = render_mesh->num_vertexes,
.pointer = &((struct VertexAttribute *)attribute_vbo.mapping)->st[0],
.stride = sizeof(struct VertexAttribute),
.type_format = alias_memory_Format_Unorm16,
.type_length = 2},
.quaternion = {.count = render_mesh->num_vertexes,
.pointer = &((struct VertexAttribute *)attribute_vbo.mapping)->quaternion[0],
.stride = sizeof(struct VertexAttribute),
.type_format = alias_memory_Format_Snorm16,
.type_length = 4},
};
RenderMesh_render_lerp_shaped(render_mesh, &output, currententity->frame, currententity->oldframe,
currententity->backlerp);
struct alias_gl_DrawAssets assets;
alias_memory_clear(&assets, sizeof(assets));
assets.image[0] = skin->texnum;
assets.uniforms[0] =
(struct alias_gl_UniformData){.vec[0] = shadelight.f[0], .vec[1] = shadelight.f[4], .vec[2] = shadelight.f[8]};
assets.uniforms[1] =
(struct alias_gl_UniformData){.vec[0] = shadelight.f[1], .vec[1] = shadelight.f[2], .vec[2] = shadelight.f[3]};
assets.uniforms[2] =
(struct alias_gl_UniformData){.vec[0] = shadelight.f[5], .vec[1] = shadelight.f[6], .vec[2] = shadelight.f[7]};
assets.uniforms[3] =
(struct alias_gl_UniformData){.vec[0] = shadelight.f[9], .vec[1] = shadelight.f[10], .vec[2] = shadelight.f[11]};
assets.element_buffer = &element_vbo;
assets.vertex_buffers[0] = &position_vbo;
assets.vertex_buffers[1] = &attribute_vbo;
alias_gl_drawElements(draw_state, &assets, render_mesh->num_indexes, 1, 0, 0);
}
if((currententity->flags & RF_WEAPONMODEL) && (r_lefthand->value == 1.0F)) {
}
}
void GL_MD2_Load(model_t *mod, struct HunkAllocator *hunk, const void *buffer) {
dmdl_t header = *(const dmdl_t *)buffer;
header.ident = LittleLong(header.ident);
header.version = LittleLong(header.version);
header.skinwidth = LittleLong(header.skinwidth);
header.skinheight = LittleLong(header.skinheight);
header.framesize = LittleLong(header.framesize);
header.num_skins = LittleLong(header.num_skins);
header.num_xyz = LittleLong(header.num_xyz);
header.num_st = LittleLong(header.num_st);
header.num_tris = LittleLong(header.num_tris);
header.num_glcmds = LittleLong(header.num_glcmds);
header.num_frames = LittleLong(header.num_frames);
header.ofs_skins = LittleLong(header.ofs_skins);
header.ofs_st = LittleLong(header.ofs_st);
header.ofs_tris = LittleLong(header.ofs_tris);
header.ofs_frames = LittleLong(header.ofs_frames);
header.ofs_glcmds = LittleLong(header.ofs_glcmds);
header.ofs_end = LittleLong(header.ofs_end);
const dstvert_t *in_st = (const dstvert_t *)(buffer + header.ofs_st);
const dtriangle_t *in_tris = (const dtriangle_t *)(buffer + header.ofs_tris);
uint32_t num_indexes = header.num_tris * 3;
uint32_t *index_remap = malloc(sizeof(*index_remap) * num_indexes);
for(uint32_t i = 0; i < header.num_tris * 3; i++) {
index_remap[i] = UINT32_MAX;
}
for(uint32_t i = 0; i < header.num_tris * 3; i++) {
if(index_remap[i] != UINT32_MAX) {
continue;
}
uint16_t i_index = in_tris[i / 3].index_xyz[i % 3];
uint16_t i_st = in_tris[i / 3].index_st[i % 3];
for(uint32_t j = 0; j < header.num_tris * 3; j++) {
uint16_t j_index = in_tris[j / 3].index_xyz[j % 3];
uint16_t j_st = in_tris[j / 3].index_st[j % 3];
if(i != j && j_index == i_index && j_st == i_st) {
index_remap[j] = i;
}
}
}
uint32_t num_vertexes = 0;
for(uint32_t i = 0; i < header.num_tris * 3; i++) {
if(index_remap[i] != UINT32_MAX) {
continue;
}
num_vertexes++;
}
struct RenderMesh *render_mesh =
allocate_RenderMesh(RENDER_MESH_FLAG_TEXTURE_COORD_1, num_indexes, 1, num_vertexes, header.num_frames, 0, 0);
num_vertexes = 0;
for(uint32_t i = 0; i < header.num_tris * 3; i++) {
if(index_remap[i] != UINT32_MAX) {
continue;
}
render_mesh->indexes[i] = num_vertexes++;
index_remap[i] = i;
}
for(uint32_t i = 0; i < header.num_tris * 3; i++) {
if(index_remap[i] != i) {
render_mesh->indexes[i] = render_mesh->indexes[index_remap[i]];
}
}
for(uint32_t j = 0; j < header.num_frames; j++) {
const daliasframe_t *in_frame = (const daliasframe_t *)(buffer + header.ofs_frames + j * header.framesize);
float scale[3], translate[3];
scale[0] = LittleFloat(in_frame->scale[0]);
scale[1] = LittleFloat(in_frame->scale[1]);
scale[2] = LittleFloat(in_frame->scale[2]);
translate[0] = LittleFloat(in_frame->translate[0]);
translate[1] = LittleFloat(in_frame->translate[1]);
translate[2] = LittleFloat(in_frame->translate[2]);
for(uint32_t i = 0; i < num_indexes; i++) {
uint32_t xyz_index = LittleLong(in_tris[index_remap[i] / 3].index_xyz[index_remap[i] % 3]);
float position[3];
position[0] = in_frame->verts[xyz_index].v[0] * scale[0] + translate[0];
position[1] = in_frame->verts[xyz_index].v[1] * scale[1] + translate[1];
position[2] = in_frame->verts[xyz_index].v[2] * scale[2] + translate[2];
RenderMesh_set_position(render_mesh, j, render_mesh->indexes[i], position);
}
}
float one_over_skin_width = 1.0f / (float)header.skinwidth;
float one_over_skin_height = 1.0f / (float)header.skinheight;
for(uint32_t i = 0; i < num_indexes; i++) {
uint32_t st_index = LittleLong(in_tris[index_remap[i] / 3].index_st[index_remap[i] % 3]);
float st[2];
st[0] = ((float)LittleShort(in_st[st_index].s) + 0.5f) * one_over_skin_width;
st[1] = ((float)LittleShort(in_st[st_index].t) + 0.5f) * one_over_skin_height;
RenderMesh_set_texture_coord_1(render_mesh, render_mesh->indexes[i], st);
}
RenderMesh_generate_vertex_orientations(render_mesh);
for(uint32_t i = 0; i < header.num_skins; i++) {
mod->skins[i] = GL_FindImage((char *)buffer + header.ofs_skins + i * MAX_SKINNAME, it_skin);
}
mod->type = mod_alias;
mod->extradata = render_mesh;
}