fixed jam-less builds; also, bye-bye, big-endians
[k8-i-v-a-n.git] / src / felib / graphics.cpp
blob337bf78efefb01f7c342d35faa68977d14ad6ef9
1 /*
3 * Iter Vehemens ad Necem (IVAN)
4 * Copyright (C) Timo Kiviluoto
5 * Released under the GNU General
6 * Public License
8 * See LICENSING which should be included
9 * along with this file for more details
12 #include <math.h>
14 #include "SDL.h"
16 #include "graphics.h"
17 #include "bitmap.h"
18 #include "whandler.h"
19 #include "error.h"
20 #include "rawbit.h"
23 void (*graphics::SwitchModeHandler) ();
25 SDL_Surface *graphics::Screen;
27 bitmap *graphics::DoubleBuffer;
28 v2 graphics::Res;
29 int graphics::ColorDepth;
30 rawbitmap *graphics::DefaultFont = 0;
32 truth dblRes = false;
33 truth origDblRes = false;
35 //#define DIVISOR (1.7)
36 float DIVISOR = 1.7;
39 static int fixVal (int v) { return (dblRes ? (int)(v*DIVISOR) : v); }
41 struct KIt {
42 float frc0, frc1, yfrc0, yfrc1;
43 int sofs[4];
47 KIt *kernel = 0;
48 unsigned char *bufc32 = 0;
50 static void freeKernel () {
51 if (kernel) { free(kernel); kernel = 0; }
55 static void buildKernel (int resx, int resy) {
56 KIt* res = (KIt*)malloc(fixVal(resy)*fixVal(resx)*sizeof(KIt));
57 for (int y = 0; y < fixVal(resy); ++y) {
58 for (int x = 0; x < fixVal(resx); ++x) {
59 KIt* i = res+y*fixVal(resx)+x;
60 float fx = x/DIVISOR;
61 float fy = y/DIVISOR;
62 float frc1 = fx-(int)fx;
63 float frc0 = 1.0-frc1;
64 float yfrc1 = fy-(int)fy;
65 float yfrc0 = 1.0-yfrc1;
66 i->frc0 = frc0;
67 i->frc1 = frc1;
68 i->yfrc0 = yfrc0;
69 i->yfrc1 = yfrc1;
70 //r[0] = (r[0]*frc0+r[1]*frc1)*yfrc0+(r[2]*frc0+r[3]*frc1)*yfrc1;
71 for (int dy = 0; dy < 2; ++dy) {
72 for (int dx = 0; dx < 2; ++dx) {
73 int sx = (int)(fx+dx);
74 int sy = (int)(fy+dy);
75 if (sx >= 0 && sy >= 0 && sx < resx && sy < resy) {
76 i->sofs[dy*2+dx] = sy*(resx*4)+sx*4;
77 } else {
78 i->sofs[dy*2+dx] = 0;
84 freeKernel();
85 kernel = res;
90 void graphics::Init () {
91 static truth AlreadyInstalled = false;
92 if (!AlreadyInstalled) {
93 AlreadyInstalled = true;
94 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE)) ABORT("Can't initialize SDL.");
95 atexit(graphics::DeInit);
100 void graphics::DeInit () {
101 delete DefaultFont;
102 DefaultFont = 0;
103 SDL_Quit();
107 void graphics::SetMode (cchar *Title, cchar *IconName, v2 NewRes, truth FullScreen, sLong adresmod) {
108 if (IconName) {
109 SDL_Surface *Icon = SDL_LoadBMP(IconName);
110 SDL_SetColorKey(Icon, SDL_SRCCOLORKEY, SDL_MapRGB(Icon->format, 255, 255, 255));
111 SDL_WM_SetIcon(Icon, NULL);
113 if (adresmod < 0) adresmod = 0; else if (adresmod > 10) adresmod = 10;
114 dblRes = (adresmod > 0);
115 if (adresmod == 10) DIVISOR = 2.0f; else DIVISOR = 1.0f+(adresmod/10.0f);
116 origDblRes = dblRes;
117 feuLong Flags = SDL_SWSURFACE;
118 if (FullScreen) {
119 SDL_ShowCursor(SDL_DISABLE);
120 Flags |= SDL_FULLSCREEN;
121 dblRes = false;
123 Screen = SDL_SetVideoMode(fixVal(NewRes.X), fixVal(NewRes.Y), /*16*/32, Flags);
124 if (!Screen) ABORT("Couldn't set video mode.");
125 if (dblRes) buildKernel(NewRes.X, NewRes.Y); else freeKernel();
126 bufc32 = (unsigned char*)realloc(bufc32, fixVal(NewRes.X)*fixVal(NewRes.Y)*4);
127 SDL_WM_SetCaption(Title, 0);
128 globalwindowhandler::Init();
129 DoubleBuffer = new bitmap(NewRes);
130 Res = NewRes;
131 ColorDepth = 32/*16*/;
135 static inline void toRGB (int* r, int* g, int* b, packcol16 c) {
136 if (b) *b = (c<<3)&0xff;
137 if (g) *g = ((c>>5)<<2)&0xff;
138 if (r) *r = ((c>>11)<<3)&0xff;
142 static inline packcol16 fromRGB (int r, int g, int b) {
143 if (r < 0) r = 0; else if (r > 255) r = 255;
144 if (g < 0) g = 0; else if (g > 255) g = 255;
145 if (b < 0) b = 0; else if (b > 255) b = 255;
146 packcol16 c = 0;
147 c |= (b>>3);
148 c |= (g>>2)<<5;
149 c |= (r>>3)<<11;
150 return c;
154 void graphics::BlitDBToScreen () {
155 if (SDL_MUSTLOCK(Screen) && SDL_LockSurface(Screen) < 0) ABORT("Can't lock screen");
156 const packcol16 *SrcPtr = DoubleBuffer->GetImage()[0];
158 const int newx = fixVal(Res.X);
159 const int newy = fixVal(Res.Y);
161 // convert source buffer
162 const packcol16 *sptr = SrcPtr;
163 uint32_t *dptr = (uint32_t*)bufc32;
164 for (int y = 0; y < newy; ++y) {
165 for (int x = 0; x < newx; ++x) {
166 packcol16 c = *sptr++;
167 unsigned char b = (c<<3)&0xff;
168 unsigned char g = ((c>>5)<<2)&0xff;
169 unsigned char r = ((c>>11)<<3)&0xff;
170 *dptr++ = b|(g<<8)|(r<<16);
174 unsigned char *DestPtr = static_cast<unsigned char*>(Screen->pixels);
175 feuLong ScreenYMove = Screen->pitch;
177 if (dblRes) {
178 if (DIVISOR != 2.0f) {
179 // copy converted buffer used kernel
180 unsigned char *curs = bufc32;
181 KIt *i = kernel;
182 for (int y = 0; y < newy; ++y) {
183 uint32_t *dp = (uint32_t*)DestPtr;
184 for (int x = 0; x < newx; ++x) {
185 uint32_t dclr = 0;
186 for (int n = 0; n < 3; ++n) {
187 int c = lrintf(curs[i->sofs[0]+n]*i->frc0+curs[i->sofs[1]+n]*i->frc1)*i->yfrc0+(curs[i->sofs[2]+n]*i->frc0+curs[i->sofs[3]+n]*i->frc1)*i->yfrc1;
188 //if (c < 0) c = 0; else if (c > 255) c = 255;
189 //dclr |= (c<<(n*8));
190 dclr |= ((c&0xff)|(255-((-(int)(c < 256))>>24)))<<(n*8); //K8 WARNING! ABSOLUTELY NON-PORTABLE AND CAUSES UB!
192 *dp++ = dclr;
193 ++i;
195 DestPtr += ScreenYMove;
197 } else {
198 for (int y = 0; y < Res.Y; ++y, DestPtr += ScreenYMove) {
199 uint32_t *s = (uint32_t*)(bufc32+y*(Res.X*4));
200 uint32_t *d = (uint32_t*)(DestPtr);
201 for (int x = 0; x < Res.X; ++x) { *d++ = *s; *d++ = *s++; }
202 DestPtr += ScreenYMove;
203 memcpy(DestPtr, bufc32+y*(Res.X*4), Res.X*4*2);
206 } else {
207 for (int y = 0; y < Res.Y; ++y, DestPtr += ScreenYMove) {
208 uint32_t *s = (uint32_t*)(bufc32+y*(Res.X*4));
209 memcpy(DestPtr, s, Res.X*4);
212 if (SDL_MUSTLOCK(Screen)) SDL_UnlockSurface(Screen);
213 SDL_UpdateRect(Screen, 0, 0, fixVal(Res.X), fixVal(Res.Y));
217 void graphics::SwitchMode () {
218 feuLong Flags;
219 if (Screen->flags & SDL_FULLSCREEN) {
220 SDL_ShowCursor(SDL_ENABLE);
221 Flags = SDL_SWSURFACE;
222 dblRes = origDblRes;
223 } else {
224 SDL_ShowCursor(SDL_DISABLE);
225 Flags = SDL_SWSURFACE|SDL_FULLSCREEN;
226 dblRes = false;
228 if (SwitchModeHandler) SwitchModeHandler();
229 Screen = SDL_SetVideoMode(fixVal(Res.X), fixVal(Res.Y), ColorDepth, Flags);
230 if (!Screen) ABORT("Couldn't toggle fullscreen mode.");
231 if (dblRes) buildKernel(Res.X, Res.Y); else freeKernel();
232 bufc32 = (unsigned char*)realloc(bufc32, fixVal(Res.X)*fixVal(Res.Y)*4);
233 BlitDBToScreen();
237 void graphics::ReinitMode (sLong adresmod) {
238 if (adresmod < 0) adresmod = 0; else if (adresmod > 10) adresmod = 10;
239 dblRes = (adresmod > 0);
240 if (adresmod == 10) DIVISOR = 2.0f; else DIVISOR = 1.0f+(adresmod/10.0f);
241 origDblRes = dblRes;
243 feuLong Flags;
244 if (Screen->flags&SDL_FULLSCREEN) {
245 dblRes = false;
246 //Flags = SDL_SWSURFACE|SDL_FULLSCREEN;
247 return; // nothing to do here, really
249 Flags = SDL_SWSURFACE;
251 Screen = SDL_SetVideoMode(fixVal(Res.X), fixVal(Res.Y), ColorDepth, Flags);
252 if (dblRes) buildKernel(Res.X, Res.Y); else freeKernel();
253 bufc32 = (unsigned char*)realloc(bufc32, fixVal(Res.X)*fixVal(Res.Y)*4);
254 BlitDBToScreen();
258 void graphics::LoadDefaultFont (cfestring &FileName) {
259 DefaultFont = new rawbitmap(FileName);