completely finished the documentation of the EBUF module (!)
[neuro.git] / src / video / coredraw.c
blob8b111ff30b61cb07f23746b04a79f2b61ae4764c
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 <extlib.h> /* we mainly use the blitting function and screen updating functions */
30 #include <ebuf.h> /* we mainly use the single item cleaning function Neuro_SCleanEBuf */
32 /*-------------------- Main Module Header --------------------------*/
33 #include "video.h"
34 #include <graphics.h>
37 /*-------------------- Other ----------------------------*/
39 /*-------------------- Global Variables ----------------------------*/
41 /*-------------------- Static Variables ----------------------------*/
43 /*-------------------- Static Prototypes ---------------------------*/
47 /*-------------------- Static Functions ----------------------------*/
49 /* a function to resolve a bug that made the volatile objects
50 * mysteriously disapear. It was because the last element of the
51 * Dynamic object was not refreshed so if an element was just
52 * before the Dynamic object, it just made it disapear :).
54 * This function searches the element just before the input element
55 * and returns it.
57 static INSTRUCTION_ENGINE *
58 get_Previous_Object_To_Object(INSTRUCTION_ENGINE *indep)
60 INSTRUCTION_ENGINE *cur, *last = NULL;
62 cur = Graphics_GetFirstElem();
64 if (cur == NULL)
65 return NULL;
67 if (indep == cur)
68 return NULL;
70 while (cur)
73 if (cur == indep)
75 /* Debug_Val(0, "found the previous elem 0x%x, (his next 0x%x)\n",
76 last, last->next);*/
77 return last;
81 last = cur;
82 cur = cur->next;
86 return NULL;
89 /* del_mask : 0 is don't clean any buffers (big memory leak)
90 * 1 is clean only the raw engine
91 * 2 is clean only the queue(instruction) engine
92 * 3 is clean both
94 static void
95 Core_clean_object(INSTRUCTION_ENGINE *cur, int dont_redraw_section, u8 del_mask)
97 Rectan buf;
98 INSTRUCTION_ENGINE *last = NULL;
99 EBUF *verify_m;
101 /* this functions needs to destroy an element
102 * from both the instruction buffer and the raw
103 * buffer.
105 * the first step we do is fill a special Rectan
106 * rectangle with the position and size of
107 * the image. Then, we draw this position and
108 * size black on screen. After that is done, we
109 * have to redraw previous objects (if theres any).
114 if (debug_track_fonts)
116 if (cur->current->layer >= 99999)
118 Debug_Print("Destroying font");
119 Debug_Val(0, "&0x%x\n", cur);
123 /* Graphics_DebugQueueIntegrityCheck(); */
125 if (!cur)
126 return;
128 /* Debug_Val(0, "destroying element address 0x%x\n", cur); */
130 buf.x = cur->current->dx;
131 buf.y = cur->current->dy;
132 buf.w = cur->current->src.w;
133 buf.h = cur->current->src.h;
135 /*if (background)
136 Lib_BlitObject(background, &buf, sclScreen2, &buf);
137 else
138 Lib_FillRect(sclScreen2, &buf, 0);
141 if (dont_redraw_section == 0)
143 Lib_FillRect(Neuro_GetScreenBuffer(), &buf, 0);
145 Graphics_RedrawSection(cur);
148 if (debug_clean_instruction_buffer)
150 Neuro_CreateEBuf(&verify_m);
151 Graphics_DebugBufferQueue(verify_m);
154 if (debug_clean_instruction_buffer)
156 Debug_Print("*initial values");
157 Debug_Val(0, "Amount of elems %d\n", Neuro_GiveEBufCount(verify_m) - 1);
158 Graphics_DebugPrintMissing(verify_m);
161 /* only set the previous element (last) if the element we need to
162 * destroy isn't the first one
164 if (cur != Graphics_GetFirstElem())
165 last = get_Previous_Object_To_Object(cur);
166 if (last)
168 /* Debug_Val(0, "changing last's(0x%x) next 0x%x to 0x%x\n", last,
169 last->next, cur->next);*/
171 last->next = cur->next;
174 /* check to see if the element cur is either first_element
175 * or last_element and if so, we will destituate it.
177 if (cur == Graphics_GetFirstElem())
179 Graphics_SetFirstElem(cur->next);
182 if (cur == Graphics_GetLastElem())
184 if (last)
186 last->next = NULL;
187 Graphics_SetLastElem(last);
189 else
190 Graphics_SetLastElem(NULL);
193 if (debug_clean_instruction_buffer)
195 Debug_Print("*before real destroy");
196 Graphics_DebugPrintMissing(verify_m);
199 /*if (use_memory_pool)
200 Push_Data_To_Pool(POOL_QUEUE, cur);
201 else*/
203 /* INSTRUCTION_ENGINE *temp; */
206 temp = cur;
207 cur = cur->next;
210 /* Debug_Val(0, "before queue total %d\n",
211 Neuro_GiveEBufCount(_Queue) + 1);*/
213 if (del_mask == 1 || del_mask == 3)
214 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), cur->current);
215 /* Debug_Val(0, "-- element address 0x%x destroyed\n", cur); */
216 if (del_mask == 2 || del_mask == 3)
217 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), cur);
219 /* Debug_Val(0, "after queue total %d\n",
220 Neuro_GiveEBufCount(_Queue) + 1); */
221 /* continue; */
224 if (debug_clean_instruction_buffer)
226 Debug_Print("**After the destroy");
227 /*Debug_Val(0, "Amount of elems in verify %d in queue %d\n",
228 Neuro_GiveEBufCount(verify_m) - 1,
229 Neuro_GiveEBufCount(_Queue) - 1);*/
230 Debug_Print("**Full output");
232 Graphics_DebugPrintQueue();
234 Graphics_DebugPrintMissing(verify_m);
235 Neuro_CleanEBuf(&verify_m);
238 /* Graphics_DebugQueueIntegrityCheck(); */
241 static void
242 clean_object(INSTRUCTION_ENGINE *cur, int dont_redraw_section)
244 Core_clean_object(cur, dont_redraw_section, 3);
247 /*-------------------- Global Functions ----------------------------*/
249 /* take note that we don't do any checks for valid pointers and such
250 * this function is supposed to be a backbone to an interface function
251 * which itself does the parity checks.
253 void
254 Graphics_DestroyElement(INSTRUCTION_ENGINE *elem)
256 RAW_ENGINE *tmp;
257 Rectan dst;
259 /* we destroy only the queue buffer because we want to make
260 * the emplacement of the element into a more comfortable
261 * place for the algorithm to avoid glitches.
264 tmp = elem->current;
266 /* we clean only the queue element and keep the raw engine buffer */
267 Core_clean_object(elem, 1, 2);
269 dst.x = tmp->dx;
270 dst.y = tmp->dy;
272 tmp->type = TDRAW_SDESTROY;
274 /* we put the raw buffer back into the queue */
275 Graphics_PushRaw(tmp);
278 void
279 Graphics_CoreDrawAll()
281 Rectan isrc, idst;
282 INSTRUCTION_ENGINE *cur, *last = NULL;
283 u32 safety = 10000; /* safety decrementor to avoid death loop */
285 if (Neuro_EBufIsEmpty(Graphics_GetQueueBuffer()))
286 return;
288 cur = Graphics_GetFirstElem();
290 /* start the real drawing */
291 while (cur)
294 if (safety <= 0)
296 Error_Print("To avoid a death loop, had to bail out of the instruction loop after 1000 loops");
297 break; /* safety break */
299 else
300 safety--;
302 if (check_integrity_on_draw)
304 Debug_Print("Data integrity check before drawing");
305 Graphics_DebugQueueIntegrityCheck();
308 memcpy(&isrc, &cur->current->src, sizeof(Rectan));
310 idst.x = cur->current->dx;
311 idst.y = cur->current->dy;
313 if (debug_instruction_buffer)
314 Debug_Val(0, "%s Flushing type %d layer %d\n", __FUNCTION__, cur->current->type, cur->current->layer);
316 /* draw the surface_ptr to the screen buffer. */
317 switch (cur->current->type)
319 case TDRAW_STATIC:
322 /* Debug_Val(0, "static draw (%d,%d) %dx%d to (%d,%d)\n",
323 isrc.x, isrc.y, isrc.w, isrc.h,
324 idst.x, idst.y);
329 Lib_BlitObject(cur->current->surface_ptr, &isrc, Neuro_GetScreenBuffer(),
330 &idst);
332 cur->current->type = TDRAW_SDRAWN;
334 /* Graphics_RedrawSection(cur); */
336 /* Debug_Val(0, "drawn static\n"); */
338 if (debug_track_fonts)
340 if (cur->current->layer >= 99999)
342 Debug_Print("Drawing font");
343 Debug_Val(0, "Coord (%d,%d) &0x%x\n",
344 cur->current->dx,
345 cur->current->dy, cur);
349 break;
351 case TDRAW_SDRAWN:
353 /* nothing needed for this type */
354 /* Debug_Val(0, "already drawn\n"); */
356 break;
358 case TDRAW_SREDRAW:
360 /* Debug_Val(0, "address of surface 0x%x\n", cur->current->surface_ptr); */
362 /* now we redraw the actual element */
363 Lib_BlitObject(cur->current->surface_ptr, &isrc, Neuro_GetScreenBuffer(),
364 &idst);
366 /* we cleanly redrawn the static element so we
367 * set the element's flag to drawn
369 cur->current->type = TDRAW_SDRAWN;
371 /* then we redraw the stuff that could have been
372 * there and actually need to be visible(and are above
373 * our element, ie layers).
375 * broken for some reason
377 Graphics_RedrawSection(cur);
379 /* Debug_Val(0, "Redrawn a static element\n"); */
381 break;
383 case TDRAW_SDESTROY:
385 INSTRUCTION_ENGINE *tmp;
387 if (cur->current->layer > 1000)
388 Debug_Print("Cleaned a static image");
391 tmp = cur;
393 cur = cur->next;
395 clean_object(tmp, 0);
397 /* we restart the loop completely since we need to draw
398 * the volatile types first before drawing the rest..
400 cur = Graphics_GetFirstElem();
402 if (cur)
403 continue;
405 break;
407 case TDRAW_DYNAMIC:
409 Lib_BlitObject(cur->current->surface_ptr, &isrc,
410 Neuro_GetScreenBuffer(), &idst);
412 cur->current->type = TDRAW_DYNAMIC_CLEAN;
414 if (dynamic_debug)
415 Debug_Val(0, "Dynamic : Tagging addr %x to clean\n", cur);
416 /* Debug_Val(0, "drawn dynamic\n"); */
418 break;
420 #if temp
421 case TDRAW_DYNAMIC_CLEAN:
423 /* Lib_BlitObject(cur->current->surface_ptr, &isrc,
424 sclScreen2, &idst);*/
426 /* clean_object(cur); */
428 break;
429 #endif /* temp */
431 case TDRAW_VOLATILE:
433 /*Debug_Val(0, "Volatile draw (%d,%d) %dx%d to (%d,%d) image 0x%x\n",
434 isrc.x, isrc.y, isrc.w, isrc.h,
435 idst.x, idst.y,
436 cur->current->surface_ptr);
439 Lib_BlitObject(cur->current->surface_ptr, &isrc,
440 Neuro_GetScreenBuffer(), &idst);
442 /* NOTE that we CAN't USE clean_object() BECAUSE
443 * it actually makes the image all BLACK
444 * so it nullifies the action of this COMPLETELY.
446 if (last)
447 last->next = cur->next;
449 /* check to see if the element cur is either first_element
450 * or last_element and if so, we will destituate it.
452 if (cur == Graphics_GetFirstElem())
454 Graphics_SetFirstElem(cur->next);
457 if (cur == Graphics_GetLastElem())
459 if (last)
461 last->next = NULL;
462 Graphics_SetLastElem(last);
467 /*if (use_memory_pool)
468 Push_Data_To_Pool(POOL_QUEUE, cur);
469 else*/
471 INSTRUCTION_ENGINE *temp;
473 temp = cur;
474 cur = cur->next;
476 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), temp->current);
477 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), temp);
479 if (cur)
480 continue;
483 break;
486 default:
488 Debug_Val(0, "ERROR Draw unknown type %d\n", cur->current->type);
490 break;
493 if (cur)
495 last = cur;
496 if (cur->next == NULL && cur != Graphics_GetLastElem())
498 Error_Print("cur->next is NULL AND it isn't the last element, bad, very bad...");
500 cur = cur->next;
502 else
503 break;
507 Graphics_SetDrawnLastCycle();
508 /* Lib_FillRect(sclScreen, &test_BoundFix, 0); */
511 void
512 Graphics_SetAllToRedraw()
514 INSTRUCTION_ENGINE *cur;
516 cur = Graphics_GetFirstElem();
518 if (cur == NULL)
519 return;
521 while (cur)
523 if (cur->current->type == TDRAW_SDRAWN)
524 cur->current->type = TDRAW_STATIC; /* TDRAW_SREDRAW seems to do a flaw */
526 cur = cur->next;
529 if (debug_instruction_buffer)
530 Debug_Print("Just Set all the instructions to be redrawn");
533 /* Graphics_CoreCleanAll might have cleaned objects
534 * that should be drawn so we will redraw those in this
535 * function.
536 * returns non zero if a volatile type was pushed
539 Graphics_RedrawSection(INSTRUCTION_ENGINE *indep)
541 Rectan buf, indep_body;
542 INSTRUCTION_ENGINE *cur;
543 int bounds_ret = 0;
544 int output = 0;
547 indep_body.x = indep->current->dx;
548 indep_body.y = indep->current->dy;
549 indep_body.w = indep->current->src.w;
550 indep_body.h = indep->current->src.h;
552 cur = Graphics_GetFirstElem();
554 if (cur == NULL)
555 return 0;
557 while (cur)
560 if (cur == indep)
562 cur = cur->next;
563 continue;
566 if (!cur->current)
568 Debug_Val(0, "BAD : the instruction 0x%x has an empty content!\n",
569 cur);
571 Debug_Val(0, "DEBUG data : indep 0x%x its next element 0x%x\n",
572 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 Debug_Print("INITIAL Redrawing font");
583 Debug_Val(0, "Font type %d (%d,%d) &0x%x\n", cur->current->type,
584 buf.x, buf.y, cur);
588 if (cur->current->type == TDRAW_SDRAWN)
591 buf.x = cur->current->dx;
592 buf.y = cur->current->dy;
593 buf.w = cur->current->src.w;
594 buf.h = cur->current->src.h;
596 bounds_ret = Neuro_BoundsCheck(&indep_body, &buf);
597 /* bounds_ret = 2; */
599 if (debug_track_fonts)
601 if (cur->current->layer >= 99999 && indep->current->layer >= 99999)
603 Debug_Print("INITIAL 2 Redrawing font");
604 Debug_Val(0, "bounds_ret %d current (%d,%d) indep (%d,%d)\n",
605 bounds_ret,
606 buf.x, buf.y,
607 indep_body.x, indep_body.y);
611 if (bounds_ret == 0)
613 Rectan bufa;
615 bufa.x = cur->current->dx;
616 bufa.y = cur->current->dy;
617 bufa.w = 0;
618 bufa.h = 0;
620 Neuro_PushVolatileDraw(cur->current->layer, &cur->current->src,
621 &bufa, cur->current->surface_ptr);
623 /*Debug_Val(0, "dynamic is inside this object\n");*/
625 if (debug_track_fonts)
627 if (cur->current->layer >= 99999)
628 Debug_Print("Redrawing font #0");
631 output = 1;
634 if (bounds_ret == 2)
636 Rectan isrc, idst;
638 memcpy(&isrc, &cur->current->src, sizeof(Rectan));
640 idst.x = cur->current->dx;
641 idst.y = cur->current->dy;
642 idst.w = 0;
643 idst.h = 0;
645 Neuro_VerticalBoundCrop(&indep_body, &isrc, &idst);
646 Neuro_HorizontalBoundCrop(&indep_body, &isrc, &idst);
648 Neuro_PushVolatileDraw(cur->current->layer,
649 &isrc, &idst, cur->current->surface_ptr);
651 if (debug_track_fonts)
653 if (cur->current->layer >= 99999)
654 Debug_Print("Redrawing font #2");
657 output = 1;
660 if (bounds_ret == 3)
662 Rectan isrc, idst, hack;
664 memcpy(&isrc, &cur->current->src, sizeof(Rectan));
666 idst.x = cur->current->dx;
667 idst.y = cur->current->dy;
668 idst.w = 0;
669 idst.h = 0;
672 if (indep_body.x > buf.x)
674 isrc.x += indep_body.x - buf.x;
675 idst.x += indep_body.x - buf.x;
677 /*isrc.y += buf.y - indep_body.y;
678 idst.y += buf.y - indep_body.y;*/
680 isrc.w -= buf.w - indep_body.w;
681 /* isrc.h += indep_body.h - buf.h; */
683 else
685 /*isrc.x += buf.x - indep_body.x;
686 idst.x += buf.x - indep_body.x;*/
688 isrc.y += indep_body.y - buf.y;
689 idst.y += indep_body.y - buf.y;
691 /* isrc.w += indep_body.w - buf.w; */
692 isrc.h -= buf.h - indep_body.h;
695 /* Neuro_PushVolatileDraw(cur->current->layer,
696 &isrc, &idst, cur->current->surface_ptr);*/
698 /* temporary hack that seems to work, we draw the whole
699 * static image... this needs testing and a better
700 * algorithm.
703 hack.x = cur->current->dx;
704 hack.y = cur->current->dy;
705 hack.w = 0;
706 hack.h = 0;
708 Neuro_PushVolatileDraw(cur->current->layer, &cur->current->src,
709 &hack, cur->current->surface_ptr);
711 /*Debug_Val(0, "we have a case 3 situation!\n");*/
713 if (debug_track_fonts)
715 if (cur->current->layer >= 99999)
716 Debug_Print("Redrawing font #3");
719 output = 1;
722 /* indep is inside cur */
723 if (bounds_ret == 4)
725 Rectan bufa;
726 Rectan nsrc;
728 bufa.x = indep_body.x;
729 bufa.y = indep_body.y;
730 bufa.w = 0;
731 bufa.h = 0;
733 nsrc.x = indep_body.x - cur->current->dx;
734 nsrc.y = indep_body.y - cur->current->dy;
735 nsrc.w = indep_body.w;
736 nsrc.h = indep_body.h;
739 bufa.x = 0;
740 bufa.y = 0;
741 bufa.w = 0;
742 bufa.h = 0;
744 nsrc.x = 0;
745 nsrc.y = 0;
746 nsrc.w = cur->current->src.w;
747 nsrc.h = cur->current->src.h;
750 Neuro_PushVolatileDraw(cur->current->layer, &nsrc,
751 &bufa, cur->current->surface_ptr);
753 if (debug_track_fonts)
755 if (cur->current->layer >= 99999)
756 Debug_Print("Redrawing font #4");
759 output = 1;
762 /* Debug_Val(0, "Redraw Section debug #%d\n", bounds_ret); */
764 cur = cur->next;
767 return output;
770 void
771 Graphics_CoreCleanAll()
773 INSTRUCTION_ENGINE *cur;
775 cur = Graphics_GetFirstElem();
777 if (cur == NULL)
778 return;
780 /* "reset" the emplacement of the last position of the image
781 * with the background if theres one or with the color black
782 * if none.
784 while (cur)
786 clean_object(cur, 1);
788 cur = cur->next;
791 Graphics_ResetScreenDraw();
794 /* only clean those with the type TDRAW_DYNAMIC_CLEAN */
795 void
796 Graphics_CoreCleanDoneDynamics()
798 INSTRUCTION_ENGINE *cur;
800 cur = Graphics_GetFirstElem();
802 if (cur == NULL)
803 return;
805 /* "reset" the emplacement of the last position of the image
806 * with the background if theres one or with the color black
807 * if none.
809 while (cur)
811 if (cur->current->type == TDRAW_DYNAMIC_CLEAN)
813 clean_object(cur, 0);
816 cur = cur->next;
820 void
821 Graphics_FreeVObject(v_object *source)
823 INSTRUCTION_ENGINE *cur, *tmp;
825 /* this function was made to avoid the painter's algorithm
826 * to have an element contain an image surface that was
827 * freed before it was processed resulting in a segmentation
828 * fault.
831 cur = Graphics_GetFirstElem();
833 while (cur)
835 tmp = cur->next;
837 if (cur->current->surface_ptr == source)
839 /*if (cur->current->type == TDRAW_SDRAWN)
840 Neuro_DestroyDraw(cur);
841 else*/
842 Core_clean_object(cur, 0, 3);
845 cur = tmp;
849 Lib_FreeVobject(source);