Qhimm.com Forums

Miscellaneous Forums => Scripting and Reverse Engineering => Topic started by: Micky on 2011-09-22 20:26:12

Title: [FF7] textbox gradient
Post by: Micky on 2011-09-22 20:26:12
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:
(http://bin.mypage.sk/FILES/gradients.jpg)
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:
Code: [Select]
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.
Title: Re: [FF7] textbox gradient
Post by: sen on 2011-09-25 15:46:12
Nice work!
Title: Re: [FF7] textbox gradient
Post by: PitBrat on 2011-09-25 16:46:10
I tried adding this as a .post shader in the shaders folder, but nothing changed in the game.
How does one implement this shader in FF7 when using Aali's OpenGL driver?
Title: Re: [FF7] textbox gradient
Post by: Micky on 2011-09-26 18:55:52
How does one implement this shader in FF7 when using Aali's OpenGL driver?
No idea, I only use the PSX version. Is Aali still maintaining it? I'm not really following development since the latest Forum redesign. But it should be easy enough to add, either using a pixel shader or the texture trick, if he can detect a screen-aligned untextured quad.
Title: Re: [FF7] textbox gradient
Post by: Covarr on 2011-09-26 19:13:05
I tried adding this as a .post shader in the shaders folder, but nothing changed in the game.
How does one implement this shader in FF7 when using Aali's OpenGL driver?
I assume you double-checked these lines in ff7_opengl.cfg?

Code: [Select]
use_shaders = yes

Code: [Select]
post_source = shaders/(whatever you named this file).post
enable_postprocessing = yes
Title: Re: [FF7] textbox gradient
Post by: PitBrat on 2011-09-27 03:53:31
PSX... Ah, that explains all the errors.
Since I've connected a second monitor, enabling postprocessing crashes the game during the intro movie.
Now it's time for a little tinkering.