1 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2 /* If you are missing that file, acquire a complete release at teeworlds.com. */
4 #include <base/detect.h>
9 #ifdef CONF_FAMILY_WINDOWS
10 #define WIN32_LEAN_AND_MEAN
14 #ifdef CONF_PLATFORM_MACOSX
15 #include <OpenGL/gl.h>
16 #include <OpenGL/glu.h>
22 #include <base/system.h>
23 #include <engine/external/pnglite/pnglite.h>
25 #include <engine/shared/config.h>
26 #include <engine/graphics.h>
27 #include <engine/storage.h>
28 #include <engine/keys.h>
29 #include <engine/console.h>
31 #include <math.h> // cosf, sinf
35 // compressed textures
36 #define GL_COMPRESSED_RGB_ARB 0x84ED
37 #define GL_COMPRESSED_RGBA_ARB 0x84EE
38 #define GL_COMPRESSED_ALPHA_ARB 0x84E9
40 #define TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
43 static CVideoMode g_aFakeModes
[] = {
44 {320,240,8,8,8}, {400,300,8,8,8}, {640,480,8,8,8},
45 {720,400,8,8,8}, {768,576,8,8,8}, {800,600,8,8,8},
46 {1024,600,8,8,8}, {1024,768,8,8,8}, {1152,864,8,8,8},
47 {1280,768,8,8,8}, {1280,800,8,8,8}, {1280,960,8,8,8},
48 {1280,1024,8,8,8}, {1368,768,8,8,8}, {1400,1050,8,8,8},
49 {1440,900,8,8,8}, {1440,1050,8,8,8}, {1600,1000,8,8,8},
50 {1600,1200,8,8,8}, {1680,1050,8,8,8}, {1792,1344,8,8,8},
51 {1800,1440,8,8,8}, {1856,1392,8,8,8}, {1920,1080,8,8,8},
52 {1920,1200,8,8,8}, {1920,1440,8,8,8}, {1920,2400,8,8,8},
55 {320,240,5,6,5}, {400,300,5,6,5}, {640,480,5,6,5},
56 {720,400,5,6,5}, {768,576,5,6,5}, {800,600,5,6,5},
57 {1024,600,5,6,5}, {1024,768,5,6,5}, {1152,864,5,6,5},
58 {1280,768,5,6,5}, {1280,800,5,6,5}, {1280,960,5,6,5},
59 {1280,1024,5,6,5}, {1368,768,5,6,5}, {1400,1050,5,6,5},
60 {1440,900,5,6,5}, {1440,1050,5,6,5}, {1600,1000,5,6,5},
61 {1600,1200,5,6,5}, {1680,1050,5,6,5}, {1792,1344,5,6,5},
62 {1800,1440,5,6,5}, {1856,1392,5,6,5}, {1920,1080,5,6,5},
63 {1920,1200,5,6,5}, {1920,1440,5,6,5}, {1920,2400,5,6,5},
67 void CGraphics_OpenGL::Flush()
69 if(m_NumVertices
== 0)
72 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
73 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
75 glVertexPointer(3, GL_FLOAT
,
78 glTexCoordPointer(2, GL_FLOAT
,
80 (char*)m_aVertices
+ sizeof(float)*3);
81 glColorPointer(4, GL_FLOAT
,
83 (char*)m_aVertices
+ sizeof(float)*5);
84 glEnableClientState(GL_VERTEX_ARRAY
);
85 glEnableClientState(GL_TEXTURE_COORD_ARRAY
);
86 glEnableClientState(GL_COLOR_ARRAY
);
90 if(m_Drawing
== DRAWING_QUADS
)
91 glDrawArrays(GL_QUADS
, 0, m_NumVertices
);
92 else if(m_Drawing
== DRAWING_LINES
)
93 glDrawArrays(GL_LINES
, 0, m_NumVertices
);
100 void CGraphics_OpenGL::AddVertices(int Count
)
102 m_NumVertices
+= Count
;
103 if((m_NumVertices
+ Count
) >= MAX_VERTICES
)
107 void CGraphics_OpenGL::Rotate4(const CPoint
&rCenter
, CVertex
*pPoints
)
109 float c
= cosf(m_Rotation
);
110 float s
= sinf(m_Rotation
);
114 for(i
= 0; i
< 4; i
++)
116 x
= pPoints
[i
].m_Pos
.x
- rCenter
.x
;
117 y
= pPoints
[i
].m_Pos
.y
- rCenter
.y
;
118 pPoints
[i
].m_Pos
.x
= x
* c
- y
* s
+ rCenter
.x
;
119 pPoints
[i
].m_Pos
.y
= x
* s
+ y
* c
+ rCenter
.y
;
123 unsigned char CGraphics_OpenGL::Sample(int w
, int h
, const unsigned char *pData
, int u
, int v
, int Offset
, int ScaleW
, int ScaleH
, int Bpp
)
126 for(int x
= 0; x
< ScaleW
; x
++)
127 for(int y
= 0; y
< ScaleH
; y
++)
128 Value
+= pData
[((v
+y
)*w
+(u
+x
))*Bpp
+Offset
];
129 return Value
/(ScaleW
*ScaleH
);
132 unsigned char *CGraphics_OpenGL::Rescale(int Width
, int Height
, int NewWidth
, int NewHeight
, int Format
, const unsigned char *pData
)
134 unsigned char *pTmpData
;
135 int ScaleW
= Width
/NewWidth
;
136 int ScaleH
= Height
/NewHeight
;
139 if(Format
== CImageInfo::FORMAT_RGBA
)
142 pTmpData
= (unsigned char *)mem_alloc(NewWidth
*NewHeight
*Bpp
, 1);
145 for(int y
= 0; y
< NewHeight
; y
++)
146 for(int x
= 0; x
< NewWidth
; x
++, c
++)
148 pTmpData
[c
*Bpp
] = Sample(Width
, Height
, pData
, x
*ScaleW
, y
*ScaleH
, 0, ScaleW
, ScaleH
, Bpp
);
149 pTmpData
[c
*Bpp
+1] = Sample(Width
, Height
, pData
, x
*ScaleW
, y
*ScaleH
, 1, ScaleW
, ScaleH
, Bpp
);
150 pTmpData
[c
*Bpp
+2] = Sample(Width
, Height
, pData
, x
*ScaleW
, y
*ScaleH
, 2, ScaleW
, ScaleH
, Bpp
);
152 pTmpData
[c
*Bpp
+3] = Sample(Width
, Height
, pData
, x
*ScaleW
, y
*ScaleH
, 3, ScaleW
, ScaleH
, Bpp
);
158 CGraphics_OpenGL::CGraphics_OpenGL()
172 m_InvalidTexture
= 0;
174 m_TextureMemoryUsage
= 0;
176 m_RenderEnable
= true;
177 m_DoScreenshot
= false;
180 void CGraphics_OpenGL::ClipEnable(int x
, int y
, int w
, int h
)
187 x
= clamp(x
, 0, ScreenWidth());
188 y
= clamp(y
, 0, ScreenHeight());
189 w
= clamp(w
, 0, ScreenWidth()-x
);
190 h
= clamp(h
, 0, ScreenHeight()-y
);
192 glScissor(x
, ScreenHeight()-(y
+h
), w
, h
);
193 glEnable(GL_SCISSOR_TEST
);
196 void CGraphics_OpenGL::ClipDisable()
199 glDisable(GL_SCISSOR_TEST
);
202 void CGraphics_OpenGL::BlendNone()
207 void CGraphics_OpenGL::BlendNormal()
210 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
213 void CGraphics_OpenGL::BlendAdditive()
216 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
219 int CGraphics_OpenGL::MemoryUsage() const
221 return m_TextureMemoryUsage
;
224 void CGraphics_OpenGL::MapScreen(float TopLeftX
, float TopLeftY
, float BottomRightX
, float BottomRightY
)
226 m_ScreenX0
= TopLeftX
;
227 m_ScreenY0
= TopLeftY
;
228 m_ScreenX1
= BottomRightX
;
229 m_ScreenY1
= BottomRightY
;
230 glMatrixMode(GL_PROJECTION
);
232 glOrtho(TopLeftX
, BottomRightX
, BottomRightY
, TopLeftY
, 1.0f
, 10.f
);
235 void CGraphics_OpenGL::GetScreen(float *pTopLeftX
, float *pTopLeftY
, float *pBottomRightX
, float *pBottomRightY
)
237 *pTopLeftX
= m_ScreenX0
;
238 *pTopLeftY
= m_ScreenY0
;
239 *pBottomRightX
= m_ScreenX1
;
240 *pBottomRightY
= m_ScreenY1
;
243 void CGraphics_OpenGL::LinesBegin()
245 dbg_assert(m_Drawing
== 0, "called Graphics()->LinesBegin twice");
246 m_Drawing
= DRAWING_LINES
;
250 void CGraphics_OpenGL::LinesEnd()
252 dbg_assert(m_Drawing
== DRAWING_LINES
, "called Graphics()->LinesEnd without begin");
257 void CGraphics_OpenGL::LinesDraw(const CLineItem
*pArray
, int Num
)
259 dbg_assert(m_Drawing
== DRAWING_LINES
, "called Graphics()->LinesDraw without begin");
261 for(int i
= 0; i
< Num
; ++i
)
263 m_aVertices
[m_NumVertices
+ 2*i
].m_Pos
.x
= pArray
[i
].m_X0
;
264 m_aVertices
[m_NumVertices
+ 2*i
].m_Pos
.y
= pArray
[i
].m_Y0
;
265 m_aVertices
[m_NumVertices
+ 2*i
].m_Tex
= m_aTexture
[0];
266 m_aVertices
[m_NumVertices
+ 2*i
].m_Color
= m_aColor
[0];
268 m_aVertices
[m_NumVertices
+ 2*i
+ 1].m_Pos
.x
= pArray
[i
].m_X1
;
269 m_aVertices
[m_NumVertices
+ 2*i
+ 1].m_Pos
.y
= pArray
[i
].m_Y1
;
270 m_aVertices
[m_NumVertices
+ 2*i
+ 1].m_Tex
= m_aTexture
[1];
271 m_aVertices
[m_NumVertices
+ 2*i
+ 1].m_Color
= m_aColor
[1];
277 int CGraphics_OpenGL::UnloadTexture(int Index
)
279 if(Index
== m_InvalidTexture
)
285 glDeleteTextures(1, &m_aTextures
[Index
].m_Tex
);
286 m_aTextures
[Index
].m_Next
= m_FirstFreeTexture
;
287 m_TextureMemoryUsage
-= m_aTextures
[Index
].m_MemSize
;
288 m_FirstFreeTexture
= Index
;
293 int CGraphics_OpenGL::LoadTextureRaw(int Width
, int Height
, int Format
, const void *pData
, int StoreFormat
, int Flags
)
296 unsigned char *pTexData
= (unsigned char *)pData
;
297 unsigned char *pTmpData
= 0;
299 int StoreOglformat
= 0;
302 // don't waste memory on texture if we are stress testing
303 if(g_Config
.m_DbgStress
)
304 return m_InvalidTexture
;
307 Tex
= m_FirstFreeTexture
;
308 m_FirstFreeTexture
= m_aTextures
[Tex
].m_Next
;
309 m_aTextures
[Tex
].m_Next
= -1;
311 // resample if needed
312 if(!(Flags
&TEXLOAD_NORESAMPLE
) && (Format
== CImageInfo::FORMAT_RGBA
|| Format
== CImageInfo::FORMAT_RGB
))
314 if(Width
> GL_MAX_TEXTURE_SIZE
|| Height
> GL_MAX_TEXTURE_SIZE
)
316 int NewWidth
= min(Width
, GL_MAX_TEXTURE_SIZE
);
317 int NewHeight
= min(Height
, GL_MAX_TEXTURE_SIZE
);
318 pTmpData
= Rescale(Width
, Height
, NewWidth
, NewHeight
, Format
, pTexData
);
323 else if(Width
> 16 && Height
> 16 && g_Config
.m_GfxTextureQuality
== 0)
325 pTmpData
= Rescale(Width
, Height
, Width
/2, Height
/2, Format
, pTexData
);
333 if(Format
== CImageInfo::FORMAT_RGB
)
335 else if(Format
== CImageInfo::FORMAT_ALPHA
)
336 Oglformat
= GL_ALPHA
;
339 if(g_Config
.m_GfxTextureCompression
)
341 StoreOglformat
= GL_COMPRESSED_RGBA_ARB
;
342 if(StoreFormat
== CImageInfo::FORMAT_RGB
)
343 StoreOglformat
= GL_COMPRESSED_RGB_ARB
;
344 else if(StoreFormat
== CImageInfo::FORMAT_ALPHA
)
345 StoreOglformat
= GL_COMPRESSED_ALPHA_ARB
;
349 StoreOglformat
= GL_RGBA
;
350 if(StoreFormat
== CImageInfo::FORMAT_RGB
)
351 StoreOglformat
= GL_RGB
;
352 else if(StoreFormat
== CImageInfo::FORMAT_ALPHA
)
353 StoreOglformat
= GL_ALPHA
;
356 glGenTextures(1, &m_aTextures
[Tex
].m_Tex
);
357 glBindTexture(GL_TEXTURE_2D
, m_aTextures
[Tex
].m_Tex
);
358 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
359 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR_MIPMAP_NEAREST
);
360 gluBuild2DMipmaps(GL_TEXTURE_2D
, StoreOglformat
, Width
, Height
, Oglformat
, GL_UNSIGNED_BYTE
, pTexData
);
362 // calculate memory usage
365 if(StoreFormat
== CImageInfo::FORMAT_RGB
)
367 else if(StoreFormat
== CImageInfo::FORMAT_ALPHA
)
370 m_aTextures
[Tex
].m_MemSize
= Width
*Height
*PixelSize
;
373 while(Width
> 2 && Height
> 2)
377 m_aTextures
[Tex
].m_MemSize
+= Width
*Height
*PixelSize
;
382 m_TextureMemoryUsage
+= m_aTextures
[Tex
].m_MemSize
;
387 // simple uncompressed RGBA loaders
388 int CGraphics_OpenGL::LoadTexture(const char *pFilename
, int StorageType
, int StoreFormat
, int Flags
)
390 int l
= str_length(pFilename
);
396 if(LoadPNG(&Img
, pFilename
, StorageType
))
398 if (StoreFormat
== CImageInfo::FORMAT_AUTO
)
399 StoreFormat
= Img
.m_Format
;
401 ID
= LoadTextureRaw(Img
.m_Width
, Img
.m_Height
, Img
.m_Format
, Img
.m_pData
, StoreFormat
, Flags
);
402 mem_free(Img
.m_pData
);
406 return m_InvalidTexture
;
409 int CGraphics_OpenGL::LoadPNG(CImageInfo
*pImg
, const char *pFilename
, int StorageType
)
411 char aCompleteFilename
[512];
412 unsigned char *pBuffer
;
413 png_t Png
; // ignore_convention
415 // open file for reading
416 png_init(0,0); // ignore_convention
418 IOHANDLE File
= m_pStorage
->OpenFile(pFilename
, IOFLAG_READ
, StorageType
, aCompleteFilename
, sizeof(aCompleteFilename
));
423 dbg_msg("game/png", "failed to open file. filename='%s'", pFilename
);
427 int Error
= png_open_file(&Png
, aCompleteFilename
); // ignore_convention
428 if(Error
!= PNG_NO_ERROR
)
430 dbg_msg("game/png", "failed to open file. filename='%s'", aCompleteFilename
);
431 if(Error
!= PNG_FILE_ERROR
)
432 png_close_file(&Png
); // ignore_convention
436 if(Png
.depth
!= 8 || (Png
.color_type
!= PNG_TRUECOLOR
&& Png
.color_type
!= PNG_TRUECOLOR_ALPHA
)) // ignore_convention
438 dbg_msg("game/png", "invalid format. filename='%s'", aCompleteFilename
);
439 png_close_file(&Png
); // ignore_convention
443 pBuffer
= (unsigned char *)mem_alloc(Png
.width
* Png
.height
* Png
.bpp
, 1); // ignore_convention
444 png_get_data(&Png
, pBuffer
); // ignore_convention
445 png_close_file(&Png
); // ignore_convention
447 pImg
->m_Width
= Png
.width
; // ignore_convention
448 pImg
->m_Height
= Png
.height
; // ignore_convention
449 if(Png
.color_type
== PNG_TRUECOLOR
) // ignore_convention
450 pImg
->m_Format
= CImageInfo::FORMAT_RGB
;
451 else if(Png
.color_type
== PNG_TRUECOLOR_ALPHA
) // ignore_convention
452 pImg
->m_Format
= CImageInfo::FORMAT_RGBA
;
453 pImg
->m_pData
= pBuffer
;
457 void CGraphics_OpenGL::ScreenshotDirect(const char *pFilename
)
461 int w
= m_ScreenWidth
;
462 int h
= m_ScreenHeight
;
463 unsigned char *pPixelData
= (unsigned char *)mem_alloc(w
*(h
+1)*3, 1);
464 unsigned char *pTempRow
= pPixelData
+w
*h
*3;
466 glGetIntegerv(GL_PACK_ALIGNMENT
, &Alignment
);
467 glPixelStorei(GL_PACK_ALIGNMENT
, 1);
468 glReadPixels(0,0, w
, h
, GL_RGB
, GL_UNSIGNED_BYTE
, pPixelData
);
469 glPixelStorei(GL_PACK_ALIGNMENT
, Alignment
);
471 // flip the pixel because opengl works from bottom left corner
472 for(y
= 0; y
< h
/2; y
++)
474 mem_copy(pTempRow
, pPixelData
+y
*w
*3, w
*3);
475 mem_copy(pPixelData
+y
*w
*3, pPixelData
+(h
-y
-1)*w
*3, w
*3);
476 mem_copy(pPixelData
+(h
-y
-1)*w
*3, pTempRow
,w
*3);
481 char aWholePath
[1024];
482 png_t Png
; // ignore_convention
484 IOHANDLE File
= m_pStorage
->OpenFile(pFilename
, IOFLAG_WRITE
, IStorage::TYPE_SAVE
, aWholePath
, sizeof(aWholePath
));
490 str_format(aBuf
, sizeof(aBuf
), "saved screenshot to '%s'", aWholePath
);
491 m_pConsole
->Print(IConsole::OUTPUT_LEVEL_STANDARD
, "client", aBuf
);
492 png_open_file_write(&Png
, aWholePath
); // ignore_convention
493 png_set_data(&Png
, w
, h
, 8, PNG_TRUECOLOR
, (unsigned char *)pPixelData
); // ignore_convention
494 png_close_file(&Png
); // ignore_convention
498 mem_free(pPixelData
);
501 void CGraphics_OpenGL::TextureSet(int TextureID
)
503 dbg_assert(m_Drawing
== 0, "called Graphics()->TextureSet within begin");
506 glDisable(GL_TEXTURE_2D
);
510 glEnable(GL_TEXTURE_2D
);
511 glBindTexture(GL_TEXTURE_2D
, m_aTextures
[TextureID
].m_Tex
);
515 void CGraphics_OpenGL::Clear(float r
, float g
, float b
)
517 glClearColor(r
,g
,b
,0.0f
);
518 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
521 void CGraphics_OpenGL::QuadsBegin()
523 dbg_assert(m_Drawing
== 0, "called Graphics()->QuadsBegin twice");
524 m_Drawing
= DRAWING_QUADS
;
526 QuadsSetSubset(0,0,1,1);
531 void CGraphics_OpenGL::QuadsEnd()
533 dbg_assert(m_Drawing
== DRAWING_QUADS
, "called Graphics()->QuadsEnd without begin");
538 void CGraphics_OpenGL::QuadsSetRotation(float Angle
)
540 dbg_assert(m_Drawing
== DRAWING_QUADS
, "called Graphics()->QuadsSetRotation without begin");
544 void CGraphics_OpenGL::SetColorVertex(const CColorVertex
*pArray
, int Num
)
546 dbg_assert(m_Drawing
!= 0, "called Graphics()->SetColorVertex without begin");
548 for(int i
= 0; i
< Num
; ++i
)
550 m_aColor
[pArray
[i
].m_Index
].r
= pArray
[i
].m_R
;
551 m_aColor
[pArray
[i
].m_Index
].g
= pArray
[i
].m_G
;
552 m_aColor
[pArray
[i
].m_Index
].b
= pArray
[i
].m_B
;
553 m_aColor
[pArray
[i
].m_Index
].a
= pArray
[i
].m_A
;
557 void CGraphics_OpenGL::SetColor(float r
, float g
, float b
, float a
)
559 dbg_assert(m_Drawing
!= 0, "called Graphics()->SetColor without begin");
560 CColorVertex Array
[4] = {
561 CColorVertex(0, r
, g
, b
, a
),
562 CColorVertex(1, r
, g
, b
, a
),
563 CColorVertex(2, r
, g
, b
, a
),
564 CColorVertex(3, r
, g
, b
, a
)};
565 SetColorVertex(Array
, 4);
568 void CGraphics_OpenGL::QuadsSetSubset(float TlU
, float TlV
, float BrU
, float BrV
)
570 dbg_assert(m_Drawing
== DRAWING_QUADS
, "called Graphics()->QuadsSetSubset without begin");
572 m_aTexture
[0].u
= TlU
; m_aTexture
[1].u
= BrU
;
573 m_aTexture
[0].v
= TlV
; m_aTexture
[1].v
= TlV
;
575 m_aTexture
[3].u
= TlU
; m_aTexture
[2].u
= BrU
;
576 m_aTexture
[3].v
= BrV
; m_aTexture
[2].v
= BrV
;
579 void CGraphics_OpenGL::QuadsSetSubsetFree(
580 float x0
, float y0
, float x1
, float y1
,
581 float x2
, float y2
, float x3
, float y3
)
583 m_aTexture
[0].u
= x0
; m_aTexture
[0].v
= y0
;
584 m_aTexture
[1].u
= x1
; m_aTexture
[1].v
= y1
;
585 m_aTexture
[2].u
= x2
; m_aTexture
[2].v
= y2
;
586 m_aTexture
[3].u
= x3
; m_aTexture
[3].v
= y3
;
589 void CGraphics_OpenGL::QuadsDraw(CQuadItem
*pArray
, int Num
)
591 for(int i
= 0; i
< Num
; ++i
)
593 pArray
[i
].m_X
-= pArray
[i
].m_Width
/2;
594 pArray
[i
].m_Y
-= pArray
[i
].m_Height
/2;
597 QuadsDrawTL(pArray
, Num
);
600 void CGraphics_OpenGL::QuadsDrawTL(const CQuadItem
*pArray
, int Num
)
605 dbg_assert(m_Drawing
== DRAWING_QUADS
, "called Graphics()->QuadsDrawTL without begin");
607 for(int i
= 0; i
< Num
; ++i
)
609 m_aVertices
[m_NumVertices
+ 4*i
].m_Pos
.x
= pArray
[i
].m_X
;
610 m_aVertices
[m_NumVertices
+ 4*i
].m_Pos
.y
= pArray
[i
].m_Y
;
611 m_aVertices
[m_NumVertices
+ 4*i
].m_Tex
= m_aTexture
[0];
612 m_aVertices
[m_NumVertices
+ 4*i
].m_Color
= m_aColor
[0];
614 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Pos
.x
= pArray
[i
].m_X
+ pArray
[i
].m_Width
;
615 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Pos
.y
= pArray
[i
].m_Y
;
616 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Tex
= m_aTexture
[1];
617 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Color
= m_aColor
[1];
619 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Pos
.x
= pArray
[i
].m_X
+ pArray
[i
].m_Width
;
620 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Pos
.y
= pArray
[i
].m_Y
+ pArray
[i
].m_Height
;
621 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Tex
= m_aTexture
[2];
622 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Color
= m_aColor
[2];
624 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Pos
.x
= pArray
[i
].m_X
;
625 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Pos
.y
= pArray
[i
].m_Y
+ pArray
[i
].m_Height
;
626 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Tex
= m_aTexture
[3];
627 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Color
= m_aColor
[3];
631 Center
.x
= pArray
[i
].m_X
+ pArray
[i
].m_Width
/2;
632 Center
.y
= pArray
[i
].m_Y
+ pArray
[i
].m_Height
/2;
634 Rotate4(Center
, &m_aVertices
[m_NumVertices
+ 4*i
]);
641 void CGraphics_OpenGL::QuadsDrawFreeform(const CFreeformItem
*pArray
, int Num
)
643 dbg_assert(m_Drawing
== DRAWING_QUADS
, "called Graphics()->QuadsDrawFreeform without begin");
645 for(int i
= 0; i
< Num
; ++i
)
647 m_aVertices
[m_NumVertices
+ 4*i
].m_Pos
.x
= pArray
[i
].m_X0
;
648 m_aVertices
[m_NumVertices
+ 4*i
].m_Pos
.y
= pArray
[i
].m_Y0
;
649 m_aVertices
[m_NumVertices
+ 4*i
].m_Tex
= m_aTexture
[0];
650 m_aVertices
[m_NumVertices
+ 4*i
].m_Color
= m_aColor
[0];
652 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Pos
.x
= pArray
[i
].m_X1
;
653 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Pos
.y
= pArray
[i
].m_Y1
;
654 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Tex
= m_aTexture
[1];
655 m_aVertices
[m_NumVertices
+ 4*i
+ 1].m_Color
= m_aColor
[1];
657 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Pos
.x
= pArray
[i
].m_X3
;
658 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Pos
.y
= pArray
[i
].m_Y3
;
659 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Tex
= m_aTexture
[3];
660 m_aVertices
[m_NumVertices
+ 4*i
+ 2].m_Color
= m_aColor
[3];
662 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Pos
.x
= pArray
[i
].m_X2
;
663 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Pos
.y
= pArray
[i
].m_Y2
;
664 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Tex
= m_aTexture
[2];
665 m_aVertices
[m_NumVertices
+ 4*i
+ 3].m_Color
= m_aColor
[2];
671 void CGraphics_OpenGL::QuadsText(float x
, float y
, float Size
, float r
, float g
, float b
, float a
, const char *pText
)
693 (c
%16)/16.0f
+1.0f
/16.0f
,
694 (c
/16)/16.0f
+1.0f
/16.0f
);
696 CQuadItem
QuadItem(x
, y
, Size
, Size
);
697 QuadsDrawTL(&QuadItem
, 1);
705 bool CGraphics_OpenGL::Init()
707 m_pStorage
= Kernel()->RequestInterface
<IStorage
>();
708 m_pConsole
= Kernel()->RequestInterface
<IConsole
>();
710 // Set all z to -5.0f
711 for(int i
= 0; i
< MAX_VERTICES
; i
++)
712 m_aVertices
[i
].m_Pos
.z
= -5.0f
;
715 m_FirstFreeTexture
= 0;
716 for(int i
= 0; i
< MAX_TEXTURES
; i
++)
717 m_aTextures
[i
].m_Next
= i
+1;
718 m_aTextures
[MAX_TEXTURES
-1].m_Next
= -1;
720 // set some default settings
722 glDisable(GL_CULL_FACE
);
723 glDisable(GL_DEPTH_TEST
);
724 glMatrixMode(GL_MODELVIEW
);
727 glAlphaFunc(GL_GREATER
, 0);
728 glEnable(GL_ALPHA_TEST
);
731 // create null texture, will get id=0
732 static const unsigned char aNullTextureData
[] = {
733 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff,
734 0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff,
735 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff,
736 0x00,0x00,0xff,0xff, 0x00,0x00,0xff,0xff, 0xff,0xff,0x00,0xff, 0xff,0xff,0x00,0xff,
739 m_InvalidTexture
= LoadTextureRaw(4,4,CImageInfo::FORMAT_RGBA
,aNullTextureData
,CImageInfo::FORMAT_RGBA
,TEXLOAD_NORESAMPLE
);
744 int CGraphics_SDL::TryInit()
746 const SDL_VideoInfo
*pInfo
;
747 int Flags
= SDL_OPENGL
;
749 m_ScreenWidth
= g_Config
.m_GfxScreenWidth
;
750 m_ScreenHeight
= g_Config
.m_GfxScreenHeight
;
752 pInfo
= SDL_GetVideoInfo();
753 SDL_EventState(SDL_MOUSEMOTION
, SDL_IGNORE
);
757 Flags
|= SDL_GL_DOUBLEBUFFER
;
758 Flags
|= SDL_HWPALETTE
;
759 if(g_Config
.m_DbgResizable
)
760 Flags
|= SDL_RESIZABLE
;
762 if(pInfo
->hw_available
) // ignore_convention
763 Flags
|= SDL_HWSURFACE
;
765 Flags
|= SDL_SWSURFACE
;
767 if(pInfo
->blit_hw
) // ignore_convention
768 Flags
|= SDL_HWACCEL
;
770 if(g_Config
.m_GfxFullscreen
)
771 Flags
|= SDL_FULLSCREEN
;
774 if(g_Config
.m_GfxFsaaSamples
)
776 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS
, 1);
777 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES
, g_Config
.m_GfxFsaaSamples
);
781 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS
, 0);
782 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES
, 0);
785 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER
, 1);
786 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL
, g_Config
.m_GfxVsync
);
789 SDL_WM_SetCaption("Teeworlds", "Teeworlds");
792 m_pScreenSurface
= SDL_SetVideoMode(m_ScreenWidth
, m_ScreenHeight
, 0, Flags
);
793 if(m_pScreenSurface
== NULL
)
795 dbg_msg("gfx", "unable to set video mode: %s", SDL_GetError());
803 int CGraphics_SDL::InitWindow()
808 // try disabling fsaa
809 while(g_Config
.m_GfxFsaaSamples
)
811 g_Config
.m_GfxFsaaSamples
--;
813 if(g_Config
.m_GfxFsaaSamples
)
814 dbg_msg("gfx", "lowering FSAA to %d and trying again", g_Config
.m_GfxFsaaSamples
);
816 dbg_msg("gfx", "disabling FSAA and trying again");
822 // try lowering the resolution
823 if(g_Config
.m_GfxScreenWidth
!= 640 || g_Config
.m_GfxScreenHeight
!= 480)
825 dbg_msg("gfx", "setting resolution to 640x480 and trying again");
826 g_Config
.m_GfxScreenWidth
= 640;
827 g_Config
.m_GfxScreenHeight
= 480;
833 dbg_msg("gfx", "out of ideas. failed to init graphics");
839 CGraphics_SDL::CGraphics_SDL()
841 m_pScreenSurface
= 0;
844 bool CGraphics_SDL::Init()
847 int Systems
= SDL_INIT_VIDEO
;
849 if(g_Config
.m_SndEnable
)
850 Systems
|= SDL_INIT_AUDIO
;
852 if(g_Config
.m_ClEventthread
)
853 Systems
|= SDL_INIT_EVENTTHREAD
;
855 if(SDL_Init(Systems
) < 0)
857 dbg_msg("gfx", "unable to init SDL: %s", SDL_GetError());
862 atexit(SDL_Quit
); // ignore_convention
864 #ifdef CONF_FAMILY_WINDOWS
865 if(!getenv("SDL_VIDEO_WINDOW_POS") && !getenv("SDL_VIDEO_CENTERED")) // ignore_convention
866 putenv("SDL_VIDEO_WINDOW_POS=8,27"); // ignore_convention
869 if(InitWindow() != 0)
874 CGraphics_OpenGL::Init();
876 MapScreen(0,0,g_Config
.m_GfxScreenWidth
, g_Config
.m_GfxScreenHeight
);
880 void CGraphics_SDL::Shutdown()
882 // TODO: SDL, is this correct?
886 void CGraphics_SDL::Minimize()
888 SDL_WM_IconifyWindow();
891 void CGraphics_SDL::Maximize()
896 int CGraphics_SDL::WindowActive()
898 return SDL_GetAppState()&SDL_APPINPUTFOCUS
;
901 int CGraphics_SDL::WindowOpen()
903 return SDL_GetAppState()&SDL_APPACTIVE
;
907 void CGraphics_SDL::TakeScreenshot(const char *pFilename
)
910 str_timestamp(aDate
, sizeof(aDate
));
911 str_format(m_aScreenshotName
, sizeof(m_aScreenshotName
), "screenshots/%s_%s.png", pFilename
?pFilename
:"screenshot", aDate
);
912 m_DoScreenshot
= true;
915 void CGraphics_SDL::Swap()
919 ScreenshotDirect(m_aScreenshotName
);
920 m_DoScreenshot
= false;
923 SDL_GL_SwapBuffers();
925 if(g_Config
.m_GfxFinish
)
930 int CGraphics_SDL::GetVideoModes(CVideoMode
*pModes
, int MaxModes
)
932 int NumModes
= sizeof(g_aFakeModes
)/sizeof(CVideoMode
);
935 if(g_Config
.m_GfxDisplayAllModes
)
937 int Count
= sizeof(g_aFakeModes
)/sizeof(CVideoMode
);
938 mem_copy(pModes
, g_aFakeModes
, sizeof(g_aFakeModes
));
944 // TODO: fix this code on osx or windows
946 ppModes
= SDL_ListModes(NULL
, SDL_OPENGL
|SDL_GL_DOUBLEBUFFER
|SDL_FULLSCREEN
);
952 else if(ppModes
== (SDL_Rect
**)-1)
959 for(int i
= 0; ppModes
[i
]; ++i
)
961 if(NumModes
== MaxModes
)
963 pModes
[NumModes
].m_Width
= ppModes
[i
]->w
;
964 pModes
[NumModes
].m_Height
= ppModes
[i
]->h
;
965 pModes
[NumModes
].m_Red
= 8;
966 pModes
[NumModes
].m_Green
= 8;
967 pModes
[NumModes
].m_Blue
= 8;
975 extern IEngineGraphics
*CreateEngineGraphics() { return new CGraphics_SDL(); }