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
22 * the core drawing algorithm.
25 /*-------------------- Extern Headers Including --------------------*/
26 #include <string.h> /* memcpy */
28 /*-------------------- Local Headers Including ---------------------*/
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 --------------------------*/
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
60 static INSTRUCTION_ENGINE
*
61 get_Previous_Object_To_Object(INSTRUCTION_ENGINE
*indep
)
63 INSTRUCTION_ENGINE
*cur
, *last
= NULL
;
65 cur
= Graphics_GetFirstElem();
78 /* Debug_Val(0, "found the previous elem 0x%x, (his next 0x%x)\n",
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
98 Core_clean_object(INSTRUCTION_ENGINE
*cur
, int dont_redraw_section
, u8 del_mask
)
101 INSTRUCTION_ENGINE
*last
= NULL
;
104 /* this functions needs to destroy an element
105 * from both the instruction buffer and the raw
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(); */
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
;
138 Lib_BlitObject(background, &buf, sclScreen2, &buf);
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
);
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())
189 Graphics_SetLastElem(last
);
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);
205 /* INSTRUCTION_ENGINE *temp; */
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); */
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(); */
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.
256 Graphics_DestroyElement(INSTRUCTION_ENGINE
*elem
)
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.
268 /* we clean only the queue element and keep the raw engine buffer */
269 Core_clean_object(elem
, 1, 2);
274 tmp
->type
= TDRAW_SDESTROY
;
276 /* we put the raw buffer back into the queue */
277 Graphics_PushRaw(tmp
);
281 Graphics_CoreDrawAll(void)
284 INSTRUCTION_ENGINE
*cur
, *last
= NULL
;
285 u32 safety
= 10000; /* safety decrementor to avoid death loop */
287 if (Neuro_EBufIsEmpty(Graphics_GetQueueBuffer()))
290 cur
= Graphics_GetFirstElem();
292 /* start the real drawing */
298 ERROR("To avoid a death loop, had to bail out of the instruction loop after 1000 loops");
299 break; /* safety break */
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
)
324 /* Debug_Val(0, "static draw (%d,%d) %dx%d to (%d,%d)\n",
325 isrc.x, isrc.y, isrc.w, isrc.h,
331 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
, Neuro_GetScreenBuffer(),
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",
346 cur
->current
->dy
, cur
));
354 /* nothing needed for this type */
355 /* Debug_Val(0, "already drawn\n"); */
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(),
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"); */
387 INSTRUCTION_ENGINE
*tmp
;
389 if (cur->current->layer > 1000)
390 Debug_Print("Cleaned a static image");
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();
411 Lib_BlitObject(cur
->current
->surface_ptr
, &isrc
,
412 Neuro_GetScreenBuffer(), &idst
);
414 cur
->current
->type
= TDRAW_DYNAMIC_CLEAN
;
417 TRACE(Neuro_s("Dynamic : Tagging addr %x to clean", cur
));
418 /* Debug_Val(0, "drawn dynamic\n"); */
423 case TDRAW_DYNAMIC_CLEAN
:
425 /* Lib_BlitObject(cur->current->surface_ptr, &isrc,
426 sclScreen2, &idst);*/
428 /* clean_object(cur); */
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,
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.
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())
464 Graphics_SetLastElem(last
);
469 /*if (use_memory_pool)
470 Push_Data_To_Pool(POOL_QUEUE, cur);
473 INSTRUCTION_ENGINE
*temp
;
478 Neuro_SCleanEBuf(Graphics_GetRawBuffer(), temp
->current
);
479 Neuro_SCleanEBuf(Graphics_GetQueueBuffer(), temp
);
490 ERROR(Neuro_s("Draw unknown type %d\n", cur
->current
->type
));
498 if (cur
->next
== NULL
&& cur
!= Graphics_GetLastElem())
500 ERROR("cur->next is NULL AND it isn't the last element, bad, very bad...");
509 Graphics_SetDrawnLastCycle();
510 /* Lib_FillRect(sclScreen, &test_BoundFix, 0); */
514 Graphics_SetAllToRedraw(void)
516 INSTRUCTION_ENGINE
*cur
;
518 cur
= Graphics_GetFirstElem();
525 if (cur
->current
->type
== TDRAW_SDRAWN
)
526 cur
->current
->type
= TDRAW_STATIC
; /* TDRAW_SREDRAW seems to do a flaw */
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
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
;
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();
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 */
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
,
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",
604 indep_body
.x
, indep_body
.y
));
612 bufa
.x
= cur
->current
->dx
;
613 bufa
.y
= cur
->current
->dy
;
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");
635 memcpy(&isrc
, &cur
->current
->src
, sizeof(Rectan
));
637 idst
.x
= cur
->current
->dx
;
638 idst
.y
= cur
->current
->dy
;
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");
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
;
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; */
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
701 hack
.x
= cur
->current
->dx
;
702 hack
.y
= cur
->current
->dy
;
706 Graphics_AddDrawingInstruction(cur
->current
->layer
, TDRAW_VOLATILE
,
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");
721 /* indep is inside cur */
727 bufa
.x
= indep_body
.x
;
728 bufa
.y
= indep_body
.y
;
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
;
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");
761 /* Debug_Val(0, "Redraw Section debug #%d\n", bounds_ret); */
770 Graphics_CoreCleanAll(void)
772 INSTRUCTION_ENGINE
*cur
;
774 cur
= Graphics_GetFirstElem();
779 /* "reset" the emplacement of the last position of the image
780 * with the background if theres one or with the color black
785 clean_object(cur
, 1);
790 Graphics_ResetScreenDraw();
793 /* only clean those with the type TDRAW_DYNAMIC_CLEAN */
795 Graphics_CoreCleanDoneDynamics(void)
797 INSTRUCTION_ENGINE
*cur
;
799 cur
= Graphics_GetFirstElem();
804 /* "reset" the emplacement of the last position of the image
805 * with the background if theres one or with the color black
810 if (cur
->current
->type
== TDRAW_DYNAMIC_CLEAN
)
812 clean_object(cur
, 0);
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
830 cur
= Graphics_GetFirstElem();
836 if (cur
->current
->surface_ptr
== source
)
838 /*if (cur->current->type == TDRAW_SDRAWN)
839 Neuro_DestroyDraw(cur);
841 Core_clean_object(cur
, 0, 3);
848 Lib_FreeVobject(source
);