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