First beta version 1.0
[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 "opengl.h"
25 #include <GL/glew.h>
26
27 static uint8_t *text_rgb = NULL;
28 static GLuint text_name;
29 static int screen_width, screen_height;
30 static int image_width, image_height;
31 static int texture_size;
32
33 /* alloc and init an image texture with size that is greater than the power of two */
34 int init_opengl(int _image_width, int _image_height)
35 {
36         int rc;
37
38         image_width = _image_width;
39         image_height = _image_height;
40
41         /* generate texture */
42         for (texture_size = 1; texture_size <= image_width || texture_size <= image_height; texture_size *= 2)
43                 ;
44         text_rgb = calloc(texture_size * texture_size * 10, 3);
45         if (!text_rgb) {
46                 fprintf(stderr, "Failed to allocate texture\n");
47                 rc = -ENOMEM;
48                 goto error;
49         }
50         glClearColor(0.0, 0.0, 0.0, 1.0);
51         glShadeModel(GL_FLAT);
52         glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
53         glGenTextures(1, &text_name);
54         glBindTexture(GL_TEXTURE_2D, text_name);
55         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
56         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
57         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, text_rgb);
58
59         return 0;
60
61 error:
62         return rc;
63 }
64
65 /* set clip planes so that the image portion of the image texture is centered and pixels are rectengular */
66 void resize_opengl(int _screen_width, int _screen_height)
67 {
68         double width_border = 1.0;
69         double height_border = 1.0;
70
71         if (_screen_width < 1 || _screen_height < 1)
72                 return;
73         screen_width = _screen_width;
74         screen_height = _screen_height;
75
76         if (image_width * screen_height > screen_width * image_height) {
77                 height_border = (double)(image_width * screen_height) / (double)(screen_width * image_height);
78         }
79         if (image_width * screen_height < screen_width * image_height) {
80                 width_border = (double)(screen_width * image_height / (double)(image_width * screen_height));
81         }
82
83         /* viewport and projection matrix */
84         glViewport(0, 0, (GLsizei)screen_width, (GLsizei)screen_height);
85         glMatrixMode(GL_PROJECTION);
86         glLoadIdentity();
87
88         double width = (double)image_width / (double)texture_size;
89         double height = (double)image_height / (double)texture_size;
90         glOrtho(
91                         -width * (width_border - 1.0) / 2,
92                         width / 2 + width * width_border / 2,
93                         height / 2 + height * height_border / 2,
94                         -height * (height_border - 1.0) / 2,
95                         -1.0, 1.0);
96         glMatrixMode(GL_MODELVIEW);
97 }
98
99 /* render image texture */
100 void render_opengl(uint8_t *rgb, int filter)
101 {
102         glClear(GL_COLOR_BUFFER_BIT);
103         glEnable(GL_TEXTURE_2D);
104         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);  /* no modulation with color */
105         glBindTexture(GL_TEXTURE_2D, text_name);
106         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
107         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
108         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
109         glBegin(GL_QUADS);
110         glTexCoord2f(0.0, 0.0);
111         glVertex3f(0.0, 0.0, 0.0);
112         glTexCoord2f(1.0, 0.0);
113         glVertex3f(1.0, 0.0, 0.0);
114         glTexCoord2f(1.0, 1.0);
115         glVertex3f(1.0, 1.0, 0.0);
116         glTexCoord2f(0.0, 1.0);
117         glVertex3f(0.0, 1.0, 0.0);
118         glEnd();
119         glDisable(GL_TEXTURE_2D);
120 }
121
122 /* free image texture */
123 void exit_opengl(void)
124 {
125         if (text_rgb) {
126                 free(text_rgb);
127                 text_rgb = NULL;
128         }
129 }
130