#include "mungal4.h" #pragma hdrstop #include "..\munga\door.h" #include "..\munga\doorfram.h" #include "..\munga\eyecandy.h" #include "l4vidrnd.h" #include "l4video.h" #include "..\munga\matrix.h" #include "..\munga\mover.h" #include "..\munga\jmover.h" #include "..\munga\player.h" #include "..\munga\camship.h" #include "..\munga\director.h" #include "..\munga\mission.h" #include "..\munga\cultural.h" #include "..\munga\nttmgr.h" #include "..\munga\app.h" #include "l4particles.h" #include "DXUtils.h" #include "bgfload.h" // BT: SetVideoPathPriority (day/night path priority) using namespace std; #include #include #include #include #include // std::sort (the .PFX particle depth sort) LPDIRECT3D9 gD3D = NULL; //STUBBED: DPL RB 1/14/07 // when this is resolved it can be removed #include "..\DPLSTUB.h" #include #define char8 unsigned char #define uint32 unsigned __int32 // basic macro to help with releasing things #define SAFE_RELEASE(handle) if (handle) { handle->Release(); handle = NULL; } //===========================================================================// // BT WEAPON BEAMS (port addition) -- the visible muzzle->hit beam the game's // fire path pushes each shot. The 1995 IG board drew weapon beams through the // dpl_* display-list layer that was never ported (so a firing Emitter drew // NOTHING). This is a self-contained additive-quad beam renderer: BTPushBeam // (called from the reconstructed fire path, mech4.cpp) queues a world-space // segment; BTDrawBeams (called in the alpha pass below, world proj + view set, // Z-test on so a beam into a hill is occluded) billboards each as a camera- // facing additive quad and fades it over its short life. No content needed. //===========================================================================// struct BTBeamFx { D3DXVECTOR3 from, to; DWORD color; // 0x00RRGGBB glow colour (additive; alpha ignored) float ttl, maxTtl; // seconds float width; // world units }; static std::vector gBTBeams; // the decoded beam grit sheet (built lazily in BTDrawBeams; shared with the // .PFX particle layer below) LPDIRECT3DTEXTURE9 gBTBeamGritTex = 0; LPDIRECT3DTEXTURE9 BTGetBeamGritTexture() { return gBTBeamGritTex; } // Called from the game (mech4.cpp) -- external linkage, matched by an extern decl there. // LOD eyepoint feed (game -> renderer): the viewpoint mech's position, the // authentic LOD reference (see the ExecuteImplementation banner). mech4 calls // this every player frame; once fed, the view-matrix extraction fallback stops. int gBTLodEyeValid = 0; void BTSetLodEye(float x, float y, float z) { d3d_OBJECT::SetCameraPosition(x, y, z); gBTLodEyeValid = 1; // DIAG (BT_LOD_LOG): prove the feed runs + what it feeds (1-in-300 calls) static int s_eyeLog = -1; if (s_eyeLog < 0) { const char *lv = getenv("BT_LOD_LOG"); s_eyeLog = (lv != 0 && lv[0] == '1') ? 1 : 0; } if (s_eyeLog) { static int s_n = 0; if ((++s_n % 300) == 1) DEBUG_STREAM << "[lodeye] fed (" << x << ", " << y << ", " << z << ") n=" << s_n << "\n" << std::flush; } } void BTPushBeam(float fx, float fy, float fz, float tx, float ty, float tz, unsigned color, float ttl, float width) { if (gBTBeams.size() > 256) return; // runaway guard BTBeamFx b; b.from = D3DXVECTOR3(fx, fy, fz); b.to = D3DXVECTOR3(tx, ty, tz); b.color = color; b.ttl = ttl; b.maxTtl = (ttl > 1e-4f) ? ttl : 1e-4f; b.width = width; gBTBeams.push_back(b); } void BTDrawBeams(LPDIRECT3DDEVICE9 dev, const D3DXMATRIX *view, float dt) { if (gBTBeams.empty()) return; D3DXMATRIX iv; D3DXMatrixInverse(&iv, NULL, view); const D3DXVECTOR3 cam(iv._41, iv._42, iv._43); // camera world position DWORD sLight, sFog, sZW, sBlend, sSrc, sDst, sCull, sCop, sCa1, sCa2, sAop, sAa1, sAddrU, sAddrV; dev->GetRenderState(D3DRS_LIGHTING, &sLight); dev->GetRenderState(D3DRS_FOGENABLE, &sFog); dev->GetRenderState(D3DRS_ZWRITEENABLE, &sZW); dev->GetRenderState(D3DRS_ALPHABLENDENABLE, &sBlend); dev->GetRenderState(D3DRS_SRCBLEND, &sSrc); dev->GetRenderState(D3DRS_DESTBLEND, &sDst); dev->GetRenderState(D3DRS_CULLMODE, &sCull); dev->GetTextureStageState(0, D3DTSS_COLOROP, &sCop); dev->GetTextureStageState(0, D3DTSS_COLORARG1, &sCa1); dev->GetTextureStageState(0, D3DTSS_COLORARG2, &sCa2); dev->GetTextureStageState(0, D3DTSS_ALPHAOP, &sAop); dev->GetTextureStageState(0, D3DTSS_ALPHAARG1, &sAa1); dev->GetSamplerState(0, D3DSAMP_ADDRESSU, &sAddrU); dev->GetSamplerState(0, D3DSAMP_ADDRESSV, &sAddrV); // AUTHENTIC BEAM TEXTURE (decoded): the original laser beam (ermlaser.bgf) is a // tube textured with `beamwhite_scr_tex` -> the `bexp` image (VIDEO/TEX/BEXP.BSL, // a chaotic red/yellow/green noise) SCROLLED fast (BTFX.VMF: SCROLL u=0.10 v=9.5) // and ramp-colourised by `softer` (0.25->0.99) for the white core. Load BEXP.BSL // once, ramp its luminance to a grayscale grit texture, and MODULATE the beam // colour by it with a scrolling UV -> the streaming "gritty" look, not a clean // gradient. BT_BEAM_TEX=0 falls back to the plain additive beam. // (file-scope so the .PFX particle layer below can share the decoded sheet) static int s_beamTexTried = 0; extern LPDIRECT3DTEXTURE9 gBTBeamGritTex; LPDIRECT3DTEXTURE9 &s_beamTex = gBTBeamGritTex; if (!s_beamTexTried) { s_beamTexTried = 1; const char *bv = getenv("BT_BEAM_TEX"); if (bv == 0 || bv[0] != '0') { FILE *fp = fopen("VIDEO\\TEX\\BEXP.BSL", "rb"); if (fp) { fseek(fp, 0, SEEK_END); long sz = ftell(fp); fseek(fp, 0, SEEK_SET); std::vector buf(sz > 0 ? sz : 1); size_t got = fread(&buf[0], 1, sz, fp); fclose(fp); if (got >= 16 && memcmp(&buf[0], "DIV-BSL2", 8) == 0) { int tw = *(int *)&buf[8], th = *(int *)&buf[12]; // 128 x 64 long need = (long)tw * th * 4; if (tw > 0 && th > 0 && (long)got >= need && SUCCEEDED(dev->CreateTexture(tw, th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &s_beamTex, NULL))) { const unsigned char *bimg = &buf[got - need]; // trailing base image D3DLOCKED_RECT lr; if (SUCCEEDED(s_beamTex->LockRect(0, &lr, NULL, 0))) { // GRIT CONTRAST (BT_BEAM_GRIT, default 2.0): the authentic // 'softer' ramp (0.25->0.99) only spans ~4:1, and additive // blending over a bright scene flattens it to near-invisible. // Expand the ramped luminance about its midpoint before baking // so the interference pattern reads like the pod footage. float grit = 2.0f; { const char *gv = getenv("BT_BEAM_GRIT"); if (gv) grit = (float)atof(gv); } for (int y = 0; y < th; ++y) { DWORD *dst = (DWORD *)((char *)lr.pBits + y * lr.Pitch); for (int x = 0; x < tw; ++x) { // BSL BIT-SLICE decode: beamwhite_scr_tex maps to 'bexp' // with NO BITSLICE tag = slice 0 (bexp1, the grit sheet) // = bits 12-15 (byte1 high nibble) of the texel word. // (The old byte-luminance read mixed bexp1/bexp2 and the // bexp99 RGBA-sprite nibbles.) const unsigned char *p = &bimg[(y * tw + x) * 4]; float lum = (float)(p[1] & 0xF0) / 240.0f; float v = 0.25f + 0.74f*lum; // 'softer' ramp v = 0.62f + (v - 0.62f) * grit; // expand about ramp midpoint if (v < 0.0f) v = 0.0f; int gg = (int)(v * 255.0f); if (gg > 255) gg = 255; dst[x] = 0xFF000000u | (gg << 16) | (gg << 8) | gg; } } s_beamTex->UnlockRect(0); } } } } } } // AUTHENTIC GEOMETRY: render the real ermlaser.bgf TUBE (a thin 2000-long tube // with UVs tiled ~8x down its length), transformed per beam (scale the length to // the shot distance, orient local -Z -> muzzle->target), instead of a camera- // facing billboard quad. BT_BEAM_TUBE=0 falls back to the billboard. static int s_tubeTried = 0; static std::vector s_tubeVB; // x,y,z,u,v per vertex static std::vector s_tubeIB; static int s_tubeVerts = 0, s_tubeTris = 0; if (!s_tubeTried) { s_tubeTried = 1; const char *tvv = getenv("BT_BEAM_TUBE"); if (tvv == 0 || tvv[0] != '0') { BgfData bd; if (LoadBgfFile("ermlaser.bgf", bd) && bd.ok && !bd.indices.empty()) { s_tubeVerts = (int)bd.verts.size(); s_tubeVB.reserve(bd.verts.size() * 5); for (size_t k = 0; k < bd.verts.size(); ++k) { s_tubeVB.push_back(bd.verts[k].x); s_tubeVB.push_back(bd.verts[k].y); s_tubeVB.push_back(bd.verts[k].z); s_tubeVB.push_back(bd.verts[k].u); s_tubeVB.push_back(bd.verts[k].v); } s_tubeIB = bd.indices; s_tubeTris = (int)(bd.indices.size() / 3); } } } const bool useTube = (s_beamTex != 0 && s_tubeTris > 0); static float s_tubeWidth = -1.0f; if (s_tubeWidth < 0.0f) { const char *wv = getenv("BT_BEAM_WIDTH"); s_tubeWidth = wv ? (float)atof(wv) : 1.0f; } // global width multiplier static float s_beamTime = 0.0f; s_beamTime += dt; const float uScroll = s_beamTime * 0.10f; // VMF SCROLL u-speed const float vScroll = s_beamTime * 9.5f; // VMF SCROLL v-speed (fast) DWORD sTFactor, sTexXf; dev->GetRenderState(D3DRS_TEXTUREFACTOR, &sTFactor); dev->GetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, &sTexXf); D3DXMATRIX ident; D3DXMatrixIdentity(&ident); dev->SetTransform(D3DTS_WORLD, &ident); dev->SetFVF(useTube ? (D3DFVF_XYZ | D3DFVF_TEX1) : (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)); dev->SetRenderState(D3DRS_LIGHTING, FALSE); dev->SetRenderState(D3DRS_FOGENABLE, FALSE); dev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); // additive glow dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // beam colour: from the TFACTOR (tube -- verts carry no colour) or vertex DIFFUSE (billboard). const DWORD kColArg = useTube ? D3DTA_TFACTOR : D3DTA_DIFFUSE; if (s_beamTex) { dev->SetTexture(0, s_beamTex); dev->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); dev->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); // grit x beam colour dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); dev->SetTextureStageState(0, D3DTSS_COLORARG2, kColArg); } else { dev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); dev->SetTextureStageState(0, D3DTSS_COLORARG1, kColArg); } dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, kColArg); // SCROLL + GRIT DENSITY: bake into the tube's UVs on the CPU, PER BEAM (89 // verts, trivial). Two lessons: // (1) the previous D3DTS_TEXTURE0 texture-coordinate transform SILENTLY // STOPPED APPLYING when the device moved to HARDWARE vertex processing // (the perf fix) -- vertex UVs are pipeline-independent; // (2) the tube's baked U (0..7.7 tiles over its NATIVE 2000u length) stays // put while the GEOMETRY compresses to the shot distance, so at typical // ranges all ~8 tiles squeeze into a short beam -> the grit minifies to // ~3 texels/pixel and bilinear-averages into a SMOOTH GRADIENT (the // "no interference pattern" report). Scale U by the compression ratio // (beamLen/2000) so the grit density is WORLD-FIXED (~1 tile / 260u -- // the billboard's proven mapping). static std::vector s_tubeScrolled; struct BV { float x, y, z; DWORD c; float u, v; }; for (size_t i = 0; i < gBTBeams.size(); ++i) { BTBeamFx &b = gBTBeams[i]; float f = b.ttl / b.maxTtl; if (f < 0) f = 0; if (f > 1) f = 1; const int r = (int)(((b.color >> 16) & 0xFF) * f); const int g = (int)(((b.color >> 8) & 0xFF) * f); const int bl = (int)(( b.color & 0xFF) * f); const DWORD col = 0xFF000000u | (r << 16) | (g << 8) | bl; D3DXVECTOR3 d3 = b.to - b.from; const float beamLen = D3DXVec3Length(&d3); D3DXVECTOR3 dir = d3; D3DXVec3Normalize(&dir, &dir); if (useTube) { // world = Scale(width,width,len/2000) * Rotate(local -Z -> dir) * Translate(muzzle). D3DXVECTOR3 up(0.0f, 1.0f, 0.0f); if (fabsf(dir.y) > 0.99f) up = D3DXVECTOR3(1.0f, 0.0f, 0.0f); D3DXVECTOR3 zc = -dir; // local +Z image D3DXVECTOR3 xc; D3DXVec3Cross(&xc, &up, &zc); D3DXVec3Normalize(&xc, &xc); D3DXVECTOR3 yc; D3DXVec3Cross(&yc, &zc, &xc); D3DXMATRIX S, R, T, W; // PER-BEAM width (b.width) x global BT_BEAM_WIDTH multiplier: a wide dim glow // and a THIN bright core render at different radii (real ermlaser = thin core // in a wider glow) instead of stacking to a solid white cylinder. const float ws = b.width * s_tubeWidth; D3DXMatrixScaling(&S, ws, ws, beamLen / 2000.0f); D3DXMatrixIdentity(&R); R._11 = xc.x; R._12 = xc.y; R._13 = xc.z; R._21 = yc.x; R._22 = yc.y; R._23 = yc.z; R._31 = zc.x; R._32 = zc.y; R._33 = zc.z; D3DXMatrixTranslation(&T, b.from.x, b.from.y, b.from.z); D3DXMatrixMultiply(&W, &S, &R); D3DXMatrixMultiply(&W, &W, &T); dev->SetTransform(D3DTS_WORLD, &W); dev->SetRenderState(D3DRS_TEXTUREFACTOR, col); // per-beam UVs: world-fixed grit density + scroll (see banner above) const float uScale = beamLen / 2000.0f; s_tubeScrolled = s_tubeVB; for (size_t k = 0; k + 4 < s_tubeScrolled.size(); k += 5) { s_tubeScrolled[k + 3] = s_tubeScrolled[k + 3] * uScale + uScroll; s_tubeScrolled[k + 4] += vScroll; } dev->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, s_tubeVerts, s_tubeTris, &s_tubeIB[0], D3DFMT_INDEX32, &s_tubeScrolled[0], 5 * sizeof(float)); } else { D3DXVECTOR3 mid = (b.from + b.to) * 0.5f; D3DXVECTOR3 toCam = cam - mid; D3DXVec3Normalize(&toCam, &toCam); D3DXVECTOR3 side; D3DXVec3Cross(&side, &dir, &toCam); D3DXVec3Normalize(&side, &side); side *= b.width * 0.5f; const float uLen = uScroll + beamLen / 260.0f; const float v0 = vScroll, v1 = vScroll + 1.6f; BV quad[4] = { { b.from.x + side.x, b.from.y + side.y, b.from.z + side.z, col, uScroll, v0 }, { b.from.x - side.x, b.from.y - side.y, b.from.z - side.z, col, uScroll, v1 }, { b.to.x + side.x, b.to.y + side.y, b.to.z + side.z, col, uLen, v0 }, { b.to.x - side.x, b.to.y - side.y, b.to.z - side.z, col, uLen, v1 }, }; dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(BV)); } b.ttl -= dt; } dev->SetTexture(0, NULL); dev->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, sTexXf); dev->SetRenderState(D3DRS_TEXTUREFACTOR, sTFactor); // drop expired beams size_t w = 0; for (size_t i = 0; i < gBTBeams.size(); ++i) if (gBTBeams[i].ttl > 0.0f) gBTBeams[w++] = gBTBeams[i]; gBTBeams.resize(w); dev->SetTransform(D3DTS_WORLD, &ident); dev->SetRenderState(D3DRS_LIGHTING, sLight); dev->SetRenderState(D3DRS_FOGENABLE, sFog); dev->SetRenderState(D3DRS_ZWRITEENABLE, sZW); dev->SetRenderState(D3DRS_ALPHABLENDENABLE, sBlend); dev->SetRenderState(D3DRS_SRCBLEND, sSrc); dev->SetRenderState(D3DRS_DESTBLEND, sDst); dev->SetRenderState(D3DRS_CULLMODE, sCull); dev->SetTextureStageState(0, D3DTSS_COLOROP, sCop); dev->SetTextureStageState(0, D3DTSS_COLORARG1, sCa1); dev->SetTextureStageState(0, D3DTSS_COLORARG2, sCa2); dev->SetTextureStageState(0, D3DTSS_ALPHAOP, sAop); dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, sAa1); dev->SetSamplerState(0, D3DSAMP_ADDRESSU, sAddrU); dev->SetSamplerState(0, D3DSAMP_ADDRESSV, sAddrV); } //===========================================================================// // BT PARTICLE EFFECTS (.PFX) -- the 1995 explosion/damage effect layer. // // The pod's damage/explosion visuals are DATA: VIDEO/*.PFX text files (format // documented inside each file), mapped to dpl effect NUMBERS by BTDPL.INI's // [pfx_day]/[pfx_night] pages ("psfxN=file.pfx" -- N is the number embedded in // resources: 2..5 = the mech damage bands, 6 = projectile-gun hit, 7 = the // mech-death explosion, 8 = zone destroyed...). The 1995 board consumed these // through dpl particle calls that were never ported: DPLIndependantEffect's // (<100) arm and ReadPSFX are both stubbed, so every weapon-hit / damage-band / // death explosion rendered NOTHING. Like the weapon-beam layer above, this is // the self-contained D3D9 port of that layer: // BTLoadPfxFile -- parses a .PFX into BTPfxDef (the documented format) // BTStartPfx -- starts an emitter instance at a world position // (called by DPLIndependantEffect for effect_number < 100) // BTDrawPfx -- per-frame sim + camera-facing additive-quad billboards // (called beside BTDrawBeams in the render loop) // Variance convention (decoded from DNBOOM.PFX: vel 150 + var -300 = a // symmetric +-150 burst): sampled = value + variance * rand01(). // NOT yet honoured (noted, low-visibility): atten/attenv (distance // attenuation), colorWarp/alphaWarp exponents are applied as t^(1/warp), // the per-file texture name (all BT effects use the firesmoke sheet; we use // the same decoded grit texture as the beams). //===========================================================================// struct BTPfxDef { int valid; unsigned identifier; int maxIssue; // total particles an instance may issue float releasePeriod; // batch interval (s) float rate; // particles per second while releasing float px, py, pz, pv; // spawn offset + positional variance float velx, vely, velz, velxv, velyv, velzv; float rad, radv, exp, expv, dexp, dexpv; // radius, expansion rate, expansion decay float accelx, accely, accelz, accelxv, accelyv, accelzv; float atten, attenv; // (not yet honoured) float sI[4], sIv[4]; // start colour inner RGBA + variance float sO[4], sOv[4]; // start colour outer RGBA + variance float eI[4], eIv[4]; // end colour inner RGBA + variance float eO[4], eOv[4]; // end colour outer RGBA + variance float colorWarp, alphaWarp; float duration, durationv; // particle lifetime }; #define BT_PFX_SLOTS 32 static BTPfxDef gBTPfxDefs[BT_PFX_SLOTS]; struct BTPfxEmitter { const BTPfxDef *def; D3DXVECTOR3 pos; // The effect's LOCAL FRAME (.PFX offsets/velocities are authored in the // victim's mech-local space -- e.g. DAFC.PFX sprays -Z, out through the // front armor toward the shooter). Identity when no frame is known. D3DXVECTOR3 ax, ay, az; float sinceRelease; int issued; int active; }; struct BTPfxParticle { D3DXVECTOR3 pos, vel, accel; float age, life; float rad, exp, dexp; float colorWarp, alphaWarp; // def-level warps, carried per particle float sI[4], sO[4], eI[4], eO[4]; }; static std::vector gBTPfxEmitters; static std::vector gBTPfxParticles; static float BTPfxRand01() // cheap deterministic LCG { static unsigned s = 0x2545F491u; s = s * 1664525u + 1013904223u; return (float)((s >> 8) & 0xFFFFFF) / 16777215.0f; } // Parse one .PFX text file (VIDEO\) into a def slot. Format per the // spec block carried inside every .PFX (and ReadPSFX's comment). static int BTLoadPfxFile(const char *file_name, BTPfxDef &d) { char path[256]; strcpy(path, "VIDEO\\"); strcat(path, file_name); FILE *fp = fopen(path, "rt"); if (!fp) { DEBUG_STREAM << "[pfx] could not open " << path << " -- its effects will not draw\n" << std::flush; return 0; } memset(&d, 0, sizeof(d)); char line[256]; int ok = 1; // line 1: texture name (recorded in the banner note; the shared sheet is used) if (!fgets(line, sizeof(line), fp)) ok = 0; if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%x %d %f %f", &d.identifier, &d.maxIssue, &d.releasePeriod, &d.rate) == 4); else ok = 0; if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f %f %f", &d.px, &d.py, &d.pz, &d.pv) == 4); else ok = 0; if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f %f %f %f %f", &d.velx, &d.vely, &d.velz, &d.velxv, &d.velyv, &d.velzv) == 6); else ok = 0; if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f %f %f %f %f", &d.rad, &d.radv, &d.exp, &d.expv, &d.dexp, &d.dexpv) == 6); else ok = 0; if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f %f %f %f %f", &d.accelx, &d.accely, &d.accelz, &d.accelxv, &d.accelyv, &d.accelzv) == 6); else ok = 0; if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f", &d.atten, &d.attenv) == 2); else ok = 0; float *quads[8] = { d.sI, d.sIv, d.sO, d.sOv, d.eI, d.eIv, d.eO, d.eOv }; for (int q = 0; ok && q < 4; ++q) // 4 lines: sI+var, sO+var, eI+var, eO+var { if (fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f %f %f %f %f %f %f", &quads[q*2][0], &quads[q*2][1], &quads[q*2][2], &quads[q*2][3], &quads[q*2+1][0], &quads[q*2+1][1], &quads[q*2+1][2], &quads[q*2+1][3]) == 8); else ok = 0; } if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f", &d.colorWarp, &d.alphaWarp) == 2); else ok = 0; if (ok && fgets(line, sizeof(line), fp)) ok = (sscanf(line, "%f %f", &d.duration, &d.durationv) == 2); else ok = 0; fclose(fp); if (!ok) { DEBUG_STREAM << "[pfx] " << path << " did not parse -- effect disabled\n" << std::flush; return 0; } d.valid = 1; return 1; } // Slot-checked load entry used by the psfx page loader (LoadMission walk). int BTLoadPfxFile_slot(const char *file_name, int slot) { if (slot < 0 || slot >= BT_PFX_SLOTS) return 0; return BTLoadPfxFile(file_name, gBTPfxDefs[slot]); } // Start one effect instance at a world position (the DPLIndependantEffect // contract: renderer-owned, runs to termination on its own). The optional // frame rows orient the .PFX's mech-local offsets/velocities in the world // (pass the victim entity's localToWorld X/Y/Z rows); identity when absent. void BTStartPfxFrame(int effect_number, float x, float y, float z, const float *xrow, const float *yrow, const float *zrow) { if (effect_number < 0 || effect_number >= BT_PFX_SLOTS) return; const BTPfxDef &d = gBTPfxDefs[effect_number]; if (!d.valid) return; if (gBTPfxEmitters.size() > 64) // runaway guard return; BTPfxEmitter e; e.def = &d; e.pos = D3DXVECTOR3(x, y, z); e.ax = xrow ? D3DXVECTOR3(xrow[0], xrow[1], xrow[2]) : D3DXVECTOR3(1, 0, 0); e.ay = yrow ? D3DXVECTOR3(yrow[0], yrow[1], yrow[2]) : D3DXVECTOR3(0, 1, 0); e.az = zrow ? D3DXVECTOR3(zrow[0], zrow[1], zrow[2]) : D3DXVECTOR3(0, 0, 1); e.sinceRelease = 1e9f; // first batch releases immediately e.issued = 0; e.active = 1; gBTPfxEmitters.push_back(e); } void BTStartPfx(int effect_number, float x, float y, float z) { BTStartPfxFrame(effect_number, x, y, z, 0, 0, 0); } static void BTPfxSpawn(const BTPfxEmitter &e) { const BTPfxDef &d = *e.def; if (gBTPfxParticles.size() > 2048) // global particle cap return; BTPfxParticle p; // Sample in the effect's LOCAL frame, then orient into the world through // the emitter's basis (the victim's localToWorld rows). The position // jitter pv is an isotropic scatter about the base offset -> symmetric // (rand +-pv); the paired variances stay value + var*rand01 (DNBOOM's // vel 150 / var -300 decodes to the symmetric +-150 burst). D3DXVECTOR3 lp( d.px + d.pv * (BTPfxRand01() * 2.0f - 1.0f), d.py + d.pv * (BTPfxRand01() * 2.0f - 1.0f), d.pz + d.pv * (BTPfxRand01() * 2.0f - 1.0f)); D3DXVECTOR3 lv( d.velx + d.velxv * BTPfxRand01(), d.vely + d.velyv * BTPfxRand01(), d.velz + d.velzv * BTPfxRand01()); D3DXVECTOR3 la( d.accelx + d.accelxv * BTPfxRand01(), d.accely + d.accelyv * BTPfxRand01(), d.accelz + d.accelzv * BTPfxRand01()); p.pos = e.pos + e.ax * lp.x + e.ay * lp.y + e.az * lp.z; p.vel = e.ax * lv.x + e.ay * lv.y + e.az * lv.z; p.accel = e.ax * la.x + e.ay * la.y + e.az * la.z; p.age = 0.0f; p.life = d.duration + d.durationv * BTPfxRand01(); if (p.life < 0.05f) p.life = 0.05f; p.rad = d.rad + d.radv * BTPfxRand01(); p.exp = d.exp + d.expv * BTPfxRand01(); p.dexp = d.dexp + d.dexpv * BTPfxRand01(); p.colorWarp = (d.colorWarp > 1e-3f) ? d.colorWarp : 1.0f; p.alphaWarp = (d.alphaWarp > 1e-3f) ? d.alphaWarp : 1.0f; for (int i = 0; i < 4; ++i) { p.sI[i] = d.sI[i] + d.sIv[i] * BTPfxRand01(); p.sO[i] = d.sO[i] + d.sOv[i] * BTPfxRand01(); p.eI[i] = d.eI[i] + d.eIv[i] * BTPfxRand01(); p.eO[i] = d.eO[i] + d.eOv[i] * BTPfxRand01(); } gBTPfxParticles.push_back(p); } // The beams' decoded grit texture (built in BTDrawBeams) -- shared with the // particles so the fire quads carry the authentic firesmoke-family noise. extern LPDIRECT3DTEXTURE9 BTGetBeamGritTexture(); void BTDrawPfx(LPDIRECT3DDEVICE9 dev, const D3DXMATRIX *view, float dt) { // ---- sim ---- if (dt > 0.1f) dt = 0.1f; // stall guard for (size_t ei = 0; ei < gBTPfxEmitters.size(); ++ei) { BTPfxEmitter &e = gBTPfxEmitters[ei]; if (!e.active) continue; const BTPfxDef &d = *e.def; e.sinceRelease += dt; if (e.sinceRelease >= d.releasePeriod) { // one batch: rate particles/sec over the release period, total-capped int batch = (int)(d.rate * (d.releasePeriod > 1e-4f ? d.releasePeriod : dt)); if (batch < 1) batch = 1; if (e.issued + batch > d.maxIssue) batch = d.maxIssue - e.issued; for (int b = 0; b < batch; ++b) BTPfxSpawn(e); e.issued += batch; e.sinceRelease = 0.0f; if (e.issued >= d.maxIssue) e.active = 0; // done issuing -> instance ends } } { // compact finished emitters size_t w = 0; for (size_t i = 0; i < gBTPfxEmitters.size(); ++i) if (gBTPfxEmitters[i].active) gBTPfxEmitters[w++] = gBTPfxEmitters[i]; gBTPfxEmitters.resize(w); } { // advance + expire particles size_t w = 0; for (size_t i = 0; i < gBTPfxParticles.size(); ++i) { BTPfxParticle &p = gBTPfxParticles[i]; p.age += dt; if (p.age >= p.life) continue; p.vel += p.accel * dt; p.pos += p.vel * dt; p.rad += p.exp * dt; p.exp += p.dexp * dt; if (p.rad < 0.05f) p.rad = 0.05f; gBTPfxParticles[w++] = p; } gBTPfxParticles.resize(w); } if (gBTPfxParticles.empty()) return; // ---- draw: camera-facing additive quads (inner core + outer glow) ---- const D3DXVECTOR3 right(view->_11, view->_21, view->_31); const D3DXVECTOR3 up (view->_12, view->_22, view->_32); DWORD sLight, sFog, sZW, sBlend, sSrc, sDst, sCull, sCop, sCa1, sCa2, sAop, sAa1, sAa2; dev->GetRenderState(D3DRS_LIGHTING, &sLight); dev->GetRenderState(D3DRS_FOGENABLE, &sFog); dev->GetRenderState(D3DRS_ZWRITEENABLE, &sZW); dev->GetRenderState(D3DRS_ALPHABLENDENABLE, &sBlend); dev->GetRenderState(D3DRS_SRCBLEND, &sSrc); dev->GetRenderState(D3DRS_DESTBLEND, &sDst); dev->GetRenderState(D3DRS_CULLMODE, &sCull); dev->GetTextureStageState(0, D3DTSS_COLOROP, &sCop); dev->GetTextureStageState(0, D3DTSS_COLORARG1, &sCa1); dev->GetTextureStageState(0, D3DTSS_COLORARG2, &sCa2); dev->GetTextureStageState(0, D3DTSS_ALPHAOP, &sAop); dev->GetTextureStageState(0, D3DTSS_ALPHAARG1, &sAa1); dev->GetTextureStageState(0, D3DTSS_ALPHAARG2, &sAa2); // PREMULTIPLIED blending (ONE, INVSRCALPHA): the one model that renders BOTH // authored particle families correctly. FIRE (bright colour, the additive // glow) and SMOKE (dark/negative-ramp colour with high alpha -> OCCLUDES the // scene behind it -- DDAM2 is 30% grey, DDTHSMK ramps to negative: both are // invisible under pure additive, which is why damaged mechs never smoked). // Vertex colour carries colour*alpha (premultiplied), vertex alpha carries // the occlusion; the texture's falloff mask modulates both. // BT_PFX_ADD=1 flips back to pure additive for A/B comparison. static int s_pfxAdditive = -1; if (s_pfxAdditive < 0) { const char *av = getenv("BT_PFX_ADD"); s_pfxAdditive = (av != 0 && av[0] == '1') ? 1 : 0; } dev->SetRenderState(D3DRS_LIGHTING, FALSE); dev->SetRenderState(D3DRS_FOGENABLE, FALSE); dev->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); // test Z, don't write it dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); dev->SetRenderState(D3DRS_DESTBLEND, s_pfxAdditive ? D3DBLEND_ONE : D3DBLEND_INVSRCALPHA); dev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // Particle sprite texture: the beams' authentic grit sheet MASKED by a // radial falloff -> soft round fiery blobs (an unmasked square sheet on an // additive quad reads as a hard BOX, which the 1995 sprites never did). // Baked once from the decoded grit; pure radial gradient if grit is absent. static LPDIRECT3DTEXTURE9 s_pfxTex = 0; static int s_pfxTexTried = 0; if (!s_pfxTexTried) { s_pfxTexTried = 1; const int TW = 64, TH = 64; LPDIRECT3DTEXTURE9 grit = BTGetBeamGritTexture(); unsigned char gritLum[128 * 64]; // grit is 128x64 when present int gw = 0, gh = 0; if (grit) { D3DSURFACE_DESC gd; if (SUCCEEDED(grit->GetLevelDesc(0, &gd)) && gd.Width <= 128 && gd.Height <= 64) { D3DLOCKED_RECT glr; if (SUCCEEDED(grit->LockRect(0, &glr, NULL, D3DLOCK_READONLY))) { gw = gd.Width; gh = gd.Height; for (int y = 0; y < gh; ++y) { const DWORD *src = (const DWORD *)((const char *)glr.pBits + y * glr.Pitch); for (int x = 0; x < gw; ++x) gritLum[y * gw + x] = (unsigned char)(src[x] & 0xFF); } grit->UnlockRect(0); } } } if (SUCCEEDED(dev->CreateTexture(TW, TH, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &s_pfxTex, NULL))) { D3DLOCKED_RECT lr; if (SUCCEEDED(s_pfxTex->LockRect(0, &lr, NULL, 0))) { for (int y = 0; y < TH; ++y) { DWORD *dst = (DWORD *)((char *)lr.pBits + y * lr.Pitch); for (int x = 0; x < TW; ++x) { float dx = (x + 0.5f) / TW * 2.0f - 1.0f; float dy = (y + 0.5f) / TH * 2.0f - 1.0f; float r = sqrtf(dx * dx + dy * dy); float f = 1.0f - r; // radial falloff if (f < 0.0f) f = 0.0f; f = f * f * (3.0f - 2.0f * f); // smoothstep edge float n = 1.0f; if (gw > 0) // authentic grit detail n = 0.35f + 0.65f * (gritLum[(y % gh) * gw + (x % gw)] / 255.0f); int v = (int)(f * n * 255.0f); if (v > 255) v = 255; // the falloff mask lives in ALPHA too: the premultiplied // draw (ONE, INVSRCALPHA) needs soft-edged OCCLUSION for // smoke, not just soft-edged colour for fire dst[x] = (v << 24) | (v << 16) | (v << 8) | v; } } s_pfxTex->UnlockRect(0); } else { s_pfxTex->Release(); s_pfxTex = 0; } } } dev->SetTexture(0, s_pfxTex); dev->SetTextureStageState(0, D3DTSS_COLOROP, s_pfxTex ? D3DTOP_MODULATE : D3DTOP_SELECTARG1); dev->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); dev->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); // occlusion = vertex alpha x the texture's falloff mask (soft-edged smoke) dev->SetTextureStageState(0, D3DTSS_ALPHAOP, s_pfxTex ? D3DTOP_MODULATE : D3DTOP_SELECTARG1); dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); dev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); D3DXMATRIX ident; D3DXMatrixIdentity(&ident); dev->SetTransform(D3DTS_WORLD, &ident); dev->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1); struct V { float x, y, z; DWORD c; float u, v; }; static std::vector verts; verts.clear(); // BACK-TO-FRONT order: premultiplied occlusion (smoke) composites in depth // order; unsorted draws pop when a near puff renders before a far one. static std::vector order; static std::vector depth; order.resize(gBTPfxParticles.size()); depth.resize(gBTPfxParticles.size()); for (size_t i = 0; i < gBTPfxParticles.size(); ++i) { const D3DXVECTOR3 &pp = gBTPfxParticles[i].pos; order[i] = i; depth[i] = pp.x * view->_13 + pp.y * view->_23 + pp.z * view->_33; // view-space z } std::sort(order.begin(), order.end(), [](size_t a, size_t b) { return depth[a] > depth[b]; }); for (size_t oi = 0; oi < order.size(); ++oi) { const BTPfxParticle &p = gBTPfxParticles[order[oi]]; float t = p.age / p.life; if (t < 0.0f) t = 0.0f; if (t > 1.0f) t = 1.0f; // colour/alpha interpolation start->end, warped (t^(1/warp): a large // warp shifts to the end colour early -- the fast orange->smoke shift) float tc = powf(t, 1.0f / p.colorWarp); float ta = powf(t, 1.0f / p.alphaWarp); // two quads: outer glow (2.2x radius) then inner core for (int layer = 0; layer < 2; ++layer) { const float *cs = layer ? p.sI : p.sO; const float *ce = layer ? p.eI : p.eO; float scale = layer ? 1.0f : 2.2f; float r = cs[0] + (ce[0] - cs[0]) * tc; float g = cs[1] + (ce[1] - cs[1]) * tc; float b = cs[2] + (ce[2] - cs[2]) * tc; float a = cs[3] + (ce[3] - cs[3]) * ta; if (a <= 0.0f) continue; if (a > 1.0f) a = 1.0f; // PREMULTIPLIED: vertex rgb = colour x alpha (the framebuffer // contribution), vertex a = alpha (the occlusion). A colour ramped // NEGATIVE (DDTHSMK's smoke tail) clamps to 0 -> pure occluding // black smoke; a bright fire colour with fading alpha dims out. int ir = (int)(r * a * 255.0f); if (ir > 255) ir = 255; if (ir < 0) ir = 0; int ig = (int)(g * a * 255.0f); if (ig > 255) ig = 255; if (ig < 0) ig = 0; int ib = (int)(b * a * 255.0f); if (ib > 255) ib = 255; if (ib < 0) ib = 0; int ia = (int)(a * 255.0f); if (ia > 255) ia = 255; if (ia < 0) ia = 0; if (ia == 0 && ir == 0 && ig == 0 && ib == 0) continue; DWORD c = ((DWORD)ia << 24) | (ir << 16) | (ig << 8) | ib; float rad = p.rad * scale; D3DXVECTOR3 rv = right * rad, uv = up * rad; V q[6]; q[0].x = p.pos.x - rv.x - uv.x; q[0].y = p.pos.y - rv.y - uv.y; q[0].z = p.pos.z - rv.z - uv.z; q[0].u = 0; q[0].v = 1; q[1].x = p.pos.x - rv.x + uv.x; q[1].y = p.pos.y - rv.y + uv.y; q[1].z = p.pos.z - rv.z + uv.z; q[1].u = 0; q[1].v = 0; q[2].x = p.pos.x + rv.x + uv.x; q[2].y = p.pos.y + rv.y + uv.y; q[2].z = p.pos.z + rv.z + uv.z; q[2].u = 1; q[2].v = 0; q[3] = q[0]; q[4] = q[2]; q[5].x = p.pos.x + rv.x - uv.x; q[5].y = p.pos.y + rv.y - uv.y; q[5].z = p.pos.z + rv.z - uv.z; q[5].u = 1; q[5].v = 1; for (int k = 0; k < 6; ++k) { q[k].c = c; verts.push_back(q[k]); } } } if (!verts.empty()) dev->DrawPrimitiveUP(D3DPT_TRIANGLELIST, (UINT)verts.size() / 3, &verts[0], sizeof(V)); dev->SetTexture(0, NULL); dev->SetRenderState(D3DRS_LIGHTING, sLight); dev->SetRenderState(D3DRS_FOGENABLE, sFog); dev->SetRenderState(D3DRS_ZWRITEENABLE, sZW); dev->SetRenderState(D3DRS_ALPHABLENDENABLE, sBlend); dev->SetRenderState(D3DRS_SRCBLEND, sSrc); dev->SetRenderState(D3DRS_DESTBLEND, sDst); dev->SetRenderState(D3DRS_CULLMODE, sCull); dev->SetTextureStageState(0, D3DTSS_COLOROP, sCop); dev->SetTextureStageState(0, D3DTSS_COLORARG1, sCa1); dev->SetTextureStageState(0, D3DTSS_COLORARG2, sCa2); dev->SetTextureStageState(0, D3DTSS_ALPHAOP, sAop); dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, sAa1); dev->SetTextureStageState(0, D3DTSS_ALPHAARG2, sAa2); } // BT (task #20): the live window client aspect (0 = never resized -> the // projection builders fall back to the configured x_size/y_size). Set by // L4NotifyWindowResized (WM_SIZE) so a user-resized window doesn't stretch // the scene fat/skinny. float gWindowAspect = 0.0f; #define PILL_COUNT 20 #define PILL_SIZE (y_size*0.03125) // 32 @ 1280x1024 #define PILL_SPACING (PILL_SIZE*0.625) // 20 @ 1280x1024 #define LOAD_COLOR 0xFF6565FF #define FADE_IN 0.05f #define PILL_ON 0.05f #define FADE_OUT 0.5f #define LOAD_TEXT_HEIGHT PILL_SIZE // 32 @ 1280x1024 #define LOAD_TEXT_WIDTH (LOAD_TEXT_HEIGHT*12.125) // 388 @ 1280x1024 #define PS_OFF 0 #define PS_FADINGIN 1 #define PS_ON 2 #define PS_FADINGOUT 3 #define LOAD_TEXT_VERT (PILL_SIZE/2.0) #ifdef LOGFRAMERATE FILE *FRAMERATE_LOG; #endif // // Includes for the DPL libraries // // RB 1/15/07 //#include //#include //#include //#include //#include // // You can enable or disable these traces here for quicker rebuilding during // profile testing, but for production they should be all turned off! // //#define TRACE_VIDEO_CULL_SETUP //#define TRACE_VIDEO_VEHICLE_RENDERABLES // #define TRACE_VIDEO_ALL_RENDERABLES // // These are other traces you can use to extract data // #if defined(TRACE_VIDEO_LOAD_OBJECT) static BitTrace Video_Load_Object("Video Load Object"); #define SET_VIDEO_LOAD_OBJECT() Video_Load_Object.Set() #define CLEAR_VIDEO_LOAD_OBJECT() Video_Load_Object.Clear() #else #define SET_VIDEO_LOAD_OBJECT() #define CLEAR_VIDEO_LOAD_OBJECT() #endif #if defined(TRACE_VIDEO_CONSTRUCT_ROOT) static BitTrace Video_Construct_Root("Video Construct Root"); #define SET_VIDEO_CONSTRUCT_ROOT() Video_Construct_Root.Set() #define CLEAR_VIDEO_CONSTRUCT_ROOT() Video_Construct_Root.Clear() #else #define SET_VIDEO_CONSTRUCT_ROOT() #define CLEAR_VIDEO_CONSTRUCT_ROOT() #endif // // This is the time spent fetching and processing the pickpoint information // from the DPL renderer. // #if defined(TRACE_VIDEO_PICKPOINT) static BitTrace Video_Pickpoint("Video Pickpoint"); #define SET_VIDEO_PICKPOINT() Video_Pickpoint.Set() #define CLEAR_VIDEO_PICKPOINT() Video_Pickpoint.Clear() #else #define SET_VIDEO_PICKPOINT() #define CLEAR_VIDEO_PICKPOINT() #endif // // Traces the time spent setting up the video culling parameters // #if defined(TRACE_VIDEO_CULL_SETUP) static BitTrace Video_Cull_Setup("Video Cull Setup"); # define SET_VIDEO_CULL_SETUP() Video_Cull_Setup.Set() # define CLEAR_VIDEO_CULL_SETUP() Video_Cull_Setup.Clear() #else # define SET_VIDEO_CULL_SETUP() # define CLEAR_VIDEO_CULL_SETUP() #endif // // This trace covers the entire time spent executing renderables as one // transition. It goes up when the execute implimentation starts running // over the all iterator and goes down when it's done. // #if defined(TRACE_VIDEO_RENDERABLES) static BitTrace Video_Renderables("Video Renderables"); #define SET_VIDEO_RENDERABLES() Video_Renderables.Set() #define CLEAR_VIDEO_RENDERABLES() Video_Renderables.Clear() #else #define SET_VIDEO_RENDERABLES() #define CLEAR_VIDEO_RENDERABLES() #endif // // Traces time spent executing renderables that belong to a vehicle entity // (currently Mech, VTV or BTPlayer) // #if defined(TRACE_VIDEO_VEHICLE_RENDERABLES) static BitTrace Video_Vehicle_Renderables("Video Vehicle Renderables"); # define SET_VIDEO_VEHICLE_RENDERABLES() Video_Vehicle_Renderables.Set() # define CLEAR_VIDEO_VEHICLE_RENDERABLES() Video_Vehicle_Renderables.Clear() #else # define SET_VIDEO_VEHICLE_RENDERABLES() # define CLEAR_VIDEO_VEHICLE_RENDERABLES() #endif // // This trace will transition as each individual renderable is executed. // It will buzz and cause serious impact to the accuracy of the trace but is // good for identifying time-eating individual renderables // #if defined(TRACE_VIDEO_ALL_RENDERABLES) static BitTrace Video_All_Renderables("Video All Renderables"); # define SET_VIDEO_ALL_RENDERABLES() Video_All_Renderables.Set() # define CLEAR_VIDEO_ALL_RENDERABLES() Video_All_Renderables.Clear() #else # define SET_VIDEO_ALL_RENDERABLES() # define CLEAR_VIDEO_ALL_RENDERABLES() #endif // // This is the routine that does a DPL_FlushArticulations on the batch of // DCS's that we've been holding during rendering, std::flushing them all to // the card in a big batch // #if defined(TRACE_VIDEO_BATCH_FLUSH) static BitTrace Video_Batch_Flush("Video Batch Flush"); # define SET_VIDEO_BATCH_FLUSH() Video_Batch_Flush.Set() # define CLEAR_VIDEO_BATCH_FLUSH() Video_Batch_Flush.Clear() #else # define SET_VIDEO_BATCH_FLUSH() # define CLEAR_VIDEO_BATCH_FLUSH() #endif // // This trace shows the time spent doing the "frame done" processing where the // renderer waits for the DPL card to become ready and then issues a command // to start the scene drawing. An additional batch std::flush can happen here. // If USE_ONE_VIDEO_TRACE is turned on, data from this trace will show up as // part of the Video_Renderer trace. // #if defined(TRACE_VIDEO_RENDERER_FRAME_DONE) # if defined(USE_ONE_VIDEO_TRACE) # define SET_VIDEO_RENDERER_FRAME_DONE() Video_Renderer.Set() # define CLEAR_VIDEO_RENDERER_FRAME_DONE() Video_Renderer.Clear() # else static BitTrace Video_Renderer_Frame_Done("Video Renderer Frame Done"); # define SET_VIDEO_RENDERER_FRAME_DONE() Video_Renderer_Frame_Done.Set() # define CLEAR_VIDEO_RENDERER_FRAME_DONE() Video_Renderer_Frame_Done.Clear() # endif #else # define SET_VIDEO_RENDERER_FRAME_DONE() # define CLEAR_VIDEO_RENDERER_FRAME_DONE() #endif // // The following traces are specifically designed for profileing the low level // DPL routines in Division's libraries. You need to link to a special "profile" // version of the division libraries for these to work. If you enable them // with a production libdpl you will get NO traces. If you disable them and // try to link to a profile version of libdpl you will get link errors. Sorry // but this is the most efficient way of connecting the c++ trace routines to // the C code of division's libraries. // // There are switches in the DPL libraries that handle turning these functions // on and off in the profile version. // //#define TRACE_DPL_LOAD_OBJECT //#define TRACE_DPL_TRANSPUTER_LINK // will buzz //#define TRACE_DPL_DO_OUTSW // will buzz //#define TRACE_DPL_OUTINT32 // will buzz #if defined(TRACE_DPL_LOAD_OBJECT) static BitTrace DPL_Load_Object("DPL Load Object"); extern "C" { void Set_DPL_Load_Object(); void Clear_DPL_Load_Object(); } void Set_DPL_Load_Object() { DPL_Load_Object.Set(); } void Clear_DPL_Load_Object() { DPL_Load_Object.Clear(); } #endif #if defined(TRACE_DPL_TRANSPUTER_LINK) static BitTrace DPL_Transputer_Link("DPL Transputer Link"); extern "C" { void Set_DPL_Transputer_Link(); void Clear_DPL_Transputer_Link(); } void Set_DPL_Transputer_Link() { DPL_Transputer_Link.Set(); } void Clear_DPL_Transputer_Link() { DPL_Transputer_Link.Clear(); } #endif #if defined(TRACE_DPL_DO_OUTSW) static BitTrace DPL_do_outsw("DPL do_outsw"); extern "C" { void Set_DPL_do_outsw(); void Clear_DPL_do_outsw(); } void Set_DPL_do_outsw() { DPL_do_outsw.Set(); } void Clear_DPL_do_outsw() { DPL_do_outsw.Clear(); } #endif #if defined(TRACE_DPL_OUTINT32) static BitTrace DPL_outint32("DPL outint32"); extern "C" { void Set_DPL_outint32(); void Clear_DPL_outint32(); } void Set_DPL_outint32() { DPL_outint32.Set(); } void Clear_DPL_outint32() { DPL_outint32.Clear(); } #endif // // The following trace will probably be obsolete soon // #if 0 #if defined(TRACE_VIDEO_FIRST_FRAME_DONE) static BitTrace Video_First_Frame_Done("Video First Frame Done"); # define SET_VIDEO_FIRST_FRAME_DONE() Video_First_Frame_Done.Set() # define CLEAR_VIDEO_FIRST_FRAME_DONE() Video_First_Frame_Done.Clear() #else # define SET_VIDEO_FIRST_FRAME_DONE() # define CLEAR_VIDEO_FIRST_FRAME_DONE() #endif #endif //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Definitions of various debugging switches // #define DEBUG_SPECIAL_CALLBACK 0 // 0 = none, 1 = print special, 2 = real noisy #define DEBUG_CREATE_CALLBACK 0 // 0 = none, #define PRINT_THE_PFX False // Set to true and the pfx definition will print when it is read in. #define RAPID_SECT_PIXEL True // True if you want to use the rapidsectpixel call for intersections #define PARTICLE_TEST False // True to issue a stream of particles at the detected intersect point #define PRINT_PICKPOINT_TEST False // True to print data whenever the intersect changes #define NOISY_RENDERER False // True enables a lot of printouts as the renderer makes/kills object #define USE_TRACKER_STRUCTURE False // True to enable the full tracker structure that holds damage zone names & such //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Definitions of system constants used only in this file // #define MAX_SPECIAL_ARGUMENTS 25 // Maximum number of arguments a "special" callback can handle #define MAX_SPECIAL_SIZE 512 // Maximum size (characters) of a "special" #define dpl_arg_sep '~' // seperator used when parsing dpl argument string //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Entity *Entity_Being_Created = 0; // !!! temp, till callback handlers become a class //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // These extern "c" routines and constants are from startdpl or from dpl // itself and need to be here. // extern "C" { //STUBBED: DPL RB 1/15/07 //extern const int // x_size, // x size of the screen (from startdpl) // y_size; // y size of the screen (startdpl) void dpl_TexmapTexels2D ( // A routine from DPL we normally couldn't access dpl_TEXMAP *tm, uint32 *texels, int32 u_size, int32 v_size, int32 bytes_per_texel); int screen_resolution( // Sets up the screen resolution (startdpl) char *dpl_argv ), explode_args( // Parses DPLARG system environmental (startdpl) char **argv, char *dpl_args, char sep ); char *dpl_TypeToString( // Converts a DPL type code into a string (libdpl) dpl_TYPE t); int32 dpl_DrawSceneComplete(void); // missing definition (libdpl) }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // see DPLReportPerfStats() //STUBBED: VIDEO RB 1/15/07 //extern "C" const int32 __sect_time; //extern "C" const int32 __last_cull_time; //extern "C" const int32 __last_draw_time; //extern "C" const int32 __last_frame_time; //extern "C" const int32 __last_pxpl_time; //extern "C" const int32 __last_frame_prims; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // dump_frame_buffer() std::declaration void dump_frame_buffer( dpl_VIEW *eye, int32 x_size, int32 y_size, Logical antialias); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The following are definitions of DPL callback functions. These are called // by the dpl file loader as it is loading graphics files so we can do material // substitution and set special attributes on geometry & such. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The "special" callback is called whenever a "special" field is processed in // incomming geometry. // dPL special callback function type. // typedef void (dpl_SPECIAL_CALLBACK)(dpl_TYPE type, void *handle, // char8 *special, uint32 special_len); static void TestSpecialCallBack( dpl_TYPE type, void *handle, char8 *special, uint32 special_len) { //STUBBED: DPL RB 1/14/07 // char // *args[MAX_SPECIAL_ARGUMENTS], // **argptr, // *argstring; // int // argcount; // float // u0, // v0, // du, // dv; // int32 // immunity; // char //// NameBuff[80], // TempBuff[MAX_SPECIAL_SIZE + 1]; // #if USE_TRACKER_STRUCTURE // dpl_tracker // *this_tracker; // #endif // // if(special_len > MAX_SPECIAL_SIZE) // { // DEBUG_STREAM<<"SPECIAL was bigger than "< MAX_SPECIAL_SIZE); // } // strncpy(TempBuff, (const char*)special, special_len); // TempBuff[special_len] = 0; // if(TempBuff[special_len-1] != 0) // { // DEBUG_STREAM<<"Caution, the following SPECIAL was not null terminated\n" << std::flush; // printf("SPECIAL->%08x: %s, %s\n", handle, dpl_TypeToString(type), TempBuff); // } // #if DEBUG_SPECIAL_CALLBACK >= 1 // printf("SPECIAL->%08x: %s, %s\n", handle, dpl_TypeToString(type), TempBuff); // #endif //// //// Scan all the argument start points into an array for easier processing. //// also avoids non-reentrand problem with strtok //// // argstring = TempBuff; // for(argcount = 0; argcount= 2 // Tell("Calling SetObjectAdditiveLODs on an object\n"); // #endif // // REMOVE dpl_SetObjectAdditiveLODs to run with older renderers // dpl_SetObjectAdditiveLODs ( (dpl_OBJECT *)handle); // } // } // break; // case dpl_type_lod: // break; // case dpl_type_geogroup: // #if USE_TRACKER_STRUCTURE // this_tracker = (dpl_tracker *)dpl_GetAppSpecific(handle); // #endif // for(argptr = args; // *argptr; // argptr++) // { // if (strncmp(*argptr, "dz_", 3) == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL GEOGROUP Damage zone "); // #endif // // #if USE_TRACKER_STRUCTURE // if (this_tracker) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("marked\n"); // #endif // strncpy(this_tracker->dz_name, *argptr, MAX_DZ_NAME_LENGTH); // this_tracker->dz_name[MAX_DZ_NAME_LENGTH - 1] = 0; // #endif // //--------------------------------------------- // // lookup damage zone index in global namelist // //--------------------------------------------- // if (Entity_Being_Created->damageZones) // { // Check_Pointer(Entity_Being_Created->damageZones); // // int // damage_zone_index; // // damage_zone_index = // Entity_Being_Created->GetDamageZoneIndex(*argptr); // // if (damage_zone_index != -1) // { // #if USE_TRACKER_STRUCTURE // this_tracker->Damage_Zone_Number = damage_zone_index; // #else // if(dpl_GetAppSpecific(handle)) // Fail("AppSpecific already set\n"); // dpl_PutAppSpecific(handle, (void *)(damage_zone_index+1)); // #endif // } // else // { // DEBUG_STREAM << std::endl << "Damage zone '" << // *argptr << "' not in table." << std::endl; // } // } // #if USE_TRACKER_STRUCTURE // } // else // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("NOT marked\n"); // #endif // } // #endif // } // else if(strcmp(*argptr,"PUNCH") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL GEOGROUP Punchize\n"); // #endif // dpl_Punchize((dpl_GEOGROUP *)handle); // } // else if(strcmp(*argptr,"DAMAGE") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL GEOGROUP damagize\n"); // #endif // if(*(++argptr)) // { // int // status; // dpl_MATERIAL *damagize_material = dpl_LookupMaterial ( *argptr, dpl_lookup_normal, &status ); // if(damagize_material) // { // dpl_Damagize((dpl_GEOGROUP *)handle, damagize_material); // } // else // { // DEBUG_STREAM<<"SPECIAL GEOGROUP DAMAGE couldn't find material "<<*argptr<<"\n" << std::flush; // Verify(damagize_material); // } // } // else // { // DEBUG_STREAM<<"SPECIAL GEOGROUP DAMAGE no material name \n" << std::flush; // Verify(*argptr); // } // } // else if(strcmp(*argptr,"WIREFRAME") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL GEOGROUP WIREFRAME\n"); // #endif // dpl_SetGeogroupWireframe((dpl_GEOGROUP *)handle, True); // } // else if(strcmp(*argptr,"GEOMETRIZE") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL GEOGROUP geometrize\n"); // #endif // if(*(++argptr)) // { // dpl_GEOMETRY // *geometry_ptr; // long // geometrize_code; // int // geometry_id = 0; // sscanf( // *argptr, // "%lx", // &geometrize_code); // do // { // geometry_ptr = dpl_GetGeogroupGeometry((dpl_GEOGROUP *)handle,geometry_id); // if(geometry_ptr) // { // dpl_Geometrize(geometry_ptr,geometrize_code); // } // geometry_id++; // } while(geometry_ptr); // } // else // { // DEBUG_STREAM<<"SPECIAL GEOGROUP GEOMETRIZE has no geometrize code\n" << std::flush; // Verify(*argptr); // } // } // else if(strcmp(*argptr,"DRAWLAST") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL GEOGROUP DRAWLAST\n"); // #endif // dpl_SetGeogroupDrawLast((dpl_GEOGROUP *)handle, True); // dpl_FlushGeogroup((dpl_GEOGROUP *)handle); // } // else if(strcmp(*argptr,"BLINK") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("SPECIAL GEOGROUP BLINK is not supported\n"); // #endif // } // else // { // DEBUG_STREAM<<"SPECIAL GEOGROUP "<<*argptr<<" is not a geogroup modifier\n" << std::flush; // } // } // break; // case dpl_type_geometry: // break; // case dpl_type_material: // for(argptr = args; // *argptr; // argptr++) // { // if(strcmp(*argptr,"IMMUNE") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL MATERIAL IMMUNE\n"); // #endif // if(*(++argptr)) // { // immunity = atol(*argptr); // dpl_SetMaterialFogImmunity ( (dpl_MATERIAL *)handle, immunity ); // dpl_FlushMaterial((dpl_MATERIAL *)handle); // } // else // { // DEBUG_STREAM<<"SPECIAL MATERIAL IMMUNE has no immune code\n" << std::flush; // Verify(*argptr); // } // } // else // { // DEBUG_STREAM<<"SPECIAL MATERIAL "<<*argptr<<" is not a material modifier\n" << std::flush; // } // } // break; // case dpl_type_texture: // for(argptr = args; // *argptr; // argptr++) // { // if(strcmp(*argptr,"SCROLL") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SCROLL\n"); // #endif // u0 = v0 = du = dv = 0.0; // if(*(++argptr)) // u0 = atof(*argptr); // else // { // DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing u0\n" << std::flush; // Verify(*argptr); // } // if(*(++argptr)) // v0 = atof(*argptr); // else // { // DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing v0\n" << std::flush; // Verify(*argptr); // } // if(*(++argptr)) // du = atof(*argptr); // else // { // DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing du\n" << std::flush; // Verify(*argptr); // } // if(*(++argptr)) // dv = atof(*argptr); // else // { // DEBUG_STREAM<<"SPECIAL TECTURE SCROLL missing dv\n" << std::flush; // Verify(*argptr); // } // dpl_SetTextureScroll ( // (dpl_TEXTURE *)handle, // u0, // v0, // du, // dv); // dpl_FlushTexture((dpl_TEXTURE *)handle); // } // else if(strcmp(*argptr,"FAKESIZE") == 0) // { // #if DEBUG_SPECIAL_CALLBACK >= 2 // Tell("Doing SPECIAL TEXURE FAKESIZE\n"); // #endif // int // size, offset; // if(*(++argptr)) // size = atoi(*argptr); // else // { // DEBUG_STREAM<<"SPECIAL TEXTURE FAKESIZE missing size\n" << std::flush; // Verify(*argptr); // } // if(*(++argptr)) // offset = atoi(*argptr); // else // { // DEBUG_STREAM<<"SPECIAL TEXTURE FAKESIZE missing offset\n" << std::flush; // Verify(*argptr); // } // dpl_FakeTextureSize((dpl_TEXTURE *)handle,size,offset); // dpl_FlushTexture((dpl_TEXTURE *)handle); // } // else // { // DEBUG_STREAM<<"SPECIAL TEXTURE "<<*argptr<<" is not a texture modifier\n" << std::flush; // } // } // break; // case dpl_type_texmap: // break; // case dpl_type_ramp: // break; // } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // The TestCreateCallBack callback is called whenever a dpl node of the indicated // type is created while loading a DPL graphics file. /* dPL create/delete callback function type. */ //typedef void (dpl_CREATE_DELETE_CALLBACK)(dpl_TYPE type, void *handle); static void TestCreateCallBack( dpl_TYPE type, #if DEBUG_CREATE_CALLBACK>=1 void *handle #else void * #endif ) { // // get a pointer to the node structure (first part of most dpl types) // #if DEBUG_CREATE_CALLBACK >=1 printf("CREATE->%08x: %s\n", handle, dpl_TypeToString(type)); #endif switch(type) { case dpl_type_error: break; case dpl_type_scene: break; case dpl_type_zones: break; case dpl_type_view: break; case dpl_type_instance: break; case dpl_type_dcs: break; case dpl_type_light: break; case dpl_type_object: break; case dpl_type_lod: break; case dpl_type_geogroup: #if USE_TRACKER_STRUCTURE { dpl_tracker *this_tracker = new dpl_tracker; this_tracker->This_Entity = Entity_Being_Created; this_tracker->dz_name[0] = 0; this_tracker->Damage_Zone_Number = -1; // no damage zone (default) if(dpl_GetAppSpecific(handle)) DEBUG_STREAM<<"app_specific hook already set!\n" << std::flush; dpl_PutAppSpecific(handle, this_tracker); break; } #endif case dpl_type_geometry: break; case dpl_type_material: break; case dpl_type_texture: break; case dpl_type_texmap: break; case dpl_type_ramp: break; } } //############################################################################# // Code to setup and handle material substitutions. //############################################################################# // NameList *materialSubstitutionList = NULL; const char *opMaterialName(const char *fileName, int opId) { hash_map>::const_iterator fileIter = gOpNames->find(string(fileName)); if (fileIter != gOpNames->end()) { hash_map::const_iterator matIter = (*fileIter).second.find(opId); if (matIter != (*fileIter).second.end()) { return (*matIter).second.c_str(); } } return NULL; } void loadTables() { gOpNames = new hash_map>(); gReplacementData = new hash_map(); FILE * opNames = fopen("VIDEO\\REPLACEMATS.tbl", "rb"); size_t numMats; fread(&numMats, sizeof(size_t), 1, opNames); for (int i = 0; i < (int)numMats; i++) { int opNum, fileNameLen, matNameLen; fread(&opNum, sizeof(int), 1, opNames); fread(&fileNameLen, sizeof(int), 1, opNames); char *fileName = new char[fileNameLen]; fread(fileName, sizeof(char), fileNameLen, opNames); fread(&matNameLen, sizeof(int), 1, opNames); char *matName = new char[matNameLen]; fread(matName, sizeof(char), matNameLen, opNames); hash_map>::const_iterator fileIter = gOpNames->find(string(fileName)); if (fileIter != gOpNames->end()) { hash_map::const_iterator matIter = (*fileIter).second.find(opNum); if (matIter != (*fileIter).second.end()) { (*gOpNames)[string(fileName)][opNum] = string(matName); } else { (*gOpNames)[string(fileName)].insert(pair(opNum, string(matName))); } } else { hash_map fileMap; fileMap.insert(pair(opNum, string(matName))); gOpNames->insert(pair>(string(fileName), fileMap)); } delete [] fileName; delete [] matName; } fclose(opNames); FILE *replacementData = fopen("VIDEO\\MATREPLACETABLE.tbl", "rb"); fread(&numMats, sizeof(size_t), 1, replacementData); for (int i = 0; i < (int)numMats; i++) { int matNameLen, texNameLen; fread(&matNameLen, sizeof(int), 1, replacementData); char *matName = new char[matNameLen]; fread(matName, sizeof(char), matNameLen, replacementData); fread(&texNameLen, sizeof(int), 1, replacementData); char *texName = new char[texNameLen]; fread(texName, sizeof(char), texNameLen, replacementData); ReplacementMaterialData data; data.texName = string(texName); fread(&data, sizeof(float), 3, replacementData); gReplacementData->insert(pair(string(matName), data)); delete [] matName; delete [] texName; } fclose(replacementData); } /* dPL material name callback function type. */ //typedef char8 *(dpl_MATERIAL_NAME_CALLBACK)(char8 *mat_name); char* substituteMaterial( char *source ) { static char buffer[MATERIAL_NAME_BUFFER_LENGTH]; NameList::Entry *entry; const char *search, *replace, *pc; int len; //---------------------------------------------- // perform text substitution // first match in the sub list gets substituted // materialSubstitutionList is a pre-prepared global namelist. //---------------------------------------------- if (materialSubstitutionList == NULL) { return source; } entry = materialSubstitutionList->GetFirstEntry(); while (entry) { search = entry->GetName(); if (search && *search && (pc = strstr((char*)source, search)) != NULL) { replace = entry->GetChar(); *buffer = '\0'; len = (char*)pc - source; while (*replace == '<') { ++replace; --len; } if (len > 0) { strncat(buffer, (const char*)source, len); } pc += strlen(search); len = strlen(replace); while (len && *(replace+len-1) == '>') { --len; if (*pc) { ++pc; } } if (len > 0) { strncat(buffer, replace, len); } Str_Cat(buffer, pc, MATERIAL_NAME_BUFFER_LENGTH); delete [] source; source = new char[strlen(buffer) + 1]; Str_Copy((char*)source, buffer, MATERIAL_NAME_BUFFER_LENGTH); break; } entry = entry->GetNextEntry(); } return source; } vector DPLRenderer::MonitorsCreateAll(int &monitorCount) { monitorCount = gD3D->GetAdapterCount(); vector allMonitors(monitorCount); for(UINT i = 0; i < monitorCount; i++) { HMONITOR monitorHandle = gD3D->GetAdapterMonitor(i); MONITORINFO info; info.cbSize = sizeof(MONITORINFO); GetMonitorInfo(monitorHandle, &info); allMonitors[i] = info; } return allMonitors; } void DPLRenderer::SetCoreRenderStates() { mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_USEW); float size = 1.0f; mDevice->SetRenderState(D3DRS_POINTSIZE, *(DWORD*)(&size)); mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); D3DXMATRIX view_matrix, proj_matrix; D3DXMatrixIdentity(&view_matrix); D3DXMatrixOrthoLH(&proj_matrix, x_size, y_size, 1.0f, 1000.0f); mDevice->SetTransform(D3DTS_VIEW, &view_matrix); mDevice->SetTransform(D3DTS_PROJECTION, &proj_matrix); mDevice->SetRenderState(D3DRS_LIGHTING, false); mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true); mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR); mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); mDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); mDevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); mDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); mDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); mDevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); mDevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); } //----------------------------------------------------------------------------- //--------------------------DPL video resource object-------------------------- //----------------------------------------------------------------------------- //############################################################################# //############################ L4VideoObject ############################ //############################################################################# L4VideoObject::L4VideoObject( const char *filename, ResourceType resource_type, Enumeration renderer_modes, // RendererModes float blink_period, float percent_time_on ) { Check_Pointer(filename); // BT audit (task #20): count every loaded video object (map pieces + props + // mech parts) so the runtime total can be compared against the map source's // instance list. 1-per-10 logging keeps the volume sane. { static int s_vidObjCount = 0; ++s_vidObjCount; if ((s_vidObjCount % 10) == 0 || s_vidObjCount < 5) DEBUG_STREAM << "[vidobj] " << s_vidObjCount << " loaded (latest: " << filename << ")" << "\n" << std::flush; } Str_Copy(objectFilename, filename, sizeof(objectFilename)); //--------------------------------------------------------------- // pad objectFilename with nulls so all .res files are identical //--------------------------------------------------------------- char *p = objectFilename + strlen(filename) + 1, *c = objectFilename + sizeof(objectFilename); for (; p < c; ++p) { *p = '\0'; } resourceType = resource_type; rendererModes = renderer_modes; blinkPeriod = blink_period; percentTimeOn = percent_time_on; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4VideoObject::~L4VideoObject() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical L4VideoObject::TestInstance() const { Verify( strlen(objectFilename) < sizeof(objectFilename) ); return True; } //############################################################################# //######################## L4VideoObjectWrapper ######################### //############################################################################# L4VideoObjectWrapper::L4VideoObjectWrapper( L4VideoObject *video_object, Logical delete_object ) { Check_Pointer(video_object); // do not use Check() videoObject = video_object; deleteObject = delete_object; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // L4VideoObjectWrapper::~L4VideoObjectWrapper() { if (deleteObject) { Unregister_Pointer(videoObject); delete videoObject; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical L4VideoObjectWrapper::TestInstance() const { if (videoObject) { Check_Pointer(videoObject); // do not use Check() } return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // static int L4VideoObjectWrapper::BuildVideoObjectChainFromResource(ChainOf *video_chain, ResourceDescription *video_resource) { //do not Check(this) - static Check(video_chain); Check(video_resource); const char *video_pointer; int object_count, index; long object_size; L4VideoObject *video_object; L4VideoObjectWrapper *video_wrapper; //---------------------------------------------------- // convert video resource into chain of video objects //---------------------------------------------------- video_pointer = (char *)video_resource->resourceAddress; Check_Pointer(video_pointer); object_count = *((int *)video_pointer); video_pointer += sizeof(int); object_size = sizeof(L4VideoObject); Verify(video_resource->resourceSize == sizeof(int) + object_count * object_size); //Tell("video chain: ("<GetObjectFilename()<<"' 0x"<GetRendererModes()); video_wrapper = new L4VideoObjectWrapper(video_object, False); Register_Object(video_wrapper); video_chain->Add(video_wrapper); } //Tell(std::dec<<"\n"); return object_count; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // static void L4VideoObjectWrapper::DeleteVideoObjectChain( ChainOf *video_chain ) { //do not Check(this) - static Check(video_chain); ChainIteratorOf video_iterator(video_chain); L4VideoObjectWrapper *video_wrapper; while ((video_wrapper = video_iterator.ReadAndNext()) != NULL) { Check(video_wrapper); Unregister_Object(video_wrapper); delete video_wrapper; } return; } void DPLRenderer::FindBestAdapterIndices(bool isWindowed) { bool spanDisable = false; bool *spanDisablePtr = NULL; //Get all available monitor indices & stats int monitorCount = 0; std::vector monitors = this->MonitorsCreateAll(monitorCount); int monitorReserved = 0x10000000; //Test for primary gauge override char* gaugeAdapterString = getenv("PRIMGAUGE"); if (gaugeAdapterString != NULL) { mPrimaryIndex = new int; *mPrimaryIndex = atoi(gaugeAdapterString); DEBUG_STREAM << "Primary gauge override- adapter " << *mPrimaryIndex << std::endl; } //Test for secondary gauge override gaugeAdapterString = getenv("SECGAUGE"); if (gaugeAdapterString != NULL) { mSecondaryIndex = new int; *mSecondaryIndex = atoi(gaugeAdapterString); DEBUG_STREAM << "Secondary gauge override- adapter " << *mSecondaryIndex << std::endl; } //Only do gauge overrides if we're using gauges during this execution if (!Application::DoSuppressGauges()) { //Test for gauge1 override gaugeAdapterString = getenv("MFDGAUGE"); if (gaugeAdapterString != NULL) { mAux1Index = new int; *mAux1Index = atoi(gaugeAdapterString); DEBUG_STREAM << "MFD Gauge Override- adapter " << *mAux1Index << std::endl; } //Test for span disable override spanDisablePtr = NULL; gaugeAdapterString = getenv("SPANDISABLE"); if (gaugeAdapterString != NULL) { spanDisable = atoi(gaugeAdapterString); spanDisablePtr = &spanDisable; DEBUG_STREAM << "Spanning Override: Span "; if (*spanDisablePtr) { DEBUG_STREAM << "Disabled"; } else { DEBUG_STREAM << "Enabled"; } DEBUG_STREAM << std::endl; } if (spanDisablePtr == NULL || *spanDisablePtr) { //Test for gauge2 override gaugeAdapterString = getenv("MFDGAUGE2"); if (gaugeAdapterString != NULL) { mAux2Index = new int; *mAux2Index = atoi(gaugeAdapterString); DEBUG_STREAM << "MFD Gauge #2 Override- adapter " << *mAux2Index << std::endl; } } //Disable spanning if they overrode the 2nd gauge if (spanDisablePtr == NULL && mAux2Index != NULL) { DEBUG_STREAM << "MFD Gauge #2 was overridden... forcing spanning disabled." << std::endl; spanDisable = true; spanDisablePtr = &spanDisable; } } //Remove all monitors explicitly assigned somewhere from the list of available monitors if (mPrimaryIndex != NULL && (*mPrimaryIndex) >= 0 && (*mPrimaryIndex) < monitorCount) { monitors[*mPrimaryIndex].dwFlags |= monitorReserved; } if (mSecondaryIndex != NULL && (*mSecondaryIndex) >= 0 && (*mSecondaryIndex) < monitorCount) { monitors[*mSecondaryIndex].dwFlags |= monitorReserved; } if (mAux1Index != NULL && (*mAux1Index) >= 0 && (*mAux1Index) < monitorCount) { monitors[*mAux1Index].dwFlags |= monitorReserved; } if (mAux2Index != NULL && (*mAux2Index) >= 0 && (*mAux2Index) < monitorCount) { monitors[*mAux2Index].dwFlags |= monitorReserved; } if (mPrimaryIndex == NULL) { DEBUG_STREAM << "Trying to find the monitor marked as active in Windows..." << std::endl; //Set up the monitor so marked as the primary (unless none are marked) for (int i = 0; i < monitorCount; i++) { int flags = monitors[i].dwFlags; if ((flags & (MONITORINFOF_PRIMARY | monitorReserved)) == MONITORINFOF_PRIMARY) { DEBUG_STREAM << "Monitor " << i << " was set as active in Windows... setting it as the primary monitor." << endl; mPrimaryIndex = new int; *mPrimaryIndex = i; monitors[i].dwFlags |= monitorReserved; break; } } } //Do gauges next, since they're the easiest to pick out if (!Application::DoSuppressGauges() && !isWindowed && monitorCount > 2) { DEBUG_STREAM << "Gauges are on, we are not in windowed mode, and we have " << monitorCount << " available monitors, so will try to find MFDs..." << std::endl; if (mAux1Index == NULL && (spanDisablePtr == NULL || !(*spanDisablePtr))) { DEBUG_STREAM << "Don't have a MFD #1 monitor yet, and spanning is not explicitly disabled, so will try to find a really wide monitor for both MFDs..." << std::endl; //try to find a really wide monitor to use as gauge1 for (int i = 0; i < monitorCount; i++) { if ((monitors[i].dwFlags & monitorReserved) == 0) { RECT size = monitors[i].rcMonitor; float aspect = ( (double)(size.right - size.left) / (double)(size.bottom - size.top)); if (aspect > 2.5f) { //Really wide! Probably a spanning monitor DEBUG_STREAM << "Monitor " << i << " is really wide, so will try to use it as the MFDs." << std::endl; mAux1Index = new int; *mAux1Index = i; monitors[i].dwFlags |= monitorReserved; if (spanDisablePtr == NULL) { DEBUG_STREAM << "Explicitly setting spanning to enabled..." << std::endl; spanDisable = FALSE; spanDisablePtr = &(spanDisable); } break; } } } } int possibleAux2Index = -1; if (mAux1Index == NULL && (spanDisablePtr == NULL || *spanDisablePtr)) { DEBUG_STREAM << "MFDs not found yet, and spanning isn't explicitly enabled. Will try to find two same-size monitors to use as MFDs..." << std::endl; map,vector> sameSizeMonitors; //Group the unclaimed monitors by resolution for (int i = 0; i < monitorCount; i++) { if ((monitors[i].dwFlags & monitorReserved) == 0) { int width = monitors[i].rcMonitor.right - monitors[i].rcMonitor.left; int height = monitors[i].rcMonitor.bottom - monitors[i].rcMonitor.top; pair resolution(width, height); if (sameSizeMonitors.find(resolution) == sameSizeMonitors.end()) { sameSizeMonitors[resolution] = vector(); } sameSizeMonitors[resolution].insert(sameSizeMonitors[resolution].begin(), i); } } //Retrieve the bucket of monitors with at least two monitors and the smallest resolution (y res counts more than x res) vector bestMonitors; int smallestYRes = -1; int bestXRes = -1; for (map,vector>::iterator it = sameSizeMonitors.begin(); it != sameSizeMonitors.end(); it++) { if ((*it).second.size() >= 2) { int yRes = (*it).first.second; int xRes = (*it).first.first; if (smallestYRes >= 0) { DEBUG_STREAM << "Multiple sets of identically-sized monitors are available. Will use smallest set..." << std::endl; } if (smallestYRes < 0 || yRes < smallestYRes || (yRes == smallestYRes && xRes < bestXRes)) { smallestYRes = yRes; bestXRes = xRes; bestMonitors = (*it).second; } } } int aux1Candidate = -1; int aux2Candidate = -1; int aux1Right = 0; int aux2Right = 0; if (bestMonitors.size() > 2) { DEBUG_STREAM << "More than 2 monitors in the set of smallest, identically-sized monitors... Will use the furthest right as right MFD, one just to the left of that as left MFD..." << std::endl; } //The second aux screen is the one furthest to the right //the first aux screen is the one just to the left of that one for (vector::iterator it = bestMonitors.begin(); it != bestMonitors.end(); it++) { int i = (*it); if ((monitors[i].dwFlags & monitorReserved) == 0) { int right = monitors[i].rcMonitor.right; if (aux2Candidate < 0 || aux2Right < right) { aux1Candidate = aux2Candidate; aux1Right = aux2Right; aux2Candidate = i; aux2Right = right; } else if (aux1Candidate < 0 || aux1Right < right) { aux1Candidate = i; aux1Right = right; } } } if (aux1Candidate >= 0 && aux2Candidate >= 0) { DEBUG_STREAM << "Got two decent same-size monitors, will use as MFDs... Left is " << aux1Candidate << " and right is " << aux2Candidate << "." << std::endl; mAux1Index = new int; *mAux1Index = aux1Candidate; monitors[aux1Candidate].dwFlags |= monitorReserved; mAux2Index = new int; *mAux2Index = aux2Candidate; monitors[aux2Candidate].dwFlags |= monitorReserved; spanDisable = true; spanDisablePtr = &spanDisable; } else { DEBUG_STREAM << "Could not find two identical monitors to use for MFDs." << std::endl; } } if (mAux2Index == NULL && mAux1Index != NULL && (spanDisablePtr == NULL || *spanDisablePtr)) { DEBUG_STREAM << "We have a left MFD and no right MFD, and spanning is not explicitly enabled. Will try to find identically-sized right MFD." << std::endl; //find a monitor that is identical to the first gauge monitor //if multiple, use the furthest to the right int bestMonitorIndex = -1; int bestMonitorRight = 0; int aux1Width = (monitors[*mAux1Index].rcMonitor.right - monitors[*mAux1Index].rcMonitor.left); int aux1Height = (monitors[*mAux1Index].rcMonitor.bottom - monitors[*mAux1Index].rcMonitor.top); for (int i = 0; i < monitorCount; i++) { if ((monitors[i].dwFlags & monitorReserved) == 0) { int monitorWidth = (monitors[i].rcMonitor.right - monitors[i].rcMonitor.left); int monitorHeight = (monitors[i].rcMonitor.bottom - monitors[i].rcMonitor.top); if (monitorWidth == aux1Width && monitorHeight == aux1Height) { if (bestMonitorIndex >= 0) { DEBUG_STREAM << "Found more than one monitor identically sized to the left MFD. Will use furthest-right monitor." << std::endl; } if (bestMonitorIndex < 0 || bestMonitorRight < monitors[i].rcMonitor.right) { bestMonitorIndex = i; bestMonitorRight = monitors[i].rcMonitor.right; } } } } if (bestMonitorIndex >= 0) { DEBUG_STREAM << "Using monitor " << bestMonitorIndex << "as right MFD monitor." << std::endl; mAux2Index = new int; *mAux2Index = bestMonitorIndex; monitors[bestMonitorIndex].dwFlags |= monitorReserved; } else { DEBUG_STREAM << "Could not find decent monitor for right MFD." << std::endl; } } } else { DEBUG_STREAM << "Either MFDs are explicitly disabled, we're running in windowed mode, or we don't have enough monitors attached to this machine. MFD monitors will not be detected." << std::endl; } if (mPrimaryIndex == NULL) { DEBUG_STREAM << "Still no appropriate primary monitor- will find tallest monitor to use." << std::endl; //Pick the monitor with the highest y resolution (leftmost if there's a tie) int bestMonitorIndex = -1; int bestMonitorHeight = 0; int bestMonitorX = 0; for (int i = 0; i < monitorCount; i++) { if ((monitors[i].dwFlags & monitorReserved) == 0) { int height = (monitors[i].rcMonitor.bottom - monitors[i].rcMonitor.top); if (bestMonitorIndex < 0 || height > bestMonitorHeight || (height == bestMonitorHeight && monitors[i].rcMonitor.left < bestMonitorX)) { bestMonitorIndex = i; bestMonitorHeight = height; bestMonitorX = monitors[i].rcMonitor.left; } } } if (bestMonitorIndex >= 0) { DEBUG_STREAM << "Using monitor " << bestMonitorIndex << " as primary monitor." << std::endl; mPrimaryIndex = new int; *mPrimaryIndex = bestMonitorIndex; monitors[bestMonitorIndex].dwFlags |= monitorReserved; } else { DEBUG_STREAM << "Could not find decent primary monitor. Likely no unclaimed monitors." << std::endl; } } if (mPrimaryIndex != NULL && isWindowed) { DEBUG_STREAM << "Game is currently running windowed mode- will set all remaining undefined monitors to be the same as the primary monitor." << std::endl; if (mSecondaryIndex == NULL) { mSecondaryIndex = new int; *mSecondaryIndex = *mPrimaryIndex; } if (mAux1Index == NULL && mAux2Index == NULL) { mAux1Index = new int; *mAux1Index = *mPrimaryIndex; mAux2Index = new int; *mAux2Index = *mPrimaryIndex; } } else if (!isWindowed && mSecondaryIndex == NULL) { DEBUG_STREAM << "Detecting secondary monitor- will attempt to use furthest-left remaining monitor." << std::endl; //Pick the leftmost remaining monitor int leftmostIndex = -1; int leftmostX = 0; for (int i = 0; i < monitorCount; i++) { if ((monitors[i].dwFlags & monitorReserved) == 0) { if (leftmostIndex < 0 || monitors[i].rcMonitor.left < leftmostX) { leftmostIndex = i; leftmostX = monitors[i].rcMonitor.left; } } } if (leftmostIndex >= 0) { DEBUG_STREAM << "Using monitor " << leftmostIndex << " as secondary monitor." << std::endl; mSecondaryIndex = new int; *mSecondaryIndex = leftmostIndex; } else { DEBUG_STREAM << "Could not find appropriate secondary monitor. Likely no unclaimed monitors remain." << std::endl; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Constructor for DPLRenderer // DPLRenderer::DPLRenderer( HWND hWnd, unsigned int screenWidth, unsigned int screenHeight, bool fullscreen, InterestType interest_type, InterestDepth depth_calibration ): VideoRenderer( 1.0f, 1.0f, RendererPriority::DefaultRendererPriority, interest_type, depth_calibration ), projectile_list(NULL), dplObjectCacheSocket(NULL, False), dplJointToDCSTranslatorSocket(NULL,False), dplRenderableSocket(NULL), mRenderables(NULL), x_size(screenWidth), y_size(screenHeight), mReticle(NULL), mCamShipHUD(NULL), mStaticObjectsHead(NULL), mStaticObjectsCount(0), mPrimaryIndex(NULL), mSecondaryIndex(NULL), mAux1Index(NULL), mAux2Index(NULL) { __int64 frequency = HiResCounterFreq(); #ifdef LOGFRAMERATE FRAMERATE_LOG = fopen("framerate.log", "wb"); fwrite(&frequency, sizeof(__int64), 1, FRAMERATE_LOG); #endif mCamera = NULL; loadTables(); // clear out our render lists memset(mRenderLists, 0, sizeof(mRenderLists)); memset(mNameTextures, 0, sizeof(mNameTextures)); memset(mOrdinalTextures, 0, sizeof(mOrdinalTextures)); D3DXCreateMatrixStack(0, &m_MatrixStack); m_MatrixStack->LoadIdentity(); gD3D = Direct3DCreate9(D3D_SDK_VERSION); if (!gD3D) { DEBUG_STREAM<<"Couldn't create Direct3D interface!"<FindBestAdapterIndices(!fullscreen); memset(&mPresentParams, 0, sizeof(D3DPRESENT_PARAMETERS)); mPresentParams.BackBufferCount = 1; mPresentParams.MultiSampleType = (D3DMULTISAMPLE_TYPE)atol(getenv("MULTISAMPLE")); if (mPresentParams.MultiSampleType > 0) { gD3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, !fullscreen, mPresentParams.MultiSampleType, &mPresentParams.MultiSampleQuality); mPresentParams.MultiSampleQuality--; } mPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD; mPresentParams.hDeviceWindow = hWnd; mPresentParams.Flags = 0; mPresentParams.FullScreen_RefreshRateInHz = (fullscreen)?60:D3DPRESENT_RATE_DEFAULT; mPresentParams.PresentationInterval = D3DPRESENT_RATE_DEFAULT; mPresentParams.BackBufferFormat = D3DFMT_X8R8G8B8; mPresentParams.EnableAutoDepthStencil = TRUE; mPresentParams.AutoDepthStencilFormat = D3DFMT_D24X8; mPresentParams.Windowed = !fullscreen; if (fullscreen) { mPresentParams.BackBufferWidth = screenWidth; mPresentParams.BackBufferHeight = screenHeight; } HRESULT hr; //DEBUG_STREAM<<"**************************"<GetAdapterModeCount(adapter, format); // DEBUG_STREAM<EnumAdapterModes(adapter, format, mode, &displayMode); // if (FAILED(hr)) // { // DEBUG_STREAM<<"\t\tFailed to retrieve display mode "<CreateDevice(*mPrimaryIndex, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &mPresentParams, &mDevice)); if (FAILED(hr)) { DEBUG_STREAM<<"Couldn't create HARDWARE_VERTEXPROCESSING device."<CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &mPresentParams, &mDevice)); if (FAILED(hr)) { PostQuitMessage(1); } } mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 0.0f, 0); mDevice->Present(NULL, NULL, NULL, NULL); ParticleEngine::Initialize(mDevice); SetCoreRenderStates(); //STUBBED: DPL RB 1/14/07 char Eye_Type[50], *Eye_Arg, // Controls generation of the eye point *DPL_Arg; // Points to DPLARG environment pointer once we get it int psfx_number; // int // i; // Temporary loop counter float eye_x, eye_y, eye_z, eye_x_rot, eye_y_rot, eye_z_rot; // // Initialize a bunch of the variables to their starting values // eyeRelative = False; completeCycleNeeded = False; lastAppState = 0; fogUpdating = True; fogRed = 0.0f; fogBlue = 0.0f; fogGreen = 0.0f; fogNear = 0.0f; fogFar = 0.0f; currentFogFar = 0.0f; currentFogNear = 0.0f; searchLightFogRed = 0.0f; searchLightFogGreen = 0.0f; searchLightFogBlue = 0.0f; searchLightFogNear = 0.0f; searchLightFogFar = 0.0f; noSearchLightFogRed = 0.0f; noSearchLightFogGreen = 0.0f; noSearchLightFogBlue = 0.0f; noSearchLightFogNear = 0.0f; noSearchLightFogFar = 0.0f; clipNear = 0.0f; clipFar = 0.0f; mEnvAmbient = 0x00404040; // bring-up floor until the env ambient loads mCloudRed = mCloudGreen = mCloudBlue = 1.0f; // no cloud tint until env sets it mCloudEmitRed = mCloudEmitGreen = mCloudEmitBlue = 0.0f; backgroundRed = 0.0f; backgroundGreen = 0.0f; backgroundBlue = 0.0f; viewAngle = 30.0f; dplMainView = NULL; dplDeathZone = NULL; dplMainZone = NULL; vehicleReticle = NULL; dplHitInstance = NULL; dplHitDCS = NULL; dplHitGeoGroup = NULL; dplHitGeometry = NULL; delayedDCSCount = 0; myUniqueID = 0; sceneLightDCS = NULL; sceneLight = NULL; sceneLightCount = 0; worldToEyeMatrix = LinearMatrix::Identity; // the current world to eye transform for our linked entity currentFrameTime = Now(); // the time at the start of renderable execution Verify(!DPLHeap); // DPLHeap = new UserHeap("DPL Heap", 2000000); Register_Object(DPLHeap); // // Clear the myPSFXDescriptons array to all zeros so we can detect attempts // to use uninitialized items. // memset(myPSFXDescriptons, 0, sizeof(myPSFXDescriptons)); // // These guys will come out of a world environment variable eventually // eye_x = 0.0f; eye_y = 10.0f; eye_z = 0.0f; eye_x_rot = 0.0f; eye_y_rot = 0.0f; eye_z_rot = 0.0f; // // Get pointers to environmentals containing DPL startup arguments and // eye positioning information. If L4EYES is present set the renderer // variable that controls the hooking up of the eye position. // Eye_Type[0] = 0; DPL_Arg = getenv("DPLARG"); Eye_Arg = getenv("L4EYES"); if(Eye_Arg) { sscanf( Eye_Arg, "%f %f %f %f %f %f %s", &eye_x, &eye_y, &eye_z, &eye_x_rot, &eye_y_rot, &eye_z_rot, Eye_Type); printf("%f, %f, %f %f, %f, %f\n", eye_x, eye_y, eye_z, eye_x_rot, eye_y_rot, eye_z_rot); Disconnected_Eye = True; // tells vidrend:: to request outside view of linked entity if(*Eye_Type == 'r') { DEBUG_STREAM<<"DPLRenderer::DPLRenderer Eye will be offset relative to vehicle\n" << std::flush; eyeRelative = True; } } // // If the argument was empty, we can't render !!! should exit sensiblly // if(!DPL_Arg) { DEBUG_STREAM << "DPLARG must be set for the Division card to come up\n" << std::flush; Verify(DPL_Arg); } // // If we're still here, try to interpret and setup the screen resolution // requested by DPLARG. The screen_resolution function is Phil's routine // in startdpl. // // if (screen_resolution ( DPL_Arg ) == 0) // { // DEBUG_STREAM << "DPLARG is bad, I couldn't understand video format\n" << std::flush; // Verify(DPL_Arg); // } // // Breakdown the DPLARGS string using expload_args from startdpl, then feed // the results to the dpl_Init routine to get DPL up and running. // char *argv[32]; // int argc = explode_args ( argv, DPL_Arg, dpl_arg_sep ); // dpl_Init ( argc, argv ); // // Setup the file paths for geometry and texture loading // // dpl_SetObjectFilePath ( ".\\video", "\\video", "..\\video" ); // dpl_SetTexmapFilePath ( ".\\video", "\\video", "..\\video" ); // dpl_SetMaterialFilePath ( ".\\video", "\\video", "..\\video" ); // dpl_SetObjectFilePath ( ".\\video", "", "" ); // std::cout<= PASS_TOTAL_COUNT) return; for (d3d_OBJECT *iter = mRenderLists[pass]; iter; iter = iter->GetNext(pass)) if ((void*)iter == (void*)object) return; object->SetPrevious(NULL, pass); object->SetNext(mRenderLists[pass], pass); if (mRenderLists[pass] != NULL) mRenderLists[pass]->SetPrevious(object, pass); mRenderLists[pass] = object; } hyper DPLRenderer::HashAdd(hyper input, char data) { const hyper multiplier = 37; return (input * multiplier) + data; } hyper DPLRenderer::HashDrawOp(L4DRAWOP *op) { char diffR = (char)(op->material.Diffuse.r * 255); char diffG = (char)(op->material.Diffuse.g * 255); char diffB = (char)(op->material.Diffuse.b * 255); char diffA = (char)(op->material.Diffuse.a * 255); char ambA = (char)(op->material.Ambient.a * 255); char ambR = (char)(op->material.Ambient.r * 255); char ambG = (char)(op->material.Ambient.g * 255); char ambB = (char)(op->material.Ambient.b * 255); char spcA = (char)(op->material.Specular.a * 255); char spcR = (char)(op->material.Specular.r * 255); char spcG = (char)(op->material.Specular.g * 255); char spcB = (char)(op->material.Specular.b * 255); char spcP = (char)(op->material.Power * 255); char emiA = (char)(op->material.Emissive.a * 255); char emiR = (char)(op->material.Emissive.r * 255); char emiG = (char)(op->material.Emissive.g * 255); char emiB = (char)(op->material.Emissive.b * 255); const hyper startValue = 37; hyper hash = startValue; hash = HashAdd(hash, diffA); hash = HashAdd(hash, diffR); hash = HashAdd(hash, diffG); hash = HashAdd(hash, diffB); hash = HashAdd(hash, ambA); hash = HashAdd(hash, ambR); hash = HashAdd(hash, ambG); hash = HashAdd(hash, ambB); hash = HashAdd(hash, spcA); hash = HashAdd(hash, spcR); hash = HashAdd(hash, spcG); hash = HashAdd(hash, spcB); hash = HashAdd(hash, spcP); hash = HashAdd(hash, emiA); hash = HashAdd(hash, emiR); hash = HashAdd(hash, emiG); hash = HashAdd(hash, emiB); hash = HashAdd(hash, (char)op->drawAsDecal); hash = HashAdd(hash, (char)op->alphaTest); hash = HashAdd(hash, (char)op->drawAsSky); char *pointerPointer = (char*)(&(op->texture.texture)); for (int i = 0; i < 4; i++) { hash = HashAdd(hash, pointerPointer[i]); } return hash; } void DPLRenderer::AddStaticObject(d3d_OBJECT *object) { object->SetPrevious(NULL, -1); object->SetNext(mStaticObjectsHead, -1); if (mStaticObjectsHead != NULL) mStaticObjectsHead->SetPrevious(object, -1); mStaticObjectsHead = object; mStaticObjectsCount++; } void DPLRenderer::RecurseStaticObject(HierarchicalDrawComponent *obj) { if (obj->IsStatic()) { if (obj->GetDrawObj() != NULL && obj->GetDrawObj()->GetMesh() != NULL) { // ADDITIVE_LODS objects (decoded IG-board semantics, see bgfload.cpp // TAG_OBJECT) carry per-op distance bands [0..OutDist) that DrawMesh // gates each frame -- merging them into a consolidated static would // draw every LOD of the composite simultaneously forever. Leave any // object with a restricted band OUT of consolidation; its component // keeps drawing it individually with the per-op band test. bool banded = false; d3d_OBJECT *dobj = obj->GetDrawObj(); for (int opn = 0; opn < dobj->GetDrawOpCount() && !banded; opn++) { const L4DRAWOP *op = dobj->GetDrawOp(opn); if (op->lodFar > 0.0f && op->lodFar < 1.0e8f) banded = true; } // baked ground-shadow models draw via the mIsShadow blend path // (translucent + depth bias); merging them would draw them opaque. if (dobj->GetIsShadow()) banded = true; if (!banded) { //Only load it for a static object if it has a valid mesh- //we'll handle valid sphere lists later this->AddStaticObject(obj->GetDrawObj()); obj->ResetDrawObj(); } } std::vector::const_iterator child_it = obj->Enumerate(); while (child_it != obj->End()) { RecurseStaticObject(*child_it); ++child_it; } } } d3d_OBJECT * DPLRenderer::ConsolidateSingleObject(LPD3DXMESH *meshes, D3DXMATRIX *transforms, UINT startingMesh, UINT meshCount, hash_map subsetHash, hash_map hashToOp, vector finalOps) { HRESULT hr; LPD3DXMESH outMesh = NULL; // BT bring-up: the pod content ships .bgf, loaded by d3d_OBJECT::LoadObjectBGF // with D3DXMESH_32BIT (32-bit index buffer). D3DXConcatenateMeshes was called // with only D3DXMESH_MANAGED (16-bit output) -> concatenating 32-bit-index // source meshes into a 16-bit output fails, leaving outMesh NULL -> the // GetNumFaces() below dereferenced NULL and crashed (RP never hit this: its // world meshes load from .x as 16-bit). Match the source meshes' index width. V( D3DXConcatenateMeshes(meshes + startingMesh, meshCount, D3DXMESH_MANAGED | D3DXMESH_32BIT, transforms + startingMesh, NULL, NULL, mDevice, &outMesh) ); if (outMesh == NULL) { DEBUG_STREAM << "ConsolidateSingleObject: D3DXConcatenateMeshes failed (hr=0x" << std::hex << (unsigned)hr << std::dec << "), skipping " << meshCount << " static meshes\n" << std::flush; return NULL; } DWORD *attributes; int numFaces = outMesh->GetNumFaces(); V( outMesh->LockAttributeBuffer(0, &attributes) ); for (int i = 0; i < numFaces; i++) { stdext::hash_map::const_iterator face_it = subsetHash.find(attributes[i]); if (face_it == subsetHash.end()) { //Freak out } stdext::hash_map::const_iterator subset_it = hashToOp.find((*face_it).second); if (subset_it == hashToOp.end()) { //Freak out } attributes[i] = (*subset_it).second; } // // PORT (draw-cost fix): sort the faces by draw-op OURSELVES and record each // op's contiguous index range for the direct-draw path. The old path relied // on GenerateAdjacency + OptimizeInplace(ATTRSORT) to build D3DX's attribute // table -- but the concatenated source meshes are double-sided BGF geometry, // whose degenerate adjacency makes the optimize FAIL silently. DrawSubset then // SCANS the whole attribute buffer of this huge merged mesh per call (~350us // x ~1300 ops when a merged map chunk is in view = the ~500ms hitch frames). // const int numOps = (int)finalOps.size(); std::vector opStart(numOps, 0), opCount(numOps, 0); { DWORD *ib = NULL; V( outMesh->LockIndexBuffer(0, (void **)&ib) ); // 32-bit (created 32BIT above) if (ib != NULL) { int badAttr = 0; // remap failures (see audit below) for (int i = 0; i < numFaces; i++) { DWORD op = attributes[i]; if ((int)op >= numOps) { op = 0; ++badAttr; } // SAME clamp as the write pass ++opCount[op]; } for (int o = 1; o < numOps; ++o) opStart[o] = opStart[o - 1] + opCount[o - 1]; std::vector sortedIB((size_t)numFaces * 3); std::vector sortedAttr((size_t)numFaces); std::vector cursor(opStart.begin(), opStart.end()); for (int i = 0; i < numFaces; i++) { DWORD op = attributes[i]; if ((int)op >= numOps) op = 0; const int dst = cursor[op]++; sortedIB[(size_t)dst * 3 + 0] = ib[(size_t)i * 3 + 0]; sortedIB[(size_t)dst * 3 + 1] = ib[(size_t)i * 3 + 1]; sortedIB[(size_t)dst * 3 + 2] = ib[(size_t)i * 3 + 2]; sortedAttr[dst] = op; } memcpy(ib, sortedIB.data(), sortedIB.size() * sizeof(DWORD)); memcpy(attributes, sortedAttr.data(), sortedAttr.size() * sizeof(DWORD)); V( outMesh->UnlockIndexBuffer() ); // AUDIT (turret-panels hunt): faces whose remapped attribute is out of // range mean the subsetHash/hashToOp lookup FAILED for their source op // ("Freak out" above is a no-op) -- those faces draw with op 0's material // or, before this counting fix, corrupted neighbouring ranges. DEBUG_STREAM << "[consol] group: srcMeshes=" << meshCount << " faces=" << numFaces << " ops=" << numOps << " badAttr=" << badAttr << "\n" << std::flush; } } V( outMesh->UnlockAttributeBuffer() ); // explicit attribute table over the now-sorted faces (keeps DrawSubset and any // D3DX consumer valid; the direct-draw ranges below are the primary path) { std::vector atable((size_t)numOps); for (int o = 0; o < numOps; ++o) { atable[o].AttribId = (DWORD)o; atable[o].FaceStart = (DWORD)opStart[o]; atable[o].FaceCount = (DWORD)opCount[o]; atable[o].VertexStart = 0; atable[o].VertexCount = outMesh->GetNumVertices(); } V( outMesh->SetAttributeTable(atable.data(), (DWORD)numOps) ); } d3d_OBJECT *consolObj = new d3d_OBJECT(mDevice, outMesh, NULL, finalOps.size()); // direct-draw ranges + cached buffers (same fast path as LoadObjectBGF objects) outMesh->GetVertexBuffer(&consolObj->mBgfVB); outMesh->GetIndexBuffer(&consolObj->mBgfIB); consolObj->mBgfStride = outMesh->GetNumBytesPerVertex(); consolObj->mBgfNumVerts = outMesh->GetNumVertices(); for (int o = 0; o < numOps; ++o) { consolObj->GetDrawOp(o)->bgfStartIndex = opStart[o] * 3; consolObj->GetDrawOp(o)->bgfPrimCount = opCount[o]; } for (int drawOpInd = 0; drawOpInd < consolObj->GetDrawOpCount(); drawOpInd++) { L4DRAWOP *op = consolObj->GetDrawOp(drawOpInd); L4DRAWOP *source = finalOps[drawOpInd]; op->material = source->material; op->texture = source->texture; op->drawAsDecal = source->drawAsDecal; op->alphaTest = source->alphaTest; op->drawAsSky = source->drawAsSky; // CONSOLIDATED-WORLD DEPTH RECESSION (coplanar cross-object resolution): // entity props lay flat polys EXACTLY in the floor plane (MECHMOVR's // dead-mech ground plates: 71 verts at y=0.000 vs afloor's y=0 top -- // the "flickering floor tile under the wreckage"). The board's global // submission-order rule drew scene traversal LAST-over-FIRST on exact // plane ties; in D3D terms, recess the merged static world by 3 depth- // buffer steps so anything drawn individually (entity props, banded // structures, the mech) deterministically wins floor-plane ties. // 7.5e-7 NDC ~ 3 LSB of D24: invisible as parallax, decisive vs // interpolation rounding. op->lodDepthBias = 7.5e-7f; if (op->texture.texture != NULL) { op->texture.texture->AddRef(); } } return consolObj; } void DPLRenderer::ConsolidateStaticObjects() { HRESULT hr; // Consolidation runs by DEFAULT (the shipping-engine configuration). It is // skipped when (a) BT_CONSOL=0 (diagnostic kill-switch), or (b) the // EXPERIMENTAL runtime-LOD selection is on (BT_LODSEL=1): merged ops combine // many instances + LOD bands of one material, so per-op band selection cannot // survive the merge (a consolidated run draws every LOD simultaneously). { const char *cv = getenv("BT_CONSOL"); const char *lv = getenv("BT_LODSEL"); const bool lodSel = (lv != 0 && *lv == '1'); if ((cv != 0 && *cv == '0') || lodSel) { DEBUG_STREAM << "[consol] OFF (" << (lodSel ? "BT_LODSEL experimental" : "BT_CONSOL=0") << ") -- statics render individually\n" << std::flush; return; } } HierarchicalDrawComponent *drawComp; SChainIteratorOf iterator(&mRenderables); while ((drawComp = iterator.ReadAndNext()) != NULL) { if (drawComp->IsStatic()) { drawComp->Execute(); this->RecurseStaticObject(drawComp); } } LPD3DXMESH *meshes = new LPD3DXMESH[mStaticObjectsCount]; D3DXMATRIX *transforms = new D3DXMATRIX[mStaticObjectsCount]; int i = 0; int opCount = 0; std::vector finalOps; stdext::hash_map hashToOp; stdext::hash_map subsetHash; int vertCount = 0; int startMesh = 0; int meshCount = 0; for (d3d_OBJECT *obj = mStaticObjectsHead; obj; obj = obj->GetNext(-1), i++) { if (vertCount + obj->GetMesh()->GetNumVertices() > 65535) { d3d_OBJECT *consol = this->ConsolidateSingleObject(meshes, transforms, startMesh, meshCount, subsetHash, hashToOp, finalOps); if (consol != NULL) this->mConsolidatedStaticObjects.push_back(consol); vertCount = 0; startMesh = meshCount; meshCount = 0; opCount = 0; //Clear the draw ops lists finalOps.clear(); hashToOp.clear(); subsetHash.clear(); } meshes[i] = obj->GetMesh(); transforms[i] = obj->GetLocalToWorld(); vertCount += meshes[i]->GetNumVertices(); meshCount++; for (int opNum = 0; opNum < obj->GetDrawOpCount(); opNum++) { hyper hash = this->HashDrawOp(obj->GetDrawOp(opNum)); stdext::hash_map::const_iterator hash_it = hashToOp.find(hash); if (hash_it == hashToOp.end()) { finalOps.insert(finalOps.end(), obj->GetDrawOp(opNum)); hashToOp.insert(std::pair(hash, (DWORD)(finalOps.size() - 1))); hash_it = hashToOp.find(hash); } subsetHash.insert(std::pair((DWORD)opCount, hash)); opCount++; } } if (meshCount > 0) { d3d_OBJECT *consol = this->ConsolidateSingleObject(meshes, transforms, startMesh, meshCount, subsetHash, hashToOp, finalOps); if (consol != NULL) this->mConsolidatedStaticObjects.push_back(consol); } d3d_OBJECT *obj = mStaticObjectsHead; while (obj != NULL) { d3d_OBJECT *next = obj->GetNext(-1); delete obj; obj = next; } mStaticObjectsHead = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // RemoveDynamicRenderable removes a renderable from the dynamic execution // socket. // void DPLRenderer::RemoveDynamicRenderable(Component *my_renderable) { Check(my_renderable); Check(&dplRenderableSocket); PlugIterator remover(my_renderable); remover.RemoveSocket(&dplRenderableSocket); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void DPLRenderer::SetFogStyle(FogStyle my_fog) { //STUBBED: DPL RB 1/14/07 switch(my_fog) { case updateFogSetting: fogUpdating = True; break; case noUpdateFogSetting: fogUpdating = False; break; case searchLightOnFogStyle: fogRed = searchLightFogRed; fogGreen = searchLightFogGreen; fogBlue = searchLightFogBlue; fogNear = searchLightFogNear; fogFar = searchLightFogFar; if(fogUpdating) { mDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_XRGB((int)(255 * fogRed), (int)(255 * fogGreen), (int)(255 * fogBlue))); // dpl_SetViewFog( // dplMainView, // dpl_fog_type_pixel_lin, // fogRed, // fogGreen, // fogBlue, // fogNear, // fogFar ); // dpl_FlushView(dplMainView); } break; case searchLightOffFogStyle: fogRed = noSearchLightFogRed; fogGreen = noSearchLightFogGreen; fogBlue = noSearchLightFogBlue; fogNear = noSearchLightFogNear; fogFar = noSearchLightFogFar; if(fogUpdating) { mDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_XRGB((int)(255 * fogRed), (int)(255 * fogGreen), (int)(255 * fogBlue))); // dpl_SetViewFog( // dplMainView, // dpl_fog_type_pixel_lin, // fogRed, // fogGreen, // fogBlue, // fogNear, // fogFar ); // dpl_FlushView(dplMainView); } break; case winnersCircleFogStyle: // // HACK!! This really shouldn't reset the clip planes, but since // it only happens at the end of the review, it should be safe for now. // // dpl_SetViewClipPlanes ( dplMainView, 0.25f, 1100.0f ); // dpl_SetViewFog( // dplMainView, // dpl_fog_type_pixel_lin, // 0.32, // 0.3, // 0.65, // 100.0f, // 1050.0f ); // dpl_FlushView(dplMainView); break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void DPLRenderer::GetCurrentFogSettings( float *fog_Red, float *fog_Green, float *fog_Blue, float *fog_Near, float *fog_Far) { *fog_Red = fogRed; *fog_Green = fogGreen; *fog_Blue = fogBlue; *fog_Near = fogNear; *fog_Far = fogFar; } void DPLRenderer::SetCurrentFogLimits( float fog_Near, float fog_Far) { currentFogNear = fog_Near; currentFogFar = fog_Far; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MarkDCSHiearchy This will std::decend a DCS tree and set the appSpecific hook // in every DCS equal to the entity pointer "entity", it calls itself recursively // to do this. // void DPLRenderer::MarkDCSHiearchy( dpl_DCS *root_DCS, // Root of the hiearchy to mark Entity *entity) // Entity pointer to mark it with { //STUBBED: DPL RB 1/14/07 //int // dcs_counter; //dpl_DCS // *child_DCS; //// //// First, mark this DCS //// //if(dpl_GetAppSpecific(root_DCS)) // Fail("DPLRenderer::MarkDCSHiearchy tried to mark a DCS that was already marked!\n"); //dpl_PutAppSpecific(root_DCS,entity); //// //// Now call this routine on all this dcs's children //// //dcs_counter = 0; //while((child_DCS=dpl_GetDCSChildDCS(root_DCS,dcs_counter)) != NULL) //{ // MarkDCSHiearchy(child_DCS, entity); // dcs_counter++; //} } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ReadPSFX // reads a pfx file into a supplied array // Most of this routine was a direct copy of phil's code and as such is a bit // on the messy side. // dpl_PARTICLESTART_EFFECT_INFO* DPLRenderer::ReadPSFX( const char *file_name) // Name of the file containing the PSFX description { //STUBBED: DPL RB 1/14/07 // FILE // *fp; // int // i, // status; // char // line[256], // *cp; // // // // Open the file containing the psfx, fail if it doesn't exist // // // strcpy(line,"video\\"); // strcat(line,file_name); // fp = fopen ( line, "rt" ); // if(!fp) // { // DEBUG_STREAM<<"Could not open pfx file "<tex = dpl_LookupTexture ( cp, dpl_lookup_normal, &status ); // #if PRINT_THE_PFX // printf ( "texture => %s\n", cp ); // #endif // // // // The remander of these statements get the rest of the PFX data // // // cp = fgets ( line, 255, fp ); // status = sscanf ( cp, // "%x %d %f %f\n", // &psfx_info->identifier, &psfx_info->maximum_issue, &psfx_info->release_period, &psfx_info->rate ); // if(status < 4) // { // std::cout<<"pfx file "<px, &psfx_info->py, &psfx_info->pz, &psfx_info->pv ); // if(status < 4) // { // std::cout<<"pfx file "<velx, &psfx_info->vely, &psfx_info->velz, // &psfx_info->velxv, &psfx_info->velyv, &psfx_info->velzv ); // if(status < 6) // { // std::cout<<"pfx file "<rad, &psfx_info->radv, &psfx_info->exp, &psfx_info->expv, &psfx_info->dexp, &psfx_info->dexpv ); // if(status < 6) // { // std::cout<<"pfx file "<accelx, &psfx_info->accely, &psfx_info->accelz, // &psfx_info->accelxv, &psfx_info->accelyv, &psfx_info->accelzv ); // if(status < 6) // { // std::cout<<"pfx file "<atten, &psfx_info->attenv ); // if(status < 2) // { // std::cout<<"pfx file "<sRi,&psfx_info->sGi,&psfx_info->sBi,&psfx_info->sAi,&psfx_info->sRiv,&psfx_info->sGiv,&psfx_info->sBiv,&psfx_info->sAiv ); // if(status < 8) // { // std::cout<<"pfx file "<sRo,&psfx_info->sGo,&psfx_info->sBo,&psfx_info->sAo,&psfx_info->sRov,&psfx_info->sGov,&psfx_info->sBov,&psfx_info->sAov ); // if(status < 8) // { // std::cout<<"pfx file "<eRi,&psfx_info->eGi,&psfx_info->eBi,&psfx_info->eAi,&psfx_info->eRiv,&psfx_info->eGiv,&psfx_info->eBiv,&psfx_info->eAiv ); // if(status < 8) // { // std::cout<<"pfx file "<eRo,&psfx_info->eGo,&psfx_info->eBo,&psfx_info->eAo,&psfx_info->eRov,&psfx_info->eGov,&psfx_info->eBov,&psfx_info->eAov ); // if(status < 8) // { // std::cout<<"pfx file "<colour_warp, &psfx_info->alpha_warp ); // if(status < 2) // { // std::cout<<"pfx file "<dur, &psfx_info->durv ); // if(status < 2) // { // std::cout<<"pfx file "<\n" ); // /*{{{ trace the psfx*/ // printf ( "psfx_info->tex = 0x%x\n", // psfx_info->tex ); // printf ( "identifier = 0x%x ", // psfx_info->identifier ); // printf ( "maximum_issue = %d ", // psfx_info->maximum_issue ); // printf ( "release_period = %f\n", // psfx_info->release_period ); // printf ( "rate = %f ", // psfx_info->rate ); // printf ( "px = %f ", // psfx_info->px ); // printf ( "py = %f ", // psfx_info->py ); // printf ( "pz = %f ", // psfx_info->pz ); // printf ( "pv = %f\n", // psfx_info->pv ); // printf ( "velx = %f ", // psfx_info->velx ); // printf ( "vely = %f ", // psfx_info->vely ); // printf ( "velz = %f\n", // psfx_info->velz ); // printf ( "velxv = %f ", // psfx_info->velxv ); // printf ( "velyv = %f ", // psfx_info->velyv ); // printf ( "velzv = %f\n", // psfx_info->velzv ); // printf ( "rad = %f ", // psfx_info->rad ); // printf ( "radv = %f\n", // psfx_info->radv ); // printf ( "exp = %f ", // psfx_info->exp ); // printf ( "expv = %f ", // psfx_info->expv ); // printf ( "dexp = %f ", // psfx_info->dexp ); // printf ( "dexpv = %f\n", // psfx_info->dexpv ); // printf ( "accelx = %f ", // psfx_info->accelx ); // printf ( "accely = %f ", // psfx_info->accely ); // printf ( "accelz = %f ", // psfx_info->accelz ); // printf ( "accelxv = %f ", // psfx_info->accelxv ); // printf ( "accelyv = %f ", // psfx_info->accelyv ); // printf ( "accelzv = %f\n", // psfx_info->accelzv ); // printf ( "atten = %f ", // psfx_info->atten ); // printf ( "attenv = %f\n", // psfx_info->attenv ); // printf ( "sRi = %f ", // psfx_info->sRi ); // printf ( "sGi = %f ", // psfx_info->sGi ); // printf ( "sBi = %f ", // psfx_info->sBi ); // printf ( "sAi = %f\n", // psfx_info->sAi ); // printf ( "sRiv = %f ", // psfx_info->sRiv ); // printf ( "sGiv = %f ", // psfx_info->sGiv ); // printf ( "sBiv = %f ", // psfx_info->sBiv ); // printf ( "sAiv = %f\n", // psfx_info->sAiv ); // printf ( "sRo = %f ", // psfx_info->sRo ); // printf ( "sGo = %f ", // psfx_info->sGo ); // printf ( "sBo = %f ", // psfx_info->sBo ); // printf ( "sAo = %f\n", // psfx_info->sAo ); // printf ( "sRov = %f ", // psfx_info->sRov ); // printf ( "sGov = %f ", // psfx_info->sGov ); // printf ( "sBov = %f ", // psfx_info->sBov ); // printf ( "sAov = %f\n", // psfx_info->sAov ); // printf ( "eRi = %f ", // psfx_info->eRi ); // printf ( "eGi = %f ", // psfx_info->eGi ); // printf ( "eBi = %f ", // psfx_info->eBi ); // printf ( "eAi = %f\n", // psfx_info->eAi ); // printf ( "eRiv = %f ", // psfx_info->eRiv ); // printf ( "eGiv = %f ", // psfx_info->eGiv ); // printf ( "eBiv = %f ", // psfx_info->eBiv ); // printf ( "eAiv = %f\n", // psfx_info->eAiv ); // printf ( "eRo = %f ", // psfx_info->eRo ); // printf ( "eGo = %f ", // psfx_info->eGo ); // printf ( "eBo = %f ", // psfx_info->eBo ); // printf ( "eAo = %f\n", // psfx_info->eAo ); // printf ( "eRov = %f ", // psfx_info->eRov ); // printf ( "eGov = %f ", // psfx_info->eGov ); // printf ( "eBov = %f ", // psfx_info->eBov ); // printf ( "eAov = %f\n", // psfx_info->eAov ); // printf ( "colour_warp = %f ", // psfx_info->colour_warp ); // printf ( "alpha_warp = %f ", // psfx_info->alpha_warp ); // printf ( "dur = %f ", // psfx_info->dur ); // printf ( "durv = %f\n", // psfx_info->durv ); // #endif return(psfx_info); } // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // New INI file handler // routine to read in an environment from a notation file and setup lights, // spfx and such... // void DPLRenderer::DPLReadINIPage( NotationFile *master_notation_file, const char *starting_page_name, Mission *mission, Logical debug_printing) { //STUBBED: DPL RB 1/14/07 float red, green, blue, x_rotate, y_rotate, z_rotate; NameList *cache_namelist, *light_namelist, *psfx_namelist, *specialfx_namelist, *include_pages, *path_pages; NameList::Entry *entry; const char *next_include_page_name, *TempStringPtr, *compare_source; if (debug_printing) std::cout<<"DPLReadINIPage processing "<MakeEntryList(starting_page_name, "objectpath")) != NULL) { Register_Object(path_pages); for(entry = path_pages->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { mObjectPaths.insert(mObjectPaths.begin(), std::string((char *)entry->dataReference)); if (debug_printing) std::cout << "objectpath '" << (char *)entry->dataReference << "'\n"; } Unregister_Object(path_pages); delete path_pages; } if ((path_pages = master_notation_file->MakeEntryList(starting_page_name, "texmappath")) != NULL) { Register_Object(path_pages); for(entry = path_pages->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { mTexmapPaths.insert(mTexmapPaths.begin(), std::string((char *)entry->dataReference)); if (debug_printing) std::cout << "texmappath '" << (char *)entry->dataReference << "'\n"; } Unregister_Object(path_pages); delete path_pages; } if ((path_pages = master_notation_file->MakeEntryList(starting_page_name, "materialpath")) != NULL) { Register_Object(path_pages); for(entry = path_pages->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { mMaterialPaths.insert(mMaterialPaths.begin(), std::string((char *)entry->dataReference)); if (debug_printing) std::cout << "materialpath '" << (char *)entry->dataReference << "'\n"; } Unregister_Object(path_pages); delete path_pages; } if (master_notation_file->GetEntry(starting_page_name, "priorityobjectpath", &TempStringPtr)) { // dpl_AddToObjectFilePath((char *)TempStringPtr, dpl_path_system); if (debug_printing) { DEBUG_STREAM << "priorityobjectpath '" << TempStringPtr << "'" << std::endl << std::flush; } } if (master_notation_file->GetEntry(starting_page_name, "prioritytexmappath", &TempStringPtr)) { // dpl_AddToTexmapFilePath((char *)TempStringPtr, dpl_path_system); if (debug_printing) { DEBUG_STREAM << "prioritytexmappath '" << TempStringPtr << "'" << std::endl << std::flush; } } if (master_notation_file->GetEntry(starting_page_name, "prioritymaterialpath", &TempStringPtr)) { // dpl_AddToMaterialFilePath((char *)TempStringPtr, dpl_path_system); if (debug_printing) { DEBUG_STREAM << "prioritymaterialpath '" << TempStringPtr << "'" << std::endl << std::flush; } } // // Get a the list of dpl objects that should be loaded into cache and load them // if ((cache_namelist = master_notation_file->MakeEntryList(starting_page_name, "cache")) != NULL) { d3d_OBJECT *d3d_a_object; Register_Object(cache_namelist); for(entry = cache_namelist->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { d3d_a_object = d3d_OBJECT::LoadObject(mDevice, (char *)entry->dataReference); if(!d3d_a_object) DEBUG_STREAM<<"Unable to cache "<<(char *)entry->dataReference<<"\n" << std::flush; else { if(debug_printing) std::cout<<"Caching "<<(char *)entry->dataReference<<"\n"; } } Unregister_Object(cache_namelist); delete cache_namelist; } // // Get the clip range // if(master_notation_file->GetEntry(starting_page_name, "clip" ,&TempStringPtr)) { sscanf(TempStringPtr, "%f %f", &clipNear, &clipFar); if(debug_printing) std::cout<<"Clip Range "<GetEntry(starting_page_name, "backgnd" ,&TempStringPtr)) { sscanf(TempStringPtr, "%f %f %f", &backgroundRed, &backgroundGreen, &backgroundBlue); if(debug_printing) std::cout<<"Background Color "<GetEntry(starting_page_name, "viewangle" ,&TempStringPtr)) { sscanf(TempStringPtr, "%f", &viewAngle); if(debug_printing) std::cout<<"View Angle "< visible geometry has NEGATIVE view-space // Z. A LH projection expects +Z and clips everything (w<0) -> black frame. // Use the matching RH projection so the mech becomes visible. // BT (task #20): honor the live window aspect if the window has been resized // (gWindowAspect, top of file; set by L4NotifyWindowResized on WM_SIZE). D3DXMatrixPerspectiveFovRH(&mProjectionMatrix, viewAngle * (PI/180.0f), gWindowAspect > 0.0f ? gWindowAspect : (float)x_size / (float)y_size, clipNear, clipFar); //mProjectionMatrix(0, 0) *= -1; mDecalEpsilon = 0.0000005f; mDecalProjectionMatrix = mProjectionMatrix; mDecalProjectionMatrix._33 -= mDecalEpsilon; // // setup the fog // if(master_notation_file->GetEntry(starting_page_name, "fog" ,&TempStringPtr)) { sscanf(TempStringPtr, "%f %f %f %f %f", &fogNear, &fogFar, &fogRed, &fogGreen, &fogBlue); searchLightFogRed = fogRed; searchLightFogGreen = fogGreen; searchLightFogBlue = fogBlue; searchLightFogNear = fogNear; searchLightFogFar = fogFar; noSearchLightFogRed = fogRed; noSearchLightFogGreen = fogGreen; noSearchLightFogBlue = fogBlue; noSearchLightFogNear = fogNear; noSearchLightFogFar = fogFar; currentFogNear = fogNear; currentFogFar = fogFar; // Force a 0-0 black fog on startup // dpl_SetViewFog(dplMainView, dpl_fog_type_pixel_lin, 0.0, 0.0, 0.0, 0.01, 0.05); //TODO: for fog testing, just set the values here mDevice->SetRenderState(D3DRS_FOGENABLE, TRUE); mDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_XRGB((int)(255 * fogRed), (int)(255 * fogGreen), (int)(255 * fogBlue))); mDevice->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR); if(debug_printing) std::cout<<"Fog "<SetRenderState(D3DRS_FOGENABLE, TRUE); mDevice->SetRenderState(D3DRS_FOGCOLOR, D3DCOLOR_XRGB((int)(255 * fogRed), (int)(255 * fogGreen), (int)(255 * fogBlue))); mDevice->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR); } } // // setup the no searchlight fog if any // if(master_notation_file->GetEntry(starting_page_name, "nosearchlightfog" ,&TempStringPtr)) { sscanf(TempStringPtr, "%f %f %f %f %f", &noSearchLightFogNear, &noSearchLightFogFar, &noSearchLightFogRed, &noSearchLightFogGreen, &noSearchLightFogBlue); if(debug_printing) std::cout<<"nosearchlightfog "<GetEntry(starting_page_name, "ambient" ,&TempStringPtr)) { sscanf(TempStringPtr, "%f %f %f ", &red, &green, &blue); mEnvAmbient = D3DCOLOR_XRGB((int)(255 * red), (int)(255 * green), (int)(255 * blue)); mDevice->SetRenderState(D3DRS_AMBIENT, mEnvAmbient); // BT: capture for the per-frame re-assert if(debug_printing) std::cout<<"Ambient Light "<GetEntry(starting_page_name, "clouds", &TempStringPtr)) { sscanf(TempStringPtr, "%f %f %f ", &this->mCloudRed, &this->mCloudGreen, &this->mCloudBlue); } if (master_notation_file->GetEntry(starting_page_name, "cloudemit", &TempStringPtr)) { sscanf(TempStringPtr, "%f %f %f ", &this->mCloudEmitRed, &this->mCloudEmitGreen, &this->mCloudEmitBlue); } // // Get a the list of lights from this page // if ((light_namelist = master_notation_file->MakeEntryList(starting_page_name, "light")) != NULL) { Register_Object(light_namelist); // // HACK !!! All the lights must (temporarily) be defined on a single page. // The lights and their DCS's should really be stored in a light object on // a chain, or as an actual entity in the simulation. This line will throw // an exception if this rule is violated // if(light_namelist->EntryCount() != 0) { if(sceneLightCount != 0) { Fail("All lights must be defined on a single INI file page!\n"); } // // Create storage space for the dpl_LIGHT and dpl_DCS structures // sceneLightCount = light_namelist->EntryCount(); if (sceneLightCount) { sceneLight = new D3DLIGHT9[sceneLightCount]; memset(sceneLight, 0, sizeof(D3DLIGHT9) * sceneLightCount); } int current_entry = 0; for(entry = light_namelist->GetFirstEntry(); entry; entry = entry->GetNextEntry(), ++current_entry) { // // Read the parameters for the light // sscanf( (char *)entry->dataReference, "%f %f %f %f %f %f", &red, &green, &blue, &x_rotate, &y_rotate, &z_rotate); if(debug_printing) std::cout<<"Light "<<(char *)entry->dataReference<<"\n"; // // Create and rotate a dcs to hold the light, and the light itself // sceneLight[current_entry].Type = D3DLIGHT_DIRECTIONAL; sceneLight[current_entry].Diffuse.r = red; sceneLight[current_entry].Diffuse.g = green; sceneLight[current_entry].Diffuse.b = blue; sceneLight[current_entry].Diffuse.a = 1.0f; D3DXMATRIX rot, rotX, rotY, rotZ; D3DXMatrixRotationX(&rotX, x_rotate * (PI/180.0f)); D3DXMatrixRotationY(&rotY, y_rotate * (PI/180.0f)); D3DXMatrixRotationZ(&rotZ, z_rotate * (PI/180.0f)); rot = rotZ * rotX * rotY; D3DXVECTOR3 dir(0, 0, -1); D3DXVECTOR4 vec; D3DXVec3Transform(&vec, &dir, &rot); dir = D3DXVECTOR3(vec.x, vec.y, vec.z); D3DXVec3Normalize(&dir, &dir); sceneLight[current_entry].Direction.x = dir.x; sceneLight[current_entry].Direction.y = dir.y; sceneLight[current_entry].Direction.z = dir.z; mDevice->SetLight(current_entry, &sceneLight[current_entry]); mDevice->LightEnable(current_entry, TRUE); // sceneLight[current_entry] = dpl_NewLight(); // sceneLightDCS[current_entry] = dpl_NewDCS(); // dpl_AddDCSToScene ( sceneLightDCS[current_entry] ); // dpl_SetLightType ( sceneLight[current_entry], dpl_light_type_directional ); // dpl_SetLightColor ( sceneLight[current_entry], red, green, blue); // dpl_SetLightDCS ( sceneLight[current_entry], sceneLightDCS[current_entry] ); // dpl_RotateDCS ( sceneLightDCS[current_entry], z_rotate, dpl_Z ); // dpl_RotateDCS ( sceneLightDCS[current_entry], x_rotate, dpl_X ); // dpl_RotateDCS ( sceneLightDCS[current_entry], y_rotate, dpl_Y ); // dpl_FlushLight ( sceneLight[current_entry] ); // dpl_FlushDCS ( sceneLightDCS[current_entry] ); } } // // Get rid of the light entry list // Unregister_Object(light_namelist); delete light_namelist; } // // Get the list of PSFX effects we should load into RAM. RECONSTRUCTED // (was stubbed with ReadPSFX): the "psfxN=file.pfx" entries on the visited // pages ([pfx_day]/[pfx_night], include-reached from the mission's arena // page) bind each dpl effect NUMBER to its authentic .PFX definition, // loaded into the BT particle layer (BTLoadPfxFile / BTStartPfx / BTDrawPfx // at the top of this file) that DPLIndependantEffect's <100 arm consumes. // if ((psfx_namelist = master_notation_file->MakeEntryList(starting_page_name, "psfx")) != NULL) { extern int BTLoadPfxFile_slot(const char *file_name, int slot); int pfx_loaded = 0; for (entry = psfx_namelist->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { int psfx_number = atoi(entry->GetName() + 4); // "psfxN" const char *psfx_file_name = entry->GetChar(); pfx_loaded += BTLoadPfxFile_slot(psfx_file_name, psfx_number); } DEBUG_STREAM << "[pfx] page '" << starting_page_name << "': " << pfx_loaded << " effect definitions loaded\n" << std::flush; delete psfx_namelist; } //// //// (original stubbed loader retained for provenance) //// //if ((psfx_namelist = master_notation_file->MakeEntryList(starting_page_name, "psfx")) != NULL) //{ // const char *psfx_file_name; // int psfx_number; // // // // create all the PSFX on the current page // // // for( entry = psfx_namelist->GetFirstEntry(); // entry; // entry = entry->GetNextEntry()) // { // psfx_number = atoi(entry->GetName()+4); // psfx_file_name = entry->GetChar(); // if(debug_printing) // std::cout<<"psfx"< MAX_PSFX_COUNT-1) // { // Fail("PSFX id number was not in the allowed range"); // } // // // // See if we are overwriting an existing psfx // // // if(myPSFXDescriptons[psfx_number]) // { // std::cout<<"psfx#"<MakeEntryList(starting_page_name, "effect")) != NULL) { const char *effect_page_name; int status, spfx_number, version; INDIE_EFFECT spfx; memset(&spfx, 0, sizeof(PARTICLE_EFFECT)); Register_Object(specialfx_namelist); // // create all the effects on the current page // for( entry = specialfx_namelist->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { // // Get the page with this effect on it // effect_page_name = entry->GetChar(); if(debug_printing) std::cout<<"specialfx"<GetEntry(effect_page_name, "id", &spfx_number); version = 1; master_notation_file->GetEntry(effect_page_name, "version", &version); if (version < 2) continue; master_notation_file->GetEntry(effect_page_name, "texbounds", &TempStringPtr); sscanf(TempStringPtr, "%f %f %f %f", &spfx.textureBounds.left, &spfx.textureBounds.top, &spfx.textureBounds.right, &spfx.textureBounds.bottom); master_notation_file->GetEntry(effect_page_name, "rotate", (int*)&spfx.rotate); master_notation_file->GetEntry(effect_page_name, "size", &spfx.fragSize); master_notation_file->GetEntry(effect_page_name, "velocity", &spfx.velocity); master_notation_file->GetEntry(effect_page_name, "varianceX", &spfx.varianceX); master_notation_file->GetEntry(effect_page_name, "varianceY", &spfx.varianceY); master_notation_file->GetEntry(effect_page_name, "varianceZ", &spfx.varianceZ); master_notation_file->GetEntry(effect_page_name, "gravity", &spfx.gravity); master_notation_file->GetEntry(effect_page_name, "count", &spfx.fragCount); master_notation_file->GetEntry(effect_page_name, "life", &spfx.fragLifetime); if (!master_notation_file->GetEntry(effect_page_name, "max_repeat", &spfx.maxRepeat)) spfx.maxRepeat = 30.0; NameList *color_list = master_notation_file->MakeEntryList(effect_page_name, "color"); int i = 0; for (NameList::Entry *color_entry = color_list->GetFirstEntry(); color_entry; color_entry = color_entry->GetNextEntry()) { memset(&spfx.colors[i], 0, sizeof(COLOR_POINT)); spfx.colors[i].active = true; int a, r, g, b; sscanf(color_entry->GetChar(), "%f %d %d %d %d", &spfx.colors[i].time, &a, &r, &g, &b); spfx.colors[i].color.argb = D3DCOLOR_ARGB(a, r, g, b); i++; } for (;i < COLOR_POINT_COUNT; i++) { memset(&spfx.colors[i], 0, sizeof(COLOR_POINT)); } // // install the effect // int isIndie = 0; master_notation_file->GetEntry(effect_page_name, "independent", &isIndie); if (isIndie) { master_notation_file->GetEntry(effect_page_name, "maxIssue", &spfx.maxIssue); master_notation_file->GetEntry(effect_page_name, "releasePeriod", &spfx.releasePeriod); master_notation_file->GetEntry(effect_page_name, "duration", &spfx.duration); spfx.id = 1000 + spfx_number; myPSFXDescriptons[spfx_number] = spfx; } else ParticleEngine::InstallEffect(spfx_number, *((PARTICLE_EFFECT*)&spfx)); } // // Get rid of the effect entry list // Unregister_Object(specialfx_namelist); delete specialfx_namelist; } //-------------------------------------------------- // Make a list of all the include pages on this page //-------------------------------------------------- if ((include_pages = master_notation_file->MakeEntryList(starting_page_name, "include")) != NULL) { Register_Object(include_pages); // // Recursively process all the include pages // for( entry = include_pages->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { // Get the name of the next include page next_include_page_name = (char *)entry->dataReference; // Process the next page recursively through this routine DPLReadINIPage( master_notation_file, next_include_page_name, mission, debug_printing); if(debug_printing) std::cout<<"DPLReadINIPage returned to "<GetEntry(starting_page_name, "compare" ,&compare_source)) { Logical match; NameList *branch_pages; CString compare_strings[10], wild_card("*"), token_string, target_string, master_compare_string(compare_source); int token_count; ResourceFile *this_resource_file; // // Get a pointer to our resource file so we can find the name of the map // resource later in this process. // Check(application); this_resource_file = application->GetResourceFile(); Check(this_resource_file); // // Print the compare string // if(debug_printing) std::cout<<"compare = "<FindResourceDescription(mission->GetMapID()))->resourceName; // std::cout<GetMissionTime(); // std::cout<GetMissionWeather(); // std::cout<GetScenarioName(); // std::cout<MakeEntryList(starting_page_name,"branch"); Register_Object(branch_pages); for( entry = branch_pages->GetFirstEntry(); entry; entry = entry->GetNextEntry()) { CString branch_command, match_string; int compare_token; // // Get the text of the branch command and print it // branch_command = (char *)entry->dataReference; if(debug_printing) std::cout<<"branch = "<GetFileName() << "' NO MATCH FOUND!!" << std::endl; } } } // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Read environment // routine to read in an environment from a notation file and setup lights, // spfx and such... // void DPLRenderer::DPLReadEnvironment(Mission *mission) { //STUBBED: DPL RB 1/14/07 char *L4DPLcfg; // const char // *cc; NotationFile *renderer_environment; Logical debug_printing; // // Get the name of the notation file from an environmental // L4DPLcfg = getenv("L4DPLCFG"); if (!L4DPLcfg) { DEBUG_STREAM<<"L4DPLCFG not defined, using dpldflt.ini!\n" << std::flush; L4DPLcfg = "dpldflt.ini"; } // // Read the environment out of a notation file // renderer_environment = new NotationFile(L4DPLcfg); Register_Object(renderer_environment); if (renderer_environment->PageCount() == 0) { DEBUG_STREAM<<"Renderer config notation file "<PageCount() == 0); } // // Register the notation file and check it // Check(renderer_environment); // BT (task #20): reset the day/night search-path accumulators before reading // this mission's INI; DPLReadINIPage prepends each objectpath/materialpath/ // texmappath entry as it visits pages (most-specific ends up first). mObjectPaths.clear(); mMaterialPaths.clear(); mTexmapPaths.clear(); if (renderer_environment->PageExists("main")) { if (!(renderer_environment->GetLogicalEntry("main", "debug", &debug_printing))) { debug_printing=False; } DPLReadINIPage(renderer_environment, "main", mission, debug_printing); #if 0 if ((cc = dpl_GetObjectFilePath()) == NULL || *cc == NULL) { dpl_SetObjectFilePath ( ".\\video", NULL, NULL ); } if ((cc = dpl_GetTexmapFilePath()) == NULL || *cc == NULL) { dpl_SetTexmapFilePath ( ".\\video", NULL, NULL ); } if ((cc = dpl_GetMaterialFilePath()) == NULL || *cc == NULL) { dpl_SetMaterialFilePath ( ".\\video", NULL, NULL ); } #endif } else { if (!(renderer_environment->GetLogicalEntry("dpl_config", "debug", &debug_printing))) { debug_printing=False; } std::cout<<"READING OLD FORMAT INI FILE '"<GetFileName()<<"'---hope this works\n"; // dpl_SetObjectFilePath ( ".\\video", NULL, NULL ); // dpl_SetTexmapFilePath ( ".\\video", NULL, NULL ); // dpl_SetMaterialFilePath ( ".\\video", NULL, NULL ); DPLReadINIPage(renderer_environment, "dpl_config", mission, debug_printing); } if (debug_printing) { // DEBUG_STREAM << "ObjectFilePath '" << dpl_GetObjectFilePath() << "'" << std::endl << std::flush; // DEBUG_STREAM << "TexmapFilePath '" << dpl_GetTexmapFilePath() << "'" << std::endl << std::flush; // DEBUG_STREAM << "MaterialFilePath '" << dpl_GetMaterialFilePath() << "'" << std::endl << std::flush; } // // BT (task #20): push the accumulated day/night search-path priority to the // BGF/BMF/texture loader. objectpath->.bgf, materialpath->.bmf, texmappath-> // textures. This invalidates the loader's cached indices so the next object // load (the mission entities, incl. the sky dome) picks the correct // time-of-day variant of every colliding stem. // // Apply the day/night SEARCH-PATH priority for ALL indices (default ON now). // The mat\day material libs carry the AUTHENTIC per-time-of-day colour RAMPs // (rock 0.25,0.21,0.16->0.8,0.5,0.4 warm tan) which the loader now bakes into // the terrain textures -- so preferring mat\day gives the correct warm desert. // (Earlier BT_MATPRI grayed the terrain ONLY because the ramp wasn't applied: // mat\day materials have no diffuse and fell back to gray. With the ramp bake // live they are correct.) BT_MATPRI=0 falls back to first-match (generic // GEO/*.BMF gray ramps + the vertex tint) for A/B. SetVideoPathPriority("bgf", mObjectPaths); { const char *mp = getenv("BT_MATPRI"); if (mp == 0 || mp[0] != '0') { SetVideoPathPriority("bmf", mMaterialPaths); SetVideoPathPriority("img", mTexmapPaths); } } if (debug_printing) { DEBUG_STREAM << "[env] object paths (" << mObjectPaths.size() << "), material paths (" << mMaterialPaths.size() << "), texmap paths (" << mTexmapPaths.size() << ") -- most-specific first\n" << std::flush; } // // Close the notation file // Verify( !renderer_environment->IsDirty() ); Unregister_Object(renderer_environment); delete renderer_environment; // // Flush all the things we've set/changed here // // dpl_FlushView(dplMainView); return; } // //############################################################################# // Destructor for the video renderer //############################################################################# // DPLRenderer::~DPLRenderer() { delete gOpNames; delete gReplacementData; if (mPrimaryIndex != NULL) { delete mPrimaryIndex; } if (mSecondaryIndex != NULL) { delete mSecondaryIndex; } if (mAux1Index != NULL) { delete mAux1Index; } if (mAux2Index != NULL) { delete mAux2Index; } SAFE_RELEASE(mDevice); SAFE_RELEASE(gD3D); //STUBBED: DPL RB 1/14/07 //int // psfx_number; ////------------------------------------------------------ //// release allocated memory used by dump_frame_buffer() ////------------------------------------------------------ //dump_frame_buffer(NULL, NULL, NULL, NULL); //// //// Delete any memory allocated to hold psfx effect descriptions //// //for( psfx_number = 0; psfx_number < MAX_PSFX_COUNT; psfx_number++) //{ // if(myPSFXDescriptons[psfx_number]) // { // delete myPSFXDescriptons[psfx_number]; // Unregister_Pointer(myPSFXDescriptons[psfx_number]); // myPSFXDescriptons[psfx_number] = NULL; // } //} //// ////~~~~~~~~~~~~~~~~~~ //// Delete all Lights ////~~~~~~~~~~~~~~~~~~ //// //if (ambientLight) //{ // Check_Pointer(ambientLight); // Unregister_Pointer(ambientLight); // dpl_DeleteLight(ambientLight); //} //if (sceneLightDCS && sceneLight) //{ // Check_Pointer(sceneLightDCS); // for(int ii=0;iiLockRect(0, &lockedRect, NULL, D3DLOCK_DISCARD); // // Figure out the position to start copying the data at // Word *word_pointer = bitmap_to_load->Data.MapPointer; __int16 *pixel_pointer = (__int16*)lockedRect.pBits; // // Actually process the texels // int bit_mask = 0x8000; for(int y = 0; y < 32; y++) { for(int x = 0; x < 128; x++) { if (*word_pointer & bit_mask) *(pixel_pointer++) = 0xFFFF; else *(pixel_pointer++) = 0x0000; bit_mask >>= 1; if (bit_mask == 0) { bit_mask = 0x8000; word_pointer++; } } } // unlock the texture now that we're done updating it local_storage->UnlockRect(0); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CacheExplosionScripts // Handles code to preload the morph and other caches with things needed by // explosion scripts. Should be called at startup, once for each. // void DPLRenderer::CacheExplosionScripts( int script_select) // The script to be cached { //STUBBED: DPL RB 1/14/07 // dpl_OBJECT // *object; // // // // Load the morph targets into the MUNGA object cache // // // switch(script_select) // { // case 104: // Thor death explosion // case 106: // Thor death explosion // { // dpl_LoadObject("flamebig.bgf", dpl_load_normal); // dpl_LoadObject("thrdbr.bgf" , dpl_load_normal); // dpl_LoadObject("ldbr.bgf" , dpl_load_normal); // dpl_LoadObject("flamesml.bgf", dpl_load_normal); //// DEBUG_STREAM << "explosion "<< script_select<<" cached\n" << std::flush; // break; // } // } } // //############################################################################# // ExplosionScripts // Contains several scripts for running various types of explosion effects. //############################################################################# // void DPLRenderer::ExplosionScripts( Entity *entity, // The entity we are dealing with ResourceDescription* ,//model_resource, // Pointer to the video resource ViewFrom ,//view_type, // Type of reference (inside/outside...etc.) int script_select) { //STUBBED: DPL RB 1/14/07 // dpl_OBJECT // *object_1; // // // // Construct a root renderable to hang the explosion effects on // // // RootRenderable *this_root = // new RootRenderable( // entity, // Entity to attach the renderable to // RootRenderable::Dynamic, // How/when to execute the renderable // NULL, // object to hang on the DCS, may be a list later // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL); // intersection mask for the object // Register_Object(this_root); // // // // Select which script to construct // // // switch(script_select) // { // case 0: // Shock wave // { // // // // Load object(s) we will be using for the explosions // // // object_1 = dpl_LoadObject("shock.bgf", dpl_load_normal); // // // // Setup control variables and transforms we need // // // Vector3D scaling_velocity_1(3.5, 3.5, 3.5); // Vector3D velocity_accel_1(0.0, 0.0, 0.0); // LinearMatrix explosion_1_offset(True); // // // // Create the scaling explosion renderables // // // ScalingExplosionRenderable *explosion_1 = // new ScalingExplosionRenderable( // entity, // Entity to attach the renderable to // ScalingExplosionRenderable::Dynamic, // How/when to execute the renderable // object_1, // This will be the scaling explosion object // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS(), // the parent DCS we will be offsetting from // &explosion_1_offset, // offset matrix to be applied prior to joint DCS // &scaling_velocity_1, // Effect control vector, Y is acceleration, X, Z are velocity // &velocity_accel_1, // 0.0f, // NULL); // -.25 gravity is normal // Register_Object(explosion_1); // // // // Create a sweep renderable to drive the material morph // // // SweepRenderable *sweep_1 = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 0.5f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // NULL); // Register_Object(sweep_1); // // // // Lookup a texture that we can use for the morphing materials // // // int // status; // dpl_TEXTURE *effect_texture = // dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status ); // if (effect_texture == NULL) // DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush; // // // // Setup a morph material renderable for each explosion shape // // // MorphMaterialRenderable *morph_material_1 = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 1.0f,1.0f,1.0f, // Material's ambient component // 1.0f,1.0f,1.0f, // Material's emissive component // 1.0f,1.0f,1.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 4.0f,0.2f,-0.05f, // Material's opacity // effect_texture, // Material's texture pointer // 0.0f, // Material's Z dither value // 0, // Material's Fog Imunity value // 0.5f,0.5f,0.5f, // Material's ambient component // 0.5f,0.5f,0.5f, // Material's emissive component // 0.5f,0.5f,0.5f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component //// 0.25f,0.25f,-0.05f, // Material's opacity // 0.1f,0.1f,-0.05f, // Material's opacity // 0.0f, // Material's Z dither value // sweep_1->GetSweepAttribute()); // Register_Object(morph_material_1); // dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1); // if(!explosion_1_instance) // Fail("explosion_1_instance came back null\n"); // dpl_SetInstanceFrontMaterial(explosion_1_instance, morph_material_1->GetMaterial()); // dpl_FlushInstance(explosion_1_instance); // break; // } // case 1: // Big explosion // { // // // // Load object(s) we will be using for the explosions // // // object_1 = dpl_LoadObject("exp.bgf", dpl_load_normal); // // // // Setup control variables and transforms we need // // // Vector3D scaling_velocity_1(0.15, 0.15, 0.15); // Vector3D scaling_velocity_2(0.18, 0.22, 0.18); // Vector3D velocity_accel_1(0.0, 0.0, 0.0); // Vector3D velocity_accel_2(0.0, 0.0, 0.0); // LinearMatrix explosion_1_offset(True); // LinearMatrix explosion_2_offset(True); // Point3D explosion_2_translate(0.0f, 0.0f, 0.0f); // EulerAngles explosion_2_rotate(0.0f, 1.0f, 0.0f); // explosion_2_offset = explosion_2_rotate; // explosion_2_offset = explosion_2_translate; // // // // Create the scaling explosion renderables // // // ScalingExplosionRenderable *explosion_1 = // new ScalingExplosionRenderable( // entity, // Entity to attach the renderable to // ScalingExplosionRenderable::Dynamic, // How/when to execute the renderable // object_1, // This will be the scaling explosion object // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS(), // the parent DCS we will be offsetting from // &explosion_1_offset, // offset matrix to be applied prior to joint DCS // &scaling_velocity_1, // Effect control vector, Y is acceleration, X, Z are velocity // &velocity_accel_1, // 0.0f, // NULL); // -.25 gravity is normal // Register_Object(explosion_1); // ScalingExplosionRenderable *explosion_2 = // new ScalingExplosionRenderable( // entity, // Entity to attach the renderable to // ScalingExplosionRenderable::Dynamic, // How/when to execute the renderable // object_1, // This will be the scaling explosion object // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS(), // the parent DCS we will be offsetting from // &explosion_2_offset, // offset matrix to be applied prior to joint DCS // &scaling_velocity_2, // Effect control vector, Y is acceleration, X, Z are velocity // &velocity_accel_2, // 0.0f, // NULL); // Register_Object(explosion_2); // // // // Create a sweep renderable to drive the material morph // // // SweepRenderable *sweep_1 = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 3.0f, // 1, // number of times to cycle before stopping // NULL); // How long to take to sweep from 0 to 1 // Register_Object(sweep_1); // SweepRenderable *sweep_2 = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 2.0f, // 1, // number of times to cycle before stopping // NULL); // How long to take to sweep from 0 to 1 // Register_Object(sweep_2); // // // // Lookup a texture that we can use for the morphing materials // // // int // status; // dpl_TEXTURE *effect_texture = // dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status ); // if (effect_texture == NULL) // DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush; // // // // Setup a morph material renderable for each explosion shape // // // #if 0 // 0.9f,0.0f,0.0f, // Material's ambient component // 1.0f,1.0f,0.0f, // Material's emissive component // 1.0f,0.7f,0.2f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 8.0f,0.2f,-0.05f, // Material's opacity // #endif // MorphMaterialRenderable *morph_material_1 = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 0.9f,0.0f,0.0f, // Material's ambient component // 1.0f,0.2f,0.0f, // Material's emissive component // 1.0f,0.2f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 10.0f,0.6f,-0.05f, // Material's opacity // effect_texture, // Material's texture pointer // 0.0f, // Material's Z dither value // 0, // Material's Fog Imunity value // 0.3f,0.0f,0.0f, // Material's ambient component // 0.5f,0.0f,0.0f, // Material's emissive component // 0.2f,0.0f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 0.25f,0.25f,-0.05f, // Material's opacity // 15.0f, // Material's Z dither value // sweep_1->GetSweepAttribute()); // Register_Object(morph_material_1); // MorphMaterialRenderable *morph_material_2 = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 0.9f,0.0f,0.0f, // Material's ambient component // 1.0f,0.6f,0.3f, // Material's emissive component // 1.0f,0.4f,0.2f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 8.0f,0.2f,-0.05f, // Material's opacity // effect_texture, // Material's texture pointer // 0.0f, // Material's Z dither value // 0, // Material's Fog Imunity value // 0.1f,0.0f,0.0f, // Material's ambient component // 0.0f,0.0f,0.0f, // Material's emissive component // 0.1f,0.0f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 0.25f,0.25f,-0.05f, // Material's opacity // 15.0f, // Material's Z dither value // sweep_2->GetSweepAttribute()); // Register_Object(morph_material_2); // // // // Override the materials in the two explosion shapes using these morph materials // // // dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1); // dpl_INSTANCE *explosion_2_instance = dpl_GetDCSInstance(explosion_2->GetDCS(), 1); // // if(!explosion_1_instance) // Fail("explosion_1_instance came back null\n"); // if(!explosion_2_instance) // Fail("explosion_2_instance came back null\n"); // // dpl_SetInstanceFrontMaterial(explosion_1_instance, morph_material_1->GetMaterial()); // dpl_SetInstanceFrontMaterial(explosion_2_instance, morph_material_2->GetMaterial()); // // dpl_FlushInstance(explosion_1_instance); // dpl_FlushInstance(explosion_2_instance); // break; // } // case 2: // Big explosion // { // // // // Load object(s) we will be using for the explosions // // // object_1 = dpl_LoadObject("exp.bgf", dpl_load_normal); // // // // Setup control variables and transforms we need // // // Vector3D scaling_velocity_1(1.0, 0.2, 1.0); // Vector3D scaling_velocity_2(0.75, 0.75, 0.75); // Vector3D velocity_accel_1(-0.00725, -0.004, -0.00725); //// Vector3D velocity_accel_1(-0.00925, -0.00925, -0.00925); // Vector3D velocity_accel_2(-0.01388, -0.01388, -0.01388); // LinearMatrix explosion_1_offset(True); // LinearMatrix explosion_2_offset(True); // Point3D explosion_2_translate(0.0f, 0.0f, 0.0f); // EulerAngles explosion_2_rotate(0.0f, 1.0f, 0.0f); // explosion_2_offset = explosion_2_rotate; // explosion_2_offset = explosion_2_translate; // // // // Create the scaling explosion renderables // // // ScalingExplosionRenderable *explosion_1 = // new ScalingExplosionRenderable( // entity, // Entity to attach the renderable to // ScalingExplosionRenderable::Dynamic, // How/when to execute the renderable // object_1, // This will be the scaling explosion object // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS(), // the parent DCS we will be offsetting from // &explosion_1_offset, // offset matrix to be applied prior to joint DCS // &scaling_velocity_1, // Effect control vector, Y is acceleration, X, Z are velocity // &velocity_accel_1, // 0.0f, // NULL); // -.25 gravity is normal // Register_Object(explosion_1); // ScalingExplosionRenderable *explosion_2 = // new ScalingExplosionRenderable( // entity, // Entity to attach the renderable to // ScalingExplosionRenderable::Dynamic, // How/when to execute the renderable // object_1, // This will be the scaling explosion object // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS(), // the parent DCS we will be offsetting from // &explosion_2_offset, // offset matrix to be applied prior to joint DCS // &scaling_velocity_2, // Effect control vector, Y is acceleration, X, Z are velocity // &velocity_accel_2, // 0.0f, // NULL); // Register_Object(explosion_2); // // // // Create a sweep renderable to drive the material morph // // // SweepRenderable *sweep_1 = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 3.0f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // NULL); // Register_Object(sweep_1); // SweepRenderable *sweep_2 = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 2.0f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // NULL); // Register_Object(sweep_2); // // // // Lookup a texture that we can use for the morphing materials // // // int // status; // dpl_TEXTURE *effect_texture = // dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status ); // if (effect_texture == NULL) // DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush; // // // // Setup a morph material renderable for each explosion shape // // // #if 0 // 0.9f,0.0f,0.0f, // Material's ambient component // 1.0f,1.0f,0.0f, // Material's emissive component // 1.0f,0.7f,0.2f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 8.0f,0.2f,-0.05f, // Material's opacity // #endif // MorphMaterialRenderable *morph_material_1 = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 0.9f,0.0f,0.0f, // Material's ambient component // 1.0f,0.2f,0.0f, // Material's emissive component // 1.0f,0.2f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 8.0f,0.2f,-0.05f, // Material's opacity // effect_texture, // Material's texture pointer // 0.0f, // Material's Z dither value // 0, // Material's Fog Imunity value // 0.3f,0.0f,0.0f, // Material's ambient component // 0.5f,0.0f,0.0f, // Material's emissive component // 0.2f,0.0f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 0.25f,0.25f,-0.05f, // Material's opacity // 15.0f, // Material's Z dither value // sweep_1->GetSweepAttribute()); // Register_Object(morph_material_1); // MorphMaterialRenderable *morph_material_2 = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 0.9f,0.0f,0.0f, // Material's ambient component // 1.0f,0.6f,0.4f, // Material's emissive component // 1.0f,0.3f,0.2f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 8.0f,0.2f,-0.05f, // Material's opacity // effect_texture, // Material's texture pointer // 0.0f, // Material's Z dither value // 0, // Material's Fog Imunity value // 0.1f,0.0f,0.0f, // Material's ambient component // 0.0f,0.0f,0.0f, // Material's emissive component // 0.0f,0.0f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 0.25f,0.25f,-0.05f, // Material's opacity // 15.0f, // Material's Z dither value // sweep_2->GetSweepAttribute()); // Register_Object(morph_material_2); // // // // Override the materials in the two explosion shapes using these morph materials // // // dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1); // dpl_INSTANCE *explosion_2_instance = dpl_GetDCSInstance(explosion_2->GetDCS(), 1); // // if(!explosion_1_instance) // Fail("explosion_1_instance came back null\n"); // if(!explosion_2_instance) // Fail("explosion_2_instance came back null\n"); // // dpl_SetInstanceFrontMaterial(explosion_1_instance, morph_material_1->GetMaterial()); // dpl_SetInstanceFrontMaterial(explosion_2_instance, morph_material_2->GetMaterial()); // // dpl_FlushInstance(explosion_1_instance); // dpl_FlushInstance(explosion_2_instance); // break; // } // case 3: // Sparks // { // // // // Load object(s) we will be using for the explosions // // // object_1 = dpl_LoadObject("spk1.bgf", dpl_load_normal); // // // // Setup control variables and transforms we need // // // Vector3D scaling_velocity_1(0.1, 0.1, 0.1); // Vector3D velocity_accel_1(0.0, 0.0, 0.0); // LinearMatrix explosion_1_offset(True); // // // // Create the scaling explosion renderables // // // ScalingExplosionRenderable *explosion_1 = // new ScalingExplosionRenderable( // entity, // Entity to attach the renderable to // ScalingExplosionRenderable::Dynamic, // How/when to execute the renderable // object_1, // This will be the scaling explosion object // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS(), // the parent DCS we will be offsetting from // &explosion_1_offset, // offset matrix to be applied prior to joint DCS // &scaling_velocity_1, // Effect control vector, Y is acceleration, X, Z are velocity // &velocity_accel_1, // -0.15f, // NULL); // -.25 gravity is normal // Register_Object(explosion_1); // // // // Create a sweep renderable to drive the material morph // // // SweepRenderable *sweep_1 = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 0.5f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // NULL); // Register_Object(sweep_1); // // // // Lookup a texture that we can use for the morphing materials // // // int // status; // dpl_TEXTURE *effect_texture = // dpl_LookupTexture ( "btfx:firesmoke1_scr_tex", dpl_lookup_normal, &status ); // if (effect_texture == NULL) // DEBUG_STREAM<<"couldn't find texture btfx:firesmoke1_scr_tex for an effect\n" << std::flush; // // // // Setup a morph material renderable for each explosion shape // // // MorphMaterialRenderable *morph_material_1 = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 1.0f,1.0f,0.0f, // Material's ambient component // 1.0f,1.0f,0.0f, // Material's emissive component // 1.0f,1.0f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 1.0f,1.0f,1.0f, // Material's opacity // effect_texture, // Material's texture pointer // 0.0f, // Material's Z dither value // 2, // Material's Fog Imunity value // 0.9f,0.0f,0.0f, // Material's ambient component // 0.9f,0.0f,0.0f, // Material's emissive component // 0.9f,0.0f,0.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0, // Material's specular component // 1.0f,1.0f,1.0f, // Material's opacity // 0.0f, // Material's Z dither value // sweep_1->GetSweepAttribute()); // Register_Object(morph_material_1); // dpl_INSTANCE *explosion_1_instance = dpl_GetDCSInstance(explosion_1->GetDCS(), 1); // if(!explosion_1_instance) // Fail("explosion_1_instance came back null\n"); // dpl_SetInstanceFrontMaterial(explosion_1_instance, morph_material_1->GetMaterial()); // dpl_FlushInstance(explosion_1_instance); // break; // } // case 4: // A huge mech explodes (yawn) // { // Point3D null_offset(0.0f, 0.0f, 0.0f); // LinearMatrix null_offset_matrix(True); // Point3D local_height(0.0f, 6.2f, 0.0f); // height of Thor // LinearMatrix local_offset(True); // local_offset = local_height; // DPLStaticChildRenderable *local_root = // new DPLStaticChildRenderable( // entity, // false, // NULL, // dpl_isect_mode_obj, // NULL, // local_offset, // this_root->GetDCS()); // Register_Object(local_root); // // // // Load morph sources we need for the effect // // // dpl_OBJECT *thor_debris_object = dpl_LoadObject("thrdbr.bgf", dpl_load_normal); // dpl_OBJECT *large_debris_object = dpl_LoadObject("ldbr.bgf", dpl_load_normal); // dpl_OBJECT *small_flames_object = dpl_LoadObject("flamesml.bgf", dpl_load_normal); // // // // Load morph targets we need for the effect // // // //------------------------------------------------ // // Renderables to handle the chunks and fireballs // //------------------------------------------------ //#if 0 // OneShotDelayRenderable *fireball_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.25f); // How long to wait before raising the trigger // Register_Object(fireball_delay); // Point3D my_offset(0.0, 4.0, 0.0); // #if DEBUG_LEVEL > 0 // DPLPSFXRenderable* initial_boom = // #endif // new DPLPSFXRenderable( // entity, // Entity to attach the renderable to // DPLPSFXRenderable::Dynamic, // How/when to execute the renderable // fireball_delay->GetTriggerAttribute(), // address containing the trigger // myPSFXDescriptons[7], // pointer to the PFX description // this_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &my_offset); // Offset (or world coordinants if DCS is NULL) // Register_Object(initial_boom); // #if DEBUG_LEVEL > 0 // DPLEffectRenderable *chunks_effect = // #endif // new DPLEffectRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // fireball_delay->GetTriggerAttribute(), // address containing the trigger // 3, // Chunks // DPL effect number to trigger // local_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &null_offset); // Offset (or world coordinants if DCS is NULL) // Register_Object(chunks_effect); // Point3D fireball_offset(1.0f, 5.0f, 1.0f); // #if DEBUG_LEVEL > 0 // DPLEffectRenderable *fireball_effect = // #endif // new DPLEffectRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // fireball_delay->GetTriggerAttribute(), // address containing the trigger // 15, // Fireball // DPL effect number to trigger // local_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &fireball_offset); // Offset (or world coordinants if DCS is NULL) // Register_Object(fireball_effect); //#endif // OneShotDelayRenderable *fireball_delay_2 = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.55f); // How long to wait before raising the trigger // Register_Object(fireball_delay_2); // Point3D fireball_offset_2(-1.0f, 5.0f, -1.0f); // #if DEBUG_LEVEL > 0 // DPLEffectRenderable *fireball_effect_2 = // #endif // new DPLEffectRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // fireball_delay_2->GetTriggerAttribute(), // address containing the trigger // 15, // Fireball // DPL effect number to trigger // local_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &fireball_offset_2); // Offset (or world coordinants if DCS is NULL) // Register_Object(fireball_effect_2); // //----------------------------------------------- // // Renderables to handle static debris // //----------------------------------------------- // OneShotDelayRenderable *static_debris_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.25f); // How long to wait before raising the trigger // Register_Object(static_debris_delay); // DPLStaticChildRenderable *mech_debris = // new DPLStaticChildRenderable( // entity, // false, // thor_debris_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // this_root->GetDCS()); // Register_Object(mech_debris); // #if DEBUG_LEVEL > 0 // MakeDCSFall *mech_debris_fall = // #endif // new MakeDCSFall( // entity, // Entity to attach the renderable to // MakeDCSFall::Dynamic, // How/when to execute the renderable // mech_debris->GetDCS(), // the DCS to control // -0.025f, // Gravity in meters/sec squared // static_debris_delay->GetTriggerAttribute()); // true if the instance is on, false if off // Register_Object(mech_debris_fall); // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *mech_debris_instance = dpl_GetDCSInstance(mech_debris->GetDCS(), 1); // #if DEBUG_LEVEL > 0 // InstanceSwitchRenderable *mech_debris_instance_switch = // #endif // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // mech_debris_instance, // the instance to control // True, // Instance is on when trigger is... // static_debris_delay->GetTriggerAttribute()); // Register_Object(mech_debris_instance_switch); // // DPLStaticChildRenderable *large_debris = // new DPLStaticChildRenderable( // entity, // false, // large_debris_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // mech_debris->GetDCS()); // Register_Object(large_debris); // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *large_debris_instance = dpl_GetDCSInstance(large_debris->GetDCS(), 1); // #if DEBUG_LEVEL > 0 // InstanceSwitchRenderable *large_debris_instance_switch = // #endif // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // large_debris_instance, // the instance to control // True, // Instance is on when trigger is... // static_debris_delay->GetTriggerAttribute()); // Register_Object(large_debris_instance_switch); // //----------------------------------------------- // // Renderables to handle fires // //----------------------------------------------- // OneShotDelayRenderable *fires_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.25f); // How long to wait before raising the trigger // Register_Object(fires_delay); // DPLStaticChildRenderable *fires = // new DPLStaticChildRenderable( // entity, // false, // NULL, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // this_root->GetDCS()); // Register_Object(fires); // #if DEBUG_LEVEL > 0 // MakeDCSFall *fires_fall = // #endif // new MakeDCSFall( // entity, // Entity to attach the renderable to // MakeDCSFall::Dynamic, // How/when to execute the renderable // fires->GetDCS(), // the DCS to control // -0.01f, // Gravity in meters/sec squared // fires_delay->GetTriggerAttribute()); // true if the instance is on, false if off // Register_Object(fires_fall); // DPLStaticChildRenderable *small_flames = // new DPLStaticChildRenderable( // entity, // false, // small_flames_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // fires->GetDCS()); // Register_Object(small_flames); // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *small_flames_instance = dpl_GetDCSInstance(small_flames->GetDCS(), 1); // #if DEBUG_LEVEL > 0 // InstanceSwitchRenderable *small_flames_instance_switch = // #endif // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // small_flames_instance, // the instance to control // True, // Instance is on when trigger is... // fires_delay->GetTriggerAttribute()); // Register_Object(small_flames_instance_switch); // // dpl_OBJECT *big_flames_object = dpl_LoadObject("flamebig.bgf", dpl_load_normal); // DPLStaticChildRenderable *big_flames = // new DPLStaticChildRenderable( // entity, // false, // big_flames_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // fires->GetDCS()); // Register_Object(big_flames); // // Make big flames object billboard along y-axis // dpl_SetDCSReorientAxes(big_flames->GetDCS(), dpl_reorient_axes_y); // dpl_FlushDCS(big_flames->GetDCS()); // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *big_flames_instance = dpl_GetDCSInstance(big_flames->GetDCS(), 1); // #if DEBUG_LEVEL > 0 // InstanceSwitchRenderable *big_flames_instance_switch = // #endif // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // big_flames_instance, // the instance to control // True, // Instance is on when trigger is... // fires_delay->GetTriggerAttribute()); // Register_Object(big_flames_instance_switch); // // // // These renderables create the rising smoke column using a pfx effect. // // //#if 0 // Point3D my_offset2(0.0, 5.0, 0.0); // #if DEBUG_LEVEL > 0 // OnePSFXRenderable *this_effect= // #endif // new OnePSFXRenderable( // entity, // Entity to attach the renderable to // OnePSFXRenderable::Static, // How/when to execute the renderable // myPSFXDescriptons[1], // name of file with the PFX description in it // this_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &my_offset2); // Offset (or world coordinants if DCS is NULL) // Register_Object(this_effect); //#endif // break; // } // //---------------------------------------- // case 5: // Sfx #105 - Delayed ground hit // //---------------------------------------- // { // // // // Create the delayed ground hit renderables // // // Point3D null_offset(0.0f, 0.0f, 0.0f); // OneShotDelayRenderable *ground_hit_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.15f); // How long to wait before raising the trigger // Register_Object(ground_hit_delay); // #if DEBUG_LEVEL > 0 // DPLEffectRenderable *ground_hit_effect = // #endif // new DPLEffectRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // ground_hit_delay->GetTriggerAttribute(), // address containing the trigger // 12, // GroundHit // DPL effect number to trigger // this_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &null_offset); // Offset (or world coordinants if DCS is NULL) // Register_Object(ground_hit_effect); // break; // } // //------------------------------------------ // case 6: // Sfx #106 - Thor death explosion // //------------------------------------------ // { // #if 0 // int status; // used with dpl calls // Point3D null_offset(0.0f, 0.0f, 0.0f); // LinearMatrix null_offset_matrix(True); // Point3D local_height(0.0f, 6.2f, 0.0f); // height of Thor // LinearMatrix local_offset(True); // local_offset = local_height; // DPLStaticChildRenderable *local_root = // new DPLStaticChildRenderable( // entity, // false, // NULL, // dpl_isect_mode_obj, // NULL, // local_offset, // this_root->GetDCS()); // Register_Object(local_root); //#if 0 // //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv // // // // Show static thor (TEMPORARY for testing) // // // dpl_OBJECT *static_thr_object = dpl_LoadObject("thr.bgf", dpl_load_normal); // DPLStaticChildRenderable *static_thr = // new DPLStaticChildRenderable( // entity, // false, // static_thr_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // local_root->GetDCS()); // Register_Object(static_thr); // // This defines how long the static_thr stays visible // OneShotDelayRenderable *static_thr_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.5f); // How long to wait before raising the trigger // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *static_thr_instance = dpl_GetDCSInstance(static_thr->GetDCS(), 1); // InstanceSwitchRenderable *static_thr_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // static_thr_instance, // the instance to control // False, // Instance is on when trigger is... // static_thr_delay->GetTriggerAttribute()); // // // //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //#endif // // // // Load objects we will be using for the explosion effect // // // DPLObjectWrapper *flash_object_wrapper = // new DPLObjectWrapper( // entity, // Entity to attach the renderable to // "exdisk_A.bgf", // Name of the DPL object to load into the wrapper // dpl_load_nocache); // Type of loading to perform on this object // Register_Object(flash_object_wrapper); // dpl_OBJECT *flash_object_a = flash_object_wrapper->GetDPLObject(); // dpl_OBJECT *flash_object_b = dpl_LoadObject("exdisk_B.bgf", dpl_load_normal); // dpl_OBJECT *flash_object_c = dpl_LoadObject("exdisk_C.bgf", dpl_load_normal); // DPLObjectWrapper *debris_object_wrapper = // new DPLObjectWrapper( // entity, // Entity to attach the renderable to // "thrtor_A.bgf", // Name of the DPL object to load into the wrapper // dpl_load_nocache); // Type of loading to perform on this object // Register_Object(debris_object_wrapper); // dpl_OBJECT *morph_debris_a = debris_object_wrapper->GetDPLObject(); // dpl_OBJECT *morph_debris_b = dpl_LoadObject("thrtor_B.bgf", dpl_load_normal); // dpl_OBJECT *morph_debris_c = dpl_LoadObject("thrtor_C.bgf", dpl_load_normal); // DPLObjectWrapper *hips_object_wrapper = // new DPLObjectWrapper( // entity, // Entity to attach the renderable to // "thrhip_A.bgf", // Name of the DPL object to load into the wrapper // dpl_load_nocache); // Type of loading to perform on this object // Register_Object(hips_object_wrapper); // dpl_OBJECT *morph_hips_a = hips_object_wrapper->GetDPLObject(); // dpl_OBJECT *morph_hips_b = dpl_LoadObject("thrhip_B.bgf", dpl_load_normal); // dpl_OBJECT *morph_hips_c = dpl_LoadObject("thrhip_C.bgf", dpl_load_normal); // dpl_OBJECT *thor_debris_object = dpl_LoadObject("thrdbr.bgf", dpl_load_normal); // dpl_OBJECT *large_debris_object = dpl_LoadObject("ldbr.bgf", dpl_load_normal); // dpl_OBJECT *small_flames_object = dpl_LoadObject("flamesml.bgf", dpl_load_normal); // dpl_OBJECT *big_flames_object = dpl_LoadObject("flamebig.bgf", dpl_load_normal); // //---------------------------------------------- // // Renderables to perform morphing flash object // //---------------------------------------------- // SweepRenderable *flash_morph_sweep = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 1.0f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // NULL, // trigger // -0.5f, // Initial value // 2.0f); // Final value // ChildMorphRenderable *flash_morph = // new ChildMorphRenderable( // entity, // Entity to attach the renderable to // ChildMorphRenderable::Dynamic, // How/when to execute the renderable // flash_object_a, // destination // flash_object_b, // start object // flash_object_c, // end object // flash_morph_sweep->GetSweepAttribute(), // pointer to control variable // dpl_morph_vertices | dpl_morph_colors, // Defines type of morph to do // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS()); // the parent DCS we will be offsetting from // // Make flash object billboard along y-axis // dpl_SetDCSReorientAxes(flash_morph->GetDCS(), dpl_reorient_axes_y); // dpl_FlushDCS(flash_morph->GetDCS()); // // This defines how long the flash stays up // OneShotDelayRenderable *flash_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 1.0f); // How long to wait before raising the trigger // Register_Object(flash_delay); // // Find the instance with the flash in it and hook up the instance switch // dpl_INSTANCE *flash_morph_instance = dpl_GetDCSInstance(flash_morph->GetDCS(), 1); // InstanceSwitchRenderable *flash_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // flash_morph_instance, // the instance to control // False, // Instance is on when trigger is... // flash_delay->GetTriggerAttribute()); // //--------------------------------------------------- // // Create a material morph to fade flash object away // //--------------------------------------------------- // OneShotDelayRenderable *flash_fade_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.5f); // How long to wait before raising the trigger // SweepRenderable *flash_fade_sweep = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 0.4f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // flash_fade_delay->GetTriggerAttribute()); // trigger variable // Register_Object(flash_fade_sweep); // // Lookup texture for smoke column // dpl_TEXTURE *flash_texture = // dpl_LookupTexture("btfx:bexp9_tex", dpl_lookup_normal, &status); // if (flash_texture == NULL) // DEBUG_STREAM<<"couldn't find texture btfx:bexp9_tex for an effect\n" << std::flush; // // // MorphMaterialRenderable *flash_fade_material = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 1.0f,1.0f,1.0f, // Material's ambient component // 1.0f,1.0f,1.0f, // Material's emissive component // 1.0f,1.0f,1.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0f, // Material's specular component // 1.0f,1.0f,1.0f, // Material's opacity // flash_texture, // Material's texture pointer // 0.0f, // Material's Z dither value // 1, // Material's Fog Imunity value // 1.0f,1.0f,1.0f, // Material's ambient component // 1.0f,1.0f,1.0f, // Material's emissive component // 1.0f,1.0f,1.0f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0f, // Material's specular component // 0.0f,0.0f,0.0f, // Material's opacity // 0.0f, // Material's Z dither value // flash_fade_sweep->GetSweepAttribute()); // Register_Object(flash_fade_material); //// dpl_INSTANCE *flash_morph_instance = dpl_GetDCSInstance(flash_morph->GetDCS(), 1); // if (!flash_morph_instance) // Fail("flash_morph_instance came back null\n"); // dpl_SetInstanceFrontMaterial(flash_morph_instance, flash_fade_material->GetMaterial()); // dpl_FlushInstance(flash_morph_instance); // //------------------------------------------------ // // Renderables to handle the chunks and fireballs // //------------------------------------------------ // OneShotDelayRenderable *fireball_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.25f); // How long to wait before raising the trigger // Register_Object(fireball_delay); // DPLEffectRenderable *chunks_effect = // new DPLEffectRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // fireball_delay->GetTriggerAttribute(), // address containing the trigger // 3, // Chunks // DPL effect number to trigger // local_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &null_offset); // Offset (or world coordinants if DCS is NULL) // Register_Object(chunks_effect); // Point3D fireball_offset(1.0f, 5.0f, 1.0f); // DPLEffectRenderable *fireball_effect = // new DPLEffectRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // fireball_delay->GetTriggerAttribute(), // address containing the trigger // 15, // Fireball // DPL effect number to trigger // local_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &fireball_offset); // Offset (or world coordinants if DCS is NULL) // Register_Object(fireball_effect); // OneShotDelayRenderable *fireball_delay_2 = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.55f); // How long to wait before raising the trigger // Register_Object(fireball_delay_2); // Point3D fireball_offset_2(-1.0f, 5.0f, -1.0f); // DPLEffectRenderable *fireball_effect_2 = // new DPLEffectRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // fireball_delay_2->GetTriggerAttribute(), // address containing the trigger // 15, // Fireball // DPL effect number to trigger // local_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &fireball_offset_2); // Offset (or world coordinants if DCS is NULL) // Register_Object(fireball_effect_2); // //------------------------------------------------------ // // Renderables to handle the torso debris explode morph // //------------------------------------------------------ // OneShotDelayRenderable *morph_debris_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.25f, // How long to wait before raising the trigger // 4.25f); // Duration of trigger // SweepRenderable *debris_morph_sweep = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 4.0f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // morph_debris_delay->GetTriggerAttribute(), // trigger variable // 0.0f, // initial value of sweep // 9.0f, // final value of sweep // SweepRenderable::Y_SQR_X); // function to apply // ChildMorphRenderable *debris_morph = // new ChildMorphRenderable( // entity, // Entity to attach the renderable to // ChildMorphRenderable::Dynamic, // How/when to execute the renderable // morph_debris_a, // destination // morph_debris_b, // start object // morph_debris_c, // end object // debris_morph_sweep->GetSweepAttribute(), // pointer to control variable // dpl_morph_vertices, // Defines type of morph to do // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // local_root->GetDCS()); // the parent DCS we will be offsetting from // MakeDCSFall *debris_make_fall = // new MakeDCSFall( // entity, // Entity to attach the renderable to // MakeDCSFall::Dynamic, // How/when to execute the renderable // debris_morph->GetDCS(), // the DCS to control // -9.81f, // Gravity in meters/sec squared // morph_debris_delay->GetTriggerAttribute()); // true if the instance is on, false if off // // Find the instance with the debris in it and hook up the instance switch // dpl_INSTANCE *debris_morph_instance = dpl_GetDCSInstance(debris_morph->GetDCS(), 1); // InstanceSwitchRenderable *debris_morph_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // debris_morph_instance, // the instance to control // True, // Instance is on when trigger is... // morph_debris_delay->GetTriggerAttribute()); // //----------------------------------------------------- // // Renderables to handle the hips debris explode morph // //----------------------------------------------------- // ChildMorphRenderable *hips_morph = // new ChildMorphRenderable( // entity, // Entity to attach the renderable to // ChildMorphRenderable::Dynamic, // How/when to execute the renderable // morph_hips_a, // destination // morph_hips_b, // start object // morph_hips_c, // end object // debris_morph_sweep->GetSweepAttribute(), // pointer to control variable // dpl_morph_vertices, // Defines type of morph to do // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // local_root->GetDCS()); // the parent DCS we will be offsetting from // MakeDCSFall *hips_make_fall = // new MakeDCSFall( // entity, // Entity to attach the renderable to // MakeDCSFall::Dynamic, // How/when to execute the renderable // hips_morph->GetDCS(), // the DCS to control // -9.81f, // Gravity in meters/sec squared // morph_debris_delay->GetTriggerAttribute()); // true if the instance is on, false if off // // Find the instance with the debris in it and hook up the instance switch // dpl_INSTANCE *hips_morph_instance = dpl_GetDCSInstance(hips_morph->GetDCS(), 1); // InstanceSwitchRenderable *hips_morph_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // hips_morph_instance, // the instance to control // True, // Instance is on when trigger is... // morph_debris_delay->GetTriggerAttribute()); // //----------------------------------------------- // // Renderables to handle static debris and fires // //----------------------------------------------- // OneShotDelayRenderable *static_debris_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.25f); // How long to wait before raising the trigger // DPLStaticChildRenderable *mech_debris = // new DPLStaticChildRenderable( // entity, // false, // thor_debris_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // this_root->GetDCS()); // Register_Object(mech_debris); // MakeDCSFall *mech_debris_fall = // new MakeDCSFall( // entity, // Entity to attach the renderable to // MakeDCSFall::Dynamic, // How/when to execute the renderable // mech_debris->GetDCS(), // the DCS to control // -0.01f, // Gravity in meters/sec squared // static_debris_delay->GetTriggerAttribute()); // true if the instance is on, false if off // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *mech_debris_instance = dpl_GetDCSInstance(mech_debris->GetDCS(), 1); // InstanceSwitchRenderable *mech_debris_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // mech_debris_instance, // the instance to control // True, // Instance is on when trigger is... // static_debris_delay->GetTriggerAttribute()); // // DPLStaticChildRenderable *large_debris = // new DPLStaticChildRenderable( // entity, // false, // large_debris_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // mech_debris->GetDCS()); // Register_Object(large_debris); // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *large_debris_instance = dpl_GetDCSInstance(large_debris->GetDCS(), 1); // InstanceSwitchRenderable *large_debris_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // large_debris_instance, // the instance to control // True, // Instance is on when trigger is... // static_debris_delay->GetTriggerAttribute()); // // DPLStaticChildRenderable *small_flames = // new DPLStaticChildRenderable( // entity, // false, // small_flames_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // mech_debris->GetDCS()); // Register_Object(small_flames); // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *small_flames_instance = dpl_GetDCSInstance(small_flames->GetDCS(), 1); // InstanceSwitchRenderable *small_flames_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // small_flames_instance, // the instance to control // True, // Instance is on when trigger is... // static_debris_delay->GetTriggerAttribute()); // // DPLStaticChildRenderable *big_flames = // new DPLStaticChildRenderable( // entity, // false, // big_flames_object, // dpl_isect_mode_obj, // NULL, // null_offset_matrix, // mech_debris->GetDCS()); // Register_Object(big_flames); // // Make big flames object billboard along y-axis // dpl_SetDCSReorientAxes(big_flames->GetDCS(), dpl_reorient_axes_y); // dpl_FlushDCS(big_flames->GetDCS()); // // Find the instance with the static_thr in it and hook up the instance switch // dpl_INSTANCE *big_flames_instance = dpl_GetDCSInstance(big_flames->GetDCS(), 1); // InstanceSwitchRenderable *big_flames_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // big_flames_instance, // the instance to control // True, // Instance is on when trigger is... // static_debris_delay->GetTriggerAttribute()); // //------------------------------------------------------------- // // Renderables to handle the rising smoke column (first shape) // //------------------------------------------------------------- //#if 1 // OneShotDelayRenderable *first_one_shot = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 0.0f); // How long to wait before raising the trigger // Register_Object(first_one_shot); // Point3D my_offset(0.0, 6.0, 0.0); // #if DEBUG_LEVEL > 0 // DPLPSFXRenderable* this_effect = // #endif // new DPLPSFXRenderable( // entity, // Entity to attach the renderable to // DPLPSFXRenderable::Dynamic, // How/when to execute the renderable // first_one_shot->GetTriggerAttribute(), // address containing the trigger // myPSFXDescriptons[1], // pointer to the PFX description // this_root->GetDCS(), // DCS the effect is relative to (may be NULL) // &my_offset); // Offset (or world coordinants if DCS is NULL) // Register_Object(this_effect); // //// the below code will be removed in favor of PFX effects once they are tested //#else //// OneShotDelayRenderable *smoke_1_morph_delay = //// new OneShotDelayRenderable( //// entity, // Entity to attach the renderable to //// OneShotDelayRenderable::Dynamic, // How/when to execute the renderable //// 0.25f); // How long to wait before raising the trigger // SweepRenderable *smoke_1_sweep = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 40.0f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // static_debris_delay->GetTriggerAttribute(), // 0.2f, // 2.5f); // ChildMorphRenderable *smoke_1_morph = // new ChildMorphRenderable( // entity, // Entity to attach the renderable to // ChildMorphRenderable::Dynamic, // How/when to execute the renderable // smoke_1_a, // destination // smoke_b, // start object // smoke_c, // end object // smoke_1_sweep->GetSweepAttribute(), // pointer to control variable // dpl_morph_vertices, // Defines type of morph to do // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS()); // the parent DCS we will be offsetting from // // Find the instance with the flash in it and hook up the instance switch // dpl_INSTANCE *smoke_1_instance = dpl_GetDCSInstance(smoke_1_morph->GetDCS(), 1); // InstanceSwitchRenderable *smoke_1_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // smoke_1_instance, // the instance to control // True, // Instance is on when trigger is... // static_debris_delay->GetTriggerAttribute()); // //-------------------------------------------------------------- // // Renderables to handle the rising smoke column (second shape) // //-------------------------------------------------------------- //#if 0 // OneShotDelayRenderable *smoke_2_morph_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 6.0f); // How long to wait before raising the trigger // SweepRenderable *smoke_2_sweep = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 30.0f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // smoke_2_morph_delay->GetTriggerAttribute(), // 0.1f, // 1.0f); // ChildMorphRenderable *smoke_2_morph = // new ChildMorphRenderable( // entity, // Entity to attach the renderable to // ChildMorphRenderable::Dynamic, // How/when to execute the renderable // smoke_2_a, // destination // smoke_b, // start object // smoke_c, // end object // smoke_2_sweep->GetSweepAttribute(), // pointer to control variable // dpl_morph_vertices, // Defines type of morph to do // false, // DPL Zone this stuff will live in (for culling) // dpl_isect_mode_obj, // type of intersections to do on this object // NULL, // intersection mask for the object // this_root->GetDCS()); // the parent DCS we will be offsetting from // // Find the instance with the flash in it and hook up the instance switch // dpl_INSTANCE *smoke_2_instance = dpl_GetDCSInstance(smoke_2_morph->GetDCS(), 1); // InstanceSwitchRenderable *smoke_2_morph_instance_switch = // new InstanceSwitchRenderable( // entity, // Entity to attach the renderable to // InstanceSwitchRenderable::Dynamic, // How/when to execute the renderable // smoke_2_instance, // the instance to control // True, // Instance is on when trigger is... // smoke_2_morph_delay->GetTriggerAttribute()); //#endif // //------------------------------------------- // // Set dither Z on material for smoke column // //------------------------------------------- // dpl_MATERIAL *damage_material = // dpl_LookupMaterial ("btfx:smoke1_mtl", // dpl_lookup_normal, // &status); // if (damage_material == 0) // { // std::cout << "couldn't find material\n"; // } // else // { // dpl_SetMaterialDitherZ(damage_material, 10.0f); // dpl_FlushMaterial(damage_material); // } // //--------------------------------------------------- // // Create a material morph to fade smoke column away // //--------------------------------------------------- // OneShotDelayRenderable *smoke_fade_delay = // new OneShotDelayRenderable( // entity, // Entity to attach the renderable to // OneShotDelayRenderable::Dynamic, // How/when to execute the renderable // 25.0f); // How long to wait before raising the trigger // SweepRenderable *smoke_fade_sweep = // new SweepRenderable( // entity, // Entity to attach the renderable to // SweepRenderable::Dynamic, // How/when to execute the renderable // 18.5f, // How long to take to sweep from 0 to 1 // 1, // number of times to cycle before stopping // smoke_fade_delay->GetTriggerAttribute()); // trigger variable // Register_Object(smoke_fade_sweep); // // Lookup texture for smoke column // dpl_TEXTURE *smoke_texture = // dpl_LookupTexture("btfx:smoke1_scr_tex", dpl_lookup_normal, &status); // if (smoke_texture == NULL) // DEBUG_STREAM<<"couldn't find texture btfx:smoke1_scr_tex for an effect\n" << std::flush; // // // MorphMaterialRenderable *smoke_fade_material = // new MorphMaterialRenderable( // entity, // Entity to attach the renderable to // MorphMaterialRenderable::Dynamic, // How/when to execute the renderable // 1.0f,1.0f,1.0f, // Material's ambient component // 0.7f,0.4f,0.4f, // Material's emissive component // 0.3714f,0.2899f,0.3714f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0f, // Material's specular component // 0.7f,0.99f,0.0f, // Material's opacity // smoke_texture, // Material's texture pointer // 10.0f, // Material's Z dither value // 3, // Material's Fog Imunity value // 1.0f,1.0f,1.0f, // Material's ambient component // 0.7f,0.4f,0.4f, // Material's emissive component // 0.3714f,0.2899f,0.3714f, // Material's diffuse component // 0.0f,0.0f,0.0f,0.0f, // Material's specular component // 0.0f,0.99f,0.0f, // Material's opacity // 10.0f, // Material's Z dither value // smoke_fade_sweep->GetSweepAttribute()); // Register_Object(smoke_fade_material); //// dpl_INSTANCE *smoke_1_instance = dpl_GetDCSInstance(smoke_1_morph->GetDCS(), 1); // if (!smoke_1_instance) // Fail("smoke_1_instance came back null\n"); // dpl_SetInstanceFrontMaterial(smoke_1_instance, smoke_fade_material->GetMaterial()); // dpl_FlushInstance(smoke_1_instance); //#endif // #else // DEBUG_STREAM <<"Explosion effect 104 called, this is disabled and shouldn't be used!\n" << std::flush; // #endif // break; // } // default: // { // break; // } // } } // //############################################################################# // MakeEntityRenderables handles creating all the renderables necessary to // display an object. This routine contains default behaviors for creating // some types of simple objects. The idea is that if a higher level routine // can't figure out how to make renderables for something this routine will be // called and the default behavior will be used. //############################################################################# // void DPLRenderer::MakeEntityRenderables( Entity *entity, // The entity we are dealing with ResourceDescription *model_resource, // Pointer to the video resource ViewFrom view_type) // Type of reference (inside/outside...etc.) { //STUBBED: DPL RB 1/14/07 char *object_filename; #if DEBUG_LEVEL > 0 int object_count; #endif L4VideoObject *video_object; L4VideoObjectWrapper *video_wrapper; ChainOf video_chain(NULL); L4VideoObject::ResourceType resource_type; // dpl_DCS *my_root_dcs; Enumeration renderer_modes; // // Set the Entity_Being_Created global so the C language callback will // be able to mark the geometry with damage zone values if necessary. // Entity_Being_Created = entity; // my_root_dcs = NULL; // // convert video resource into chain of video objects and make an iterator // for that chain // if (model_resource) { #if DEBUG_LEVEL > 0 object_count = #endif L4VideoObjectWrapper::BuildVideoObjectChainFromResource(&video_chain, model_resource); } ChainIteratorOf video_iterator(video_chain); // // Switch to allow us to have scripts at this level for constructing certain // types of video objects (whether or not they have a video resource) // switch (entity->GetClassID()) { // // Dropzones have no graphical appearance so we do nothing // case DropZoneClassID: break; // // Player objects have no graphical appearance unless one is created // at a higher (game specific) level, so we do nothing here. // case PlayerClassID: break; // this entity has no visual appearance case AudioEntityClassID: break; // // Cultural and landmark are the only ones with "destroyed" processing // This is similar to the default case but does not allow us to be // inside the entity, does not allow us to be a mover, // case CulturalIconClassID: case LandmarkClassID: { dpl_INSTANCE *this_instance = NULL; // BT bring-up: the per-object instance // assignments below are DPL-stubbed // (commented out) -> initialise so the // /RTC1 uninitialised-variable check does // not fault when this_instance is passed // to StateInstanceSwitchRenderable. d3d_OBJECT *this_object; dpl_ISECT_MODE intersect_mode; HierarchicalDrawComponent *component = NULL; uint32 intersect_mask; LinearMatrix offset_matrix = LinearMatrix::Identity; //dpl_DCS *root_DCS, *this_DCS; // // Make sure the object has a video resource // if (!model_resource) { VideoRenderer::MakeEntityRenderables(entity, model_resource, view_type); Entity_Being_Created = NULL; return; } // intersect_mode = dpl_isect_mode_geometry; intersect_mask = INTERSECT_ALL; Logical first_object = True; video_iterator.First(); while ((video_wrapper = video_iterator.ReadAndNext()) != NULL) { video_object = video_wrapper->GetVideoObject(); object_filename = video_object->GetObjectFilename(); resource_type = video_object->GetResourceType(); renderer_modes = video_object->GetRendererModes(); #if NOISY_RENDERER Tell("L4VIDEO.cpp loading object " << object_filename); Tell(" type " << resource_type); Tell(" mode 0x" < false, // DPL Zone this stuff will live in (for culling) intersect_mode, // type of intersections to do on this object intersect_mask); // intersection mask for the object //root_DCS = this_static_root->GetDCS(); //------------------------------------------------------ // if root object billboards (all others billboard too) //------------------------------------------------------ //this_DCS = root_DCS; // this_instance = this_static_root->GetInstance(); // // Set my_root_dcs because we want this guy's hiearchy to be marked // with his entity pointer // // my_root_dcs = root_DCS; } else { if (renderer_modes | L4VideoObject::BillboardObject) { //------------------------------------------ // attach additional object to separate DCS // because it is billboarded //------------------------------------------ component = new DPLStaticChildRenderable( entity, false, this_object, intersect_mode, intersect_mask, offset_matrix, NULL); // this_DCS = this_child->GetDCS(); // this_instance = this_child->GetInstance(); } else { //---------------------------------------- // attach additional objects to root_DCS // (HACK) temporary implementation (HACK) //---------------------------------------- component = new DCSInstanceRenderable( entity, // Entity to attach the renderable to DCSInstanceRenderable::Static, // How/when to execute the renderable this_object, // object to connect to the instance NULL, // the DCS to add the instance to intersect_mode, // type of intersections to do on this object intersect_mask, // intersection mask for the object True); // initial visibility setting //this_DCS = NULL; // this_instance = another_instance->GetInstance(); } } // add the new object to our renderables list if (component) mRenderables.Add(component); component = NULL; // // Hook up the object to an instance switch renderable responsive to state // StateIndicator* simulation_state = (StateIndicator *)entity->GetAttributePointer("SimulationState"); switch(resource_type) { case L4VideoObject::Object: { component = new StateInstanceSwitchRenderable( entity, // Entity to attach the renderable to StateInstanceSwitchRenderable::Watcher, // How/when to execute the renderable this_instance, // the instance to control False, // true to turn on in this state, false for off simulation_state, // State dial we use to control the on/off CulturalIcon::BurningState); // State that we look for break; } case L4VideoObject::Rubble: { component = new StateInstanceSwitchRenderable( entity, // Entity to attach the renderable to StateInstanceSwitchRenderable::Watcher, // How/when to execute the renderable this_instance, // the instance to control True, // true to turn on in this state, false for off simulation_state, // State dial we use to control the on/off CulturalIcon::BurningState); // State that we look for break; } } if (component) mRenderables.Add(component); //---------------------------------- // billboard object if so indicated //---------------------------------- // if (this_DCS && (renderer_modes & L4VideoObject::BillboardObject)) // { // int axes = dpl_reorient_axes_none; // if (renderer_modes & L4VideoObject::BillboardXAxis) // { // axes |= dpl_reorient_axes_x; // } // if (renderer_modes & L4VideoObject::BillboardYAxis) // { // axes |= dpl_reorient_axes_y; // } // if (renderer_modes & L4VideoObject::BillboardZAxis) // { // axes |= dpl_reorient_axes_z; // } // dpl_SetDCSReorientAxes(this_DCS, (dpl_REORIENT_AXES)axes); // dpl_FlushDCS(this_DCS); // } } break; } // // Case to handle rivets using the fast projectile code // case RivetClassID: { d3d_OBJECT *this_object; video_iterator.First(); video_wrapper = video_iterator.ReadAndNext(); Check(video_wrapper); video_object = video_wrapper->GetVideoObject(); Check_Pointer(video_object); object_filename = video_object->GetObjectFilename(); this_object = d3d_OBJECT::LoadObject(GetDevice(), object_filename); #if DEBUG_LEVEL > 0 ProjectileRootRenderable *projectile = #endif new ProjectileRootRenderable( entity, // Entity to attach the renderable to ProjectileRootRenderable::Dynamic, // How/when to execute the renderable this_object, // object to hang on the DCS, may be a list later false); // DPL Zone this stuff will live in (for culling) Register_Object(projectile); break; } // // Script for generating renderables for eyecandy // case EyeCandyClassID: { int effect_number; dpl_ISECT_MODE dpl_isect_mode_obj; RootRenderable *this_root = new RootRenderable( entity, // Entity to attach the renderable to RootRenderable::Dynamic, // How/when to execute the renderable NULL, // object to hang on the DCS, may be a list later false, // DPL Zone this stuff will live in (for culling) dpl_isect_mode_obj, // type of intersections to do on this object NULL); // intersection mask for the object Register_Object(this_root); StateIndicator* simulation_state = (StateIndicator *)entity->GetAttributePointer("SimulationState"); video_iterator.First(); while ((video_wrapper = video_iterator.ReadAndNext()) != NULL) { video_object = video_wrapper->GetVideoObject(); effect_number = atoi(video_object->GetObjectFilename()); #if DEBUG_LEVEL > 0 DPLSFXRenderable *this_effect = #endif new DPLSFXRenderable( entity, // Entity to attach the effect to false, // DPL zone everything will be in Point3D::Identity, // Point offset from the parent DCS this_root, // Parent DCS (can be NULL for world) simulation_state, // Trigger effect when this state changes EyeCandy::effectOn, // Trigger effect when in this state effect_number, // Type of effect to trigger .01); // Effect repeat speed. Register_Object(this_effect); } break; } // // Script for generating an explosion of type specified in the resource file // case ExplosionClassID: { DEBUG_STREAM << "Explosion Created in MakeEntityRenderables:" << std::endl << std::flush; int effect_number; video_iterator.First(); while ((video_wrapper = video_iterator.ReadAndNext()) != NULL) { video_object = video_wrapper->GetVideoObject(); effect_number = atoi(video_object->GetObjectFilename()); DEBUG_STREAM << " ** effect_number = " << effect_number << std::endl << std::flush; if(effect_number < 100 || effect_number >= 1000) { DEBUG_STREAM << " ** DPLIndependantEffect([" << entity->localOrigin.linearPosition.x << ", " << entity->localOrigin.linearPosition.y << ", " << entity->localOrigin.linearPosition.z << "], " << effect_number << ");" << std::endl << std::flush; // Both effect-number ENCODINGS resolve to the same psfx slot: // <100 = the raw dpl board number; >=1000 = the WinTesla-era // "1000+slot" INDIE id carried by the damage-band resources // (1002-1005 = ddam1-4 light..critical damage smoke, 1008 = // ddam5 zone-destroyed -- the SAME [pfx_day] mapping). BT // ships no INDIE descriptors (the version-2 specialfx pages // don't exist), so all slots route to the BT .PFX layer, with // the Explosion entity's ORIENTATION (the victim's frame) -- // the .PFX offsets/velocities are authored mech-local. { int pfx_slot = (effect_number >= 1000) ? effect_number - 1000 : effect_number; extern void BTStartPfxFrame(int, float, float, float, const float *, const float *, const float *); float xr[3] = { (float)entity->localToWorld(0,0), (float)entity->localToWorld(0,1), (float)entity->localToWorld(0,2) }; float yr[3] = { (float)entity->localToWorld(1,0), (float)entity->localToWorld(1,1), (float)entity->localToWorld(1,2) }; float zr[3] = { (float)entity->localToWorld(2,0), (float)entity->localToWorld(2,1), (float)entity->localToWorld(2,2) }; BTStartPfxFrame(pfx_slot, (float)entity->localOrigin.linearPosition.x, (float)entity->localOrigin.linearPosition.y, (float)entity->localOrigin.linearPosition.z, xr, yr, zr); } } else { DEBUG_STREAM << " ** ExplosionScripts(*entity*, RES[" << model_resource->resourceID << " - " << model_resource->resourceName << "], " << "ViewFrom::" << (view_type == ViewFrom::insideEntity ? "insideEntity" : (view_type == ViewFrom::outsideEntity ? "outsideEntity" : "collisionEntity")) << ", " << (effect_number - 100) << ");" << std::endl << std::flush; ExplosionScripts( entity, // The entity we are dealing with model_resource, // Pointer to the video resource view_type, // Type of reference (inside/outside...etc.) effect_number - 100); } } break; } case CameraDirectorClassID: { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Create the CameraDirector HUD Renderable if not a Replicant //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // if (entity->GetInstance() == CameraDirector::MasterInstance) { CameraDirector *camera_director = (CameraDirector*) entity; Check_Pointer(camera_director); int *player_index = &camera_director->goalPlayerIndex; Check_Pointer(player_index); Logical *display_rank_window = &camera_director->displayRankingWindow; Check_Pointer(display_rank_window); mCamShipHUD = new CameraShipHUDRenderable(entity, CameraShipHUDRenderable::Dynamic, player_index, display_rank_window); } break; } // // Script for a drivable camera, the camera is invisible to other players // case CameraShipClassID: { if(view_type == insideEntity) { // // Build an empty root renderable and an eye renderable // dpl_ISECT_MODE dpl_isect_mode_obj; RootRenderable *this_root = new RootRenderable( entity, // Entity to attach the renderable to RootRenderable::Dynamic, // How/when to execute the renderable NULL, // object to hang on the DCS, may be a list later false, // DPL Zone this stuff will live in (for culling) dpl_isect_mode_obj, // type of intersections to do on this object NULL); // intersection mask for the object Register_Object(this_root); #if 0 //DEBUG_LEVEL > 0 DPLEyeRenderable* this_eye = #endif mCamera = new DPLEyeRenderable( entity, LinearMatrix::Identity, this_root, NULL ); Register_Object(this_eye); } break; } // // Script for doorframe, so it can be used in any game // case DoorFrameClassID: { Verify( object_count == 6 ); //------------------------------------------------ // First video object is root shape for the door // followed by left door shape, right door shape, // door lights, left door lights, and right door // lights. //------------------------------------------------ d3d_OBJECT *object, *left, *right, *object_lights, *left_lights, *right_lights; int object_number = 0; video_iterator.First(); while ((video_wrapper = video_iterator.ReadAndNext()) != NULL) { video_object = video_wrapper->GetVideoObject(); object_filename = video_object->GetObjectFilename(); #if NOISY_RENDERER Tell("L4VIDEO.cpp loading door object "<GetSubsystem(0); Point3D* left_door_position = &left_door_sub->currentPosition; Door *right_door_sub = (Door*) entity->GetSubsystem(1); Point3D* right_door_position = &right_door_sub->currentPosition; dpl_ISECT_MODE dpl_isect_mode_obj; RootRenderable *door_sill = new RootRenderable( entity, // Entity to attach the renderable to RootRenderable::Static, // How/when to execute the renderable object, // object to hang on the DCS, may be a list later false, // DPL Zone this stuff will live in (for culling) dpl_isect_mode_obj, // type of intersections to do on this object NULL); // intersection mask for the object Register_Object(door_sill); // // Set my_root_dcs because we want this guy's hiearchy to be marked // with his entity pointer // // my_root_dcs = door_sill->GetDCS(); LinearMatrix my_ident(True); DPLChildPointRenderable* left_door = new DPLChildPointRenderable( entity, false, left, dpl_isect_mode_obj, NULL, my_ident, door_sill, left_door_position); Register_Object(left_door); DPLChildPointRenderable* right_door = new DPLChildPointRenderable( entity, false, right, dpl_isect_mode_obj, NULL, my_ident, door_sill, right_door_position); Register_Object(right_door); #if DEBUG_LEVEL > 0 DCSInstanceRenderable *door_sill_lights_instance = #endif new DCSInstanceRenderable( entity, // Entity to attach the renderable to DCSInstanceRenderable::Static, // How/when to execute the renderable object_lights, // object to connect to the instance door_sill, // the DCS to add the instance to dpl_isect_mode_obj, // type of intersections to do on this object NULL, // intersection mask for the object True); // initial visibility setting Register_Object(door_sill_lights_instance); #if DEBUG_LEVEL > 0 DCSInstanceRenderable *left_door_lights_instance = #endif new DCSInstanceRenderable( entity, // Entity to attach the renderable to DCSInstanceRenderable::Static, // How/when to execute the renderable left_lights, // object to connect to the instance left_door, // the DCS to add the instance to dpl_isect_mode_obj, // type of intersections to do on this object NULL, // intersection mask for the object True); // initial visibility setting Register_Object(left_door_lights_instance); #if DEBUG_LEVEL > 0 DCSInstanceRenderable *right_door_lights_instance = #endif new DCSInstanceRenderable( entity, // Entity to attach the renderable to DCSInstanceRenderable::Static, // How/when to execute the renderable right_lights, // object to connect to the instance right_door, // the DCS to add the instance to dpl_isect_mode_obj, // type of intersections to do on this object NULL, // intersection mask for the object True); // initial visibility setting Register_Object(right_door_lights_instance); break; } // // This is the script run on anything that isn't already listed above // default: { d3d_OBJECT *this_object; dpl_ISECT_MODE intersect_mode; uint32 intersect_mask; LinearMatrix offset_matrix = LinearMatrix::Identity; Component *component = NULL; HierarchicalDrawComponent *rootCom = NULL; HierarchicalDrawComponent *thisCom = NULL; // // First, establish that this level doesn't know what to do // if the object has no video resource. // if (!model_resource) { VideoRenderer::MakeEntityRenderables(entity, model_resource, view_type); Entity_Being_Created = NULL; return; } // // If we're inside the entity, set up the intersect mode and mask so we // won't intersect ourselves with the pickpoint. Other items get full // geometry intersection. // if (view_type == insideEntity) { // intersect_mode = dpl_isect_mode_obj; intersect_mask = NULL; } else { // intersect_mode = dpl_isect_mode_geometry; intersect_mask = INTERSECT_ALL; } Logical first_object = True; video_iterator.First(); while ((video_wrapper = video_iterator.ReadAndNext()) != NULL) { video_object = video_wrapper->GetVideoObject(); object_filename = video_object->GetObjectFilename(); resource_type = video_object->GetResourceType(); renderer_modes = video_object->GetRendererModes(); #if NOISY_RENDERER Tell("L4VIDEO.cpp loading object " << object_filename); Tell(" type " << resource_type); Tell(" mode 0x" <IsDerivedFrom(*Mover::GetClassDerivations())) { // // It's a mover, construct it with a dynamic root renderable so it can move // also remember it's DCS so we can hook other shapes to it later. // SET_VIDEO_CONSTRUCT_ROOT(); rootCom = new RootRenderable( entity, // Entity to attach the renderable to RootRenderable::Dynamic, // How/when to execute the renderable this_object, // object to hang on the DCS, may be a list later false, // DPL Zone this stuff will live in (for culling) intersect_mode, // type of intersections to do on this object intersect_mask); // intersection mask for the object Register_Object(this_root); CLEAR_VIDEO_CONSTRUCT_ROOT(); } else { // // It's a static, construct it with a static RootRenderable and // remember it's DCS so we can hook other shapes to it later. // rootCom = new RootRenderable( entity, // Entity to attach the renderable to RootRenderable::Static, // How/when to execute the renderable this_object, // object to hang on the DCS, may be a list later false, // DPL Zone this stuff will live in (for culling) intersect_mode, // type of intersections to do on this object intersect_mask); // intersection mask for the object } // // Set my_root_dcs because we want this guy's hiearchy to be marked // with his entity pointer // // my_root_dcs = root_DCS; // // If we are inside the entity, then we must build an eyepoint for it too. // since there is no special construction, we build the eyepoint with a // zero offset. // if (view_type == insideEntity) { EulerAngles *eyepoint_rotation = (EulerAngles *)entity->GetAttributePointer("EyepointRotation"); #if 0 //DEBUG_LEVEL > 0 DPLEyeRenderable *this_eye = #endif mCamera = new DPLEyeRenderable( entity, LinearMatrix::Identity, rootCom, eyepoint_rotation); Register_Object(this_eye); } //------------------------------------------------------ // if root object billboards (all others billboard too) //------------------------------------------------------ // this_DCS = root_DCS; } else { if (renderer_modes & L4VideoObject::BillboardObject) { //------------------------------------------ // attach additional object to separate DCS // because it is billboarded //------------------------------------------ thisCom = new DPLStaticChildRenderable( entity, false, this_object, intersect_mode, intersect_mask, offset_matrix, rootCom); Register_Object(this_child); // this_DCS = this_child->GetDCS(); } else { //---------------------------------------- // attach additional objects to root_DCS // (HACK) temporary implementation (HACK) //---------------------------------------- thisCom = new DCSInstanceRenderable( entity, // Entity to attach the renderable to DCSInstanceRenderable::Static, // How/when to execute the renderable this_object, // object to connect to the instance rootCom, // the DCS to add the instance to intersect_mode, // type of intersections to do on this object intersect_mask, // intersection mask for the object True); // initial visibility setting Register_Object(another_instance); // this_DCS = NULL; } } //---------------------------------- // billboard object if so indicated //---------------------------------- if (thisCom && (renderer_modes & L4VideoObject::BillboardObject)) { // int axes = dpl_reorient_axes_none; if (renderer_modes & L4VideoObject::BillboardXAxis) { // axes |= dpl_reorient_axes_x; } if (renderer_modes & L4VideoObject::BillboardYAxis) { // axes |= dpl_reorient_axes_y; } if (renderer_modes & L4VideoObject::BillboardZAxis) { // axes |= dpl_reorient_axes_z; } // dpl_SetDCSReorientAxes(this_DCS, (dpl_REORIENT_AXES)axes); // dpl_FlushDCS(this_DCS); } //MOVED THIS TO ROOTRENDERABLE - Was this a hack? //mRenderables.Add(component); } break; } } // // release the video chain memory // L4VideoObjectWrapper::DeleteVideoObjectChain(&video_chain); // // Clear the entity pointer passed to the callback system // Entity_Being_Created = NULL; // // If my_root_dcs is non-null, mark the entity's DCS hiearchy with it's // entity pointer. // // if(my_root_dcs) // { // MarkDCSHiearchy(my_root_dcs,entity); //#if 0 // if(entity->GetClassID() == DemolitionPackClassID) // { // Point3D temp_point(0.0,0.0,0.0); // #if DEBUG_LEVEL > 0 // OnePSFXRenderable *this_effect= // #endif // new OnePSFXRenderable( // entity, // Entity to attach the renderable to // OnePSFXRenderable::Static, // How/when to execute the renderable // myPSFXDescriptons[3], // name of file with the PFX description in it // my_root_dcs, // DCS the effect is relative to (may be NULL) // &temp_point); // Offset (or world coordinants if DCS is NULL) // Register_Object(this_effect); // } //#endif // } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // This should be called prior to the rendering of a frame to setup the culling // data the renderer keeps (mostly the world to eye transform) // void DPLRenderer::SetupCull() { Entity *linked_entity; LinearMatrix site_to_world, world_to_site, eye_rotation, eye_inverted; EntitySegment *eyepoint_segment; EulerAngles *eyepoint_rotation; // // To test the functionality, this is not as efficient as it could be. // when it gets fully patched into the renderer it will be improved. // // Figure out what type of entity this is. // linked_entity = GetLinkedEntity(); eyepoint_rotation = (EulerAngles*)linked_entity->GetAttributePointer("EyepointRotation"); if(linked_entity->IsDerivedFrom(*JointedMover::GetClassDerivations())) { JointedMover *linked_jointed_mover; linked_jointed_mover = Cast_Object(JointedMover*, linked_entity); eyepoint_segment = linked_jointed_mover->GetSegment("siteeyepoint"); if(!eyepoint_segment) { Fail("DPLRenderer::SetupCull jointed mover had no siteeyepoint\n"); } if(!eyepoint_rotation) { Fail("DPLRenderer::SetupCull jointed mover had no EyepointRotation attribute\n"); } linked_jointed_mover->GetSegmentToWorld(*eyepoint_segment, &site_to_world); if(eyepoint_rotation) { world_to_site.Invert(site_to_world); eye_rotation = *eyepoint_rotation; eye_inverted.Invert(eye_rotation); worldToEyeMatrix.Multiply(world_to_site, eye_inverted); } else { worldToEyeMatrix.Invert(site_to_world); } } else { site_to_world = linked_entity->localOrigin; if(eyepoint_rotation) { world_to_site.Invert(site_to_world); eye_rotation = *eyepoint_rotation; eye_inverted.Invert(eye_rotation); worldToEyeMatrix.Multiply(world_to_site, eye_inverted); } else { worldToEyeMatrix.Invert(site_to_world); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ void DPLRenderer::ResetStatistics() { total_cull = 0; total_draw = 0; total_pixelplanes = 0; total_frame_time = 0; frame_count = 0; target_frame_time = 56000; target_frame_count= 0; report_time = currentFrameTime + 60.0f; } void DPLRenderer::ReportStatistics() { if(frame_count != 0) { std::cout<<"Frames "<GetApplicationState(); switch (currentAppState) { case Application::CreatingMission: case Application::LoadingMission: case Application::WaitingForLaunch: //if (mLoadingScreenThread == NULL) //{ // mLoadingScreenRunning = true; // mLoadingScreenThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ExecuteLoadScreenThread, this, 0, NULL); //} //hr = mDevice->TestCooperativeLevel(); //if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET) //{ // mPrimaryDeviceReseting = true; // DEBUG_STREAM << this << " RESETTING DEVICE - WAITING FOR FRAME TO FINISH" << std::endl << std::flush; // while (mRenderingLoadingFrame) // { // Sleep(100); // } // DEBUG_STREAM << this << " RESETTING DEVICE - DONE WAITING FOR FRAME TO FINISH" << std::endl << std::flush; // int bbCount = mPresentParams.BackBufferCount; // int bbWidth = mPresentParams.BackBufferWidth; // int bbHeight = mPresentParams.BackBufferHeight; // ParticleEngine::Destroy(); // V(mDevice->Reset(&mPresentParams)); // ParticleEngine::Initialize(mDevice); // this->SetCoreRenderStates(); // mPresentParams.BackBufferCount = bbCount; // mPresentParams.BackBufferWidth = bbWidth; // mPresentParams.BackBufferHeight = bbHeight; // mPrimaryDeviceReseting = false; //} ticks = HiResNowTicks(); #ifdef LOGFRAMERATE fputc(1, FRAMERATE_LOG); fwrite(&ticks, sizeof(__int64), 1, FRAMERATE_LOG); #endif return; case Application::LaunchingMission: case Application::RunningMission: break; } if (lastAppState != currentAppState && currentAppState == Application::LaunchingMission) { this->mDevice->SetRenderState(D3DRS_LIGHTING, true); this->mDevice->SetTransform(D3DTS_PROJECTION, &this->mProjectionMatrix); this->mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, D3DCOLOR_ARGB(128, 255, 255, 255)); this->mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); } lastAppState = currentAppState; // BT (task #20): window-resize aspect fix, applied PER-FRAME on the render // thread. (The WM_SIZE-time path can't reach the renderer: APPMGR.cpp:73 // reassigns the global `application` while iterating and leaves it NULL // between frames, so l4_application is NULL at message-pump time.) The // WndProc just records gWindowAspect; here the projection is rebuilt when // it changes so the fixed-size backbuffer's stretch into the resized client // area is cancelled. { static float appliedAspect = 0.0f; if (gWindowAspect > 0.0f && gWindowAspect != appliedAspect && viewAngle > 0.0f && clipFar > clipNear) { appliedAspect = gWindowAspect; D3DXMatrixPerspectiveFovRH(&mProjectionMatrix, viewAngle * (PI / 180.0f), appliedAspect, clipNear, clipFar); mDecalProjectionMatrix = mProjectionMatrix; mDecalProjectionMatrix._33 -= mDecalEpsilon; mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix); DEBUG_STREAM << "[resize] projection rebuilt (frame): aspect=" << appliedAspect << "\n" << std::flush; } } // before we execute everything we need to clear // the render lists memset(mRenderLists, 0, sizeof(mRenderLists)); HierarchicalDrawComponent *drawComp; SChainIteratorOf iterator(&mRenderables); while ((drawComp = iterator.ReadAndNext()) != NULL) drawComp->Execute(); if (mReticle) mReticle->Execute(); if (mCamShipHUD) mCamShipHUD->Execute(); gNumBatches = 0; { extern int gBTNumCulled; gBTNumCulled = 0; } static Time lastFrameTime = mTargetRenderTime; Scalar dT = mTargetRenderTime - lastFrameTime; lastFrameTime = mTargetRenderTime; currentFrameTime = Now(); // DIAG (turn-hitch hunt): time the render phases -- draw CPU vs Present // (GPU-queue block). Logged on slow frames + 1 Hz stats. LARGE_INTEGER _rt0; QueryPerformanceCounter(&_rt0); DWORD currentFog; mDevice->GetRenderState(D3DRS_FOGCOLOR, ¤tFog); hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, currentFog, 1.0f, 0); hr = mDevice->BeginScene(); mDevice->SetFVF(L4VERTEX_FVF); D3DXMATRIX viewTransform; mDevice->GetTransform(D3DTS_VIEW, &viewTransform); { static int dbgVP = 0; if (dbgVP < 3) { D3DXMATRIX projNow; mDevice->GetTransform(D3DTS_PROJECTION, &projNow); DEBUG_STREAM << "[VP] VIEW row3=(" << viewTransform._41 << "," << viewTransform._42 << "," << viewTransform._43 << ") VIEW._33=" << viewTransform._33 << " | PROJ diag=(" << projNow._11 << "," << projNow._22 << "," << projNow._33 << "," << projNow._34 << ") PROJ._43=" << projNow._43 << "\n" << std::flush; ++dbgVP; } } // PORT (turn-hitch fix): publish this frame's view frustum so d3d_OBJECT::Draw // can skip objects fully outside it. The 1995 code drew everything (the IG // board clipped in hardware) -- ~2700 draw calls/frame = ~107ms CPU on D3D9; // culling the off-screen set is the port's equivalent of that hardware stage. // Gate: BT_CULL_FRUSTUM (default ON; =0 restores draw-everything). { static int s_fcull = -1; if (s_fcull < 0) { const char *cv = getenv("BT_CULL_FRUSTUM"); s_fcull = (cv == 0 || *cv != '0') ? 1 : 0; } // GPU WARM-UP: managed-pool buffers/textures upload to the GPU on FIRST // USE, so the first frame that reveals a previously-unculled object pays // its upload right then (one big hitch on the first look around). Draw // EVERYTHING for the first few frames so all uploads land during mission // start, then cull normally. static int s_warmup = 3; if (s_warmup > 0) { --s_warmup; d3d_OBJECT::SetCullFrustum(NULL); } else if (s_fcull) { // use the renderer's OWN main projection (mProjectionMatrix), not a // GetTransform read-back -- the device state between frames can hold a // pass-specific matrix (sky/decal/HUD), which made the frustum silently // degenerate for whole stretches (nothing culled). D3DXMATRIX viewProj; D3DXMatrixMultiply(&viewProj, &viewTransform, &mProjectionMatrix); d3d_OBJECT::SetCullFrustum(&viewProj); } else d3d_OBJECT::SetCullFrustum(NULL); // camera world position for LOD distance selection. Row-vector D3D view // matrix (LookAt layout): the camera BASIS VECTORS ARE THE COLUMNS // (xaxis = (_11,_21,_31) etc.) and row 4 = (-eye.x_axis, -eye.y_axis, // -eye.z_axis), so eye = -(t.x*col1 + t.y*col2 + t.z*col3). (The first // version used the ROWS as the basis -- a transposed rotation whose // "position" varied with the camera ANGLE, making LOD bands pop in/out // as the view rotated: structures AND the mech blinked with turns.) // LOD EYEPOINT: prefer the GAME-FED viewpoint-entity position (BTSetLodEye // from mech4 -- the authentic reference: the pod's eyepoint sat ON the // mech, so turning never changed any LOD distance). Our chase camera // ORBITS the mech +-40u as it turns, which swept objects near their band // edges in and out ("scenery blinks with viewing angle", floor flicker at // the arena fringe). Fall back to the camera extracted from the view // matrix (eye = -t*colBasis) when the game never fed a position. extern int gBTLodEyeValid; if (!gBTLodEyeValid) { const float ex = -(viewTransform._41 * viewTransform._11 + viewTransform._42 * viewTransform._12 + viewTransform._43 * viewTransform._13); const float ey = -(viewTransform._41 * viewTransform._21 + viewTransform._42 * viewTransform._22 + viewTransform._43 * viewTransform._23); const float ez = -(viewTransform._41 * viewTransform._31 + viewTransform._42 * viewTransform._32 + viewTransform._43 * viewTransform._33); d3d_OBJECT::SetCameraPosition(ex, ey, ez); } } // // Start with the opaque pass // // // BACKFACE CULLING (task #20): the bring-up D3DCULL_NONE drew interior/back // faces the original never rendered -- distant "dark wedge" shapes were the // INSIDES of dune/butte meshes, and standing inside a crescent-ridge mound // looked like being sealed in rock (the authentic renderer culls those, so // you can see out). BT_CULL selects the mode: cw (default) / ccw / off. // { static DWORD s_cull = 0; if (s_cull == 0) { const char *cv = getenv("BT_CULL"); s_cull = (cv == NULL) ? D3DCULL_CW : (cv[0]=='0' || cv[0]=='n' || cv[0]=='N') ? D3DCULL_NONE : (cv[0]=='c' && cv[1]=='c') ? D3DCULL_CCW : D3DCULL_CW; } mDevice->SetRenderState(D3DRS_CULLMODE, s_cull); } // // LIGHTING (task #20): the maps define their own directional lights (an INI // light page parsed at map load into sceneLight[] -- SetLight/LightEnable at // :3065) and the BGF loader computes smooth per-vertex normals (bgfload.cpp: // 319-456), so the whole authentic pipeline already exists; the old bring-up // line here force-disabled it. Lit whenever the map shipped lights (env // BT_LIGHTING=0 falls back to flat); ambient floor keeps the shadow sides // readable (BT_AMBIENT= to tune, default 0x404040). // { static int s_lit = -1; static int s_ambientOverride = 0; static DWORD s_ambient = 0x00404040; if (s_lit < 0) { const char *lv = getenv("BT_LIGHTING"); s_lit = (lv == 0 || *lv != '0') ? 1 : 0; const char *av = getenv("BT_AMBIENT"); if (av != 0) { s_ambient = (DWORD)strtoul(av, NULL, 16); s_ambientOverride = 1; } } if (s_lit && sceneLightCount > 0) { mDevice->SetRenderState(D3DRS_LIGHTING, TRUE); // BT (task #20): re-assert the AUTHENTIC env ambient (mEnvAmbient, set // by the map's INI 'ambient=' page -- e.g. des_day 0.45) each frame, // NOT the bring-up gray floor. BT_AMBIENT= still overrides for tuning. mDevice->SetRenderState(D3DRS_AMBIENT, s_ambientOverride ? s_ambient : mEnvAmbient); mDevice->SetRenderState(D3DRS_NORMALIZENORMALS, TRUE); // animated joints scale } else { mDevice->SetRenderState(D3DRS_LIGHTING, FALSE); } } mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(¤tFogNear))); mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(¤tFogFar))); mDevice->SetRenderState(D3DRS_ZWRITEENABLE, true); mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, false); mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); // // (task #20 lighting) With lighting ON, take the lit material colors from the // per-vertex diffuse (the BGF loader bakes the BMF material tint there) -- // no SetMaterial exists in this path and D3D's default material has a BLACK // ambient (shadow sides would render pitch black). // { const char *lv2 = getenv("BT_LIGHTING"); if ((lv2 == 0 || *lv2 != '0') && sceneLightCount > 0) { mDevice->SetRenderState(D3DRS_COLORVERTEX, TRUE); mDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); mDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_COLOR1); } else { mDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); } } mDevice->SetTextureStageState(2, D3DTSS_COLOROP, D3DTOP_DISABLE); d3d_OBJECT::ResetState(mDevice); if (!l4_application->IsDead()) { std::list::const_iterator iter; for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter) { (*iter)->Draw(PASS_OPAQUE, &viewTransform, mTargetRenderTime); } } for (d3d_OBJECT *obj = mRenderLists[PASS_OPAQUE]; obj != NULL; obj = obj->GetNext(PASS_OPAQUE)) obj->Draw(PASS_OPAQUE, &viewTransform, mTargetRenderTime); // // Next up is the decal pass // mDevice->SetTransform(D3DTS_PROJECTION, &mDecalProjectionMatrix); if (!l4_application->IsDead()) { std::list::const_iterator iter; for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter) { (*iter)->Draw(PASS_DECAL, &viewTransform, mTargetRenderTime); } } for (d3d_OBJECT *obj = mRenderLists[PASS_DECAL]; obj != NULL; obj = obj->GetNext(PASS_DECAL)) obj->Draw(PASS_DECAL, &viewTransform, mTargetRenderTime); // // The sphere pass // //Set it up so the fog won't affect spheres' colors so much- extend the near fog plane out float fogModNear = currentFogFar; float fogModFar = fogModNear + (currentFogFar - currentFogNear); mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(&fogModNear))); mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(&fogModFar))); for (d3d_OBJECT *obj = mRenderLists[PASS_SPHERE]; obj != NULL; obj = obj->GetNext(PASS_SPHERE)) obj->Draw(PASS_SPHERE, &viewTransform, mTargetRenderTime); // // The sky pass // // BT (task #20): HORIZON SEAM fix. The sky is a FLAT plane at Y~110 spanning // +/-6000 (not a dome). Reusing the world far=2100 projection TRUNCATES that // plane a few degrees above the true horizon, and the gap below its rim shows // the frame Clear = fog colour -> a hard lavender band. Also the old code // extended sky fog to near*3/far*6, leaving the plane's rim near-unfogged // (saturated blue edge above the band). FIX: (a) a sky-only projection with // a far plane large enough for the plane to reach the horizon; (b) the SAME // fog as the world so the descended rim hazes to the fog colour continuously. // Both restored after the sky loop (the alpha-blend/particle passes MUST run // under the world projection + world fog). BT_SKY_FAR=0 restores the old // truncated behaviour for A/B. static const int s_skyFar = (getenv("BT_SKY_FAR") == 0 || getenv("BT_SKY_FAR")[0] != '0'); if (s_skyFar) { // world fog (no *3/*6): the sky plane's far edge fogs to the horizon colour. mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(¤tFogNear))); mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(¤tFogFar))); D3DXMATRIX skyProj; D3DXMatrixPerspectiveFovRH(&skyProj, viewAngle * (PI / 180.0f), gWindowAspect > 0.0f ? gWindowAspect : (float)x_size / (float)y_size, clipNear, 9000.0f); mDevice->SetTransform(D3DTS_PROJECTION, &skyProj); } else { //Further extend the fog distance fogModNear = currentFogNear * 3; fogModFar = currentFogFar * 6; mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(&fogModNear))); mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(&fogModFar))); mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix); } // BT fix (task #20): the SKY is pre-shaded art and must draw FULLBRIGHT -- // with scene lighting enabled (the task-#20 lighting revival) the dome was // being lit like world geometry: daylight on the sun side, black on the far // side ("the sky is half day and half black"). Exempt the sky pass. DWORD skySavedLighting = FALSE; mDevice->GetRenderState(D3DRS_LIGHTING, &skySavedLighting); mDevice->SetRenderState(D3DRS_LIGHTING, FALSE); // BT (task #20): SCREEN-toward-white combine for the sky (was MODULATE). // The cloud art (bintA) is a GRAYSCALE intensity map; the sky's colour is the // material tint (0.3,0.5,1.0) baked into the vertex diffuse. MODULATE (texel // x tint) gave saturated NAVY with dark banding ("two-tone, nothing like // clouds"). The original combined them as a SCREEN / lerp-to-white: // screen(D,T) = T + D*(1-T) = lerp(D, white, T) -- bright cloud texels -> near // white, dark -> the pale blue tint. One texture stage does it exactly: // D3DTOP_LERP(Arg0=TEXTURE, Arg1=TFACTOR=white, Arg2=DIFFUSE) = T*1 + D*(1-T). // Measured screen(0.3,0.5,1.0, 0.85)=(228,236,255) ~ original top (229,230,255). // NOW DEFAULT OFF: the sky material (dsky_mtl) has its own 'sky' RAMP // (0,0,0.6 -> 0.99,0.99,0.99) which the loader bakes into the sky texture and // draws with a white vertex/material -- the authentic path with proper WHITES. // The screen combine was the pre-ramp heuristic; BT_SKY_SCREEN=1 re-enables it. static const int s_skyScreen = (getenv("BT_SKY_SCREEN") != 0 && getenv("BT_SKY_SCREEN")[0] != '0'); DWORD skyOp = 0, skyA0 = 0, skyA1 = 0, skyA2 = 0, skyTF = 0; if (s_skyScreen) { mDevice->GetTextureStageState(0, D3DTSS_COLOROP, &skyOp); mDevice->GetTextureStageState(0, D3DTSS_COLORARG0, &skyA0); mDevice->GetTextureStageState(0, D3DTSS_COLORARG1, &skyA1); mDevice->GetTextureStageState(0, D3DTSS_COLORARG2, &skyA2); mDevice->GetRenderState(D3DRS_TEXTUREFACTOR, &skyTF); mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, 0xFFFFFFFF); mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_LERP); mDevice->SetTextureStageState(0, D3DTSS_COLORARG0, D3DTA_TEXTURE); mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR); mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); } if (!l4_application->IsDead()) { std::list::const_iterator iter; for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter) { (*iter)->Draw(PASS_SKY, &viewTransform, mTargetRenderTime); } } for (d3d_OBJECT *obj = mRenderLists[PASS_SKY]; obj != NULL; obj = obj->GetNext(PASS_SKY)) obj->Draw(PASS_SKY, &viewTransform, mTargetRenderTime); if (s_skyScreen) { mDevice->SetTextureStageState(0, D3DTSS_COLOROP, skyOp); mDevice->SetTextureStageState(0, D3DTSS_COLORARG0, skyA0); mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, skyA1); mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, skyA2); mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, skyTF); } mDevice->SetRenderState(D3DRS_LIGHTING, skySavedLighting); // restore for the world // BT (task #20): RESTORE the world projection after the sky pass -- the // alpha-blend (explosions/effects), particle, and reticle/HUD passes below // MUST render under the world far=2100 projection, not the sky's far=9000. if (s_skyFar) mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix); //Reactivate fog mDevice->SetRenderState(D3DRS_FOGSTART, *((DWORD*)(¤tFogNear))); mDevice->SetRenderState(D3DRS_FOGEND, *((DWORD*)(¤tFogFar))); // // Finally we do the alpha blend pass // mDevice->SetRenderState(D3DRS_ZWRITEENABLE,false); mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,true); mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2); if (!l4_application->IsDead()) { std::list::const_iterator iter; for (iter = this->mConsolidatedStaticObjects.begin(); iter != this->mConsolidatedStaticObjects.end(); ++iter) { (*iter)->Draw(PASS_ALPHABLEND, &viewTransform, mTargetRenderTime); } } for (d3d_OBJECT *obj = mRenderLists[PASS_ALPHABLEND]; obj != NULL; obj = obj->GetNext(PASS_ALPHABLEND)) obj->Draw(PASS_ALPHABLEND, &viewTransform, mTargetRenderTime); // BT weapon beams (port addition): draw + age the queued muzzle->hit beams // here in the alpha pass (world projection + view already set; Z-test on so a // beam is occluded where it enters terrain). See BTDrawBeams above. BTDrawBeams(mDevice, &viewTransform, (float)dT); // BT .PFX particle effects (explosions / damage bands / mech death) -- the // same pass as the beams: world proj+view set, Z-test on, additive quads. { extern void BTDrawPfx(LPDIRECT3DDEVICE9 dev, const D3DXMATRIX *view, float dt); BTDrawPfx(mDevice, &viewTransform, (float)dT); } // // And don't forget particles too // D3DXMATRIX ident; mDevice->SetTransform(D3DTS_WORLD, D3DXMatrixIdentity(&ident)); if (!l4_application->IsDead()) { ParticleEngine::RenderParticles(&viewTransform, dT); for (int i=0; iSetFVF(L4VERTEX_2D_FVF); mDevice->SetRenderState(D3DRS_ZWRITEENABLE, true); mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_DIFFUSE); mDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_TEXTURE); mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE); mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_TEXTURE); mDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1); mDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); if (mReticle && !l4_application->IsDead()) mReticle->Render(0, &viewTransform); if (mCamShipHUD) mCamShipHUD->Render(0, &viewTransform); // DEV-COMPOSITE: in DOCKED mode (BT_DEV_GAUGES_DOCK) blit the 6-surface gauge panel // into this window as the LAST draw before EndScene (no-op otherwise / off pod). extern void BTDrawGaugeInset(LPDIRECT3DDEVICE9 device); BTDrawGaugeInset(mDevice); hr = mDevice->EndScene(); // DEV-COMPOSITE: default mode -- render the 6 cockpit surfaces into a SEPARATE window // (its own additional swap chain on this device) + present it, between the main // EndScene and the main Present. No-op unless BT_DEV_GAUGES (and not docked mode). extern void BTGaugeWindowRenderAndPresent(LPDIRECT3DDEVICE9 device); BTGaugeWindowRenderAndPresent(mDevice); // DIAG (turn-hitch hunt): draw CPU is _rt0..here; Present blocks on the GPU. LARGE_INTEGER _rt1; QueryPerformanceCounter(&_rt1); hr = mDevice->Present(NULL, NULL, NULL, NULL); { LARGE_INTEGER _rt2, _rf; QueryPerformanceCounter(&_rt2); QueryPerformanceFrequency(&_rf); const double drawMs = (double)(_rt1.QuadPart - _rt0.QuadPart) * 1000.0 / (double)_rf.QuadPart; const double presentMs = (double)(_rt2.QuadPart - _rt1.QuadPart) * 1000.0 / (double)_rf.QuadPart; static double sAcc = 0.0, sMaxD = 0.0, sMaxP = 0.0; static int sFrames = 0; sAcc += drawMs + presentMs; ++sFrames; if (drawMs > sMaxD) sMaxD = drawMs; if (presentMs > sMaxP) sMaxP = presentMs; if (drawMs + presentMs > 150.0) DEBUG_STREAM << "[rslow] draw=" << drawMs << "ms present=" << presentMs << "ms batches=" << gNumBatches << "\n" << std::flush; if (sAcc >= 1000.0) { extern int gBTNumCulled; DEBUG_STREAM << "[rstat] frames=" << sFrames << " avg=" << (sAcc / sFrames) << "ms maxDraw=" << sMaxD << " maxPresent=" << sMaxP << " batches=" << gNumBatches << " culled=" << gBTNumCulled << "\n" << std::flush; sAcc = 0.0; sFrames = 0; sMaxD = 0.0; sMaxP = 0.0; } } if (hr == D3DERR_DEVICELOST) { int bbCount = mPresentParams.BackBufferCount; int bbWidth = mPresentParams.BackBufferWidth; int bbHeight = mPresentParams.BackBufferHeight; ParticleEngine::Destroy(); V(mDevice->Reset(&mPresentParams)); ParticleEngine::Initialize(mDevice); this->SetCoreRenderStates(); mPresentParams.BackBufferCount = bbCount; mPresentParams.BackBufferWidth = bbWidth; mPresentParams.BackBufferHeight = bbHeight; } ticks = HiResNowTicks(); #ifdef LOGFRAMERATE fputc(1, FRAMERATE_LOG); fwrite(&ticks, sizeof(__int64), 1, FRAMERATE_LOG); #endif } void DPLRenderer::ExecuteIdle() { HRESULT hr; hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0); hr = mDevice->BeginScene(); hr = mDevice->EndScene(); if (mDevice->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST) { int bbCount = mPresentParams.BackBufferCount; int bbWidth = mPresentParams.BackBufferWidth; int bbHeight = mPresentParams.BackBufferHeight; ParticleEngine::Destroy(); V(mDevice->Reset(&mPresentParams)); ParticleEngine::Initialize(mDevice); this->SetCoreRenderStates(); mPresentParams.BackBufferCount = bbCount; mPresentParams.BackBufferWidth = bbWidth; mPresentParams.BackBufferHeight = bbHeight; } } // //############################################################################# // DPLDelayDCSFlush and DPLDoDCSBatchFlush queue up a list of DCS pointers // for later std::flushing in one big batch. //############################################################################# // void DPLRenderer::DPLDelayDCSFlush( dpl_DCS *my_dcs) // The DCS we want to remember for later { // // Make sure the array hasn't become overfilled somehow and make // sure the DCS is valid. // Verify(delayedDCSCount <= DELAY_DCS_FLUSH_ARRAY_SIZE); Check_Pointer(my_dcs); // // If the array is full, std::flush it out to make space for this DCS // if(delayedDCSCount == DELAY_DCS_FLUSH_ARRAY_SIZE) { DPLDoDCSBatchFlush(); } // // Add the New DCS to the list // delayDCSFlushArray[delayedDCSCount++] = my_dcs; } void DPLRenderer::DPLDoDCSBatchFlush() // Flush the dcs's remembered by DPLDelayDCSFlush { //STUBBED: DPL RB 1/14/07 //SET_VIDEO_BATCH_FLUSH(); //// //// Make sure the array hasn't become overfilled somehow //// //Verify(delayedDCSCount <= DELAY_DCS_FLUSH_ARRAY_SIZE); //// //// Flush the array and reset the counters that go with it //// //if(delayedDCSCount != 0) //{ // delayDCSFlushArray[delayedDCSCount] = NULL; // dpl_FlushDCSArticulations(delayDCSFlushArray); // delayedDCSCount = 0; //} //CLEAR_VIDEO_BATCH_FLUSH(); } // //############################################################################# // DPLReportFreeMemory writes current free memory in graphics card to any // output stream. //############################################################################# // void DPLRenderer::DPLReportFreeMemory(std::ostream &output) { //STUBBED: DPL RB 1/14/07 // output << "Free memory in card: " << dpl_FreeMemory() << " bytes." << std::endl; return; } // //############################################################################# // DPLReportPerfStats writes performance statistics to std::cout (stdout). //############################################################################# // void DPLRenderer::DPLReportPerfStats(std::ostream &output) { //STUBBED: DPL RB 1/15/07 ////----------------------------------------------------- //// HACK - copied from camera.c must re-copy if changed //// //// case '?': //// printf ("sect time %d dcs 0x%x inst 0x%x\n", //// __sect_time, sect_dcs, sect_inst ); ////----------------------------------------------------- //output << "sect time " << __sect_time << // " dcs and inst not available" << std::endl; ////------------------------------------------------------------ //// HACK - copied from dpl_vpx.c must re-copy if changed //// //// void dpl_PerfStats(void) //// printf ( "cull %d draw %d frame %d pxpl %d prims %d\n", //// __last_cull_time, //// __last_draw_time, //// __last_frame_time, //// __last_pxpl_time, //// __last_frame_prims ); ////------------------------------------------------------------ //output << // "cull " << __last_cull_time << // " draw " << __last_draw_time << // " frame " << __last_frame_time << // " pxpl " << __last_pxpl_time << // " prims " << __last_frame_prims << // std::endl; //if(statistics_started) //{ // ReportStatistics(); //} //else //{ // ResetStatistics(); // statistics_started = True; //} //return; } // //############################################################################# // DPLToggleWireframe toggles the state of dpl global wireframe. //############################################################################# // void DPLRenderer::DPLToggleWireframe() { //STUBBBED: DPL RB 1/14/07 //static Logical wireframe_on = 0; //if ((wireframe_on ^= 1) != 0) //{ // DEBUG_STREAM << "wireframe ON" << std::endl << std::flush; // dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_on, NULL ); //} //else //{ // DEBUG_STREAM << "wireframe OFF" << std::endl << std::flush; // dpl_SetRenderProperty(dpl_render_prop_wireframe, dpl_render_value_off, NULL ); //} } // //############################################################################# // DPLTogglePVision toggles the state of dpl "predator" vision. //############################################################################# // void DPLRenderer::DPLTogglePVision() { //STUBBED: DPL RB 1/14/07 //static Logical pvision_on = 0; //dpl_EXPLOSION_EFFECT_INFO sfx_info; //sfx_info.x = sfx_info.y = sfx_info.z = 0; //if ((pvision_on ^= 1) != 0) //{ // DEBUG_STREAM << "pvision ON" << std::endl << std::flush; // sfx_info.type = -1; //} //else //{ // DEBUG_STREAM << "pvision OFF" << std::endl << std::flush; // sfx_info.type = -2; //} //dpl_Effect(dpl_effect_type_explosion, NULL, &sfx_info); //return; } // //############################################################################# // DPLFrameDump writes screen image to targa file. //############################################################################# // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // oneD_filter() antialiased framegrab support void oneD_filter( uint32 *linebuffer, unsigned short *rframe, unsigned short *gframe, unsigned short *bframe, int32 y, int32 x_size ) { int32 pos, i, r, g, b; unsigned char *clinebuf = (unsigned char *)linebuffer; pos = y * x_size; for (i=0; i> 8) & 0xff); *clinebuf++ = (unsigned char)((g >> 8) & 0xff); *clinebuf++ = (unsigned char)((b >> 8) & 0xff); } return; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // dump_frame_buffer() void dump_frame_buffer( dpl_VIEW *eye, int32 x_size, int32 y_size, Logical antialias ) { //STUBBED: DPL RB 1/14/07 ////do not check eye here ////---------------------------------------- //// control variable and operating buffers ////---------------------------------------- //static uint32 // dumped_frames = 0, // *line_buffer = NULL; //static unsigned short // *rframebuffer = NULL, // *gframebuffer = NULL, // *bframebuffer = NULL; //if (eye == NULL) //{ // //-------------------------- // // release allocated memory // //-------------------------- // if (line_buffer) // { // Unregister_Pointer(line_buffer); // delete line_buffer; // } // if (rframebuffer) // { // Unregister_Pointer(rframebuffer); // delete rframebuffer; // } // if (gframebuffer) // { // Unregister_Pointer(gframebuffer); // delete gframebuffer; // } // if (bframebuffer) // { // Unregister_Pointer(bframebuffer); // delete bframebuffer; // } // return; //} //Check_Pointer(eye); ////----------------------------------------------------------------- //// AA kernel definition: //// //// normalized screen coordinates are -1.0 .. +1.0 //// these map (in NTSC) to 705 and 512. //// So a pixel in x is //// 2.0 / 704 = 2.841e-3 //// in y = 3.906e-3 //// for the re-use 5-sample kernel we displace by 0.5 pixels ... ////----------------------------------------------------------------- //static const int32 kernel_size = 4; //static const float xk = 2.0f / x_size; //static const float yk = 2.0f / y_size; //static const float ox = xk / 4.0f; //static const float oy = yk / 4.0f; //static const float jx = 0.0f; // ox / 4.0f //static const float jy = 0.0f; // oy / 4.0f //static const float x_kernel[4] = { -(ox+jx), ox-jx, jx-ox, jx+ox }; //static const float y_kernel[4] = { oy-jy, oy+jy, -(jy+oy), jy-oy }; //static const int kernel_weights[4] = { 64, 64, 64, 64 }; ////--------------------- //// operating variables ////--------------------- //int32 passes = (antialias)?kernel_size:1; //int32 size = x_size * y_size; //int32 frameptr; //int32 i, x, y; //DEBUG_STREAM << "Dump frame buffer (antialias=" << // ((antialias)?"True":"False") << ") - press Esc to cancel." << std::endl; ////---------------------------- //// allocate operating buffers ////---------------------------- //if (line_buffer == NULL) //{ // //----------------------------------------------------------------------- // // NOTE - must call dump_frame_buffer(NULL, NULL, NULL, NULL) to release // //----------------------------------------------------------------------- // line_buffer = new uint32[1024]; // Register_Pointer(line_buffer); // rframebuffer = new unsigned short[size]; // Register_Pointer(rframebuffer); // gframebuffer = new unsigned short[size]; // Register_Pointer(gframebuffer); // bframebuffer = new unsigned short[size]; // Register_Pointer(bframebuffer); //} ////------------------------------ //// clear out r g b framebuffers ////------------------------------ //frameptr = 0; //for (i=0; i> 8) & 0xff); //tga_hdr[14] = (unsigned char)(y_size & 0xff); //tga_hdr[15] = (unsigned char)((y_size >> 8) & 0xff); //tga_hdr[16] = 0x18; //tga_hdr[17] = 0x00; //DEBUG_STREAM << "Writing image to file '" << fname << "' . . . " << std::flush; //fp = fopen(fname, "wb"); //fwrite(tga_hdr, 18, 1, fp); //for (y=0; yidentifier & 0xffff0000) | GetUniqueID() | ((subid << 16) & 0x00ff0000); //tempParticle.px = location.x; //tempParticle.py = location.y; //tempParticle.pz = location.z; //dpl_Effect(dpl_effect_type_particlestart, my_DCS, &tempParticle); // std::cout<<"psfx identifier used was "<= 1000) { effect_number -= 1000; if(effect_number < 0 || effect_number > MAX_PSFX_COUNT-1) { Fail("PSFX id number was not in the allowed range"); } // DPLIndependantPFX(location,myPSFXDescriptons[effect_number],my_DCS,subid); // find a free emitter ParticleEmitter *emitter = NULL; for (int i=0; iSetEffect(&myPSFXDescriptons[effect_number]); emitter->SetPosition(location.x, location.y, location.z); emitter->Start(); } return; } // // Board effect numbers (<100) -- the 1995 dpl explosion/damage effects. // RECONSTRUCTED: routed to the BT .PFX particle layer (the [pfx_day]/ // [pfx_night] psfxN mapping loads each number's authentic .PFX definition; // see the layer banner at the top of this file). This is what makes every // weapon-hit / damage-band / mech-death explosion actually VISIBLE -- the // original dpl_Effect(dpl_effect_type_explosion, ...) below was IG-board // hardware and was never ported. // { extern void BTStartPfx(int effect_number, float x, float y, float z); BTStartPfx(effect_number, location.x, location.y, location.z); } //dpl_EXPLOSION_EFFECT_INFO my_explosion; //my_explosion.type = effect_number; //my_explosion.x = location.x; //my_explosion.y = location.y; //my_explosion.z = location.z; //dpl_Effect ( dpl_effect_type_explosion, my_DCS, &my_explosion ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DPLRenderer::SetViewAngle(Degree new_angle) { //STUBBED: DPL RB 1/14/07 //Check(this); //// ////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //// Convert From Degree To Radian ////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //// //Radian view_angle; //view_angle = new_angle; //viewAngle = view_angle; //viewRatio = tan(viewAngle/2.0f); //// ////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //// Calc Aspect Ratio and Set View Projection ////~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //// //aspectRatio = (float) y_size / (float) x_size; //dpl_SetViewProjection ( dplMainView, -1.0f, -aspectRatio, 1.0f, aspectRatio, 1.0f/viewRatio); //dpl_FlushView(dplMainView); } // //############################################################################# // Startup the implementation of the Division video renderer //############################################################################# // void DPLRenderer::LoadMissionImplementation(Mission *mission) { Check(this); Tell("DPLVideoRenderer::StartImplementation has been called\n"); DPLReadEnvironment(mission); LoadNameBitmaps(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BT (task #20): window-resize aspect fix. gWindowAspect (defined at the top // of this file) holds the live client aspect; D3D9 stretches the fixed-size // backbuffer into the client area, so rendering with the CLIENT aspect cancels // the stretch. // void L4NotifyWindowResized(int client_w, int client_h) { if (client_w <= 0 || client_h <= 0) return; gWindowAspect = (float)client_w / (float)client_h; DEBUG_STREAM << "[resize] client " << client_w << "x" << client_h << " aspect=" << gWindowAspect << " app=" << (void *)l4_application << "\n" << std::flush; if (l4_application != NULL) { DPLRenderer *renderer = l4_application->GetVideoRenderer(); if (renderer != NULL) renderer->UpdateWindowAspect(client_w, client_h); } } void DPLRenderer::UpdateWindowAspect(int client_w, int client_h) { if (client_w <= 0 || client_h <= 0) return; gWindowAspect = (float)client_w / (float)client_h; if (viewAngle <= 0.0f || clipFar <= clipNear) { DEBUG_STREAM << "[resize] projection not built yet (viewAngle=" << viewAngle << ")\n" << std::flush; return; // projection not built yet; the builder below picks it up } D3DXMatrixPerspectiveFovRH(&mProjectionMatrix, viewAngle * (PI / 180.0f), gWindowAspect, clipNear, clipFar); mDecalProjectionMatrix = mProjectionMatrix; mDecalProjectionMatrix._33 -= mDecalEpsilon; if (mDevice != NULL) mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix); DEBUG_STREAM << "[resize] projection rebuilt: fov=" << viewAngle << " aspect=" << gWindowAspect << " _11=" << mProjectionMatrix._11 << " _22=" << mProjectionMatrix._22 << "\n" << std::flush; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DEBUG(bring-up): install a valid projection + lighting so loaded geometry is // visible even when the full DPLReadEnvironment path has not been wired (BT). // void DPLRenderer::EnsureValidProjection() { // // BT (task #20): this was a bring-up SAFETY NET for when the real DPL // environment (BTDPL.INI via DPLReadEnvironment) had not yet been wired -- // it forced near/far=0.25/1300, KILLED fog, and set WHITE ambient, which // clobbered the authentic clip range (2100), the haze fog (600/2050), and // the map ambient (0.45). DPLReadEnvironment now runs and sets all of those // from the map's INI page, so honour them: only fall back to fixed values // when the env genuinely failed to produce a valid projection. // if (viewAngle > 0.0f && clipFar > clipNear) { // Env is valid -- just (re)assert the env-built projection on the device. // Do NOT touch fog or ambient (the env set the authentic values). if (mDevice != NULL) mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix); DEBUG_STREAM << "[VP] env projection honoured: fov=" << viewAngle << " near=" << clipNear << " far=" << clipFar << " fog=" << currentFogNear << ".." << currentFogFar << "\n" << std::flush; return; } // ---- FALLBACK: env did not set a projection (should not happen with the // catch-all branch in BTDPL.INI, but keeps the mech visible if it does). viewAngle = 60.0f; clipNear = 0.25f; clipFar = 1300.0f; viewRatio = (float)tan(viewAngle * 0.5f * (PI / 180.0f)); D3DXMatrixIdentity(&mProjectionMatrix); D3DXMatrixPerspectiveFovRH(&mProjectionMatrix, viewAngle * (PI / 180.0f), gWindowAspect > 0.0f ? gWindowAspect : (float)x_size / (float)y_size, clipNear, clipFar); mDecalEpsilon = 0.0000005f; mDecalProjectionMatrix = mProjectionMatrix; mDecalProjectionMatrix._33 -= mDecalEpsilon; // push fog far away so the mech is not fogged to the background colour fogNear = currentFogNear = 1.0e9f; fogFar = currentFogFar = 1.0e9f; if (mDevice != NULL) { mDevice->SetTransform(D3DTS_PROJECTION, &mProjectionMatrix); mDevice->SetRenderState(D3DRS_FOGENABLE, FALSE); mDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(255, 255, 255)); } DEBUG_STREAM << "[VP] EnsureValidProjection FALLBACK (env failed): RH fov=" << viewAngle << " near=" << clipNear << " far=" << clipFar << "\n" << std::flush; } //############################################################################## // Name Bitmap Support // void DPLRenderer::SortAndReloadNameBitmaps() { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Get the Entity Group of Players //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EntityGroup *player_group = application->GetEntityManager()->FindGroup("Players"); ChainIteratorOf player_iterator(player_group->groupMembers); Player *current_player; while ((current_player = (Player*)player_iterator.ReadAndNext()) != NULL) { BitMap *name_bitmap = application->GetCurrentMission()->GetLargeNameBitmap(current_player->playerBitmapIndex); if (name_bitmap && current_player->IsScoringPlayer()) { int index = current_player->playerRanking + 1; if (mNameTextures[index]) mNameTextures[index]->Release(); mDevice->CreateTexture(128, 32, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &mNameTextures[index], NULL); LoadBitSliceTexture(name_bitmap, mNameTextures[index]); } } LoadOrdinalBitmaps(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DPLRenderer::LoadOrdinalBitmaps() { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Check if we have a Director on this machine, // if so, create load the ordinal Bitmaps only //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // if (application->GetMissionPlayer()->GetInstance() == CameraDirector::MasterInstance && application->GetMissionPlayer()->IsDerivedFrom(*CameraDirector::GetClassDerivations())) { // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Make Sure index is in the right place // in case < 8 players!!!! //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int index = 0; for(int ii=1; ii<5; ++ii) { // //~~~~~~~~~~~~~~~~~~ // Index Starts at 1 //~~~~~~~~~~~~~~~~~~ // BitMap *ordinal_bitmap = application->GetCurrentMission()->GetOrdinalBitmap(ii); if (mOrdinalTextures[index]) mOrdinalTextures[index]->Release(); mDevice->CreateTexture(128, 32, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &mOrdinalTextures[index], NULL); LoadBitSliceTexture(ordinal_bitmap, mOrdinalTextures[index]); ++index; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // unsigned int* DPLRenderer::MakeBitSliceStorage() { Check(this); // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Allocate some temporary memory //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // uint32 *worst_case_texels = new uint32[128*64]; if(!worst_case_texels) { Fail("Could not allocate RAM for worst case texels\n"); } // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Zero Out Memory so Empty Texture space is Black //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // for(int ii=0;ii<8192;++ii) { worst_case_texels[ii] = 0; } return worst_case_texels; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DPLRenderer::LoadNameBitmaps() { int player_count = application->GetCurrentMission()->GetPlayerCount(); for (int ii=0; iiGetCurrentMission()->GetLargeNameBitmap(ii + 1); if (name_bitmap) { if (mNameTextures[ii]) mNameTextures[ii]->Release(); HRESULT hr; V(mDevice->CreateTexture(128, 32, 1, 0, D3DFMT_A4R4G4B4, D3DPOOL_MANAGED, &mNameTextures[ii], NULL)); LoadBitSliceTexture(name_bitmap, mNameTextures[ii]); } } LoadOrdinalBitmaps(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DPLRenderer::ShutdownImplementation() { //STUBBED: DPL RB 1/14/07 // Tell("DPLVideoRenderer::StopImplementation has been called\n"); // dpl_EnableSyncOnCreate(); // SChainIteratorOf projectile_iterator(&projectile_list); // TreeIteratorOf cache_iterator(&dplObjectCacheSocket); //#if defined(LAB_ONLY) // std::cout<<"max projectiles "<objectPointer; delete my_cache_line; // // Return the object pointer // return(object_pointer); } void DPLRenderer::PutCachedObject( const CString &object_name, // Name of the object we will cache dpl_OBJECT *object_pointer) // pointer to the object being cached { // // Create the cache line data structure // #if 0 typedef PlugOf DPLObjectCacheLine; DPLObjectCacheLine *my_cache_line = new DPLObjectCacheLine(object_pointer); #endif DPLObjectCacheLine *my_cache_line = new DPLObjectCacheLine( object_name, object_pointer); Register_Object(my_cache_line); // // Store this cache line in the cache // dplObjectCacheSocket.AddValue(my_cache_line, object_name); } //----------------------------------------------------------------------------- //--------------------------Projectile Speedup--------------------------------- //----------------------------------------------------------------------------- InnerProjectileRenderable* DPLRenderer::GetProjectile( d3d_OBJECT *graphical_object, // object to hang on the DCS, may be a list later bool isDeathZone) // DPL Zone this stuff will live in (for culling) { //STUBBED: DPL RB 1/14/07 //InnerProjectileRenderable // *return_projectile; //dpl_INSTANCE // *temp_instance; //// //// Are there projectiles in the list? //// //SChainIteratorOf iterator(&projectile_list); //if ((return_projectile = iterator.GetCurrent()) != NULL) //{ // // Yes, remove it from the list set it's instance and return it // iterator.Remove(); // temp_instance = return_projectile->GetInstance(); // if(graphical_object != dpl_GetInstanceObject(temp_instance)) // { // dpl_SetInstanceObject (temp_instance, graphical_object); // dpl_FlushInstance (temp_instance); // } // return(return_projectile); //} //else //{ // // no, make a new one and return that InnerProjectileRenderable *projectile = new InnerProjectileRenderable( graphical_object, // object to hang on the DCS, may be a list later isDeathZone); // DPL Zone this stuff will live in (for culling) return(projectile); //} } void DPLRenderer::ReleaseProjectile( InnerProjectileRenderable* inner_projectile) { // add the projectile back to the list //projectile_list.Add(inner_projectile); } //----------------------------------------------------------------------------- //--------------------------Joint to DCS translator---------------------------- //----------------------------------------------------------------------------- //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DPLJointToDCSTranslator is a class that contains a joint number to dcs // pointer translation table. This lets a renderer find the dcs that goes // with a particular segment. // DPLJointToDCSTranslator::DPLJointToDCSTranslator( Entity *entity, // The entity to translate dpl_DCS *dcs_array[]) // Array of DCS's to translate { JointedMover *my_jointed_mover; // // Make sure this is a jointed mover, then cast the entity pointer over // if (entity->IsDerivedFrom(*JointedMover::GetClassDerivations())) { my_jointed_mover = (JointedMover*)entity; } else { Fail("DPLJointToDCSTranslator was called on an entity NOT a JointedMover\n"); } // // Find out how many joints the entity has, then allocate enough RAM for a // DCS pointer to every joint. // JointSubsystem* joint_subsystem = my_jointed_mover->GetJointSubsystem(); Check(joint_subsystem); translation_array = new (dpl_DCS(*[joint_subsystem->GetJointCount()])); Register_Pointer(translation_array); // // Setup to iterate the entity segment table // EntitySegment::SegmentTableIterator segment_iterator(my_jointed_mover->segmentTable); EntitySegment *current_segment; while ((current_segment = segment_iterator.ReadAndNext()) != NULL) { // // For each segment, see if it has a joint index, if it does, put the // DCS for that joint into the translation array // Check(current_segment); int joint_index = current_segment->GetJointIndex(); if(joint_index != -1) { translation_array[joint_index] = dcs_array[current_segment->GetIndex()]; } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DPLJointToDCSTranslator::~DPLJointToDCSTranslator() { Unregister_Pointer(translation_array); delete[] translation_array; translation_array = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Logical DPLJointToDCSTranslator::TestInstance() const { return True; } //----------------------------------------------------------------------------- //--------------------------Resource creation support-------------------------- //----------------------------------------------------------------------------- //############################################################################# //############# DPLRenderer::CreateModelVideoStreamResource ############# //############################################################################# ResourceDescription::ResourceID DPLRenderer::CreateModelVideoStreamResource( ResourceFile *resource_file, const char *model_name, NotationFile *model_file, const ResourceDirectories * /*directories*/ ) { ResourceDescription *res_description = resource_file->FindResourceDescription( model_name, ResourceDescription::VideoModelResourceType ); if (res_description == NULL) { NameList *video_entries = model_file->MakeEntryList("video"); if (video_entries != NULL) { Register_Object(video_entries); //---------------------------------------------- // parse video model data and store in resource //---------------------------------------------- Tell("Building video resource for model '" << model_name << "'.\n"); NameList::Entry *entry, *next_entry; const char *entry_name, *entry_pointer, *argument_start; int length; char argument[40], *argument_pointer; L4VideoObject::ResourceType resource_type; Enumeration //(see L4VideoObject::RendererModes) renderer_modes; enum { parsing_filename, seeking_switch, parsing_switch, parsing_billboard } state; L4VideoObject *video_object; L4VideoObjectWrapper *video_wrapper; ChainOf video_chain(NULL); char *video_stream, *video_pointer; int object_count; long object_size, stream_length; //------------------------------------------------ // parse each entry in [video] page of model file //------------------------------------------------ next_entry = video_entries->GetFirstEntry(); while (next_entry) { entry = next_entry; Check(entry); next_entry = entry->GetNextEntry(); // so 'continue' works entry_name = entry->GetName(); if (entry_name && *entry_name) { //-------------------------------------------- // could be "skeleton" or "object" or comment //-------------------------------------------- if (strcmp(entry_name, "object") == 0) { resource_type = L4VideoObject::Object; } else if (strcmp(entry_name, "rubble") == 0) { resource_type = L4VideoObject::Rubble; } else if (strcmp(entry_name, "skeleton") == 0) { resource_type = L4VideoObject::Skeleton; } else if (Comment_Line(entry_name)) { // do nothing - skip comments continue; } else if (strncmp(entry_name, "skeleton", 8) == 0) { // do nothing - skip temporary skeleton entries continue; } else if (strncmp(entry_name, "destroyed", 9) == 0) { // do nothing - skip destroyed skeleton entries continue; } else if (strncmp(entry_name, "dzm", 3) == 0) { // do nothing - skip damage zone material entries continue; } else { // resource_type = L4VideoObject::Unknown; DEBUG_STREAM << "Unknown entry '" << entry_name << "' in model '" << model_name << "' ignored." << std::endl; continue; } //--------------------------------- // parse and process each argument //--------------------------------- entry_pointer = entry->GetChar(); while (entry_pointer && *entry_pointer) { //------------------------- // skip leading whitespace //------------------------- while (*entry_pointer != '\0' && isspace(*entry_pointer)) { ++entry_pointer; } //--------------------------- // exit loop if nothing left //--------------------------- if (*entry_pointer == '\0') { break; } //------------------------------------------- // parse the next argument into local buffer //------------------------------------------- argument_start = entry_pointer; while (*entry_pointer != '\0' && !isspace(*entry_pointer)) { ++entry_pointer; } length = entry_pointer - argument_start; Verify( length < sizeof(argument) ); strncpy(argument, argument_start, length); argument[length] = '\0'; //---------------------- // parse local argument //---------------------- argument_pointer = argument; renderer_modes = L4VideoObject::Normal; state = parsing_filename; while (*argument_pointer != '\0') { switch (state) { case parsing_filename: switch (*argument_pointer) { #if 0 case '.': if ((resource_type == L4VideoObject::Object) || (resource_type == L4VideoObject::Rubble)) { *argument_pointer = '\0'; // terminate filename state = seeking_switch; } break; #endif case '/': *argument_pointer = '\0'; // terminate filename state = parsing_switch; break; default: // later check for valid filename character... break; } break; case seeking_switch: if (*argument_pointer == '/') { state = parsing_switch; } break; case parsing_switch: switch (*argument_pointer) { case 'b': case 'B': state = parsing_billboard; break; case 'i': case 'I': renderer_modes |= L4VideoObject::IntersectImmune; state = seeking_switch; break; default: state = seeking_switch; break; } break; case parsing_billboard: switch (*argument_pointer) { case 'x': case 'X': renderer_modes |= L4VideoObject::BillboardXAxis; break; case 'y': case 'Y': renderer_modes |= L4VideoObject::BillboardYAxis; break; case 'z': case 'Z': renderer_modes |= L4VideoObject::BillboardZAxis; break; case '/': state = parsing_switch; break; default: state = seeking_switch; break; } break; // no default: } ++argument_pointer; } //----------------------------------------------- // create video resource object and add to chain //----------------------------------------------- video_object = new L4VideoObject( argument, resource_type, renderer_modes ); Register_Pointer(video_object); // not _Object! video_wrapper = new L4VideoObjectWrapper( video_object, True // delete object when done ); Register_Object(video_wrapper); //Tell(" adding video object '"< video_iterator(video_chain); object_count = video_iterator.GetSize(); object_size = sizeof(L4VideoObject); stream_length = sizeof(int) + object_count * object_size; video_stream = new char[stream_length]; Register_Pointer(video_stream); video_pointer = video_stream; *((int *)video_pointer) = object_count; video_pointer += sizeof(int); Tell(" count " <GetVideoObject(); if (!stricmp(video_object->GetObjectFilename(), "bp1.bgf")) video_pointer += 1 - 1; *((L4VideoObject *)video_pointer) = *video_object; video_pointer += object_size; } //-------------------------------------------------- // store stream of video resources in resource file //-------------------------------------------------- res_description = resource_file->AddResource( model_name, ResourceDescription::VideoModelResourceType, 1, ResourceDescription::Preload, video_stream, stream_length ); //-------------------------- // release allocated memory //-------------------------- // video_chain L4VideoObjectWrapper::DeleteVideoObjectChain(&video_chain); // video_stream Unregister_Pointer(video_stream); delete video_stream; // video_entries Unregister_Object(video_entries); delete video_entries; } else { //------------------------------- // no [video] page in model file //------------------------------- return (ResourceDescription::NullResourceID); } } return (res_description->resourceID); } //===========================================================================//