#include <Application.h>
#include <WindowScreen.h>
#include <Screen.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <SupportDefs.h>
#ifdef DEBUGGING
#define PRINT(x) printf x
#else
#define PRINT(x)
#endif
#define set_pixel(x,y,color) (frame_buffer[x + (line_length*y)] = color)
#define get_pixel(x,y) (frame_buffer[x + (line_length*y)])
class NApplication : public BApplication {
public:
NApplication();
bool is_quitting;
private:
bool QuitRequested();
void ReadyToRun();
};
class NWindowScreen : public BWindowScreen {
public:
NWindowScreen(status_t*);
private:
void ScreenConnected(bool);
int32 MyCode();
static int32 Entry(void*);
void set_frame_rate(float fps) {frame_pause = (bigtime_t)((1000 * 1000)/fps);}
enum {
INVALID = 0x7fffffff
};
typedef struct {
float init_velocity;
float gravity;
double cos_z_theta;
int32 y;
int32 x;
int32 timeval;
uint32 last_draw;
int32 lx,ly;
} particle;
uint32 particle_count;
particle *particle_list;
void draw_line(int x1, int y1, int x2, int y2, int color);
void draw_rect(int x, int y, int w, int h, int color);
void fill_rect(int x, int y, int w, int h, int color);
void draw_ellipse(int cx, int cy, int wide, int deep, int color);
void fill_ellipse(int x, int y, int xradius, int yradius, int color);
void ellipse_points(int x, int y, int x_offset, int y_offset, int color);
void ellipse_fill_points(int x, int y, int x_offset, int y_offset, int color);
thread_id tid;
sem_id sem;
area_id area;
uint8* save_buffer;
uint8* frame_buffer;
ulong line_length;
bigtime_t frame_pause;
int width,height;
int COLORS;
bool thread_is_locked;
};
int
main()
{
NApplication app;
return 0;
}
NApplication::NApplication()
:BApplication("application/x-vnd.Prok-DemoTemplate")
{
Run();
}
void NApplication::ReadyToRun()
{
PRINT(("ReadyToRun()\n"));
status_t ret = B_ERROR;
is_quitting = false;
NWindowScreen *ws = new NWindowScreen(&ret);
PRINT(("WindowScreen ctor returned. ret = %s\n", strerror(ret)));
if((ws == NULL) || (ret < B_OK))
{
PostMessage(B_QUIT_REQUESTED);
}
else
PRINT(("everything's just peachy. done with ReadyToRun().\n"));
}
bool NApplication::QuitRequested()
{
PRINT(("QuitRequested()\n"));
status_t ret;
is_quitting = true;
wait_for_thread(find_thread("rendering thread"), &ret);
return true;
}
NWindowScreen::NWindowScreen(status_t *ret)
: BWindowScreen("Example", B_8_BIT_640x480, ret), width(639), height(479), COLORS(256)
{
PRINT(("WindowScreen ctor.\n"));
thread_is_locked = true;
tid = 0;
if(*ret == B_OK)
{
PRINT(("creating blocking sem and save_buffer area.\n"));
sem = create_sem(0,"WindowScreen Access");
area = create_area("save", (void**)&save_buffer, B_ANY_ADDRESS, 640*480, B_NO_LOCK, B_READ_AREA|B_WRITE_AREA);
if((sem < B_OK) || (area < B_OK))
{
PRINT(("create_area() or create_sem() failed\n"));
*ret = B_ERROR;
}
else
{
PRINT(("calling Show().\n"));
Show();
}
}
else
{
PRINT(("BWindowScreen base class ctor returned failure\n"));
be_app->PostMessage(B_QUIT_REQUESTED);
}
set_frame_rate(30.);
}
void
NWindowScreen::ScreenConnected(bool connected)
{
PRINT(("ScreenConnected()\n"));
fflush(stdout);
if(connected)
{
if(SetSpace(B_8_BIT_640x480) < B_OK)
{
PRINT(("SetSpace() failed\n"));
be_app->PostMessage(B_QUIT_REQUESTED);
return;
}
frame_buffer = (uint8*)(CardInfo()->frame_buffer);
line_length = FrameBufferInfo()->bytes_per_row;
if(tid == 0)
{
PRINT(("zeroing the framebuffer\n"));
memset(frame_buffer,0,480*line_length);
PRINT(("spawning the render thread.\n"));
tid = spawn_thread(Entry,"rendering thread", B_URGENT_DISPLAY_PRIORITY,this);
if(resume_thread(tid) < B_OK)
{
be_app->PostMessage(B_QUIT_REQUESTED);
return;
}
}
else
{
for(int y=0;y<480;y++)
{
memcpy(frame_buffer+y*line_length,save_buffer+640*y,640);
}
}
rgb_color palette[256];
rgb_color c1;
for(int i=0,j=0;i<256;i++,j++)
{
if(i<64)
{
c1.red = j*4;
c1.green = j*4;
c1.blue = j*4;
c1.alpha = 255;
}
if((i>=64) && (i<128))
{
c1.red = j*4;
c1.green = 0;
c1.blue = 0;
c1.alpha = 255;
}
if((i>=128) && (i<192))
{
c1.red = 0;
c1.green = j*4;
c1.blue = 0;
c1.alpha = 255;
}
if((i>=192) && (i<256))
{
c1.red = 0;
c1.green = 0;
c1.blue = j*4;
c1.alpha = 255;
}
if(j == 64)
j=0;
palette[i]=c1;
}
SetColorList(palette);
thread_is_locked = false;
release_sem(sem);
}
else
{
if(!thread_is_locked)
{
acquire_sem(sem);
thread_is_locked = true;
}
if((((NApplication*)be_app)->is_quitting))
{
status_t ret;
kill_thread(tid);
wait_for_thread(tid,&ret);
delete_sem(sem);
delete_area(area);
free(particle_list);
}
else
{
rgb_color c={0,0,0,255};
rgb_color palette[256];
for(int i=0;i<256;i++)
palette[i] = c;
SetColorList(palette);
for(int y=0;y<480;y++)
memcpy(save_buffer+640*y,frame_buffer+y*line_length,640);
}
}
}
int32
NWindowScreen::Entry(void* p)
{
return ((NWindowScreen*)p)->MyCode();
}
int32
NWindowScreen::MyCode()
{
bigtime_t trgt = system_time() + frame_pause;
srandom(system_time());
particle_count = 1024*2;
particle_list = (particle *)malloc(sizeof(particle)*particle_count);
for (uint32 i=0; i<particle_count; i++) {
uint32 rand_max = 0xffffffff;
particle_list[i].init_velocity = -((double)((rand_max>>1)+(random()%(rand_max>>1)))/rand_max)*3.333;
particle_list[i].gravity = -(((double)((rand_max>>1)+(random()%(rand_max>>1)))/rand_max))*0.599;
particle_list[i].lx = 0;
particle_list[i].ly = 0;
particle_list[i].last_draw = INVALID;
particle_list[i].timeval = random() & 64;
particle_list[i].x = 0;
particle_list[i].y = 0;
particle_list[i].cos_z_theta = cos(random() % 360);
}
while (!(((NApplication*)be_app)->is_quitting)) {
if (BScreen(this).WaitForRetrace() != B_OK) {
if (system_time() < trgt)
snooze(trgt - system_time());
trgt = system_time() + frame_pause;
}
acquire_sem(sem);
PRINT(("rendering a frame.\n"));
int32 x, y, cx,cy;
set_frame_rate(60.);
cx = width/2;
cy = height/2;
PRINT(("Starting particle drawing loop\n"));
particle *s = particle_list;
for (uint32 i=0; i<particle_count; i++) {
PRINT(("drawing particle %d\r", i));
s->lx = s->x;
s->ly = s->y;
PRINT(("cx=%d, cy=%d\n", cx,cy));
y = s->y = (int32)(cy + (int32)((s->gravity/2)*(s->timeval*s->timeval)*1.94) + ((s->init_velocity - (s->gravity*s->timeval)) * s->timeval));
x = s->x = (int32)(cx + (int32)(s->timeval * s->cos_z_theta));
s->timeval++;
if(x <= 0)
goto erase_and_reset;
if(x > width)
goto erase_and_reset;
if(y < 0)
goto erase;
if(y > height)
goto erase_and_reset;
if (s->last_draw != INVALID)
set_pixel(s->lx,s->ly,0);
set_pixel(s->x,s->y, 169);
s->last_draw = 1;
goto loop;
erase_and_reset:
if((s->lx <= width) && (s->lx >= 0) && (s->ly <= height) && (s->ly >= 0))
set_pixel(s->lx, s->ly,0);
s->x = 0;
s->y = 0;
s->lx = 0;
s->ly = 0;
s->timeval = 0;
s->last_draw = INVALID;
goto loop;
erase:
if(s->last_draw != INVALID)
set_pixel(s->lx, s->ly,0);
s->lx = s->x;
s->ly = s->y;
s->last_draw = INVALID;
loop:
s++;
}
PRINT(("frame done\n"));
release_sem(sem);
}
return B_OK;
}
Functions:
void draw_line(int x1, int y1, int x2, int y2, int color);
void draw_rect(int x, int y, int w, int h, int color);
void fill_rect(int x, int y, int w, int h, int color);
void draw_ellipse(int x, int y, int xradius, int yradius, int color);
void fill_ellipse(int x, int y, int xradius, int yradius, int color);
*/
void
NWindowScreen::draw_line(int x1, int y1, int x2, int y2, int color)
{
int d,x,y,ax,ay,sx,sy,dx,dy;
#define ABS(x) (((x)<0) ? -(x) : (x))
#define SGN(x) (((x)<0) ? -1 : 1)
dx=x2-x1; ax=ABS(dx)<<1; sx=SGN(dx);
dy=y2-y1; ay=ABS(dy)<<1; sy=SGN(dy);
x=x1;
y=y1;
if(ax>ay)
{
d=ay-(ax>>1);
for(;;)
{
set_pixel(x,y,color);
if(x==x2) return;
if(d>=0)
{
y+=sy;
d-=ax;
}
x+=sx;
d+=ay;
}
}
else
{
d=ax-(ay>>1);
for(;;)
{
set_pixel(x,y,color);
if(y==y2) return;
if(d>=0)
{
x+=sx;
d-=ay;
}
y+=sy;
d+=ax;
}
}
}
void
NWindowScreen::draw_rect(int x, int y, int w, int h, int color)
{
draw_line(x,y,x+w,y,color);
draw_line(x,y,x,y+h,color);
draw_line(x,y+h,x+w,y+h,color);
draw_line(x+w,y,x+w,y+h,color);
}
void
NWindowScreen::fill_rect(int x, int y, int w, int h, int color)
{
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
set_pixel(i, j, color);
}
}
}
void
NWindowScreen::draw_ellipse(int cx, int cy, int wide, int deep, int color)
{
if((wide < 1) || (deep < 1))
{
set_pixel(cx,cy,color);
return;
}
int16 x, y;
int16 wide_squared, deep_squared;
double d;
x = 0;
y = deep;
wide_squared = wide * wide;
deep_squared = deep * deep;
d = deep_squared - (wide_squared*deep) + (wide_squared/4);
ellipse_points(x, y, cx, cy, color);
while((wide_squared*(y - 0.5)) > (deep_squared*(x + 1)))
{
if(d < 0)
d += deep_squared*(2*x + 3);
else
{
d += deep_squared*(2*x + 3) + wide_squared*(-2*y + 2);
y--;
}
x++;
ellipse_points(x, y, cx, cy, color);
}
d = deep_squared*((x+0.5)*(x+0.5)) + wide_squared*((y-1)*(y-1)) - deep_squared*wide_squared;
while(y > 0)
{
if(d < 0)
{
d += deep_squared*(2*x + 2) + wide_squared*(-2*y + 3);
x++;
}
else
d += wide_squared*(-2*y + 3);
y--;
ellipse_points(x, y, cx, cy, color);
}
}
void
NWindowScreen::fill_ellipse(int cx, int cy, int wide, int deep, int color)
{
if((wide < 1) || (deep < 1))
{
set_pixel(cx,cy,color);
return;
}
int16 x, y;
int16 wide_squared, deep_squared;
double d;
x = 0;
y = deep;
wide_squared = wide * wide;
deep_squared = deep * deep;
d = deep_squared - (wide_squared*deep) + (wide_squared/4);
ellipse_fill_points(x, y, cx, cy, color);
while((wide_squared*(y - 0.5)) > (deep_squared*(x + 1)))
{
if(d < 0)
d += deep_squared*(2*x + 3);
else
{
d += deep_squared*(2*x + 3) + wide_squared*(-2*y + 2);
y--;
}
x++;
ellipse_fill_points(x, y, cx, cy, color);
}
d = deep_squared*((x+0.5)*(x+0.5)) + wide_squared*((y-1)*(y-1)) - deep_squared*wide_squared;
while(y > 0)
{
if(d < 0)
{
d += deep_squared*(2*x + 2) + wide_squared*(-2*y + 3);
x++;
}
else
d += wide_squared*(-2*y + 3);
y--;
ellipse_fill_points(x, y, cx, cy, color);
}
}
void
NWindowScreen::ellipse_points(int x, int y, int x_offset, int y_offset, int color)
{
int xCoord, yCoord;
xCoord = x_offset + x;
yCoord = y_offset + y;
if((xCoord > 0) && (yCoord > 0) && (xCoord < width) && (yCoord < height))
set_pixel(xCoord,yCoord,color);
xCoord = x_offset - x;
if((xCoord > 0) && (yCoord > 0) && (xCoord < width) && (yCoord < height))
set_pixel(xCoord,yCoord,color);
xCoord = x_offset + x;
yCoord = y_offset - y;
if((xCoord > 0) && (yCoord > 0) && (xCoord < width) && (yCoord < height))
set_pixel(xCoord,yCoord,color);
xCoord = x_offset - x;
if((xCoord > 0) && (yCoord > 0) && (xCoord < width) && (yCoord < height))
set_pixel(xCoord,yCoord,color);
}
void
NWindowScreen::ellipse_fill_points(int x, int y, int x_offset, int y_offset, int color)
{
int xCoord1, yCoord1;
int xCoord2, yCoord2;
xCoord1 = x_offset - x;
yCoord1 = y_offset + y;
xCoord2 = x_offset + x;
yCoord2 = y_offset + y;
if((xCoord1 > 0) && (yCoord1 > 0) && (xCoord1 < width) && (yCoord1 < height))
if((xCoord2 > 0) && (yCoord2 > 0) && (xCoord2 < width) && (yCoord2 < height))
draw_line(xCoord1,yCoord1,xCoord2,yCoord2,color);
xCoord1 = x_offset - x;
yCoord1 = y_offset - y;
xCoord2 = x_offset + x;
yCoord2 = y_offset - y;
if((xCoord1 > 0) && (yCoord1 > 0) && (xCoord1 < width) && (yCoord1 < height))
if((xCoord2 > 0) && (yCoord2 > 0) && (xCoord2 < width) && (yCoord2 < height))
draw_line(xCoord1,yCoord1,xCoord2,yCoord2,color);
}