package achtbit;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Calendar;
import java.util.Date;
import java.util.Observable;
import java.util.Observer;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
/*
*
* Created on: 25.09.2012
* Author: Christian Wahlmann
* This file is part of achtBit.
* achtBit 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.
* achtBit 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 achtBit. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
* @author christianw
*/
public class ScreenJPanel extends javax.swing.JPanel implements Observer, AchtbitPanel {
public static final int textInputBuffer=0xd200;
public static final int charset=0xd600;
public static final int screen=0xe000;
public static final int textPalette=0xe400;
public static final int palette=0xff40;
public static final int gfxMode=0xff70;
public static final int gfxColor=0xff71;
public static final int screenRefresh=0xff72;
public static final int screenInterrupt=0xff73;
public static final int cursorPosition=0xff76;
public static final int textColor=0xff78;
public static final int cursorEnable=0xff79;
public static final int textInputBufferPointer=0xff7a;
public static final int cursorSpeed=0xff7c;
public static final int timerSec=0xff7d;
public static final int timerMin=0xff7e;
public static final int timerHour=0xff7f;
public static final int timerDay=0xff80;
public static final int timerMonth=0xff81;
public static final int timerYear=0xff82;
public static final int gfxColor1=0xff84;
private BufferedImage screenImage=null;
private boolean cursorVisible=false;
private int cursorCount=20;
private boolean fixedZoom=false;
private UpdateRequest updateRequest;
/**
* Creates new form ScreenJPanel
*/
public ScreenJPanel() {
initComponents();
resetPalette();
reset();
screenImage=new BufferedImage(320,200,BufferedImage.TYPE_3BYTE_BGR);
update();
updateRequest = new UpdateRequest(this);
Memory.instance().addObserver(this);
}
public final void resetPalette() {
readPalette("stdPalette.png");
readCharset("stdCharset.png");
}
public final void reset() {
Memory mem=Memory.instance();
mem.setByte(gfxMode,0);
mem.setByte(gfxColor,0xb2);
mem.setByte(gfxColor+1,0x7F);
mem.setWord(cursorPosition,0);
mem.setByte(textColor,0xc2);
mem.setByte(cursorEnable,1);
mem.setByte(cursorSpeed,20);
mem.setByte(textInputBuffer,0);
mem.setWord(textInputBufferPointer,textInputBuffer);
for (int i=0; i<0x320; i++) {
mem.setByte(screen+i,' ');
mem.setByte(textPalette+i,mem.getByte(textColor));
}
this.cursorCount=mem.getByte(cursorSpeed);
this.cursorVisible=false;
Calendar cal = Calendar.getInstance();
cal.setTime( new Date() );
Memory.instance().setWord(ScreenJPanel.timerYear, cal.get(Calendar.YEAR));
Memory.instance().setByte(ScreenJPanel.timerMonth, cal.get(Calendar.MONTH)+1);
Memory.instance().setByte(ScreenJPanel.timerDay, cal.get(Calendar.DAY_OF_MONTH));
Memory.instance().setByte(ScreenJPanel.timerHour, cal.get(Calendar.HOUR_OF_DAY));
Memory.instance().setByte(ScreenJPanel.timerMin, cal.get(Calendar.MINUTE));
Memory.instance().setByte(ScreenJPanel.timerSec, cal.get(Calendar.SECOND));
}
public boolean isFixedZoom() {
return fixedZoom;
}
public void setFixedZoom(boolean fixedZoom) {
this.fixedZoom = fixedZoom;
}
public void readPalette(String filename) {
try {
BufferedImage pal = ImageIO.read( getClass().getResource(filename ) );
Memory mem=Memory.instance();
int p=ScreenJPanel.palette;
for (int c=0; c<16; c++) {
int argb=pal.getRGB(c,0);
int r=(argb>>16)&0xff;
int g=(argb>>8)&0xff;
int b=argb&0xff;
mem.setByte(p,r,true);
mem.setByte(p+1,g,true);
mem.setByte(p+2,b,true);
p+=3;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void readCharset(String filename) {
try {
BufferedImage cs = ImageIO.read( getClass().getResource(filename ));
Memory mem=Memory.instance();
int p=ScreenJPanel.charset;
int y=0;
for (int j=0; j<16; j++) {
int x=0;
for (int i=0; i<16; i++) {
for (int l=0; l<10; l++) {
int b=0;
for (int k=0; k<8; k++) {
b=b<<1;
if (cs.getRGB(x+k, y+l)!=-1) b++;
}
mem.setByte(p,b,true);
p++;
}
x+=8;
}
y+=10;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public final synchronized void drawScreen() {
Memory mem=Memory.instance();
if (mem.getByte(ScreenJPanel.gfxMode)==1) {
int p=ScreenJPanel.screen;
int c=mem.getByte(ScreenJPanel.gfxColor);
int fg=(c & 0x0f)*3+ScreenJPanel.palette;
int bg=(c / 16)*3+ScreenJPanel.palette;
Color fgcolor=new Color(mem.getByte(fg), mem.getByte(fg+1), mem.getByte(fg+2));
Color bgcolor=new Color(mem.getByte(bg), mem.getByte(bg+1), mem.getByte(bg+2));
for (int y=0; y<200; y++) {
for (int x=0; x<40; x++) {
drawByte(x,y,mem.getByte(p), fgcolor, bgcolor);
p++;
}
}
}
else if (mem.getByte(ScreenJPanel.gfxMode)==2) {
int p=ScreenJPanel.screen;
int c=mem.getByte(ScreenJPanel.gfxColor);
int c1=mem.getByte(ScreenJPanel.gfxColor1);
int f0=(c / 16)*3+ScreenJPanel.palette;
int f1=(c & 0x0f)*3+ScreenJPanel.palette;
int f2=(1 / 16)*3+ScreenJPanel.palette;
int f3=(c1 & 0x0f)*3+ScreenJPanel.palette;
Color[] color={
new Color(mem.getByte(f0), mem.getByte(f0+1), mem.getByte(f0+2)),
new Color(mem.getByte(f1), mem.getByte(f1+1), mem.getByte(f1+2)),
new Color(mem.getByte(f2), mem.getByte(f2+1), mem.getByte(f2+2)),
new Color(mem.getByte(f3), mem.getByte(f3+1), mem.getByte(f3+2))
};
for (int y=0; y<200; y++) {
for (int x=0; x<40; x++) {
drawTupel(x,y,mem.getByte(p), color);
p++;
}
}
}
else if (mem.getByte(ScreenJPanel.gfxMode)==3) {
int p=ScreenJPanel.screen;
for (int y=0; y<100; y++) {
for (int x=0; x<80; x++) {
int b=mem.getByte(p)&0xff;
int c0=(b/16)*3+ScreenJPanel.palette;
int c1=(b&15)*3+ScreenJPanel.palette;
Color color0=new Color(mem.getByte(c0), mem.getByte(c0+1), mem.getByte(c0+2));
Color color1=new Color(mem.getByte(c1), mem.getByte(c1+1), mem.getByte(c1+2));
draw2x2Pixel(x*4,y*2,color0);
draw2x2Pixel(x*4+2,y*2,color1);
p++;
}
}
}
else {
int p=ScreenJPanel.screen;
int pc=ScreenJPanel.textPalette;
for (int y=0; y<20; y++) {
for (int x=0; x<40; x++) {
drawChar(x,y,mem.getByte(p),mem.getByte(pc));
p++;
pc++;
}
}
if (mem.getByte(ScreenJPanel.cursorEnable)!=0 && cursorVisible) {
int x=mem.getByte(cursorPosition);
int y=mem.getByte(cursorPosition+1);
p=x+y*40;
drawChar(x,y,mem.getByte(screen+p),mem.getByte(textPalette+p)^0xff);
}
}
}
public void drawChar(int x, int y, int ch, int c) {
Memory mem=Memory.instance();
int fg=(c & 0x0f)*3+ScreenJPanel.palette;
int bg=(c / 16)*3+ScreenJPanel.palette;
Color fgcolor=new Color(mem.getByte(fg), mem.getByte(fg+1), mem.getByte(fg+2));
Color bgcolor=new Color(mem.getByte(bg), mem.getByte(bg+1), mem.getByte(bg+2));
int pch=ch*10+ScreenJPanel.charset;
for (int j=0; j<10; j++) {
drawByte(x,y*10+j,mem.getByte(pch),fgcolor,bgcolor);
pch++;
}
}
public void drawByte(int x, int y, int bt, Color fg, Color bg) {
Memory mem=Memory.instance();
int b=bt;
for (int i=0; i<8; i++) {
if ((b & 0x80) >0) this.screenImage.setRGB(x*8+i, y, fg.getRGB());
else this.screenImage.setRGB(x*8+i, y, bg.getRGB());
b=b<<1;
}
}
public void drawTupel(int x, int y, int bt, Color[] color) {
Memory mem=Memory.instance();
int b=bt;
for (int i=0; i<4; i++) {
int c=(b>>6)&3;
this.screenImage.setRGB(x*8+i*2, y, color[c].getRGB());
this.screenImage.setRGB(x*8+i*2+1, y, color[c].getRGB());
b=b<<2;
}
}
public void draw2x2Pixel(int x, int y, Color color) {
for (int i=0; i<2; i++)
for (int j=0; j<2; j++)
this.screenImage.setRGB(x+i, y+j, color.getRGB());
}
public void update(Observable o, Object o1) {
if (!(o instanceof Memory)) return;
if ((Memory.instance().getByte(ScreenJPanel.screenRefresh) & 1)==0) return;
Memory.instance().setByte(ScreenJPanel.screenRefresh,0);
if (CpuState.instance().isRunning()) {
cursorCount--;
if (cursorCount==0) {
this.cursorCount=Memory.instance().getByte(cursorSpeed);
cursorVisible=!cursorVisible;
}
}
if (updateRequest.isDone()) {
updateRequest.setDone(false);
EventQueue.invokeLater(updateRequest);
}
}
public void update() {
drawScreen();
repaint();
}
@Override
public void paint(Graphics g) {
if (screenImage==null) return;
int w=this.getWidth();
int h=this.getHeight();
g.setColor(Color.black);
g.fillRect(0,0,w,h);
if (!fixedZoom) {
if (w>h*8/5) w=h*8/5;
else h=w*5/8;
}
else {
int zw=w/screenImage.getWidth();
int zh=h/screenImage.getHeight();
int z=(zw<zh)?zw:zh;
w=screenImage.getWidth()*z;
h=screenImage.getHeight()*z;
}
int x=(this.getWidth()-w)/2;
int y=(this.getHeight()-h)/2;
g.drawImage(screenImage, x,y, w,h,this);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
setFocusCycleRoot(true);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 300, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
public static void main(String[] args) {
ScreenJPanel sp=new ScreenJPanel();
JFrame f=new JFrame();
f.add(sp);
f.setVisible(true);
Memory.instance().setByte(ScreenJPanel.gfxMode, 0);
for (int i=0; i<255; i++) {
Memory.instance().setByte(ScreenJPanel.screen+(i&15)+(i/16)*40,i,true);
Memory.instance().setByte(ScreenJPanel.textColor+(i&15)+(i/16)*40,i,true);
}
sp.drawScreen();
sp.repaint();
}
}