1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      BeOS BWindow/BBitmap windowed driver.
12  *
13  *      By Angelo Mottola.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 #include "bealleg.h"
19 #include "allegro/internal/aintern.h"
20 #include "allegro/platform/aintbeos.h"
21 
22 #if !defined ALLEGRO_BEOS && !defined ALLEGRO_HAIKU
23 #error something is wrong with the makefile
24 #endif
25 
26 #define UPDATER_PERIOD      16000
27 
28 
29 static unsigned char cmap[256];
30 static char driver_desc[256] = EMPTY_STRING;
31 
32 
33 
34 /* window_updater:
35  *  Thread doing the dirty work: keeps updating dirty lines on the window.
36  */
window_updater(void * data)37 static int32 window_updater(void *data)
38 {
39    BeAllegroWindow *w = (BeAllegroWindow *)data;
40    BRect bounds, update_rect;
41    int line, start, end, h, i, j;
42    unsigned char *src, *dest;
43 
44    bounds = w->Bounds();
45 
46    h = (int)bounds.bottom + 1;
47    update_rect.left = 0;
48    update_rect.right = bounds.right;
49 
50    while (!w->dying) {
51       acquire_sem(_be_window_lock);
52       w->Lock();
53       line = 0;
54       while (line < h) {
55          while ((line < h) && (!_be_dirty_lines[line]))
56             line++;
57          if (line >= h)
58             break;
59          start = line;
60          while ((line < h) && (_be_dirty_lines[line])) {
61             _be_dirty_lines[line] = 0;
62             line++;
63          }
64          update_rect.top = start;
65          update_rect.bottom = line - 1;
66          if (_be_allegro_window->screen_depth == 8) {
67             src = (uint8 *)w->buffer->Bits() + (start * w->buffer->BytesPerRow());
68             dest = (uint8 *)w->aux_buffer->Bits() + (start * w->aux_buffer->BytesPerRow());
69             for (i=start; i<line; i++) {
70                for (j=0; j<_be_allegro_window->screen_width; j++)
71                   dest[j] = cmap[src[j]];
72                src += w->buffer->BytesPerRow();
73                dest += w->aux_buffer->BytesPerRow();
74             }
75             _be_allegro_view->DrawBitmapAsync(w->aux_buffer, update_rect, update_rect);
76          }
77          else
78             _be_allegro_view->DrawBitmapAsync(w->buffer, update_rect, update_rect);
79       }
80       _be_allegro_view->Sync();
81       w->Unlock();
82       snooze(UPDATER_PERIOD);
83    }
84 
85    return B_OK;
86 }
87 
88 
89 
90 /* be_gfx_bwindow_acquire:
91  *  Locks the screen bitmap.
92  */
be_gfx_bwindow_acquire(struct BITMAP * bmp)93 extern "C" void be_gfx_bwindow_acquire(struct BITMAP *bmp)
94 {
95    if (!(bmp->id & BMP_ID_LOCKED)) {
96       bmp->id |= BMP_ID_LOCKED;
97    }
98 }
99 
100 
101 
102 /* be_gfx_bwindow_release:
103  *  Unlocks the screen bitmap.
104  */
be_gfx_bwindow_release(struct BITMAP * bmp)105 extern "C" void be_gfx_bwindow_release(struct BITMAP *bmp)
106 {
107    if (bmp->id & BMP_ID_LOCKED) {
108       bmp->id &= ~(BMP_ID_LOCKED | BMP_ID_AUTOLOCK);
109       release_sem(_be_window_lock);
110    }
111 }
112 
113 
114 
115 #ifdef ALLEGRO_NO_ASM
116 
117 /* _be_gfx_bwindow_read_write_bank:
118  *  Returns new line and marks it as dirty.
119  */
_be_gfx_bwindow_read_write_bank(BITMAP * bmp,int line)120 extern "C" uintptr_t _be_gfx_bwindow_read_write_bank(BITMAP *bmp, int line)
121 {
122    if (!bmp->id & BMP_ID_LOCKED) {
123       bmp->id |= (BMP_ID_LOCKED | BMP_ID_AUTOLOCK);
124    }
125    _be_dirty_lines[bmp->y_ofs + line] = 1;
126    return (unsigned long)(bmp->line[line]);
127 }
128 
129 
130 
131 /* _be_gfx_bwindow_unwrite_bank:
132  *  If necessary, unlocks bitmap and makes the drawing thread
133  *  to update.
134  */
_be_gfx_bwindow_unwrite_bank(BITMAP * bmp)135 extern "C" void _be_gfx_bwindow_unwrite_bank(BITMAP *bmp)
136 {
137    if (bmp->id & BMP_ID_AUTOLOCK) {
138       bmp->id &= ~(BMP_ID_LOCKED | BMP_ID_AUTOLOCK);
139       release_sem(_be_window_lock);
140    }
141 }
142 
143 #endif
144 
145 
146 
147 /* BeAllegroWindow::BeAllegroWindow:
148  *  Constructor, creates the window and the BBitmap framebuffer,
149  *  and starts the drawing thread.
150  */
BeAllegroWindow(BRect frame,const char * title,window_look look,window_feel feel,uint32 flags,uint32 workspaces,uint32 v_w,uint32 v_h,uint32 color_depth)151 BeAllegroWindow::BeAllegroWindow(BRect frame, const char *title,
152    window_look look, window_feel feel, uint32 flags, uint32 workspaces,
153    uint32 v_w, uint32 v_h, uint32 color_depth)
154    : BWindow(frame, title, look, feel, flags, workspaces)
155 {
156    BRect rect = Bounds();
157    uint32 i;
158    color_space space = B_NO_COLOR_SPACE;
159 
160    _be_allegro_view = new BeAllegroView(rect, "Allegro",
161       B_FOLLOW_ALL_SIDES, B_WILL_DRAW, 0);
162    rgb_color color = {0, 0, 0, 0};
163    _be_allegro_view->SetViewColor(color);
164    AddChild(_be_allegro_view);
165 
166    switch (color_depth) {
167       case 8:  space = B_CMAP8; break;
168       case 15: space = B_RGB15; break;
169       case 16: space = B_RGB16; break;
170       case 32: space = B_RGB32; break;
171    }
172    buffer = new BBitmap(rect, space);
173    if (color_depth == 8)
174       aux_buffer = new BBitmap(rect, B_CMAP8);
175    else
176       aux_buffer = NULL;
177    dying = false;
178    screen_width = (int)rect.right + 1;
179    screen_height = (int)rect.bottom + 1;
180    screen_depth = color_depth;
181 
182    _be_dirty_lines = (int *)calloc(v_h, sizeof(int));
183 
184    _be_window_lock = create_sem(0, "window lock");
185 
186    drawing_thread_id = spawn_thread(window_updater, "window updater",
187       B_REAL_TIME_DISPLAY_PRIORITY, (void *)this);
188    resume_thread(drawing_thread_id);
189 }
190 
191 
192 
193 /* BeAllegroWindow::~BeAllegroWindow:
194  *  Stops the drawing thread and frees used memory.
195  */
~BeAllegroWindow()196 BeAllegroWindow::~BeAllegroWindow()
197 {
198    int32 result;
199 
200    dying = true;
201    delete_sem(_be_window_lock);
202    Unlock();
203    wait_for_thread(drawing_thread_id, &result);
204    drawing_thread_id = -1;
205    Hide();
206 
207    _be_focus_count = 0;
208 
209    if (buffer)
210       delete buffer;
211    buffer = NULL;
212    if (aux_buffer)
213       delete aux_buffer;
214    aux_buffer = NULL;
215 
216    if (_be_dirty_lines) {
217       free(_be_dirty_lines);
218       _be_dirty_lines = NULL;
219    }
220 }
221 
222 
223 
224 /* BeAllegroWindow::MessageReceived:
225  *  System messages handler.
226  */
MessageReceived(BMessage * message)227 void BeAllegroWindow::MessageReceived(BMessage *message)
228 {
229    switch (message->what) {
230       case B_SIMPLE_DATA:
231          break;
232 
233       case B_MOUSE_WHEEL_CHANGED:
234          float dy;
235          message->FindFloat("be:wheel_delta_y", &dy);
236          _be_mouse_z += ((int)dy > 0 ? -1 : 1);
237          break;
238 
239       default:
240          BWindow::MessageReceived(message);
241          break;
242    }
243 }
244 
245 
246 
247 /* BeAllegroWindow::WindowActivated:
248  *  Callback for when the window gains/looses focus.
249  */
WindowActivated(bool active)250 void BeAllegroWindow::WindowActivated(bool active)
251 {
252    _be_change_focus(active);
253    if (active) {
254       _be_allegro_window->Lock();
255       for (int i=0; i<_be_allegro_window->screen_height; i++)
256          _be_dirty_lines[i] = 1;
257       _be_allegro_window->Unlock();
258       release_sem(_be_window_lock);
259    }
260    BWindow::WindowActivated(active);
261 }
262 
263 
264 
265 /* BeAllegroWindow::QuitRequested:
266  *  User requested to close the program window.
267  */
QuitRequested(void)268 bool BeAllegroWindow::QuitRequested(void)
269 {
270     return _be_handle_window_close(Title());
271 }
272 
273 
274 
275 /* be_gfx_bwindow_init:
276  *  Initializes specified video mode.
277  */
be_gfx_bwindow_init(int w,int h,int v_w,int v_h,int color_depth)278 extern "C" struct BITMAP *be_gfx_bwindow_init(int w, int h, int v_w, int v_h, int color_depth)
279 {
280    BITMAP *bmp;
281 
282    if (1
283 #ifdef ALLEGRO_COLOR8
284        && (color_depth != 8)
285 #endif
286 #ifdef ALLEGRO_COLOR16
287        && (color_depth != 15)
288        && (color_depth != 16)
289 #endif
290 #ifdef ALLEGRO_COLOR32
291        && (color_depth != 32)
292 #endif
293        ) {
294       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported color depth"));
295       return NULL;
296    }
297 
298    if ((!v_w) && (!v_h)) {
299       v_w = w;
300       v_h = h;
301    }
302 
303    if ((w != v_w) || (h != v_h)) {
304       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported virtual resolution"));
305       return NULL;
306    }
307 
308    set_display_switch_mode(SWITCH_PAUSE);
309 
310    _be_allegro_window = new BeAllegroWindow(BRect(0, 0, w-1, h-1), wnd_title,
311 			      B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
312 			      B_NOT_RESIZABLE | B_NOT_ZOOMABLE,
313 			      B_CURRENT_WORKSPACE, v_w, v_h, color_depth);
314    _be_window = _be_allegro_window;
315    if (!_be_allegro_window->buffer->IsValid() ||
316        ((color_depth == 8) && (!_be_allegro_window->aux_buffer->IsValid()))) {
317       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
318       goto cleanup;
319    }
320 
321    _be_mouse_view = new BView(_be_allegro_window->Bounds(),
322 			     "allegro mouse view", B_FOLLOW_ALL_SIDES, 0);
323    _be_allegro_window->Lock();
324    _be_allegro_window->AddChild(_be_mouse_view);
325    _be_allegro_window->Unlock();
326 
327    _be_mouse_window = _be_allegro_window;
328    _be_mouse_window_mode = true;
329 
330    release_sem(_be_mouse_view_attached);
331 
332    _be_allegro_window->MoveTo(6, 25);
333    _be_allegro_window->Show();
334 
335    gfx_beos_bwindow.w       = w;
336    gfx_beos_bwindow.h       = h;
337    gfx_beos_bwindow.linear  = TRUE;
338    gfx_beos_bwindow.vid_mem = _be_allegro_window->buffer->BitsLength();
339 
340    bmp = _make_bitmap(v_w, v_h, (unsigned long)_be_allegro_window->buffer->Bits(),
341               &gfx_beos_bwindow, color_depth,
342 		      _be_allegro_window->buffer->BytesPerRow());
343 
344    if (!bmp) {
345       ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory"));
346       goto cleanup;
347    }
348 
349 #ifdef ALLEGRO_NO_ASM
350    bmp->read_bank = (void *)_be_gfx_bwindow_read_write_bank;
351    bmp->write_bank = (void *)_be_gfx_bwindow_read_write_bank;
352    _screen_vtable.unwrite_bank = (void *)_be_gfx_bwindow_unwrite_bank;
353 #else
354    bmp->read_bank = _be_gfx_bwindow_read_write_bank_asm;
355    bmp->write_bank = _be_gfx_bwindow_read_write_bank_asm;
356    _screen_vtable.unwrite_bank = _be_gfx_bwindow_unwrite_bank_asm;
357 #endif
358 
359    _screen_vtable.acquire = be_gfx_bwindow_acquire;
360    _screen_vtable.release = be_gfx_bwindow_release;
361 
362    _be_gfx_set_truecolor_shifts();
363 
364    uszprintf(driver_desc, sizeof(driver_desc), get_config_text("BWindow object, %d bit BBitmap framebuffer"),
365              color_depth);
366    gfx_beos_bwindow.desc = driver_desc;
367 
368    snooze(50000);
369    _be_gfx_initialized = true;
370 
371    return bmp;
372 
373 cleanup:
374    be_gfx_bwindow_exit(NULL);
375    return NULL;
376 }
377 
378 
379 
380 /* be_gfx_bwindow_exit:
381  *  Shuts down the driver.
382  */
be_gfx_bwindow_exit(struct BITMAP * bmp)383 extern "C" void be_gfx_bwindow_exit(struct BITMAP *bmp)
384 {
385    _be_gfx_initialized = false;
386 
387    if (_be_allegro_window) {
388       if (_be_mouse_view_attached < 1) {
389          acquire_sem(_be_mouse_view_attached);
390       }
391 
392       _be_allegro_window->Lock();
393       _be_allegro_window->Quit();
394 
395       _be_allegro_window = NULL;
396       _be_window = NULL;
397    }
398    _be_mouse_window   = NULL;
399    _be_mouse_view     = NULL;
400 }
401 
402 
403 
404 /* be_gfx_bwindow_set_palette:
405  *  Sets the internal color map to reflect the given palette, and
406  *  makes the drawing thread to update the window.
407  */
be_gfx_bwindow_set_palette(AL_CONST struct RGB * p,int from,int to,int vsync)408 extern "C" void be_gfx_bwindow_set_palette(AL_CONST struct RGB *p, int from, int to, int vsync)
409 {
410    int i;
411 
412    if (vsync)
413       be_gfx_vsync();
414 
415    if (_be_allegro_window->screen_depth != 8)
416       return;
417 
418    _be_allegro_window->Lock();
419    for (i=from; i<=to; i++)
420       cmap[i] = BScreen().IndexForColor(p[i].r << 2, p[i].g << 2, p[i].b << 2);
421    for (i=0; i<_be_allegro_window->screen_height; i++)
422       _be_dirty_lines[i] = 1;
423    _be_allegro_window->Unlock();
424    release_sem(_be_window_lock);
425 }
426 
427