bool parseCinematic(Cinematic * c, const char * data, size_t size) { const char * cinematicId = util::safeGetString(data, size); if(!cinematicId) { LogError << "Error parsing file magic number"; return false; } if(std::strcmp(cinematicId, "KFA") != 0) { LogError << "Wrong magic number"; return false; } s32 version; if(!util::safeGet(version, data, size)) { LogError << "Error reading file version"; return false; } LogDebug("version " << version); if(version < CINEMATIC_VERSION_1_75) { LogError << "Too old version " << version << " expected at least " << CINEMATIC_VERSION_1_75; } if(version > CINEMATIC_VERSION_1_76) { LogError << "Wrong version " << version << " expected max " << CINEMATIC_VERSION_1_76; return false; } // Ignore a string. util::safeGetString(data, size); // Load bitmaps. s32 nbitmaps; if(!util::safeGet(nbitmaps, data, size)) { LogError << "Error reading bitmap count"; return false; } LogDebug(nbitmaps << " images:"); c->m_bitmaps.reserve(nbitmaps); for(int i = 0; i < nbitmaps; i++) { s32 scale = 0; if(!util::safeGet(scale, data, size)) { LogError << "Error reading bitmap scale"; return false; } const char * str = util::safeGetString(data, size); if(!str) { LogError << "Error reading bitmap path"; return false; } LogDebug(" - " << i << ": \"" << str << '"'); res::path path = fixTexturePath(str); LogDebug(" => " << path << " (scale x" << scale << ')'); CinematicBitmap * newBitmap = CreateCinematicBitmap(path, scale); if(newBitmap) { c->m_bitmaps.push_back(newBitmap); } } // Load sounds. s32 nsounds; if(!util::safeGet(nsounds, data, size)) { LogError << "Error reading sound count"; return false; } LogDebug(nsounds << " sounds:"); for(int i = 0; i < nsounds; i++) { if(version >= CINEMATIC_VERSION_1_76) { s16 ignored; if(!util::safeGet(ignored, data, size)) { LogError << "Error reading sound id"; return false; } } const char * str = util::safeGetString(data, size); if(!str) { LogError << "Error reading sound path"; return false; } LogDebug(" - " << i << ": \"" << str << '"'); std::pair<res::path, bool> path = fixSoundPath(str); LogDebug(" => " << path.first << (path.second ? " (speech)" : "")); AddSoundToList(path.first, path.second); } // Load track and keys. SavedCinematicTrack t; if(!util::safeGet(t, data, size)) { LogError << "Error reading track"; return false; } if(t.startframe != 0) { LogWarning << "Cinematic startframe is not 0"; } AllocTrack(t.endframe, t.fps); LogDebug(t.nbkey << " keyframes:"); for(int i = 0; i < t.nbkey; i++) { CinematicKeyframe k; int idsound; if(version <= CINEMATIC_VERSION_1_75) { C_KEY_1_75 k175; if(!util::safeGet(k175, data, size)) { LogError << "Error reading key v1.75"; return false; } k.angz = k175.angz; k.color = Color::fromBGRA(ColorBGRA(k175.color)); k.colord = Color::fromBGRA(ColorBGRA(k175.colord)); k.colorf = Color::fromBGRA(ColorBGRA(k175.colorf)); k.frame = k175.frame; k.fx = k175.fx; k.numbitmap = k175.numbitmap; k.pos = k175.pos.toVec3(); k.speed = k175.speed; k.typeinterp = k175.typeinterp; k.force = k175.force; idsound = k175.idsound; k.idsound = -1; k.light = k175.light; k.posgrille = k175.posgrille.toVec3(); k.angzgrille = k175.angzgrille; k.speedtrack = k175.speedtrack; arx_assert(k175.posgrille.toVec3() == Vec3f_ZERO); arx_assert(k175.angzgrille == 0.f); } else { C_KEY_1_76 k176; if(!util::safeGet(k176, data, size)) { LogError << "Error reading key v1.76"; return false; } k.angz = k176.angz; k.color = Color::fromBGRA(ColorBGRA(k176.color)); k.colord = Color::fromBGRA(ColorBGRA(k176.colord)); k.colorf = Color::fromBGRA(ColorBGRA(k176.colorf)); k.frame = k176.frame; k.fx = k176.fx; k.numbitmap = k176.numbitmap; k.pos = k176.pos.toVec3(); k.speed = k176.speed; k.typeinterp = k176.typeinterp; k.force = k176.force; k.light = k176.light; k.posgrille = k176.posgrille.toVec3(); k.angzgrille = k176.angzgrille; k.speedtrack = k176.speedtrack; idsound = k176.idsound[0]; // 0 was the language code for 'French' k.idsound = k176.idsound[3]; // 3 was the language code for 'English' arx_assert(k176.posgrille.toVec3() == Vec3f_ZERO); arx_assert(k176.angzgrille == 0.f); } if(k.force < 0) { k.force = 1; } // The cinematics were authored for 4:3 - if the light only fades off // outside of that region, it should never fade off. // This fixes ugly transitions when fallin and fallout are close together. { float f = std::min(k.light.fallin, k.light.fallout); float d0 = glm::distance(Vec2f(k.light.pos), Vec2f(-320.f, -240.f)); float d1 = glm::distance(Vec2f(k.light.pos), Vec2f(320.f, -240.f)); float d2 = glm::distance(Vec2f(k.light.pos), Vec2f(320.f, 240.f)); float d3 = glm::distance(Vec2f(k.light.pos), Vec2f(-320.f, 240.f)); if(f > std::max(std::max(d0, d1), std::max(d2, d3))) { k.light.fallin = k.light.fallout = std::numeric_limits<float>::max() / 3; } } // The final vertex positions were manually scaled to fit the whole screen // when rendering cinematics. This applies the same scaling by moving // the camera closer. We can do this because all bitmaps are at z == 0. { arx_assert(k.posgrille.z == 0.f); k.pos.z *= 0.8f; // 0.8 == 512/640 == 384/480 } AddKeyLoad(k); LogDebug(" - " << i << ": frame " << k.frame << " image: " << k.numbitmap); if(k.idsound >= 0) { LogDebug(" + sound: " << k.idsound); } if(i == 0) { c->m_pos = k.pos; c->angz = k.angz; c->numbitmap = k.numbitmap; c->fx = k.fx; c->ti = k.typeinterp; c->color = k.color; c->colord = k.colord; c->colorflash = k.colorf; c->speed = k.speed; c->idsound = idsound; c->force = k.force; c->m_light = k.light; c->posgrille = k.posgrille; c->angzgrille = k.angzgrille; c->speedtrack = k.speedtrack; } } UpDateAllKeyLight(); SetCurrFrame(0); GereTrack(c, 0, false, false); c->projectload = true; LogDebug("loaded cinematic"); return true; }
/*---------------------------------------------------------------*/ void Cinematic::Render(float FDIFF) { CinematicBitmap * tb; LargeurRender = DANAESIZX; HauteurRender = DANAESIZY; if (projectload) { GRenderer->Clear(Renderer::ColorBuffer); GRenderer->BeginScene(); GereTrack(this, FDIFF); //sound if (changekey) { if (idsound >= 0) { PlaySoundKeyFramer(idsound); } } //draw GRenderer->SetBlendFunc(Renderer::BlendSrcAlpha, Renderer::BlendInvSrcAlpha); GRenderer->GetTextureStage(0)->SetColorOp(TextureStage::OpModulate, TextureStage::ArgTexture, TextureStage::ArgDiffuse); GRenderer->GetTextureStage(0)->SetAlphaOp(TextureStage::OpModulate, TextureStage::ArgTexture, TextureStage::ArgDiffuse); GRenderer->GetTextureStage(1)->DisableAlpha(); //image key tb = m_bitmaps[numbitmap]; //fx int col = 0x00FFFFFF; switch (fx & 0x000000FF) { case FX_FADEIN: col = FX_FadeIN(a, color, colord); break; case FX_FADEOUT: col = FX_FadeOUT(a, color, colord); break; case FX_BLUR: FX_Blur(this, tb); break; default: break; } //fx precalculation switch (fx & 0x0000ff00) { case FX_DREAM: if ((this->fxsuiv & 0x0000ff00) == FX_DREAM) FX_DreamPrecalc(tb, 15.f, (FPS > 1.f) ? GetTrackFPS() / FPS : 0.f); else FX_DreamPrecalc(tb, 15.f * a, (FPS > 1.f) ? GetTrackFPS() / FPS : 0.f); break; default: break; } Camera.pos = pos; SetTargetCamera(&Camera, Camera.pos.x, Camera.pos.y, 0.f); Camera.angle.b = 0; Camera.angle.g = angz; Camera.centerx = LargeurRender >> 1; Camera.centery = HauteurRender >> 1; Camera.clip.right = LargeurRender; Camera.clip.bottom = HauteurRender; PrepareCamera(&Camera); SetActiveCamera(&Camera); int alpha = ((int)(a * 255.f)) << 24; int stopline = tb->nbx; if (stopline & 1) stopline++; if (force ^ 1) alpha = 0xFF000000; col |= alpha; CinematicLight lightt, *l = NULL; if ((this->light.intensity >= 0.f) && (this->lightd.intensity >= 0.f)) { lightt = this->light; lightt.pos.x += (float)(LargeurRender >> 1); lightt.pos.y += (float)(HauteurRender >> 1); #define SPEEDINTENSITYRND (10.f) float flIntensityRNDToReach = lightt.intensiternd * rnd(); m_flIntensityRND += (flIntensityRNDToReach - m_flIntensityRND) * FDIFF * SPEEDINTENSITYRND; m_flIntensityRND = m_flIntensityRND < 0.f ? 0.f : m_flIntensityRND > 1.f ? 1.f : m_flIntensityRND; LightRND = lightt.intensity + (lightt.intensiternd * rnd()); if (LightRND > 1.f) LightRND = 1.f; l = &lightt; } if (tb->grid.nbvertexs) DrawGrille(&tb->grid, col, fx, l, &posgrille, angzgrille); //PASS #2 if (force & 1) { switch (ti) { case INTERP_NO: Camera.pos = possuiv; SetTargetCamera(&Camera, Camera.pos.x, Camera.pos.y, 0.f); Camera.angle.b = 0; Camera.angle.g = angzsuiv; PrepareCamera(&Camera); break; case INTERP_LINEAR: break; case INTERP_BEZIER: break; } tb = m_bitmaps[numbitmapsuiv]; alpha = 0xFF000000 - alpha; col &= 0x00FFFFFF; col |= alpha; l = NULL; if ((this->light.intensity >= 0.f) && (this->lightd.intensity >= 0.f)) { lightt = this->lightd; lightt.pos.x += (float)(LargeurRender >> 1); lightt.pos.y += (float)(HauteurRender >> 1); LightRND = lightt.intensity + (lightt.intensiternd * rnd()); if (LightRND > 1.f) LightRND = 1.f; l = &lightt; } if (tb->grid.nbvertexs) DrawGrille(&tb->grid, col, fx, l, &posgrillesuiv, angzgrillesuiv); }
/*---------------------------------------------------------------*/ void Cinematic::Render(float FDIFF) { CinematicBitmap * tb; LargeurRender = g_size.width(); HauteurRender = g_size.height(); if(projectload) { GRenderer->Clear(Renderer::ColorBuffer); GereTrack(this, FDIFF); //sound if(changekey && idsound >= 0) PlaySoundKeyFramer(idsound); //draw GRenderer->SetBlendFunc(Renderer::BlendSrcAlpha, Renderer::BlendInvSrcAlpha); GRenderer->GetTextureStage(0)->setColorOp(TextureStage::OpModulate, TextureStage::ArgTexture, TextureStage::ArgDiffuse); GRenderer->GetTextureStage(0)->setAlphaOp(TextureStage::OpModulate, TextureStage::ArgTexture, TextureStage::ArgDiffuse); GRenderer->GetTextureStage(1)->disableAlpha(); //image key tb = m_bitmaps[numbitmap]; //fx int col = 0x00FFFFFF; switch(fx & 0x000000FF) { case FX_FADEIN: col = FX_FadeIN(a, color, colord); break; case FX_FADEOUT: col = FX_FadeOUT(a, color, colord); break; case FX_BLUR: FX_Blur(this, tb, m_camera); break; default: break; } //fx precalculation switch(fx & 0x0000ff00) { case FX_DREAM: if ((this->fxsuiv & 0x0000ff00) == FX_DREAM) FX_DreamPrecalc(tb, 15.f, (FPS > 1.f) ? GetTrackFPS() / FPS : 0.f); else FX_DreamPrecalc(tb, 15.f * a, (FPS > 1.f) ? GetTrackFPS() / FPS : 0.f); break; default: break; } m_camera.orgTrans.pos = pos; m_camera.setTargetCamera(m_camera.orgTrans.pos.x, m_camera.orgTrans.pos.y, 0.f); m_camera.angle.setPitch(0); m_camera.angle.setRoll(angz); m_camera.clip = Rect(LargeurRender, HauteurRender); m_camera.center = m_camera.clip.center(); PrepareCamera(&m_camera, g_size); SetActiveCamera(&m_camera); int alpha = ((int)(a * 255.f)) << 24; if(force ^ 1) alpha = 0xFF000000; col |= alpha; CinematicLight lightt, *l = NULL; if(this->light.intensity >= 0.f && this->lightd.intensity >= 0.f) { lightt = this->light; lightt.pos.x += (float)(LargeurRender >> 1); lightt.pos.y += (float)(HauteurRender >> 1); static const float SPEEDINTENSITYRND = 10.f; float flIntensityRNDToReach = lightt.intensiternd * rnd(); m_flIntensityRND += (flIntensityRNDToReach - m_flIntensityRND) * FDIFF * SPEEDINTENSITYRND; m_flIntensityRND = m_flIntensityRND < 0.f ? 0.f : m_flIntensityRND > 1.f ? 1.f : m_flIntensityRND; LightRND = lightt.intensity + (lightt.intensiternd * rnd()); if(LightRND > 1.f) LightRND = 1.f; l = &lightt; } if(tb->grid.nbvertexs) DrawGrille(&tb->grid, col, fx, l, &posgrille, angzgrille); //PASS #2 if(force & 1) { switch(ti) { case INTERP_NO: m_camera.orgTrans.pos = possuiv; m_camera.setTargetCamera(m_camera.orgTrans.pos.x, m_camera.orgTrans.pos.y, 0.f); m_camera.angle.setPitch(0); m_camera.angle.setRoll(angzsuiv); PrepareCamera(&m_camera, g_size); break; case INTERP_LINEAR: break; case INTERP_BEZIER: break; } tb = m_bitmaps[numbitmapsuiv]; alpha = 0xFF000000 - alpha; col &= 0x00FFFFFF; col |= alpha; l = NULL; if(this->light.intensity >= 0.f && this->lightd.intensity >= 0.f) { lightt = this->lightd; lightt.pos.x += (float)(LargeurRender >> 1); lightt.pos.y += (float)(HauteurRender >> 1); LightRND = lightt.intensity + (lightt.intensiternd * rnd()); if(LightRND > 1.f) LightRND = 1.f; l = &lightt; } if(tb->grid.nbvertexs) DrawGrille(&tb->grid, col, fx, l, &posgrillesuiv, angzgrillesuiv); }