Well, this is something I spent a bit researching, though it is really of minor importance. The corner colours for a text box in FF7 can be changed in the settings, something like this:
The top left gradient should be familiar to people who played around with this. The hardware draws a quad internally as two triangles, and each triangle interpolates the colours at its corners. Because the same colour is used along the long edge you get a constant colour, and not a mix of all 4 colours as you would expect from a bilinear interpolation.
Nowadays you can solve this easily with a few lines in a pixel shader, except my ancient mac-mini has only a few texture combiners. So I looked a bit into how to solve this otherwise.
The top right gradient is a triangle fan, with the centre colour the average of all corners. It's slightly improved, but still off from a bilinear interpolation. The solution I am most happy with is the bottom left: It uses a tiny 2x2 pixel texture so that it can use the bilinear interpolation hardware used for textures. Unfortunately the precision for that is slightly less than for the vertex colour interpolation, but otherwise it is the best result.
Source:
import sys, array
from OpenGL.GL import *
import pygame
from pygame.locals import *
def main(*argv):
pygame.init()
screen = pygame.display.set_mode((640, 480), HWSURFACE|DOUBLEBUF|OPENGL)
# set up view
glViewport(0, 0, 640, 480)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0, 640, 480, 0, -1, 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# scale and offset texture coordinates to that we sample from pixel centre to pixel centre
glMatrixMode(GL_TEXTURE)
glLoadIdentity()
glScalef(1.0/2.0, 1.0/2.0,1)
glTranslatef(0.5,0.5,0)
glDisable(GL_DEPTH_TEST)
glDisable(GL_CULL_FACE)
glDisable(GL_LIGHTING)
glDisable(GL_BLEND)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
# gradient colours
colours = array.array("B", [255,0,0,255, 0,255,0,255, 0,255,0,255, 0,0,255,255])
# colours = array.array("B", [255,0,0,255, 0,255,0,255, 0,0,255,255, 255,255,0,255])
# colours = array.array("B", [255,0,0,255, 0,255,0,255, 255,0,0,255, 0,255,0,255])
# colours = array.array("B", [255,255,255,255, 0,0,0,255, 0,0,0,255, 0,0,0,255])
# colours = array.array("B", [255,0,0,255, 128,128,0,255, 128,128,0,255, 0,255,0,255])
# create texture from gradient colours
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colours.tostring())
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
# simple replace mode: fragment colour is just texture colour
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
glClearColor(0.5, 0.5, 0.5, 0)
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
elif event.type == KEYDOWN:
if event.key == pygame.K_ESCAPE:
exit()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# plain vertex colours
glBegin(GL_QUADS)
glColor4ub(colours[0],colours[1],colours[2],colours[3])
glVertex2i(40,40)
glColor4ub(colours[4],colours[5],colours[6],colours[7])
glVertex2i(300,40)
glColor4ub(colours[12],colours[13],colours[14],colours[15])
glVertex2i(300,220)
glColor4ub(colours[8],colours[9],colours[10],colours[11])
glVertex2i(40,220)
glEnd()
# triangle fan with mixed colour in the centre
center = (
(colours[0]+colours[4]+colours[12]+colours[8]) / 4,
(colours[1]+colours[5]+colours[13]+colours[9]) / 4,
(colours[2]+colours[6]+colours[14]+colours[10]) / 4,
(colours[3]+colours[7]+colours[15]+colours[11]) / 4
)
glBegin(GL_TRIANGLE_FAN)
glColor4ub(center[0],center[1],center[2],center[3])
glVertex2i(470,130)
glColor4ub(colours[0],colours[1],colours[2],colours[3])
glVertex2i(340,40)
glColor4ub(colours[4],colours[5],colours[6],colours[7])
glVertex2i(600,40)
glColor4ub(colours[12],colours[13],colours[14],colours[15])
glVertex2i(600,220)
glColor4ub(colours[8],colours[9],colours[10],colours[11])
glVertex2i(340,220)
glColor4ub(colours[0],colours[1],colours[2],colours[3])
glVertex2i(340,40)
glEnd()
# texture
glEnable(GL_TEXTURE_2D)
glBegin(GL_QUADS)
glTexCoord2i(0,0)
glVertex2i(40,260)
glTexCoord2i(1,0)
glVertex2i(300,260)
glTexCoord2i(1,1)
glVertex2i(300,440)
glTexCoord2i(0,1)
glVertex2i(40,440)
glEnd()
glDisable(GL_TEXTURE_2D)
pygame.display.flip()
if __name__ == "__main__":
main(*sys.argv[1:])
There are a few different gradients to play around with.