3 * libneuro, a light weight abstraction of high or lower libraries
4 * and toolkit for applications.
5 * Copyright (C) 2005-2006 Nicholas Niro, Robert Lemay
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 * contains all the "useful" or used functions by the engines.
24 * those functions are called by calling a tertiarry function which will
25 * be the same for all the graphics/sound/... libraries. The idea of this
26 * way is to provide an uniform way to implement other libraries(Library Abstraction Layer).
27 * functions which can be used for different libraries will be of the module
28 * Low_. example : Low_Init(). Only one library can be used at a time.
29 * Options also will have to be set expetially for the initialisation functions.
30 * Im not sure how exactly we should do it yet.
34 /* #include <endian.h> */
39 #include <neuro/graphics.h>
40 #include <neuro/extlib.h>
41 #include <neuro/other.h>
43 /* freetype includes */
45 #include FT_FREETYPE_H
48 /* SDL variable types used
51 * SDL_Surface -> v_object
59 * SDL_UpdateRect -> Lib_UpdateRect
60 * SDL_BlitSurface -> Lib_BlitObject
61 * SDL_FillRect -> Lib_FillRect
62 * SDL_Flip -> Lib_Flip
63 * SDL_SetVideoMode -> Lib_VideoInit
64 * SDL_CreateRGBSurface ->
65 * SDL_FreeSurface -> Lib_FreeVobject
68 * SDL_GetKeyState -> Lib_GetKeyState
69 * SDL_GetMouseState -> Lib_GetMouseState
72 typedef struct options_list
74 u32 Xsize
, Ysize
; /* screen size */
75 u8 bpp
; /* bytes per pixel */
76 u32 Primary_screen_flags
; /* flags for the primary screen */
77 u32 Secondary_screen_flags
; /* flags for the secondary (buffer) screen */
81 static options_list options
= {
87 static u8 mouse_wheel
= 0; /* mouse wheel variable */
89 static FT_Library font_lib
;
92 Lib_SetScreenSize(u32 width
, u32 height
)
94 options
.Xsize
= width
;
95 options
.Ysize
= height
;
99 Lib_GetScreenSize(u32
*width
, u32
*height
)
101 *width
= options
.Xsize
;
102 *height
= options
.Ysize
;
105 /* video constructor destructor */
107 Lib_VideoInit(v_object
**screen
, v_object
**screen_buf
)
110 SDL_Surface
*temp1
= NULL
, *temp2
= NULL
;
112 _err_
= SDL_Init(SDL_INIT_VIDEO
);
116 Error_Print("SDL_Init failure");
120 temp1
= SDL_SetVideoMode(options
.Xsize
, options
.Ysize
, options
.bpp
, options
.Primary_screen_flags
);
123 Error_Print("SDL_SetVideoMode failure");
129 u32 Rmask
, Gmask
, Bmask
, Amask
;
131 #if __BYTE_ORDER == __LITTLE_ENDIAN
136 #endif /* __BYTE_ORDER == __LITTLE_ENDIAN */
138 #if __BYTE_ORDER == __BIG_ENDIAN
143 #endif /* __BYTE_ORDER == __BIG_ENDIAN */
145 #if __BYTE_ORDER == __PDP_ENDIAN
150 #endif /* __BYTE_ORDER == __PDP_ENDIAN */
152 /*temp2 = SDL_CreateRGBSurface(options.Secondary_screen_flags, options.Xsize, options.Ysize, options.bpp, Rmask, Gmask, Bmask, Amask);*/
153 temp2
= (SDL_Surface
*)Lib_CreateVObject(options
.Secondary_screen_flags
, options
.Xsize
, options
.Ysize
, options
.bpp
, temp1
->format
->Rmask
, temp1
->format
->Gmask
, temp1
->format
->Bmask
, temp1
->format
->Amask
);
157 Error_Print("Lib_CreateVObject failure");
168 Lib_BlitObject(v_object
*source
, Rectan
*src
, v_object
*destination
, Rectan
*dst
)
170 if (!source
|| !destination
)
173 SDL_BlitSurface((SDL_Surface
*)source
, (SDL_Rect
*)src
, (SDL_Surface
*)destination
, (SDL_Rect
*)dst
);
177 Lib_SyncPixels(v_object
*src
)
183 stdio_seek(SDL_RWops
*context
, int offset
, int whence
)
186 return gzseek(context
->hidden
.stdio
.fp
, offset
, whence
);
188 if ( gzseek(context->hidden.stdio.fp, offset, whence) == 0 )
190 return(gztell(context->hidden.stdio.fp));
194 SDL_Error(SDL_EFSEEK);
201 stdio_read(SDL_RWops
*context
, void *ptr
, int size
, int maxnum
)
205 /* nread = fread(ptr, size, maxnum, context->hidden.stdio.fp); */
208 nread
= gzread(context
->hidden
.stdio
.fp
, ptr
, maxnum
);
216 nread
= gzread(context
->hidden
.stdio
.fp
, &buf
[0], maxnum
);
217 nread
+= gzread(context
->hidden
.stdio
.fp
, &buf
[1], maxnum
);
226 nread
= gzread(context
->hidden
.stdio
.fp
, &buf
[0], maxnum
);
227 nread
+= gzread(context
->hidden
.stdio
.fp
, &buf
[1], maxnum
);
228 nread
+= gzread(context
->hidden
.stdio
.fp
, &buf
[2], maxnum
);
229 nread
+= gzread(context
->hidden
.stdio
.fp
, &buf
[3], maxnum
);
232 /*Debug_Val(0, "asked for size %d maxnum %d -- read %d\n",
233 size, maxnum, nread);*/
236 SDL_Error(SDL_EFREAD
);
241 /* this won't be needed, we don't actually want to write
245 stdio_write(SDL_RWops
*context
, const void *ptr
, int size
, int num
)
249 nwrote
= fwrite(ptr
, size
, num
, context
->hidden
.stdio
.fp
);
250 if ( nwrote
== 0 && ferror(context
->hidden
.stdio
.fp
) ) {
251 SDL_Error(SDL_EFWRITE
);
257 stdio_close(SDL_RWops
*context
)
260 if ( context
->hidden
.stdio
.autoclose
) {
261 /* WARNING: Check the return value here! */
262 /* fclose(context->hidden.stdio.fp); */
263 gzclose(context
->hidden
.stdio
.fp
);
272 Lib_LoadBMP(const char *path
, v_object
**img
)
278 fp
= gzopen(path
, "rb");
286 ops
->seek
= stdio_seek
;
287 ops
->read
= stdio_read
;
288 ops
->write
= stdio_write
;
289 ops
->close
= stdio_close
;
290 ops
->hidden
.stdio
.fp
= fp
;
291 ops
->hidden
.stdio
.autoclose
= 1;
293 *img
= SDL_LoadBMP_RW(ops
, 1);
297 Debug_Val(0, "Unable to load image \"%s\" SDL says : %s\n", path
, SDL_GetError());
303 #else /* NOT USE_ZLIB */
304 *img
= SDL_LoadBMP(path
);
305 #endif /* NOT USE_ZLIB */
309 Lib_LoadBMPBuffer(void *data
, v_object
**img
)
320 ops
->seek
= stdio_seek
;
321 ops
->read
= stdio_read
;
322 ops
->write
= stdio_write
;
323 ops
->close
= stdio_close
;
324 /*ops->hidden.stdio.fp = fp;
325 ops->hidden.stdio.autoclose = 1;*/
326 ops
->hidden
.unknown
.data1
= data
;
328 *img
= SDL_LoadBMP_RW(ops
, 1);
332 Debug_Val(0, "Unable to load buffer image SDL says : %s\n", SDL_GetError());
337 findColor(SDL_Palette
*pal
, u8 r
, u8 g
, u8 b
)
339 /* Do colorspace distance matching */
347 for ( i
=0; i
<pal
->ncolors
; ++i
)
349 rd
= pal
->colors
[i
].r
- r
;
350 gd
= pal
->colors
[i
].g
- g
;
351 bd
= pal
->colors
[i
].b
- b
;
352 distance
= (rd
*rd
)+(gd
*gd
)+(bd
*bd
);
353 if ( distance
< smallest
)
356 if ( distance
== 0 ) /* Perfect match! */
365 Lib_RenderUnicode(font_object
*ttf
, u32 size
, u32 character
, i16
*x
, i16
*y
, u32 color
, Rectan
*src
, Rectan
*dst
)
368 static u32 expect
= 0;
369 static u32 codepoint
= 0;
370 v_object
*output
= NULL
;
373 /* XImage *mask_data = NULL; */
381 /* our first pick for the background is pure pink */
382 bg_color
= Neuro_MapRGB(255, 0, 255);
384 /* in case the fancy of the external program
385 * is having pure pink color fonts (heh it can happen)
386 * we make the background color to pure black.
388 if (bg_color
== color
)
389 bg_color
= Neuro_MapRGB(0, 0, 0);
391 if (character
== ' ')
401 _err
= FT_Select_Charmap(face
, FT_ENCODING_UNICODE
);
404 Error_Print("Couldn't select the encoding unicode");
408 _err
= FT_Set_Char_Size(face
, size
* 64, size
* 64, 72, 72);
411 Error_Print("Couldn't set face character size");
415 /* support for multi bytes characters */
416 if (character
>= 0xC0)
418 if (character
< 0xE0)
420 codepoint
= character
& 0x1F;
423 else if (character
< 0xF0)
425 codepoint
= character
& 0x0F;
428 else if (character
< 0xF8)
430 codepoint
= character
& 0x07;
435 else if (character
>= 0x80)
442 codepoint
+= character
& 0x3F;
451 codepoint
= character
;
453 _err
= FT_Load_Char(face
, codepoint
, FT_LOAD_RENDER
| FT_LOAD_MONOCHROME
);
454 /* _err = FT_Load_Char(face, character, FT_LOAD_MONOCHROME); */
458 Error_Print("Couldn't load character");
465 FT_BitmapGlyph bitmap
;
468 Neuro_GiveConvertRGB(color
, &R
, &G
, &B
);
470 if (face
->glyph
->format
!= FT_GLYPH_FORMAT_BITMAP
)
472 Debug_Print("Unknown non bitmap format");
475 /*if (face->glyph->format == FT_GLYPH_FORMAT_BITMAP)
477 Debug_Print("Bitmap format");
481 Debug_Print("Unknown non bitmap format");
485 /* Debug_Val(0, "font size %dx%d\n", face->glyph->bitmap.width,
486 face->glyph->bitmap.rows); */
489 /* allocate the surface */
490 output
= Lib_CreateVObject(0, face
->glyph
->bitmap
.width
,
491 face
->glyph
->bitmap
.rows
, 16, 0, 0, 0, 0);
494 bitmap
= (FT_BitmapGlyph
)face
->glyph
;
499 screen
= Neuro_GetScreenBuffer();
503 Lib_SyncPixels(output
);
505 Lib_LockVObject(output
);
510 /* create the mask */
512 mask_data = CreateMask(output, face->glyph->bitmap.width, face->glyph->bitmap.rows);
517 if (face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_GRAY
&& !space_char
)
519 while (row
< face
->glyph
->bitmap
.rows
)
523 while (pixel
< face
->glyph
->bitmap
.width
)
527 if ((gray
= face
->glyph
->bitmap
.buffer
[(row
* face
->glyph
->bitmap
.pitch
) + pixel
]))
532 tx
= (*x
+ pixel
) + face
->glyph
->metrics
.horiBearingX
/ 64;
533 ty
= (*y
+ row
) - face
->glyph
->metrics
.horiBearingY
/ 64;
535 /*Debug_Val(0, "tcolor %d rcolor %d alpha %d\n", tcolor,
537 tcolor
= Lib_GetPixel(screen
, tx
, ty
);
538 rcolor
= AlphaPixels(color
, tcolor
, (double)(256 - gray
));
539 Lib_PutPixel(screen
, tx
, ty
, rcolor
);
544 /* if (character == 'X')
551 if (character
== 'X')
556 #endif /* alpha_fonts */
558 if (face
->glyph
->bitmap
.pixel_mode
== FT_PIXEL_MODE_MONO
&& !space_char
)
566 bm
= face
->glyph
->bitmap
.buffer
;
569 if (IsLittleEndian())
593 while (row
< face
->glyph
->bitmap
.rows
)
599 /* tx = (*x + pixel) + face->glyph->metrics.horiBearingX / 64;
600 ty = (*y + row) - face->glyph->metrics.horiBearingY / 64; */
601 /* tx = pixel + face->glyph->metrics.horiBearingX / 64;
602 ty = row - face->glyph->metrics.horiBearingY / 64;*/
608 /* Debug_Val(0, "dot at (%d,%d)\n", tx, ty); */
609 Lib_PutPixel(output
, tx
, ty
, color
);
614 /* the background pixels... we will
615 * make the pixels of this color
618 Lib_PutPixel(output
, tx
, ty
, bg_color
);
622 if (pixel
>= face
->glyph
->bitmap
.width
- 1)
627 rstart
+= face
->glyph
->bitmap
.pitch
;
645 src
->w
= face
->glyph
->bitmap
.width
;
646 src
->h
= face
->glyph
->bitmap
.rows
;
648 dst
->x
= *x
+ face
->glyph
->metrics
.horiBearingX
/ 64;
649 dst
->y
= (size
+ *y
) - face
->glyph
->metrics
.horiBearingY
/ 64;
655 if (obj
&& mask_data
)
657 /* copy the mask data (for transparency) to the V_OBJECT
658 * shapemask variable properly.
660 CreatePixmap(mask_data
, *obj
->cwin
, &obj
->shapemask
);
662 /* we no longer need the mask_data variable, it got copied
663 * to the good place so we destroy it.
665 XDestroyImage(mask_data
);
667 #endif /* font_mask XXX */
669 /* we will need to call the function Lib_SetColorKey
670 * which will itself generate the transparency
673 Lib_SetColorKey(output
, bg_color
);
676 *x
= *x
+ face
->glyph
->metrics
.horiAdvance
/ 64;
677 /* *y = *y + face->glyph->metrics.vertAdvance / 64; */
680 Lib_UnlockVObject(output
);
687 Lib_MapRGB(v_object
*vobj
, u8 r
, u8 g
, u8 b
)
690 SDL_PixelFormat
*fmt
;
692 temp
= (SDL_Surface
*)vobj
;
697 if ( fmt
->palette
== NULL
)
701 return (r
>> fmt
->Rloss
) << fmt
->Rshift
| (g
>> fmt
->Gloss
) << fmt
->Gshift
| (b
>> fmt
->Bloss
) << fmt
->Bshift
| fmt
->Amask
;
705 return (r
<< fmt
->Rloss
) >> fmt
->Rshift
| (g
<< fmt
->Gloss
) >> fmt
->Gshift
| (b
<< fmt
->Bloss
) >> fmt
->Bshift
| fmt
->Amask
;
710 return findColor(fmt
->palette
, r
, g
, b
);
714 return Neuro_GiveRGB(r
, g
, b
);
719 Lib_SetColorKey(v_object
*vobj
, u32 key
)
724 SDL_SetColorKey((SDL_Surface
*)vobj
, SDL_SRCCOLORKEY
| SDL_RLEACCEL
, key
);
728 Lib_SetAlpha(v_object
*vobj
, u8 alpha
)
733 SDL_SetAlpha((SDL_Surface
*)vobj
, SDL_SRCALPHA
| SDL_RLEACCEL
, alpha
);
737 Lib_CreateVObject(u32 flags
, i32 width
, i32 height
, i32 depth
, u32 Rmask
, u32 Gmask
,
738 u32 Bmask
, u32 Amask
)
740 return (v_object
*)SDL_CreateRGBSurface(flags
, width
, height
, depth
, Rmask
, Gmask
, Bmask
, Amask
);
744 Lib_UpdateRect(v_object
*source
, Rectan
*src
)
750 SDL_UpdateRect((SDL_Surface
*)source
, src
->x
, src
->y
, src
->w
, src
->h
);
752 SDL_UpdateRect((SDL_Surface
*)source
, 0, 0, 0, 0);
756 Lib_GetPixel(v_object
*srf
, int x
, int y
)
765 Lib_LockVObject(srf
);
767 Lib_GetVObjectData(srf
, NULL
, NULL
, NULL
, &pitch
, &pixels
, NULL
, &bpp
,
768 NULL
, NULL
, NULL
, NULL
);
770 /* bpp = surface->format->BytesPerPixel; */
771 /* Here p is the address to the pixel we want to retrieve */
772 /* p = (u8 *)surface->pixels + y * surface->pitch + x * bpp; */
773 p
= (u8
*)pixels
+ y
* pitch
+ x
* bpp
;
781 /* err = *(u16 *)p; */
793 if(SDL_BYTEORDER
== SDL_BIG_ENDIAN
)
794 err
= p
[0] << 16 | p
[1] << 8 | p
[2];
796 err
= p
[0] | p
[1] << 8 | p
[2] << 16;
808 err
= 0; /* shouldn't happen, but avoids warnings */
812 Lib_UnlockVObject(srf
);
819 Lib_PutPixel(v_object
*srf
, int x
, int y
, u32 pixel
)
821 /* SDL_Surface *surface = (SDL_Surface*)srf; */
822 /* SDL_LockSurface(surface); */
828 Lib_GetVObjectData(srf
, NULL
, NULL
, NULL
, &pitch
, &pixels
, NULL
, &bpp
,
829 NULL
, NULL
, NULL
, NULL
);
831 /* Lib_LockVObject(srf); */
832 /* int bpp = surface->format->BytesPerPixel; */
833 /* Here p is the address to the pixel we want to set */
834 /* p = (u8*)surface->pixels + y * surface->pitch + x * bpp; */
835 p
= (u8
*)pixels
+ y
* pitch
+ x
* bpp
;
853 if(SDL_BYTEORDER
== SDL_BIG_ENDIAN
)
855 p
[0] = (pixel
>> 16) & 0xff;
856 p
[1] = (pixel
>> 8) & 0xff;
862 p
[1] = (pixel
>> 8) & 0xff;
863 p
[2] = (pixel
>> 16) & 0xff;
875 /* SDL_UnlockSurface(surface); */
876 /* Lib_UnlockVObject(srf); */
880 Lib_FillRect(v_object
*source
, Rectan
*src
, u32 color
)
882 SDL_FillRect((SDL_Surface
*)source
, (SDL_Rect
*)src
, color
);
886 Lib_Flip(v_object
*source
)
888 SDL_Flip((SDL_Surface
*)source
);
889 /* Lib_UpdateRect(source, 0); */
893 Lib_FreeVobject(v_object
*source
)
897 temp
= (SDL_Surface
*)source
;
904 if (temp->format->palette)
906 if (temp->format->palette->colors)
907 free(temp->format->palette->colors);
909 free(temp->format->palette);
921 /* free(temp); */ /* we'll let SDL_FreeSurface this job... hope it does it ;P */
924 /* poor SDL needs a third support, see above. This is concerning mem leaks in
925 * the poor SDL free surface function.
927 SDL_FreeSurface((SDL_Surface
*)source
);
931 /* this function will become obsolete soon */
933 Lib_GiveVobjectProp(v_object
*source
, Rectan
*output
)
937 temp
= (SDL_Surface
*)source
;
946 Lib_LockVObject(v_object
*vobj
)
948 SDL_LockSurface((SDL_Surface
*)vobj
);
952 Lib_UnlockVObject(v_object
*vobj
)
954 SDL_UnlockSurface((SDL_Surface
*)vobj
);
958 Lib_GetDefaultDepth()
960 return 16; /* TEMPORARY please make get the real value from somewhere!!! TODO TODO */
965 Lib_LoadFontFile(char *fonts_file_path
)
970 _err
= FT_New_Face(font_lib
, fonts_file_path
, 0, &face
);
981 Lib_CleanFont(font_object
*font
)
989 return FT_Init_FreeType(&font_lib
);
995 FT_Done_FreeType(font_lib
);
1000 Lib_GetVObjectData(v_object
*vobj
, u32
*flags
, i32
*h
, i32
*w
, u32
*pitch
,
1001 void **pixels
, Rectan
**clip_rect
, u8
*bpp
,
1002 u32
*Rmask
, u32
*Gmask
, u32
*Bmask
,u32
*Amask
)
1004 SDL_Surface
*srf
= (SDL_Surface
*)vobj
;
1007 *flags
= srf
->flags
;
1014 *pitch
= srf
->pitch
;
1016 *pixels
= srf
->pixels
;
1018 *clip_rect
= (Rectan
*)&srf
->clip_rect
;
1020 *bpp
= srf
->format
->BytesPerPixel
;
1022 *Rmask
= srf
->format
->Rmask
;
1024 *Gmask
= srf
->format
->Gmask
;
1026 *Bmask
= srf
->format
->Bmask
;
1028 *Amask
= srf
->format
->Amask
;
1038 /*----------------- Input Events -----------------*/
1041 Lib_GetKeyState(i32
*numkeys
)
1043 return SDL_GetKeyState(numkeys
);
1047 Lib_CheckKeyStatus(u32 key
)
1051 keyd
= SDL_GetKeyState(NULL
);
1064 while(SDL_PollEvent(&event
))
1076 Lib_GetMouseState(i32
*x
, i32
*y
)
1080 value
= SDL_BUTTON(SDL_GetMouseState(x
, y
));
1082 /* to fix what appears to be a bug... might
1083 * be a cheap hack... but it works :)
1088 if (mouse_wheel
&& value
== 0)
1090 value
= mouse_wheel
;
1098 Lib_PollEvent(void *s_event
)
1103 while(SDL_PollEvent(&event
))
1107 case SDL_MOUSEBUTTONDOWN
:
1109 if (event
.button
.button
== SDL_BUTTON_WHEELUP
1110 || event
.button
.button
== SDL_BUTTON_WHEELDOWN
)
1112 mouse_wheel
= event
.button
.button
;
1128 /* nothing needed, done in the video init */
1135 /* nothing needed, done in the video exit */