1
0
mirror of https://github.com/FunkyFr3sh/cnc-ddraw.git synced 2025-03-16 14:28:52 +01:00
2018-09-18 01:14:18 +02:00

1028 lines
30 KiB
C

/*
* Copyright (c) 2010 Toni Spets <toni.spets@iki.fi>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <windows.h>
#include <stdio.h>
#include "opengl.h"
#include "main.h"
#include "surface.h"
#include "paletteshader.h"
#define TEXTURE_COUNT 4
char OpenglVersion[128];
static HGLRC OpenGLContext;
static int MaxFPS;
static BOOL VSyncEnabled;
static DWORD FrameLength;
static GLuint PaletteConvertProgram;
static GLuint ScaleProgram;
static BOOL GotError;
static int SurfaceTexWidth;
static int SurfaceTexHeight;
static int *SurfaceTex;
static GLenum SurfaceFormat = GL_LUMINANCE;
static GLuint SurfaceTexIds[TEXTURE_COUNT];
static GLuint PaletteTexIds[TEXTURE_COUNT];
static float ScaleW;
static float ScaleH;
static GLint MainTexCoordAttrLoc = -1;
static GLint MainVertexCoordAttrLoc = -1;
static GLuint MainVBOs[3], MainVAO;
static GLint FrameCountUniLoc = -1;
static GLuint FrameBufferId;
static GLuint FrameBufferTexId;
static GLuint ScaleVBOs[3], ScaleVAO;
static BOOL UseOpenGL;
static HGLRC CreateContext(HDC hdc);
static void SetMaxFPS(int baseMaxFPS);
static void BuildPrograms();
static void CreateTextures(int width, int height);
static void InitPaletteConvertProgram();
static void InitScaleProgram();
static void Render();
static void DeleteContext(HGLRC context);
static BOOL TextureUploadTest();
static BOOL ShaderTest();
BOOL detect_cutscene();
DWORD WINAPI render_soft_main(void);
DWORD WINAPI render_main(void)
{
Sleep(500);
GotError = UseOpenGL = FALSE;
OpenGLContext = CreateContext(ddraw->render.hDC);
if (OpenGLContext)
{
OpenGL_Init();
SetMaxFPS(ddraw->render.maxfps);
BuildPrograms();
CreateTextures(ddraw->width, ddraw->height);
InitPaletteConvertProgram();
InitScaleProgram();
GotError = GotError || !TextureUploadTest();
GotError = GotError || !ShaderTest();
GotError = GotError || glGetError() != GL_NO_ERROR;
UseOpenGL = !(ddraw->autorenderer && (!PaletteConvertProgram || GotError));
Render();
DeleteContext(OpenGLContext);
}
if (!UseOpenGL)
{
ddraw->renderer = render_soft_main;
render_soft_main();
}
return 0;
}
static HGLRC CreateContext(HDC hdc)
{
HGLRC context = wglCreateContext(hdc);
BOOL madeCurrent = context && wglMakeCurrent(hdc, context);
char *glversion = (char *)glGetString(GL_VERSION);
if (glversion)
{
strncpy(OpenglVersion, glversion, sizeof(OpenglVersion));
const char deli[2] = " ";
strtok(OpenglVersion, deli);
}
else
OpenglVersion[0] = '0';
if (!madeCurrent || (ddraw->autorenderer && glGetError() != GL_NO_ERROR))
{
if (madeCurrent)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(context);
}
context = 0;
}
return context;
}
static void SetMaxFPS(int baseMaxFPS)
{
MaxFPS = baseMaxFPS;
VSyncEnabled = FALSE;
if (OpenGL_ExtExists("WGL_EXT_swap_control_tear", ddraw->render.hDC))
{
if (wglSwapIntervalEXT)
{
if (ddraw->vsync)
{
wglSwapIntervalEXT(-1);
MaxFPS = 1000;
VSyncEnabled = TRUE;
}
else
wglSwapIntervalEXT(0);
}
}
else if (OpenGL_ExtExists("WGL_EXT_swap_control", ddraw->render.hDC))
{
if (wglSwapIntervalEXT)
{
if (ddraw->vsync)
{
wglSwapIntervalEXT(1);
MaxFPS = 1000;
VSyncEnabled = TRUE;
}
else
wglSwapIntervalEXT(0);
}
}
if (MaxFPS < 0)
MaxFPS = ddraw->mode.dmDisplayFrequency;
if (MaxFPS == 0)
MaxFPS = 125;
if (MaxFPS >= 1000)
MaxFPS = 0;
if (MaxFPS > 0)
FrameLength = 1000.0f / MaxFPS;
}
static void BuildPrograms()
{
PaletteConvertProgram = ScaleProgram = 0;
if (OpenGL_GotVersion3)
{
PaletteConvertProgram = OpenGL_BuildProgram(PassthroughVertShaderSrc, PaletteFragShaderSrc);
ScaleProgram = OpenGL_BuildProgramFromFile(ddraw->shader);
}
else if (OpenGL_GotVersion2)
{
PaletteConvertProgram = OpenGL_BuildProgram(PassthroughVertShader110Src, PaletteFragShader110Src);
}
}
static void CreateTextures(int width, int height)
{
SurfaceTexWidth =
width <= 1024 ? 1024 : width <= 2048 ? 2048 : width <= 4096 ? 4096 : width;
SurfaceTexHeight =
height <= 512 ? 512 : height <= 1024 ? 1024 : height <= 2048 ? 2048 : height <= 4096 ? 4096 : height;
SurfaceTex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, SurfaceTexWidth * SurfaceTexHeight * sizeof(int));
ScaleW = (float)width / SurfaceTexWidth;
ScaleH = (float)height / SurfaceTexHeight;
glGenTextures(TEXTURE_COUNT, SurfaceTexIds);
int i;
for (i = 0; i < TEXTURE_COUNT; i++)
{
glBindTexture(GL_TEXTURE_2D, SurfaceTexIds[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GotError = GotError || glGetError() != GL_NO_ERROR;
while (glGetError() != GL_NO_ERROR);
if (PaletteConvertProgram)
{
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_LUMINANCE8,
SurfaceTexWidth,
SurfaceTexHeight,
0,
SurfaceFormat = GL_LUMINANCE,
GL_UNSIGNED_BYTE,
0);
if (glGetError() != GL_NO_ERROR)
{
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_R8,
SurfaceTexWidth,
SurfaceTexHeight,
0,
SurfaceFormat = GL_RED,
GL_UNSIGNED_BYTE,
0);
}
if (glGetError() != GL_NO_ERROR)
{
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
SurfaceTexWidth,
SurfaceTexHeight,
0,
SurfaceFormat = GL_RED,
GL_UNSIGNED_BYTE,
0);
}
if (!ddraw->autorenderer && glGetError() != GL_NO_ERROR) // very slow...
{
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA8,
SurfaceTexWidth,
SurfaceTexHeight,
0,
SurfaceFormat = GL_RED,
GL_UNSIGNED_BYTE,
0);
}
}
else
{
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA8,
SurfaceTexWidth,
SurfaceTexHeight,
0,
SurfaceFormat = GL_RGBA,
GL_UNSIGNED_BYTE,
0);
}
}
glGenTextures(TEXTURE_COUNT, PaletteTexIds);
for (i = 0; i < TEXTURE_COUNT; i++)
{
glBindTexture(GL_TEXTURE_2D, PaletteTexIds[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
}
static void InitPaletteConvertProgram()
{
if (!PaletteConvertProgram)
return;
glUseProgram(PaletteConvertProgram);
glUniform1i(glGetUniformLocation(PaletteConvertProgram, "SurfaceTex"), 0);
glUniform1i(glGetUniformLocation(PaletteConvertProgram, "PaletteTex"), 1);
if (OpenGL_GotVersion3)
{
MainVertexCoordAttrLoc = glGetAttribLocation(PaletteConvertProgram, "VertexCoord");
MainTexCoordAttrLoc = glGetAttribLocation(PaletteConvertProgram, "TexCoord");
glGenBuffers(3, MainVBOs);
if (ScaleProgram)
{
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[0]);
static const GLfloat vertexCoord[] = {
-1.0f,-1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
1.0f,-1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[1]);
GLfloat texCoord[] = {
0.0f, 0.0f,
0.0f, ScaleH,
ScaleW, ScaleH,
ScaleW, 0.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoord), texCoord, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
else
{
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[0]);
static const GLfloat vertexCoord[] = {
-1.0f, 1.0f,
1.0f, 1.0f,
1.0f,-1.0f,
-1.0f,-1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[1]);
GLfloat texCoord[] = {
0.0f, 0.0f,
ScaleW, 0.0f,
ScaleW, ScaleH,
0.0f, ScaleH,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoord), texCoord, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glGenVertexArrays(1, &MainVAO);
glBindVertexArray(MainVAO);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[0]);
glVertexAttribPointer(MainVertexCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(MainVertexCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[1]);
glVertexAttribPointer(MainTexCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(MainTexCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, MainVBOs[2]);
static const GLushort indices[] =
{
0, 1, 2,
0, 2, 3,
};
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0);
const float mvpMatrix[16] = {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1,
};
glUniformMatrix4fv(glGetUniformLocation(PaletteConvertProgram, "MVPMatrix"), 1, GL_FALSE, mvpMatrix);
}
}
static void InitScaleProgram()
{
if (!ScaleProgram)
return;
glUseProgram(ScaleProgram);
GLint vertexCoordAttrLoc = glGetAttribLocation(ScaleProgram, "VertexCoord");
GLint texCoordAttrLoc = glGetAttribLocation(ScaleProgram, "TexCoord");
FrameCountUniLoc = glGetUniformLocation(ScaleProgram, "FrameCount");
glGenBuffers(3, ScaleVBOs);
glBindBuffer(GL_ARRAY_BUFFER, ScaleVBOs[0]);
static const GLfloat vertexCoord[] = {
-1.0f, 1.0f,
1.0f, 1.0f,
1.0f,-1.0f,
-1.0f,-1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexCoord), vertexCoord, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, ScaleVBOs[1]);
GLfloat texCoord[] = {
0.0f, 0.0f,
ScaleW, 0.0f,
ScaleW, ScaleH,
0.0f, ScaleH,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoord), texCoord, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &ScaleVAO);
glBindVertexArray(ScaleVAO);
glBindBuffer(GL_ARRAY_BUFFER, ScaleVBOs[0]);
glVertexAttribPointer(vertexCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(vertexCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, ScaleVBOs[1]);
glVertexAttribPointer(texCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(texCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ScaleVBOs[2]);
static const GLushort indices[] =
{
0, 1, 2,
0, 2, 3,
};
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0);
float inputSize[2], outputSize[2], textureSize[2];
inputSize[0] = ddraw->width;
inputSize[1] = ddraw->height;
textureSize[0] = SurfaceTexWidth;
textureSize[1] = SurfaceTexHeight;
outputSize[0] = ddraw->render.viewport.width;
outputSize[1] = ddraw->render.viewport.height;
glUniform2fv(glGetUniformLocation(ScaleProgram, "OutputSize"), 1, outputSize);
glUniform2fv(glGetUniformLocation(ScaleProgram, "TextureSize"), 1, textureSize);
glUniform2fv(glGetUniformLocation(ScaleProgram, "InputSize"), 1, inputSize);
glUniform1i(glGetUniformLocation(ScaleProgram, "FrameDirection"), 1);
glUniform1i(glGetUniformLocation(ScaleProgram, "Texture"), 0);
const float mvpMatrix[16] = {
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1,
};
glUniformMatrix4fv(glGetUniformLocation(ScaleProgram, "MVPMatrix"), 1, GL_FALSE, mvpMatrix);
glGenFramebuffers(1, &FrameBufferId);
glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferId);
glGenTextures(1, &FrameBufferTexId);
glBindTexture(GL_TEXTURE_2D, FrameBufferTexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, SurfaceTexWidth, SurfaceTexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FrameBufferTexId, 0);
GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, drawBuffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteTextures(1, &FrameBufferTexId);
if (glDeleteFramebuffers)
glDeleteFramebuffers(1, &FrameBufferId);
if (glDeleteProgram)
glDeleteProgram(ScaleProgram);
ScaleProgram = 0;
if (glDeleteBuffers)
glDeleteBuffers(3, ScaleVBOs);
if (glDeleteVertexArrays)
glDeleteVertexArrays(1, &ScaleVAO);
if (PaletteConvertProgram)
{
glBindVertexArray(MainVAO);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[0]);
static const GLfloat vertexCoordPal[] = {
-1.0f, 1.0f,
1.0f, 1.0f,
1.0f,-1.0f,
-1.0f,-1.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexCoordPal), vertexCoordPal, GL_STATIC_DRAW);
glVertexAttribPointer(MainVertexCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(MainVertexCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindVertexArray(MainVAO);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[1]);
GLfloat texCoordPal[] = {
0.0f, 0.0f,
ScaleW, 0.0f,
ScaleW, ScaleH,
0.0f, ScaleH,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoordPal), texCoordPal, GL_STATIC_DRAW);
glVertexAttribPointer(MainTexCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(MainTexCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
static void Render()
{
DWORD tick_start = 0;
DWORD tick_end = 0;
glViewport(
ddraw->render.viewport.x, ddraw->render.viewport.y,
ddraw->render.viewport.width, ddraw->render.viewport.height);
if (PaletteConvertProgram)
glUseProgram(PaletteConvertProgram);
else
glEnable(GL_TEXTURE_2D);
while (UseOpenGL && ddraw->render.run && WaitForSingleObject(ddraw->render.sem, INFINITE) != WAIT_FAILED)
{
#if _DEBUG
static DWORD tick_fps = 0;
static DWORD frame_count = 0;
static char debugText[512] = { 0 };
static double frameTime = 0;
RECT debugrc = { 0, 0, ddraw->width, ddraw->height };
if (ddraw->primary && ddraw->primary->palette)
DrawText(ddraw->primary->hDC, debugText, -1, &debugrc, DT_NOCLIP);
tick_start = timeGetTime();
if (tick_start >= tick_fps)
{
snprintf(
debugText,
sizeof(debugText),
"FPS: %lu | Time: %2.2f ms ",
frame_count,
frameTime);
frame_count = 0;
tick_fps = tick_start + 1000;
CounterStart();
}
frame_count++;
#endif
ScaleW = (float)ddraw->width / SurfaceTexWidth;
ScaleH = (float)ddraw->height / SurfaceTexHeight;
static int texIndex = 0, palIndex = 0;
BOOL scaleChanged = FALSE;
if (MaxFPS > 0)
tick_start = timeGetTime();
EnterCriticalSection(&ddraw->cs);
if (ddraw->primary && ddraw->primary->palette)
{
if (ddraw->vhack)
{
if (detect_cutscene())
{
ScaleW *= (float)CUTSCENE_WIDTH / ddraw->width;
ScaleH *= (float)CUTSCENE_HEIGHT / ddraw->height;
if (!InterlockedExchange(&ddraw->incutscene, TRUE))
scaleChanged = TRUE;
}
else
{
if (InterlockedExchange(&ddraw->incutscene, FALSE))
scaleChanged = TRUE;
}
}
if (PaletteConvertProgram)
{
if (InterlockedExchange(&ddraw->render.paletteUpdated, FALSE))
{
if (++palIndex >= TEXTURE_COUNT)
palIndex = 0;
glBindTexture(GL_TEXTURE_2D, PaletteTexIds[palIndex]);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
256,
1,
GL_RGBA,
GL_UNSIGNED_BYTE,
ddraw->primary->palette->data_bgr);
}
if (InterlockedExchange(&ddraw->render.surfaceUpdated, FALSE))
{
if (++texIndex >= TEXTURE_COUNT)
texIndex = 0;
glBindTexture(GL_TEXTURE_2D, SurfaceTexIds[texIndex]);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
ddraw->width,
ddraw->height,
SurfaceFormat,
GL_UNSIGNED_BYTE,
ddraw->primary->surface);
}
}
else
{
int i, j;
for (i = 0; i<ddraw->height; i++)
{
int i_dst = i*ddraw->width;
int i_src = i*ddraw->primary->lPitch;
for (j = 0; j<ddraw->width; j++)
{
SurfaceTex[i_dst + j] =
ddraw->primary->palette->data_bgr[
((unsigned char *)ddraw->primary->surface)[i_src + j*ddraw->primary->lXPitch]];
}
}
}
static int errorCheckCount = 0;
if (ddraw->autorenderer && errorCheckCount < 3)
{
errorCheckCount++;
glFinish();
if (glGetError() != GL_NO_ERROR)
UseOpenGL = FALSE;
}
}
LeaveCriticalSection(&ddraw->cs);
if (!PaletteConvertProgram)
{
glBindTexture(GL_TEXTURE_2D, SurfaceTexIds[texIndex]);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
ddraw->width,
ddraw->height,
GL_RGBA,
GL_UNSIGNED_BYTE,
SurfaceTex);
}
if (scaleChanged)
{
if (ScaleProgram && PaletteConvertProgram)
{
glBindVertexArray(MainVAO);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[1]);
GLfloat texCoord[] = {
0.0f, 0.0f,
0.0f, ScaleH,
ScaleW, ScaleH,
ScaleW, 0.0f,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoord), texCoord, GL_STATIC_DRAW);
glVertexAttribPointer(MainTexCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(MainTexCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
else if (OpenGL_GotVersion3 && PaletteConvertProgram)
{
glBindVertexArray(MainVAO);
glBindBuffer(GL_ARRAY_BUFFER, MainVBOs[1]);
GLfloat texCoord[] = {
0.0f, 0.0f,
ScaleW, 0.0f,
ScaleW, ScaleH,
0.0f, ScaleH,
};
glBufferData(GL_ARRAY_BUFFER, sizeof(texCoord), texCoord, GL_STATIC_DRAW);
glVertexAttribPointer(MainTexCoordAttrLoc, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(MainTexCoordAttrLoc);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
}
if (PaletteConvertProgram)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, SurfaceTexIds[texIndex]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, PaletteTexIds[palIndex]);
glActiveTexture(GL_TEXTURE0);
}
if (ScaleProgram && PaletteConvertProgram)
{
// draw surface into framebuffer
glUseProgram(PaletteConvertProgram);
glViewport(0, 0, ddraw->width, ddraw->height);
glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferId);
glBindVertexArray(MainVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glViewport(
ddraw->render.viewport.x, ddraw->render.viewport.y,
ddraw->render.viewport.width, ddraw->render.viewport.height);
// apply filter
glUseProgram(ScaleProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, FrameBufferTexId);
static int frames = 1;
if (FrameCountUniLoc != -1)
glUniform1i(FrameCountUniLoc, frames++);
glBindVertexArray(ScaleVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
}
else if (OpenGL_GotVersion3 && PaletteConvertProgram)
{
glBindVertexArray(MainVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
}
else
{
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0, 0); glVertex2f(-1, 1);
glTexCoord2f(ScaleW, 0); glVertex2f(1, 1);
glTexCoord2f(ScaleW, ScaleH); glVertex2f(1, -1);
glTexCoord2f(0, ScaleH); glVertex2f(-1, -1);
glEnd();
}
SwapBuffers(ddraw->render.hDC);
if (VSyncEnabled)
glFinish();
#if _DEBUG
if (frame_count == 1) frameTime = CounterStop();
#endif
if (MaxFPS > 0)
{
tick_end = timeGetTime();
if (tick_end - tick_start < FrameLength)
Sleep(FrameLength - (tick_end - tick_start));
}
}
}
static void DeleteContext(HGLRC context)
{
HeapFree(GetProcessHeap(), 0, SurfaceTex);
glDeleteTextures(TEXTURE_COUNT, SurfaceTexIds);
glDeleteTextures(TEXTURE_COUNT, PaletteTexIds);
if (glUseProgram)
glUseProgram(0);
if (ScaleProgram)
{
glDeleteTextures(1, &FrameBufferTexId);
if (glDeleteBuffers)
glDeleteBuffers(3, ScaleVBOs);
if (glDeleteFramebuffers)
glDeleteFramebuffers(1, &FrameBufferId);
if (glDeleteVertexArrays)
glDeleteVertexArrays(1, &ScaleVAO);
}
if (glDeleteProgram)
{
if (PaletteConvertProgram)
glDeleteProgram(PaletteConvertProgram);
if (ScaleProgram)
glDeleteProgram(ScaleProgram);
}
if (OpenGL_GotVersion3)
{
if (PaletteConvertProgram)
{
if (glDeleteBuffers)
glDeleteBuffers(3, MainVBOs);
if (glDeleteVertexArrays)
glDeleteVertexArrays(1, &MainVAO);
}
}
wglMakeCurrent(NULL, NULL);
wglDeleteContext(context);
}
static BOOL TextureUploadTest()
{
static char testData[] = { 0,1,2,0,0,2,3,0,0,4,5,0,0,6,7,0,0,8,9,0 };
int i;
for (i = 0; i < TEXTURE_COUNT; i++)
{
memcpy(SurfaceTex, testData, sizeof(testData));
glBindTexture(GL_TEXTURE_2D, SurfaceTexIds[i]);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
ddraw->width,
ddraw->height,
SurfaceFormat,
GL_UNSIGNED_BYTE,
SurfaceTex);
glFinish();
memset(SurfaceTex, 0, sizeof(testData));
glGetTexImage(GL_TEXTURE_2D, 0, SurfaceFormat, GL_UNSIGNED_BYTE, SurfaceTex);
glFinish();
if (memcmp(SurfaceTex, testData, sizeof(testData)) != 0)
return FALSE;
}
for (i = 0; i < TEXTURE_COUNT; i++)
{
glBindTexture(GL_TEXTURE_2D, PaletteTexIds[i]);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
256,
1,
GL_RGBA,
GL_UNSIGNED_BYTE,
SurfaceTex);
glFinish();
memset(SurfaceTex, 0, sizeof(testData));
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, SurfaceTex);
glFinish();
if (memcmp(SurfaceTex, testData, sizeof(testData)) != 0)
return FALSE;
}
return TRUE;
}
static BOOL ShaderTest()
{
if (OpenGL_GotVersion3 && PaletteConvertProgram)
{
memset(SurfaceTex, 0, SurfaceTexHeight * SurfaceTexWidth * sizeof(int));
GLuint fboId = 0;
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
GLuint fboTexId = 0;
glGenTextures(1, &fboTexId);
glBindTexture(GL_TEXTURE_2D, fboTexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, SurfaceTexWidth, SurfaceTexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, SurfaceTex);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTexId, 0);
GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, drawBuffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE)
{
static char gray0pal[] = { 128,128,128,128 };
glBindTexture(GL_TEXTURE_2D, PaletteTexIds[0]);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
1,
1,
GL_RGBA,
GL_UNSIGNED_BYTE,
gray0pal);
glBindTexture(GL_TEXTURE_2D, SurfaceTexIds[0]);
glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
SurfaceTexWidth,
SurfaceTexHeight,
SurfaceFormat,
GL_UNSIGNED_BYTE,
SurfaceTex);
glViewport(0, 0, SurfaceTexWidth, SurfaceTexHeight);
glUseProgram(PaletteConvertProgram);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, PaletteTexIds[0]);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(MainVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glFinish();
glBindTexture(GL_TEXTURE_2D, fboTexId);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, SurfaceTex);
glFinish();
int i;
for (i = 0; i < SurfaceTexHeight * SurfaceTexWidth; i++)
{
if (SurfaceTex[i] != 0x80808080)
return FALSE;
}
}
glBindTexture(GL_TEXTURE_2D, 0);
if (glDeleteFramebuffers)
glDeleteFramebuffers(1, &fboId);
glDeleteTextures(1, &fboTexId);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
return TRUE;
}