chess board texture on the fly - best approach?

I am trying to assemble 2d chess board textures for each move in a game. Each 2d texture represents a single ‘frame’ if you will of a chess game. I’m not sure of the correct approach. Kind of like what you see here:

chesstempo.com/pgn-viewer.html

I have made a PNG image with the board (360x360 pixels) and the chess pieces (each 45x45 pixels). This is attached.


For each board position I already have a string (looks like this when printed from command line):

r n b q k b n r
p p p p p p p p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
P P P P P P P P
R N B Q K B N R

Where lower case is ‘black’ and upper case is ‘white’.

Problem is, I’m not sure the best way to go about overlaying the 45x45 chess pieces on the 360x360 board in real-time. I want to generate on-the-fly a ‘frame’ texture for each board move and set each one of those to a quad that is pickable by the user. So the user can click a given quad (with a texture on it) (more or less a 2d ui) and switch my 3d view to the matching chess board position…

Solutions I can think of…

  1. Build a single texture in real-time (by setting raw pixels) for each board position (not sure how to do this without setting raw pixels which is expensive).
  2. Make a quad for the board with the 360x360 texture applied to it. Then make a quad for each chess piece and apply the appropriate 45x45 texture. Render the board and translate each chess piece quad above it…then use Render-to-Texture for each board position (not sure if this would be too expensive).
  3. Use brute force miltitexturing…I would need 9 textures in use I think to make this work…most graphics cards only support up to 8.

Any thoughts on the best path? Or an alternate?

You might want to use a PNMImage for this. You can start by loading the image you attached as a texture atlas into one PNMImage and then copy the board and chess piece subimages from it as needed into a new PNMImage for each board frame.

Here is some code:

from panda3d.core import *
from direct.showbase.ShowBase import ShowBase


class MyApp(ShowBase):

    def __init__(self):

        ShowBase.__init__(self)

        # load texture atlas
        tex_atlas = PNMImage("smallboard_512.png")
        
        # Create a chess board frame
        
        # initialize the frame image
        board_frame = PNMImage(360, 360, 4)
        # copy the board image from the texture atlas into it
        board_frame.copySubImage(tex_atlas, 0, 0, 0, 0, 360, 360)
        # copy the chess piece images from the texture atlas into it
        y_from = 360 + 45
        board_frame.blendSubImage(tex_atlas, 0, 0, 45 * 4, y_from, 45, 45)
        board_frame.blendSubImage(tex_atlas, 45, 0, 45 * 3, y_from, 45, 45)
        board_frame.blendSubImage(tex_atlas, 45 * 2, 0, 45 * 2, y_from, 45, 45)
        board_frame.blendSubImage(tex_atlas, 45 * 3, 0, 45, y_from, 45, 45)
        board_frame.blendSubImage(tex_atlas, 45 * 4, 0, 0, y_from, 45, 45)
        board_frame.blendSubImage(tex_atlas, 45 * 5, 0, 45 * 2, y_from, 45, 45)
        board_frame.blendSubImage(tex_atlas, 45 * 6, 0, 45 * 3, y_from, 45, 45)
        board_frame.blendSubImage(tex_atlas, 45 * 7, 0, 45 * 4, y_from, 45, 45)
        x_from = 45 * 5
        for i in range(8):
            board_frame.blendSubImage(tex_atlas, 45 * i, 45, x_from, y_from, 45, 45)
        # and so on...

        # load the board frame image into a Texture
        tex = Texture("board_tex")
        tex.load(board_frame)
        # create a quad for the board frame
        cm = CardMaker("board_frame_quad")
        cm.setFrame(0, 360, -360, 0) # units are in pixels
        cm.setHasNormals(False)
        self.board_frame_quad = self.pixel2d.attachNewNode(cm.generate())
        # set the Texture
        self.board_frame_quad.set_texture(TextureStage.getDefault(), tex)


app = MyApp()
app.run()

Got it! Thanks for the code sample. Appreciate the help.