/** * Initialize the scene * Set root data directory and load/init required assets */ int init_scene() { /* data root directory is "[tutorials]/data" */ set_datadir(); /* Initialize default FPS camera, FPS cameras automically handle input and smoothing */ vec4f pos; vec4f target; vec3_setf(&pos, 0.0f, 1.0f, -5.0f); vec3_setf(&target, 0.0f, 1.0f, 1.0f); cam_fps_init(&g_cam, &pos, &target, CAM_NEAR, CAM_FAR, math_torad(CAM_FOV)); g_scene = scn_create_scene("main"); if (g_scene == 0) { err_print(__FILE__, __LINE__, "Initializing scene failed"); return FALSE; } /* Activate the scene and the camera */ scn_setactive(g_scene); wld_set_cam(&g_cam.c); /* create default timer */ g_timer = timer_createinstance(TRUE); if (g_timer == NULL) { err_print(__FILE__, __LINE__, "Could not create timer"); return FALSE; } return tut02_load_data(); }
struct aabb* aabb_merge(struct aabb* rb, const struct aabb* b1, const struct aabb* b2) { struct vec4f minpt; struct vec4f maxpt; vec3_setf(&minpt, minf(b1->minpt.x, b2->minpt.x), minf(b1->minpt.y, b2->minpt.y), minf(b1->minpt.z, b2->minpt.z)); vec3_setf(&maxpt, maxf(b1->maxpt.x, b2->maxpt.x), maxf(b1->maxpt.y, b2->maxpt.y), maxf(b1->maxpt.z, b2->maxpt.z)); return aabb_setv(rb, &minpt, &maxpt); }
int sphere_intersects(const struct sphere* s1, const struct sphere* s2) { struct vec3f d; vec3_setf(&d, s2->x - s1->x, s2->y - s1->y, s2->z - s1->z); float l = vec3_dot(&d, &d); float sr = s2->r + s1->r; return (l*l - sr*sr) < EPSILON; }
const struct mat3f* model_loadmat_pq(struct mat3f* rm, const float* pos, const float* quat) { struct vec3f p; struct quat4f q; vec3_setf(&p, pos[0], pos[1], pos[2]); quat_setf(&q, quat[0], quat[1], quat[2], quat[3]); return mat3_set_trans_rot(rm, &p, &q); }
Vector Quat::getEuler() { float rx; float ry; float rz; quat_geteuler(&rx, &ry, &rz, &this->q_); Vector r; vec3_setf(&r.v_, rx, ry, rz); return r; }
const struct vec4f* gfx_csm_get_cascades(const struct mat3f* view) { static struct vec4f cascades[CSM_CASCADE_CNT]; struct vec4f center; for (uint i = 0; i < CSM_CASCADE_CNT; i++) { const struct sphere* s = &g_csm->cascades[i].bounds; vec3_setf(¢er, s->x, s->y, s->z); vec3_transformsrt(¢er, ¢er, view); vec4_setf(&cascades[i], center.x, center.y, center.z, s->r); } return cascades; }
struct sphere* sphere_merge(struct sphere* rs, const struct sphere* s1, const struct sphere* s2) { struct vec4f cdiff; vec3_setf(&cdiff, s2->x - s1->x, s2->y - s1->y, s2->z - s1->z); float rd = s2->r - s1->r; float rd_sqr = rd * rd; float ld_sqr = cdiff.x*cdiff.x + cdiff.y*cdiff.y + cdiff.z*cdiff.z; if (rd_sqr < ld_sqr) { float ld = sqrtf(ld_sqr); struct vec4f c; vec3_setf(&c, s1->x, s1->y, s1->z); float k = (ld + s2->r - s1->r)/(2.0f*ld); vec3_add(&c, &c, vec3_muls(&cdiff, &cdiff, k)); rs->x = c.x; rs->y = c.y; rs->z = c.z; rs->r = (ld + s1->r + s2->r)*0.5f; return rs; } else { if (rd >= 0.0f) return sphere_sets(rs, s2); else return sphere_sets(rs, s1); } }
struct sphere* sphere_xform(struct sphere* rs, const struct sphere* s, const struct mat3f* m) { /* we have to transform radius by scale value of transform matrix * to determine scale value, we find the highest scale component of the matrix */ float xlen = m->m11*m->m11 + m->m12*m->m12 + m->m13*m->m13; float ylen = m->m21*m->m21 + m->m22*m->m22 + m->m23*m->m23; float zlen = m->m31*m->m31 + m->m32*m->m32 + m->m33*m->m33; float isqr_scale = maxf(xlen, ylen); isqr_scale = maxf(isqr_scale, zlen); /* transform center */ struct vec4f c; vec3_setf(&c, s->x, s->y, s->z); vec3_transformsrt(&c, &c, m); return sphere_setf(rs, c.x, c.y, c.z, s->r*sqrtf(isqr_scale)); }
void csm_calc_minsphere(struct sphere* bounds, const struct frustum* f, const struct mat3f* view, const struct mat3f* view_inv) { /* reference: * http://www.gamedev.net/topic/604797-minimum-bounding-sphere-of-a-frustum/ */ struct vec3f a; struct vec3f b; struct vec3f p; struct vec3f tmp; vec3_transformsrt(&a, &f->points[1], view); vec3_transformsrt(&b, &f->points[5], view); float z = (vec3_dot(&b, &b) - vec3_dot(&a, &a))/(2.0f*(b.z - a.z)); vec3_setf(&p, 0.0f, 0.0f, z); vec3_transformsrt(&p, &p, view_inv); sphere_setf(bounds, p.x, p.y, p.z, vec3_len(vec3_sub(&tmp, &f->points[5], &p)) + 0.01f); }
result_t wld_initmgr() { result_t r; r = hashtable_open_create(mem_heap(), &g_wld.stable, 5, 10, 0); if (IS_FAIL(r)) { err_print(__FILE__, __LINE__, "Initializing world manager failed"); return r; } r = arr_create(mem_heap(), &g_wld.sections, sizeof(struct wld_section), 5, 10, 0); if (IS_FAIL(r)) { err_print(__FILE__, __LINE__, "Initializing world manager failed"); return r; } /* camera */ struct vec3f pos; cam_init(&g_wld.default_cam, vec3_setf(&pos, 0.0f, 0.0f, -1.0f), &g_vec3_zero, CAM_NEAR, CAM_FAR, math_torad(CAM_FOV)); g_wld.cam = &g_wld.default_cam; return RET_OK; }
void gfx_csm_prepare(const struct gfx_view_params* params, const struct vec3f* light_dir, const struct aabb* world_bounds) { static const float tolerance = 10.0f; struct vec3f dir; vec3_setv(&dir, light_dir); float texoffset_x = 0.5f + (0.5f/g_csm->shadowmap_size); float texoffset_y = 0.5f + (0.5f/g_csm->shadowmap_size); struct mat3f view_inv; struct mat4f tex_mat; struct mat4f tmp_mat; float splits[CSM_CASCADE_CNT+1]; mat3_setf(&view_inv, params->view.m11, params->view.m21, params->view.m31, params->view.m12, params->view.m22, params->view.m32, params->view.m13, params->view.m23, params->view.m33, params->cam_pos.x, params->cam_pos.y, params->cam_pos.z); mat4_setf(&tex_mat, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, texoffset_x, texoffset_y, 0.0f, 1.0f); float csm_far = minf(CSM_FAR_MAX, params->cam->ffar); csm_split_range(params->cam->fnear, csm_far, splits); /* calculate cascades */ struct frustum f; /* frustum points for cascades */ struct plane vp_planes[6]; for (uint i = 0; i < CSM_CASCADE_CNT; i++) { cam_calc_frustumcorners(params->cam, (struct vec3f*)f.points, &splits[i], &splits[i+1]); csm_calc_minsphere(&g_csm->cascades[i].bounds, &f, ¶ms->view, &view_inv); memcpy(&g_csm->cascade_frusts[i], &f, sizeof(f)); /* cascade matrixes: first we find two extreme points of the world, related to cascade */ struct vec3f scenter; struct ray r; struct plane upper_plane; struct plane lower_plane; struct vec3f upper_pt; struct vec3f lower_pt; struct vec3f xaxis; struct vec3f yaxis; struct vec3f viewpos; struct vec3f tmp; struct vec3f lowerpt_vs; float sr = g_csm->cascades[i].bounds.r; vec3_setf(&scenter, g_csm->cascades[i].bounds.x, g_csm->cascades[i].bounds.y, g_csm->cascades[i].bounds.z); ray_setv(&r, &scenter, &dir); plane_setv(&upper_plane, &g_vec3_unity_neg, fabs(world_bounds->maxpt.y)); plane_setv(&lower_plane, &g_vec3_unity, fabs(world_bounds->minpt.y)); vec3_sub(&upper_pt, &r.pt, vec3_muls(&tmp, &dir, fabs(ray_intersect_plane(&r, &upper_plane)) + tolerance)); vec3_add(&lower_pt, &r.pt, vec3_muls(&tmp, &dir, fabs(ray_intersect_plane(&r, &lower_plane)) + tolerance)); /* view matrix of light view for the cascade : * dir = light_dir * up = (1, 0, 0) * pos = sphere center */ vec3_norm(&xaxis, vec3_cross(&tmp, &g_vec3_unitx, &dir)); vec3_cross(&yaxis, &dir, &xaxis); vec3_sub(&viewpos, &upper_pt, vec3_muls(&tmp, &dir, tolerance)); mat3_setf(&g_csm->cascades[i].view, xaxis.x, yaxis.x, dir.x, xaxis.y, yaxis.y, dir.y, xaxis.z, yaxis.z, dir.z, -vec3_dot(&xaxis, &viewpos), -vec3_dot(&yaxis, &viewpos), -vec3_dot(&dir, &viewpos)); /* orthographic projection matrix for cascade */ vec3_transformsrt(&lowerpt_vs, &lower_pt, &g_csm->cascades[i].view); float nnear = tolerance*0.5f; float nfar = lowerpt_vs.z + sr; csm_calc_orthoproj(&g_csm->cascades[i].proj, sr*2.0f + 1.0f/g_csm->shadowmap_size, sr*2.0f + 1.0f/g_csm->shadowmap_size, nnear, nfar); g_csm->cascades[i].nnear = nnear; g_csm->cascades[i].nfar = nfar; /* calculate final matrix */ mat3_mul4(&g_csm->cascade_vps[i], &g_csm->cascades[i].view, &g_csm->cascades[i].proj); cam_calc_frustumplanes(vp_planes, &g_csm->cascade_vps[i]); csm_calc_cascadeplanes(&g_csm->cascade_planes[i*4], vp_planes, &g_csm->cascade_vps[i]); csm_round_mat(&g_csm->cascade_vps[i], &g_csm->cascade_vps[i], g_csm->shadowmap_size); mat4_mul(&g_csm->shadow_mats[i], mat3_mul4(&tmp_mat, &view_inv, &g_csm->cascade_vps[i]), &tex_mat); } /* caculate shadow area bounds (aabb) */ struct aabb cascade_near; struct aabb cascade_far; aabb_setzero(&g_csm->frustum_bounds); aabb_from_sphere(&cascade_near, &g_csm->cascades[0].bounds); aabb_from_sphere(&cascade_far, &g_csm->cascades[CSM_CASCADE_CNT-1].bounds); aabb_merge(&g_csm->frustum_bounds, &cascade_near, &cascade_far); vec3_setv(&g_csm->light_dir, &dir); }
Vector::Vector(float x, float y, float z) { vec3_setf(&v_, x, y, z); }
int import_anim(const struct import_params* params) { uint flags = 0; if (params->coord == COORD_NONE) flags |= aiProcess_MakeLeftHanded; const struct aiScene* scene = aiImportFileEx(params->in_filepath, flags, NULL); if (scene == NULL) { printf(TERM_BOLDRED "Error: (assimp) %s\n" TERM_RESET, aiGetErrorString()); return FALSE; } if (scene->mNumAnimations == 0) { printf(TERM_BOLDRED "Error: no animation exist in the file '%s'" TERM_RESET, params->in_filepath); return FALSE; } g_anim_coord = params->coord; uint fps = params->anim_fps != 0 ? params->anim_fps : DEFAULT_FPS; uint channel_cnt = 0; uint frame_cnt = 0; int has_scale = FALSE; /* channel count is the sum of all animation channels */ /* frame_cnt is the maximum of all animation channel key counts */ for (uint i = 0; i < scene->mNumAnimations; i++) { const struct aiAnimation* anim = scene->mAnimations[i]; channel_cnt += anim->mNumChannels; for (uint k = 0; k < anim->mNumChannels; k++) { frame_cnt = maxui(frame_cnt, maxui(anim->mChannels[k]->mNumPositionKeys, maxui(anim->mChannels[k]->mNumRotationKeys, anim->mChannels[k]->mNumScalingKeys))); } } if (channel_cnt == 0) { printf(TERM_BOLDRED "Error: no animation channels exist in the file '%s'" TERM_RESET, params->in_filepath); return FALSE; } /* parse my data from assimp data */ struct anim_ext h3danim; memset(&h3danim, 0x00, sizeof(h3danim)); /* channels */ struct anim_channel_ext* h3dchannels = (struct anim_channel_ext*) ALLOC(sizeof(struct anim_channel_ext)*channel_cnt, 0); ASSERT(h3dchannels != NULL); memset(h3dchannels, 0x00, sizeof(struct anim_channel_ext)*channel_cnt); uint channel_offset = 0; for (uint i = 0; i < scene->mNumAnimations; i++) { struct aiAnimation* anim = scene->mAnimations[i]; for (uint k = 0; k < anim->mNumChannels; k++) { struct aiNodeAnim* channel = anim->mChannels[k]; struct anim_channel_ext* h3dchannel = &h3dchannels[k + channel_offset]; str_safecpy(h3dchannel->c.bindto, sizeof(h3dchannel->c.bindto), channel->mNodeName.data); h3dchannel->pos_scale = (struct vec4f*)ALLOC(sizeof(struct vec4f)*frame_cnt, 0); h3dchannel->rot = (struct quat4f*)ALLOC(sizeof(struct quat4f)*frame_cnt, 0); ASSERT(h3dchannel->pos_scale && h3dchannel->rot); struct vec3f pos; struct quat4f quat; float scale = 1.0f; /* fill channel data */ for (uint f = 0; f < frame_cnt; f++) { if (f < channel->mNumPositionKeys) { vec3_setf(&pos, channel->mPositionKeys[f].mValue.x, channel->mPositionKeys[f].mValue.y, channel->mPositionKeys[f].mValue.z); } if (f < channel->mNumRotationKeys) { quat_setf(&quat, channel->mRotationKeys[f].mValue.x, channel->mRotationKeys[f].mValue.y, channel->mRotationKeys[f].mValue.z, channel->mRotationKeys[f].mValue.w); } if (f < channel->mNumScalingKeys) { scale = (channel->mScalingKeys[f].mValue.x + channel->mScalingKeys[f].mValue.y + channel->mScalingKeys[f].mValue.z) / 3.0f; has_scale |= !math_isequal(scale, 1.0f); } import_convert_vec3(&pos, &pos, g_anim_coord); import_convert_quat(&quat, &quat, g_anim_coord); vec4_setf(&h3dchannel->pos_scale[f], pos.x, pos.y, pos.z, scale); quat_setf(&h3dchannel->rot[f], quat.x, quat.y, quat.z, quat.w); } } channel_offset += anim->mNumChannels; } /* write to file */ h3danim.a.channel_cnt = channel_cnt; h3danim.a.frame_cnt = frame_cnt; h3danim.a.has_scale = has_scale; h3danim.a.fps = fps; h3danim.channels = h3dchannels; /* parse json clip file */ h3danim.clips = import_loadclips(params->clips_json_filepath, frame_cnt, &h3danim.a.clip_cnt); /* write */ int r = import_writeanim(params->out_filepath, &h3danim); /* report */ if (r) { printf(TERM_BOLDGREEN "ok, saved: \"%s\".\n" TERM_RESET, params->out_filepath); if (params->verbose) { printf(TERM_WHITE); printf("Animation report:\n" " animation count: %d\n" " frame count: %d\n" " channel count: %d\n" " has_scale: %s\n" " fps: %d\n", scene->mNumAnimations, frame_cnt, channel_cnt, has_scale ? "yes" : "no", fps); printf(TERM_RESET); } } /* cleanup */ for (uint i = 0; i < h3danim.a.channel_cnt; i++) { if (h3danim.channels[i].pos_scale != NULL) FREE(h3danim.channels[i].pos_scale); if (h3danim.channels[i].rot != NULL) FREE(h3danim.channels[i].rot); } FREE(h3danim.clips); FREE(h3danim.channels); aiReleaseImport(scene); return r; }