Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS

Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
This commit is contained in:
Cyd
2026-06-24 21:28:16 -05:00
commit 2b8ca921cb
66341 changed files with 7923174 additions and 0 deletions
@@ -0,0 +1,926 @@
#if 0
/**********************************************************************
*<
FILE: boolctrl.cpp
DESCRIPTION: A boolean controller
CREATED BY: Rolf Berteig
HISTORY: 11/18/96
*> Copyright (c) 1996, All Rights Reserved.
**********************************************************************/
#include "ctrl.h"
#include "units.h"
#include "exprlib.h"
#define BOOL_CONTROL_CLASS_ID Class_ID(0x984b8d27,0x938f3e43)
#define BOOL_CONTROL_CNAME GetString(IDS_RB_BOOLCONTROL)
#define KEY_SELECTED (1<<0)
#define KEY_FLAGGED (1<<1)
#define MAKEBOOL(fl) ( (fl)<=0.0f ? FALSE : TRUE )
class BKey {
public:
TimeValue time;
DWORD flags;
BKey() {flags=0;}
BKey(TimeValue t) {time=t; flags=0;}
};
class BoolControl : public StdControl {
public:
Tab<BKey> keys;
Interval range, valid;
BOOL onOff, startOnOff, rangeLinked;
BoolControl();
// Animatable methods
void DeleteThis() {delete this;}
int IsKeyable() {return 1;}
BOOL IsAnimated() {return keys.Count?TRUE:FALSE;}
Class_ID ClassID() {return BOOL_CONTROL_CLASS_ID;}
SClass_ID SuperClassID() {return CTRL_FLOAT_CLASS_ID;}
void GetClassName(TSTR& s) {s = BOOL_CONTROL_CNAME;}
// Reference methods
RefResult NotifyRefChanged(Interval, RefTargetHandle, PartID&, RefMessage) {return REF_SUCCEED;}
IOResult Save(ISave *isave);
IOResult Load(ILoad *iload);
RefTargetHandle Clone(RemapDir &remap = NoRemap());
// Control methods
void Copy(Control *from);
BOOL IsLeaf() {return TRUE;}
void CommitValue(TimeValue t) {}
void RestoreValue(TimeValue t) {}
void HoldTrack();
Interval GetTimeRange(DWORD flags);
void EditTimeRange(Interval range,DWORD flags);
void MapKeys(TimeMap *map,DWORD flags );
int NumKeys() {return keys.Count();}
TimeValue GetKeyTime(int index) {return keys[index].time;}
int GetKeyIndex(TimeValue t);
void DeleteKeyAtTime(TimeValue t);
BOOL IsKeyAtTime(TimeValue t,DWORD flags);
void DeleteTime(Interval iv, DWORD flags);
void ReverseTime(Interval iv, DWORD flags);
void ScaleTime(Interval iv, float s);
void InsertTime(TimeValue ins, TimeValue amount);
BOOL SupportTimeOperations() {return TRUE;}
void DeleteKeys(DWORD flags);
void DeleteKeyByIndex(int index);
void SelectKeys(TrackHitTab& sel, DWORD flags);
void SelectKeyByIndex(int i,BOOL sel);
void FlagKey(TrackHitRecord hit);
int GetFlagKeyIndex();
int NumSelKeys();
void CloneSelectedKeys(BOOL offset=FALSE);
void AddNewKey(TimeValue t,DWORD flags);
BOOL IsKeySelected(int index);
BOOL CanCopyTrack(Interval iv, DWORD flags) {return TRUE;}
BOOL CanPasteTrack(TrackClipObject *cobj,Interval iv, DWORD flags) {return cobj->ClassID()==ClassID();}
TrackClipObject *CopyTrack(Interval iv, DWORD flags);
void PasteTrack(TrackClipObject *cobj,Interval iv, DWORD flags);
int GetSelKeyCoords(TimeValue &t, float &val,DWORD flags);
void SetSelKeyCoords(TimeValue t, float val,DWORD flags);
int SetSelKeyCoordsExpr(ParamDimension *dim,TCHAR *timeExpr, TCHAR *valExpr, DWORD flags);
int HitTestTrack(
TrackHitTab& hits,
Rect& rcHit,
Rect& rcTrack,
float zoom,
int scroll,
DWORD flags);
int PaintTrack(
ParamDimensionBase *dim,
HDC hdc,
Rect& rcTrack,
Rect& rcPaint,
float zoom,
int scroll,
DWORD flags);
// StdControl methods
void GetValueLocalTime(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE) {GetValue(t,val,valid,method);}
void GetValue(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE);
void SetValueLocalTime(TimeValue t, void *val, int commit, GetSetMethod method);
void Extrapolate(Interval range,TimeValue t,void *val,Interval &valid,int type);
void *CreateTempValue() {return new float;}
void DeleteTempValue(void *val) {delete (float*)val;}
void ApplyValue(void *val, void *delta) {*((float*)val) += *((float*)delta);}
void MultiplyValue(void *val, float m) {*((float*)val) *= m;}
void SortKeys();
};
class BoolClassDesc:public ClassDesc {
public:
int IsPublic() {return 1;}
void * Create(BOOL loading) {return new BoolControl();}
const TCHAR * ClassName() {return BOOL_CONTROL_CNAME;}
SClass_ID SuperClassID() {return CTRL_FLOAT_CLASS_ID; }
Class_ID ClassID() {return BOOL_CONTROL_CLASS_ID;}
const TCHAR* Category() {return _T("");}
};
static BoolClassDesc boolCD;
ClassDesc* GetBoolControlDesc() {return &boolCD;}
class BoolControlRestore : public RestoreObj {
public:
Tab<BKey> undo;
Tab<BKey> redo;
Interval urange, rrange;
BoolControl *cont;
BoolControlRestore(BoolControl *c) {
cont = c;
undo = c->keys;
urange = c->range;
}
void Restore(int isUndo) {
if (isUndo) {
redo = cont->keys;
rrange = cont->range;
}
cont->keys = undo;
cont->range = urange;
cont->NotifyDependents(FOREVER,0,REFMSG_CHANGE);
}
void Redo() {
cont->keys = redo;
cont->range = rrange;
cont->NotifyDependents(FOREVER,0,REFMSG_CHANGE);
}
int Size() {return 1;}
void EndHold() {cont->ClearAFlag(A_HELD);}
};
class BoolClipObject : public TrackClipObject {
public:
Tab<BKey> tab;
Class_ID ClassID() {return BOOL_CONTROL_CLASS_ID;}
SClass_ID SuperClassID() { return CTRL_FLOAT_CLASS_ID; }
void DeleteThis() {delete this;}
BoolClipObject(Interval iv) : TrackClipObject(iv) {}
};
//-----------------------------------------------------------------------------
BoolControl::BoolControl()
{
//SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!"));
//MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK);
startOnOff = TRUE;
rangeLinked = TRUE;
}
RefTargetHandle BoolControl::Clone(RemapDir &remap)
{
//SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!"));
//MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK);
BoolControl *bc = new BoolControl;
bc->range = range;
bc->valid = valid;
bc->keys = keys;
bc->onOff = onOff;
bc->startOnOff = startOnOff;
CloneControl(bc,remap);
return bc;
}
#define KEYTIME_CHUNKID 0x0100
#define KEYFLAGS_CHUNKID 0x0110
#define NUMKEYS_CHUNKID 0x0130
IOResult BoolControl::Save(ISave *isave)
{
//MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK);
//SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!"));
ULONG nb;
int ct = keys.Count();
// Save the number of keys
isave->BeginChunk(NUMKEYS_CHUNKID);
isave->Write(&ct,sizeof(ct),&nb);
isave->EndChunk();
// Write each key
for (int i=0; i<ct; i++) {
isave->BeginChunk(KEYTIME_CHUNKID);
isave->Write(&keys[i].time,sizeof(keys[i].time),&nb);
isave->EndChunk();
isave->BeginChunk(KEYFLAGS_CHUNKID);
isave->Write(&keys[i].flags,sizeof(keys[i].flags),&nb);
isave->EndChunk();
}
return IO_OK;
}
IOResult BoolControl::Load(ILoad *iload)
{
//MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK);
//SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!"));
ULONG nb;
int ct;
IOResult res;
if (IO_OK!=(res=iload->OpenChunk())) return res;
assert(iload->CurChunkID()==NUMKEYS_CHUNKID);
iload->Read(&ct,sizeof(ct),&nb);
iload->CloseChunk();
keys.SetCount(ct);
for (int i=0; i<ct; i++) {
iload->OpenChunk();
assert(iload->CurChunkID()==KEYTIME_CHUNKID);
iload->Read(&keys[i].time,sizeof(keys[i].time),&nb);
iload->CloseChunk();
iload->OpenChunk();
assert(iload->CurChunkID()==KEYFLAGS_CHUNKID);
iload->Read(&keys[i].flags,sizeof(keys[i].flags),&nb);
iload->CloseChunk();
}
return IO_OK;
}
void BoolControl::Copy(Control *from)
{
//MessageBox(NULL, "WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!", "WTF?", MB_OK);
//SPEW(("jerryeds","WHY THE FUCK IS BOOL BEING CALLED??? IT SHOULD NEVER BE CALLLED!"));
if (from) {
if (from->SuperClassID()!=CTRL_FLOAT_CLASS_ID) return;
TimeValue t;
float s;
Interval iv;
TimeValue tpf = GetTicksPerFrame();
Interval v = from->GetTimeRange(TIMERANGE_ALL);
BOOL state = 1;
TimeValue astart = GetAnimStart();
if (v.Start()>astart) {
from->GetValue(astart, &s, iv);
if (s<=0.0f) {
state = 0;
AddNewKey(astart, 0);
}
}
for (t = v.Start(); t<=v.End(); t+=tpf) {
from->GetValue(t, &s, iv);
if (state) {
if (s<=0.0f) {
state = 0;
AddNewKey(t, 0);
}
}
else {
if (s>0.0f) {
state = 1;
AddNewKey(t, 0);
}
}
}
}
}
void BoolControl::HoldTrack()
{
if (theHold.Holding()&&!TestAFlag(A_HELD)) {
theHold.Put(new BoolControlRestore(this));
SetAFlag(A_HELD);
}
}
void BoolControl::EditTimeRange(Interval range,DWORD flags)
{
HoldTrack();
if (flags&EDITRANGE_LINKTOKEYS && keys.Count()) {
this->range.Set(keys[0].time,keys[keys.Count()-1].time);
rangeLinked = TRUE;
} else {
rangeLinked = FALSE;
this->range = range;
}
valid.SetEmpty();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
Interval BoolControl::GetTimeRange(DWORD flags)
{
if (rangeLinked && keys.Count())
return Interval(keys[0].time,keys[keys.Count()-1].time);
else return range;
}
int BoolControl::GetSelKeyCoords(TimeValue &t, float &val,DWORD flags)
{
BOOL tfound=FALSE, tuncommon = FALSE;
int n = keys.Count(), res;
TimeValue atime;
for (int i = 0; i < n; i++ ) {
if (keys[i].flags & KEY_SELECTED) {
if (tfound) {
if (keys[i].time!=atime) {
return KEYS_MULTISELECTED;
}
} else {
tfound = TRUE;
atime = keys[i].time;
}
}
if (tuncommon) return KEYS_MULTISELECTED;
}
t = atime;
res = 0;
if (tfound && !tuncommon) {
res |= KEYS_COMMONTIME;
}
if (!tfound) {
res = KEYS_NONESELECTED;
}
return res;
}
int BoolControl::SetSelKeyCoordsExpr(
ParamDimension *dim,
TCHAR *timeExpr, TCHAR *valExpr, DWORD flags)
{
Expr texpr;
float tfin, tfout=0.0f;
if (timeExpr) {
texpr.defVar(SCALAR_VAR,KEYCOORDS_TIMEVAR);
if (texpr.load(timeExpr)!=EXPR_NORMAL) return KEYCOORDS_EXPR_ERROR;
}
int n = keys.Count();
if (!n) return KEYCOORDS_EXPR_OK;
HoldTrack();
for (int i=0; i<n; i++) {
if (!(flags&KEYCOORDS_VALUEONLY)) {
if (keys[i].flags & KEY_SELECTED) {
tfin = float(keys[i].time)/float(GetTicksPerFrame());
texpr.eval(&tfout, 1, &tfin);
keys[i].time = int(tfout*GetTicksPerFrame());
}
}
}
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
return KEYCOORDS_EXPR_OK;
}
void BoolControl::SetSelKeyCoords(TimeValue t, float val,DWORD flags)
{
int n = keys.Count();
if (!n) return;
HoldTrack();
for (int i = 0; i < n; i++ ) {
if (!(flags&KEYCOORDS_VALUEONLY)) {
if (keys[i].flags & KEY_SELECTED) {
keys[i].time = t;
}
}
}
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::MapKeys(TimeMap *map,DWORD flags)
{
int n = keys.Count();
BOOL changed = FALSE;
if (!n) return;
HoldTrack();
if (flags&TRACK_MAPRANGE) {
TimeValue t0 = map->map(range.Start());
TimeValue t1 = map->map(range.End());
range.Set(t0,t1);
changed = TRUE;
}
if (flags&TRACK_DOALL) {
for (int i=0; i<n; i++) {
keys[i].time = map->map(keys[i].time);
changed = TRUE;
}
} else
if (flags&TRACK_DOSEL) {
BOOL slide = flags&TRACK_SLIDEUNSEL;
TimeValue delta = 0, prev;
int start, end, inc;
if (flags&TRACK_RIGHTTOLEFT) {
start = n-1;
end = -1;
inc = -1;
} else {
start = 0;
end = n;
inc = 1;
}
for (int i=start; i!=end; i+=inc) {
if (keys[i].flags & KEY_SELECTED) {
prev = keys[i].time;
keys[i].time = map->map(keys[i].time);
delta = keys[i].time - prev;
changed = TRUE;
} else if (slide) {
keys[i].time += delta;
}
}
}
if (changed) {
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
}
int BoolControl::GetKeyIndex(TimeValue t)
{
for (int i=0; i<keys.Count(); i++) {
if (keys[i].time==t) return i;
if (keys[i].time<t) return -1;
}
return -1;
}
void BoolControl::DeleteKeyAtTime(TimeValue t)
{
int index = GetKeyIndex(t);
if (index>=0) {
HoldTrack();
keys.Delete(index,1);
valid.SetEmpty();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
}
BOOL BoolControl::IsKeyAtTime(TimeValue t,DWORD flags)
{
for (int i=0; i<keys.Count(); i++) {
if (keys[i].time>t) return FALSE;
if (keys[i].time==t) return TRUE;
}
return FALSE;
}
void BoolControl::DeleteTime(Interval iv, DWORD flags)
{
Interval test = TestInterval(iv,flags);
int n = keys.Count();
int d = iv.Duration()-1;
if (d<0) d = 0;
HoldTrack();
for (int i = n-1; i >= 0; i--) {
if (test.InInterval(keys[i].time)) {
keys.Delete(i,1);
} else
if (!(flags&TIME_NOSLIDE)) {
if (keys[i].time > test.End()) {
keys[i].time -= d;
}
}
}
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::ReverseTime(Interval iv, DWORD flags)
{
Interval test = TestInterval(iv,flags);
int n = keys.Count();
HoldTrack();
for (int i = 0; i < n; i++) {
if (test.InInterval(keys[i].time)) {
TimeValue delta = keys[i].time - iv.Start();
keys[i].time = iv.End()-delta;
}
}
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::ScaleTime(Interval iv, float s)
{
int n = keys.Count();
TimeValue delta = int(s*float(iv.End()-iv.Start())) + iv.Start()-iv.End();
HoldTrack();
for (int i = 0; i < n; i++) {
if (iv.InInterval(keys[i].time)) {
keys[i].time =
int(s*float(keys[i].time - iv.Start())) + iv.Start();
} else
if (keys[i].time > iv.End()) {
keys[i].time += delta;
}
}
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::InsertTime(TimeValue ins, TimeValue amount)
{
int n = keys.Count();
HoldTrack();
for (int i = 0; i < n; i++) {
if (keys[i].time >= ins) {
keys[i].time += amount;
}
}
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::DeleteKeys(DWORD flags)
{
int n = keys.Count();
HoldTrack();
for (int i = n-1; i >= 0; i--) {
if (flags&TRACK_DOALL || keys[i].flags&KEY_SELECTED) {
keys.Delete(i,1);
}
}
valid.SetEmpty();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::DeleteKeyByIndex(int index)
{
HoldTrack();
keys.Delete(index,1);
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::SelectKeyByIndex(int i,BOOL sel)
{
HoldTrack();
if (sel) keys[i].flags |= KEY_SELECTED;
else keys[i].flags &= ~KEY_SELECTED;
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::SelectKeys(TrackHitTab& sel, DWORD flags)
{
HoldTrack();
if (flags&SELKEYS_CLEARKEYS) {
int n = keys.Count();
for (int i = 0; i < n; i++ ) {
keys[i].flags &= ~KEY_SELECTED;
}
}
if (flags&SELKEYS_DESELECT) {
for (int i = 0; i < sel.Count(); i++ ) {
keys[sel[i].hit].flags &= ~KEY_SELECTED;
}
}
if (flags&SELKEYS_SELECT) {
for (int i = 0; i < sel.Count(); i++ ) {
keys[sel[i].hit].flags |= KEY_SELECTED;
}
}
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::FlagKey(TrackHitRecord hit)
{
int n = keys.Count();
for (int i = 0; i < n; i++) {
keys[i].flags &= ~KEY_FLAGGED;
}
assert(hit.hit>=0&&hit.hit<(DWORD)n);
keys[hit.hit].flags |= KEY_FLAGGED;
}
int BoolControl::GetFlagKeyIndex()
{
int n = keys.Count();
for (int i = 0; i < n; i++) {
if (keys[i].flags & KEY_FLAGGED) {
return i;
}
}
return -1;
}
int BoolControl::NumSelKeys()
{
int n = keys.Count();
int c = 0;
for ( int i = 0; i < n; i++ ) {
if (keys[i].flags & KEY_SELECTED) {
c++;
}
}
return c;
}
void BoolControl::CloneSelectedKeys(BOOL offset)
{
int n = keys.Count();
HoldTrack();
BOOL changed = FALSE;
for (int i = 0; i < n; i++) {
if (keys[i].flags & KEY_SELECTED) {
BKey key(keys[i].time);
key.flags |= KEY_SELECTED;
keys.Append(1,&key,5);
keys[i].flags &= ~KEY_SELECTED;
changed = TRUE;
}
}
if (changed) {
keys.Shrink();
valid.SetEmpty();
SortKeys();
}
}
void BoolControl::AddNewKey(TimeValue t,DWORD flags)
{
HoldTrack();
BKey key(t);
if (flags&ADDKEY_SELECT) {
key.flags |= KEY_SELECTED;
}
if (flags&ADDKEY_FLAGGED) {
int n = keys.Count();
for (int i = 0; i < n; i++) {
keys[i].flags &= ~KEY_FLAGGED;
}
key.flags |= KEY_FLAGGED;
}
keys.Append(1,&key);
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
BOOL BoolControl::IsKeySelected(int index)
{
return keys[index].flags & KEY_SELECTED;
}
TrackClipObject *BoolControl::CopyTrack(Interval iv, DWORD flags)
{
BoolClipObject *cobj = new BoolClipObject(iv);
Interval test = TestInterval(iv,flags);
for (int i = 0; i < keys.Count(); i++) {
if (test.InInterval(keys[i].time)) {
BKey nk(keys[i].time);
cobj->tab.Append(1,&nk,10);
}
}
cobj->tab.Shrink();
return cobj;
}
void BoolControl::PasteTrack(TrackClipObject *cobj,Interval iv, DWORD flags)
{
BoolClipObject *cob = (BoolClipObject*)cobj;
HoldTrack();
DeleteTime(iv,flags);
InsertTime(iv.Start(),cob->clip.Duration()-1);
for (int i = 0; i < cob->tab.Count(); i++) {
BKey key(cob->tab[i].time);
key.time -= cob->clip.Start() - iv.Start();
keys.Append(1,&key);
}
valid.SetEmpty();
SortKeys();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
int BoolControl::HitTestTrack(
TrackHitTab& hits,
Rect& rcHit,
Rect& rcTrack,
float zoom,
int scroll,
DWORD flags)
{
int left = ScreenToTime(rcTrack.left,zoom,scroll) - 4;
int right = ScreenToTime(rcTrack.right,zoom,scroll) + 4;
int n = keys.Count();
int y = (rcTrack.top+rcTrack.bottom)/2;
for ( int i = 0; i < n; i++ ) {
if (flags&HITTRACK_SELONLY &&
!(keys[i].flags & KEY_SELECTED)) continue;
if (flags&HITTRACK_UNSELONLY &&
(keys[i].flags & KEY_SELECTED)) continue;
if (keys[i].time > right) {
break;
}
if (keys[i].time > left) {
int x = TimeToScreen(keys[i].time,zoom,scroll);
if (rcHit.Contains(IPoint2(x,y))) {
TrackHitRecord rec(i,0);
hits.Append(1,&rec);
if (flags&HITTRACK_ABORTONHIT) return TRACK_DONE;
}
}
}
return TRACK_DONE;
}
int BoolControl::PaintTrack(
ParamDimensionBase *dim,
HDC hdc,
Rect& rcTrack,
Rect& rcPaint,
float zoom,
int scroll,
DWORD flags)
{
int left = ScreenToTime(rcPaint.left-8,zoom,scroll);
int right = ScreenToTime(rcPaint.right+8,zoom,scroll);
int n = keys.Count();
int y = (rcTrack.top+rcTrack.bottom)/2, lx, x = rcPaint.left-2;
HBRUSH selBrush = CreateSolidBrush(RGB(255,255,255));
HBRUSH barBrush = CreateSolidBrush(RGB(113,160,231)); //RGB(80,100,180)
HBRUSH unselBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
BOOL state = startOnOff;
SelectObject(hdc,GetStockObject(BLACK_PEN));
SelectObject(hdc,barBrush);
for (int i = 0; i < n; i++) {
lx = x;
x = TimeToScreen(keys[i].time,zoom,scroll);
if (keys[i].time > left) {
if (state) {
Rectangle(hdc,lx,y-4,x,y+4);
}
}
state = !state;
if (keys[i].time > right) {
break;
}
}
if (state) {
Rectangle(hdc,x,y-4,rcPaint.right,y+4);
}
for (i = 0; i < n; i++) {
if (keys[i].time > right) {
break;
}
if (keys[i].time > left) {
x = TimeToScreen(keys[i].time,zoom,scroll);
if ((flags&PAINTTRACK_SHOWSEL) && (keys[i].flags&KEY_SELECTED)) {
SelectObject(hdc,selBrush);
} else {
SelectObject(hdc,unselBrush);
}
Ellipse(hdc,x-4,y-5,x+4,y+5);
}
}
DeleteObject(selBrush);
DeleteObject(barBrush);
return TRACK_DONE;
}
void BoolControl::GetValue(
TimeValue t, void *val, Interval &valid, GetSetMethod method)
{
Interval wvalid = FOREVER;
float *v = (float*)val;
t = ApplyEase(t,wvalid);
if (!this->valid.InInterval(t)) {
onOff = startOnOff;
for (int i=0; i<keys.Count(); i++) {
if (keys[i].time>t) break;
onOff = !onOff;
}
if (keys.Count()) {
if (t < keys[0].time) {
this->valid.Set(TIME_NegInfinity,keys[0].time-1);
} else
if (t > keys[keys.Count()-1].time) {
this->valid.Set(keys[keys.Count()-1].time,TIME_PosInfinity);
} else this->valid.SetInstant(t);
} else {
this->valid = FOREVER;
}
}
valid &= this->valid;
*v = onOff ? 1.0f : -1.0f;
}
void BoolControl::SetValueLocalTime(
TimeValue t, void *val, int commit, GetSetMethod method)
{
float *v = (float*)val;
float tv;
GetValue(t,&tv,FOREVER);
if (MAKEBOOL(tv) == MAKEBOOL(*v)) {
return;
}
if (Animating()) {
int index = GetKeyIndex(t);
if (index>=0) {
keys.Delete(index,1);
keys.Shrink();
} else {
BKey k(t);
keys.Append(1,&k);
SortKeys();
}
} else {
if (keys.Count()) {
startOnOff = !startOnOff;
} else {
onOff = startOnOff = MAKEBOOL(*v);
}
}
valid.SetEmpty();
NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE);
}
void BoolControl::Extrapolate(
Interval range,TimeValue t,void *val,Interval &valid,int type)
{
GetValue(t,val,valid);
}
static int __cdecl CompareBKeys(const BKey *k1, const BKey *k2)
{
if (k1->time < k2->time) return -1;
if (k1->time > k2->time) return 1;
return 0;
}
void BoolControl::SortKeys()
{
keys.Sort((CompareFnc)CompareBKeys);
}
#endif