After rereading your question, I got the feeling, that I misunderstood your question. So I'll expand my answer referring to this specific part of your question:
Maybe we can perform this logic on the CPU and use it to make a texture? The problem here is that I don't know of any way to access and modify specific pixels outside of shaders.
A texture is basically just an array of (color) values. If you have a 256x256 image, that uses 3 color values (RGB) and each color value is stored in a single byte (
char), then your array has 196608 byte sized elements. The color values are usually grouped so that 3 subsequent values represent a single pixel. Then the pixels are also ordered by column and row. So the first 765 array elements represent your first row/column of pixels in the image, the next 765 the second, and so on. With this information, you can calculate where every pixel is located in the image and modify its value as desired.
In case the texture you want to modify is loaded from a file, you should already have the pixel data since this is the format that OpenGL expects when you upload your texture. If the texture is dynamically generated on the GPU, just look into the previous version of my answer (below) for further guidance.
However, calculating lots of pixel data on the CPU is probably quite ineffective. I think the best solution would be to do all modifications on the GPU. If you can't achieve what you want with the standard render pipeline, you should read some tutorials about OpenGL compute shaders. I haven't worked myself with them yet, but I am pretty confident, that your problem should be solvable with them.
According to this discussion in the official OpenGL Forum, you can use
glReadPixels to get a texture from VRAM back to your normal RAM. However, in the reference pages, they say:
glReadPixels, glReadnPixels — read a block of pixels from the frame buffer
Important here is the term "frame buffer". To find out how to use it with textures, have a look at this StackOverflow question.
However, the accepted answer also mentions, that you can use
glGetTexImage (link to reference page), which is probably more suited. Have a look into the accepted answer of this StackOverflow link to get an understanding of how to use it.
Both methods should give you the pixel data on the CPU side, so you can modify it as you wish and send it back to the GPU afterward. However, this is probably a relatively slow approach.