#include "opengl.h"
#include <GL/glew.h>
+#define MAX_OSD 2
static uint8_t *legacy_rgb = NULL;
static uint8_t *benson_rgb = NULL;
+static uint8_t *osd_rgba[MAX_OSD] = { NULL, NULL };
static GLuint legacy_name;
static GLuint benson_name;
+static GLuint osd_name[MAX_OSD];
static int screen_width, screen_height;
static int image_width, image_height;
+static int osd_width[MAX_OSD], osd_height[MAX_OSD];
static int texture_size;
+static int osd_size[MAX_OSD];
/* alloc and init an image texture with size that is greater than the power of two */
int init_opengl(int _image_width, int _image_height)
return rc;
}
+/* alloc and init an osd texture with size that is greater than the power of two */
+int init_osd(int num, int _osd_width, int _osd_height)
+{
+ int rc;
+
+ if (num < 0 || num >= MAX_OSD) {
+ print_error("given OSD number out of range");
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ osd_width[num] = _osd_width;
+ osd_height[num] = _osd_height;
+
+ /* generate texture */
+ for (osd_size[num] = 1; osd_size[num] <= osd_width[num] || osd_size[num] <= osd_height[num]; osd_size[num] *= 2)
+ ;
+ osd_rgba[num] = calloc(osd_size[num] * osd_size[num], 4);
+ if (!osd_rgba[num]) {
+ print_error("Failed to allocate texture\n");
+ rc = -ENOMEM;
+ goto error;
+ }
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
+ glGenTextures(1, &osd_name[num]);
+ glBindTexture(GL_TEXTURE_2D, osd_name[num]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, osd_size[num], osd_size[num], 0, GL_RGBA, GL_UNSIGNED_BYTE, osd_rgba[num]);
+
+ return 0;
+
+error:
+ return rc;
+}
+
/* set clip planes so that the image portion of the image texture is centered and pixels are rectengular */
void resize_opengl(int _screen_width, int _screen_height)
{
screen_height = _screen_height;
}
-
void opengl_clear(void)
{
+ /* clear screen */
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
if (view_width < 1 || view_height < 1)
return;
- /* viewport and projection matrix */
+ /* viewport and projection matrix to view rectangle */
glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
/* render legacy image texture */
-void opengl_render_legacy(uint8_t *rgb, int filter)
+void opengl_blit_legacy(uint8_t *rgb, int filter)
{
double width = (double)image_width / (double)texture_size;
double height = (double)image_height / (double)texture_size;
glEnable(GL_TEXTURE_2D);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); /* no modulation with color */
glBindTexture(GL_TEXTURE_2D, legacy_name);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
glDisable(GL_TEXTURE_2D);
}
-static double fov = 64.0;
-
/* set viewport for improved rendering */
-void opengl_viewport_improved(int split, int benson_at_line)
+void opengl_viewport_improved(int split, int benson_at_line, double fov, double benson_size)
{
int view_x, view_y;
int view_width, view_height;
/* make frustum to center the view in the game view above benson */
double left = -slope;
double right = slope;
- double top = slope * (double)benson_at_line / (double)image_width;
- double bottom = -slope * ((double)image_height * 2.0 - (double)benson_at_line) / (double)image_width;
+ double benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
+ double top = slope * ((double)image_height - benson_start_at_position) / (double)image_width;
+ double bottom = -slope * ((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
glFrustum(left, right, bottom, top, 1.0, 5000000000.0);
glMatrixMode(GL_MODELVIEW);
-
-#if 1
- /* test rectangle */
- glColor3d(0.5, 0.4, 0.4);
- glBegin(GL_QUADS);
- glVertex3f(-1.0, -1.0, -1.0);
- glVertex3f(1.0, -1.0, -1.0);
- glVertex3f(1.0, 1.0, -1.0);
- glVertex3f(-1.0, 1.0, -1.0);
- glEnd();
-#endif
}
/* render only benson */
-void opengl_render_benson(uint8_t *rgb, int filter, int benson_at_line)
+void opengl_blit_benson(uint8_t *rgb, int filter, int benson_at_line, double fov, double benson_size, int pixel_size)
{
- double texture_left = 0.0;
- double texture_right = (double)image_width / (double)texture_size;
- double texture_top = (double)benson_at_line / (double)texture_size;
- double texture_bottom = (double)image_height / (double)texture_size;
- double benson_top = -(double)benson_at_line / (double)image_width;
- double benson_bottom = -((double)image_height * 2.0 - (double)benson_at_line) / (double)image_width;
+ double border = (benson_size != 1.0) ? (double)pixel_size : 0.0;
+ double texture_left = border / (double)texture_size;
+ double texture_right = ((double)image_width - border) / (double)texture_size;
+ double texture_top = ((double)benson_at_line + border) / (double)texture_size;
+ double texture_bottom = ((double)image_height -border) / (double)texture_size;
+ double benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
+ double benson_top = -((double)image_height - benson_start_at_position) / (double)image_width;
+ double benson_bottom = -((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
/* calculate field-of-view */
double slope = tan(fov / 360 * M_PI);
/* render benson */
rgb += image_width * benson_at_line * 3;
glEnable(GL_TEXTURE_2D);
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); /* no modulation with color */
glBindTexture(GL_TEXTURE_2D, benson_name);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, benson_at_line, image_width, image_height - benson_at_line, GL_RGB, GL_UNSIGNED_BYTE, rgb);
glBegin(GL_QUADS);
glTexCoord2f(texture_left, texture_bottom);
- glVertex3f(-2.0, 2.0 * benson_bottom, -2.0 / slope);
+ glVertex3f(-100.0 * benson_size, 100.0 * benson_bottom, -100.0 / slope);
glTexCoord2f(texture_right, texture_bottom);
- glVertex3f(2.0, 2.0 * benson_bottom, -2.0 / slope);
+ glVertex3f(100.0 * benson_size, 100.0 * benson_bottom, -100.0 / slope);
glTexCoord2f(texture_right, texture_top);
- glVertex3f(2.0, 2.0 * benson_top, -2.0 / slope);
+ glVertex3f(100.0 * benson_size, 100.0 * benson_top, -100.0 / slope);
glTexCoord2f(texture_left, texture_top);
- glVertex3f(-2.0, 2.0 * benson_top, -2.0 / slope);
+ glVertex3f(-100.0 * benson_size, 100.0 * benson_top, -100.0 / slope);
glEnd();
glDisable(GL_TEXTURE_2D);
}
+/* render osd texture */
+void opengl_blit_osd(int num, uint8_t *rgba, int filter, int benson_at_line, double fov, double benson_size, double scale_x, double scale_y, double offset_x, double offset_y)
+{
+ double texture_left = 0.0;
+ double texture_right = (double)osd_width[num] / (double)osd_size[num];
+ double texture_top = 0.0;
+ double texture_bottom = (double)osd_height[num] / (double)osd_size[num];
+ double benson_start_at_position;
+ double osd_left = 0.0;
+ double osd_right = 1.0;
+ double osd_top = 0.0;
+ double osd_bottom = 1.0;
+ double slope, range, center;
+ if (fov) {
+ osd_left = -1.0;
+ osd_right = 1.0;
+ benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
+ osd_top = ((double)image_height - benson_start_at_position) / (double)image_width;
+ osd_bottom = -((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
+ /* calculate field-of-view */
+ slope = tan(fov / 360 * M_PI);
+ }
+ range = (osd_right - osd_left) / 2.0;
+ center = (osd_right + osd_left) / 2.0;
+ osd_left = (osd_left - center) * scale_x + center + range * offset_x;
+ osd_right = (osd_right - center) * scale_x + center + range * offset_x;
+ range = (osd_bottom - osd_top) / 2.0;
+ center = (osd_bottom + osd_top) / 2.0;
+ osd_top = (osd_top - center) * scale_y + center + range * offset_y;
+ osd_bottom = (osd_bottom - center) * scale_y + center + range * offset_y;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, osd_name[num]);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, osd_width[num], osd_height[num], GL_RGBA, GL_UNSIGNED_BYTE, rgba);
+ glBegin(GL_QUADS);
+ if (fov) {
+ /* perspective viewport */
+ glTexCoord2f(texture_left, texture_bottom);
+ glVertex3f(100.0 * osd_left, 100.0 * osd_bottom, -100.0 / slope);
+ glTexCoord2f(texture_right, texture_bottom);
+ glVertex3f(100.0 * osd_right, 100.0 * osd_bottom, -100.0 / slope);
+ glTexCoord2f(texture_right, texture_top);
+ glVertex3f(100.0 * osd_right, 100.0 * osd_top, -100.0 / slope);
+ glTexCoord2f(texture_left, texture_top);
+ glVertex3f(100.0 * osd_left, 100.0 * osd_top, -100.0 / slope);
+ } else {
+ /* orthogonal viewport */
+ glTexCoord2f(texture_left, texture_top);
+ glVertex3f(osd_left, osd_top, 0.0);
+ glTexCoord2f(texture_right, texture_top);
+ glVertex3f(osd_right, osd_top, 0.0);
+ glTexCoord2f(texture_right, texture_bottom);
+ glVertex3f(osd_right, osd_bottom, 0.0);
+ glTexCoord2f(texture_left, texture_bottom);
+ glVertex3f(osd_left, osd_bottom, 0.0);
+ }
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+}
+
+/* set color and opacity */
+void opengl_render_color(double r, double g, double b, double a)
+{
+ if (a < 1.0) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glColor4d(r, g, b, a);
+ } else {
+ glDisable(GL_BLEND);
+ glColor3d(r, g, b);
+ }
+}
+
+/* render polygon */
+void opengl_render_polygon(double *x, double *y, double *z, int count, int cull_face)
+{
+ int i;
+
+ if (cull_face) {
+ glEnable(GL_CULL_FACE);
+ glFrontFace(GL_CW);
+ glCullFace(GL_BACK);
+ }
+ glBegin(GL_POLYGON);
+ for (i = 0; i < count; i++)
+ glVertex3d(x[i], y[i], -z[i]);
+ glEnd();
+ if (cull_face)
+ glDisable(GL_CULL_FACE);
+}
+
+/* render polygon, but make sure any size of it is visible */
+void opengl_render_polygon_and_line(double *x, double *y, double *z, int count)
+{
+ int i;
+
+ glBegin(GL_POLYGON);
+ for (i = 0; i < count; i++)
+ glVertex3d(x[i], y[i], -z[i]);
+ glEnd();
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < count; i++)
+ glVertex3d(x[i], y[i], -z[i]);
+ glEnd();
+}
+
+/* render line */
+void opengl_render_line(double x1, double y1, double z1, double x2, double y2, double z2, double size)
+{
+ if (size == 0.0) {
+ glBegin(GL_LINES);
+ glVertex3f(x1, y1, -z1);
+ glVertex3f(x2, y2, -z2);
+ glEnd();
+ return;
+ }
+}
+
+/* render point */
+void opengl_render_point(double x, double y, double z, double size)
+{
+ if (size == 0.0) {
+ glBegin(GL_POINTS);
+ glVertex3f(x, y, -z);
+ glEnd();
+ return;
+ }
+}
+
/* free image texture */
void exit_opengl(void)
{
+ int i;
+
if (legacy_rgb) {
free(legacy_rgb);
legacy_rgb = NULL;
free(benson_rgb);
benson_rgb = NULL;
}
+ for (i = 0; i < MAX_OSD; i++) {
+ if (osd_rgba[i]) {
+ free(osd_rgba[i]);
+ osd_rgba[i] = NULL;
+ }
+ }
}