Replace printf/fprintf with own print_info() / print_error() using SDL_log
[mercenary-reloaded.git] / src / libsdl / opengl.c
1 /* OpenGL rendering
2  *
3  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
4  * All Rights Reserved
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include "print.h"
25 #include "opengl.h"
26 #include <GL/glew.h>
27
28 static uint8_t *text_rgb = NULL;
29 static GLuint text_name;
30 static int screen_width, screen_height;
31 static int image_width, image_height;
32 static int texture_size;
33
34 /* alloc and init an image texture with size that is greater than the power of two */
35 int init_opengl(int _image_width, int _image_height)
36 {
37         int rc;
38
39         image_width = _image_width;
40         image_height = _image_height;
41
42         /* generate texture */
43         for (texture_size = 1; texture_size <= image_width || texture_size <= image_height; texture_size *= 2)
44                 ;
45         text_rgb = calloc(texture_size * texture_size * 10, 3);
46         if (!text_rgb) {
47                 print_error("Failed to allocate texture\n");
48                 rc = -ENOMEM;
49                 goto error;
50         }
51         glClearColor(0.0, 0.0, 0.0, 1.0);
52         glShadeModel(GL_FLAT);
53         glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
54         glGenTextures(1, &text_name);
55         glBindTexture(GL_TEXTURE_2D, text_name);
56         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
57         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
58         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, text_rgb);
59
60         return 0;
61
62 error:
63         return rc;
64 }
65
66 /* set clip planes so that the image portion of the image texture is centered and pixels are rectengular */
67 void resize_opengl(int _screen_width, int _screen_height)
68 {
69         double width_border = 1.0;
70         double height_border = 1.0;
71
72         if (_screen_width < 1 || _screen_height < 1)
73                 return;
74         screen_width = _screen_width;
75         screen_height = _screen_height;
76
77         if (image_width * screen_height > screen_width * image_height) {
78                 height_border = (double)(image_width * screen_height) / (double)(screen_width * image_height);
79         }
80         if (image_width * screen_height < screen_width * image_height) {
81                 width_border = (double)(screen_width * image_height / (double)(image_width * screen_height));
82         }
83
84         /* viewport and projection matrix */
85         glViewport(0, 0, (GLsizei)screen_width, (GLsizei)screen_height);
86         glMatrixMode(GL_PROJECTION);
87         glLoadIdentity();
88
89         double width = (double)image_width / (double)texture_size;
90         double height = (double)image_height / (double)texture_size;
91         glOrtho(
92                         -width * (width_border - 1.0) / 2,
93                         width / 2 + width * width_border / 2,
94                         height / 2 + height * height_border / 2,
95                         -height * (height_border - 1.0) / 2,
96                         -1.0, 1.0);
97         glMatrixMode(GL_MODELVIEW);
98 }
99
100 /* render image texture */
101 void render_opengl(uint8_t *rgb, int filter)
102 {
103         glClear(GL_COLOR_BUFFER_BIT);
104         glEnable(GL_TEXTURE_2D);
105         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);  /* no modulation with color */
106         glBindTexture(GL_TEXTURE_2D, text_name);
107         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
108         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
109         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
110         glBegin(GL_QUADS);
111         glTexCoord2f(0.0, 0.0);
112         glVertex3f(0.0, 0.0, 0.0);
113         glTexCoord2f(1.0, 0.0);
114         glVertex3f(1.0, 0.0, 0.0);
115         glTexCoord2f(1.0, 1.0);
116         glVertex3f(1.0, 1.0, 0.0);
117         glTexCoord2f(0.0, 1.0);
118         glVertex3f(0.0, 1.0, 0.0);
119         glEnd();
120         glDisable(GL_TEXTURE_2D);
121 }
122
123 /* free image texture */
124 void exit_opengl(void)
125 {
126         if (text_rgb) {
127                 free(text_rgb);
128                 text_rgb = NULL;
129         }
130 }
131