2019-03-31 18:51:31 -06:00
|
|
|
/*
|
|
|
|
Copyright 2016-2019 Arisotura
|
|
|
|
|
|
|
|
This file is part of melonDS.
|
|
|
|
|
|
|
|
melonDS is free software: you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free
|
|
|
|
Software Foundation, either version 3 of the License, or (at your option)
|
|
|
|
any later version.
|
|
|
|
|
|
|
|
melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
|
|
with melonDS. If not, see http://www.gnu.org/licenses/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <GL/gl.h>
|
|
|
|
#include <GL/glext.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "NDS.h"
|
|
|
|
#include "GPU.h"
|
|
|
|
#include "Platform.h"
|
|
|
|
|
|
|
|
namespace GPU3D
|
|
|
|
{
|
|
|
|
namespace GLRenderer43
|
|
|
|
{
|
|
|
|
|
2019-03-31 20:20:43 -06:00
|
|
|
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
|
|
|
|
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
|
|
|
|
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
|
|
|
|
PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture;
|
2019-03-31 18:51:31 -06:00
|
|
|
|
2019-03-31 20:20:43 -06:00
|
|
|
PFNGLGENBUFFERSPROC glGenBuffers;
|
|
|
|
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
|
|
|
|
PFNGLBINDBUFFERPROC glBindBuffer;
|
|
|
|
PFNGLMAPBUFFERPROC glMapBuffer;
|
|
|
|
PFNGLMAPBUFFERRANGEPROC glMapBufferRange;
|
|
|
|
PFNGLUNMAPBUFFERPROC glUnmapBuffer;
|
|
|
|
PFNGLBUFFERDATAPROC glBufferData;
|
2019-04-10 14:49:06 -06:00
|
|
|
PFNGLBUFFERSUBDATAPROC glBufferSubData;
|
|
|
|
|
|
|
|
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
|
|
|
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
|
|
|
|
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
|
|
|
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
|
2019-05-01 18:28:31 -06:00
|
|
|
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
|
2019-04-10 14:49:06 -06:00
|
|
|
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
|
2019-04-24 14:38:50 -06:00
|
|
|
PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;
|
2019-03-31 18:51:31 -06:00
|
|
|
|
2019-04-09 15:23:24 -06:00
|
|
|
PFNGLCREATESHADERPROC glCreateShader;
|
|
|
|
PFNGLSHADERSOURCEPROC glShaderSource;
|
|
|
|
PFNGLCOMPILESHADERPROC glCompileShader;
|
|
|
|
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
|
|
|
PFNGLATTACHSHADERPROC glAttachShader;
|
|
|
|
PFNGLLINKPROGRAMPROC glLinkProgram;
|
|
|
|
PFNGLUSEPROGRAMPROC glUseProgram;
|
|
|
|
PFNGLGETSHADERIVPROC glGetShaderiv;
|
|
|
|
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
|
|
|
PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
|
|
|
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
|
|
|
PFNGLDELETESHADERPROC glDeleteShader;
|
|
|
|
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
2019-05-01 18:28:31 -06:00
|
|
|
PFNGLUNIFORM1UIPROC glUniform1ui;
|
|
|
|
PFNGLUNIFORM4UIPROC glUniform4ui;
|
2019-04-09 15:23:24 -06:00
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
PFNGLACTIVETEXTUREPROC glActiveTexture;
|
2019-04-24 14:38:50 -06:00
|
|
|
PFNGLBINDIMAGETEXTUREPROC glBindImageTexture;
|
2019-04-09 15:23:24 -06:00
|
|
|
|
2019-04-24 14:38:50 -06:00
|
|
|
PFNGLGETSTRINGIPROC glGetStringi;
|
|
|
|
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
#define kShaderHeader "#version 430"
|
|
|
|
|
|
|
|
|
|
|
|
const char* kClearVS = kShaderHeader R"(
|
|
|
|
|
|
|
|
layout(location=0) in vec2 vPosition;
|
|
|
|
|
|
|
|
layout(location=1) uniform uint uDepth;
|
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
|
|
|
float fdepth = (float(uDepth) / 8388608.0) - 1.0;
|
|
|
|
gl_Position = vec4(vPosition, fdepth, 1.0);
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
|
|
|
const char* kClearFS = kShaderHeader R"(
|
|
|
|
|
|
|
|
layout(location=0) uniform uvec4 uColor;
|
|
|
|
|
|
|
|
out vec4 oColor;
|
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
|
|
|
oColor = vec4(uColor).bgra / 255.0;
|
|
|
|
}
|
|
|
|
)";
|
2019-04-25 05:32:15 -06:00
|
|
|
|
|
|
|
|
|
|
|
const char* kRenderVSCommon = R"(
|
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
layout(location=0) in uvec4 vPosition;
|
|
|
|
layout(location=1) in uvec4 vColor;
|
|
|
|
layout(location=2) in ivec2 vTexcoord;
|
|
|
|
layout(location=3) in uvec3 vPolygonAttr;
|
|
|
|
|
|
|
|
smooth out vec4 fColor;
|
|
|
|
smooth out vec2 fTexcoord;
|
|
|
|
flat out uvec3 fPolygonAttr;
|
2019-04-25 05:32:15 -06:00
|
|
|
)";
|
|
|
|
|
|
|
|
const char* kRenderFSCommon = R"(
|
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
layout(binding=0) uniform usampler2D TexMem;
|
|
|
|
layout(binding=1) uniform sampler2D TexPalMem;
|
|
|
|
|
|
|
|
smooth in vec4 fColor;
|
|
|
|
smooth in vec2 fTexcoord;
|
|
|
|
flat in uvec3 fPolygonAttr;
|
|
|
|
|
|
|
|
out vec4 oColor;
|
|
|
|
|
|
|
|
vec4 TextureLookup()
|
|
|
|
{
|
|
|
|
uint attr = fPolygonAttr.y;
|
|
|
|
uint paladdr = fPolygonAttr.z;
|
|
|
|
|
2019-04-29 10:47:32 -06:00
|
|
|
float alpha0;
|
|
|
|
if ((attr & (1<<29)) != 0) alpha0 = 0.0;
|
|
|
|
else alpha0 = 1.0;
|
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
int tw = 8 << int((attr >> 20) & 0x7);
|
|
|
|
int th = 8 << int((attr >> 23) & 0x7);
|
|
|
|
|
|
|
|
int vramaddr = int(attr & 0xFFFF) << 3;
|
|
|
|
ivec2 st = ivec2(fTexcoord);
|
|
|
|
|
2019-04-29 10:24:36 -06:00
|
|
|
if ((attr & (1<<16)) != 0)
|
|
|
|
{
|
|
|
|
if ((attr & (1<<18)) != 0)
|
|
|
|
{
|
|
|
|
if ((st.x & tw) != 0)
|
|
|
|
st.x = (tw-1) - (st.x & (tw-1));
|
|
|
|
else
|
|
|
|
st.x = (st.x & (tw-1));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
st.x &= (tw-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
st.x = clamp(st.x, 0, tw-1);
|
|
|
|
|
|
|
|
if ((attr & (1<<17)) != 0)
|
|
|
|
{
|
|
|
|
if ((attr & (1<<19)) != 0)
|
|
|
|
{
|
|
|
|
if ((st.y & th) != 0)
|
|
|
|
st.y = (th-1) - (st.y & (th-1));
|
|
|
|
else
|
|
|
|
st.y = (st.y & (th-1));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
st.y &= (th-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
st.y = clamp(st.y, 0, th-1);
|
2019-04-28 20:19:56 -06:00
|
|
|
|
|
|
|
uint type = (attr >> 26) & 0x7;
|
2019-04-29 10:47:32 -06:00
|
|
|
if (type == 1)
|
|
|
|
{
|
|
|
|
vramaddr += ((st.y * tw) + st.x);
|
|
|
|
uvec4 pixel = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
|
|
|
|
pixel.a = (pixel.r & 0xE0);
|
|
|
|
pixel.a = (pixel.a >> 3) + (pixel.a >> 6);
|
|
|
|
pixel.r &= 0x1F;
|
|
|
|
|
|
|
|
paladdr = (paladdr << 3) + pixel.r;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
|
|
|
|
return vec4(color.rgb, float(pixel.a)/31.0);
|
|
|
|
}
|
|
|
|
else if (type == 2)
|
|
|
|
{
|
|
|
|
vramaddr += ((st.y * tw) + st.x) >> 2;
|
|
|
|
uvec4 pixel = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
pixel.r >>= (2 * (st.x & 3));
|
|
|
|
pixel.r &= 0x03;
|
|
|
|
|
|
|
|
paladdr = (paladdr << 2) + pixel.r;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
|
2019-04-29 10:52:23 -06:00
|
|
|
return vec4(color.rgb, max(step(1,pixel.r),alpha0));
|
2019-04-29 10:47:32 -06:00
|
|
|
}
|
|
|
|
else if (type == 3)
|
|
|
|
{
|
|
|
|
vramaddr += ((st.y * tw) + st.x) >> 1;
|
|
|
|
uvec4 pixel = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
if ((st.x & 1) != 0) pixel.r >>= 4;
|
|
|
|
else pixel.r &= 0x0F;
|
|
|
|
|
|
|
|
paladdr = (paladdr << 3) + pixel.r;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
|
2019-04-29 10:52:23 -06:00
|
|
|
return vec4(color.rgb, max(step(1,pixel.r),alpha0));
|
2019-04-29 10:47:32 -06:00
|
|
|
}
|
|
|
|
else if (type == 4)
|
2019-04-28 20:19:56 -06:00
|
|
|
{
|
|
|
|
vramaddr += ((st.y * tw) + st.x);
|
|
|
|
uvec4 pixel = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
|
|
|
|
paladdr = (paladdr << 3) + pixel.r;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
|
2019-04-29 10:52:23 -06:00
|
|
|
return vec4(color.rgb, max(step(1,pixel.r),alpha0));
|
2019-04-28 20:19:56 -06:00
|
|
|
}
|
2019-04-29 05:05:15 -06:00
|
|
|
else if (type == 5)
|
|
|
|
{
|
|
|
|
vramaddr += ((st.y & 0x3FC) * (tw>>2)) + (st.x & 0x3FC) + (st.y & 0x3);
|
|
|
|
uvec4 p = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
uint val = (p.r >> (2 * (st.x & 0x3))) & 0x3;
|
|
|
|
|
|
|
|
int slot1addr = 0x20000 + ((vramaddr & 0x1FFFC) >> 1);
|
|
|
|
if (vramaddr >= 0x40000) slot1addr += 0x10000;
|
|
|
|
|
|
|
|
uint palinfo;
|
|
|
|
p = texelFetch(TexMem, ivec2(slot1addr&0x3FF, slot1addr>>10), 0);
|
|
|
|
palinfo = p.r;
|
|
|
|
slot1addr++;
|
|
|
|
p = texelFetch(TexMem, ivec2(slot1addr&0x3FF, slot1addr>>10), 0);
|
|
|
|
palinfo |= (p.r << 8);
|
|
|
|
|
|
|
|
paladdr = (paladdr << 3) + ((palinfo & 0x3FFF) << 1);
|
|
|
|
palinfo >>= 14;
|
|
|
|
|
|
|
|
if (val == 0)
|
|
|
|
{
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
return vec4(color.rgb, 1.0);
|
|
|
|
}
|
|
|
|
else if (val == 1)
|
|
|
|
{
|
|
|
|
paladdr++;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
return vec4(color.rgb, 1.0);
|
|
|
|
}
|
|
|
|
else if (val == 2)
|
|
|
|
{
|
|
|
|
if (palinfo == 1)
|
|
|
|
{
|
|
|
|
vec4 color0 = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
paladdr++;
|
|
|
|
vec4 color1 = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
return vec4((color0.rgb + color1.rgb) / 2.0, 1.0);
|
|
|
|
}
|
|
|
|
else if (palinfo == 3)
|
|
|
|
{
|
|
|
|
vec4 color0 = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
paladdr++;
|
|
|
|
vec4 color1 = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
return vec4((color0.rgb*5.0 + color1.rgb*3.0) / 8.0, 1.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
paladdr += 2;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
return vec4(color.rgb, 1.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (palinfo == 2)
|
|
|
|
{
|
|
|
|
paladdr += 3;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
return vec4(color.rgb, 1.0);
|
|
|
|
}
|
|
|
|
else if (palinfo == 3)
|
|
|
|
{
|
|
|
|
vec4 color0 = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
paladdr++;
|
|
|
|
vec4 color1 = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
|
|
|
return vec4((color0.rgb*3.0 + color1.rgb*5.0) / 8.0, 1.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return vec4(0.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-29 10:47:32 -06:00
|
|
|
else if (type == 6)
|
|
|
|
{
|
|
|
|
vramaddr += ((st.y * tw) + st.x);
|
|
|
|
uvec4 pixel = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
|
|
|
|
pixel.a = (pixel.r & 0xF8) >> 3;
|
|
|
|
pixel.r &= 0x07;
|
|
|
|
|
|
|
|
paladdr = (paladdr << 3) + pixel.r;
|
|
|
|
vec4 color = texelFetch(TexPalMem, ivec2(paladdr&0x3FF, paladdr>>10), 0);
|
2019-04-28 20:19:56 -06:00
|
|
|
|
2019-04-29 10:47:32 -06:00
|
|
|
return vec4(color.rgb, float(pixel.a)/31.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vramaddr += ((st.y * tw) + st.x) << 1;
|
|
|
|
uvec4 pixelL = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
vramaddr++;
|
|
|
|
uvec4 pixelH = texelFetch(TexMem, ivec2(vramaddr&0x3FF, vramaddr>>10), 0);
|
|
|
|
|
|
|
|
vec4 color;
|
|
|
|
color.r = float(pixelL.r & 0x1F) / 31.0;
|
|
|
|
color.g = float((pixelL.r >> 5) | ((pixelH.r & 0x03) << 3)) / 31.0;
|
|
|
|
color.b = float((pixelH.r & 0x7C) >> 2) / 31.0;
|
|
|
|
color.a = float(pixelH.r >> 7);
|
|
|
|
|
|
|
|
return color;
|
|
|
|
}
|
2019-04-28 20:19:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
vec4 FinalColor()
|
2019-04-25 05:32:15 -06:00
|
|
|
{
|
2019-04-28 20:19:56 -06:00
|
|
|
vec4 col;
|
|
|
|
vec4 vcol = vec4(fColor.rgb,1.0);
|
|
|
|
|
2019-04-29 10:47:32 -06:00
|
|
|
// TODO: also check DISPCNT
|
|
|
|
if (((fPolygonAttr.y >> 26) & 0x7) == 0)
|
|
|
|
{
|
|
|
|
// no texture
|
|
|
|
col = vcol;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vec4 tcol = TextureLookup();
|
|
|
|
|
|
|
|
col = vcol * tcol;
|
|
|
|
}
|
2019-04-28 20:19:56 -06:00
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
return col.bgra * vec4(63.0/255.0, 63.0/255.0, 63.0/255.0, 31.0/255.0);
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
|
|
const char* kRenderVS_Z = R"(
|
2019-04-09 15:23:24 -06:00
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
2019-04-24 14:38:50 -06:00
|
|
|
uint attr = vPolygonAttr.x;
|
|
|
|
uint zshift = (attr >> 16) & 0x1F;
|
|
|
|
|
2019-04-10 14:49:06 -06:00
|
|
|
vec4 fpos;
|
2019-04-10 15:25:01 -06:00
|
|
|
fpos.x = ((float(vPosition.x) * 2.0) / 256.0) - 1.0;
|
|
|
|
fpos.y = ((float(vPosition.y) * 2.0) / 192.0) - 1.0;
|
2019-04-29 11:13:20 -06:00
|
|
|
fpos.z = (float(vPosition.z << zshift) / 8388608.0) - 1.0;
|
2019-04-25 05:32:15 -06:00
|
|
|
fpos.w = float(vPosition.w) / 65536.0f;
|
2019-04-10 15:55:34 -06:00
|
|
|
fpos.xyz *= fpos.w;
|
2019-04-10 14:49:06 -06:00
|
|
|
|
2019-04-10 15:47:58 -06:00
|
|
|
fColor = vec4(vColor) / vec4(255.0,255.0,255.0,31.0);
|
2019-04-28 20:19:56 -06:00
|
|
|
fTexcoord = vec2(vTexcoord) / 16.0;
|
|
|
|
fPolygonAttr = vPolygonAttr;
|
2019-04-10 15:25:01 -06:00
|
|
|
|
2019-04-10 14:49:06 -06:00
|
|
|
gl_Position = fpos;
|
2019-04-09 15:23:24 -06:00
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
const char* kRenderVS_W = R"(
|
|
|
|
|
|
|
|
smooth out float fZ;
|
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
|
|
|
uint attr = vPolygonAttr.x;
|
|
|
|
uint zshift = (attr >> 16) & 0x1F;
|
|
|
|
|
|
|
|
vec4 fpos;
|
|
|
|
fpos.x = ((float(vPosition.x) * 2.0) / 256.0) - 1.0;
|
|
|
|
fpos.y = ((float(vPosition.y) * 2.0) / 192.0) - 1.0;
|
|
|
|
fZ = float(vPosition.z << zshift) / 16777216.0;
|
|
|
|
fpos.w = float(vPosition.w) / 65536.0f;
|
|
|
|
fpos.xy *= fpos.w;
|
|
|
|
|
|
|
|
fColor = vec4(vColor) / vec4(255.0,255.0,255.0,31.0);
|
2019-04-28 20:19:56 -06:00
|
|
|
fTexcoord = vec2(vTexcoord) / 16.0;
|
|
|
|
fPolygonAttr = vPolygonAttr;
|
2019-04-25 05:32:15 -06:00
|
|
|
|
|
|
|
gl_Position = fpos;
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
const char* kRenderFS_ZO = R"(
|
2019-04-09 15:23:24 -06:00
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
2019-05-01 15:35:48 -06:00
|
|
|
vec4 col = FinalColor();
|
|
|
|
if (col.a < 31.0/255.0) discard;
|
|
|
|
|
|
|
|
oColor = col;
|
2019-04-09 15:23:24 -06:00
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
const char* kRenderFS_WO = R"(
|
2019-04-09 15:23:24 -06:00
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
smooth in float fZ;
|
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
2019-05-01 15:35:48 -06:00
|
|
|
vec4 col = FinalColor();
|
|
|
|
if (col.a < 31.0/255.0) discard;
|
2019-04-25 05:32:15 -06:00
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
oColor = col;
|
|
|
|
gl_FragDepth = fZ;
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
|
|
|
const char* kRenderFS_ZT = R"(
|
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
|
|
|
vec4 col = FinalColor();
|
|
|
|
if (col.a > 30.0/255.0) discard;
|
|
|
|
|
|
|
|
oColor = col;
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
|
|
|
const char* kRenderFS_WT = R"(
|
|
|
|
|
|
|
|
smooth in float fZ;
|
|
|
|
|
|
|
|
void main()
|
|
|
|
{
|
|
|
|
vec4 col = FinalColor();
|
|
|
|
if (col.a > 30.0/255.0) discard;
|
|
|
|
|
|
|
|
oColor = col;
|
2019-04-25 05:32:15 -06:00
|
|
|
gl_FragDepth = fZ;
|
|
|
|
}
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
RenderFlag_WBuffer = 0x01,
|
2019-05-01 15:35:48 -06:00
|
|
|
RenderFlag_Trans = 0x02,
|
2019-04-25 05:32:15 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
GLuint ClearShaderPlain[3];
|
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
GLuint RenderShader[16][3];
|
2019-03-31 20:20:43 -06:00
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
Polygon* PolyData;
|
|
|
|
|
|
|
|
u16* Indices;
|
|
|
|
u32 RenderKey;
|
|
|
|
|
|
|
|
} RendererPolygon;
|
|
|
|
|
|
|
|
RendererPolygon PolygonList[2048];
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
GLuint ClearVertexBufferID, ClearVertexArrayID;
|
|
|
|
|
2019-04-10 14:49:06 -06:00
|
|
|
// vertex buffer
|
|
|
|
// * XYZW: 4x16bit
|
|
|
|
// * RGBA: 4x8bit
|
|
|
|
// * ST: 2x16bit
|
|
|
|
// * polygon data: 3x32bit (polygon/texture attributes)
|
|
|
|
//
|
|
|
|
// polygon attributes:
|
|
|
|
// * bit4-7, 11, 14-15, 24-29: POLYGON_ATTR
|
|
|
|
// * bit16-20: Z shift
|
|
|
|
// * bit8: front-facing (?)
|
2019-04-25 05:32:15 -06:00
|
|
|
// * bit9: W-buffering (?)
|
2019-04-10 14:49:06 -06:00
|
|
|
|
|
|
|
GLuint VertexBufferID;
|
|
|
|
u32 VertexBuffer[10240 * 7];
|
|
|
|
u32 NumVertices;
|
|
|
|
|
|
|
|
GLuint VertexArrayID;
|
|
|
|
u16 IndexBuffer[2048 * 10];
|
|
|
|
u32 NumTriangles;
|
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
GLuint TexMemID;
|
|
|
|
GLuint TexPalMemID;
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
GLuint FramebufferTex[3];
|
2019-03-31 20:20:43 -06:00
|
|
|
GLuint FramebufferID, PixelbufferID;
|
2019-03-31 18:51:31 -06:00
|
|
|
u8 Framebuffer[256*192*4];
|
|
|
|
u8 CurLine[256*4];
|
|
|
|
|
|
|
|
|
|
|
|
bool InitGLExtensions()
|
|
|
|
{
|
|
|
|
#define LOADPROC(type, name) \
|
|
|
|
name = (PFN##type##PROC)Platform::GL_GetProcAddress(#name); \
|
2019-03-31 20:50:48 -06:00
|
|
|
if (!name) { printf("OpenGL: " #name " not found\n"); return false; }
|
2019-03-31 18:51:31 -06:00
|
|
|
|
|
|
|
LOADPROC(GLGENFRAMEBUFFERS, glGenFramebuffers);
|
2019-03-31 20:20:43 -06:00
|
|
|
LOADPROC(GLDELETEFRAMEBUFFERS, glDeleteFramebuffers);
|
2019-03-31 18:51:31 -06:00
|
|
|
LOADPROC(GLBINDFRAMEBUFFER, glBindFramebuffer);
|
|
|
|
LOADPROC(GLFRAMEBUFFERTEXTURE, glFramebufferTexture);
|
|
|
|
|
2019-03-31 20:20:43 -06:00
|
|
|
LOADPROC(GLGENBUFFERS, glGenBuffers);
|
|
|
|
LOADPROC(GLDELETEBUFFERS, glDeleteBuffers);
|
|
|
|
LOADPROC(GLBINDBUFFER, glBindBuffer);
|
|
|
|
LOADPROC(GLMAPBUFFER, glMapBuffer);
|
|
|
|
LOADPROC(GLMAPBUFFERRANGE, glMapBufferRange);
|
|
|
|
LOADPROC(GLUNMAPBUFFER, glUnmapBuffer);
|
|
|
|
LOADPROC(GLBUFFERDATA, glBufferData);
|
2019-04-10 14:49:06 -06:00
|
|
|
LOADPROC(GLBUFFERSUBDATA, glBufferSubData);
|
|
|
|
|
|
|
|
LOADPROC(GLGENVERTEXARRAYS, glGenVertexArrays);
|
|
|
|
LOADPROC(GLDELETEVERTEXARRAYS, glDeleteVertexArrays);
|
|
|
|
LOADPROC(GLBINDVERTEXARRAY, glBindVertexArray);
|
|
|
|
LOADPROC(GLENABLEVERTEXATTRIBARRAY, glEnableVertexAttribArray);
|
2019-05-01 18:28:31 -06:00
|
|
|
LOADPROC(GLDISABLEVERTEXATTRIBARRAY, glDisableVertexAttribArray);
|
2019-04-10 14:49:06 -06:00
|
|
|
LOADPROC(GLVERTEXATTRIBPOINTER, glVertexAttribPointer);
|
|
|
|
LOADPROC(GLVERTEXATTRIBIPOINTER, glVertexAttribIPointer);
|
2019-03-31 20:20:43 -06:00
|
|
|
|
2019-04-09 15:23:24 -06:00
|
|
|
LOADPROC(GLCREATESHADER, glCreateShader);
|
|
|
|
LOADPROC(GLSHADERSOURCE, glShaderSource);
|
|
|
|
LOADPROC(GLCOMPILESHADER, glCompileShader);
|
|
|
|
LOADPROC(GLCREATEPROGRAM, glCreateProgram);
|
|
|
|
LOADPROC(GLATTACHSHADER, glAttachShader);
|
|
|
|
LOADPROC(GLLINKPROGRAM, glLinkProgram);
|
|
|
|
LOADPROC(GLUSEPROGRAM, glUseProgram);
|
|
|
|
LOADPROC(GLGETSHADERIV, glGetShaderiv);
|
|
|
|
LOADPROC(GLGETSHADERINFOLOG, glGetShaderInfoLog);
|
|
|
|
LOADPROC(GLGETPROGRAMIV, glGetProgramiv);
|
|
|
|
LOADPROC(GLGETPROGRAMINFOLOG, glGetProgramInfoLog);
|
|
|
|
LOADPROC(GLDELETESHADER, glDeleteShader);
|
|
|
|
LOADPROC(GLDELETEPROGRAM, glDeleteProgram);
|
2019-05-01 18:28:31 -06:00
|
|
|
LOADPROC(GLUNIFORM1UI, glUniform1ui);
|
|
|
|
LOADPROC(GLUNIFORM4UI, glUniform4ui);
|
2019-04-09 15:23:24 -06:00
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
LOADPROC(GLACTIVETEXTURE, glActiveTexture);
|
2019-04-24 14:38:50 -06:00
|
|
|
LOADPROC(GLBINDIMAGETEXTURE, glBindImageTexture);
|
|
|
|
|
|
|
|
LOADPROC(GLGETSTRINGI, glGetStringi);
|
|
|
|
|
2019-03-31 18:51:31 -06:00
|
|
|
#undef LOADPROC
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-09 15:23:24 -06:00
|
|
|
bool BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char* name)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
int res;
|
|
|
|
|
|
|
|
ids[0] = glCreateShader(GL_VERTEX_SHADER);
|
|
|
|
len = strlen(vs);
|
|
|
|
glShaderSource(ids[0], 1, &vs, &len);
|
|
|
|
glCompileShader(ids[0]);
|
|
|
|
|
|
|
|
glGetShaderiv(ids[0], GL_COMPILE_STATUS, &res);
|
|
|
|
if (res != GL_TRUE)
|
|
|
|
{
|
|
|
|
glGetShaderiv(ids[0], GL_INFO_LOG_LENGTH, &res);
|
|
|
|
if (res < 1) res = 1024;
|
|
|
|
char* log = new char[res+1];
|
|
|
|
glGetShaderInfoLog(ids[0], res+1, NULL, log);
|
|
|
|
printf("OpenGL: failed to compile vertex shader %s: %s\n", name, log);
|
2019-04-28 20:19:56 -06:00
|
|
|
printf("shader source:\n--\n%s\n--\n", vs);
|
2019-04-09 15:23:24 -06:00
|
|
|
delete[] log;
|
|
|
|
|
|
|
|
glDeleteShader(ids[0]);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ids[1] = glCreateShader(GL_FRAGMENT_SHADER);
|
2019-04-10 14:49:06 -06:00
|
|
|
len = strlen(fs);
|
2019-04-09 15:23:24 -06:00
|
|
|
glShaderSource(ids[1], 1, &fs, &len);
|
|
|
|
glCompileShader(ids[1]);
|
|
|
|
|
|
|
|
glGetShaderiv(ids[1], GL_COMPILE_STATUS, &res);
|
|
|
|
if (res != GL_TRUE)
|
|
|
|
{
|
|
|
|
glGetShaderiv(ids[1], GL_INFO_LOG_LENGTH, &res);
|
|
|
|
if (res < 1) res = 1024;
|
|
|
|
char* log = new char[res+1];
|
|
|
|
glGetShaderInfoLog(ids[1], res+1, NULL, log);
|
|
|
|
printf("OpenGL: failed to compile fragment shader %s: %s\n", name, log);
|
2019-04-28 20:19:56 -06:00
|
|
|
printf("shader source:\n--\n%s\n--\n", fs);
|
2019-04-09 15:23:24 -06:00
|
|
|
delete[] log;
|
|
|
|
|
|
|
|
glDeleteShader(ids[0]);
|
|
|
|
glDeleteShader(ids[1]);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
ids[2] = glCreateProgram();
|
|
|
|
glAttachShader(ids[2], ids[0]);
|
|
|
|
glAttachShader(ids[2], ids[1]);
|
|
|
|
glLinkProgram(ids[2]);
|
|
|
|
|
|
|
|
glGetProgramiv(ids[2], GL_LINK_STATUS, &res);
|
|
|
|
if (res != GL_TRUE)
|
|
|
|
{
|
|
|
|
glGetProgramiv(ids[2], GL_INFO_LOG_LENGTH, &res);
|
|
|
|
if (res < 1) res = 1024;
|
|
|
|
char* log = new char[res+1];
|
|
|
|
glGetProgramInfoLog(ids[2], res+1, NULL, log);
|
|
|
|
printf("OpenGL: failed to link program %s: %s\n", name, log);
|
|
|
|
delete[] log;
|
|
|
|
|
|
|
|
glDeleteShader(ids[0]);
|
|
|
|
glDeleteShader(ids[1]);
|
|
|
|
glDeleteProgram(ids[2]);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
bool BuildRenderShader(u32 flags, const char* vs, const char* fs)
|
|
|
|
{
|
|
|
|
char shadername[32];
|
|
|
|
sprintf(shadername, "RenderShader%02X", flags);
|
|
|
|
|
|
|
|
int headerlen = strlen(kShaderHeader);
|
|
|
|
|
|
|
|
int vslen = strlen(vs);
|
|
|
|
int vsclen = strlen(kRenderVSCommon);
|
|
|
|
char* vsbuf = new char[headerlen + vsclen + vslen + 1];
|
|
|
|
strcpy(&vsbuf[0], kShaderHeader);
|
|
|
|
strcpy(&vsbuf[headerlen], kRenderVSCommon);
|
|
|
|
strcpy(&vsbuf[headerlen + vsclen], vs);
|
|
|
|
|
|
|
|
int fslen = strlen(fs);
|
|
|
|
int fsclen = strlen(kRenderFSCommon);
|
|
|
|
char* fsbuf = new char[headerlen + fsclen + fslen + 1];
|
|
|
|
strcpy(&fsbuf[0], kShaderHeader);
|
|
|
|
strcpy(&fsbuf[headerlen], kRenderFSCommon);
|
|
|
|
strcpy(&fsbuf[headerlen + fsclen], fs);
|
|
|
|
|
|
|
|
bool ret = BuildShaderProgram(vsbuf, fsbuf, RenderShader[flags], shadername);
|
|
|
|
|
|
|
|
delete[] vsbuf;
|
|
|
|
delete[] fsbuf;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UseRenderShader(u32 flags)
|
|
|
|
{
|
|
|
|
glUseProgram(RenderShader[flags][2]);
|
|
|
|
}
|
|
|
|
|
2019-03-31 18:51:31 -06:00
|
|
|
bool Init()
|
|
|
|
{
|
|
|
|
if (!InitGLExtensions()) return false;
|
|
|
|
|
2019-04-09 15:23:24 -06:00
|
|
|
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
|
|
|
|
const GLubyte* version = glGetString(GL_VERSION); // version as a string
|
|
|
|
printf("OpenGL: renderer: %s\n", renderer);
|
|
|
|
printf("OpenGL: version: %s\n", version);
|
|
|
|
|
2019-04-24 14:38:50 -06:00
|
|
|
int barg1, barg2;
|
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &barg1);
|
|
|
|
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &barg2);
|
|
|
|
printf("max texture: %d\n", barg1);
|
|
|
|
printf("max comb. texture: %d\n", barg2);
|
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &barg1);
|
|
|
|
printf("max tex size: %d\n", barg1);
|
|
|
|
|
2019-04-24 14:38:50 -06:00
|
|
|
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &barg1);
|
|
|
|
printf("max arraytex levels: %d\n", barg1);
|
|
|
|
|
|
|
|
/*glGetIntegerv(GL_NUM_EXTENSIONS, &barg1);
|
|
|
|
printf("extensions: %d\n", barg1);
|
|
|
|
for (int i = 0; i < barg1; i++)
|
|
|
|
{
|
|
|
|
const GLubyte* ext = glGetStringi(GL_EXTENSIONS, i);
|
|
|
|
printf("- %s\n", ext);
|
|
|
|
}*/
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
2019-04-09 15:23:24 -06:00
|
|
|
|
2019-04-10 14:49:06 -06:00
|
|
|
// TODO: make configurable (hires, etc)
|
|
|
|
glViewport(0, 0, 256, 192);
|
|
|
|
glDepthRange(0, 1);
|
2019-04-24 14:38:50 -06:00
|
|
|
glClearDepth(1.0);
|
2019-04-10 14:49:06 -06:00
|
|
|
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
if (!BuildShaderProgram(kClearVS, kClearFS, ClearShaderPlain, "ClearShader"))
|
|
|
|
return false;
|
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
if (!BuildRenderShader(0,
|
|
|
|
kRenderVS_Z, kRenderFS_ZO)) return false;
|
|
|
|
if (!BuildRenderShader(RenderFlag_WBuffer,
|
|
|
|
kRenderVS_W, kRenderFS_WO)) return false;
|
|
|
|
if (!BuildRenderShader(RenderFlag_Trans,
|
|
|
|
kRenderVS_Z, kRenderFS_ZT)) return false;
|
|
|
|
if (!BuildRenderShader(RenderFlag_Trans | RenderFlag_WBuffer,
|
|
|
|
kRenderVS_W, kRenderFS_WT)) return false;
|
2019-04-09 15:23:24 -06:00
|
|
|
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
float clearvtx[6*2] =
|
|
|
|
{
|
|
|
|
-1.0, -1.0,
|
|
|
|
1.0, 1.0,
|
|
|
|
-1.0, 1.0,
|
|
|
|
|
|
|
|
-1.0, -1.0,
|
|
|
|
1.0, -1.0,
|
|
|
|
1.0, 1.0
|
|
|
|
};
|
|
|
|
|
|
|
|
glGenBuffers(1, &ClearVertexBufferID);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(clearvtx), clearvtx, GL_STATIC_DRAW);
|
|
|
|
|
|
|
|
glGenVertexArrays(1, &ClearVertexArrayID);
|
|
|
|
glBindVertexArray(ClearVertexArrayID);
|
|
|
|
glEnableVertexAttribArray(0); // position
|
|
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
|
|
|
|
|
|
|
|
|
2019-04-10 14:49:06 -06:00
|
|
|
glGenBuffers(1, &VertexBufferID);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexBuffer), NULL, GL_DYNAMIC_DRAW);
|
|
|
|
|
|
|
|
glGenVertexArrays(1, &VertexArrayID);
|
|
|
|
glBindVertexArray(VertexArrayID);
|
|
|
|
glEnableVertexAttribArray(0); // position
|
|
|
|
glVertexAttribIPointer(0, 4, GL_UNSIGNED_SHORT, 7*4, (void*)(0));
|
|
|
|
glEnableVertexAttribArray(1); // color
|
|
|
|
glVertexAttribIPointer(1, 4, GL_UNSIGNED_BYTE, 7*4, (void*)(2*4));
|
|
|
|
glEnableVertexAttribArray(2); // texcoords
|
2019-04-28 20:19:56 -06:00
|
|
|
glVertexAttribIPointer(2, 2, GL_SHORT, 7*4, (void*)(3*4));
|
2019-04-10 14:49:06 -06:00
|
|
|
glEnableVertexAttribArray(3); // attrib
|
|
|
|
glVertexAttribIPointer(3, 3, GL_UNSIGNED_INT, 7*4, (void*)(4*4));
|
|
|
|
|
|
|
|
|
2019-03-31 18:51:31 -06:00
|
|
|
glGenFramebuffers(1, &FramebufferID);
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID);
|
|
|
|
|
2019-04-24 14:38:50 -06:00
|
|
|
glGenTextures(1, &FramebufferTex[0]);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, FramebufferTex[0]);
|
2019-03-31 18:51:31 -06:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
2019-04-24 14:38:50 -06:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, FramebufferTex[0], 0);
|
|
|
|
|
|
|
|
glGenTextures(1, &FramebufferTex[1]);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, FramebufferTex[1]);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 256, 192, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); // welp
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, FramebufferTex[1], 0);
|
2019-03-31 18:51:31 -06:00
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
glGenTextures(1, &FramebufferTex[2]);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, FramebufferTex[2]);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX, 256, 192, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
glFramebufferTexture(GL_FRAMEBUFFER, GL_STENCIL_INDEX, FramebufferTex[2], 0);
|
|
|
|
|
2019-03-31 20:20:43 -06:00
|
|
|
glGenBuffers(1, &PixelbufferID);
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, PixelbufferID);
|
2019-03-31 20:58:21 -06:00
|
|
|
//glBufferData(GL_PIXEL_PACK_BUFFER, 256*48*4, NULL, GL_DYNAMIC_READ);
|
|
|
|
glBufferData(GL_PIXEL_PACK_BUFFER, 256*192*4, NULL, GL_DYNAMIC_READ);
|
2019-03-31 20:20:43 -06:00
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glGenTextures(1, &TexMemID);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, TexMemID);
|
2019-04-24 14:38:50 -06:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
2019-04-28 20:19:56 -06:00
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, 1024, 512, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glGenTextures(1, &TexPalMemID);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, TexPalMemID);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 1024, 48, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
|
2019-04-24 14:38:50 -06:00
|
|
|
|
2019-03-31 18:51:31 -06:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeInit()
|
|
|
|
{
|
2019-04-24 14:38:50 -06:00
|
|
|
// TODO CLEAN UP SHIT!!!!
|
2019-03-31 18:51:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void Reset()
|
|
|
|
{
|
|
|
|
//
|
|
|
|
}
|
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
|
|
|
|
void SetupPolygon(RendererPolygon* rp, Polygon* polygon)
|
|
|
|
{
|
|
|
|
rp->PolyData = polygon;
|
|
|
|
|
|
|
|
// render key: depending on what we're drawing
|
|
|
|
// opaque polygons:
|
|
|
|
// - depthfunc
|
|
|
|
// -- alpha=0
|
|
|
|
// regular translucent polygons:
|
|
|
|
// - depthfunc
|
|
|
|
// -- depthwrite
|
|
|
|
// --- polyID
|
|
|
|
// shadow mask polygons:
|
|
|
|
// - depthfunc?????
|
|
|
|
// shadow polygons:
|
|
|
|
// - depthfunc
|
|
|
|
// -- depthwrite
|
|
|
|
// --- polyID
|
|
|
|
|
|
|
|
rp->RenderKey = (polygon->Attr >> 14) & 0x1; // bit14 - depth func
|
|
|
|
if (!polygon->IsShadowMask)
|
|
|
|
{
|
|
|
|
if (polygon->Translucent)
|
|
|
|
{
|
|
|
|
rp->RenderKey |= (polygon->Attr >> 10) & 0x2; // bit11 - depth write
|
|
|
|
rp->RenderKey |= (polygon->Attr & 0x3F000000) >> 16; // polygon ID
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ((polygon->Attr & 0x001F0000) == 0)
|
|
|
|
rp->RenderKey |= 0x2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BuildPolygons(RendererPolygon* polygons, int npolys)
|
2019-04-10 14:49:06 -06:00
|
|
|
{
|
|
|
|
u32* vptr = &VertexBuffer[0];
|
|
|
|
u32 vidx = 0;
|
|
|
|
|
|
|
|
u16* iptr = &IndexBuffer[0];
|
|
|
|
u32 numtriangles = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < npolys; i++)
|
|
|
|
{
|
2019-05-01 15:35:48 -06:00
|
|
|
RendererPolygon* rp = &polygons[i];
|
|
|
|
Polygon* poly = rp->PolyData;
|
2019-04-10 14:49:06 -06:00
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
rp->Indices = iptr;
|
2019-04-28 20:19:56 -06:00
|
|
|
|
2019-04-10 14:49:06 -06:00
|
|
|
u32 vidx_first = vidx;
|
|
|
|
|
|
|
|
u32 polyattr = poly->Attr;
|
|
|
|
|
|
|
|
u32 alpha = (polyattr >> 16) & 0x1F;
|
|
|
|
|
|
|
|
u32 vtxattr = polyattr & 0x1F00C8F0;
|
|
|
|
if (poly->FacingView) vtxattr |= (1<<8);
|
|
|
|
if (poly->WBuffer) vtxattr |= (1<<9);
|
|
|
|
|
|
|
|
// assemble vertices
|
|
|
|
for (int j = 0; j < poly->NumVertices; j++)
|
|
|
|
{
|
|
|
|
Vertex* vtx = poly->Vertices[j];
|
|
|
|
|
|
|
|
u32 z = poly->FinalZ[j];
|
|
|
|
u32 w = poly->FinalW[j];
|
|
|
|
|
|
|
|
// Z should always fit within 16 bits, so it's okay to do this
|
|
|
|
u32 zshift = 0;
|
|
|
|
while (z > 0xFFFF) { z >>= 1; zshift++; }
|
|
|
|
|
|
|
|
// TODO hires-upgraded positions?
|
|
|
|
*vptr++ = vtx->FinalPosition[0] | (vtx->FinalPosition[1] << 16);
|
|
|
|
*vptr++ = z | (w << 16);
|
2019-04-24 14:38:50 -06:00
|
|
|
|
2019-04-10 14:49:06 -06:00
|
|
|
*vptr++ = (vtx->FinalColor[0] >> 1) |
|
|
|
|
((vtx->FinalColor[1] >> 1) << 8) |
|
|
|
|
((vtx->FinalColor[2] >> 1) << 16) |
|
|
|
|
(alpha << 24);
|
|
|
|
|
2019-04-29 05:05:15 -06:00
|
|
|
*vptr++ = (u16)vtx->TexCoords[0] | ((u16)vtx->TexCoords[1] << 16);
|
2019-04-10 14:49:06 -06:00
|
|
|
|
|
|
|
*vptr++ = vtxattr | (zshift << 16);
|
|
|
|
*vptr++ = poly->TexParam;
|
|
|
|
*vptr++ = poly->TexPalette;
|
|
|
|
|
|
|
|
if (j >= 2)
|
|
|
|
{
|
|
|
|
// build a triangle
|
|
|
|
*iptr++ = vidx_first;
|
|
|
|
*iptr++ = vidx - 1;
|
|
|
|
*iptr++ = vidx;
|
|
|
|
numtriangles++;
|
|
|
|
}
|
|
|
|
|
|
|
|
vidx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NumTriangles = numtriangles;
|
|
|
|
NumVertices = vidx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-31 18:51:31 -06:00
|
|
|
void VCount144()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderFrame()
|
|
|
|
{
|
2019-04-28 20:19:56 -06:00
|
|
|
// SUCKY!!!!!!!!!!!!!!!!!!
|
|
|
|
// TODO: detect when VRAM blocks are modified!
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, TexMemID);
|
|
|
|
for (int i = 0; i < 4; i++)
|
2019-04-24 14:38:50 -06:00
|
|
|
{
|
2019-04-28 20:19:56 -06:00
|
|
|
u32 mask = GPU::VRAMMap_Texture[i];
|
|
|
|
u8* vram;
|
|
|
|
if (!mask) continue;
|
|
|
|
else if (mask & (1<<0)) vram = GPU::VRAM_A;
|
|
|
|
else if (mask & (1<<1)) vram = GPU::VRAM_B;
|
|
|
|
else if (mask & (1<<2)) vram = GPU::VRAM_C;
|
|
|
|
else if (mask & (1<<3)) vram = GPU::VRAM_D;
|
|
|
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i*128, 1024, 128, GL_RED_INTEGER, GL_UNSIGNED_BYTE, vram);
|
2019-04-24 14:38:50 -06:00
|
|
|
}
|
2019-04-10 14:49:06 -06:00
|
|
|
|
2019-04-28 20:19:56 -06:00
|
|
|
glActiveTexture(GL_TEXTURE1);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, TexPalMemID);
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
// 6 x 16K chunks
|
|
|
|
u32 mask = GPU::VRAMMap_TexPal[i];
|
|
|
|
u8* vram;
|
|
|
|
if (!mask) continue;
|
|
|
|
else if (mask & (1<<4)) vram = &GPU::VRAM_E[(i&3)*0x4000];
|
|
|
|
else if (mask & (1<<5)) vram = GPU::VRAM_F;
|
|
|
|
else if (mask & (1<<6)) vram = GPU::VRAM_G;
|
|
|
|
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i*8, 1024, 8, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, vram);
|
|
|
|
}
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
// clear buffers
|
|
|
|
// TODO: clear bitmap
|
|
|
|
{
|
|
|
|
glUseProgram(ClearShaderPlain[2]);
|
|
|
|
glDepthFunc(GL_ALWAYS);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
|
|
|
|
u32 r = RenderClearAttr1 & 0x1F;
|
|
|
|
u32 g = (RenderClearAttr1 >> 5) & 0x1F;
|
|
|
|
u32 b = (RenderClearAttr1 >> 10) & 0x1F;
|
|
|
|
u32 a = (RenderClearAttr1 >> 16) & 0x1F;
|
|
|
|
u32 z = ((RenderClearAttr2 & 0x7FFF) * 0x200) + 0x1FF;
|
|
|
|
|
|
|
|
if (r) r = r*2 + 1;
|
|
|
|
if (g) g = g*2 + 1;
|
|
|
|
if (b) b = b*2 + 1;
|
|
|
|
|
|
|
|
glUniform4ui(0, r, g, b, a);
|
|
|
|
glUniform1ui(1, z);
|
|
|
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID);
|
|
|
|
glBindVertexArray(ClearVertexArrayID);
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 2*3);
|
|
|
|
}
|
2019-04-28 20:19:56 -06:00
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
if (RenderNumPolygons)
|
|
|
|
{
|
|
|
|
// render shit here
|
|
|
|
u32 flags = 0;
|
|
|
|
if (RenderPolygonRAM[0]->WBuffer) flags |= RenderFlag_WBuffer;
|
2019-04-10 14:49:06 -06:00
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
int npolys = 0;
|
|
|
|
for (int i = 0; i < RenderNumPolygons; i++)
|
|
|
|
{
|
|
|
|
if (RenderPolygonRAM[i]->Degenerate) continue;
|
|
|
|
SetupPolygon(&PolygonList[npolys++], RenderPolygonRAM[i]);
|
|
|
|
}
|
|
|
|
|
2019-05-01 18:28:31 -06:00
|
|
|
BuildPolygons(&PolygonList[0], npolys);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
|
|
|
|
glBufferSubData(GL_ARRAY_BUFFER, 0, NumVertices*7*4, VertexBuffer);
|
|
|
|
|
|
|
|
// pass 1: opaque pixels
|
|
|
|
|
2019-05-01 15:35:48 -06:00
|
|
|
UseRenderShader(flags);
|
2019-04-24 14:38:50 -06:00
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
// zorp
|
|
|
|
glDepthFunc(GL_LESS);
|
2019-04-24 14:38:50 -06:00
|
|
|
|
2019-04-25 05:32:15 -06:00
|
|
|
glBindVertexArray(VertexArrayID);
|
|
|
|
glDrawElements(GL_TRIANGLES, NumTriangles*3, GL_UNSIGNED_SHORT, IndexBuffer);
|
|
|
|
}
|
2019-04-10 14:49:06 -06:00
|
|
|
|
2019-03-31 20:20:43 -06:00
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID);
|
|
|
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
|
|
//glReadPixels(0, 0, 256, 48, GL_RGBA, GL_UNSIGNED_BYTE, Framebuffer);
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, PixelbufferID);
|
2019-03-31 20:58:21 -06:00
|
|
|
//glReadPixels(0, 0, 256, 48, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
glReadPixels(0, 0, 256, 192, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
2019-03-31 18:51:31 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void RequestLine(int line)
|
|
|
|
{
|
|
|
|
if (line == 0)
|
|
|
|
{
|
2019-03-31 20:20:43 -06:00
|
|
|
u8* data = (u8*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
2019-03-31 20:58:21 -06:00
|
|
|
//if (data) memcpy(&Framebuffer[4*256*0], data, 4*256*48);
|
|
|
|
if (data) memcpy(&Framebuffer[4*256*0], data, 4*256*192);
|
2019-03-31 20:20:43 -06:00
|
|
|
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
|
|
|
|
2019-03-31 20:58:21 -06:00
|
|
|
//glReadPixels(0, 48, 256, 48, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
2019-03-31 20:20:43 -06:00
|
|
|
}
|
2019-03-31 20:58:21 -06:00
|
|
|
/*else if (line == 48)
|
2019-03-31 20:20:43 -06:00
|
|
|
{
|
|
|
|
u8* data = (u8*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
|
|
|
if (data) memcpy(&Framebuffer[4*256*48], data, 4*256*48);
|
|
|
|
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
|
|
|
|
|
|
|
glReadPixels(0, 96, 256, 48, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
}
|
|
|
|
else if (line == 96)
|
|
|
|
{
|
|
|
|
u8* data = (u8*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
|
|
|
if (data) memcpy(&Framebuffer[4*256*96], data, 4*256*48);
|
|
|
|
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
|
|
|
|
|
|
|
glReadPixels(0, 144, 256, 48, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
}
|
|
|
|
else if (line == 144)
|
|
|
|
{
|
|
|
|
u8* data = (u8*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
|
|
|
|
if (data) memcpy(&Framebuffer[4*256*144], data, 4*256*48);
|
|
|
|
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
2019-03-31 20:58:21 -06:00
|
|
|
}*/
|
2019-03-31 20:22:03 -06:00
|
|
|
}
|
2019-03-31 18:51:31 -06:00
|
|
|
|
2019-03-31 20:22:03 -06:00
|
|
|
u32* GetLine(int line)
|
|
|
|
{
|
2019-03-31 18:51:31 -06:00
|
|
|
return (u32*)&Framebuffer[256*4 * line];
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|