#include "ChartWindow.h"
#include <AppFileInfo.h>
#include <Application.h>
#include <Bitmap.h>
#include <Box.h>
#include <Button.h>
#include <ByteOrder.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuField.h>
#include <MenuItem.h>
#include <Path.h>
#include <PlaySound.h>
#include <PopUpMenu.h>
#include <RadioButton.h>
#include <Screen.h>
#include <Slider.h>
#include <TextControl.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ChartWindow"
enum {
CRC_START = 0x29dec231,
CRC_KEY = 0x1789feb3
};
#define MAX_FONT_SIZE 12.0f
enum {
TOP_LEFT_LIMIT = 26,
H_BORDER = 5,
V_BORDER = 2,
ANIM_LABEL = 52,
ANIM_POPUP = 125,
DISP_LABEL = 40,
DISP_POPUP = 122,
BUTTON_WIDTH = 50,
BUTTON_OFFSET = -100,
SPACE_LABEL = 40,
SPACE_POPUP = 53,
INSTANT_LOAD = 205,
LEFT_OFFSET = 2,
STATUS_BOX = 98,
STATUS_LABEL = 13,
STATUS_EDIT = 25,
STATUS_OFFSET = 2,
BOX_H_OFFSET = 4,
BOX_V_OFFSET = 14,
FULL_SCREEN = 16,
AUTO_DEMO = 22,
SECOND_THREAD = 16,
COLORS_BOX = 146,
COLORS_LABEL = 16,
COLORS_OFFSET = 2,
COLOR_CELL = 8,
SPECIAL_BOX = 92,
SPECIAL_LABEL = 16,
SPECIAL_OFFSET = 2,
STAR_DENSITY_H = 160,
STAR_DENSITY_V = 34,
REFRESH_RATE_H = 320,
REFRESH_RATE_V = 34
};
int32 LEFT_WIDTH = 96;
enum {
STAR_DENSITY_MIN = 400,
STAR_DENSITY_MAX = 20000,
STAR_DENSITY_DEFAULT = 2000
};
#define REFRESH_RATE_MIN 0.6
#define REFRESH_RATE_MAX 600.0
#define REFRESH_RATE_DEFAULT 60.0
enum {
COLOR_BUTTON_PICT = 0,
DENSITY_BUTTON_PICT = 1,
REFRESH_BUTTON_PICT = 2
};
enum {
WINDOW_H_MIN = 220,
WINDOW_V_MIN = 146,
WINDOW_H_STD = 800,
WINDOW_V_STD = 600,
WINDOW_H_MAX = 1920,
WINDOW_V_MAX = 1440,
WINDOW_H_STEP = 224,
WINDOW_V_STEP = 168
};
enum {
STAT_DELAY = 1000000
};
#define Z_CUT_RATIO 20.0
#define DH_REF 0.8
#define DV_REF 0.6
#define abs(x) (((x)>0)?(x):-(x))
static rgb_color color_list[7] = {
{ 255, 160, 160, 255 },
{ 160, 255, 160, 255 },
{ 160, 160, 255, 255 },
{ 255, 255, 160, 255 },
{ 255, 208, 160, 255 },
{ 255, 160, 255, 255 },
{ 255, 255, 255, 255 }
};
static int32 light_gradient[8] = {
0x2000,
0x5000,
0x7800,
0x9800,
0xb800,
0xd000,
0xe800,
0x10000
};
TPoint
TPoint::operator* (const float k) const
{
TPoint v;
v.x = x*k;
v.y = y*k;
v.z = z*k;
return v;
}
TPoint
TPoint::operator- (const TPoint& v2) const
{
TPoint v;
v.x = x-v2.x;
v.y = y-v2.y;
v.z = z-v2.z;
return v;
}
TPoint TPoint::operator+ (const TPoint& v2) const {
TPoint v;
v.x = x+v2.x;
v.y = y+v2.y;
v.z = z+v2.z;
return v;
}
TPoint
TPoint::operator^ (const TPoint& v2) const
{
TPoint v;
v.x = y*v2.z - z*v2.y;
v.y = z*v2.x - x*v2.z;
v.z = x*v2.y - y*v2.x;
return v;
}
float
TPoint::Length() const
{
return sqrt(x*x + y*y + z*z);
}
TPoint
TMatrix::operator* (const TPoint& v) const
{
TPoint res;
res.x = m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z;
res.y = m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z;
res.z = m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z;
return res;
}
TPoint
TMatrix::Axis(int32 index)
{
TPoint v;
v.x = m[index][0];
v.y = m[index][1];
v.z = m[index][2];
return v;
}
TMatrix
TMatrix::Transpose() const
{
TMatrix inv;
inv.m[0][0] = m[0][0];
inv.m[0][1] = m[1][0];
inv.m[0][2] = m[2][0];
inv.m[1][0] = m[0][1];
inv.m[1][1] = m[1][1];
inv.m[1][2] = m[2][1];
inv.m[2][0] = m[0][2];
inv.m[2][1] = m[1][2];
inv.m[2][2] = m[2][2];
return inv;
}
void
TMatrix::Set(const float alpha, const float theta, const float phi)
{
float cD,sD,cI,sI,cA,sA;
cD = cos(alpha);
sD = sin(alpha);
cI = cos(theta);
sI = sin(theta);
cA = cos(phi);
sA = sin(phi);
m[0][0] = cD*cA+sD*sI*sA;
m[1][0] = -sA*cI;
m[2][0] = sD*cA-cD*sI*sA;
m[0][1] = cD*sA-sD*sI*cA;
m[1][1] = cI*cA;
m[2][1] = sD*sA+cD*cA*sI;
m[0][2] = -sD*cI;
m[1][2] = -sI;
m[2][2] = cD*cI;
}
void
LaunchSound()
{
}
status_t
get_file_version_info(directory_which dir,
char *filename, version_info *info)
{
BPath path;
BFile file;
status_t res;
BAppFileInfo appinfo;
if ((res = find_directory(dir, &path)) != B_NO_ERROR)
return res;
path.Append(filename);
file.SetTo(path.Path(), O_RDONLY);
if ((res = file.InitCheck()) != B_NO_ERROR)
return res;
if ((res = appinfo.SetTo(&file)) != B_NO_ERROR)
return res;
return appinfo.GetVersionInfo(info, B_APP_VERSION_KIND);
}
ChartWindow::ChartWindow(BRect frame, const char *name)
: BDirectWindow(frame, name, B_TITLED_WINDOW, 0)
{
float h, v, h2, v2;
int32 colors[3];
BRect r;
BMenu *menu;
BButton *button;
BCheckBox *check_box, *full_screen;
BMenuItem *item;
BMenuField *popup;
BStringView *string;
BRadioButton *radio;
BFont font;
if (font.Size() > MAX_FONT_SIZE)
font.SetSize(MAX_FONT_SIZE);
BFont boldFont(be_bold_font);
if (boldFont.Size() > MAX_FONT_SIZE)
boldFont.SetSize(MAX_FONT_SIZE);
frame.OffsetTo(0.0, 0.0);
InitPatterns();
SetSizeLimits(WINDOW_H_MIN, WINDOW_H_MAX, WINDOW_V_MIN, WINDOW_V_MAX);
SetZoomLimits(WINDOW_H_STD, WINDOW_V_STD);
fOffscreen = NULL;
fMaxWidth = WINDOW_H_STD - LEFT_WIDTH;
fMaxHeight = WINDOW_V_STD - TOP_LEFT_LIMIT;
for (int32 i = 0; i < 7; i++)
fCurrentSettings.colors[i] = false;
fCurrentSettings.colors[1] = true;
fCurrentSettings.colors[2] = true;
fCurrentSettings.colors[3] = true;
fCurrentSettings.fullscreen_mode = WINDOW_MODE;
fCurrentSettings.special = SPECIAL_NONE;
fCurrentSettings.display = DISPLAY_OFF;
fCurrentSettings.animation = ANIMATION_OFF;
fCurrentSettings.back_color.red = 0;
fCurrentSettings.back_color.green = 0;
fCurrentSettings.back_color.blue = 0;
fCurrentSettings.back_color.alpha = 255;
fCurrentSettings.star_density = STAR_DENSITY_DEFAULT;
fCurrentSettings.refresh_rate = REFRESH_RATE_DEFAULT;
BScreen screen(this);
fCurrentSettings.depth = screen.ColorSpace();
fCurrentSettings.width = (int32)frame.right+1-LEFT_WIDTH;
fCurrentSettings.height = (int32)frame.bottom+1-TOP_LEFT_LIMIT;
fPreviousFullscreenMode = WINDOW_MODE;
fNextSettings.Set(&fCurrentSettings);
fInstantLoadLevel = 0;
fSecondThreadThreshold = 0.5;
fLastDynamicDelay = 0.0;
fCrcAlea = CRC_START;
fStars.list = (star*)malloc(sizeof(star)*STAR_DENSITY_MAX);
fSpecials.list = (star*)malloc(sizeof(star)*SPECIAL_COUNT_MAX);
fSpecialList = (special*)malloc(sizeof(special)*SPECIAL_COUNT_MAX);
InitStars(SPACE_CHAOS);
fStars.count = fCurrentSettings.star_density;
fStars.erase_count = 0;
InitSpecials(SPECIAL_NONE);
fSpecials.erase_count = 0;
colors[0] = 1;
colors[1] = 2;
colors[2] = 3;
SetStarColors(colors, 3);
fCameraAlpha = 0.2;
fCameraTheta = 0.0;
fCameraPhi = 0.0;
fCamera.Set(fCameraAlpha, fCameraTheta, fCameraPhi);
fCameraInvert = fCamera.Transpose();
fOrigin.x = 0.5;
fOrigin.y = 0.5;
fOrigin.z = 0.1;
fTrackingTarget = -1;
fSpeed = 0.0115;
fTargetSpeed = fSpeed;
InitGeometry();
SetGeometry(fCurrentSettings.width, fCurrentSettings.height);
SetCubeOffset();
fDirectBuffer.buffer_width = fCurrentSettings.width;
fDirectBuffer.buffer_height = fCurrentSettings.height;
fDirectBuffer.clip_list_count = 1;
fDirectBuffer.clip_bounds.top = 0;
fDirectBuffer.clip_bounds.left = 0;
fDirectBuffer.clip_bounds.right = -1;
fDirectBuffer.clip_bounds.bottom = -1;
fDirectBuffer.clip_list[0].top = 0;
fDirectBuffer.clip_list[0].left = 0;
fDirectBuffer.clip_list[0].right = -1;
fDirectBuffer.clip_list[0].bottom = -1;
fDirectConnected = false;
r.Set(0.0, 0.0, frame.right, TOP_LEFT_LIMIT - 1);
fTopView = new BView(r, "top view", B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW);
fTopView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
AddChild(fTopView);
LEFT_WIDTH = (int32)fTopView->StringWidth(B_TRANSLATE("Full screen"))
+ 22 + H_BORDER;
if (LEFT_WIDTH < 96)
LEFT_WIDTH = 96;
h = 2;
v = V_BORDER;
r.Set(h, v, h+INSTANT_LOAD-1, v + (TOP_LEFT_LIMIT - 1 - 2*V_BORDER));
fInstantLoad = new InstantView(r);
fTopView->AddChild(fInstantLoad);
fInstantLoad->SetViewColor(0, 0, 0);
h += INSTANT_LOAD+H_BORDER;
menu = new BPopUpMenu(B_TRANSLATE("Off"));
item = new BMenuItem(B_TRANSLATE("Off"), new BMessage(ANIM_OFF_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Slow rotation"),
new BMessage(ANIM_SLOW_ROT_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Slow motion"),
new BMessage(ANIM_SLOW_MOVE_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Fast motion"),
new BMessage(ANIM_FAST_MOVE_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Free motion"),
new BMessage(ANIM_FREE_MOVE_MSG));
item->SetTarget(this);
menu->AddItem(item);
r.Set(h, v, h+ANIM_LABEL+ANIM_POPUP-1, v +
(TOP_LEFT_LIMIT - 1 - 2*V_BORDER));
popup = new BMenuField(r, "", B_TRANSLATE("Animation:"), menu);
popup->SetFont(&font);
popup->MenuBar()->SetFont(&font);
popup->Menu()->SetFont(&font);
popup->SetDivider(popup->StringWidth(popup->Label()) + 4.0f);
fTopView->AddChild(popup);
h += ANIM_LABEL + ANIM_POPUP + H_BORDER;
menu = new BPopUpMenu(B_TRANSLATE("Off"));
item = new BMenuItem(B_TRANSLATE("Off"), new BMessage(DISP_OFF_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("LineArray"),
new BMessage(DISP_LINE_MSG));
item->SetTarget(this);
item->SetEnabled(false);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("DrawBitmap"),
new BMessage(DISP_BITMAP_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("DirectWindow"),
new BMessage(DISP_DIRECT_MSG));
item->SetTarget(this);
item->SetEnabled(BDirectWindow::SupportsWindowMode());
menu->AddItem(item);
r.Set(h, v, h+DISP_LABEL+DISP_POPUP-1, v +
(TOP_LEFT_LIMIT - 1 - 2*V_BORDER));
popup = new BMenuField(r, "", B_TRANSLATE("Display:"), menu);
popup->SetFont(&font);
popup->MenuBar()->SetFont(&font);
popup->Menu()->SetFont(&font);
popup->SetDivider(popup->StringWidth(popup->Label()) + 4.0f);
fTopView->AddChild(popup);
h += DISP_LABEL + DISP_POPUP + H_BORDER;
r.Set(0, 0, BUTTON_WIDTH-1, TOP_LEFT_LIMIT - 1 - 2*V_BORDER);
fOffwindowButton = new BButton(r, "", "", NULL);
fOffwindowButton->Hide();
AddChild(fOffwindowButton);
fOffwindowButton->ResizeTo(r.Width(), r.Height());
r.Set(h, v, h+BUTTON_WIDTH-1, v + (TOP_LEFT_LIMIT - 1 - 2*V_BORDER));
fRefreshButton = new BPictureButton(r, "",
ButtonPicture(false, REFRESH_BUTTON_PICT),
ButtonPicture(true, REFRESH_BUTTON_PICT),
new BMessage(OPEN_REFRESH_MSG));
fRefreshButton->SetViewColor(B_TRANSPARENT_32_BIT);
fRefreshButton->ResizeToPreferred();
fTopView->AddChild(fRefreshButton);
h += BUTTON_WIDTH+2*H_BORDER;
r.Set(h, v, h+BUTTON_WIDTH-1, v + (TOP_LEFT_LIMIT - 1 - 2*V_BORDER));
fColorButton = new BPictureButton(r, "",
ButtonPicture(false, COLOR_BUTTON_PICT),
ButtonPicture(true, COLOR_BUTTON_PICT),
new BMessage(OPEN_COLOR_MSG));
fColorButton->SetViewColor(B_TRANSPARENT_32_BIT);
fColorButton->ResizeToPreferred();
fTopView->AddChild(fColorButton);
h += BUTTON_WIDTH+2*H_BORDER;
r.Set(h, v, h+BUTTON_WIDTH-1, v + (TOP_LEFT_LIMIT - 1 - 2*V_BORDER));
fDensityButton = new BPictureButton(r, "",
ButtonPicture(false, DENSITY_BUTTON_PICT),
ButtonPicture(true, DENSITY_BUTTON_PICT),
new BMessage(OPEN_DENSITY_MSG));
fDensityButton->SetViewColor(B_TRANSPARENT_32_BIT);
fDensityButton->ResizeToPreferred();
fTopView->AddChild(fDensityButton);
h += BUTTON_WIDTH+H_BORDER;
menu = new BPopUpMenu(B_TRANSLATE("Chaos"));
item = new BMenuItem(B_TRANSLATE("Chaos"),
new BMessage(SPACE_CHAOS_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Amas"), new BMessage(SPACE_AMAS_MSG));
item->SetTarget(this);
menu->AddItem(item);
item = new BMenuItem(B_TRANSLATE("Spiral"),
new BMessage(SPACE_SPIRAL_MSG));
item->SetTarget(this);
menu->AddItem(item);
r.Set(h, v, h+SPACE_LABEL+SPACE_POPUP-1, v +
(TOP_LEFT_LIMIT - 1 - 2*V_BORDER));
popup = new BMenuField(r, "", B_TRANSLATE("Space:"), menu);
popup->SetFont(&font);
popup->MenuBar()->SetFont(&font);
popup->Menu()->SetFont(&font);
popup->ResizeToPreferred();
popup->SetDivider(popup->StringWidth(popup->Label()) + 4.0f);
fTopView->AddChild(popup);
h += SPACE_LABEL+SPACE_POPUP+2*H_BORDER;
r.Set(0.0, TOP_LEFT_LIMIT, LEFT_WIDTH - 1, frame.bottom);
fLeftView = new BView(r, "top view", B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM, B_WILL_DRAW);
fLeftView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
AddChild(fLeftView);
h2 = LEFT_OFFSET;
v2 = LEFT_OFFSET;
h = h2;
v = v2;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2, v+STATUS_BOX-1);
fStatusBox = new BBox(r);
fStatusBox->SetFont(&boldFont);
fStatusBox->SetLabel(B_TRANSLATE("Status"));
fLeftView->AddChild(fStatusBox);
float boxWidth, boxHeight;
fStatusBox->GetPreferredSize(&boxWidth, &boxHeight);
boxWidth += r.left;
h = BOX_H_OFFSET;
v = BOX_V_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+STATUS_LABEL-1);
string = new BStringView(r, "", B_TRANSLATE("Frames/s"));
string->SetFont(&font);
string->SetAlignment(B_ALIGN_CENTER);
fStatusBox->AddChild(string);
v += STATUS_LABEL+STATUS_OFFSET;
r.Set(h-1, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET,
v+STATUS_EDIT-1);
fFramesView = new BStringView(r, "", "0.0");
fFramesView->SetAlignment(B_ALIGN_RIGHT);
fFramesView->SetFont(be_bold_font);
fFramesView->SetFontSize(24.0);
fFramesView->SetViewColor(B_TRANSPARENT_32_BIT);
fStatusBox->AddChild(fFramesView);
v += STATUS_EDIT+STATUS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+STATUS_LABEL-1);
string = new BStringView(r, "", B_TRANSLATE("CPU load"));
string->SetAlignment(B_ALIGN_CENTER);
string->SetFont(&font);
fStatusBox->AddChild(string);
v += STATUS_LABEL+STATUS_OFFSET;
r.Set(h-1, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET,
v+STATUS_EDIT-1);
fCpuLoadView = new BStringView(r, "", "0.0");
fCpuLoadView->SetAlignment(B_ALIGN_RIGHT);
fCpuLoadView->SetFont(be_bold_font);
fCpuLoadView->SetFontSize(24.0);
fCpuLoadView->SetViewColor(B_TRANSPARENT_32_BIT);
fStatusBox->AddChild(fCpuLoadView);
v2 += STATUS_BOX+LEFT_OFFSET*2;
h = h2;
v = v2;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-1, v+FULL_SCREEN-1);
full_screen = new BCheckBox(r, "", B_TRANSLATE("Full screen"),
new BMessage(FULL_SCREEN_MSG));
full_screen->SetTarget(this);
full_screen->SetFont(&font);
full_screen->ResizeToPreferred();
float width, height;
full_screen->GetPreferredSize(&width, &height);
boxWidth = max_c(width + r.left, boxWidth);
fLeftView->AddChild(full_screen);
v2 += FULL_SCREEN+LEFT_OFFSET*2;
h = h2;
v = v2;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-1, v+AUTO_DEMO-1);
button = new BButton(r, "", B_TRANSLATE("Auto demo"),
new BMessage(AUTO_DEMO_MSG));
button->SetTarget(this);
button->ResizeToPreferred();
button->GetPreferredSize(&width, &height);
boxWidth = max_c(width + r.left, boxWidth);
fLeftView->AddChild(button);
v2 += button->Frame().Height()+LEFT_OFFSET*2;
h = h2;
v = v2;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-1, v+SECOND_THREAD-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("2 threads"),
new BMessage(SECOND_THREAD_MSG));
check_box->SetTarget(this);
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fLeftView->AddChild(check_box);
v2 += SECOND_THREAD+LEFT_OFFSET*2 + 2;
h = h2;
v = v2;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2, v+COLORS_BOX-1);
fColorsBox = new BBox(r);
fColorsBox->SetLabel(B_TRANSLATE("Colors"));
fColorsBox->SetFont(&boldFont);
fLeftView->AddChild(fColorsBox);
h = BOX_H_OFFSET;
v = BOX_V_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("Red"),
new BMessage(COLORS_RED_MSG));
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fColorsBox->AddChild(check_box);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("Green"),
new BMessage(COLORS_GREEN_MSG));
check_box->SetValue(1);
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fColorsBox->AddChild(check_box);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("Blue"),
new BMessage(COLORS_BLUE_MSG));
check_box->SetValue(1);
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fColorsBox->AddChild(check_box);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("Yellow"),
new BMessage(COLORS_YELLOW_MSG));
check_box->SetValue(1);
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fColorsBox->AddChild(check_box);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("Orange"),
new BMessage(COLORS_ORANGE_MSG));
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fColorsBox->AddChild(check_box);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("Pink"),
new BMessage(COLORS_PINK_MSG));
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fColorsBox->AddChild(check_box);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
check_box = new BCheckBox(r, "", B_TRANSLATE("White"),
new BMessage(COLORS_WHITE_MSG));
check_box->SetFont(&font);
check_box->ResizeToPreferred();
fColorsBox->AddChild(check_box);
v2 += COLORS_BOX+LEFT_OFFSET*2;
h = h2;
v = v2;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2, v+SPECIAL_BOX-1);
fSpecialBox = new BBox(r);
fSpecialBox->SetFont(&boldFont);
fSpecialBox->SetLabel(B_TRANSLATE("Special"));
fLeftView->AddChild(fSpecialBox);
h = BOX_H_OFFSET;
v = BOX_V_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
radio = new BRadioButton(r, "", B_TRANSLATE("None"),
new BMessage(SPECIAL_NONE_MSG));
radio->SetValue(1);
radio->SetFont(&font);
radio->ResizeToPreferred();
fSpecialBox->AddChild(radio);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
radio = new BRadioButton(r, "", B_TRANSLATE("Comet"),
new BMessage(SPECIAL_COMET_MSG));
radio->SetFont(&font);
radio->ResizeToPreferred();
fSpecialBox->AddChild(radio);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
radio = new BRadioButton(r, "", B_TRANSLATE("Novas"),
new BMessage(SPECIAL_NOVAS_MSG));
radio->SetFont(&font);
radio->ResizeToPreferred();
fSpecialBox->AddChild(radio);
v += COLORS_LABEL+COLORS_OFFSET;
r.Set(h, v, h+LEFT_WIDTH-2*LEFT_OFFSET-2*BOX_H_OFFSET-1,
v+COLORS_LABEL-1);
radio = new BRadioButton(r, "", B_TRANSLATE("Battle"),
new BMessage(SPECIAL_BATTLE_MSG));
radio->SetEnabled(false);
radio->SetFont(&font);
radio->ResizeToPreferred();
fSpecialBox->AddChild(radio);
r.Set(LEFT_WIDTH, TOP_LEFT_LIMIT, frame.right, frame.bottom);
fChartView = new ChartView(r);
fChartView->SetViewColor(0, 0, 0);
AddChild(fChartView);
r = Bounds();
r.bottom = fSpecialBox->Frame().bottom + H_BORDER * 2 + 20;
if (r.Height() > Bounds().Height())
ResizeTo(r.Width(), r.Height());
fDrawingLock = create_sem(1, "chart locker");
fSecondThreadLock = create_sem(0, "chart second locker");
fSecondThreadRelease = create_sem(0, "chart second release");
fKillThread = false;
fAnimationThread = spawn_thread(ChartWindow::Animation, "chart animation",
B_NORMAL_PRIORITY,
(void*)this);
fSecondAnimationThread = spawn_thread(ChartWindow::Animation2, "chart animation2",
B_NORMAL_PRIORITY,
(void*)this);
resume_thread(fSecondAnimationThread);
resume_thread(fAnimationThread);
}
ChartWindow::~ChartWindow()
{
status_t result;
fKillThread = true;
wait_for_thread(fAnimationThread, &result);
wait_for_thread(fSecondAnimationThread, &result);
delete fOffscreen;
delete_sem(fDrawingLock);
delete_sem(fSecondThreadLock);
delete_sem(fSecondThreadRelease);
free(fStars.list);
free(fSpecials.list);
free(fSpecialList);
}
bool
ChartWindow::QuitRequested()
{
be_app->PostMessage(B_QUIT_REQUESTED);
return BWindow::QuitRequested();
}
void
ChartWindow::MessageReceived(BMessage *message)
{
int32 index, color;
BHandler *handler;
BCheckBox *check_box;
BSlider *slider;
message->FindPointer("source", (void**)&handler);
switch(message->what) {
case ANIM_OFF_MSG :
case ANIM_SLOW_ROT_MSG :
case ANIM_SLOW_MOVE_MSG :
case ANIM_FAST_MOVE_MSG :
case ANIM_FREE_MOVE_MSG :
fNextSettings.animation = ANIMATION_OFF + (message->what - ANIM_OFF_MSG);
break;
case DISP_OFF_MSG :
case DISP_BITMAP_MSG :
case DISP_DIRECT_MSG :
fNextSettings.display = DISPLAY_OFF + (message->what - DISP_OFF_MSG);
break;
case SPACE_CHAOS_MSG :
case SPACE_AMAS_MSG :
case SPACE_SPIRAL_MSG :
fNextSettings.space_model = SPACE_CHAOS + (message->what - SPACE_CHAOS_MSG);
break;
case FULL_SCREEN_MSG :
check_box = dynamic_cast<BCheckBox*>(handler);
if (check_box == NULL)
break;
if (check_box->Value())
fNextSettings.fullscreen_mode = FULLSCREEN_MODE;
else
fNextSettings.fullscreen_mode = WINDOW_MODE;
break;
case AUTO_DEMO_MSG :
fNextSettings.fullscreen_mode = FULLDEMO_MODE;
fNextSettings.animation = ANIMATION_FREE_MOVE;
fNextSettings.special = SPECIAL_COMET;
LaunchSound();
break;
case BACK_DEMO_MSG :
fNextSettings.fullscreen_mode = fPreviousFullscreenMode;
break;
case SECOND_THREAD_MSG :
check_box = dynamic_cast<BCheckBox*>(handler);
if (check_box == NULL)
break;
fNextSettings.second_thread = (check_box->Value()?true:false);
break;
case COLORS_RED_MSG :
case COLORS_GREEN_MSG :
case COLORS_BLUE_MSG :
case COLORS_YELLOW_MSG :
case COLORS_ORANGE_MSG :
case COLORS_PINK_MSG :
case COLORS_WHITE_MSG :
index = message->what - COLORS_RED_MSG;
check_box = dynamic_cast<BCheckBox*>(handler);
if (check_box == NULL)
break;
fNextSettings.colors[index] = (check_box->Value()?true:false);
break;
case SPECIAL_NONE_MSG :
case SPECIAL_COMET_MSG :
case SPECIAL_NOVAS_MSG :
case SPECIAL_BATTLE_MSG :
fNextSettings.special = SPECIAL_NONE + (message->what - SPECIAL_NONE_MSG);
break;
case COLOR_PALETTE_MSG :
message->FindInt32("be:value", &color);
fNextSettings.back_color.red = (color >> 24);
fNextSettings.back_color.green = (color >> 16);
fNextSettings.back_color.blue = (color >> 8);
fNextSettings.back_color.alpha = color;
break;
case STAR_DENSITY_MSG :
slider = dynamic_cast<BSlider*>(handler);
if (slider == NULL)
break;
fNextSettings.star_density = slider->Value();
break;
case REFRESH_RATE_MSG :
slider = dynamic_cast<BSlider*>(handler);
if (slider == NULL)
break;
fNextSettings.refresh_rate = exp(slider->Value()*0.001*(log(REFRESH_RATE_MAX/REFRESH_RATE_MIN)))*
REFRESH_RATE_MIN;
break;
case OPEN_COLOR_MSG :
OpenColorPalette(BPoint(200.0, 200.0));
break;
case OPEN_DENSITY_MSG :
OpenStarDensity(BPoint(280.0, 280.0));
break;
case OPEN_REFRESH_MSG :
OpenRefresh(BPoint(240.0, 340.0));
break;
default :
BDirectWindow::MessageReceived(message);
break;
}
}
void
ChartWindow::ScreenChanged(BRect screen_size, color_space depth)
{
fNextSettings.depth = BScreen(this).ColorSpace();
}
void
ChartWindow::FrameResized(float new_width, float new_height)
{
fNextSettings.width = (int32)Frame().Width()+1-LEFT_WIDTH;
fNextSettings.height = (int32)Frame().Height()+1-TOP_LEFT_LIMIT;
}
BWindow *
ChartWindow::GetAppWindow(const char *name)
{
int32 index;
BWindow *window;
for (index = 0;; index++) {
window = be_app->WindowAt(index);
if (window == NULL)
break;
if (window->LockWithTimeout(200000) == B_OK) {
if (strcmp(window->Name() + 2, name) == 0) {
window->Unlock();
break;
}
window->Unlock();
}
}
return window;
}
BPicture *
ChartWindow::ButtonPicture(bool active, int32 button_type)
{
char word[6];
int32 value;
BRect r;
BPoint delta;
BPicture *pict;
pict = new BPicture();
r = fOffwindowButton->Bounds();
fOffwindowButton->SetValue(active);
fOffwindowButton->BeginPicture(pict);
fOffwindowButton->Draw(r);
if (button_type == COLOR_BUTTON_PICT) {
r.InsetBy(6.0, 4.0);
fOffwindowButton->SetHighColor(0, 0, 0);
fOffwindowButton->StrokeRect(r);
r.InsetBy(1.0, 1.0);
fOffwindowButton->SetHighColor(fCurrentSettings.back_color);
fOffwindowButton->FillRect(r);
}
else if (button_type == DENSITY_BUTTON_PICT) {
value = (fCurrentSettings.star_density*100 + STAR_DENSITY_MAX/2) / STAR_DENSITY_MAX;
sprintf(word, "%3" B_PRId32, value);
draw_string:
fOffwindowButton->SetFont(be_bold_font);
fOffwindowButton->SetFontSize(14.0);
delta.x = BUTTON_WIDTH/2-(fOffwindowButton->StringWidth(word) * 0.5);
delta.y = (TOP_LEFT_LIMIT-2*V_BORDER)/2 + 6.0;
fOffwindowButton->DrawString(word, delta);
}
else {
sprintf(word, "%3.1f", fCurrentSettings.refresh_rate + 0.05);
goto draw_string;
}
return fOffwindowButton->EndPicture();
}
void
ChartWindow::OpenColorPalette(BPoint here)
{
BRect frame;
BPoint point;
BWindow *window = GetAppWindow(B_TRANSLATE("Space color"));
if (window == NULL) {
frame.Set(here.x, here.y, here.x + 199.0, here.y + 99.0);
window = new BWindow(frame, B_TRANSLATE("Space color"),
B_FLOATING_WINDOW_LOOK,
B_FLOATING_APP_WINDOW_FEEL,
B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK | B_NOT_RESIZABLE);
point.Set(0, 0);
BColorControl *colorControl = new ChartColorControl(point,
new BMessage(COLOR_PALETTE_MSG));
colorControl->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
colorControl->SetTarget(NULL, this);
colorControl->SetValue(fCurrentSettings.back_color);
colorControl->ResizeToPreferred();
window->ResizeTo(colorControl->Bounds().Width(), colorControl->Bounds().Height());
window->AddChild(colorControl);
window->Show();
}
window->Activate();
}
void
ChartWindow::OpenStarDensity(BPoint here)
{
BWindow *window = GetAppWindow(B_TRANSLATE("Star density"));
if (window == NULL) {
BRect frame(here.x, here.y, here.x + STAR_DENSITY_H-1,
here.y + STAR_DENSITY_V-1);
window = new BWindow(frame, B_TRANSLATE("Star density"),
B_FLOATING_WINDOW_LOOK,
B_FLOATING_APP_WINDOW_FEEL,
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK);
frame.OffsetTo(0.0, 0.0);
BSlider *slider = new BSlider(frame, "", NULL, new BMessage(STAR_DENSITY_MSG),
STAR_DENSITY_MIN, STAR_DENSITY_MAX);
slider->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
slider->SetTarget(NULL, this);
slider->SetValue(fCurrentSettings.star_density);
slider->SetModificationMessage(new BMessage(STAR_DENSITY_MSG));
slider->SetLimitLabels(B_TRANSLATE(" 5% (low)"),
B_TRANSLATE("(high) 100% "));
slider->ResizeToPreferred();
window->ResizeTo(slider->Bounds().Width(), slider->Bounds().Height());
window->AddChild(slider);
window->Show();
}
window->Activate();
}
void
ChartWindow::OpenRefresh(BPoint here)
{
BWindow *window = GetAppWindow(B_TRANSLATE("Refresh rate"));
if (window == NULL) {
BRect frame(here.x, here.y, here.x + REFRESH_RATE_H-1,
here.y + REFRESH_RATE_V-1);
window = new BWindow(frame, B_TRANSLATE("Refresh rate"),
B_FLOATING_WINDOW_LOOK,
B_FLOATING_APP_WINDOW_FEEL,
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK);
frame.OffsetTo(0.0, 0.0);
BSlider *slider = new BSlider(frame, "", NULL, new BMessage(REFRESH_RATE_MSG), 0, 1000);
slider->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
slider->SetTarget(NULL, this);
slider->SetValue((int32)(1000 * log(fCurrentSettings.refresh_rate / REFRESH_RATE_MIN) /
log(REFRESH_RATE_MAX/REFRESH_RATE_MIN)));
slider->SetModificationMessage(new BMessage(REFRESH_RATE_MSG));
slider->SetLimitLabels(B_TRANSLATE(" 0.6 f/s (logarithmic scale)"),
B_TRANSLATE("600.0 f/s"));
slider->ResizeToPreferred();
window->ResizeTo(slider->Bounds().Width(), slider->Bounds().Height());
window->AddChild(slider);
window->Show();
}
window->Activate();
}
void
ChartWindow::DrawInstantLoad(float frame_per_second)
{
int32 i;
bigtime_t timeout;
int32 level = (int32)((frame_per_second + 6.0) * (1.0/12.0));
if (level > 50)
level = 50;
if (level == fInstantLoadLevel)
return;
if (fCurrentSettings.display == DISPLAY_BITMAP)
timeout = 100000;
else
timeout = 0;
if (LockWithTimeout(timeout) != B_OK)
return;
if (level > fInstantLoadLevel) {
for (i = fInstantLoadLevel; i < level; i++) {
if (i < fInstantLoad->step)
fInstantLoad->SetHighColor(255, 90, 90);
else if ((i / fInstantLoad->step) & 1)
fInstantLoad->SetHighColor(90, 255, 90);
else
fInstantLoad->SetHighColor(40, 200, 40);
fInstantLoad->FillRect(BRect(3 + i * 4, 2, 5 + i * 4, 19));
}
}
else {
fInstantLoad->SetHighColor(0, 0, 0);
for (i = level; i < fInstantLoadLevel; i++)
fInstantLoad->FillRect(BRect(3 + i * 4, 2, 5 +i * 4, 19));
}
Flush();
fInstantLoadLevel = level;
Unlock();
}
void
ChartWindow::PrintStatNumbers(float fps)
{
char text_frames[6];
char text_cpu_load[6];
float frame_rate, load;
bigtime_t timeout;
if (fps <= fCurrentSettings.refresh_rate) {
load = 100.0;
frame_rate = fps + 0.05;
}
else {
load = (100.0*fCurrentSettings.refresh_rate)/fps + 0.05;
frame_rate = fCurrentSettings.refresh_rate + 0.05;
}
sprintf(text_cpu_load, "%3.1f", load);
sprintf(text_frames, "%3.1f", frame_rate);
if (fCurrentSettings.display == DISPLAY_BITMAP)
timeout = 100000;
else
timeout = 0;
if (LockWithTimeout(timeout) == B_OK) {
fFramesView->SetText(text_frames);
fCpuLoadView->SetText(text_cpu_load);
Unlock();
}
}
void
ChartWindow::InitGeometry()
{
float dz = sqrt(1.0 - (DH_REF*DH_REF + DV_REF*DV_REF) * (0.5 + 0.5/Z_CUT_RATIO) * (0.5 + 0.5/Z_CUT_RATIO));
fDepthRef = dz / (1.0 - 1.0/Z_CUT_RATIO);
fGeometry.z_max = fDepthRef;
fGeometry.z_min = fDepthRef/Z_CUT_RATIO;
fGeometry.z_max_square = fGeometry.z_max * fGeometry.z_max;
fGeometry.xz_max = (0.5*DH_REF)/fGeometry.z_max;
fGeometry.xz_min = -fGeometry.xz_max;
fGeometry.yz_max = (0.5*DV_REF)/fGeometry.z_max;
fGeometry.yz_min = -fGeometry.yz_max;
}
void
ChartWindow::ChangeSetting(setting new_set)
{
int32 i, color_count, old_step;
int32 color_index[7];
if (fCurrentSettings.fullscreen_mode != new_set.fullscreen_mode) {
switch (new_set.fullscreen_mode) {
case WINDOW_MODE :
fPreviousFullscreenMode = WINDOW_MODE;
ResizeTo(fPreviousFrame.Width(), fPreviousFrame.Height());
MoveTo(fPreviousFrame.left, fPreviousFrame.top);
break;
case FULLSCREEN_MODE :
{
fPreviousFullscreenMode = FULLSCREEN_MODE;
if (fCurrentSettings.fullscreen_mode == WINDOW_MODE)
fPreviousFrame = Frame();
BScreen a_screen(this);
MoveTo(a_screen.Frame().left, a_screen.Frame().top);
ResizeTo(a_screen.Frame().Width(), a_screen.Frame().Height());
}
break;
case FULLDEMO_MODE :
{
fPreviousFullscreenMode = fCurrentSettings.fullscreen_mode;
if (fCurrentSettings.fullscreen_mode == WINDOW_MODE)
fPreviousFrame = Frame();
BScreen b_screen(this);
ResizeTo(b_screen.Frame().Width() + LEFT_WIDTH, b_screen.Frame().Height() + TOP_LEFT_LIMIT);
MoveTo(b_screen.Frame().left - LEFT_WIDTH, b_screen.Frame().top - TOP_LEFT_LIMIT);
}
break;
}
}
if (fCurrentSettings.refresh_rate != new_set.refresh_rate) {
fCurrentSettings.refresh_rate = new_set.refresh_rate;
old_step = fInstantLoad->step;
fInstantLoad->step = (int32)((fCurrentSettings.refresh_rate+6.0)/12.0);
if (fInstantLoad->step < 1)
fInstantLoad->step = 1;
if (LockWithTimeout(200000) == B_OK) {
if (old_step != fInstantLoad->step)
fInstantLoad->Invalidate();
fRefreshButton->SetEnabledOff(ButtonPicture(false, REFRESH_BUTTON_PICT));
fRefreshButton->SetEnabledOn(ButtonPicture(true, REFRESH_BUTTON_PICT));
fRefreshButton->Invalidate();
Unlock();
}
if (fCurrentSettings.animation != ANIMATION_OFF)
fFrameDelay = (bigtime_t)(1000000.0/new_set.refresh_rate);
}
for (i=0; i<7; i++)
if (fCurrentSettings.colors[i] != new_set.colors[i]) {
color_count = 0;
for (i=0; i<7; i++)
if (new_set.colors[i])
color_index[color_count++] = i;
if (color_count == 0)
color_index[color_count++] = 6;
SetStarColors(color_index, color_count);
break;
}
if (new_set.special != fCurrentSettings.special)
InitSpecials(new_set.special);
if (new_set.display != fCurrentSettings.display) {
if (new_set.display == DISPLAY_BITMAP) {
CheckBitmap(new_set.depth, new_set.width, new_set.height);
SetGeometry(fBitmapBuffer.buffer_width, fBitmapBuffer.buffer_height);
SetBitmapBackGround();
fStars.erase_count = 0;
fSpecials.erase_count = 0;
}
if (new_set.display == DISPLAY_DIRECT) {
while (acquire_sem(fDrawingLock) == B_INTERRUPTED)
;
fChartView->LockLooper();
fChartView->SetHighColor(fCurrentSettings.back_color);
fChartView->FillRect(fChartView->Bounds());
fChartView->UnlockLooper();
SetGeometry(fDirectBuffer.buffer_width, fDirectBuffer.buffer_height);
RefreshClipping(&fDirectBuffer, &fStars);
RefreshClipping(&fDirectBuffer, &fSpecials);
release_sem(fDrawingLock);
}
}
if (new_set.animation != fCurrentSettings.animation) {
if (new_set.animation == ANIMATION_OFF)
fFrameDelay = 100000;
else
fFrameDelay = (bigtime_t)(1000000.0/new_set.refresh_rate);
if (new_set.animation == ANIMATION_FREE_MOVE) {
fDynamicAlpha = 0.0;
fDynamicTheta = 0.0;
fDynamicPhi = 0.0;
fCountAlpha = 0;
fCountTheta = 0;
fCountPhi = 0;
}
}
if (new_set.space_model != fCurrentSettings.space_model) {
InitStars(new_set.space_model);
InitSpecials(new_set.special);
}
if ((new_set.back_color.red != fCurrentSettings.back_color.red) ||
(new_set.back_color.green != fCurrentSettings.back_color.green) ||
(new_set.back_color.blue != fCurrentSettings.back_color.blue)) {
if (LockWithTimeout(200000) == B_OK) {
BScreen screen(this);
fCurrentSettings.back_color = new_set.back_color;
fBackColorIndex = screen.IndexForColor(new_set.back_color);
fChartView->SetViewColor(new_set.back_color);
fColorButton->SetEnabledOff(ButtonPicture(false, COLOR_BUTTON_PICT));
fColorButton->SetEnabledOn(ButtonPicture(true, COLOR_BUTTON_PICT));
fColorButton->Invalidate();
SetColorSpace(&fBitmapBuffer, fBitmapBuffer.depth);
while (acquire_sem(fDrawingLock) == B_INTERRUPTED)
;
SetColorSpace(&fDirectBuffer, fDirectBuffer.depth);
release_sem(fDrawingLock);
if (new_set.display == DISPLAY_BITMAP) {
SetBitmapBackGround();
fStars.erase_count = 0;
fSpecials.erase_count = 0;
}
else
fChartView->Invalidate();
Unlock();
}
}
if (new_set.star_density != fCurrentSettings.star_density) {
if (LockWithTimeout(200000) == B_OK) {
fCurrentSettings.star_density = new_set.star_density;
fDensityButton->SetEnabledOff(ButtonPicture(false, DENSITY_BUTTON_PICT));
fDensityButton->SetEnabledOn(ButtonPicture(true, DENSITY_BUTTON_PICT));
fDensityButton->Invalidate();
Unlock();
}
fStars.count = new_set.star_density;
}
if (new_set.depth != fCurrentSettings.depth) {
CheckBitmap(new_set.depth, new_set.width, new_set.height);
if (new_set.display == DISPLAY_BITMAP) {
SetBitmapBackGround();
fStars.erase_count = 0;
fSpecials.erase_count = 0;
}
}
if ((new_set.width != fCurrentSettings.width) || (new_set.height != fCurrentSettings.height)) {
CheckBitmap(new_set.depth, new_set.width, new_set.height);
fBitmapBuffer.buffer_width = new_set.width;
fBitmapBuffer.buffer_height = new_set.height;
if (new_set.display == DISPLAY_BITMAP)
SetGeometry(fBitmapBuffer.buffer_width, fBitmapBuffer.buffer_height);
SetBitmapClipping(new_set.width, new_set.height);
}
fCurrentSettings.Set(&new_set);
}
void
ChartWindow::InitStars(int32 space_model)
{
star *s;
int32 step;
int32 amas_select[32];
float dx, dy, dz, dist, fact, alpha, r;
float factor[8];
uint32 i, index, i_step;
TPoint amas[8];
switch (space_model) {
case SPACE_CHAOS :
FillStarList(fStars.list, STAR_DENSITY_MAX);
fKeyPointCount = 0;
break;
case SPACE_AMAS :
case SPACE_SPIRAL :
FillStarList(fStars.list, 8);
for (i=0; i<8; i++) {
amas[i].x = fStars.list[i].x;
amas[i].y = fStars.list[i].y;
amas[i].z = fStars.list[i].z;
amas_select[i] = i;
factor[i] = ((float)(fCrcAlea&2047) + 0.5)*(1.0/128.0) + 16.0/3.0;
CrcStep();
CrcStep();
}
for (i=8; i<32; i++) {
amas_select[i] = (fCrcAlea & 7);
CrcStep();
}
FillStarList(fStars.list, STAR_DENSITY_MAX);
if (space_model == SPACE_AMAS)
i_step = 1;
else
i_step = 2;
s = fStars.list;
for (i=0; i<STAR_DENSITY_MAX; i+=i_step) {
index = amas_select[i&31];
dx = s->x-amas[index].x;
if (dx < -0.5) dx += 1.0;
if (dx > 0.5) dx -= 1.0;
dy = s->y-amas[index].y;
if (dy < -0.5) dy += 1.0;
if (dy > 0.5) dy -= 1.0;
dz = s->z-amas[index].z;
if (dz < -0.5) dz += 1.0;
if (dz > 0.5) dz -= 1.0;
step = 0;
dist = (abs(dx) + abs(dy) + abs(dz))*factor[index];
while (dist > 1.0) {
dist *= 0.5;
step++;
}
step -= (fCrcAlea&3);
CrcStep();
fact = 1.0;
for (;step>=0; step--)
fact *= 0.55;
dx *= fact;
dy *= fact;
dz *= fact;
s->x = amas[index].x + dx;
if (s->x >= 1.0) s->x -= 1.0;
if (s->x <= 0.0) s->x += 1.0;
s->y = amas[index].y + dy;
if (s->y >= 1.0) s->y -= 1.0;
if (s->y <= 0.0) s->y += 1.0;
s->z = amas[index].z + dz;
if (s->z >= 1.0) s->z -= 1.0;
if (s->z <= 0.0) s->z += 1.0;
s += i_step;
}
for (i=0; i<8; i++)
fKeyPoints[i] = amas[i];
fKeyPointCount = 8;
if (space_model == SPACE_AMAS)
break;
s = fStars.list+1;
for (i=1; i<STAR_DENSITY_MAX; i+=2) {
if (fCrcAlea & 2048) {
dx = s->x - 0.5;
dy = s->y - 0.5;
dz = s->z - 0.5;
step = 0;
dist = (dx*dx + dy*dy + dz*dz) * (32.0/0.75);
while (dist > 1.0) {
dist *= 0.5;
step++;
}
step -= (fCrcAlea&3);
CrcStep();
fact = 0.5;
for (;step>=0; step--)
fact *= 0.55;
dx *= fact;
dy *= fact;
dz *= fact;
}
else {
alpha = 3.4 * s->x * (s->x*0.5 + 1.0);
if (fCrcAlea & 64)
alpha += 3.14159;
r = s->x * 0.34 + 0.08;
r += (s->y-0.725 + 0.03 * (float)(fCrcAlea & 15))*0.04*(1.2+r);
r *= 0.5;
dx = (s->z-0.8 + 0.04 * (float)(fCrcAlea & 15)) * (2.0 - abs(s->y - 0.5)) * (0.025*0.5);
dy = cos(alpha) * r;
dz = sin(alpha) * r;
}
CrcStep();
s->x = 0.5 + dx;
s->y = 0.5 + dy;
s->z = 0.5 + dz;
s += 2;
}
fKeyPoints[8].x = 0.5;
fKeyPoints[8].y = 0.5;
fKeyPoints[8].z = 0.5;
for (i=9; i<16; i++) {
fKeyPoints[i].x = fStars.list[i*(STAR_DENSITY_MAX/18)].x;
fKeyPoints[i].y = fStars.list[i*(STAR_DENSITY_MAX/18)].y;
fKeyPoints[i].z = fStars.list[i*(STAR_DENSITY_MAX/18)].z;
}
fKeyPointCount = 16;
break;
}
for (i=0; i<STAR_DENSITY_MAX; i++) {
fStars.list[i].size = (float)((fCrcAlea&15)+17)*(1.0/56.0);
if ((fCrcAlea & 0xc0) == 0)
fStars.list[i].size *= 2.0;
if ((fCrcAlea & 0x3f00) == 0)
fStars.list[i].size *= 3.0;
CrcStep();
}
}
void
ChartWindow::FillStarList(star *list, int32 count)
{
int32 i;
for (i=0; i<count; i++) {
list[i].x = ((float)(fCrcAlea&2047) + 0.5)*(1.0/2048.0);
CrcStep();
}
for (i=0; i<count; i++) {
list[i].y = ((float)(fCrcAlea&2047) + 0.5)*(1.0/2048.0);
CrcStep();
}
for (i=0; i<count; i++) {
list[i].z = ((float)(fCrcAlea&2047) + 0.5)*(1.0/2048.0);
CrcStep();
}
}
void
ChartWindow::InitSpecials(int32 code)
{
int i, j;
float alpha, ksin, kcos, coeff;
TPoint dx, dy;
TMatrix matrix;
switch (code) {
case SPECIAL_NONE :
fSpecials.count = 0;
break;
case SPECIAL_COMET :
fSpecials.count = 512;
FillStarList(fSpecials.list, 4);
for (j=0; j<2; j++) {
fComet[j].x = fSpecials.list[j].x;
fComet[j].y = fSpecials.list[j].y;
fComet[j].z = fSpecials.list[j].z;
fSpecials.list[0].size = 1.4;
matrix.Set(fSpecials.list[j+2].x * 6.28319, fSpecials.list[j+2].y * 3.14159 - 1.5708, 0.0);
fDeltaComet[j] = matrix.Axis(0) * 0.0015;
dx = matrix.Axis(1);
dy = matrix.Axis(2);
for (i=j+2; i<fSpecials.count; i+=2) {
fSpecials.list[i].x = -10.0;
fSpecials.list[i].y = 0.0;
fSpecials.list[i].z = 0.0;
fSpecialList[i].comet.count = i/2;
fSpecialList[i].comet.count0 = (fCrcAlea & 31) + 93;
CrcStep();
alpha = ((fCrcAlea>>8) & 1023) * (6.283159/1024.0);
CrcStep();
coeff = 0.000114 + 0.0000016 * (float)((fCrcAlea>>17) & 31);
if ((fCrcAlea & 7) > 4) coeff *= 0.75;
if ((fCrcAlea & 7) == 7) coeff *= 0.65;
CrcStep();
ksin = sin(alpha) * coeff;
kcos = cos(alpha) * coeff;
fSpecialList[i].comet.dx = dx.x * kcos + dy.x * ksin;
fSpecialList[i].comet.dy = dx.y * kcos + dy.y * ksin;
fSpecialList[i].comet.dz = dx.z * kcos + dy.z * ksin;
}
}
break;
case SPECIAL_NOVAS :
fSpecials.count = 96;
for (i=0; i<fSpecials.count; i++) {
fSpecialList[i].nova.count = i + 40;
fSpecialList[i].nova.count0 = (fCrcAlea & 63) + 28;
CrcStep();
fSpecials.list[i].x = fStars.list[i].x + (fCrcAlea & 1)*0.02 - 0.01;
CrcStep();
fSpecials.list[i].y = fStars.list[i].y + (fCrcAlea & 1)*0.02 - 0.01;
CrcStep();
fSpecials.list[i].z = fStars.list[i].z + (fCrcAlea & 1)*0.02 - 0.01;
CrcStep();
fSpecials.list[i].size = 0.0;
}
break;
case SPECIAL_BATTLE :
fSpecials.count = 0;
break;
}
}
void
ChartWindow::SetStarColors(int32 *color_list, int32 color_count)
{
int32 i, index;
index = 0;
for (i=0; i<STAR_DENSITY_MAX; i++) {
fStars.list[i].color_type = color_list[index];
index++;
if (index >= color_count)
index = 0;
}
for (i=0; i<SPECIAL_COUNT_MAX; i++) {
fSpecials.list[i].color_type = color_list[index];
index++;
if (index >= color_count)
index = 0;
}
}
void
ChartWindow::SetGeometry(int32 dh, int32 dv)
{
float zoom;
fGeometry.zoom_factor = (float)dh*(fDepthRef/DH_REF);
zoom = (float)dv*(fDepthRef/DV_REF);
if (zoom > fGeometry.zoom_factor)
fGeometry.zoom_factor = zoom;
fGeometry.offset_h = (float)dh * 0.5;
fGeometry.offset_v = (float)dv * 0.5;
fGeometry.zoom_factor *= 2.0;
fGeometry.offset_h = fGeometry.offset_h * 2.0 - 1.0;
fGeometry.offset_v = fGeometry.offset_v * 2.0 - 1.0;
}
void
ChartWindow::SetColorSpace(buffer *buf, color_space depth)
{
bool swap_needed;
int32 red_shift = 0, green_shift = 0;
int32 blue_shift = 0, alpha_shift = 0;
int32 step_doubling = 0;
int32 red_divide_shift = 0, green_divide_shift = 0;
int32 blue_divide_shift = 0, alpha_divide_shift = 0;
int32 i;
uint32 color;
uint32 *col;
BScreen screen(this);
rgb_color ref_color;
buf->depth = depth;
switch (depth) {
case B_RGBA32_BIG :
case B_RGB32_BIG :
case B_RGBA32 :
case B_RGB32 :
buf->depth_mode = PIXEL_4_BYTES;
buf->bytes_per_pixel = 4;
red_shift = 16;
green_shift = 8;
blue_shift = 0;
alpha_shift = 24;
red_divide_shift = 0;
green_divide_shift = 0;
blue_divide_shift = 0;
alpha_divide_shift = 0;
step_doubling = 32;
break;
case B_RGB16_BIG :
case B_RGB16 :
buf->depth_mode = PIXEL_2_BYTES;
buf->bytes_per_pixel = 2;
red_shift = 11;
red_divide_shift = 3;
green_shift = 5;
green_divide_shift = 2;
blue_shift = 0;
blue_divide_shift = 3;
alpha_shift = 32;
alpha_divide_shift = 8;
step_doubling = 16;
break;
case B_RGB15 :
case B_RGBA15 :
case B_RGB15_BIG :
case B_RGBA15_BIG :
buf->depth_mode = PIXEL_2_BYTES;
buf->bytes_per_pixel = 2;
red_shift = 10;
red_divide_shift = 3;
green_shift = 5;
green_divide_shift = 3;
blue_shift = 0;
blue_divide_shift = 3;
alpha_shift = 15;
alpha_divide_shift = 7;
step_doubling = 16;
break;
case B_CMAP8 :
default:
buf->depth_mode = PIXEL_1_BYTE;
buf->bytes_per_pixel = 1;
break;
}
switch (depth) {
case B_RGBA32_BIG :
case B_RGB32_BIG :
case B_RGB16_BIG :
case B_RGB15_BIG :
case B_RGBA15_BIG :
swap_needed = true;
break;
case B_RGBA32 :
case B_RGB32 :
case B_RGB16 :
case B_RGB15 :
case B_RGBA15 :
case B_CMAP8 :
default:
swap_needed = false;
break;
}
#if B_HOST_IS_BENDIAN
swap_needed = ~swap_needed;
#endif
col = buf->colors[0];
switch (buf->depth_mode) {
case PIXEL_1_BYTE :
for (i=0; i<7*8; i++) {
ref_color = color_list[i>>3];
ref_color.red = (ref_color.red*light_gradient[i&7])>>16;
ref_color.green = (ref_color.green*light_gradient[i&7])>>16;
ref_color.blue = (ref_color.blue*light_gradient[i&7])>>16;
color = screen.IndexForColor(ref_color);
col[i] = (color<<24) | (color<<16) | (color<<8) | color;
}
color = screen.IndexForColor(fCurrentSettings.back_color);
buf->back_color = (color<<24) | (color<<16) | (color<<8) | color;
break;
case PIXEL_2_BYTES :
case PIXEL_4_BYTES :
for (i=0; i<7*8; i++) {
ref_color = color_list[i>>3];
ref_color.red = (ref_color.red*light_gradient[i&7])>>16;
ref_color.green = (ref_color.green*light_gradient[i&7])>>16;
ref_color.blue = (ref_color.blue*light_gradient[i&7])>>16;
color = ((uint8)ref_color.red >> red_divide_shift) << red_shift;
color |= ((uint8)ref_color.green >> green_divide_shift) << green_shift;
color |= ((uint8)ref_color.blue >> blue_divide_shift) << blue_shift;
color |= ((uint8)ref_color.alpha >> alpha_divide_shift) << alpha_shift;
col[i] = (color<<step_doubling) | color;
}
color = ((uint8)fCurrentSettings.back_color.red >> red_divide_shift) << red_shift;
color |= ((uint8)fCurrentSettings.back_color.green >> green_divide_shift) << green_shift;
color |= ((uint8)fCurrentSettings.back_color.blue >> blue_divide_shift) << blue_shift;
color |= ((uint8)fCurrentSettings.back_color.alpha >> alpha_divide_shift) << alpha_shift;
buf->back_color = (color<<step_doubling) | color;
break;
}
if (swap_needed) {
col = buf->colors[0];
for (i = 0; i < 7*8; i++) {
col[i] = B_SWAP_INT32(col[i]);
}
buf->back_color = B_SWAP_INT32(buf->back_color);
}
}
void
ChartWindow::SetPatternBits(buffer *buf)
{
for (int32 i=0; i<32; i++) {
buf->pattern_bits[i] = (void*)((char*)buf->bits +
buf->bytes_per_row * pattern_dv[i] +
buf->bytes_per_pixel * pattern_dh[i]);
}
}
int32
ChartWindow::Animation(void *data)
{
int32 i, cur_4_frames_index, cur_last_fps, count_fps;
float time_factor = 0, total_fps;
float last_fps[4];
bigtime_t next_stat;
bigtime_t timer, time_left, current;
bigtime_t before_frame, after_frame, fps;
bigtime_t last_4_frames[4];
ChartWindow *w;
w = (ChartWindow*)data;
timer = system_time();
w->fFrameDelay = 100000;
next_stat = timer + STAT_DELAY;
cur_4_frames_index = 0;
cur_last_fps = 0;
for (i=0; i<4; i++)
last_fps[i] = 0.0;
total_fps = 0.0;
count_fps = 0;
while (!w->fKillThread) {
before_frame = system_time();
timer += w->fFrameDelay;
w->ChangeSetting(w->fNextSettings);
if (w->fCurrentSettings.display == DISPLAY_BITMAP) {
w->RefreshStars(&w->fBitmapBuffer, time_factor * 2.4);
if (w->LockWithTimeout(200000) == B_OK) {
w->fChartView->DrawBitmap(w->fOffscreen);
w->Unlock();
}
}
else if (w->fCurrentSettings.display == DISPLAY_DIRECT) {
while (acquire_sem(w->fDrawingLock) == B_INTERRUPTED)
;
if (w->fDirectConnected)
w->RefreshStars(&w->fDirectBuffer, time_factor * 2.4);
release_sem(w->fDrawingLock);
}
w->CameraAnimation(time_factor);
after_frame = system_time();
if (w->fCurrentSettings.display != DISPLAY_OFF) {
last_4_frames[cur_4_frames_index] = after_frame - before_frame;
cur_4_frames_index++;
if (cur_4_frames_index == 4) {
cur_4_frames_index = 0;
last_fps[cur_last_fps++ & 3] =
last_4_frames[0]+last_4_frames[1]+last_4_frames[2]+last_4_frames[3];
fps = (bigtime_t) (16e6 / (last_fps[0]+last_fps[1]+last_fps[2]+last_fps[3]));
w->DrawInstantLoad(fps);
total_fps += fps;
count_fps += 1;
if (after_frame > next_stat) {
w->PrintStatNumbers(total_fps/(float)count_fps);
next_stat = after_frame+STAT_DELAY;
total_fps = 0.0;
count_fps = 0;
}
}
}
current = system_time();
time_left = timer-current;
if (time_left > 2000) {
snooze(time_left);
time_left = 0;
}
else if (time_left < -5000)
timer = current;
time_factor = (float)(system_time() - before_frame) * (1.0/4e4);
}
return 0;
}
int32
ChartWindow::Animation2(void *data)
{
ChartWindow *w = (ChartWindow*)data;
while (!w->fKillThread) {
status_t status;
do {
status = acquire_sem_etc(w->fSecondThreadLock, 1, B_TIMEOUT, 500000);
if (w->fKillThread)
return 0;
} while (status == B_TIMED_OUT || status == B_INTERRUPTED);
bigtime_t before = system_time();
RefreshStarPacket(w->fSecondThreadBuffer, &w->fStars2, &w->fGeometry);
RefreshStarPacket(w->fSecondThreadBuffer, &w->fSpecials2, &w->fGeometry);
bigtime_t after = system_time();
w->fSecondThreadDelay = max_c(after-before, 1);
release_sem(w->fSecondThreadRelease);
}
return 0;
}
void
ChartWindow::SetCubeOffset()
{
int32 i;
TPoint min, max, dx, dy, dz, p1;
min.x = min.y = min.z = 10.0;
max.x = max.y = max.z = -10.0;
dx = fCamera.Axis(0)*(DH_REF*0.5);
dy = fCamera.Axis(1)*(DV_REF*0.5);
dz = fCamera.Axis(2)*fDepthRef;
for (i=0; i<8; i++) {
if (i&1) p1 = dz + dx;
else p1 = dz - dx;
if (i&2) p1 = p1 + dy;
else p1 = p1 - dy;
if (i&4) p1 = p1 * (1.0 / Z_CUT_RATIO);
p1 = p1 + fOrigin;
if (min.x > p1.x) min.x = p1.x;
if (min.y > p1.y) min.y = p1.y;
if (min.z > p1.z) min.z = p1.z;
if (max.x < p1.x) max.x = p1.x;
if (max.y < p1.y) max.y = p1.y;
if (max.z < p1.z) max.z = p1.z;
}
while (min.x < 0.0) {
min.x += 1.0;
max.x += 1.0;
fOrigin.x += 1.0;
}
while (min.y < 0.0) {
min.y += 1.0;
max.y += 1.0;
fOrigin.y += 1.0;
}
while (min.z < 0.0) {
min.z += 1.0;
max.z += 1.0;
fOrigin.z += 1.0;
}
while (max.x >= 2.0) {
min.x -= 1.0;
max.x -= 1.0;
fOrigin.x -= 1.0;
}
while (max.y >= 2.0) {
min.y -= 1.0;
max.y -= 1.0;
fOrigin.y -= 1.0;
}
while (max.z >= 2.0) {
min.z -= 1.0;
max.z -= 1.0;
fOrigin.z -= 1.0;
}
fCut.x = (min.x + max.x - 1.0) * 0.5;
fCut.y = (min.y + max.y - 1.0) * 0.5;
fCut.z = (min.z + max.z - 1.0) * 0.5;
SyncGeo();
}
void
ChartWindow::CameraAnimation(float time_factor)
{
TPoint move;
switch (fCurrentSettings.animation) {
case ANIMATION_ROTATE :
move = fCamera.Axis(2);
move = move * 0.45;
fOrigin = fOrigin + move;
fCameraAlpha += 0.011*time_factor;
if (fCameraAlpha > 2*3.14159)
fCameraAlpha -= 2*3.14159;
if (fCameraTheta < 0.18)
fCameraTheta += 0.003*time_factor;
if (fCameraTheta > 0.22)
fCameraTheta -= 0.003*time_factor;
if (fCameraPhi < -0.02)
fCameraPhi += 0.003*time_factor;
if (fCameraPhi > 0.02)
fCameraPhi -= 0.003*time_factor;
fCamera.Set(fCameraAlpha, fCameraTheta, fCameraPhi);
fCameraInvert = fCamera.Transpose();
move = fCamera.Axis(2);
move = move * -0.45;
fOrigin = fOrigin + move;
SetCubeOffset();
break;
case ANIMATION_SLOW_MOVE :
move = fCamera.Axis(2);
move = move * 0.006*time_factor;
fOrigin = fOrigin + move;
SetCubeOffset();
break;
case ANIMATION_FAST_MOVE :
move = fCamera.Axis(2);
move = move * 0.018*time_factor;
fOrigin = fOrigin + move;
SetCubeOffset();
break;
case ANIMATION_FREE_MOVE :
fLastDynamicDelay += time_factor;
if (fLastDynamicDelay > 0.5) {
fLastDynamicDelay -= 0.5;
if (fLastDynamicDelay > 0.2)
fLastDynamicDelay = 0.2;
if (fTrackingTarget < 0) {
if ((fCrcAlea & 0x4200) == 0) {
if (fCrcAlea & 0x8000)
fCountAlpha += 1 - (fCountAlpha/4);
else
fCountAlpha += -1 - (fCountAlpha/4);
CrcStep();
if (fCrcAlea & 0x8000)
fCountTheta += 1 - (fCountTheta/4);
else
fCountTheta += -1 - (fCountTheta/4);
CrcStep();
if (fCrcAlea & 0x8000)
fCountPhi += 1 - (fCountPhi/4);
else
fCountPhi += -1 - (fCountPhi/4);
CrcStep();
}
CrcStep();
}
else
FollowTarget();
if ((fCrcAlea & 0xf80) == 0)
SelectNewTarget();
if (fCountAlpha < 0)
fDynamicAlpha += -0.0005 - fDynamicAlpha * 0.025;
else if (fCountAlpha > 0)
fDynamicAlpha += 0.0005 - fDynamicAlpha * 0.025;
if (fCountTheta < 0)
fDynamicTheta += -0.0002 - fDynamicTheta * 0.025;
else if (fCountTheta > 0)
fDynamicTheta += 0.0002 - fDynamicTheta * 0.025;
if (fCountPhi < 0)
fDynamicPhi += -0.00025 - fDynamicPhi * 0.025;
else if (fCountPhi >0)
fDynamicPhi += 0.00025 - fDynamicPhi * 0.025;
}
fCameraAlpha += fDynamicAlpha*time_factor;
if (fCameraAlpha < 0.0)
fCameraAlpha += 2*3.14159;
else if (fCameraAlpha > 2*3.14159)
fCameraAlpha -= 2*3.14159;
fCameraTheta += fDynamicTheta*time_factor;
if (fCameraTheta < 0.0)
fCameraTheta += 2*3.14159;
else if (fCameraTheta > 2*3.14159)
fCameraTheta -= 2*3.14159;
fCameraPhi += fDynamicPhi*time_factor;
if (fCameraPhi < 0.0)
fCameraPhi += 2*3.14159;
else if (fCameraPhi > 2*3.14159)
fCameraPhi -= 2*3.14159;
fCamera.Set(fCameraAlpha, fCameraTheta, fCameraPhi);
fCameraInvert = fCamera.Transpose();
move = fCamera.Axis(2);
move = move * 0.0115*time_factor;
fOrigin = fOrigin + move;
SetCubeOffset();
break;
}
}
void
ChartWindow::SelectNewTarget()
{
float ratio, ratio_min;
float dist, lateral, axial, ftmp;
int32 i, index_min;
TPoint axis, pt, vect;
axis = fCamera.Axis(2);
ratio_min = 1e6;
index_min = -3;
for (i=-2; i<fKeyPointCount; i++) {
if (i < 0) {
if (fCurrentSettings.special == SPECIAL_COMET)
pt = fComet[i+2];
else
continue;
}
else
pt = fKeyPoints[i];
if (pt.x < fCut.x)
pt.x += 1.0;
if (pt.y < fCut.y)
pt.y += 1.0;
if (pt.z < fCut.z)
pt.z += 1.0;
pt = pt - fOrigin;
dist = pt.Length();
ftmp = 1.0/dist;
pt.x *= ftmp;
pt.y *= ftmp;
pt.z *= ftmp;
vect = pt ^ axis;
lateral = axis.Length();
axial = pt.x*axis.x + pt.y*axis.y + pt.z*axis.z;
ratio = (lateral/axial) * sqrt(dist);
if ((dist > 0.05) && (ratio < ratio_min)) {
ratio_min = ratio;
index_min = i;
}
}
fTrackingTarget = index_min+2;
}
void
ChartWindow::FollowTarget()
{
float x0, y0, x, y, z, cphi, sphi;
TPoint pt;
if (fTrackingTarget < 2)
pt = fComet[fTrackingTarget];
else
pt = fKeyPoints[fTrackingTarget-2];
if (pt.x < fCut.x)
pt.x += 1.0;
if (pt.y < fCut.y)
pt.y += 1.0;
if (pt.z < fCut.z)
pt.z += 1.0;
pt = pt - fOrigin;
x = fCameraInvert.m[0][0]*pt.x + fCameraInvert.m[1][0]*pt.y + fCameraInvert.m[2][0]*pt.z;
y = fCameraInvert.m[0][1]*pt.x + fCameraInvert.m[1][1]*pt.y + fCameraInvert.m[2][1]*pt.z;
z = fCameraInvert.m[0][2]*pt.x + fCameraInvert.m[1][2]*pt.y + fCameraInvert.m[2][2]*pt.z;
if (z <= 0.001) {
fCountAlpha = 0;
fCountTheta = -1;
fCountPhi = 0;
}
else {
cphi = cos(fCameraPhi);
sphi = sin(fCameraPhi);
x0 = x*cphi - y*sphi;
y0 = x*sphi + y*cphi;
if (abs(x0) > abs(y0)) {
if (x0 > 0)
fCountAlpha = -1;
else
fCountAlpha = 1;
fCountTheta = 0;
fCountPhi = 0;
}
else {
if (y0 > 0)
fCountTheta = -1;
else
fCountTheta = 1;
fCountAlpha = 0;
fCountPhi = 0;
}
}
}
void
ChartWindow::AnimSpecials(float time_step)
{
int i, j;
star *s;
float delta;
special *sp;
switch (fCurrentSettings.special) {
case SPECIAL_COMET :
for (j=0; j<2; j++) {
fComet[j] = fComet[j] + fDeltaComet[j] * time_step;
if (fComet[j].x < 0.0) fComet[j].x += 1.0;
else if (fComet[j].x > 1.0) fComet[j].x -= 1.0;
if (fComet[j].y < 0.0) fComet[j].y += 1.0;
else if (fComet[j].y > 1.0) fComet[j].y -= 1.0;
if (fComet[j].z < 0.0) fComet[j].z += 1.0;
else if (fComet[j].z > 1.0) fComet[j].z -= 1.0;
fSpecials.list[j].x = fComet[j].x;
fSpecials.list[j].y = fComet[j].y;
fSpecials.list[j].z = fComet[j].z;
s = fSpecials.list+j+2;
sp = fSpecialList+j+2;
for (i=j+2; i<fSpecials.count; i+=2) {
sp->comet.count -= (int32)time_step;
if (sp->comet.count <= 0.0) {
delta = (0.6 + (float)(fCrcAlea & 31) * (1.0/32.0)) * time_step;
s->x = fComet[j].x + 6.0 * sp->comet.dx - fDeltaComet[j].x * delta;
s->y = fComet[j].y + 6.0 * sp->comet.dy - fDeltaComet[j].y * delta;
s->z = fComet[j].z + 6.0 * sp->comet.dz - fDeltaComet[j].z * delta;
s->size = 0.6;
sp->comet.count = (int32)(sp->comet.count0 + (fCrcAlea & 63));
CrcStep();
}
else {
s->x += sp->comet.dx * time_step;
s->y += sp->comet.dy * time_step;
s->z += sp->comet.dz * time_step;
s->size *= (1.0 - 0.031 * time_step + 0.001 * time_step * time_step);
}
sp+=2;
s+=2;
}
}
break;
case SPECIAL_NOVAS :
sp = fSpecialList;
for (i=0; i<fSpecials.count; i++) {
sp->nova.count -= time_step;
if (sp->nova.count <= 0.0) {
fSpecials.list[i].x -= 10.0;
sp->nova.count = sp->nova.count0 + (fCrcAlea & 31);
CrcStep();
}
else if (sp->nova.count < 16.0) {
if (fSpecials.list[i].x < 0.0)
fSpecials.list[i].x += 10.0;
fSpecials.list[i].size = sp->nova.count;
}
sp++;
}
break;
case SPECIAL_BATTLE :
break;
}
}
void
ChartWindow::SyncGeo()
{
fGeometry.x = fOrigin.x;
fGeometry.y = fOrigin.y;
fGeometry.z = fOrigin.z;
fGeometry.cutx = fCut.x;
fGeometry.cuty = fCut.y;
fGeometry.cutz = fCut.z;
memcpy(fGeometry.m, fCameraInvert.m, sizeof(float)*9);
}
void
ChartWindow::RefreshStars(buffer *buf, float time_step)
{
AnimSpecials(time_step);
if (fCurrentSettings.second_thread) {
int32 star_threshold = (int32)((float)fStars.count * fSecondThreadThreshold + 0.5);
int32 special_threshold = (int32)((float)fSpecials.count * fSecondThreadThreshold + 0.5);
star_packet stars1;
stars1.list = fStars.list;
stars1.count = star_threshold;
stars1.erase_count = star_threshold;
if (stars1.erase_count > fStars.erase_count)
stars1.erase_count = fStars.erase_count;
fStars2.list = fStars.list + star_threshold;
fStars2.count = fStars.count - star_threshold;
fStars2.erase_count = fStars.erase_count - star_threshold;
if (fStars2.erase_count < 0)
fStars2.erase_count = 0;
star_packet specials1;
specials1.list = fSpecials.list;
specials1.count = special_threshold;
specials1.erase_count = special_threshold;
if (specials1.erase_count > fSpecials.erase_count)
specials1.erase_count = fSpecials.erase_count;
fSpecials2.list = fSpecials.list + special_threshold;
fSpecials2.count = fSpecials.count - special_threshold;
fSpecials2.erase_count = fSpecials.erase_count - special_threshold;
if (fSpecials2.erase_count < 0)
fSpecials2.erase_count = 0;
fSecondThreadBuffer = buf;
release_sem(fSecondThreadLock);
bigtime_t before = system_time();
RefreshStarPacket(buf, &stars1, &fGeometry);
RefreshStarPacket(buf, &specials1, &fGeometry);
bigtime_t after = system_time();
while (acquire_sem(fSecondThreadRelease) == B_INTERRUPTED)
;
float ratio = ((float)fSecondThreadDelay /
(float)max_c(after - before, 1))
* (fSecondThreadThreshold / (1.0 - fSecondThreadThreshold));
fSecondThreadThreshold = ratio / (1.0 + ratio);
} else {
RefreshStarPacket(buf, &fStars, &fGeometry);
RefreshStarPacket(buf, &fSpecials, &fGeometry);
}
fStars.erase_count = fStars.count;
fSpecials.erase_count = fSpecials.count;
}
void
ChartWindow::CheckBitmap(color_space depth, int32 width, int32 height)
{
color_space cur_depth;
if (LockWithTimeout(200000) != B_OK)
return;
if (fOffscreen == NULL)
cur_depth = B_NO_COLOR_SPACE;
else
cur_depth = fBitmapBuffer.depth;
if ((cur_depth != depth) || (width > fMaxWidth) || (height > fMaxHeight)) {
if (fOffscreen)
delete fOffscreen;
while ((width > fMaxWidth) || (height > fMaxHeight)) {
fMaxWidth += WINDOW_H_STEP;
fMaxHeight += WINDOW_V_STEP;
}
fOffscreen = new BBitmap(BRect(0, 0, fMaxWidth-1, fMaxHeight-1), depth);
if (!fOffscreen->IsValid()) {
delete fOffscreen;
fOffscreen = NULL;
fBitmapBuffer.depth = B_NO_COLOR_SPACE;
fBitmapBuffer.clip_bounds.top = 0;
fBitmapBuffer.clip_bounds.left = 0;
fBitmapBuffer.clip_bounds.right = -1;
fBitmapBuffer.clip_bounds.bottom = -1;
}
else {
fBitmapBuffer.bits = fOffscreen->Bits();
fBitmapBuffer.bytes_per_row = fOffscreen->BytesPerRow();
fBitmapBuffer.buffer_width = fCurrentSettings.width;
fBitmapBuffer.buffer_height = fCurrentSettings.height;
SetColorSpace(&fBitmapBuffer, fOffscreen->ColorSpace());
SetPatternBits(&fBitmapBuffer);
SetBitmapClipping(fCurrentSettings.width, fCurrentSettings.height);
SetBitmapBackGround();
}
}
Unlock();
}
void
ChartWindow::SetBitmapClipping(int32 width, int32 height)
{
fBitmapBuffer.clip_list_count = 1;
fBitmapBuffer.clip_bounds.top = 0;
fBitmapBuffer.clip_bounds.left = 0;
fBitmapBuffer.clip_bounds.right = width-1;
fBitmapBuffer.clip_bounds.bottom = height-1;
fBitmapBuffer.clip_list[0].top = fBitmapBuffer.clip_bounds.top;
fBitmapBuffer.clip_list[0].left = fBitmapBuffer.clip_bounds.left;
fBitmapBuffer.clip_list[0].right = fBitmapBuffer.clip_bounds.right;
fBitmapBuffer.clip_list[0].bottom = fBitmapBuffer.clip_bounds.bottom;
}
void
ChartWindow::SetBitmapBackGround()
{
int32 i, count;
uint32 *bits;
uint32 color;
bits = (uint32*)fOffscreen->Bits();
count = fOffscreen->BitsLength()/4;
color = fBitmapBuffer.back_color;
for (i=0; i<count; i++)
bits[i] = color;
}
void
ChartWindow::DirectConnected(direct_buffer_info *info)
{
while (acquire_sem(fDrawingLock) == B_INTERRUPTED)
;
SwitchContext(info);
release_sem(fDrawingLock);
}
void
ChartWindow::SwitchContext(direct_buffer_info *info)
{
uint32 i, j;
switch (info->buffer_state & B_DIRECT_MODE_MASK) {
case B_DIRECT_START :
fDirectConnected = true;
case B_DIRECT_MODIFY :
fDirectBuffer.bits = (void*)((char*)info->bits +
(info->window_bounds.top + TOP_LEFT_LIMIT) * info->bytes_per_row +
(info->window_bounds.left + LEFT_WIDTH) * (info->bits_per_pixel>>3));
fDirectBuffer.bytes_per_row = info->bytes_per_row;
SetColorSpace(&fDirectBuffer, info->pixel_format);
SetPatternBits(&fDirectBuffer);
fDirectBuffer.buffer_width =
info->window_bounds.right-info->window_bounds.left+1 - LEFT_WIDTH;
fDirectBuffer.buffer_height =
info->window_bounds.bottom-info->window_bounds.top+1 - TOP_LEFT_LIMIT;
j = 0;
for (i=0; i<info->clip_list_count; i++) {
fDirectBuffer.clip_list[j].top = info->clip_list[i].top - info->window_bounds.top;
if (fDirectBuffer.clip_list[j].top < TOP_LEFT_LIMIT)
fDirectBuffer.clip_list[j].top = TOP_LEFT_LIMIT;
fDirectBuffer.clip_list[j].left = info->clip_list[i].left - info->window_bounds.left;
if (fDirectBuffer.clip_list[j].left < LEFT_WIDTH)
fDirectBuffer.clip_list[j].left = LEFT_WIDTH;
fDirectBuffer.clip_list[j].right = info->clip_list[i].right - info->window_bounds.left;
fDirectBuffer.clip_list[j].bottom = info->clip_list[i].bottom - info->window_bounds.top;
if ((fDirectBuffer.clip_list[j].top <= fDirectBuffer.clip_list[j].bottom) &&
(fDirectBuffer.clip_list[j].left <= fDirectBuffer.clip_list[j].right)) {
fDirectBuffer.clip_list[j].top -= TOP_LEFT_LIMIT;
fDirectBuffer.clip_list[j].left -= LEFT_WIDTH;
fDirectBuffer.clip_list[j].right -= LEFT_WIDTH;
fDirectBuffer.clip_list[j].bottom -= TOP_LEFT_LIMIT;
j++;
if (j == 64)
break;
}
}
fDirectBuffer.clip_list_count = j;
fDirectBuffer.clip_bounds.top = 20000;
fDirectBuffer.clip_bounds.left = 20000;
fDirectBuffer.clip_bounds.right = -20000;
fDirectBuffer.clip_bounds.bottom = -20000;
for (i=0; i<fDirectBuffer.clip_list_count; i++) {
if (fDirectBuffer.clip_bounds.top > fDirectBuffer.clip_list[i].top)
fDirectBuffer.clip_bounds.top = fDirectBuffer.clip_list[i].top;
if (fDirectBuffer.clip_bounds.left > fDirectBuffer.clip_list[i].left)
fDirectBuffer.clip_bounds.left = fDirectBuffer.clip_list[i].left;
if (fDirectBuffer.clip_bounds.right < fDirectBuffer.clip_list[i].right)
fDirectBuffer.clip_bounds.right = fDirectBuffer.clip_list[i].right;
if (fDirectBuffer.clip_bounds.bottom < fDirectBuffer.clip_list[i].bottom)
fDirectBuffer.clip_bounds.bottom = fDirectBuffer.clip_list[i].bottom;
}
if ((fDirectBuffer.clip_bounds.top > fDirectBuffer.clip_bounds.bottom) ||
(fDirectBuffer.clip_bounds.left > fDirectBuffer.clip_bounds.right)) {
fStars.erase_count = 0;
goto nothing_visible;
}
if (fCurrentSettings.display == DISPLAY_DIRECT) {
SetGeometry(fDirectBuffer.buffer_width, fDirectBuffer.buffer_height);
if (info->buffer_state & B_BUFFER_RESET) {
fStars.erase_count = 0;
}
else if (info->buffer_state & B_CLIPPING_MODIFIED) {
RefreshClipping(&fDirectBuffer, &fStars);
RefreshClipping(&fDirectBuffer, &fSpecials);
}
}
break;
case B_DIRECT_STOP :
fDirectConnected = false;
nothing_visible:
fDirectBuffer.clip_list_count = 1;
fDirectBuffer.clip_bounds.top = 0;
fDirectBuffer.clip_bounds.left = 0;
fDirectBuffer.clip_bounds.right = -1;
fDirectBuffer.clip_bounds.bottom = -1;
fDirectBuffer.clip_list[0].top = 0;
fDirectBuffer.clip_list[0].left = 0;
fDirectBuffer.clip_list[0].right = -1;
fDirectBuffer.clip_list[0].bottom = -1;
break;
}
}
void
ChartWindow::setting::Set(setting *master)
{
memcpy(this, master, sizeof(setting));
}
void
ChartWindow::CrcStep()
{
fCrcAlea <<= 1;
if (fCrcAlea < 0)
fCrcAlea ^= CRC_KEY;
}