removed the obsolete Lib_GetKeyState function
[neuro.git] / src / video / painter.c
bloba2f0a0c90f2ee3dbd6dd51430480f54ed06d6b83
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
23 /* painter.c
24 * The core painter's algorithm module.
27 /*
28 * this code is my own version of the painter's algorithm.
29 * It is thus used to draw images in an order you have to
30 * input when "pushing" an image, called layers.
31 * This module also requires 3 other variables which contain
32 * the size of the image, a pointer to the image and the
33 * destination of the image.
35 * To make the painter's algorithm, I used 2 types of data.
36 * I use raw data which contains exactly what the external
37 * process gives us and then theres the instruction data which
38 * contains a pointer to a single raw data and a pointer
39 * to the next instruction data.
41 * The instruction datas order are changed every time a new
42 * image is pushed. It is organized in a growing order,
43 * the smallest layers are the first ones and the biggest
44 * are the last instructions drawn.
46 * Now, you see, the major advantage of this is we can also
47 * redraw images that were below another one which would for
48 * example be deleted. But for this, we have do an expansive
49 * bounds search for images which have to be redrawn.
51 * Also note that raw datas have different types that trigger
52 * behaviors. Static and dynamic are the two most important
53 * types, then theres the temporary type and the rest
54 * are pretty much sub types for those that I mentioned earlier.
58 /*-------------------- Extern Headers Including --------------------*/
59 #include <string.h> /* memcpy */
61 /*-------------------- Local Headers Including ---------------------*/
62 #include <extlib.h> /* we only use Lib_GetScreenSize */
63 #include <ebuf.h> /* we use all the "normal" allocation function from this */
64 #include <other.h> /* we call all the bounding check functions from it
65 and also the bound fix ones */
67 /*-------------------- Main Module Header --------------------------*/
68 #include "video.h"
69 #include <graphics.h>
71 /*-------------------- Other ----------------------------*/
73 /*-------------------- Global Variables ----------------------------*/
75 /*-------------------- Static Variables ----------------------------*/
77 static INSTRUCTION_ENGINE *first_element;
78 static INSTRUCTION_ENGINE *last_element;
80 static EBUF *Raw;
81 static EBUF *Queue;
83 /* buffered screen size for fast consultation */
84 static Rectan screenSize;
86 /* a rectangle meant to test the bound fix algorithm */
87 /* static Rectan test_BoundFix; */
89 /*-------------------- Static Prototypes ---------------------------*/
93 /*-------------------- Static Functions ----------------------------*/
95 /* A function that handles "fixes" needed on images
96 * to make them constrainted in the main screen.
97 * returns 0 if all is ok and 1 if the image needs
98 * to be dropped.
100 static u8
101 BoundFixChecker(Rectan *indep, Rectan *isrc, Rectan *idst)
103 Rectan bufa;
105 bufa.x = idst->x;
106 bufa.y = idst->y;
107 bufa.w = isrc->w - 1;
108 bufa.h = isrc->h - 1;
110 switch (Neuro_BoundsCheck(indep, &bufa))
112 case 0: /* the v_object is inside the screen, all is ok */
113 break;
115 case 1: /* the v_object is outside the screen, we need to drop this instruction */
117 /* Debug_Print("a drawing instruction was dropped because its destination is outbound"); */
118 return 1;
120 break;
122 /* here is the fun, the v_object is overlapping the screen
123 * and we got to only draw the part that is still inside
124 * the screen
126 case 2:
128 /* to do this, I'm thinking we could use 2 similar functions
129 * the 1st one would check and "correct" the parts of the
130 * v_object that is not inside the screen vertically and
131 * the 2nd one would do the same but horizontally.
132 * The only thing to do is to change the isrc(Rectan)'s
133 * values.
135 Neuro_VerticalBoundCrop(indep, isrc, idst);
136 Neuro_HorizontalBoundCrop(indep, isrc, idst);
137 /* Info_Print("Fixed the coordinates/size of the drawing instruction."); */
139 break;
141 default:
143 /* Debug_Print("a drawing instruction was dropped because its destination is outbound"); */
144 return 1;
146 break;
149 return 0;
152 /* compute the instruction_engine buffer every
153 * time a new raw element is added.
155 static INSTRUCTION_ENGINE *
156 computeRawEngine(RAW_ENGINE *toadd)
158 register EBUF *tmp;
159 register INSTRUCTION_ENGINE *buf = NULL, *cur = NULL, *last = NULL;
160 register u32 current; /* current number of elements in instruction */
162 tmp = Queue;
164 /*if (use_memory_pool)
165 buf = Pull_Data_From_Pool(POOL_QUEUE);*/
167 if (buf == NULL)
169 /* Debug_Val(0, "computeRawEngine buf is empty so we allocate for %d\n", toadd->layer); */
170 Neuro_AllocEBuf(tmp, sizeof(INSTRUCTION_ENGINE*), sizeof(INSTRUCTION_ENGINE));
171 buf = Neuro_GiveCurEBuf(tmp);
173 /*else
174 Debug_Val(0, "computeRawEngine recycled an object! %d\n", toadd->layer);*/
177 current = Neuro_GiveEBufCount(tmp);
179 buf->current = toadd;
180 buf->next = NULL;
183 /* this is the special case for a TDRAW_SDESTROY element
184 * every one of those elements will be put into the
185 * layer 0.
187 if (buf->current->type == TDRAW_SDESTROY)
189 buf->current->layer = 0;
193 * special case so volatile types always are put in the
194 * beginning of the queue. Both to make the process
195 * faster and to make the volatiles have precedence
196 * over everything to avoid conflicts.
198 if (buf->current->type == TDRAW_VOLATILE)
200 /* we make the type be of the layer 0 so it is
201 * always the first in the list.
203 * the layer 0 is reserved stricly for volatile
204 * types.
207 buf->current->layer = 1;
210 if (debug_instruction_buffer)
211 Debug_Val(0, "Push --> layer %d type %d\n", toadd->layer, toadd->type);
213 if (last_element != NULL)
215 if (last_element->current == NULL)
217 Debug_Val(0, "CAUGHT ERROR in last_element current == %d -- debug %d\nDropping this call\n",
218 current,
219 (int)last_element->current);
220 return NULL;
223 if (last_element->current->layer <= buf->current->layer)
225 last_element->next = buf;
226 last_element = buf;
227 /*Debug_Val(0, "proof layer %d real layer %d ptr %d\n",
228 (*buf)[current]->current->layer,
229 (*last_element)->current->layer,
230 (int)(*last_element)->current);*/
231 /* Debug_Val(0, "Placed the object at the end of the queue\n"); */
233 return buf;
236 else
238 first_element = buf;
239 last_element = buf;
240 /* Debug_Val(0, "Just placed the frame as the first element, starting the queue\n"); */
241 return buf;
244 cur = first_element;
245 /* cur = Neuro_GiveEBuf(tmp, first); */
246 while (cur != NULL)
248 /* Debug_Val(0, "looped cur %d buf %d\n", cur->current->layer, buf->current->layer); */
249 if (cur->current->layer > buf->current->layer)
251 /*printf("Event current layer %d > toadd layer %d\n",
252 cur->current->layer,
253 toadd->layer);
256 /* to avoid death loops */
257 /*if (cur->next == buf)
258 cur->next = NULL;*/
260 if (cur == first_element)
262 #if temp
263 /* switch **buf with the current position */
264 temp = Neuro_GiveEBuf(tmp, first);
265 Neuro_SetEBuf(tmp, Neuro_GiveEBufAddr(tmp, first), buf);
266 Neuro_SetEBuf(tmp, Neuro_GiveEBufAddr(tmp, current), temp);
268 /*printf("Beginning LL change : cur %d, buf[0][0] %d\n",
269 (int)cur,
270 (int)buf[0]);
272 if (cur->current == NULL || cur->current->surface_ptr == NULL)
273 cur = Neuro_GiveEBuf(tmp, first);
274 if (Neuro_GiveEBuf(tmp, first) == buf)
276 Error_Print("huge problem, it is going to put its next element as the same node as itself, creating a death loop!!\n");
277 cur->next = NULL;
279 else
280 cur->next = temp;
281 #endif /* temp */
282 /*Debug_Val(0, "New First element proclaimed %d\n",
283 buf->current->layer);*/
284 buf->next = first_element;
285 first_element = buf;
287 else
288 buf->next = cur;
289 if (last != NULL)
291 last->next = buf;
293 break;
295 else
297 /* Debug_Val(0, "nothing to be done\n"); */
299 last = cur;
300 cur = cur->next;
302 /* printf("End of the looping process\n"); */
305 if (debug_instruction_buffer)
307 Debug_Val(0, "BEGIN inside computeRawEngine debug print\n");
308 Graphics_DebugPrintQueue();
309 Debug_Val(0, "END inside computeRawEngine debug print\n");
312 return buf;
316 /*-------------------- Global Functions ----------------------------*/
318 /* - layer is the priority by which it much be drawn.
319 * - src should be used to know which part of the
320 * surface has to be drawn(for sprites mostly).
321 * - dst is the destination X Y on the screen
322 * - surface is the pointer of the loaded image.
324 INSTRUCTION_ENGINE *
325 Graphics_AddDrawingInstruction(u32 layer, u8 type, Rectan *isrc, Rectan *idst, void *isurface)
327 RAW_ENGINE *buf = NULL;
328 Rectan tIsrc, tIdst;
330 if (isurface == NULL || isrc == NULL || idst == NULL)
331 return NULL;
333 memcpy(&tIsrc, isrc, sizeof(Rectan));
334 memcpy(&tIdst, idst, sizeof(Rectan));
336 if (BoundFixChecker(&screenSize, &tIsrc, &tIdst) == 1)
338 /* Debug_Val(10, "a drawing instruction was dropped because its destination is outbound"); */
339 return NULL;
342 #if retain_image_inipos
343 tIsrc.x = isrc->x;
344 tIsrc.y = isrc->y;
345 tIsrc.w = isrc->w;
346 tIsrc.h = isrc->h;
348 tIdst.x = idst->x;
349 tIdst.y = idst->y;
350 #endif /* retain_image_inipos */
352 /* a square in the middle of the screen to test
353 * the bound fix checker on an object other than
354 * the screen itself.
356 /* BoundFixChecker(&test_BoundFix, &tIsrc, &tIdst); */
358 /*if (use_memory_pool)
359 buf = Pull_Data_From_Pool(POOL_RAWENGINE);*/
361 if (buf == NULL)
363 Neuro_AllocEBuf(Raw, sizeof(RAW_ENGINE*), sizeof(RAW_ENGINE));
365 buf = Neuro_GiveCurEBuf(Raw);
368 /* we reserve the first 5 spots for our need
369 * we might reserve more than 5
370 * if the need comes out.
372 buf->layer = layer + 5;
373 buf->type = type;
374 memcpy(&buf->src, &tIsrc, sizeof(Rectan));
376 buf->dx = tIdst.x;
377 buf->dy = tIdst.y;
379 buf->surface_ptr = isurface;
381 /* sets a flag to tell when changed things
382 * and I think the whole screen will be
383 * redrawn.
385 Neuro_RedrawScreen();
387 /* if (buf->type == TDRAW_STATIC || buf->type == TDRAW_DYNAMIC)
388 Graphics_SetAllToRedraw();*/
390 return computeRawEngine((RAW_ENGINE*)buf);
393 INSTRUCTION_ENGINE *
394 Graphics_PushRaw(RAW_ENGINE *raw)
396 return computeRawEngine((RAW_ENGINE*)raw);
400 INSTRUCTION_ENGINE *
401 Graphics_GetFirstElem()
403 return first_element;
406 void
407 Graphics_SetFirstElem(INSTRUCTION_ENGINE *elem)
409 first_element = elem;
412 INSTRUCTION_ENGINE *
413 Graphics_GetLastElem()
415 return last_element;
418 void
419 Graphics_SetLastElem(INSTRUCTION_ENGINE *elem)
421 last_element = elem;
424 EBUF *
425 Graphics_GetRawBuffer()
427 return Raw;
430 EBUF *
431 Graphics_GetQueueBuffer()
433 return Queue;
436 /*-------------------- Constructor Destructor ----------------------*/
439 Graphics_PainterInit()
441 i32 screenwidth, screenheight;
443 Neuro_CreateEBuf(&Raw);
444 Neuro_CreateEBuf(&Queue);
446 /* get the screen size from the "official" source */
447 Lib_GetScreenSize(&screenwidth, &screenheight);
449 /* populate a buffer variable that keeps the size of the screen for fast consultation. */
450 screenSize.x = 0;
451 screenSize.y = 0;
452 screenSize.w = screenwidth;
453 screenSize.h = screenheight;
455 return 0;
459 Graphics_PainterReset()
461 Neuro_CleanEBuf(&Raw);
462 Neuro_CleanEBuf(&Queue);
464 Neuro_CreateEBuf(&Raw);
465 Neuro_CreateEBuf(&Queue);
467 first_element = NULL;
468 last_element = NULL;
470 return 0;
473 void
474 Graphics_PainterClean()
476 Debug_Val(0, "Raw total %d\n", Neuro_GiveEBufCount(Raw));
477 Debug_Val(0, "Queue total %d\n", Neuro_GiveEBufCount(Queue));
479 Neuro_CleanEBuf(&Raw);
480 Neuro_CleanEBuf(&Queue);
482 first_element = NULL;
483 last_element = NULL;