diff --git a/include/reign.h b/include/reign.h index 45a318c..65ff395 100644 --- a/include/reign.h +++ b/include/reign.h @@ -217,6 +217,8 @@ struct RE_instance { // Billboards enum RE_draw_type draw_type; + vec3 vertex_pos[4]; + vec2 vertex_uv[4]; // Lights vec3 vec; @@ -260,6 +262,7 @@ bool RE_instance_load_next_motion(struct RE_instance *instance, const char *name bool RE_instance_free_next_motion(struct RE_instance *instance); bool RE_instance_set_mesh_show(struct RE_instance *instance, const char *mesh_name, bool show); bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x, float y, float z); +bool RE_instance_set_vertex_uv(struct RE_instance *instance, int index, float u, float v); int RE_instance_get_bone_index(struct RE_instance *instance, const char *name); bool RE_instance_trans_local_pos_to_world_pos_by_bone(struct RE_instance *instance, int bone, vec3 offset, vec3 out); float RE_instance_calc_height(struct RE_instance *instance, float x, float z); diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 7cd80cc..4ec171e 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -201,8 +201,10 @@ struct RE_renderer { GLint blend_tex; GLint use_blend_texture; - GLuint billboard_vao; - GLuint billboard_attr_buffer; + GLuint billboard_particle_vao; + GLuint billboard_particle_attr_buffer; + GLuint billboard_instance_vao; + GLuint billboard_instance_attr_buffer; struct hash_table *billboard_textures; // cg_no -> struct billboard_texture* uint32_t last_frame_timestamp; diff --git a/src/3d/reign.c b/src/3d/reign.c index 4220526..28549b5 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -53,6 +53,14 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin) instance->use_mag_speed = true; instance->column_height = 1.0f; instance->column_radius = 1.0f; + glm_vec3_copy((vec3){-1.0f, 2.0f, 0.0f}, instance->vertex_pos[0]); + glm_vec3_copy((vec3){-1.0f, 0.0f, 0.0f}, instance->vertex_pos[1]); + glm_vec3_copy((vec3){ 1.0f, 2.0f, 0.0f}, instance->vertex_pos[2]); + glm_vec3_copy((vec3){ 1.0f, 0.0f, 0.0f}, instance->vertex_pos[3]); + glm_vec2_copy((vec2){0.0f, 0.0f}, instance->vertex_uv[0]); + glm_vec2_copy((vec2){0.0f, 1.0f}, instance->vertex_uv[1]); + glm_vec2_copy((vec2){1.0f, 0.0f}, instance->vertex_uv[2]); + glm_vec2_copy((vec2){1.0f, 1.0f}, instance->vertex_uv[3]); glm_mat4_identity(instance->local_transform); glm_mat3_identity(instance->normal_transform); return instance; @@ -610,19 +618,28 @@ bool RE_instance_set_mesh_show(struct RE_instance *instance, const char *mesh_na return false; } +// Converts from the (top-left, top-right, bottom-left, bottom-right) order used +// by the API to the vertex order of the billboard mesh. +static const int billboard_vertex_index[4] = {0, 2, 1, 3}; + bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x, float y, float z) { - if (!instance) + if (!instance || (unsigned)index >= 4) return false; if (instance->type != RE_ITYPE_BILLBOARD) ERROR("not implemented"); - // Hack: This works because SetInstanceVertexPos is only used to scale - // billboards, and SetInstanceScale is not used for billboards. - if (index == 1) { - instance->scale[0] = x; - instance->scale[1] = y / 2.0; - } - return false; + glm_vec3_copy((vec3){x, y, z}, instance->vertex_pos[billboard_vertex_index[index]]); + return true; +} + +bool RE_instance_set_vertex_uv(struct RE_instance *instance, int index, float u, float v) +{ + if (!instance || (unsigned)index >= 4) + return false; + if (instance->type != RE_ITYPE_BILLBOARD) + ERROR("not implemented"); + glm_vec2_copy((vec2){u, v}, instance->vertex_uv[billboard_vertex_index[index]]); + return true; } int RE_instance_get_bone_index(struct RE_instance *instance, const char *name) diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 8fe7179..545ff19 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -166,24 +166,8 @@ static void destroy_outline_renderer(struct outline_renderer *or) glDeleteProgram(or->program); } -static void init_billboard_mesh(struct RE_renderer *r) +static void init_billboard_unused_vertex_attrs(void) { - static const GLfloat vertices[] = { - // x, y, z, u, v - -1.0, 1.0, 0.0, 0.0, 0.0, - -1.0, -1.0, 0.0, 0.0, 1.0, - 1.0, 1.0, 0.0, 1.0, 0.0, - 1.0, -1.0, 0.0, 1.0, 1.0, - }; - glGenVertexArrays(1, &r->billboard_vao); - glBindVertexArray(r->billboard_vao); - glGenBuffers(1, &r->billboard_attr_buffer); - glBindBuffer(GL_ARRAY_BUFFER, r->billboard_attr_buffer); - - glEnableVertexAttribArray(VATTR_POS); - glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0); - glEnableVertexAttribArray(VATTR_UV); - glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12); glDisableVertexAttribArray(VATTR_LIGHT_UV); glVertexAttrib2f(VATTR_LIGHT_UV, 0.0, 0.0); glDisableVertexAttribArray(VATTR_COLOR); @@ -196,8 +180,39 @@ static void init_billboard_mesh(struct RE_renderer *r) glVertexAttribI4i(VATTR_BONE_INDEX, 0, 0, 0, 0); glDisableVertexAttribArray(VATTR_BONE_WEIGHT); glVertexAttrib4f(VATTR_BONE_WEIGHT, 0.0, 0.0, 0.0, 0.0); +} +static void init_billboard_mesh(struct RE_renderer *r) +{ + static const GLfloat vertices[] = { + // x, y, z, u, v + -1.0, 1.0, 0.0, 0.0, 0.0, + -1.0, -1.0, 0.0, 0.0, 1.0, + 1.0, 1.0, 0.0, 1.0, 0.0, + 1.0, -1.0, 0.0, 1.0, 1.0, + }; + glGenBuffers(1, &r->billboard_particle_attr_buffer); + glBindBuffer(GL_ARRAY_BUFFER, r->billboard_particle_attr_buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + glGenBuffers(1, &r->billboard_instance_attr_buffer); + + glGenVertexArrays(1, &r->billboard_particle_vao); + glBindVertexArray(r->billboard_particle_vao); + glBindBuffer(GL_ARRAY_BUFFER, r->billboard_particle_attr_buffer); + glEnableVertexAttribArray(VATTR_POS); + glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0); + glEnableVertexAttribArray(VATTR_UV); + glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12); + init_billboard_unused_vertex_attrs(); + + glGenVertexArrays(1, &r->billboard_instance_vao); + glBindVertexArray(r->billboard_instance_vao); + glBindBuffer(GL_ARRAY_BUFFER, r->billboard_instance_attr_buffer); + glEnableVertexAttribArray(VATTR_POS); + glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0); + glEnableVertexAttribArray(VATTR_UV); + glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12); + init_billboard_unused_vertex_attrs(); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -205,8 +220,10 @@ static void init_billboard_mesh(struct RE_renderer *r) static void destroy_billboard_mesh(struct RE_renderer *r) { - glDeleteVertexArrays(1, &r->billboard_vao); - glDeleteBuffers(1, &r->billboard_attr_buffer); + glDeleteVertexArrays(1, &r->billboard_particle_vao); + glDeleteVertexArrays(1, &r->billboard_instance_vao); + glDeleteBuffers(1, &r->billboard_particle_attr_buffer); + glDeleteBuffers(1, &r->billboard_instance_attr_buffer); } struct RE_renderer *RE_renderer_new(void) @@ -603,8 +620,6 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma glm_mat4_pick3t(view_mat, rot); glm_mat4_ins3(rot, local_transform); glm_scale(local_transform, inst->scale); - // Billboard instances are bottomed at y=0. - glm_translate_y(local_transform, 1.0); mat3 normal_transform; // This should be safe because billboards do not have non-uniform scaling. glm_mat4_pick3(local_transform, normal_transform); @@ -629,7 +644,15 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, bt->texture); glUniform1i(r->texture, 0); - glBindVertexArray(r->billboard_vao); + GLfloat vertices[4][5]; + for (int i = 0; i < 4; i++) { + glm_vec3_copy(inst->vertex_pos[i], vertices[i]); + glm_vec2_copy(inst->vertex_uv[i], vertices[i] + 3); + } + glBindVertexArray(r->billboard_instance_vao); + glBindBuffer(GL_ARRAY_BUFFER, r->billboard_instance_attr_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -649,7 +672,7 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance glActiveTexture(GL_TEXTURE0); glUniform1i(r->texture, 0); - glBindVertexArray(r->billboard_vao); + glBindVertexArray(r->billboard_particle_vao); for (int index = 0; index < pae_obj->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; @@ -742,7 +765,7 @@ static void render_s3de_billboard_particles(struct RE_renderer *r, struct RE_ins } glActiveTexture(GL_TEXTURE0); glUniform1i(r->texture, 0); - glBindVertexArray(r->billboard_vao); + glBindVertexArray(r->billboard_particle_vao); glDisable(GL_CULL_FACE); glBindTexture(GL_TEXTURE_2D, bt->texture); diff --git a/src/hll/ReignEngine.c b/src/hll/ReignEngine.c index a763fde..79ec8c4 100644 --- a/src/hll/ReignEngine.c +++ b/src/hll/ReignEngine.c @@ -2405,7 +2405,11 @@ static bool SealEngine_GetInstanceAngleB(int plugin, int instance, float *angle_ return true; } -//bool SealEngine_SetInstanceVertexUV(int PluginNumber, int InstanceNumber, int Index, float U, float V); +static bool SealEngine_SetInstanceVertexUV(int plugin, int instance, int index, float u, float v) +{ + return RE_instance_set_vertex_uv(get_instance(plugin, instance), index, u, v); +} + //bool SealEngine_GetInstanceDiffuse(int PluginNumber, int InstanceNumber, float *pR, float *pG, float *pB); //bool SealEngine_GetInstanceAmbient(int PluginNumber, int InstanceNumber, float *pR, float *pG, float *pB); @@ -2636,7 +2640,7 @@ HLL_QUIET_UNIMPLEMENTED(false, bool, SealEngine, IsThreadLoadingMode, int Plugin HLL_EXPORT(GetInstanceAngle, SealEngine_GetInstanceAngle), \ HLL_EXPORT(GetInstanceAngleP, SealEngine_GetInstanceAngleP), \ HLL_EXPORT(GetInstanceAngleB, SealEngine_GetInstanceAngleB), \ - HLL_TODO_EXPORT(SetInstanceVertexUV, SealEngine_SetInstanceVertexUV), \ + HLL_EXPORT(SetInstanceVertexUV, SealEngine_SetInstanceVertexUV), \ HLL_TODO_EXPORT(GetInstanceDiffuse, SealEngine_GetInstanceDiffuse), \ HLL_TODO_EXPORT(GetInstanceAmbient, SealEngine_GetInstanceAmbient), \ HLL_EXPORT(GetInstanceAlpha, SealEngine_GetInstanceAlpha), \