moved almost all hardcoded constants to "define.dat"
[k8-i-v-a-n.git] / src / felib / graphics.cpp
blob18099e5dba17de24a93b3a45226f0ff066d6216e
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 #ifndef DISABLE_OPENGL
15 # include <GL/gl.h>
16 #endif
18 #include "SDL.h"
20 #include "graphics.h"
21 #include "bitmap.h"
22 #include "whandler.h"
23 #include "feerror.h"
24 #include "rawbit.h"
26 #if !defined(DISABLE_SOUND) && defined(ENABLE_ALSA)
27 # include <alsa/asoundlib.h>
28 // shut the fuck up, alsa!
30 static void alsa_message_fucker (const char *file, int line, const char *function_, int err, const char *fmt, ...) {}
32 void fuck_alsa_messages () {
33 snd_lib_error_set_handler(&alsa_message_fucker);
35 #else
36 void fuck_alsa_messages () {}
37 #endif
40 void (*graphics::SwitchModeHandler) ();
42 SDL_Surface *graphics::Screen;
44 bitmap *graphics::DoubleBuffer;
45 v2 graphics::Res;
46 int graphics::ColorDepth;
47 rawbitmap *graphics::DefaultFont = 0;
49 int graphics::curx = -666;
50 int graphics::cury = -666;
51 int graphics::curvisible = 0;
54 CursorState::CursorState (int ax, int ay, int avis, int newx, int newy, truth newvis) { x = ax; y = ay; vis = avis; graphics::curx = newx; graphics::cury = newy; if (newvis) graphics::showCursor(); else graphics::hideCursor(); }
55 CursorState::CursorState (int ax, int ay, int avis, int newx, int newy) { x = ax; y = ay; vis = avis; graphics::curx = newx; graphics::cury = newy; }
56 CursorState::CursorState (int ax, int ay, int avis, truth newvis) { x = ax; y = ay; vis = avis; if (newvis) graphics::showCursor(); else graphics::hideCursor(); }
57 CursorState::~CursorState () { if (vis != -666) { graphics::curx = x; graphics::cury = y; graphics::curvisible = vis; } }
60 static truth dblRes = false;
61 static truth origDblRes = false;
62 static uint8_t *bufc32 = 0;
64 //#define DIVISOR (1.7)
65 static float DIVISOR = 1.7;
68 static int fixVal (int v) { return (dblRes ? (int)(v*DIVISOR) : v); }
71 #ifndef DISABLE_OPENGL
72 static GLuint maintid = 0;
75 static void killTexture () {
76 if (maintid != 0) {
77 glDeleteTextures(1, &maintid);
78 maintid = 0;
83 void graphics::createTexture () {
84 glGenTextures(1, &maintid);
85 if (maintid == 0) ABORT("Couldn't create OpenGL texture.");
87 //GLint gltextbinding;
88 //glGetIntegerv(GL_TEXTURE_BINDING_2D, &gltextbinding);
89 //scope(exit) glBindTexture(GL_TEXTURE_2D, gltextbinding);
91 glBindTexture(GL_TEXTURE_2D, maintid);
92 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
93 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
96 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
97 //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
99 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Res.X, Res.Y, 0, /*GL_RGBA*/GL_RGBA, GL_UNSIGNED_BYTE, NULL); // this inits texture
103 #else
105 struct KIt {
106 float frc0, frc1, yfrc0, yfrc1;
107 int sofs[4];
110 static KIt *kernel = 0;
112 #endif
115 static void buildKernel (int resx, int resy) {
116 bufc32 = (uint8_t*)realloc(bufc32, resx*resy*4);
117 #ifdef DISABLE_OPENGL
118 if (fixVal(resx) == resx && fixVal(resy) == resy) return;
119 // build kernel
120 KIt* res = (KIt*)realloc(kernel, fixVal(resy)*fixVal(resx)*sizeof(KIt));
121 for (int y = 0; y < fixVal(resy); ++y) {
122 for (int x = 0; x < fixVal(resx); ++x) {
123 KIt* i = res+y*fixVal(resx)+x;
124 float fx = x/DIVISOR;
125 float fy = y/DIVISOR;
126 float frc1 = fx-(int)fx;
127 float frc0 = 1.0-frc1;
128 float yfrc1 = fy-(int)fy;
129 float yfrc0 = 1.0-yfrc1;
130 i->frc0 = frc0;
131 i->frc1 = frc1;
132 i->yfrc0 = yfrc0;
133 i->yfrc1 = yfrc1;
134 //r[0] = (r[0]*frc0+r[1]*frc1)*yfrc0+(r[2]*frc0+r[3]*frc1)*yfrc1;
135 for (int dy = 0; dy < 2; ++dy) {
136 for (int dx = 0; dx < 2; ++dx) {
137 int sx = (int)(fx+dx);
138 int sy = (int)(fy+dy);
139 if (sx >= 0 && sy >= 0 && sx < resx && sy < resy) {
140 i->sofs[dy*2+dx] = sy*(resx*4)+sx*4;
141 } else {
142 i->sofs[dy*2+dx] = 0;
148 kernel = res;
149 #endif
153 void graphics::Init () {
154 static truth AlreadyInstalled = false;
155 if (!AlreadyInstalled) {
156 AlreadyInstalled = true;
157 if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE)) ABORT("Can't initialize SDL.");
158 atexit(graphics::DeInit);
163 void graphics::DeInit () {
164 #ifndef DISABLE_OPENGL
165 killTexture();
166 #endif
167 delete DefaultFont;
168 DefaultFont = 0;
169 SDL_Quit();
173 void graphics::SetMode (cchar *Title, cchar *IconName, v2 NewRes, truth FullScreen, sLong adresmod) {
174 if (IconName) {
175 SDL_Surface *Icon = SDL_LoadBMP(IconName);
176 SDL_SetColorKey(Icon, SDL_SRCCOLORKEY, SDL_MapRGB(Icon->format, 255, 255, 255));
177 SDL_WM_SetIcon(Icon, NULL);
180 if (adresmod < 0) adresmod = 0; else if (adresmod > 10) adresmod = 10;
181 dblRes = (adresmod > 0);
182 if (adresmod == 10) DIVISOR = 2.0f; else DIVISOR = 1.0f+(adresmod/10.0f);
183 origDblRes = dblRes;
184 feuLong Flags = 0;
186 if (FullScreen) {
187 SDL_ShowCursor(SDL_DISABLE);
188 Flags |= SDL_FULLSCREEN;
189 dblRes = false;
192 #ifndef DISABLE_OPENGL
193 Flags |= SDL_OPENGL;
194 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
195 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
196 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
197 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
198 //SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
199 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
200 killTexture();
201 #else
202 Flags |= SDL_SWSURFACE;
203 #endif
205 Screen = SDL_SetVideoMode(fixVal(NewRes.X), fixVal(NewRes.Y), /*16*/32, Flags);
206 if (!Screen) ABORT("Couldn't set video mode.");
207 SDL_WM_SetCaption(Title, 0);
208 globalwindowhandler::Init();
209 DoubleBuffer = new bitmap(NewRes);
210 Res = NewRes;
211 ColorDepth = 32/*16*/;
212 fuck_alsa_messages();
213 buildKernel(NewRes.X, NewRes.Y);
215 #ifndef DISABLE_OPENGL
216 createTexture();
217 #endif
221 #if 0
222 static inline void toRGB (int* r, int* g, int* b, packcol16 c) {
223 if (b) *b = (c<<3)&0xff;
224 if (g) *g = ((c>>5)<<2)&0xff;
225 if (r) *r = ((c>>11)<<3)&0xff;
229 static inline packcol16 fromRGB (int r, int g, int b) {
230 if (r < 0) r = 0; else if (r > 255) r = 255;
231 if (g < 0) g = 0; else if (g > 255) g = 255;
232 if (b < 0) b = 0; else if (b > 255) b = 255;
233 packcol16 c = 0;
234 c |= (b>>3);
235 c |= (g>>2)<<5;
236 c |= (r>>3)<<11;
237 return c;
239 #endif
242 void graphics::gotoXY (int cx, int cy) {
243 curx = cx;
244 cury = cy;
248 bool graphics::isCursorVisible () { return (curvisible > 0); }
249 void graphics::showCursor () { ++curvisible; }
250 void graphics::hideCursor () { --curvisible; }
252 CursorState graphics::getCursorState () { return CursorState(curx, cury, curvisible); }
253 CursorState graphics::getCursorState (int newx, int newy, truth newvis) { return CursorState(curx, cury, curvisible, newx, newy, newvis); }
254 CursorState graphics::getCursorState (int newx, int newy) { return CursorState(curx, cury, curvisible, newx, newy); }
255 CursorState graphics::getCursorState (truth newvis) { return CursorState(curx, cury, curvisible, newvis); }
258 void graphics::BlitDBToScreen () {
259 const packcol16 *SrcPtr = DoubleBuffer->GetImage()[0];
260 const int newx = fixVal(Res.X);
261 const int newy = fixVal(Res.Y);
263 // convert source buffer
264 const packcol16 *sptr = SrcPtr;
265 uint32_t *dptr = (uint32_t*)bufc32;
266 for (int y = 0; y < Res.Y; ++y) {
267 for (int x = 0; x < Res.X; ++x) {
268 packcol16 c = *sptr++;
269 unsigned char b = (c<<3)&0xff;
270 unsigned char g = ((c>>5)<<2)&0xff;
271 unsigned char r = ((c>>11)<<3)&0xff;
272 *dptr++ = b|(g<<8)|(r<<16);
276 if (curvisible > 0 && curx >= -7 && cury >= 0 && curx+8 <= Res.X && cury < Res.Y) {
277 truth curhi = (SDL_GetTicks()%1200 < 600);
278 dptr = (uint32_t*)bufc32;
279 dptr += cury*Res.X;
280 if (curx >= 0) dptr += curx;
281 for (int x = curx; x < curx+8; ++x) {
282 if (x >= 0 && x < Res.X) *dptr++ = (curhi ? 0xffffff : 0x7f7f7f);
286 #if DISABLE_OPENGL
287 if (SDL_MUSTLOCK(Screen) && SDL_LockSurface(Screen) < 0) ABORT("Can't lock screen");
289 unsigned char *DestPtr = static_cast<unsigned char*>(Screen->pixels);
290 feuLong ScreenYMove = Screen->pitch;
292 if (dblRes) {
293 if (DIVISOR != 2.0f) {
294 // copy converted buffer used kernel
295 unsigned char *curs = bufc32;
296 KIt *i = kernel;
297 for (int y = 0; y < newy; ++y) {
298 uint32_t *dp = (uint32_t*)DestPtr;
299 for (int x = 0; x < newx; ++x) {
300 uint32_t dclr = 0;
301 for (int n = 0; n < 3; ++n) {
302 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;
303 //if (c < 0) c = 0; else if (c > 255) c = 255;
304 //dclr |= (c<<(n*8));
305 dclr |= ((c&0xff)|(255-((-(int)(c < 256))>>24)))<<(n*8); //K8 WARNING! ABSOLUTELY NON-PORTABLE AND CAUSES UB!
307 *dp++ = dclr;
308 ++i;
310 DestPtr += ScreenYMove;
312 } else {
313 for (int y = 0; y < Res.Y; ++y, DestPtr += ScreenYMove) {
314 uint32_t *s = (uint32_t*)(bufc32+y*(Res.X*4));
315 uint32_t *d = (uint32_t*)(DestPtr);
316 for (int x = 0; x < Res.X; ++x) { *d++ = *s; *d++ = *s++; }
317 DestPtr += ScreenYMove;
318 memcpy(DestPtr, bufc32+y*(Res.X*4), Res.X*4*2);
321 } else {
322 for (int y = 0; y < Res.Y; ++y, DestPtr += ScreenYMove) {
323 uint32_t *s = (uint32_t*)(bufc32+y*(Res.X*4));
324 memcpy(DestPtr, s, Res.X*4);
327 if (SDL_MUSTLOCK(Screen)) SDL_UnlockSurface(Screen);
328 SDL_UpdateRect(Screen, 0, 0, fixVal(Res.X), fixVal(Res.Y));
329 #else
330 if (maintid == 0) ABORT("OpenGL not initialized.");
332 glMatrixMode(GL_PROJECTION); // for ortho camera
333 glLoadIdentity();
334 glOrtho(0, newx, newy, 0, -1, 1); // top-to-bottom
336 glViewport(0, 0, newx, newy);
338 glMatrixMode(GL_MODELVIEW);
339 glLoadIdentity();
341 glBindTexture(GL_TEXTURE_2D, maintid);
342 glTexSubImage2D(GL_TEXTURE_2D, 0, 0/*x*/, 0/*y*/, Res.X, Res.Y, /*GL_RGBA*/GL_BGRA, GL_UNSIGNED_BYTE, bufc32);
344 glEnable(GL_TEXTURE_2D);
345 glDisable(GL_LIGHTING);
346 glDisable(GL_DITHER);
347 glDisable(GL_BLEND);
348 glDisable(GL_DEPTH_TEST);
349 glDisable(GL_STENCIL_TEST);
350 glDisable(GL_SCISSOR_TEST);
351 glDisable(GL_CULL_FACE);
352 glDisable(GL_POLYGON_OFFSET_FILL);
353 glDisable(GL_ALPHA_TEST);
354 glDisable(GL_FOG);
355 glDisable(GL_COLOR_LOGIC_OP);
356 glDisable(GL_INDEX_LOGIC_OP);
357 glDisable(GL_POLYGON_SMOOTH);
359 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
360 glBegin(GL_QUADS);
361 glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0); // top-left
362 glTexCoord2f(1.0f, 0.0f); glVertex2i(newx, 0); // top-right
363 glTexCoord2f(1.0f, 1.0f); glVertex2i(newx, newy); // bottom-right
364 glTexCoord2f(0.0f, 1.0f); glVertex2i(0, newy); // bottom-left
365 glEnd();
367 glBindTexture(GL_TEXTURE_2D, 0);
369 SDL_GL_SwapBuffers();
370 #endif
374 void graphics::SwitchMode () {
375 feuLong Flags;
376 if (Screen->flags & SDL_FULLSCREEN) {
377 SDL_ShowCursor(SDL_ENABLE);
378 Flags = SDL_SWSURFACE;
379 dblRes = origDblRes;
380 } else {
381 SDL_ShowCursor(SDL_DISABLE);
382 Flags = SDL_SWSURFACE|SDL_FULLSCREEN;
383 dblRes = false;
385 if (SwitchModeHandler) SwitchModeHandler();
386 #ifndef DISABLE_OPENGL
387 Flags |= SDL_OPENGL;
388 killTexture();
389 #endif
390 Screen = SDL_SetVideoMode(fixVal(Res.X), fixVal(Res.Y), ColorDepth, Flags);
391 if (!Screen) ABORT("Couldn't toggle fullscreen mode.");
392 buildKernel(Res.X, Res.Y);
393 #ifndef DISABLE_OPENGL
394 createTexture();
395 #endif
396 BlitDBToScreen();
400 void graphics::ReinitMode (sLong adresmod) {
401 if (adresmod < 0) adresmod = 0; else if (adresmod > 10) adresmod = 10;
402 dblRes = (adresmod > 0);
403 if (adresmod == 10) DIVISOR = 2.0f; else DIVISOR = 1.0f+(adresmod/10.0f);
404 origDblRes = dblRes;
406 if (Screen->flags&SDL_FULLSCREEN) {
407 dblRes = false;
408 //Flags = SDL_SWSURFACE|SDL_FULLSCREEN;
409 return; // nothing to do here, really
411 feuLong Flags = 0;
412 #ifndef DISABLE_OPENGL
413 Flags |= SDL_OPENGL;
414 killTexture();
415 #else
416 Flags = SDL_SWSURFACE;
417 #endif
418 Screen = SDL_SetVideoMode(fixVal(Res.X), fixVal(Res.Y), ColorDepth, Flags);
419 buildKernel(Res.X, Res.Y);
420 #ifndef DISABLE_OPENGL
421 createTexture();
422 #endif
423 BlitDBToScreen();
427 void graphics::LoadDefaultFont (cfestring &FileName) {
428 DefaultFont = new rawbitmap(FileName);