libs/neuronet: Implemented the new function NNet_GetMaster.
[neuro.git] / src / video / coredraw.c
blob03b2a03d8e52445a6added108b551288e150959c
1 /*
2 * libneuro, a light weight abstraction of high or lower libraries
3 * and toolkit for applications.
4 * Copyright (C) 2005-2006 Nicholas Niro, Robert Lemay
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 /* coredraw.c
22 * the core drawing algorithm.
25 /*-------------------- Extern Headers Including --------------------*/
26 #include <string.h> /* memcpy */
28 /*-------------------- Local Headers Including ---------------------*/
29 #include <global.h>
30 #include <extlib.h> /* we mainly use the blitting function and screen updating functions */
31 #include <ebuf.h> /* we mainly use the single item cleaning function Neuro_SCleanEBuf */
33 /*-------------------- Main Module Header --------------------------*/
34 #include "video.h"
35 #include <graphics.h>
38 /*-------------------- Other ----------------------------*/
40 NEURO_MODULE_CHANNEL("video/coredraw");
42 /*-------------------- Global Variables ----------------------------*/
44 /*-------------------- Static Variables ----------------------------*/
46 /*-------------------- Static Prototypes ---------------------------*/
50 /*-------------------- Static Functions ----------------------------*/
52 /* a function to resolve a bug that made the volatile objects
53 * mysteriously disapear. It was because the last element of the
54 * Dynamic object was not refreshed so if an element was just
55 * before the Dynamic object, it just made it disapear :).
57 * This function searches the element just before the input element
58 * and returns it.
60 static INSTRUCTION_ENGINE *
61 get_Previous_Object_To_Object(INSTRUCTION_ENGINE *indep)
63 INSTRUCTION_ENGINE *cur, *last = NULL;
65 cur = Graphics_GetFirstElem();
67 if (cur == NULL)
68 return NULL;
70 if (indep == cur)
71 return NULL;
73 while (cur)
76 if (cur == indep)
78 /* Debug_Val(0, "found the previous elem 0x%x, (his next 0x%x)\n",
79 last, last->next);*/
80 return last;
84 last = cur;
85 cur = cur->next;
89 return NULL;
92 /* del_mask : 0 is don't clean any buffers (big memory leak)
93 * 1 is clean only the raw engine
94 * 2 is clean only the queue(instruction) engine
95 * 3 is clean both
97 static void
98 Core_clean_object(INSTRUCTION_ENGINE *cur, int dont_redraw_section, u8 del_mask)
100 Rectan buf;
101 INSTRUCTION_ENGINE *last = NULL;
102 EBUF *verify_m;
104 /* this functions needs to destroy an element
105 * from both the instruction buffer and the raw
106 * buffer.
108 * the first step we do is fill a special Rectan
109 * rectangle with the position and size of
110 * the image. Then, we draw this position and
111 * size black on screen. After that is done, we
112 * have to redraw previous objects (if theres any).
117 if (debug_track_fonts)
119 if (cur->current->layer >= 99999)
121 TRACE(Neuro_s("Destroying font - &0x%x", cur));
125 /* Graphics_DebugQueueIntegrityCheck(); */
127 if (!cur)
128 return;
130 /* Debug_Val(0, "destroying element address 0x%x\n", cur); */
132 buf.x = cur->current->dx;
133 buf.y = cur->current->dy;
134 buf.w = cur->current->src.w;
135 buf.h = cur->current->src.h;
137 /*if (background)
138 Lib_BlitObject(background, &buf, sclScreen2, &buf);
139 else
140 Lib_FillRect(sclScreen2, &buf, 0);
143 if (dont_redraw_section == 0)
145 Lib_FillRect(Neuro_GetScreenBuffer(), &buf, 0);
147 Graphics_RedrawSection(cur);
150 if (debug_clean_instruction_buffer)
152 Neuro_CreateEBuf(&verify_m);
153 Graphics_DebugBufferQueue(verify_m);
156 if (debug_clean_instruction_buffer)
158 TRACE(Neuro_s("*initial values - Amount of elems %d",
159 Neuro_GiveEBufCount(verify_m) - 1));
160 Graphics_DebugPrintMissing(verify_m);
163 /* only set the previous element (last) if the element we need to
164 * destroy isn't the first one
166 if (cur != Graphics_GetFirstElem())
167 last = get_Previous_Object_To_Object(cur);
168 if (last)
170 /* Debug_Val(0, "changing last's(0x%x) next 0x%x to 0x%x\n", last,
171 last->next, cur->next);*/
173 last->next = cur->next;
176 /* check to see if the element cur is either first_element
177 * or last_element and if so, we will destituate it.
179 if (cur == Graphics_GetFirstElem())
181 Graphics_SetFirstElem(cur->next);
184 if (cur == Graphics_GetLastElem())
186 if (last)
188 last->next = NULL;
189 Graphics_SetLastElem(last);
191 else
192 Graphics_SetLastElem(NULL);
195 if (debug_clean_instruction_buffer)
197 TRACE("*before real destroy");
198 Graphics_DebugPrintMissing(verify_m);
201 /*if (use_memory_pool)
202 Push_Data_To_Pool(POOL_QUEUE, cur);
203 else*/
205 /* INSTRUCTION_ENGINE *temp; */
208 temp = cur;
209 cur = cur->next;
212 /* Debug_Val(0, "before queue total %d\n",
213 Neuro_GiveEBufCount(_Queue) + 1);*/
215 if (del_mask == 1 || del_mask == 3)
216 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), cur->current);
217 /* Debug_Val(0, "-- element address 0x%x destroyed\n", cur); */
218 if (del_mask == 2 || del_mask == 3)
219 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), cur);
221 /* Debug_Val(0, "after queue total %d\n",
222 Neuro_GiveEBufCount(_Queue) + 1); */
223 /* continue; */
226 if (debug_clean_instruction_buffer)
228 TRACE("**After the destroy");
229 /*Debug_Val(0, "Amount of elems in verify %d in queue %d\n",
230 Neuro_GiveEBufCount(verify_m) - 1,
231 Neuro_GiveEBufCount(_Queue) - 1);*/
232 TRACE("**Full output");
234 Graphics_DebugPrintQueue();
236 Graphics_DebugPrintMissing(verify_m);
237 Neuro_CleanEBuf(&verify_m);
240 /* Graphics_DebugQueueIntegrityCheck(); */
243 static void
244 clean_object(INSTRUCTION_ENGINE *cur, int dont_redraw_section)
246 Core_clean_object(cur, dont_redraw_section, 3);
249 /*-------------------- Global Functions ----------------------------*/
251 /* take note that we don't do any checks for valid pointers and such
252 * this function is supposed to be a backbone to an interface function
253 * which itself does the parity checks.
255 void
256 Graphics_DestroyElement(INSTRUCTION_ENGINE *elem)
258 RAW_ENGINE *tmp;
259 Rectan dst;
261 /* we destroy only the queue buffer because we want to make
262 * the emplacement of the element into a more comfortable
263 * place for the algorithm to avoid glitches.
266 tmp = elem->current;
268 /* we clean only the queue element and keep the raw engine buffer */
269 Core_clean_object(elem, 1, 2);
271 dst.x = tmp->dx;
272 dst.y = tmp->dy;
274 tmp->type = TDRAW_SDESTROY;
276 /* we put the raw buffer back into the queue */
277 Graphics_PushRaw(tmp);
280 void
281 Graphics_CoreDrawAll(void)
283 Rectan isrc, idst;
284 INSTRUCTION_ENGINE *cur, *last = NULL;
285 u32 safety = 10000; /* safety decrementor to avoid death loop */
287 if (Neuro_EBufIsEmpty(Graphics_GetQueueBuffer()))
288 return;
290 cur = Graphics_GetFirstElem();
292 /* start the real drawing */
293 while (cur)
296 if (safety <= 0)
298 ERROR("To avoid a death loop, had to bail out of the instruction loop after 1000 loops");
299 break; /* safety break */
301 else
302 safety--;
304 if (check_integrity_on_draw)
306 TRACE("Data integrity check before drawing");
307 Graphics_DebugQueueIntegrityCheck();
310 memcpy(&isrc, &cur->current->src, sizeof(Rectan));
312 idst.x = cur->current->dx;
313 idst.y = cur->current->dy;
315 if (debug_instruction_buffer)
316 TRACE(Neuro_s("%s Flushing type %d layer %d\n", __FUNCTION__, cur->current->type, cur->current->layer));
318 /* draw the surface_ptr to the screen buffer. */
319 switch (cur->current->type)
321 case TDRAW_STATIC:
324 /* Debug_Val(0, "static draw (%d,%d) %dx%d to (%d,%d)\n",
325 isrc.x, isrc.y, isrc.w, isrc.h,
326 idst.x, idst.y);
331 Lib_BlitObject(cur->current->surface_ptr, &isrc, Neuro_GetScreenBuffer(),
332 &idst);
334 cur->current->type = TDRAW_SDRAWN;
336 /* Graphics_RedrawSection(cur); */
338 /* Debug_Val(0, "drawn static\n"); */
340 if (debug_track_fonts)
342 if (cur->current->layer >= 99999)
344 TRACE(Neuro_s("Drawing font - Coord (%d,%d) &0x%x\n",
345 cur->current->dx,
346 cur->current->dy, cur));
350 break;
352 case TDRAW_SDRAWN:
354 /* nothing needed for this type */
355 /* Debug_Val(0, "already drawn\n"); */
357 break;
359 case TDRAW_SREDRAW:
361 /* Debug_Val(0, "address of surface 0x%x\n", cur->current->surface_ptr); */
363 /* now we redraw the actual element */
364 Lib_BlitObject(cur->current->surface_ptr, &isrc, Neuro_GetScreenBuffer(),
365 &idst);
367 /* we cleanly redrawn the static element so we
368 * set the element's flag to drawn
370 cur->current->type = TDRAW_SDRAWN;
372 /* then we redraw the stuff that could have been
373 * there and actually need to be visible(and are above
374 * our element, ie layers).
376 * broken for some reason
378 TRACE("Pushed a SRedraw and flagged for redrawing");
379 Graphics_RedrawSection(cur);
381 /* Debug_Val(0, "Redrawn a static element\n"); */
383 break;
385 case TDRAW_SDESTROY:
387 INSTRUCTION_ENGINE *tmp;
389 if (cur->current->layer > 1000)
390 Debug_Print("Cleaned a static image");
393 tmp = cur;
395 cur = cur->next;
397 clean_object(tmp, 0);
399 /* we restart the loop completely since we need to draw
400 * the volatile types first before drawing the rest..
402 cur = Graphics_GetFirstElem();
404 if (cur)
405 continue;
407 break;
409 case TDRAW_DYNAMIC:
411 Lib_BlitObject(cur->current->surface_ptr, &isrc,
412 Neuro_GetScreenBuffer(), &idst);
414 cur->current->type = TDRAW_DYNAMIC_CLEAN;
416 if (dynamic_debug)
417 TRACE(Neuro_s("Dynamic : Tagging addr %x to clean", cur));
418 /* Debug_Val(0, "drawn dynamic\n"); */
420 break;
422 #if temp
423 case TDRAW_DYNAMIC_CLEAN:
425 /* Lib_BlitObject(cur->current->surface_ptr, &isrc,
426 sclScreen2, &idst);*/
428 /* clean_object(cur); */
430 break;
431 #endif /* temp */
433 case TDRAW_VOLATILE:
435 /*Debug_Val(0, "Volatile draw (%d,%d) %dx%d to (%d,%d) image 0x%x\n",
436 isrc.x, isrc.y, isrc.w, isrc.h,
437 idst.x, idst.y,
438 cur->current->surface_ptr);
441 Lib_BlitObject(cur->current->surface_ptr, &isrc,
442 Neuro_GetScreenBuffer(), &idst);
444 /* NOTE that we CAN't USE clean_object() BECAUSE
445 * it actually makes the image all BLACK
446 * so it nullifies the action of this COMPLETELY.
448 if (last)
449 last->next = cur->next;
451 /* check to see if the element cur is either first_element
452 * or last_element and if so, we will destituate it.
454 if (cur == Graphics_GetFirstElem())
456 Graphics_SetFirstElem(cur->next);
459 if (cur == Graphics_GetLastElem())
461 if (last)
463 last->next = NULL;
464 Graphics_SetLastElem(last);
469 /*if (use_memory_pool)
470 Push_Data_To_Pool(POOL_QUEUE, cur);
471 else*/
473 INSTRUCTION_ENGINE *temp;
475 temp = cur;
476 cur = cur->next;
478 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), temp->current);
479 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), temp);
481 if (cur)
482 continue;
485 break;
488 default:
490 ERROR(Neuro_s("Draw unknown type %d\n", cur->current->type));
492 break;
495 if (cur)
497 last = cur;
498 if (cur->next == NULL && cur != Graphics_GetLastElem())
500 ERROR("cur->next is NULL AND it isn't the last element, bad, very bad...");
502 cur = cur->next;
504 else
505 break;
509 Graphics_SetDrawnLastCycle();
510 /* Lib_FillRect(sclScreen, &test_BoundFix, 0); */
513 void
514 Graphics_SetAllToRedraw(void)
516 INSTRUCTION_ENGINE *cur;
518 cur = Graphics_GetFirstElem();
520 if (cur == NULL)
521 return;
523 while (cur)
525 if (cur->current->type == TDRAW_SDRAWN)
526 cur->current->type = TDRAW_STATIC; /* TDRAW_SREDRAW seems to do a flaw */
528 cur = cur->next;
531 if (debug_instruction_buffer)
532 TRACE("Just Set all the instructions to be redrawn");
535 /* Graphics_CoreCleanAll might have cleaned objects
536 * that should be drawn so we will redraw those in this
537 * function.
538 * returns non zero if a volatile type was pushed
541 Graphics_RedrawSection(INSTRUCTION_ENGINE *indep)
543 Rectan buf, indep_body;
544 INSTRUCTION_ENGINE *cur;
545 int bounds_ret = 0;
546 int output = 0;
548 TRACE("Redrawing Section");
550 indep_body.x = indep->current->dx;
551 indep_body.y = indep->current->dy;
552 indep_body.w = indep->current->src.w;
553 indep_body.h = indep->current->src.h;
555 cur = Graphics_GetFirstElem();
557 if (cur == NULL)
558 return 0;
560 while (cur)
563 if (cur == indep)
565 cur = cur->next;
566 continue;
569 if (!cur->current)
571 ERROR(Neuro_s("BAD : the instruction 0x%x has an empty content! indep 0x%x its next element 0x%x",
572 cur, indep, indep->next));
573 /* odd error, this ain't supposed to happen :L */
574 return 0;
577 if (debug_track_fonts)
579 if (cur->current->layer >= 99999 && indep->current->layer >= 99999)
581 TRACE(Neuro_s("INITIAL Redrawing font -- Font type %d (%d,%d) &0x%x\n", cur->current->type,
582 buf.x, buf.y, cur));
586 if (cur->current->type == TDRAW_SDRAWN)
589 buf.x = cur->current->dx;
590 buf.y = cur->current->dy;
591 buf.w = cur->current->src.w;
592 buf.h = cur->current->src.h;
594 bounds_ret = Neuro_BoundsCheck(&indep_body, &buf);
595 /* bounds_ret = 2; */
597 if (debug_track_fonts)
599 if (cur->current->layer >= 99999 && indep->current->layer >= 99999)
601 TRACE(Neuro_s("INITIAL 2 Redrawing font -- bounds_ret %d current (%d,%d) indep (%d,%d)\n",
602 bounds_ret,
603 buf.x, buf.y,
604 indep_body.x, indep_body.y));
608 if (bounds_ret == 0)
610 Rectan bufa;
612 bufa.x = cur->current->dx;
613 bufa.y = cur->current->dy;
614 bufa.w = 0;
615 bufa.h = 0;
617 Graphics_AddDrawingInstruction(cur->current->layer, TDRAW_VOLATILE, &cur->current->src,
618 &bufa, cur->current->surface_ptr);
620 /*Debug_Val(0, "dynamic is inside this object\n");*/
622 if (debug_track_fonts)
624 if (cur->current->layer >= 99999)
625 TRACE("Redrawing font #0");
628 output = 1;
631 if (bounds_ret == 2)
633 Rectan isrc, idst;
635 memcpy(&isrc, &cur->current->src, sizeof(Rectan));
637 idst.x = cur->current->dx;
638 idst.y = cur->current->dy;
639 idst.w = 0;
640 idst.h = 0;
642 Neuro_VerticalBoundCrop(&indep_body, &isrc, &idst);
643 Neuro_HorizontalBoundCrop(&indep_body, &isrc, &idst);
645 Graphics_AddDrawingInstruction(cur->current->layer, TDRAW_VOLATILE,
646 &isrc, &idst, cur->current->surface_ptr);
648 if (debug_track_fonts)
650 if (cur->current->layer >= 99999)
651 TRACE("Redrawing font #2");
654 output = 1;
657 if (bounds_ret == 3)
659 Rectan isrc, idst, hack;
661 memcpy(&isrc, &cur->current->src, sizeof(Rectan));
663 idst.x = cur->current->dx;
664 idst.y = cur->current->dy;
665 idst.w = 0;
666 idst.h = 0;
669 if (indep_body.x > buf.x)
671 isrc.x += indep_body.x - buf.x;
672 idst.x += indep_body.x - buf.x;
674 /*isrc.y += buf.y - indep_body.y;
675 idst.y += buf.y - indep_body.y;*/
677 isrc.w -= buf.w - indep_body.w;
678 /* isrc.h += indep_body.h - buf.h; */
680 else
682 /*isrc.x += buf.x - indep_body.x;
683 idst.x += buf.x - indep_body.x;*/
685 isrc.y += indep_body.y - buf.y;
686 idst.y += indep_body.y - buf.y;
688 /* isrc.w += indep_body.w - buf.w; */
689 isrc.h -= buf.h - indep_body.h;
692 /* Graphics_AddDrawingInstruction(cur->current->layer,
693 TDRAW_VOLATILE, &isrc, &idst, cur->current->surface_ptr);
696 /* temporary hack that seems to work, we draw the whole
697 * static image... this needs testing and a better
698 * algorithm.
701 hack.x = cur->current->dx;
702 hack.y = cur->current->dy;
703 hack.w = 0;
704 hack.h = 0;
706 Graphics_AddDrawingInstruction(cur->current->layer, TDRAW_VOLATILE,
707 &cur->current->src,
708 &hack, cur->current->surface_ptr);
710 /*Debug_Val(0, "we have a case 3 situation!\n");*/
712 if (debug_track_fonts)
714 if (cur->current->layer >= 99999)
715 TRACE("Redrawing font #3");
718 output = 1;
721 /* indep is inside cur */
722 if (bounds_ret == 4)
724 Rectan bufa;
725 Rectan nsrc;
727 bufa.x = indep_body.x;
728 bufa.y = indep_body.y;
729 bufa.w = 0;
730 bufa.h = 0;
732 nsrc.x = indep_body.x - cur->current->dx;
733 nsrc.y = indep_body.y - cur->current->dy;
734 nsrc.w = indep_body.w;
735 nsrc.h = indep_body.h;
738 bufa.x = 0;
739 bufa.y = 0;
740 bufa.w = 0;
741 bufa.h = 0;
743 nsrc.x = 0;
744 nsrc.y = 0;
745 nsrc.w = cur->current->src.w;
746 nsrc.h = cur->current->src.h;
749 Graphics_AddDrawingInstruction(cur->current->layer, TDRAW_VOLATILE,
750 &nsrc, &bufa, cur->current->surface_ptr);
752 if (debug_track_fonts)
754 if (cur->current->layer >= 99999)
755 TRACE("Redrawing font #4");
758 output = 1;
761 /* Debug_Val(0, "Redraw Section debug #%d\n", bounds_ret); */
763 cur = cur->next;
766 return output;
769 void
770 Graphics_CoreCleanAll(void)
772 INSTRUCTION_ENGINE *cur;
774 cur = Graphics_GetFirstElem();
776 if (cur == NULL)
777 return;
779 /* "reset" the emplacement of the last position of the image
780 * with the background if theres one or with the color black
781 * if none.
783 while (cur)
785 clean_object(cur, 1);
787 cur = cur->next;
790 Graphics_ResetScreenDraw();
793 /* only clean those with the type TDRAW_DYNAMIC_CLEAN */
794 void
795 Graphics_CoreCleanDoneDynamics(void)
797 INSTRUCTION_ENGINE *cur;
799 cur = Graphics_GetFirstElem();
801 if (cur == NULL)
802 return;
804 /* "reset" the emplacement of the last position of the image
805 * with the background if theres one or with the color black
806 * if none.
808 while (cur)
810 if (cur->current->type == TDRAW_DYNAMIC_CLEAN)
812 clean_object(cur, 0);
815 cur = cur->next;
819 void
820 Graphics_FreeVObject(v_object *source)
822 INSTRUCTION_ENGINE *cur, *tmp;
824 /* this function was made to avoid the painter's algorithm
825 * to have an element contain an image surface that was
826 * freed before it was processed resulting in a segmentation
827 * fault.
830 cur = Graphics_GetFirstElem();
832 while (cur)
834 tmp = cur->next;
836 if (cur->current->surface_ptr == source)
838 /*if (cur->current->type == TDRAW_SDRAWN)
839 Neuro_DestroyDraw(cur);
840 else*/
841 Core_clean_object(cur, 0, 3);
844 cur = tmp;
848 Lib_FreeVobject(source);