StarWindow.cpp
by Pierre Raynaud-Richard.
*/
Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
*/
#include <Application.h>
#include "StarWindow.h"
#include "Stars.h"
#include <string.h>
#include <stdlib.h>
#include <AppFileInfo.h>
#include <FindDirectory.h>
#include <Alert.h>
#include <File.h>
#include <Path.h>
#include <Debug.h>
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);
}
enum {
CRC_START = 0x56dec231,
CRC_KEY = 0x1789feb3
};
StarWindow::StarWindow(BRect frame, const char *name)
: BDirectWindow(frame, name, B_TITLED_WINDOW, 0)
{
uint32 i;
int32 x, y, dx, dy, cnt, square;
crc_alea = CRC_START;
star_count_max = 8192;
star_count = 0;
star_list = (star*)malloc(sizeof(star)*star_count_max);
for (i = 0; i < star_count_max; i++) {
do {
dx = (crc_alea&0xffff) - 0x8000;
CrcStep();
CrcStep();
dy = (crc_alea&0xffff) - 0x8000;
CrcStep();
CrcStep();
} while ((dx == 0) && (dy == 0));
square = dx*dx+dy*dy;
while (square < 0x08000000) {
dx <<= 1;
dy <<= 1;
square <<= 2;
}
star_list[i].dx0 = dx;
star_list[i].dy0 = dy;
cnt = 0;
x = 0;
y = 0;
while ((x<0x4000000) && (x>-0x4000000) && (y<0x4000000) && (y>-0x4000000)) {
x += dx;
y += dy;
dx += (dx>>4);
dy += (dy>>4);
cnt++;
}
star_list[i].count0 = cnt + ((crc_alea&0xf0000)>>16);
star_list[i].last_draw = INVALID;
star_list[i].x = 0x40000000;
star_list[i].y = 0x40000000;
star_list[i].dx = 0;
star_list[i].dy = 0;
star_list[i].count = (i&255);
}
drawing_lock = create_sem(0, "star locker");
kill_my_thread = false;
my_thread = spawn_thread(StarWindow::StarAnimation, "StarAnimation",
B_DISPLAY_PRIORITY, (void*)this);
resume_thread(my_thread);
frame.OffsetTo(0.0, 0.0);
AddShortcut('f', B_COMMAND_KEY, new BMessage('full'));
SetSizeLimits(40.0, 2000.0, 40.0, 2000.0);
if (!BDirectWindow::SupportsWindowMode()) {
bool sSwapped;
char *buf;
BAlert *quit_alert;
key_map *map;
get_key_map(&map, &buf);
if (map != NULL) {
sSwapped = (map->left_control_key == 0x5d)
&& (map->left_command_key == 0x5c);
} else
sSwapped = false;
free(map);
free(buf);
quit_alert = new BAlert("QuitAlert", sSwapped ?
"This demo runs only in full screen mode.\n"
"While running, press 'Ctrl-Q' to quit.":
"This demo runs only in full screen mode.\n"
"While running, press 'Alt-Q' to quit.",
"Quit", "Start demo", NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
if (quit_alert->Go() == 0)
((StarsApp*)be_app)->abort_required = true;
else
SetFullScreen(true);
}
}
StarWindow::~StarWindow()
{
kill_my_thread = true;
delete_sem(drawing_lock);
status_t result;
wait_for_thread(my_thread, &result);
free(star_list);
}
bool
StarWindow::QuitRequested()
{
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
}
void
StarWindow::MessageReceived(BMessage *message)
{
int8 key_code;
switch (message->what) {
case 'full':
SetFullScreen(!IsFullScreen());
break;
case B_KEY_DOWN:
if (!IsFullScreen())
break;
if (message->FindInt8("byte", &key_code) != B_OK)
break;
if (key_code == B_ESCAPE)
PostMessage(B_QUIT_REQUESTED);
break;
default:
BDirectWindow::MessageReceived(message);
break;
}
}
void
StarWindow::CrcStep()
{
crc_alea <<= 1;
if (crc_alea < 0)
crc_alea ^= CRC_KEY;
}
void
StarWindow::DirectConnected(direct_buffer_info *info)
{
switch (info->buffer_state & B_DIRECT_MODE_MASK) {
case B_DIRECT_START:
SwitchContext(info);
release_sem(drawing_lock);
break;
case B_DIRECT_STOP:
acquire_sem(drawing_lock);
break;
case B_DIRECT_MODIFY:
acquire_sem(drawing_lock);
SwitchContext(info);
release_sem(drawing_lock);
break;
default:
break;
}
}
void
StarWindow::SwitchContext(direct_buffer_info *info)
{
star *s;
int32 x, y, deltax, deltay;
uint32 i, j, window_area, cx, cy;
uint32 star_count_new;
clipping_rect *r;
window_area = (info->window_bounds.right-info->window_bounds.left+1)*
(info->window_bounds.bottom-info->window_bounds.top+1);
if (window_area > (1<<20))
window_area = (1<<20);
star_count_new = (star_count_max*(window_area>>10))>>10;
if (star_count_new > star_count_max)
star_count_new = star_count_max;
cx = (info->window_bounds.right+info->window_bounds.left+1)/2;
cy = (info->window_bounds.bottom+info->window_bounds.top+1)/2;
clipping_bound.left = info->clip_bounds.left - cx;
clipping_bound.right = info->clip_bounds.right - cx;
clipping_bound.top = info->clip_bounds.top - cy;
clipping_bound.bottom = info->clip_bounds.bottom - cy;
clipping_list_count = info->clip_list_count;
if (clipping_list_count > MAX_CLIPPING_RECT_COUNT)
clipping_list_count = MAX_CLIPPING_RECT_COUNT;
for (i=0; i<clipping_list_count; i++) {
clipping_list[i].left = info->clip_list[i].left - cx;
clipping_list[i].right = info->clip_list[i].right - cx;
clipping_list[i].top = info->clip_list[i].top - cy;
clipping_list[i].bottom = info->clip_list[i].bottom - cy;
}
row_bytes = info->bytes_per_row / (info->bits_per_pixel / 8);
draw_ptr8 = (uint8*)info->bits + info->bytes_per_row
* info->window_bounds.top + info->window_bounds.left
* (info->bits_per_pixel / 8);
draw_ptr16 = (uint16*)draw_ptr8;
draw_ptr32 = (uint32*)draw_ptr8;
if ((info->buffer_state & B_BUFFER_RESET) ||
(need_r3_buffer_reset_work_around &&
((info->buffer_state & (B_DIRECT_MODE_MASK|B_BUFFER_MOVED)) == B_DIRECT_START))) {
s = star_list;
for (i=0; i<star_count_max; i++) {
s->last_draw = INVALID;
s++;
}
}
else {
deltax = cx_old - (cx - info->window_bounds.left);
deltay = cy_old - (cy - info->window_bounds.top);
s = star_list;
for (i=0; i<star_count; i++) {
if (s->last_draw == INVALID)
goto not_defined;
x = (s->x>>16) + deltax;
y = (s->y>>16) + deltay;
if ((x < clipping_bound.left) || (x > clipping_bound.right) ||
(y < clipping_bound.top) || (y > clipping_bound.bottom))
goto invisible;
if (clipping_list_count == 1)
goto visible;
r = clipping_list;
for (j=0; j<clipping_list_count; j++) {
if ((x >= r->left) && (x <= r->right) &&
(y >= r->top) && (y <= r->bottom))
goto visible;
r++;
}
goto invisible;
visible:
if (i >= star_count_new) {
if (pixel_depth == 32)
draw_ptr32[s->last_draw] = 0;
else if (pixel_depth == 16)
draw_ptr16[s->last_draw] = 0;
else
draw_ptr8[s->last_draw] = 0;
}
goto not_defined;
invisible:
if ((info->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_MODIFY) {
if (pixel_depth == 32)
draw_ptr32[s->last_draw] = 0;
else if (pixel_depth == 16)
draw_ptr16[s->last_draw] = 0;
else
draw_ptr8[s->last_draw] = 0;
}
s->last_draw = INVALID;
not_defined:
s++;
}
s = star_list+star_count;
for (i=star_count; i<star_count_new; i++) {
s->last_draw = INVALID;
s++;
}
}
window_offset = row_bytes*(cy-info->window_bounds.top) + (cx-info->window_bounds.left);
switch (info->pixel_format) {
case B_RGBA32 :
case B_RGB32 :
pixel_depth = 32;
((uint8*)&pixel32)[0] = 0x20;
((uint8*)&pixel32)[1] = 0xff;
((uint8*)&pixel32)[2] = 0x20;
((uint8*)&pixel32)[3] = 0xff;
break;
case B_RGB16 :
pixel_depth = 16;
((uint8*)&pixel16)[0] = 0xe0;
((uint8*)&pixel16)[1] = 0x07;
break;
case B_RGB15 :
case B_RGBA15 :
pixel_depth = 16;
((uint8*)&pixel16)[0] = 0xe0;
((uint8*)&pixel16)[1] = 0x03;
break;
case B_CMAP8 :
pixel_depth = 8;
pixel8 = 52;
break;
case B_RGBA32_BIG :
case B_RGB32_BIG :
pixel_depth = 32;
((uint8*)&pixel32)[3] = 0x20;
((uint8*)&pixel32)[2] = 0xff;
((uint8*)&pixel32)[1] = 0x20;
((uint8*)&pixel32)[0] = 0xff;
break;
case B_RGB16_BIG :
pixel_depth = 16;
((uint8*)&pixel16)[1] = 0xe0;
((uint8*)&pixel16)[0] = 0x07;
break;
case B_RGB15_BIG :
case B_RGBA15_BIG :
pixel_depth = 16;
((uint8*)&pixel16)[1] = 0xe0;
((uint8*)&pixel16)[0] = 0x03;
break;
default:
fprintf(stderr, "ERROR - unsupported color space!\n");
exit(1);
break;
}
star_count = star_count_new;
cx_old = cx - info->window_bounds.left;
cy_old = cy - info->window_bounds.top;
}
status_t
StarWindow::StarAnimation(void *data)
{
star *s;
int32 x, y;
uint32 i, j;
bigtime_t time;
StarWindow *w;
clipping_rect *r;
w = (StarWindow*)data;
while (!w->kill_my_thread) {
time = system_time()+16000;
while (acquire_sem(w->drawing_lock) == B_INTERRUPTED)
;
if (w->kill_my_thread)
break;
s = w->star_list;
for (i=0; i<w->star_count; i++) {
if (s->count == 0) {
x = s->x = ((w->crc_alea&0x1f00)>>8) - 16;
y = s->y = ((w->crc_alea&0x1f0000)>>16) - 16;
s->dx = s->dx0;
s->dy = s->dy0;
s->count = s->count0 + (w->crc_alea&0x7);
w->CrcStep();
}
else {
s->count--;
x = s->x += s->dx;
y = s->y += s->dy;
s->dx += (s->dx>>4);
s->dy += (s->dy>>4);
}
if (s->last_draw != INVALID) {
if (w->pixel_depth == 32)
w->draw_ptr32[s->last_draw] = 0;
else if (w->pixel_depth == 16)
w->draw_ptr16[s->last_draw] = 0;
else
w->draw_ptr8[s->last_draw] = 0;
}
x >>= 16;
y >>= 16;
if ((x < w->clipping_bound.left) || (x > w->clipping_bound.right) ||
(y < w->clipping_bound.top) || (y > w->clipping_bound.bottom))
goto invisible;
if (w->clipping_list_count == 1) {
visible:
s->last_draw = w->window_offset + w->row_bytes*y + x;
if (w->pixel_depth == 32)
w->draw_ptr32[s->last_draw] = w->pixel32;
else if (w->pixel_depth == 16)
w->draw_ptr16[s->last_draw] = w->pixel16;
else
w->draw_ptr8[s->last_draw] = w->pixel8;
goto loop;
}
r = w->clipping_list;
for (j=0; j<w->clipping_list_count; j++) {
if ((x >= r->left) && (x <= r->right) &&
(y >= r->top) && (y <= r->bottom))
goto visible;
r++;
}
invisible:
s->last_draw = INVALID;
loop:
s++;
}
release_sem(w->drawing_lock);
time -= system_time();
if (time > 0)
snooze(time);
}
return 0;
}